Browse Source

Merge remote-tracking branch 'refs/remotes/upstream/master'

Matt C 8 years ago
parent
commit
02fce74a65
83 changed files with 12866 additions and 2645 deletions
  1. 1 0
      .gitignore
  2. 39 34
      Gruntfile.js
  3. 0 0
      build/prod/cyberchef.htm
  4. BIN
      build/prod/images/fork_me.png
  5. BIN
      build/prod/images/maximise-16x16.png
  6. BIN
      build/prod/images/restore-16x16.png
  7. 1 0
      build/prod/index.html
  8. 0 0
      build/prod/scripts.js
  9. 0 0
      build/prod/styles.css
  10. 9 12
      package.json
  11. 0 58
      src/css/lib/jquery.splitter.css
  12. 5 5
      src/css/structure/layout.css
  13. 4 0
      src/css/structure/overrides.css
  14. 2 2
      src/css/themes/classic.css
  15. 11 7
      src/html/index.html
  16. 3 0
      src/js/.eslintrc.json
  17. 13 1
      src/js/config/Categories.js
  18. 259 254
      src/js/config/OperationConfig.js
  19. 26 26
      src/js/core/Chef.js
  20. 22 22
      src/js/core/Dish.js
  21. 66 51
      src/js/core/FlowControl.js
  22. 16 16
      src/js/core/Ingredient.js
  23. 53 53
      src/js/core/Operation.js
  24. 64 65
      src/js/core/Recipe.js
  25. 18 18
      src/js/core/Utils.js
  26. 768 0
      src/js/lib/cryptoapi/crypto-api.js
  27. 113 0
      src/js/lib/cryptoapi/hasher.md2.js
  28. 204 0
      src/js/lib/cryptoapi/hasher.md4.js
  29. 125 0
      src/js/lib/cryptoapi/hasher.sha0.js
  30. 264 54
      src/js/lib/split.js
  31. 8466 0
      src/js/lib/xpath.js
  32. 2 2
      src/js/operations/Base.js
  33. 58 58
      src/js/operations/Base64.js
  34. 56 56
      src/js/operations/BitwiseOp.js
  35. 61 61
      src/js/operations/ByteRepr.js
  36. 8 8
      src/js/operations/CharEnc.js
  37. 76 16
      src/js/operations/Checksum.js
  38. 101 64
      src/js/operations/Cipher.js
  39. 152 37
      src/js/operations/Code.js
  40. 39 39
      src/js/operations/Compress.js
  41. 25 25
      src/js/operations/Convert.js
  42. 13 13
      src/js/operations/DateTime.js
  43. 15 15
      src/js/operations/Endian.js
  44. 25 25
      src/js/operations/Entropy.js
  45. 69 69
      src/js/operations/Extract.js
  46. 19 19
      src/js/operations/FileType.js
  47. 31 31
      src/js/operations/HTML.js
  48. 6 6
      src/js/operations/HTTP.js
  49. 95 53
      src/js/operations/Hash.js
  50. 28 28
      src/js/operations/Hexdump.js
  51. 213 213
      src/js/operations/IP.js
  52. 22 22
      src/js/operations/JS.js
  53. 23 23
      src/js/operations/MAC.js
  54. 7 7
      src/js/operations/OS.js
  55. 101 101
      src/js/operations/PublicKey.js
  56. 2 2
      src/js/operations/Punycode.js
  57. 7 7
      src/js/operations/QuotedPrintable.js
  58. 40 40
      src/js/operations/Rotate.js
  59. 19 19
      src/js/operations/SeqUtils.js
  60. 91 65
      src/js/operations/StrUtils.js
  61. 29 29
      src/js/operations/Tidy.js
  62. 16 16
      src/js/operations/URL.js
  63. 1 1
      src/js/operations/UUID.js
  64. 3 3
      src/js/operations/Unicode.js
  65. 119 118
      src/js/views/html/ControlsWaiter.js
  66. 170 169
      src/js/views/html/HTMLApp.js
  67. 10 10
      src/js/views/html/HTMLCategory.js
  68. 37 37
      src/js/views/html/HTMLIngredient.js
  69. 20 20
      src/js/views/html/HTMLOperation.js
  70. 88 88
      src/js/views/html/HighlighterWaiter.js
  71. 29 29
      src/js/views/html/InputWaiter.js
  72. 94 93
      src/js/views/html/Manager.js
  73. 74 74
      src/js/views/html/OperationsWaiter.js
  74. 8 8
      src/js/views/html/OptionsWaiter.js
  75. 87 38
      src/js/views/html/OutputWaiter.js
  76. 72 72
      src/js/views/html/RecipeWaiter.js
  77. 9 9
      src/js/views/html/SeasonalWaiter.js
  78. 9 9
      src/js/views/html/WindowWaiter.js
  79. 14 14
      src/js/views/html/main.js
  80. BIN
      src/static/images/fork_me.png
  81. BIN
      src/static/images/maximise-16x16.png
  82. BIN
      src/static/images/restore-16x16.png
  83. 21 6
      src/static/stats.txt

+ 1 - 0
.gitignore

@@ -4,3 +4,4 @@ build/dev
 docs/*
 !docs/*.conf.json
 !docs/*.ico
+.vscode

+ 39 - 34
Gruntfile.js

@@ -7,12 +7,12 @@ module.exports = function(grunt) {
     // Tasks
     grunt.registerTask("dev",
         "A persistent task which creates a development build whenever source files are modified.",
-        ["clean:dev", "concat:css", "concat:js", "copy:html_dev", "copy:static_dev", "chmod:build", "watch"]);
+        ["clean:dev", "concat:css", "concat:js", "copy:htmlDev", "copy:staticDev", "chmod:build", "watch"]);
 
     grunt.registerTask("prod",
         "Creates a production-ready build. Use the --msg flag to add a compile message.",
-        ["eslint", "exec:stats", "clean", "jsdoc", "concat", "copy:html_dev", "copy:html_prod", "copy:html_inline",
-         "copy:static_dev", "copy:static_prod", "cssmin", "uglify:prod", "inline", "htmlmin", "chmod"]);
+        ["eslint", "exec:stats", "clean", "jsdoc", "concat", "copy:htmlDev", "copy:htmlProd", "copy:htmlInline",
+         "copy:staticDev", "copy:staticProd", "cssmin", "uglify:prod", "inline", "htmlmin", "chmod"]);
 
     grunt.registerTask("docs",
         "Compiles documentation in the /docs directory.",
@@ -20,15 +20,15 @@ module.exports = function(grunt) {
 
     grunt.registerTask("stats",
         "Provides statistics about the code base such as how many lines there are as well as details of file sizes before and after compression.",
-        ["concat:js", "uglify:prod", "exec:stats", "exec:repo_size", "exec:display_stats"]);
+        ["concat:js", "uglify:prod", "exec:stats", "exec:repoSize", "exec:displayStats"]);
 
     grunt.registerTask("release",
         "Prepares and deploys a production version of CyberChef to the gh-pages branch.",
-        ["copy:gh_pages", "exec:deploy_gh_pages"]);
+        ["copy:ghPages", "exec:deployGhPages"]);
 
     grunt.registerTask("default",
         "Lints the code base and shows stats",
-        ["jshint", "exec:stats", "exec:display_stats"]);
+        ["eslint", "exec:stats", "exec:displayStats"]);
 
     grunt.registerTask("doc", "docs");
     grunt.registerTask("lint", "eslint");
@@ -50,7 +50,7 @@ module.exports = function(grunt) {
 
 
     // JS includes
-    var js_files = [
+    var jsFiles = [
         // Third party framework libraries
         "src/js/lib/jquery-2.1.1.js",
         "src/js/lib/bootstrap-3.3.6.js",
@@ -93,6 +93,10 @@ module.exports = function(grunt) {
         "src/js/lib/cryptojs/tripledes.js",
         "src/js/lib/cryptojs/rc4.js",
         "src/js/lib/cryptojs/pbkdf2.js",
+        "src/js/lib/cryptoapi/crypto-api.js",
+        "src/js/lib/cryptoapi/hasher.md2.js",
+        "src/js/lib/cryptoapi/hasher.md4.js",
+        "src/js/lib/cryptoapi/hasher.sha0.js",
         "src/js/lib/jsbn/jsbn.js",
         "src/js/lib/jsbn/jsbn2.js",
         "src/js/lib/jsbn/base64.js",
@@ -130,7 +134,8 @@ module.exports = function(grunt) {
         "src/js/lib/vkbeautify.js",
         "src/js/lib/Sortable.js",
         "src/js/lib/bootstrap-colorpicker.js",
-
+        "src/js/lib/xpath.js",
+        
         // Custom libraries
         "src/js/lib/canvas_components.js",
 
@@ -174,10 +179,10 @@ module.exports = function(grunt) {
  * limitations under the License.\n\
  */\n';
 
-    var template_options = {
+    var templateOptions = {
         data: {
-            compile_msg: grunt.option("compile-msg") || grunt.option("msg") || "",
-            codebase_stats: grunt.file.read("src/static/stats.txt").split("\n").join("<br>")
+            compileMsg: grunt.option("compile-msg") || grunt.option("msg") || "",
+            codebaseStats: grunt.file.read("src/static/stats.txt").split("\n").join("<br>")
         }
     };
 
@@ -215,7 +220,7 @@ module.exports = function(grunt) {
         },
         concat: {
             options: {
-                process: template_options
+                process: templateOptions
             },
             css: {
                 options: {
@@ -237,43 +242,43 @@ module.exports = function(grunt) {
                 options: {
                     banner: '"use strict";\n'
                 },
-                src: js_files,
+                src: jsFiles,
                 dest: "build/dev/scripts.js"
             }
         },
         copy: {
-            html_dev: {
+            htmlDev: {
                 options: {
                     process: function(content, srcpath) {
-                        return grunt.template.process(content, template_options);
+                        return grunt.template.process(content, templateOptions);
                     }
                 },
                 src: "src/html/index.html",
                 dest: "build/dev/index.html"
             },
-            html_prod: {
+            htmlProd: {
                 options: {
                     process: function(content, srcpath) {
-                        return grunt.template.process(content, template_options);
+                        return grunt.template.process(content, templateOptions);
                     }
                 },
                 src: "src/html/index.html",
                 dest: "build/prod/index.html"
             },
-            html_inline: {
+            htmlInline: {
                 options: {
                     process: function(content, srcpath) {
                         // TODO: Do all this in Jade
                         content = content.replace(
                             '<a href="cyberchef.htm" style="float: left; margin-left: 10px; margin-right: 80px;" download>Download CyberChef<img src="images/download-24x24.png" /></a>',
                             '<span style="float: left; margin-left: 10px;">Compile time: ' + grunt.template.today("dd/mm/yyyy HH:MM:ss") + " UTC</span>");
-                        return grunt.template.process(content, template_options);
+                        return grunt.template.process(content, templateOptions);
                     }
                 },
                 src: "src/html/index.html",
                 dest: "build/prod/cyberchef.htm"
             },
-            static_dev: {
+            staticDev: {
                 files: [
                     {
                         expand: true,
@@ -288,7 +293,7 @@ module.exports = function(grunt) {
                     }
                 ]
             },
-            static_prod: {
+            staticProd: {
                 files: [
                     {
                         expand: true,
@@ -303,13 +308,13 @@ module.exports = function(grunt) {
                     }
                 ]
             },
-            gh_pages: {
+            ghPages: {
                 options: {
                     process: function(content, srcpath) {
                         // Add Google Analytics code to index.html
                         content = content.replace("</body></html>",
                             grunt.file.read("src/static/ga.html") + "</body></html>");
-                        return grunt.template.process(content, template_options);
+                        return grunt.template.process(content, templateOptions);
                     }
                 },
                 src: "build/prod/index.html",
@@ -326,12 +331,12 @@ module.exports = function(grunt) {
                 ASCIIOnly: true,
                 beautify: {
                     beautify: false,
-                    inline_script: true,
-                    ascii_only: true,
-                    screw_ie8: true
+                    inline_script: true, // eslint-disable-line camelcase
+                    ascii_only: true, // eslint-disable-line camelcase
+                    screw_ie8: true // eslint-disable-line camelcase
                 },
                 compress: {
-                    screw_ie8: true
+                    screw_ie8: true // eslint-disable-line camelcase
                 },
                 banner: banner
             },
@@ -403,7 +408,7 @@ module.exports = function(grunt) {
             }
         },
         exec: {
-            repo_size: {
+            repoSize: {
                 command: [
                     "git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
                     "du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
@@ -438,13 +443,13 @@ module.exports = function(grunt) {
                     ].join(" >> src/static/stats.txt;") + " >> src/static/stats.txt;",
                 stderr: false
             },
-            display_stats: {
+            displayStats: {
                 command: "cat src/static/stats.txt"
             },
-            clean_git: {
+            cleanGit: {
                 command: "git gc --prune=now --aggressive"
             },
-            deploy_gh_pages: {
+            deployGhPages: {
                 command: [
                         "git add build/prod/index.html -v",
                         "COMMIT_HASH=$(git rev-parse HEAD)",
@@ -466,15 +471,15 @@ module.exports = function(grunt) {
             },
             html: {
                 files: "src/html/**/*.html",
-                tasks: ["copy:html_dev", "chmod:build"]
+                tasks: ["copy:htmlDev", "chmod:build"]
             },
             static: {
                 files: ["src/static/**/*", "src/static/**/.*"],
-                tasks: ["copy:static_dev", "chmod:build"]
+                tasks: ["copy:staticDev", "chmod:build"]
             },
             grunt: {
                 files: "Gruntfile.js",
-                tasks: ["clean:dev", "concat:css", "concat:js", "copy:html_dev", "copy:static_dev", "chmod:build"]
+                tasks: ["clean:dev", "concat:css", "concat:js", "copy:htmlDev", "copy:staticDev", "chmod:build"]
             }
         },
     });

File diff suppressed because it is too large
+ 0 - 0
build/prod/cyberchef.htm


BIN
build/prod/images/fork_me.png


BIN
build/prod/images/maximise-16x16.png


BIN
build/prod/images/restore-16x16.png


File diff suppressed because it is too large
+ 1 - 0
build/prod/index.html


File diff suppressed because it is too large
+ 0 - 0
build/prod/scripts.js


File diff suppressed because it is too large
+ 0 - 0
build/prod/styles.css


+ 9 - 12
package.json

@@ -21,27 +21,24 @@
     "format",
     "cybersecurity"
   ],
-  "bugs": {
-    "email": ""
-  },
   "repository": {
     "type": "git",
-    "url": ""
+    "url": "https://github.com/gchq/CyberChef/"
   },
   "devDependencies": {
-    "grunt": "~0.4.5",
+    "grunt": "~1.0.1",
     "grunt-chmod": "~1.1.1",
     "grunt-contrib-clean": "~1.0.0",
     "grunt-contrib-concat": "~1.0.0",
-    "grunt-contrib-copy": "~0.8.2",
-    "grunt-contrib-cssmin": "~0.14.0",
-    "grunt-contrib-htmlmin": "~0.6.0",
-    "grunt-contrib-uglify": "~0.11.1",
-    "grunt-contrib-watch": "~0.6.1",
+    "grunt-contrib-copy": "~1.0.0",
+    "grunt-contrib-cssmin": "~1.0.2",
+    "grunt-contrib-htmlmin": "~2.0.0",
+    "grunt-contrib-uglify": "~2.0.0",
+    "grunt-contrib-watch": "~1.0.0",
     "grunt-eslint": "^19.0.0",
-    "grunt-exec": "~0.4.6",
+    "grunt-exec": "~1.0.1",
     "grunt-inline-alt": "~0.3.10",
-    "grunt-jsdoc": "^1.1.0",
+    "grunt-jsdoc": "^2.1.0",
     "ink-docstrap": "^1.1.4"
   }
 }

+ 0 - 58
src/css/lib/jquery.splitter.css

@@ -1,58 +0,0 @@
-/** @license
-========================================================================
-  StyleSheet for JQuery splitter Plugin
-  Copyright (C) 2010 Jakub Jankiewicz <http://jcubic.pl>
- 
-  Same license as plugin
-*/
-.splitter_panel {
-  position: relative;
-}
-.splitter_panel .vsplitter {
-    background-color: grey;
-    cursor: col-resize;
-    z-index:900;
-    width: 4px;
-}
-
-.splitter_panel .hsplitter {
-    background-color: #5F5F5F;
-    cursor: row-resize;
-    z-index: 800;
-    height: 4px;
-}
-.splitter_panel .vsplitter.splitter-invisible,
-.splitter_panel .hsplitter.splitter-invisible {
-    background: none;
-}
-.splitter_panel .vsplitter, .splitter_panel .left_panel, .splitter_panel .right_panel,
-.splitter_panel .hsplitter, .splitter_panel .top_panel, .splitter_panel .bottom_panel {
-    position: absolute;
-    overflow: auto;
-}
-.splitter_panel .vsplitter, .splitter_panel .left_panel, .splitter_panel .right_panel {
-  height: 100%;
-}
-.splitter_panel .hsplitter, .splitter_panel .top_panel, .splitter_panel .bottom_panel {
-  width: 100%;
-}
-.splitter_panel .top_panel, .splitter_panel .left_panel, .splitter_panel .vsplitter {
-   top: 0;
-}
-.splitter_panel .top_panel, .splitter_panel .bottom_panel, .splitter_panel .left_panel, .splitter_panel .hsplitter {
-   left: 0;
-}
-.splitter_panel .bottom_panel {
-   bottom: 0;
-}
-.splitter_panel .right_panel {
-   right: 0;
-}
-.splitterMask {
-  position: absolute;
-  left: 0;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  z-index: 1000;
-}

+ 5 - 5
src/css/structure/layout.css

@@ -105,8 +105,8 @@ textarea,
     border: none;
 }
 
-#op_list,
-#rec_list {
+#op-list,
+#rec-list {
     position: absolute;
     top: 43px;
     bottom: 0;
@@ -116,13 +116,13 @@ textarea,
     padding: 0;
 }
 
-.op_list {
+.op-list {
     list-style-type: none;
     margin: 0;
     padding: 0;
 }
 
-#rec_list {
+#rec-list {
     bottom: 120px; /* Linked to #controls height */
     overflow: auto;
 }
@@ -137,7 +137,7 @@ textarea,
 #controls {
     position: absolute;
     width: 100%;
-    height: 120px;  /* Linked to #rec_list bottom */
+    height: 120px;  /* Linked to #rec-list bottom */
     bottom: 0;
     padding: 10px;
 }

+ 4 - 0
src/css/structure/overrides.css

@@ -64,6 +64,10 @@ blockquote {
     font-size: inherit;
 }
 
+blockquote a {
+    cursor: pointer;
+}
+
 optgroup {
     font-weight: bold;
 }

+ 2 - 2
src/css/themes/classic.css

@@ -30,13 +30,13 @@
     border-top-width: 0;
 }
 
-.op_list .operation { /*blue*/
+.op-list .operation { /*blue*/
     color: #3a87ad;
     background-color: #d9edf7;
     border-color: #bce8f1;
 }
 
-#rec_list .operation { /*green*/
+#rec-list .operation { /*green*/
     color: #468847;
     background-color: #dff0d8;
     border-color: #d6e9c6;

+ 11 - 7
src/html/index.html

@@ -58,13 +58,13 @@
                 <div id="operations" class="split split-horizontal no-select">
                     <div class="title no-select">Operations</div>
                     <input type="search" class="form-control" id="search" placeholder="Search..." autocomplete="off">
-                    <ul class="op_list" id="search-results"></ul>
+                    <ul class="op-list" id="search-results"></ul>
                     <div class="panel-group no-select" id="categories"></div>
                 </div>
                 
                 <div id="recipe" class="split split-horizontal no-select">
                     <div class="title no-select">Recipe</div>
-                    <ul id="rec_list" class="no-select"></ul>
+                    <ul id="rec-list" class="no-select"></ul>
                     
                     <div id="controls" class="no-select">
                         <div id="operational-controls">
@@ -114,9 +114,10 @@
                         <div class="title no-select">
                             Output
                             <div class="btn-group io-btn-group">
-                                <button type="button" class="btn btn-default btn-sm" id="save-to-file"><img src="images/save_as-16x16.png" /> Save to file</button>
-                                <button type="button" class="btn btn-default btn-sm" id="switch"><img src="images/switch-16x16.png" /> Move output to input</button>
-                                <button type="button" class="btn btn-default btn-sm" id="undo-switch" disabled="disabled"><img src="images/undo-16x16.png" /> Undo</button>
+                                <button type="button" class="btn btn-default btn-sm" id="save-to-file" title="Save to file"><img src="images/save_as-16x16.png" /> Save to file</button>
+                                <button type="button" class="btn btn-default btn-sm" id="switch" title="Move output to input"><img src="images/switch-16x16.png" /> Move output to input</button>
+                                <button type="button" class="btn btn-default btn-sm" id="undo-switch" title="Undo move" disabled="disabled"><img src="images/undo-16x16.png" /> Undo</button>
+                                <button type="button" class="btn btn-default btn-sm" id="maximise-output" title="Maximise"><img src="images/maximise-16x16.png" /> Max</button>
                             </div>
                             <div class="io-info" id="output-info"></div>
                             <div class="io-info" id="output-selection-info"></div>
@@ -251,7 +252,7 @@
                             <li><span style="font-weight: bold">To remove:</span> hit the red cross or drag out of the list below</li>
                         </ul>
                         <br>
-                        <ul id="edit-favourites-list" class="op_list"></ul>
+                        <ul id="edit-favourites-list" class="op-list"></ul>
                         <div class="option-item">
                         </div>
                     </div>
@@ -335,7 +336,7 @@
                                 <div role='tabpanel' class='tab-pane' id='stats'>
                                     <br>
                                     <p>If you're a nerd like me, you might find statistics really fun! Here's some about the CyberChef code base:</p>
-                                    <br><pre><%= codebase_stats %></pre>
+                                    <br><pre><%= codebaseStats %></pre>
                                 </div>
                                 <div role='tabpanel' class='tab-pane' id='about' style="padding: 20px;">
                                     <h4>What</h4>
@@ -364,6 +365,9 @@
                     <div class="modal-footer">
                         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                     </div>
+                    <a href="https://github.com/gchq/CyberChef">
+                        <img style="position: absolute; top: 0; right: 0; border: 0;" src="images/fork_me.png" alt="Fork me on GitHub">
+                    </a>
                 </div>
             </div>
         </div>

+ 3 - 0
src/js/.eslintrc.json

@@ -58,6 +58,9 @@
         "quotes": ["error", "double", {
             "avoidEscape": true
         }],
+        "camelcase": ["error", {
+            "properties": "always"
+        }],
         "semi": ["error", "always"],
         "unicode-bom": "error"
     },

+ 13 - 1
src/js/config/Categories.js

@@ -17,7 +17,7 @@
  * @constant
  * @type {CatConf[]}
  */
-const Categories = [
+var Categories = [
     {
         name: "Favourites",
         ops: []
@@ -82,6 +82,7 @@ const Categories = [
             "XOR Brute Force",
             "Vigenère Encode",
             "Vigenère Decode",
+            "Substitute",
             "Derive PBKDF2 key",
             "Derive EVP key",
         ]
@@ -148,6 +149,7 @@ const Categories = [
             "Sort",
             "Unique",
             "Split",
+            "Filter",
             "Count occurrences",
             "Expand alphabet range",
             "Parse escaped string",
@@ -189,6 +191,8 @@ const Categories = [
             "Extract file paths",
             "Extract dates",
             "Regular expression",
+            "XPath expression",
+            "CSS selector",
         ]
     },
     {
@@ -210,7 +214,10 @@ const Categories = [
         ops: [
             "Analyse hash",
             "Generate all hashes",
+            "MD2",
+            "MD4",
             "MD5",
+            "SHA0",
             "SHA1",
             "SHA224",
             "SHA256",
@@ -219,7 +226,10 @@ const Categories = [
             "SHA3",
             "RIPEMD-160",
             "HMAC",
+            "Fletcher-8 Checksum",
             "Fletcher-16 Checksum",
+            "Fletcher-32 Checksum",
+            "Fletcher-64 Checksum",
             "Adler-32 Checksum",
             "CRC-32 Checksum",
             "TCP/IP Checksum",
@@ -241,6 +251,8 @@ const Categories = [
             "SQL Minify",
             "CSS Beautify",
             "CSS Minify",
+            "XPath expression",
+            "CSS selector",
             "Strip HTML tags",
             "Diff",
         ]

File diff suppressed because it is too large
+ 259 - 254
src/js/config/OperationConfig.js


+ 26 - 26
src/js/core/Chef.js

@@ -15,10 +15,10 @@ var Chef = function() {
 /**
  * Runs the recipe over the input.
  *
- * @param {string} input_text - The input data as a string
- * @param {Object[]} recipe_config - The recipe configuration object
+ * @param {string} inputText - The input data as a string
+ * @param {Object[]} recipeConfig - The recipe configuration object
  * @param {Object} options - The options object storing various user choices
- * @param {boolean} options.attemp_highlight - Whether or not to attempt highlighting
+ * @param {boolean} options.attempHighlight - Whether or not to attempt highlighting
  * @param {number} progress - The position in the recipe to start from
  * @param {number} [step] - The number of operations to execute
  *
@@ -30,41 +30,41 @@ var Chef = function() {
  * @returns {number} response.duration - The number of ms it took to execute the recipe
  * @returns {number} response.error - The error object thrown by a failed operation (false if no error)
 */
-Chef.prototype.bake = function(input_text, recipe_config, options, progress, step) {
-    var start_time  = new Date().getTime(),
-        recipe      = new Recipe(recipe_config),
-        contains_fc = recipe.contains_flow_control(),
-        error       = false;
+Chef.prototype.bake = function(inputText, recipeConfig, options, progress, step) {
+    var startTime  = new Date().getTime(),
+        recipe     = new Recipe(recipeConfig),
+        containsFc = recipe.containsFlowControl(),
+        error      = false;
 
-    // Reset attempt_highlight flag
-    if (options.hasOwnProperty("attempt_highlight")) {
-        options.attempt_highlight = true;
+    // Reset attemptHighlight flag
+    if (options.hasOwnProperty("attemptHighlight")) {
+        options.attemptHighlight = true;
     }
 
-    if (contains_fc) options.attempt_highlight = false;
+    if (containsFc) options.attemptHighlight = false;
 
     // Clean up progress
-    if (progress >= recipe_config.length) {
+    if (progress >= recipeConfig.length) {
         progress = 0;
     }
 
     if (step) {
         // Unset breakpoint on this step
-        recipe.set_breakpoint(progress, false);
+        recipe.setBreakpoint(progress, false);
         // Set breakpoint on next step
-        recipe.set_breakpoint(progress + 1, true);
+        recipe.setBreakpoint(progress + 1, true);
     }
 
     // If stepping with flow control, we have to start from the beginning
     // but still want to skip all previous breakpoints
-    if (progress > 0 && contains_fc) {
-        recipe.remove_breaks_up_to(progress);
+    if (progress > 0 && containsFc) {
+        recipe.removeBreaksUpTo(progress);
         progress = 0;
     }
 
     // If starting from scratch, load data
     if (progress === 0) {
-        this.dish.set(input_text, Dish.STRING);
+        this.dish.set(inputText, Dish.STRING);
     }
 
     try {
@@ -80,10 +80,10 @@ Chef.prototype.bake = function(input_text, recipe_config, options, progress, ste
         result: this.dish.type === Dish.HTML ?
             this.dish.get(Dish.HTML) :
             this.dish.get(Dish.STRING),
-        type: Dish.enum_lookup(this.dish.type),
+        type: Dish.enumLookup(this.dish.type),
         progress: progress,
         options: options,
-        duration: new Date().getTime() - start_time,
+        duration: new Date().getTime() - startTime,
         error: error
     };
 };
@@ -103,18 +103,18 @@ Chef.prototype.bake = function(input_text, recipe_config, options, progress, ste
  * This will only actually execute the recipe if auto-bake is enabled, otherwise it will just load
  * the recipe, ingredients and dish.
  *
- * @param {Object[]} recipe_config - The recipe configuration object
+ * @param {Object[]} recipeConfig - The recipe configuration object
  * @returns {number} The time it took to run the silent bake in milliseconds.
 */
-Chef.prototype.silent_bake = function(recipe_config) {
-    var start_time = new Date().getTime(),
-        recipe     = new Recipe(recipe_config),
-        dish       = new Dish("", Dish.STRING);
+Chef.prototype.silentBake = function(recipeConfig) {
+    var startTime = new Date().getTime(),
+        recipe    = new Recipe(recipeConfig),
+        dish      = new Dish("", Dish.STRING);
 
     try {
         recipe.execute(dish);
     } catch(err) {
         // Suppress all errors
     }
-    return new Date().getTime() - start_time;
+    return new Date().getTime() - startTime;
 };

+ 22 - 22
src/js/core/Dish.js

@@ -6,7 +6,7 @@
  * @license Apache-2.0
  *
  * @class
- * @param {byte_array|string|number} value - The value of the input data.
+ * @param {byteArray|string|number} value - The value of the input data.
  * @param {number} type - The data type of value, see Dish enums.
  */
 var Dish = function(value, type) {
@@ -45,12 +45,12 @@ Dish.HTML = 3;
  * Returns the data type enum for the given type string.
  *
  * @static
- * @param {string} type_str - The name of the data type.
+ * @param {string} typeStr - The name of the data type.
  * @returns {number} The data type enum value.
  */
-Dish.type_enum = function(type_str) {
-    switch (type_str) {
-        case "byte_array":
+Dish.typeEnum = function(typeStr) {
+    switch (typeStr) {
+        case "byteArray":
         case "Byte array":
             return Dish.BYTE_ARRAY;
         case "string":
@@ -72,13 +72,13 @@ Dish.type_enum = function(type_str) {
  * Returns the data type string for the given type enum.
  *
  * @static
- * @param {string} type_enum - The enum value of the data type.
+ * @param {string} typeEnum - The enum value of the data type.
  * @returns {number} The data type as a string.
  */
-Dish.enum_lookup = function(type_enum) {
-    switch (type_enum) {
+Dish.enumLookup = function(typeEnum) {
+    switch (typeEnum) {
         case Dish.BYTE_ARRAY:
-            return "byte_array";
+            return "byteArray";
         case Dish.STRING:
             return "string";
         case Dish.NUMBER:
@@ -94,7 +94,7 @@ Dish.enum_lookup = function(type_enum) {
 /**
  * Sets the data value and type and then validates them.
  *
- * @param {byte_array|string|number} value - The value of the input data.
+ * @param {byteArray|string|number} value - The value of the input data.
  * @param {number} type - The data type of value, see Dish enums.
  */
 Dish.prototype.set = function(value, type) {
@@ -103,7 +103,7 @@ Dish.prototype.set = function(value, type) {
     
     if (!this.valid()) {
         var sample = Utils.truncate(JSON.stringify(this.value), 13);
-        throw "Data is not a valid " + Dish.enum_lookup(type) + ": " + sample;
+        throw "Data is not a valid " + Dish.enumLookup(type) + ": " + sample;
     }
 };
 
@@ -112,7 +112,7 @@ Dish.prototype.set = function(value, type) {
  * Returns the value of the data in the type format specified.
  *
  * @param {number} type - The data type of value, see Dish enums.
- * @returns {byte_array|string|number} The value of the output data.
+ * @returns {byteArray|string|number} The value of the output data.
  */
 Dish.prototype.get = function(type) {
     if (this.type !== type) {
@@ -125,36 +125,36 @@ Dish.prototype.get = function(type) {
 /**
  * Translates the data to the given type format.
  *
- * @param {number} to_type - The data type of value, see Dish enums.
+ * @param {number} toType - The data type of value, see Dish enums.
  */
-Dish.prototype.translate = function(to_type) {
-    // Convert data to intermediate byte_array type
+Dish.prototype.translate = function(toType) {
+    // Convert data to intermediate byteArray type
     switch (this.type) {
         case Dish.STRING:
-            this.value = this.value ? Utils.str_to_byte_array(this.value) : [];
+            this.value = this.value ? Utils.strToByteArray(this.value) : [];
             this.type = Dish.BYTE_ARRAY;
             break;
         case Dish.NUMBER:
-            this.value = typeof this.value == "number" ? Utils.str_to_byte_array(this.value.toString()) : [];
+            this.value = typeof this.value == "number" ? Utils.strToByteArray(this.value.toString()) : [];
             this.type = Dish.BYTE_ARRAY;
             break;
         case Dish.HTML:
-            this.value = this.value ? Utils.str_to_byte_array(Utils.strip_html_tags(this.value, true)) : [];
+            this.value = this.value ? Utils.strToByteArray(Utils.stripHtmlTags(this.value, true)) : [];
             this.type = Dish.BYTE_ARRAY;
             break;
         default:
             break;
     }
     
-    // Convert from byte_array to to_type
-    switch (to_type) {
+    // Convert from byteArray to toType
+    switch (toType) {
         case Dish.STRING:
         case Dish.HTML:
-            this.value = this.value ? Utils.byte_array_to_utf8(this.value) : "";
+            this.value = this.value ? Utils.byteArrayToUtf8(this.value) : "";
             this.type = Dish.STRING;
             break;
         case Dish.NUMBER:
-            this.value = this.value ? parseFloat(Utils.byte_array_to_utf8(this.value)) : 0;
+            this.value = this.value ? parseFloat(Utils.byteArrayToUtf8(this.value)) : 0;
             this.type = Dish.NUMBER;
             break;
         default:

+ 66 - 51
src/js/core/FlowControl.js

@@ -7,7 +7,7 @@
  *
  * @namespace
  */
-const FlowControl = {
+var FlowControl = {
 
     /**
      * @constant
@@ -19,6 +19,11 @@ const FlowControl = {
      * @default
      */
     MERGE_DELIM: "\\n",
+    /**
+     * @constant
+     * @default
+     */
+    FORK_IGNORE_ERRORS: false,
     
     /**
      * Fork operation.
@@ -26,47 +31,55 @@ const FlowControl = {
      * @param {Object} state - The current state of the recipe.
      * @param {number} state.progress - The current position in the recipe.
      * @param {Dish} state.dish - The Dish being operated on.
-     * @param {Operation[]} state.op_list - The list of operations in the recipe.
+     * @param {Operation[]} state.opList - The list of operations in the recipe.
      * @returns {Object} The updated state of the recipe.
      */
-    run_fork: function(state) {
-        var op_list     = state.op_list,
-            input_type  = op_list[state.progress].input_type,
-            output_type = op_list[state.progress].output_type,
-            input       = state.dish.get(input_type),
-            ings        = op_list[state.progress].get_ing_values(),
-            split_delim = ings[0],
-            merge_delim = ings[1],
-            sub_op_list = [],
-            inputs      = [];
+    runFork: function(state) {
+        var opList       = state.opList,
+            inputType    = opList[state.progress].inputType,
+            outputType   = opList[state.progress].outputType,
+            input        = state.dish.get(inputType),
+            ings         = opList[state.progress].getIngValues(),
+            splitDelim   = ings[0],
+            mergeDelim   = ings[1],
+            ignoreErrors = ings[2],
+            subOpList    = [],
+            inputs       = [];
         
         if (input)
-            inputs = input.split(split_delim);
+            inputs = input.split(splitDelim);
         
-        // Create sub_op_list for each tranche to operate on
+        // Create subOpList for each tranche to operate on
         // (all remaining operations unless we encounter a Merge)
-        for (var i = state.progress + 1; i < op_list.length; i++) {
-            if (op_list[i].name === "Merge" && !op_list[i].is_disabled()) {
+        for (var i = state.progress + 1; i < opList.length; i++) {
+            if (opList[i].name === "Merge" && !opList[i].isDisabled()) {
                 break;
             } else {
-                sub_op_list.push(op_list[i]);
+                subOpList.push(opList[i]);
             }
         }
         
         var recipe = new Recipe(),
             output = "",
-            progress;
+            progress = 0;
             
-        recipe.add_operations(sub_op_list);
+        recipe.addOperations(subOpList);
         
         // Run recipe over each tranche
         for (i = 0; i < inputs.length; i++) {
-            var dish = new Dish(inputs[i], input_type);
-            progress = recipe.execute(dish, 0);
-            output += dish.get(output_type) + merge_delim;
+            var dish = new Dish(inputs[i], inputType);
+            try {
+                progress = recipe.execute(dish, 0);
+            } catch(err) {
+                if (!ignoreErrors) {
+                    throw err;
+                }
+                progress = err.progress + 1;
+            }
+            output += dish.get(outputType) + mergeDelim;
         }
         
-        state.dish.set(output, output_type);
+        state.dish.set(output, outputType);
         state.progress += progress;
         return state;
     },
@@ -78,10 +91,10 @@ const FlowControl = {
      * @param {Object} state - The current state of the recipe.
      * @param {number} state.progress - The current position in the recipe.
      * @param {Dish} state.dish - The Dish being operated on.
-     * @param {Operation[]} state.op_list - The list of operations in the recipe.
+     * @param {Operation[]} state.opList - The list of operations in the recipe.
      * @returns {Object} The updated state of the recipe.
      */
-    run_merge: function(state) {
+    runMerge: function(state) {
         // No need to actually do anything here. The fork operation will
         // merge when it sees this operation.
         return state;
@@ -105,21 +118,22 @@ const FlowControl = {
      * @param {Object} state - The current state of the recipe.
      * @param {number} state.progress - The current position in the recipe.
      * @param {Dish} state.dish - The Dish being operated on.
-     * @param {Operation[]} state.op_list - The list of operations in the recipe.
-     * @param {number} state.num_jumps - The number of jumps taken so far.
+     * @param {Operation[]} state.opList - The list of operations in the recipe.
+     * @param {number} state.numJumps - The number of jumps taken so far.
      * @returns {Object} The updated state of the recipe.
      */
-    run_jump: function(state) {
-        var ings      = state.op_list[state.progress].get_ing_values(),
-            jump_num  = ings[0],
-            max_jumps = ings[1];
+    runJump: function(state) {
+        var ings     = state.opList[state.progress].getIngValues(),
+            jumpNum  = ings[0],
+            maxJumps = ings[1];
         
-        if (state.num_jumps >= max_jumps) {
-            throw "Reached maximum jumps, sorry!";
+        if (state.numJumps >= maxJumps) {
+            state.progress++;
+            return state;
         }
         
-        state.progress += jump_num;
-        state.num_jumps++;
+        state.progress += jumpNum;
+        state.numJumps++;
         return state;
     },
     
@@ -130,24 +144,25 @@ const FlowControl = {
      * @param {Object} state - The current state of the recipe.
      * @param {number} state.progress - The current position in the recipe.
      * @param {Dish} state.dish - The Dish being operated on.
-     * @param {Operation[]} state.op_list - The list of operations in the recipe.
-     * @param {number} state.num_jumps - The number of jumps taken so far.
+     * @param {Operation[]} state.opList - The list of operations in the recipe.
+     * @param {number} state.numJumps - The number of jumps taken so far.
      * @returns {Object} The updated state of the recipe.
      */
-    run_cond_jump: function(state) {
-        var ings      = state.op_list[state.progress].get_ing_values(),
-            dish      = state.dish,
-            regex_str = ings[0],
-            jump_num  = ings[1],
-            max_jumps = ings[2];
+    runCondJump: function(state) {
+        var ings     = state.opList[state.progress].getIngValues(),
+            dish     = state.dish,
+            regexStr = ings[0],
+            jumpNum  = ings[1],
+            maxJumps = ings[2];
         
-        if (state.num_jumps >= max_jumps) {
-            throw "Reached maximum jumps, sorry!";
+        if (state.numJumps >= maxJumps) {
+            state.progress++;
+            return state;
         }
         
-        if (regex_str !== "" && dish.get(Dish.STRING).search(regex_str) > -1) {
-            state.progress += jump_num;
-            state.num_jumps++;
+        if (regexStr !== "" && dish.get(Dish.STRING).search(regexStr) > -1) {
+            state.progress += jumpNum;
+            state.numJumps++;
         }
         
         return state;
@@ -160,11 +175,11 @@ const FlowControl = {
      * @param {Object} state - The current state of the recipe.
      * @param {number} state.progress - The current position in the recipe.
      * @param {Dish} state.dish - The Dish being operated on.
-     * @param {Operation[]} state.op_list - The list of operations in the recipe.
+     * @param {Operation[]} state.opList - The list of operations in the recipe.
      * @returns {Object} The updated state of the recipe.
      */
-    run_return: function(state) {
-        state.progress = state.op_list.length;
+    runReturn: function(state) {
+        state.progress = state.opList.length;
         return state;
     },
     

+ 16 - 16
src/js/core/Ingredient.js

@@ -6,15 +6,15 @@
  * @license Apache-2.0
  *
  * @class
- * @param {Object} ingredient_config
+ * @param {Object} ingredientConfig
  */
-var Ingredient = function(ingredient_config) {
+var Ingredient = function(ingredientConfig) {
     this.name  = "";
     this.type  = "";
     this.value = null;
     
-    if (ingredient_config) {
-        this._parse_config(ingredient_config);
+    if (ingredientConfig) {
+        this._parseConfig(ingredientConfig);
     }
 };
 
@@ -23,11 +23,11 @@ var Ingredient = function(ingredient_config) {
  * Reads and parses the given config.
  *
  * @private
- * @param {Object} ingredient_config
+ * @param {Object} ingredientConfig
  */
-Ingredient.prototype._parse_config = function(ingredient_config) {
-    this.name = ingredient_config.name;
-    this.type = ingredient_config.type;
+Ingredient.prototype._parseConfig = function(ingredientConfig) {
+    this.name = ingredientConfig.name;
+    this.type = ingredientConfig.type;
 };
 
 
@@ -36,7 +36,7 @@ Ingredient.prototype._parse_config = function(ingredient_config) {
  *
  * @returns {*}
  */
-Ingredient.prototype.get_config = function() {
+Ingredient.prototype.getConfig = function() {
     return this.value;
 };
 
@@ -46,7 +46,7 @@ Ingredient.prototype.get_config = function() {
  *
  * @param {*} value
  */
-Ingredient.prototype.set_value = function(value) {
+Ingredient.prototype.setValue = function(value) {
     this.value = Ingredient.prepare(value, this.type);
 };
 
@@ -61,14 +61,14 @@ Ingredient.prototype.set_value = function(value) {
 */
 Ingredient.prepare = function(data, type) {
     switch (type) {
-        case "binary_string":
-        case "binary_short_string":
-        case "editable_option":
-            return Utils.parse_escaped_chars(data);
-        case "byte_array":
+        case "binaryString":
+        case "binaryShortString":
+        case "editableOption":
+            return Utils.parseEscapedChars(data);
+        case "byteArray":
             if (typeof data == "string") {
                 data = data.replace(/\s+/g, "");
-                return Utils.hex_to_byte_array(data);
+                return Utils.hexToByteArray(data);
             } else {
                 return data;
             }

+ 53 - 53
src/js/core/Operation.js

@@ -6,23 +6,23 @@
  * @license Apache-2.0
  *
  * @class
- * @param {string} operation_name
- * @param {Object} operation_config
+ * @param {string} operationName
+ * @param {Object} operationConfig
  */
-var Operation = function(operation_name, operation_config) {
-    this.name              = operation_name;
-    this.description       = "";
-    this.input_type        = -1;
-    this.output_type       = -1;
-    this.run               = null;
-    this.highlight         = null;
-    this.highlight_reverse = null;
-    this.breakpoint        = false;
-    this.disabled          = false;
-    this.ing_list          = [];
+var Operation = function(operationName, operationConfig) {
+    this.name             = operationName;
+    this.description      = "";
+    this.inputType        = -1;
+    this.outputType       = -1;
+    this.run              = null;
+    this.highlight        = null;
+    this.highlightReverse = null;
+    this.breakpoint       = false;
+    this.disabled         = false;
+    this.ingList          = [];
     
-    if (operation_config) {
-        this._parse_config(operation_config);
+    if (operationConfig) {
+        this._parseConfig(operationConfig);
     }
 };
 
@@ -31,21 +31,21 @@ var Operation = function(operation_name, operation_config) {
  * Reads and parses the given config.
  *
  * @private
- * @param {Object} operation_config
+ * @param {Object} operationConfig
  */
-Operation.prototype._parse_config = function(operation_config) {
-    this.description       = operation_config.description;
-    this.input_type        = Dish.type_enum(operation_config.input_type);
-    this.output_type       = Dish.type_enum(operation_config.output_type);
-    this.run               = operation_config.run;
-    this.highlight         = operation_config.highlight;
-    this.highlight_reverse = operation_config.highlight_reverse;
-    this.flow_control      = operation_config.flow_control;
-
-    for (var a = 0; a < operation_config.args.length; a++) {
-        var ingredient_config = operation_config.args[a];
-        var ingredient = new Ingredient(ingredient_config);
-        this.add_ingredient(ingredient);
+Operation.prototype._parseConfig = function(operationConfig) {
+    this.description      = operationConfig.description;
+    this.inputType        = Dish.typeEnum(operationConfig.inputType);
+    this.outputType       = Dish.typeEnum(operationConfig.outputType);
+    this.run              = operationConfig.run;
+    this.highlight        = operationConfig.highlight;
+    this.highlightReverse = operationConfig.highlightReverse;
+    this.flowControl      = operationConfig.flowControl;
+
+    for (var a = 0; a < operationConfig.args.length; a++) {
+        var ingredientConfig = operationConfig.args[a];
+        var ingredient = new Ingredient(ingredientConfig);
+        this.addIngredient(ingredient);
     }
 };
 
@@ -55,19 +55,19 @@ Operation.prototype._parse_config = function(operation_config) {
  *
  * @returns {Object}
  */
-Operation.prototype.get_config = function() {
-    var ingredient_config = [];
+Operation.prototype.getConfig = function() {
+    var ingredientConfig = [];
     
-    for (var o = 0; o < this.ing_list.length; o++) {
-        ingredient_config.push(this.ing_list[o].get_config());
+    for (var o = 0; o < this.ingList.length; o++) {
+        ingredientConfig.push(this.ingList[o].getConfig());
     }
     
-    var operation_config = {
+    var operationConfig = {
         "op": this.name,
-        "args": ingredient_config
+        "args": ingredientConfig
     };
     
-    return operation_config;
+    return operationConfig;
 };
 
 
@@ -76,19 +76,19 @@ Operation.prototype.get_config = function() {
  *
  * @param {Ingredient} ingredient
  */
-Operation.prototype.add_ingredient = function(ingredient) {
-    this.ing_list.push(ingredient);
+Operation.prototype.addIngredient = function(ingredient) {
+    this.ingList.push(ingredient);
 };
 
 
 /**
  * Set the Ingredient values for this Operation.
  *
- * @param {Object[]} ing_values
+ * @param {Object[]} ingValues
  */
-Operation.prototype.set_ing_values = function(ing_values) {
-    for (var i = 0; i < ing_values.length; i++) {
-        this.ing_list[i].set_value(ing_values[i]);
+Operation.prototype.setIngValues = function(ingValues) {
+    for (var i = 0; i < ingValues.length; i++) {
+        this.ingList[i].setValue(ingValues[i]);
     }
 };
 
@@ -98,12 +98,12 @@ Operation.prototype.set_ing_values = function(ing_values) {
  *
  * @returns {Object[]}
  */
-Operation.prototype.get_ing_values = function() {
-    var ing_values = [];
-    for (var i = 0; i < this.ing_list.length; i++) {
-        ing_values.push(this.ing_list[i].value);
+Operation.prototype.getIngValues = function() {
+    var ingValues = [];
+    for (var i = 0; i < this.ingList.length; i++) {
+        ingValues.push(this.ingList[i].value);
     }
-    return ing_values;
+    return ingValues;
 };
 
 
@@ -112,7 +112,7 @@ Operation.prototype.get_ing_values = function() {
  *
  * @param {boolean} value
  */
-Operation.prototype.set_breakpoint = function(value) {
+Operation.prototype.setBreakpoint = function(value) {
     this.breakpoint = !!value;
 };
 
@@ -122,7 +122,7 @@ Operation.prototype.set_breakpoint = function(value) {
  *
  * @returns {boolean}
  */
-Operation.prototype.is_breakpoint = function() {
+Operation.prototype.isBreakpoint = function() {
     return this.breakpoint;
 };
 
@@ -132,7 +132,7 @@ Operation.prototype.is_breakpoint = function() {
  *
  * @param {boolean} value
  */
-Operation.prototype.set_disabled = function(value) {
+Operation.prototype.setDisabled = function(value) {
     this.disabled = !!value;
 };
 
@@ -142,7 +142,7 @@ Operation.prototype.set_disabled = function(value) {
  *
  * @returns {boolean}
  */
-Operation.prototype.is_disabled = function() {
+Operation.prototype.isDisabled = function() {
     return this.disabled;
 };
 
@@ -152,6 +152,6 @@ Operation.prototype.is_disabled = function() {
  *
  * @returns {boolean}
  */
-Operation.prototype.is_flow_control = function() {
-    return this.flow_control;
+Operation.prototype.isFlowControl = function() {
+    return this.flowControl;
 };

+ 64 - 65
src/js/core/Recipe.js

@@ -6,13 +6,13 @@
  * @license Apache-2.0
  *
  * @class
- * @param {Object} recipe_config
+ * @param {Object} recipeConfig
  */
-var Recipe = function(recipe_config) {
-    this.op_list = [];
+var Recipe = function(recipeConfig) {
+    this.opList = [];
     
-    if (recipe_config) {
-        this._parse_config(recipe_config);
+    if (recipeConfig) {
+        this._parseConfig(recipeConfig);
     }
 };
 
@@ -21,17 +21,17 @@ var Recipe = function(recipe_config) {
  * Reads and parses the given config.
  *
  * @private
- * @param {Object} recipe_config
+ * @param {Object} recipeConfig
  */
-Recipe.prototype._parse_config = function(recipe_config) {
-    for (var c = 0; c < recipe_config.length; c++) {
-        var operation_name = recipe_config[c].op;
-        var operation_config = OperationConfig[operation_name];
-        var operation = new Operation(operation_name, operation_config);
-        operation.set_ing_values(recipe_config[c].args);
-        operation.set_breakpoint(recipe_config[c].breakpoint);
-        operation.set_disabled(recipe_config[c].disabled);
-        this.add_operation(operation);
+Recipe.prototype._parseConfig = function(recipeConfig) {
+    for (var c = 0; c < recipeConfig.length; c++) {
+        var operationName = recipeConfig[c].op;
+        var operationConfig = OperationConfig[operationName];
+        var operation = new Operation(operationName, operationConfig);
+        operation.setIngValues(recipeConfig[c].args);
+        operation.setBreakpoint(recipeConfig[c].breakpoint);
+        operation.setDisabled(recipeConfig[c].disabled);
+        this.addOperation(operation);
     }
 };
 
@@ -41,14 +41,14 @@ Recipe.prototype._parse_config = function(recipe_config) {
  *
  * @returns {*}
  */
-Recipe.prototype.get_config = function() {
-    var recipe_config = [];
+Recipe.prototype.getConfig = function() {
+    var recipeConfig = [];
     
-    for (var o = 0; o < this.op_list.length; o++) {
-        recipe_config.push(this.op_list[o].get_config());
+    for (var o = 0; o < this.opList.length; o++) {
+        recipeConfig.push(this.opList[o].getConfig());
     }
     
-    return recipe_config;
+    return recipeConfig;
 };
 
 
@@ -57,8 +57,8 @@ Recipe.prototype.get_config = function() {
  *
  * @param {Operation} operation
  */
-Recipe.prototype.add_operation = function(operation) {
-    this.op_list.push(operation);
+Recipe.prototype.addOperation = function(operation) {
+    this.opList.push(operation);
 };
 
 
@@ -67,8 +67,8 @@ Recipe.prototype.add_operation = function(operation) {
  *
  * @param {Operation[]} operations
  */
-Recipe.prototype.add_operations = function(operations) {
-    this.op_list = this.op_list.concat(operations);
+Recipe.prototype.addOperations = function(operations) {
+    this.opList = this.opList.concat(operations);
 };
 
 
@@ -78,9 +78,9 @@ Recipe.prototype.add_operations = function(operations) {
  * @param {number} position - The index of the Operation
  * @param {boolean} value
  */
-Recipe.prototype.set_breakpoint = function(position, value) {
+Recipe.prototype.setBreakpoint = function(position, value) {
     try {
-        this.op_list[position].set_breakpoint(value);
+        this.opList[position].setBreakpoint(value);
     } catch (err) {
         // Ignore index error
     }
@@ -93,9 +93,9 @@ Recipe.prototype.set_breakpoint = function(position, value) {
  *
  * @param {number} pos
  */
-Recipe.prototype.remove_breaks_up_to = function(pos) {
+Recipe.prototype.removeBreaksUpTo = function(pos) {
     for (var i = 0; i < pos; i++) {
-        this.op_list[i].set_breakpoint(false);
+        this.opList[i].setBreakpoint(false);
     }
 };
 
@@ -105,9 +105,9 @@ Recipe.prototype.remove_breaks_up_to = function(pos) {
  *
  * @returns {boolean}
  */
-Recipe.prototype.contains_flow_control = function() {
-    for (var i = 0; i < this.op_list.length; i++) {
-        if (this.op_list[i].is_flow_control()) return true;
+Recipe.prototype.containsFlowControl = function() {
+    for (var i = 0; i < this.opList.length; i++) {
+        if (this.opList[i].isFlowControl()) return true;
     }
     return false;
 };
@@ -117,17 +117,17 @@ Recipe.prototype.contains_flow_control = function() {
  * Returns the index of the last Operation index that will be executed, taking into account disabled
  * Operations and breakpoints.
  *
- * @param {number} [start_index=0] - The index to start searching from
+ * @param {number} [startIndex=0] - The index to start searching from
  * @returns (number}
  */
-Recipe.prototype.last_op_index = function(start_index) {
-    var i = start_index + 1 || 0,
+Recipe.prototype.lastOpIndex = function(startIndex) {
+    var i = startIndex + 1 || 0,
         op;
         
-    for (; i < this.op_list.length; i++) {
-        op = this.op_list[i];
-        if (op.is_disabled()) return i-1;
-        if (op.is_breakpoint()) return i-1;
+    for (; i < this.opList.length; i++) {
+        op = this.opList[i];
+        if (op.isDisabled()) return i-1;
+        if (op.isBreakpoint()) return i-1;
     }
     
     return i-1;
@@ -138,59 +138,58 @@ Recipe.prototype.last_op_index = function(start_index) {
  * Executes each operation in the recipe over the given Dish.
  *
  * @param {Dish} dish
- * @param {number} [start_from=0] - The index of the Operation to start executing from
+ * @param {number} [startFrom=0] - The index of the Operation to start executing from
  * @returns {number} - The final progress through the recipe
  */
-Recipe.prototype.execute = function(dish, start_from) {
-    start_from = start_from || 0;
-    var op, input, output, num_jumps = 0;
+Recipe.prototype.execute = function(dish, startFrom) {
+    startFrom = startFrom || 0;
+    var op, input, output, numJumps = 0;
     
-    for (var i = start_from; i < this.op_list.length; i++) {
-        op = this.op_list[i];
-        if (op.is_disabled()) {
+    for (var i = startFrom; i < this.opList.length; i++) {
+        op = this.opList[i];
+        if (op.isDisabled()) {
             continue;
         }
-        if (op.is_breakpoint()) {
+        if (op.isBreakpoint()) {
             return i;
         }
         
         try {
-            input = dish.get(op.input_type);
+            input = dish.get(op.inputType);
             
-            if (op.is_flow_control()) {
+            if (op.isFlowControl()) {
                 // Package up the current state
                 var state = {
                     "progress" : i,
                     "dish"     : dish,
-                    "op_list"  : this.op_list,
-                    "num_jumps" : num_jumps
+                    "opList"  : this.opList,
+                    "numJumps" : numJumps
                 };
                 
                 state = op.run(state);
                 i = state.progress;
-                num_jumps = state.num_jumps;
+                numJumps = state.numJumps;
             } else {
-                output = op.run(input, op.get_ing_values());
-                dish.set(output, op.output_type);
+                output = op.run(input, op.getIngValues());
+                dish.set(output, op.outputType);
             }
         } catch (err) {
             var e = typeof err == "string" ? { message: err } : err;
 
             e.progress = i;
-            e.display_str = op.name + " - ";
             if (e.fileName) {
-                e.display_str += e.name + " in " + e.fileName +
-                    " on line " + e.lineNumber +
-                    ".<br><br>Message: " + e.message;
+                e.displayStr = op.name + " - " + e.name + " in " +
+                    e.fileName + " on line " + e.lineNumber +
+                    ".<br><br>Message: " + (e.displayStr || e.message);
             } else {
-                e.display_str += e.message;
+                e.displayStr = op.name + " - " + (e.displayStr || e.message);
             }
             
             throw e;
         }
     }
     
-    return this.op_list.length;
+    return this.opList.length;
 };
 
 
@@ -199,17 +198,17 @@ Recipe.prototype.execute = function(dish, start_from) {
  *
  * @returns {string}
  */
-Recipe.prototype.to_string = function() {
-    return JSON.stringify(this.get_config());
+Recipe.prototype.toString = function() {
+    return JSON.stringify(this.getConfig());
 };
 
 
 /**
  * Creates a Recipe from a given configuration string.
  *
- * @param {string} recipe_str
+ * @param {string} recipeStr
  */
-Recipe.prototype.from_string = function(recipe_str) {
-    var recipe_config = JSON.parse(recipe_str);
-    this._parse_config(recipe_config);
+Recipe.prototype.fromString = function(recipeStr) {
+    var recipeConfig = JSON.parse(recipeStr);
+    this._parseConfig(recipeConfig);
 };

File diff suppressed because it is too large
+ 18 - 18
src/js/core/Utils.js


+ 768 - 0
src/js/lib/cryptoapi/crypto-api.js

@@ -0,0 +1,768 @@
+/** @license
+========================================================================
+  Crypto API for JavaScript - https://github.com/nf404/crypto-api
+  
+  The MIT License (MIT)
+
+  Copyright (c) 2015 nf404
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/*global module, require */
+(/**
+ * @param {Object} root
+ * @returns {CryptoApi}
+ */
+    function (root) {
+    'use strict';
+    /**
+     * @class CryptoApi
+     * @classdesc Main class
+     * @public
+     */
+    var CryptoApi = function cryptoApi () {
+        /**
+         * @property Hashers
+         * @type {Hashers}
+         */
+        this.Hashers = new Hashers();
+        /**
+         * @property Encodes
+         * @type {Encodes}
+         */
+        this.Encodes = new Encodes();
+        /**
+         * @property Macs
+         * @type {Macs}
+         */
+        this.Macs = new Macs();
+        /**
+         * @property Tools
+         * @type {Tools}
+         */
+        this.Tools = new Tools();
+    };
+
+    /**
+     * @interface HasherInterface
+     * @classdesc All hashers MUST implement this interface
+     * @public
+     */
+    var HasherInterface = function () {};
+    /**
+     * @memberOf HasherInterface
+     * @constructor
+     */
+    HasherInterface.prototype.constructor = function constructor() {};
+    /**
+     * @desc Process ready block
+     * @memberOf HasherInterface
+     * @method processBlock
+     * @param {number[]} block
+     */
+    HasherInterface.prototype.processBlock = function processBlock(block) {};
+    /**
+     * Update message
+     * @memberOf HasherInterface
+     * @method update
+     * @param {string} message
+     */
+    HasherInterface.prototype.update = function update(message) {};
+    /**
+     * @desc Process last block and return hash
+     * @memberOf HasherInterface
+     * @method finalize
+     * @return {HashArray} hash
+     */
+    HasherInterface.prototype.finalize = function finalize() {};
+
+    /**
+     * @class BaseHasher
+     * @param {string} name
+     * @param {Object} options
+     * @public
+     */
+    var BaseHasher = function(name, options) {};
+    BaseHasher.prototype.constructor = function (name, options) {
+        /**
+         * @desc Hasher name
+         * @property name
+         * @type {string}
+         */
+        this.name = name;
+        /**
+         * @desc All algorithm variables that changed during process
+         * @property state
+         * @type {Object}
+         */
+        this.state = {};
+        /**
+         * @desc Unprocessed Message
+         * @memberof! BaseHasher#
+         * @alias state.message
+         * @type {number[]}
+         */
+        this.state.message = [];
+        /**
+         * @desc Length of message
+         * @memberof! BaseHasher#
+         * @alias state.length
+         * @type {number}
+         */
+        this.state.length = 0;
+        /**
+         * @memberof! BaseHasher#
+         * @alias state.options
+         * @type {Object}
+         */
+        this.state.options = options;
+        this.blockUnits = [];
+    };
+
+    /**
+     *  Size of unit in bytes (4 = 32 bits)
+     * @memberOf BaseHasher
+     * @member {number} unitSize
+     * @static
+     */
+    BaseHasher.prototype.unitSize = 4;
+    /**
+     * Bytes order in unit
+     *   0 - normal
+     *   1 - reverse
+     * @memberOf BaseHasher
+     * @member {number} unitOrder
+     * @static
+     */
+    BaseHasher.prototype.unitOrder = 0;
+    /**
+     * Size of block in units
+     * @memberOf BaseHasher
+     * @member {number} blockSize
+     * @static
+     */
+    BaseHasher.prototype.blockSize = 16;
+    /**
+     * Return current state
+     * @memberOf BaseHasher
+     * @method getState
+     * @returns {Object}
+     */
+    BaseHasher.prototype.getState = function getState() {
+        return JSON.parse(JSON.stringify(this.state));
+    };
+    /**
+     * Set state
+     * @memberOf BaseHasher
+     * @method setState
+     * @param {Object} state
+     * @return {HasherInterface}
+     */
+    BaseHasher.prototype.setState = function setState(state) {
+        this.state = state;
+        return this;
+    };
+
+    /**
+     * Update message
+     * @memberOf BaseHasher
+     * @method update
+     * @param {string} message
+     */
+    BaseHasher.prototype.update = function update(message) {
+      var l = 0;
+      for (var i = 0, msgLen = message.length; i < msgLen; i++) {
+        var charcode = message.charCodeAt(i);
+        if (charcode < 0x80) {
+          this.state.message.push(charcode);
+          l += 1;
+        }
+        else if (charcode < 0x800) {
+          this.state.message.push(0xc0 | (charcode >> 6),
+            0x80 | (charcode & 0x3f));
+          l += 2;
+        }
+        else if (charcode < 0xd800 || charcode >= 0xe000) {
+          this.state.message.push(0xe0 | (charcode >> 12),
+            0x80 | ((charcode >> 6) & 0x3f),
+            0x80 | (charcode & 0x3f));
+          l += 3;
+        }
+        // surrogate pair
+        else {
+          i++;
+          // UTF-16 encodes 0x10000-0x10FFFF by
+          // subtracting 0x10000 and splitting the
+          // 20 bits of 0x0-0xFFFFF into two halves
+          charcode = 0x10000 + (((charcode & 0x3ff) << 10)
+            | (message.charCodeAt(i) & 0x3ff));
+          this.state.message.push(0xf0 | (charcode >> 18),
+            0x80 | ((charcode >> 12) & 0x3f),
+            0x80 | ((charcode >> 6) & 0x3f),
+            0x80 | (charcode & 0x3f));
+          l += 4;
+        }
+      }
+      this.state.length += l;
+
+      this.process();
+    };
+
+    /**
+     * Update message from array
+     * @memberOf BaseHasher
+     * @method updateFromArray
+     * @param {number[]} message
+     * @return {BaseHasher}
+     */
+    BaseHasher.prototype.updateFromArray = function updateFromArray(message) {
+      this.state.length += message.length;
+      this.state.message = this.state.message.concat(message);
+      this.process();
+      return this;
+    };
+
+    /**
+     * Process ready blocks
+     * @memberOf BaseHasher
+     * @method process
+     */
+    BaseHasher.prototype.process = function process() {
+      while (this.state.message.length >= this.blockSize * this.unitSize) {
+        var j = 0, b = 0, block = this.state.message.splice(0, this.blockSize * this.unitSize);
+        if (this.unitSize > 1) {
+          this.blockUnits = [];
+          for (var i = 0, u = 0; i < block.length; i += this.unitSize, u++) {
+            if (this.unitOrder === 1) {
+              for (j = this.unitSize - 1, b = 0; j >= 0; j--, b += 8) {
+                this.blockUnits[u] |= (block[i + j] << b);
+              }
+            } else {
+              for (j = 0, b = 0; j < this.unitSize; j++, b += 8) {
+                this.blockUnits[u] |= (block[i + j] << b);
+              }
+            }
+          }
+          this.processBlock(this.blockUnits);
+        } else {
+          this.processBlock(block);
+        }
+      }
+    };
+    /**
+     * @memberOf CryptoApi
+     * @member {BaseHasher} BaseHasher
+     */
+    CryptoApi.prototype.BaseHasher = BaseHasher;
+
+    /**
+     * @class Hasher8
+     * @desc Hasher for 32 bit little endian blocks
+     * @extends BaseHasher
+     * @param {string} name
+     * @param {Object} options
+     * @public
+     */
+    var Hasher8 = function (name, options) {
+      this.constructor(name, options);
+    };
+    Hasher8.prototype = Object.create(BaseHasher.prototype);
+
+    /**
+     * @desc Normal order of bytes
+     * @memberOf Hasher8#
+     * @member {number} unitOrder
+     */
+    Hasher8.prototype.unitOrder = 0;
+    /**
+     * @desc Size of unit = 1 byte
+     * @memberOf Hasher8#
+     * @member {number} unitSize
+     */
+    Hasher8.prototype.unitSize = 1;
+
+    /**
+     * @memberOf Hasher8
+     * @constructor
+     * @param {string} name
+     * @param {Object} options
+     */
+    Hasher8.prototype.constructor = function (name, options) {
+      BaseHasher.prototype.constructor.call(this, name, options);
+    };
+    /**
+     * Process ready blocks
+     * @memberOf Hasher8
+     * @method process
+     */
+    Hasher8.prototype.process = function process() {
+      while (this.state.message.length >= this.blockSize * this.unitSize) {
+        var block = this.state.message.splice(0, this.blockSize * this.unitSize);
+        this.blockUnits = [];
+        for (var i = 0; i < this.blockSize; i++) {
+          this.blockUnits[i] = (block[i]);
+        }
+        this.processBlock(this.blockUnits);
+      }
+    };
+
+    /**
+     * @memberOf CryptoApi
+     * @member {Hasher8} Hasher8
+     */
+    CryptoApi.prototype.Hasher8 = Hasher8;
+
+  /**
+     * @class Hasher32le
+     * @desc Hasher for 32 bit little endian blocks
+     * @extends BaseHasher
+     * @param {string} name
+     * @param {Object} options
+     * @public
+     */
+    var Hasher32le = function (name, options) {
+      this.constructor(name, options);
+    };
+    Hasher32le.prototype = Object.create(BaseHasher.prototype);
+
+    Hasher32le.prototype.unitOrder = 0; // Normal order of bytes
+
+    /**
+     * @memberOf Hasher32le
+     * @constructor
+     * @param {string} name
+     * @param {Object} options
+     */
+    Hasher32le.prototype.constructor = function (name, options) {
+      BaseHasher.prototype.constructor.call(this, name, options);
+    };
+    /**
+     * Process ready blocks
+     * @memberOf Hasher32le
+     * @method process
+     */
+    Hasher32le.prototype.process = function process() {
+      while (this.state.message.length >= this.blockSize * this.unitSize) {
+        var block = this.state.message.splice(0, this.blockSize * this.unitSize);
+        this.blockUnits = [];
+        for (var i = 0, b = 0; i < this.blockSize; i++, b+=4) {
+          this.blockUnits[i] = (block[b]);
+          this.blockUnits[i] |= (block[b + 1] << 8);
+          this.blockUnits[i] |= (block[b + 2] << 16);
+          this.blockUnits[i] |= (block[b + 3] << 24);
+        }
+        this.processBlock(this.blockUnits);
+      }
+    };
+
+    /**
+     * @memberOf CryptoApi
+     * @member {Hasher32le} Hasher32
+     */
+    CryptoApi.prototype.Hasher32le = Hasher32le;
+
+    /**
+     * @class Hasher32be
+     * @desc Hasher for 32 bit big endian blocks
+     * @extends BaseHasher
+     * @param {string} name
+     * @param {Object} options
+     * @public
+     */
+    var Hasher32be = function (name, options) {
+      this.constructor(name, options);
+    };
+    Hasher32be.prototype = Object.create(BaseHasher.prototype);
+
+    Hasher32be.prototype.unitOrder = 1; // Reverse order of bytes
+
+    /**
+     * @memberOf Hasher32be
+     * @constructor
+     * @param {string} name
+     * @param {Object} options
+     */
+    Hasher32be.prototype.constructor = function (name, options) {
+        BaseHasher.prototype.constructor.call(this, name, options);
+    };
+    /**
+     * Process ready blocks
+     * @memberOf Hasher32be
+     * @method process
+     */
+    Hasher32be.prototype.process = function process() {
+      while (this.state.message.length >= this.blockSize * this.unitSize) {
+        var block = this.state.message.splice(0, this.blockSize * this.unitSize);
+        this.blockUnits = [];
+        for (var i = 0, b = 0; i < this.blockSize; i++, b+=4) {
+          this.blockUnits[i] = (block[b] << 24);
+          this.blockUnits[i] |= (block[b + 1] << 16);
+          this.blockUnits[i] |= (block[b + 2] << 8);
+          this.blockUnits[i] |= (block[b + 3]);
+        }
+        this.processBlock(this.blockUnits);
+      }
+    };
+
+    /**
+     * @memberOf CryptoApi
+     * @member {Hasher32be} Hasher32be
+     */
+    CryptoApi.prototype.Hasher32be = Hasher32be;
+
+    /**
+     * @interface MacInterface
+     * @classdesc All coders MUST implement this interface
+     * @public
+     */
+    var MacInterface = function () {};
+    /**
+     * @memberOf MacInterface
+     * @param {string|number[]} key
+     * @param {string} hasher
+     * @param {Object} options
+     * @constructor
+     */
+    MacInterface.prototype.constructor = function constructor(key, hasher, options) {};
+    /**
+     * @desc Process ready block
+     * @memberOf MacInterface
+     * @method processBlock
+     * @param {number[]} block
+     */
+    MacInterface.prototype.processBlock = function processBlock(block) {};
+    /**
+     * Update message
+     * @memberOf MacInterface
+     * @method update
+     * @param {string|number[]} message
+     * @return {MacInterface}
+     */
+    MacInterface.prototype.update = function update(message) {};
+    /**
+     * @desc Process last block and return hash
+     * @memberOf MacInterface
+     * @method finalize
+     * @return {HashArray} hash
+     */
+    MacInterface.prototype.finalize = function finalize() {};
+
+    /**
+     * @class BaseMac
+     * @extends BaseHasher
+     * @param {string|number[]} key
+     * @param {string} hasher
+     * @param {Object} options
+     * @public
+     */
+    var BaseMac = function(key, hasher, options) {};
+    BaseMac.prototype = Object.create(BaseHasher.prototype);
+    BaseMac.prototype.constructor = function (key, hasher, options) {
+        BaseHasher.prototype.constructor.call(this, hasher, options);
+    };
+    /**
+     * @memberOf CryptoApi
+     * @member {BaseMac} BaseMac
+     */
+    CryptoApi.prototype.BaseMac = BaseMac;
+    /**
+     * @interface EncodeInterface
+     * @classdesc All encodes MUST implement this interface
+     * @public
+     */
+    var EncodeInterface = function () {};
+    /**
+     * @memberOf EncodeInterface
+     * @constructor
+     * @param {HashArray} hash
+     */
+    EncodeInterface.prototype.constructor = function constructor(hash) {};
+    /**
+     * @desc Stringify hash
+     * @memberOf EncodeInterface
+     * @method stringify
+     * @returns {string}
+     */
+    EncodeInterface.prototype.stringify = function encode() {};
+
+
+    /**
+     * @class BaseEncode
+     * @desc Encode HashArray
+     * @param {HashArray} hash
+     * @public
+     */
+    var BaseEncode = function (hash) {};
+    /**
+     * @memberOf BaseEncode
+     * @constructor
+     * @param {HashArray} hash
+     */
+    BaseEncode.prototype.constructor = function constructor(hash) {
+        /**
+         * @property hash
+         * @type {HashArray}
+         */
+        this.hash = hash;
+    };
+    /**
+     * @memberOf CryptoApi
+     * @member {BaseEncode} BaseEncode
+     */
+    CryptoApi.prototype.BaseEncode = BaseEncode;
+
+    /**
+     * @class Hashers
+     * @classdesc Collection of hashers
+     */
+    var Hashers = function hashers() {
+        /**
+         * @property hashers
+         * @type {Object}
+         */
+        this.hashers = {};
+    };
+    /**
+     * @memberOf Hashers
+     * @method add
+     * @param {string} name
+     * @param {HasherInterface} hasher
+     */
+    Hashers.prototype.add = function add(name, hasher) {
+        if (hasher === undefined) {
+            throw Error('Error adding hasher: ' + name);
+        }
+        this.hashers[name] = hasher;
+    };
+    /**
+     * @memberOf Hashers
+     * @method add
+     * @param {string} name
+     * @param {Object} options
+     * @returns {HasherInterface}
+     */
+    Hashers.prototype.get = function get(name, options) {
+        var Hasher = this.hashers[name];
+        if ((Hasher === undefined) && (typeof require !== 'undefined')) {
+            var filename = name;
+            if (filename === 'sha224') {
+                filename = 'sha256';
+            }
+            require('./hasher.' + filename);
+            Hasher = this.hashers[name];
+        }
+        if (Hasher === undefined) {
+            throw Error('No hash algorithm: ' + name);
+        }
+        return new Hasher(name, options);
+    };
+
+    /**
+     * @class Encodes
+     * @classdesc Collection of encodes
+     */
+    var Encodes = function encodes() {
+        /**
+         * @property encodes
+         * @type {Object}
+         */
+        this.encodes = {};
+    };
+    /**
+     * @memberOf Encodes
+     * @method add
+     * @param {string} name
+     * @param {BaseEncode} encode
+     */
+    Encodes.prototype.add = function add(name, encode) {
+        if (encode === undefined) {
+            throw Error('Error adding encode: ' + name);
+        }
+        this.encodes[name] = encode;
+    };
+    /**
+     * @memberOf Encodes
+     * @method get
+     * @param {string} name
+     * @param {HashArray} hash
+     * @returns {BaseEncode}
+     */
+    Encodes.prototype.get = function get(name, hash) {
+        var Encode = this.encodes[name];
+        if ((Encode === undefined) && (typeof require !== 'undefined')) {
+            require('./enc.' + name);
+            Encode = this.encodes[name];
+        }
+        if (Encode === undefined) {
+            throw Error('No encode type: ' + name);
+        }
+        return new Encode(hash);
+    };
+
+    /**
+     * @class Macs
+     * @classdesc Collection of macs
+     */
+    var Macs = function macs() {
+        /**
+         * @property macs
+         * @type {Object}
+         */
+        this.macs = {};
+    };
+    /**
+     * @memberOf Macs
+     * @method add
+     * @param {string} name
+     * @param {BaseMac} mac
+     */
+    Macs.prototype.add = function add(name, mac) {
+        if (mac === undefined) {
+            throw Error('Error adding mac: ' + name);
+        }
+        this.macs[name] = mac;
+    };
+    /**
+     * @memberOf Macs
+     * @method get
+     * @param {string} name
+     * @param {string|number[]} key
+     * @param {string} hasher
+     * @param {Object} options
+     * @returns {MacInterface}
+     */
+    Macs.prototype.get = function get(name, key, hasher, options) {
+        var Mac = this.macs[name];
+        if ((Mac === undefined) && (typeof require !== 'undefined')) {
+            require('./mac.' + name);
+            Mac = this.macs[name];
+        }
+        if (Mac === undefined) {
+            throw Error('No mac type: ' + name);
+        }
+        return new Mac(key, hasher, options);
+    };
+
+    /**
+     * @class Tools
+     * @classdesc Helper with some methods
+     */
+    var Tools = function tools() {};
+    /**
+     * Rotate x to n bits left
+     * @memberOf Tools
+     * @method rotateLeft
+     * @param {number} x
+     * @param {number} n
+     * @returns {number}
+     */
+    Tools.prototype.rotateLeft = function rotateLeft(x, n) {
+        return ((x << n) | (x >>> (32 - n))) | 0;
+    };
+    /**
+     * Rotate x to n bits right
+     * @memberOf Tools
+     * @method rotateLeft
+     * @param {number} x
+     * @param {number} n
+     * @returns {number}
+     */
+    Tools.prototype.rotateRight = function rotateLeft(x, n) {
+        return ((x >>> n) | (x << (32 - n))) | 0;
+    };
+    /**
+     * @class HashArray
+     * @classdesc Array of hash bytes
+     * @instanceof {Array}
+     * @param {number[]} hash
+     * @param {Encodes} Encodes
+     * @public
+     */
+    var HashArray = function (hash, Encodes) {
+        Array.prototype.push.apply(this, hash);
+        /**
+         * @property Encodes
+         * @type {Encodes}
+         */
+        this.Encodes = Encodes;
+    };
+    HashArray.prototype = Object.create(Array.prototype);
+    HashArray.prototype.constructor = HashArray;
+
+    /**
+     * Get hash as string
+     * @param {string} method
+     * @returns {string|*}
+     */
+    HashArray.prototype.stringify = function stringify(method) {
+        return this.Encodes.get(method, this).stringify();
+    };
+
+    /**
+     * Hash message with algo
+     *
+     * @memberof CryptoApi
+     * @method hash
+     * @public
+     * @param {string} algo
+     * @param {string} message
+     * @param {Object} options
+     * @return {HashArray} hash
+     */
+    CryptoApi.prototype.hash = function hash(algo, message, options) {
+      var hash = this.hasher(algo, options);
+      hash.update(message);
+        return hash.finalize();
+    };
+    /**
+     * Get new Hasher object
+     *
+     * @memberof CryptoApi
+     * @method hasher
+     * @public
+     * @param {string} algo
+     * @param {Object} options
+     * @returns {HasherInterface}
+     */
+    CryptoApi.prototype.hasher = function hasher(algo, options) {
+        return this.Hashers.get(algo, options);
+    };
+    /**
+     * Get new MAC object
+     *
+     * @memberof CryptoApi
+     * @method mac
+     * @public
+     * @param {string} algo
+     * @param {string|number[]} key
+     * @param {string} hasher
+     * @param {Object} options
+     * @returns {MacInterface}
+     */
+    CryptoApi.prototype.mac = function mac(algo, key, hasher, options) {
+        return this.Macs.get(algo, key, hasher, options);
+    };
+    /**
+     * Get new HashArray
+     *
+     * @memberof CryptoApi
+     * @method hashArray
+     * @public
+     * @param {number[]} hash
+     * @returns {HashArray}
+     */
+    CryptoApi.prototype.hashArray = function hashArray(hash) {
+        return new HashArray(hash, this.Encodes);
+    };
+    root.CryptoApi = new CryptoApi();
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = root.CryptoApi;
+    } else {
+        return root.CryptoApi;
+    }
+})(this);

+ 113 - 0
src/js/lib/cryptoapi/hasher.md2.js

@@ -0,0 +1,113 @@
+/*global require */
+(/**
+ * @param {CryptoApi} CryptoApi
+ * @returns {Md2}
+ */
+    function (CryptoApi) {
+    'use strict';
+
+    /**
+     * @class Md2
+     * @extends Hasher8
+     * @implements HasherInterface
+     * @desc Md2 hasher
+     */
+    var Md2 = function (name, options) {
+        this.constructor(name, options);
+    };
+    Md2.prototype = Object.create(CryptoApi.Hasher8.prototype);
+    /**
+     * @memberOf Md2
+     * @constructor
+     */
+    Md2.prototype.constructor = function (name, options) {
+        CryptoApi.Hasher8.prototype.constructor.call(this, name, options);
+        /**
+         * @desc Hash state
+         * @memberOf! Md2#
+         * @alias state.hash
+         * @type {number[]}
+         */
+        this.state.hash = new Array(48);
+        /**
+         * @desc Checksum
+         * @memberOf! Md2#
+         * @alias state.checksum
+         * @type {number[]}
+         */
+        this.state.checksum = new Array(16);
+    };
+
+    /**
+     * @desc Constants from Pi
+     * @link https://github.com/e-sushi/MD2-S-box-creator
+     * @memberOf Md2#
+     * @member {number[]} piSubst
+     */
+    Md2.prototype.piSubst = [
+        0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
+        0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
+        0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
+        0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
+        0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
+        0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
+        0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
+        0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
+        0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
+        0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
+        0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
+        0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
+        0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
+        0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
+        0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
+        0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14];
+
+    /**
+     * @memberOf Md2
+     * @method processBlock
+     * @param {number[]} block
+     */
+    Md2.prototype.processBlock = function processBlock(block) {
+        // Append hash
+        for (var i = 0; i < 16; i++) {
+            this.state.hash[16 + i] = block[i];
+            this.state.hash[32 + i] = this.state.hash[16 + i] ^ this.state.hash[i];
+        }
+
+        // 18 Rounds
+        var t = 0;
+        for (i = 0; i < 18; i++) {
+            for (var j = 0; j < 48; j++) {
+                t = this.state.hash[j] ^= this.piSubst[t];
+            }
+            t = (t + i) & 0xff;
+        }
+
+        // Append checksum
+        t = this.state.checksum[15];
+        for (i = 0; i < 16; i++) {
+            t = this.state.checksum[i] ^= this.piSubst[block[i] ^ t];
+        }
+    };
+
+    /**
+     * @memberOf Md2
+     * @method finalize
+     * @return {HashArray}
+     */
+    Md2.prototype.finalize = function finalize() {
+        var padLen = this.state.message.length & 0xf;
+        this.update(new Array(17 - padLen).join(String.fromCharCode(16 - padLen)));
+
+        // Process checksum
+        this.updateFromArray(this.state.checksum);
+
+        // Return hash
+        return CryptoApi.hashArray(this.state.hash.slice(0, 16));
+    };
+
+    CryptoApi.Hashers.add('md2', Md2);
+    return Md2;
+})(
+    this.CryptoApi || require('./crypto-api')
+);

+ 204 - 0
src/js/lib/cryptoapi/hasher.md4.js

@@ -0,0 +1,204 @@
+/*global require */
+(/**
+ * @param {CryptoApi} CryptoApi
+ * @returns {Md4}
+ */
+  function (CryptoApi) {
+  'use strict';
+
+  /**
+   * @class Md4
+   * @desc Md4 hasher
+   * @implements HasherInterface
+   * @extends Hasher32le
+   */
+  var Md4 = function md4(name, options) {
+    this.constructor(name, options);
+  };
+  Md4.prototype = Object.create(CryptoApi.Hasher32le.prototype);
+  /**
+   * @memberOf Md4
+   * @constructor
+   */
+  Md4.prototype.constructor = function (name, options) {
+    CryptoApi.Hasher32le.prototype.constructor.call(this, name, options);
+    /**
+     * @desc Hash state
+     * @memberOf! Md4#
+     * @alias state.hash
+     * @type {number[]}
+     */
+    this.state.hash = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
+  };
+
+  /**
+   * @desc Transform constants
+   * @memberOf Md4
+   * @member {number[]} S
+   * @const
+   */
+  Md4.prototype.S = [
+    [3, 7, 11, 19],
+    [3, 5, 9, 13],
+    [3, 9, 11, 15]
+  ];
+  Md4.prototype.F = 0x00000000;
+  Md4.prototype.G = 0x5a827999;
+  Md4.prototype.H = 0x6ed9eba1;
+
+// Transform functions
+  /**
+   * @param {number} x
+   * @param {number} y
+   * @param {number} z
+   * @returns {number}
+   */
+  Md4.prototype.FF = function FF(x, y, z) {
+    return (x & y) | ((~x) & z);
+  };
+  /**
+   * @param {number} x
+   * @param {number} y
+   * @param {number} z
+   * @returns {number}
+   */
+  Md4.prototype.GG = function GG(x, y, z) {
+    return (x & y) | (x & z) | (y & z);
+  };
+  /**
+   * @param {number} x
+   * @param {number} y
+   * @param {number} z
+   * @returns {number}
+   */
+  Md4.prototype.HH = function HH(x, y, z) {
+    return x ^ y ^ z;
+  };
+  /**
+   *
+   * @param {function} f
+   * @param {number} k
+   * @param {number} a
+   * @param {number} x
+   * @param {number} y
+   * @param {number} z
+   * @param {number} m
+   * @param {number} s
+   * @returns {number}
+   * @constructor
+   */
+  Md4.prototype.CC = function CC(f, k, a, x, y, z, m, s) {
+    return CryptoApi.Tools.rotateLeft((a + f(x, y, z) + m + k), s) | 0;
+  };
+
+  /**
+   * @memberOf Md4
+   * @method processBlock
+   * @param {number[]} block
+   */
+  Md4.prototype.processBlock = function processBlock(block) {
+    // Working variables
+    var a = this.state.hash[0] | 0;
+    var b = this.state.hash[1] | 0;
+    var c = this.state.hash[2] | 0;
+    var d = this.state.hash[3] | 0;
+
+    // Round 1
+    a = this.CC(this.FF, this.F, a, b, c, d, block[0], this.S[0][0]);
+    d = this.CC(this.FF, this.F, d, a, b, c, block[1], this.S[0][1]);
+    c = this.CC(this.FF, this.F, c, d, a, b, block[2], this.S[0][2]);
+    b = this.CC(this.FF, this.F, b, c, d, a, block[3], this.S[0][3]);
+    a = this.CC(this.FF, this.F, a, b, c, d, block[4], this.S[0][0]);
+    d = this.CC(this.FF, this.F, d, a, b, c, block[5], this.S[0][1]);
+    c = this.CC(this.FF, this.F, c, d, a, b, block[6], this.S[0][2]);
+    b = this.CC(this.FF, this.F, b, c, d, a, block[7], this.S[0][3]);
+    a = this.CC(this.FF, this.F, a, b, c, d, block[8], this.S[0][0]);
+    d = this.CC(this.FF, this.F, d, a, b, c, block[9], this.S[0][1]);
+    c = this.CC(this.FF, this.F, c, d, a, b, block[10], this.S[0][2]);
+    b = this.CC(this.FF, this.F, b, c, d, a, block[11], this.S[0][3]);
+    a = this.CC(this.FF, this.F, a, b, c, d, block[12], this.S[0][0]);
+    d = this.CC(this.FF, this.F, d, a, b, c, block[13], this.S[0][1]);
+    c = this.CC(this.FF, this.F, c, d, a, b, block[14], this.S[0][2]);
+    b = this.CC(this.FF, this.F, b, c, d, a, block[15], this.S[0][3]);
+
+    // Round 2
+    a = this.CC(this.GG, this.G, a, b, c, d, block[0], this.S[1][0]);
+    d = this.CC(this.GG, this.G, d, a, b, c, block[4], this.S[1][1]);
+    c = this.CC(this.GG, this.G, c, d, a, b, block[8], this.S[1][2]);
+    b = this.CC(this.GG, this.G, b, c, d, a, block[12], this.S[1][3]);
+    a = this.CC(this.GG, this.G, a, b, c, d, block[1], this.S[1][0]);
+    d = this.CC(this.GG, this.G, d, a, b, c, block[5], this.S[1][1]);
+    c = this.CC(this.GG, this.G, c, d, a, b, block[9], this.S[1][2]);
+    b = this.CC(this.GG, this.G, b, c, d, a, block[13], this.S[1][3]);
+    a = this.CC(this.GG, this.G, a, b, c, d, block[2], this.S[1][0]);
+    d = this.CC(this.GG, this.G, d, a, b, c, block[6], this.S[1][1]);
+    c = this.CC(this.GG, this.G, c, d, a, b, block[10], this.S[1][2]);
+    b = this.CC(this.GG, this.G, b, c, d, a, block[14], this.S[1][3]);
+    a = this.CC(this.GG, this.G, a, b, c, d, block[3], this.S[1][0]);
+    d = this.CC(this.GG, this.G, d, a, b, c, block[7], this.S[1][1]);
+    c = this.CC(this.GG, this.G, c, d, a, b, block[11], this.S[1][2]);
+    b = this.CC(this.GG, this.G, b, c, d, a, block[15], this.S[1][3]);
+
+    // Round 3
+    a = this.CC(this.HH, this.H, a, b, c, d, block[0], this.S[2][0]);
+    d = this.CC(this.HH, this.H, d, a, b, c, block[8], this.S[2][1]);
+    c = this.CC(this.HH, this.H, c, d, a, b, block[4], this.S[2][2]);
+    b = this.CC(this.HH, this.H, b, c, d, a, block[12], this.S[2][3]);
+    a = this.CC(this.HH, this.H, a, b, c, d, block[2], this.S[2][0]);
+    d = this.CC(this.HH, this.H, d, a, b, c, block[10], this.S[2][1]);
+    c = this.CC(this.HH, this.H, c, d, a, b, block[6], this.S[2][2]);
+    b = this.CC(this.HH, this.H, b, c, d, a, block[14], this.S[2][3]);
+    a = this.CC(this.HH, this.H, a, b, c, d, block[1], this.S[2][0]);
+    d = this.CC(this.HH, this.H, d, a, b, c, block[9], this.S[2][1]);
+    c = this.CC(this.HH, this.H, c, d, a, b, block[5], this.S[2][2]);
+    b = this.CC(this.HH, this.H, b, c, d, a, block[13], this.S[2][3]);
+    a = this.CC(this.HH, this.H, a, b, c, d, block[3], this.S[2][0]);
+    d = this.CC(this.HH, this.H, d, a, b, c, block[11], this.S[2][1]);
+    c = this.CC(this.HH, this.H, c, d, a, b, block[7], this.S[2][2]);
+    b = this.CC(this.HH, this.H, b, c, d, a, block[15], this.S[2][3]);
+
+    this.state.hash = [
+      (this.state.hash[0] + a) | 0,
+      (this.state.hash[1] + b) | 0,
+      (this.state.hash[2] + c) | 0,
+      (this.state.hash[3] + d) | 0
+    ];
+  };
+  /**
+   * @memberOf Md4
+   * @method finalize
+   * @return {HashArray} hash
+   */
+  Md4.prototype.finalize = function finalize() {
+    // Add padding
+    var padLen = this.state.message.length < 56 ? 56 - this.state.message.length : 120 - this.state.message.length;
+    var padding = new Array(padLen);
+    padding[0] = 0x80;
+
+    // Add length
+    var lengthBits = this.state.length * 8;
+    for (var i = 0; i < 4; i++) {
+      padding.push((lengthBits >> (8 * i)) & 0xff);
+    }
+    // @todo fix length to 64 bit
+    for (i = 0; i < 4; i++) {
+      padding.push(0);
+    }
+    this.updateFromArray(padding);
+
+    var hash = [];
+    for (i = 0; i < this.state.hash.length; i++) {
+      for (var j = 0; j < 4; j++) {
+        hash.push((this.state.hash[i] >> 8 * j) & 0xff);
+      }
+    }
+
+    // Return hash
+    return CryptoApi.hashArray(hash);
+  };
+
+  CryptoApi.Hashers.add('md4', Md4);
+  return Md4;
+})(
+    this.CryptoApi || require('./crypto-api')
+);

+ 125 - 0
src/js/lib/cryptoapi/hasher.sha0.js

@@ -0,0 +1,125 @@
+/*global require */
+(/**
+ *
+ * @param {CryptoApi} CryptoApi
+ * @returns {Sha0}
+ */
+  function (CryptoApi) {
+  'use strict';
+
+  // Transform constants
+  var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
+
+  /**
+   * @class Sha0
+   * @desc Sha0 hasher
+   * @implements HasherInterface
+   * @extends Hasher32be
+   */
+  var Sha0 = function sha0(name, options) {
+    this.constructor(name, options);
+  };
+  Sha0.prototype = Object.create(CryptoApi.Hasher32be.prototype);
+  /**
+   * @memberOf Sha0
+   * @constructor
+   */
+  Sha0.prototype.constructor = function (name, options) {
+    CryptoApi.Hasher32be.prototype.constructor.call(this, name, options);
+    /**
+     * @desc Hash state
+     * @memberOf! Sha0#
+     * @alias state.hash
+     * @type {number[]}
+     */
+    this.state.hash = [
+      0x67452301,
+      0xefcdab89,
+      0x98badcfe,
+      0x10325476,
+      0xc3d2e1f0
+    ];
+    this.W = [];
+  };
+
+  /**
+   * @memberOf Sha0
+   * @method processBlock
+   * @param {number[]} M
+   */
+  Sha0.prototype.processBlock = function processBlock(M) {
+    // Working variables
+    var a = this.state.hash[0] | 0;
+    var b = this.state.hash[1] | 0;
+    var c = this.state.hash[2] | 0;
+    var d = this.state.hash[3] | 0;
+    var e = this.state.hash[4] | 0;
+
+    // Calculate hash
+    for (var i = 0; i < 80; i++) {
+      if (i < 16) {
+        this.W[i] = M[i] | 0;
+      } else {
+        this.W[i] = (this.W[i - 3] ^ this.W[i - 8] ^ this.W[i - 14] ^ this.W[i - 16]) | 0;
+      }
+
+      var t = (CryptoApi.Tools.rotateLeft(a, 5) + e + this.W[i] + K[(i / 20) >> 0]) | 0;
+      if (i < 20) {
+        t = (t + ((b & c) | (~b & d))) | 0;
+      } else if (i < 40) {
+        t = (t + (b ^ c ^ d)) | 0;
+      } else if (i < 60) {
+        t = (t + ((b & c) | (b & d) | (c & d))) | 0;
+      } else {
+        t = (t + (b ^ c ^ d)) | 0;
+      }
+      e = d;
+      d = c;
+      c = CryptoApi.Tools.rotateLeft(b, 30) | 0;
+      b = a;
+      a = t;
+    }
+
+    this.state.hash[0] = (this.state.hash[0] + a) | 0;
+    this.state.hash[1] = (this.state.hash[1] + b) | 0;
+    this.state.hash[2] = (this.state.hash[2] + c) | 0;
+    this.state.hash[3] = (this.state.hash[3] + d) | 0;
+    this.state.hash[4] = (this.state.hash[4] + e) | 0;
+  };
+
+  /**
+   * @memberOf Sha0
+   * @method finalize
+   * @return {HashArray} hash
+   */
+  Sha0.prototype.finalize = function finalize() {
+    // Add padding
+    var padLen = this.state.message.length < 56 ? 56 - this.state.message.length : 120 - this.state.message.length;
+    padLen += 4; // @todo fix length to 64 bit
+    var padding = new Array(padLen);
+    padding[0] = 0x80;
+
+    // Add length
+    var lengthBits = this.state.length * 8;
+    for (var i = 3; i >= 0; i--) {
+      padding.push((lengthBits >> (8 * i)) & 0xff);
+    }
+
+    this.updateFromArray(padding);
+
+    var hash = [];
+    for (var k = 0, l = this.state.hash.length; k < l; k++) {
+      for (var j = 3; j >= 0; j--) {
+        hash.push((this.state.hash[k] >> 8 * j) & 0xFF);
+      }
+    }
+
+    // Return hash
+    return CryptoApi.hashArray(hash);
+  };
+
+  CryptoApi.Hashers.add('sha0', Sha0);
+  return Sha0;
+})(
+    this.CryptoApi || require('./crypto-api')
+);

+ 264 - 54
src/js/lib/split.js

@@ -1,6 +1,6 @@
 /** @license
 ========================================================================
-  Split.js v1.0.7
+  Split.js v1.1.1
   Copyright (c) 2015 Nathan Cahill
 
   Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,17 +22,43 @@
   THE SOFTWARE.
 */
 
+
+// The programming goals of Split.js are to deliver readable, understandable and
+// maintainable code, while at the same time manually optimizing for tiny minified file size,
+// browser compatibility without additional requirements, graceful fallback (IE8 is supported)
+// and very few assumptions about the user's page layout.
+//
+// Make sure all browsers handle this JS library correctly with ES5.
+// More information here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
 'use strict';
 
+// A wrapper function that does a couple things:
+//
+// 1. Doesn't pollute the global namespace. This is important for a library.
+// 2. Allows us to mount the library in different module systems, as well as
+//    directly in the browser.
 (function() {
 
+// Save the global `this` for use later. In this case, since the library only
+// runs in the browser, it will refer to `window`. Also, figure out if we're in IE8
+// or not. IE8 will still render correctly, but will be static instead of draggable.
+//
+// Save a couple long function names that are used frequently.
+// This optimization saves around 400 bytes.
 var global = this
+  , isIE8 = global.attachEvent && !global[addEventListener]
+  , document = global.document
   , addEventListener = 'addEventListener'
   , removeEventListener = 'removeEventListener'
   , getBoundingClientRect = 'getBoundingClientRect'
-  , isIE8 = global.attachEvent && !global[addEventListener]
-  , document = global.document
 
+  // This library only needs two helper functions:
+  //
+  // The first determines which prefixes of CSS calc we need.
+  // We only need to do this once on startup, when this anonymous function is called.
+  // 
+  // Tests -webkit, -moz and -o prefixes. Modified from StackOverflow:
+  // http://stackoverflow.com/questions/16625140/js-feature-detection-to-detect-the-usage-of-webkit-calc-over-calc/16625167#16625167
   , calc = (function () {
         var el
           , prefixes = ["", "-webkit-", "-moz-", "-o-"]
@@ -46,6 +72,10 @@ var global = this
             }
         }
     })()
+
+  // The second helper function allows elements and string selectors to be used
+  // interchangeably. In either case an element is returned. This allows us to
+  // do `Split(elem1, elem2)` as well as `Split('#id1', '#id2')`.
   , elementOrSelector = function (el) {
         if (typeof el === 'string' || el instanceof String) {
             return document.querySelector(el)
@@ -54,6 +84,38 @@ var global = this
         }
     }
 
+  // The main function to initialize a split. Split.js thinks about each pair
+  // of elements as an independant pair. Dragging the gutter between two elements
+  // only changes the dimensions of elements in that pair. This is key to understanding
+  // how the following functions operate, since each function is bound to a pair.
+  // 
+  // A pair object is shaped like this:
+  // 
+  // {
+  //     a: DOM element,
+  //     b: DOM element,
+  //     aMin: Number,
+  //     bMin: Number,
+  //     dragging: Boolean,
+  //     parent: DOM element,
+  //     isFirst: Boolean,
+  //     isLast: Boolean,
+  //     direction: 'horizontal' | 'vertical'
+  // }
+  //
+  // The basic sequence:
+  // 
+  // 1. Set defaults to something sane. `options` doesn't have to be passed at all.
+  // 2. Initialize a bunch of strings based on the direction we're splitting.
+  //    A lot of the behavior in the rest of the library is paramatized down to
+  //    rely on CSS strings and classes.
+  // 3. Define the dragging helper functions, and a few helpers to go with them.
+  // 4. Define a few more functions that "balance" the entire split instance.
+  //    Split.js tries it's best to cope with min sizes that don't add up.
+  // 5. Loop through the elements while pairing them off. Every pair gets an
+  //    `pair` object, a gutter, and special isFirst/isLast properties.
+  // 6. Actually size the pair elements, insert gutters and attach event listeners.
+  // 7. Balance all of the pairs to accomodate min sizes as best as possible.
   , Split = function (ids, options) {
     var dimension
       , i
@@ -65,8 +127,9 @@ var global = this
       , paddingB
       , pairs = []
 
-    // Set defaults
-
+    // 1. Set defaults to something sane. `options` doesn't have to be passed at all,
+    // so create an options object if none exists. Pixel values 10, 100 and 30 are
+    // arbitrary but feel natural.
     options = typeof options !== 'undefined' ?  options : {}
 
     if (typeof options.gutterSize === 'undefined') options.gutterSize = 10
@@ -74,6 +137,9 @@ var global = this
     if (typeof options.snapOffset === 'undefined') options.snapOffset = 30
     if (typeof options.direction === 'undefined') options.direction = 'horizontal'
 
+    // 2. Initialize a bunch of strings based on the direction we're splitting.
+    // A lot of the behavior in the rest of the library is paramatized down to
+    // rely on CSS strings and classes.
     if (options.direction == 'horizontal') {
         dimension = 'width'
         clientDimension = 'clientWidth'
@@ -94,25 +160,43 @@ var global = this
         if (!options.cursor) options.cursor = 'ns-resize'
     }
 
-    // Event listeners for drag events, bound to a pair object.
-    // Calculate the pair's position and size when dragging starts.
-    // Prevent selection on start and re-enable it when done.
-
+    // 3. Define the dragging helper functions, and a few helpers to go with them.
+    // Each helper is bound to a pair object that contains it's metadata. This
+    // also makes it easy to store references to listeners that that will be
+    // added and removed.
+    // 
+    // Even though there are no other functions contained in them, aliasing
+    // this to self saves 50 bytes or so since it's used so frequently.
+    //
+    // The pair object saves metadata like dragging state, position and
+    // event listener references.
+    //
+    // startDragging calls `calculateSizes` to store the inital size in the pair object.
+    // It also adds event listeners for mouse/touch events,
+    // and prevents selection while dragging so avoid the selecting text.
     var startDragging = function (e) {
+            // Alias frequently used variables to save space. 200 bytes.
             var self = this
               , a = self.a
               , b = self.b
 
+            // Call the onDragStart callback.
             if (!self.dragging && options.onDragStart) {
                 options.onDragStart()
             }
 
+            // Don't actually drag the element. We emulate that in the drag function.
             e.preventDefault()
 
+            // Set the dragging property of the pair object.
             self.dragging = true
+
+            // Create two event listeners bound to the same pair object and store
+            // them in the pair object.
             self.move = drag.bind(self)
             self.stop = stopDragging.bind(self)
 
+            // All the binding. `window` gets the stop events in case we drag out of the elements.
             global[addEventListener]('mouseup', self.stop)
             global[addEventListener]('touchend', self.stop)
             global[addEventListener]('touchcancel', self.stop)
@@ -120,10 +204,11 @@ var global = this
             self.parent[addEventListener]('mousemove', self.move)
             self.parent[addEventListener]('touchmove', self.move)
 
-            a[addEventListener]('selectstart', preventSelection)
-            a[addEventListener]('dragstart', preventSelection)
-            b[addEventListener]('selectstart', preventSelection)
-            b[addEventListener]('dragstart', preventSelection)
+            // Disable selection. Disable!
+            a[addEventListener]('selectstart', noop)
+            a[addEventListener]('dragstart', noop)
+            b[addEventListener]('selectstart', noop)
+            b[addEventListener]('dragstart', noop)
 
             a.style.userSelect = 'none'
             a.style.webkitUserSelect = 'none'
@@ -135,11 +220,16 @@ var global = this
             b.style.MozUserSelect = 'none'
             b.style.pointerEvents = 'none'
 
+            // Set the cursor, both on the gutter and the parent element.
+            // Doing only a, b and gutter causes flickering.
             self.gutter.style.cursor = options.cursor
             self.parent.style.cursor = options.cursor
 
+            // Cache the initial sizes of the pair.
             calculateSizes.call(self)
         }
+
+      // stopDragging is very similar to startDragging in reverse.
       , stopDragging = function () {
             var self = this
               , a = self.a
@@ -151,6 +241,7 @@ var global = this
 
             self.dragging = false
 
+            // Remove the stored event listeners. This is why we store them.
             global[removeEventListener]('mouseup', self.stop)
             global[removeEventListener]('touchend', self.stop)
             global[removeEventListener]('touchcancel', self.stop)
@@ -158,13 +249,15 @@ var global = this
             self.parent[removeEventListener]('mousemove', self.move)
             self.parent[removeEventListener]('touchmove', self.move)
 
+            // Delete them once they are removed. I think this makes a difference
+            // in memory usage with a lot of splits on one page. But I don't know for sure.
             delete self.stop
             delete self.move
 
-            a[removeEventListener]('selectstart', preventSelection)
-            a[removeEventListener]('dragstart', preventSelection)
-            b[removeEventListener]('selectstart', preventSelection)
-            b[removeEventListener]('dragstart', preventSelection)
+            a[removeEventListener]('selectstart', noop)
+            a[removeEventListener]('dragstart', noop)
+            b[removeEventListener]('selectstart', noop)
+            b[removeEventListener]('dragstart', noop)
 
             a.style.userSelect = ''
             a.style.webkitUserSelect = ''
@@ -179,36 +272,70 @@ var global = this
             self.gutter.style.cursor = ''
             self.parent.style.cursor = ''
         }
+
+      // drag, where all the magic happens. The logic is really quite simple:
+      // 
+      // 1. Ignore if the pair is not dragging.
+      // 2. Get the offset of the event.
+      // 3. Snap offset to min if within snappable range (within min + snapOffset).
+      // 4. Actually adjust each element in the pair to offset.
+      // 
+      // ---------------------------------------------------------------------
+      // |    | <- this.aMin               ||              this.bMin -> |    |
+      // |    |  | <- this.snapOffset      ||     this.snapOffset -> |  |    |
+      // |    |  |                         ||                        |  |    |
+      // |    |  |                         ||                        |  |    |
+      // ---------------------------------------------------------------------
+      // | <- this.start                                        this.size -> |
       , drag = function (e) {
             var offset
 
             if (!this.dragging) return
 
-            // Get the relative position of the event from the first side of the
-            // pair.
-
+            // Get the offset of the event from the first side of the
+            // pair `this.start`. Supports touch events, but not multitouch, so only the first
+            // finger `touches[0]` is counted.
             if ('touches' in e) {
                 offset = e.touches[0][clientAxis] - this.start
             } else {
                 offset = e[clientAxis] - this.start
             }
 
-            // If within snapOffset of min or max, set offset to min or max
-
-            if (offset <=  this.aMin + options.snapOffset) {
-                offset = this.aMin
-            } else if (offset >= this.size - this.bMin - options.snapOffset) {
-                offset = this.size - this.bMin
+            // If within snapOffset of min or max, set offset to min or max.
+            // snapOffset buffers aMin and bMin, so logic is opposite for both.
+            // Include the appropriate gutter sizes to prevent overflows.
+            if (offset <= this.aMin + options.snapOffset + this.aGutterSize) {
+                offset = this.aMin + this.aGutterSize
+            } else if (offset >= this.size - (this.bMin + options.snapOffset + this.bGutterSize)) {
+                offset = this.size - (this.bMin + this.bGutterSize)
             }
 
+            // Actually adjust the size.
             adjust.call(this, offset)
 
+            // Call the drag callback continously. Don't do anything too intensive
+            // in this callback.
             if (options.onDrag) {
                 options.onDrag()
             }
         }
+
+      // Cache some important sizes when drag starts, so we don't have to do that
+      // continously:
+      // 
+      // `size`: The total size of the pair. First element + second element + first gutter + second gutter.
+      // `percentage`: The percentage between 0-100 that the pair occupies in the parent.
+      // `start`: The leading side of the first element.
+      //
+      // ------------------------------------------------ - - - - - - - - - - -
+      // |      aGutterSize -> |||                      |                     |
+      // |                     |||                      |                     |
+      // |                     |||                      |                     |
+      // |                     ||| <- bGutterSize       |                     |
+      // ------------------------------------------------ - - - - - - - - - - -
+      // | <- start                             size -> |       parentSize -> |
       , calculateSizes = function () {
-            // Calculate the pairs size, and percentage of the parent size
+            // Figure out the parent size minus padding.
             var computedStyle = global.getComputedStyle(this.parent)
               , parentSize = this.parent[clientDimension] - parseFloat(computedStyle[paddingA]) - parseFloat(computedStyle[paddingB])
 
@@ -216,13 +343,21 @@ var global = this
             this.percentage = Math.min(this.size / parentSize * 100, 100)
             this.start = this.a[getBoundingClientRect]()[position]
         }
-      , adjust = function (offset) {
-            // A size is the same as offset. B size is total size - A size.
-            // Both sizes are calculated from the initial parent percentage.
 
+      // Actually adjust the size of elements `a` and `b` to `offset` while dragging.
+      // calc is used to allow calc(percentage + gutterpx) on the whole split instance,
+      // which allows the viewport to be resized without additional logic.
+      // Element a's size is the same as offset. b's size is total size - a size.
+      // Both sizes are calculated from the initial parent percentage, then the gutter size is subtracted.
+      , adjust = function (offset) {
             this.a.style[dimension] = calc + '(' + (offset / this.size * this.percentage) + '% - ' + this.aGutterSize + 'px)'
             this.b.style[dimension] = calc + '(' + (this.percentage - (offset / this.size * this.percentage)) + '% - ' + this.bGutterSize + 'px)'
         }
+
+      // 4. Define a few more functions that "balance" the entire split instance.
+      // Split.js tries it's best to cope with min sizes that don't add up.
+      // At some point this should go away since it breaks out of the calc(% - px) model.
+      // Maybe it's a user error if you pass uncomputable minSizes.
       , fitMin = function () {
             var self = this
               , a = self.a
@@ -260,9 +395,31 @@ var global = this
                 fitMinReverse.call(pairs[i])
             }
         }
-      , preventSelection = function () { return false }
+      , setElementSize = function (el, size, gutterSize) {
+            // Split.js allows setting sizes via numbers (ideally), or if you must,
+            // by string, like '300px'. This is less than ideal, because it breaks
+            // the fluid layout that `calc(% - px)` provides. You're on your own if you do that,
+            // make sure you calculate the gutter size by hand.
+            if (typeof size !== 'string' && !(size instanceof String)) {
+                if (!isIE8) {
+                    size = calc + '(' + size + '% - ' + gutterSize + 'px)'
+                } else {
+                    size = options.sizes[i] + '%'
+                }
+            }
+
+            el.style[dimension] = size
+        }
+
+      // No-op function to prevent default. Used to prevent selection.
+      , noop = function () { return false }
+
+      // All DOM elements in the split should have a common parent. We can grab
+      // the first elements parent and hope users read the docs because the
+      // behavior will be whacky otherwise.
       , parent = elementOrSelector(ids[0]).parentNode
 
+    // Set default options.sizes to equal percentages of the parent element.
     if (!options.sizes) {
         var percent = 100 / ids.length
 
@@ -273,6 +430,8 @@ var global = this
         }
     }
 
+    // Standardize minSize to an array if it isn't already. This allows minSize
+    // to be passed as a number.
     if (!Array.isArray(options.minSize)) {
         var minSizes = []
 
@@ -283,15 +442,34 @@ var global = this
         options.minSize = minSizes
     }
 
+    // 5. Loop through the elements while pairing them off. Every pair gets a
+    // `pair` object, a gutter, and isFirst/isLast properties.
+    //
+    // Basic logic:
+    //
+    // - Starting with the second element `i > 0`, create `pair` objects with
+    //   `a = ids[i - 1]` and `b = ids[i]`
+    // - Set gutter sizes based on the _pair_ being first/last. The first and last
+    //   pair have gutterSize / 2, since they only have one half gutter, and not two.
+    // - Create gutter elements and add event listeners.
+    // - Set the size of the elements, minus the gutter sizes.
+    //
+    // -----------------------------------------------------------------------
+    // |     i=0     |         i=1         |        i=2       |      i=3     |
+    // |             |       isFirst       |                  |     isLast   |
+    // |           pair 0                pair 1             pair 2           |
+    // |             |                     |                  |              |
+    // -----------------------------------------------------------------------
     for (i = 0; i < ids.length; i++) {
         var el = elementOrSelector(ids[i])
-          , isFirst = (i == 1)
-          , isLast = (i == ids.length - 1)
-          , size
+          , isFirstPair = (i == 1)
+          , isLastPair = (i == ids.length - 1)
+          , size = options.sizes[i]
           , gutterSize = options.gutterSize
           , pair
 
         if (i > 0) {
+            // Create the pair object with it's metadata.
             pair = {
                 a: elementOrSelector(ids[i - 1]),
                 b: el,
@@ -299,27 +477,31 @@ var global = this
                 bMin: options.minSize[i],
                 dragging: false,
                 parent: parent,
-                isFirst: isFirst,
-                isLast: isLast,
+                isFirst: isFirstPair,
+                isLast: isLastPair,
                 direction: options.direction
             }
 
             // For first and last pairs, first and last gutter width is half.
-
             pair.aGutterSize = options.gutterSize
             pair.bGutterSize = options.gutterSize
 
-            if (isFirst) {
+            if (isFirstPair) {
                 pair.aGutterSize = options.gutterSize / 2
             }
 
-            if (isLast) {
+            if (isLastPair) {
                 pair.bGutterSize = options.gutterSize / 2
             }
         }
 
+        // Determine the size of the current element. IE8 is supported by
+        // staticly assigning sizes without draggable gutters. Assigns a string
+        // to `size`.
+        // 
         // IE9 and above
         if (!isIE8) {
+            // Create gutter elements for each pair.
             if (i > 0) {
                 var gutter = document.createElement('div')
 
@@ -334,35 +516,62 @@ var global = this
                 pair.gutter = gutter
             }
 
+            // Half-size gutters for first and last elements.
             if (i === 0 || i == ids.length - 1) {
                 gutterSize = options.gutterSize / 2
             }
-
-            if (typeof options.sizes[i] === 'string' || options.sizes[i] instanceof String) {
-                size = options.sizes[i]
-            } else {
-                size = calc + '(' + options.sizes[i] + '% - ' + gutterSize + 'px)'
-            }
-
-        // IE8 and below
-        } else {
-            if (typeof options.sizes[i] === 'string' || options.sizes[i] instanceof String) {
-                size = options.sizes[i]
-            } else {
-                size = options.sizes[i] + '%'
-            }
         }
 
-        el.style[dimension] = size
+        // Set the element size to our determined size.
+        setElementSize(el, size, gutterSize)
 
+        // After the first iteration, and we have a pair object, append it to the
+        // list of pairs.
         if (i > 0) {
             pairs.push(pair)
         }
     }
 
+    // Balance the pairs to try to accomodate min sizes.
     balancePairs(pairs)
+
+    return {
+        setSizes: function (sizes) {
+            for (var i = 0; i < sizes.length; i++) {
+                if (i > 0) {
+                    var pair = pairs[i - 1]
+
+                    setElementSize(pair.a, sizes[i - 1], pair.aGutterSize)
+                    setElementSize(pair.b, sizes[i], pair.bGutterSize)
+                }
+            }
+        },
+        collapse: function (i) {
+            var pair
+
+            if (i === pairs.length) {
+                pair = pairs[i - 1]
+
+                calculateSizes.call(pair)
+                adjust.call(pair, pair.size - pair.bGutterSize)
+            } else {
+                pair = pairs[i]
+
+                calculateSizes.call(pair)
+                adjust.call(pair, pair.aGutterSize)
+            }
+        },
+        destroy: function () {
+            for (var i = 0; i < pairs.length; i++) {
+                pairs[i].parent.removeChild(pairs[i].gutter)
+                pairs[i].a.style[dimension] = ''
+                pairs[i].b.style[dimension] = ''
+            }
+        }
+    }
 }
 
+// Play nicely with module systems, and the browser too if you include it raw.
 if (typeof exports !== 'undefined') {
     if (typeof module !== 'undefined' && module.exports) {
         exports = module.exports = Split
@@ -372,4 +581,5 @@ if (typeof exports !== 'undefined') {
     global.Split = Split
 }
 
+// Call our wrapper function with the current global. In this case, `window`.
 }).call(window);

+ 8466 - 0
src/js/lib/xpath.js

@@ -0,0 +1,8466 @@
+/** @license
+========================================================================
+  XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ 
+  Copyright (c) 2012 Sergey Ilinsky
+  Dual licensed under the MIT and GPL licenses.
+*/
+(function(){
+
+//	Javascript objects
+var cString		= window.String,
+	cBoolean	= window.Boolean,
+	cNumber		= window.Number,
+	cObject		= window.Object,
+	cArray		= window.Array,
+	cRegExp		= window.RegExp,
+	cDate		= window.Date,
+	cFunction	= window.Function,
+	cMath		= window.Math,
+// Error Objects
+	cError		= window.Error,
+	cSyntaxError= window.SyntaxError,
+	cTypeError	= window.TypeError,
+//	misc
+	fIsNaN		= window.isNaN,
+	fIsFinite	= window.isFinite,
+	nNaN		= window.NaN,
+	nInfinity	= window.Infinity,
+	// Functions
+	fWindow_btoa	= window.btoa,
+	fWindow_atob	= window.atob,
+	fWindow_parseInt= window.parseInt,
+	fString_trim	=(function() {
+		return cString.prototype.trim ? function(sValue) {return cString(sValue).trim();} : function(sValue) {
+			return cString(sValue).replace(/^\s+|\s+$/g, '');
+		};
+	})(),
+	fArray_indexOf	=(function() {
+		return cArray.prototype.indexOf ? function(aValue, vItem) {return aValue.indexOf(vItem);} : function(aValue, vItem) {
+			for (var nIndex = 0, nLength = aValue.length; nIndex < nLength; nIndex++)
+				if (aValue[nIndex] === vItem)
+					return nIndex;
+			return -1;
+		};
+	})();
+
+var sNS_XSD	= "http://www.w3.org/2001/XMLSchema",
+	sNS_XPF	= "http://www.w3.org/2005/xpath-functions",
+	sNS_XNS	= "http://www.w3.org/2000/xmlns/",
+	sNS_XML	= "http://www.w3.org/XML/1998/namespace";
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cException(sCode
+
+	) {
+
+	this.code		= sCode;
+	this.message	=
+
+					  oException_messages[sCode];
+};
+
+cException.prototype	= new cError;
+
+// "http://www.w3.org/2005/xqt-errors"
+
+var oException_messages	= {};
+oException_messages["XPDY0002"]	= "Evaluation of an expression relies on some part of the dynamic context that has not been assigned a value.";
+oException_messages["XPST0003"]	= "Expression is not a valid instance of the grammar";
+oException_messages["XPTY0004"]	= "Type is not appropriate for the context in which the expression occurs";
+oException_messages["XPST0008"]	= "Expression refers to an element name, attribute name, schema type name, namespace prefix, or variable name that is not defined in the static context";
+oException_messages["XPST0010"]	= "Axis not supported";
+oException_messages["XPST0017"]	= "Expanded QName and number of arguments in a function call do not match the name and arity of a function signature";
+oException_messages["XPTY0018"]	= "The result of the last step in a path expression contains both nodes and atomic values";
+oException_messages["XPTY0019"]	= "The result of a step (other than the last step) in a path expression contains an atomic value.";
+oException_messages["XPTY0020"]	= "In an axis step, the context item is not a node.";
+oException_messages["XPST0051"]	= "It is a static error if a QName that is used as an AtomicType in a SequenceType is not defined in the in-scope schema types as an atomic type.";
+oException_messages["XPST0081"]	= "A QName used in an expression contains a namespace prefix that cannot be expanded into a namespace URI by using the statically known namespaces.";
+//
+oException_messages["FORG0001"]	= "Invalid value for cast/constructor.";
+oException_messages["FORG0003"]	= "fn:zero-or-one called with a sequence containing more than one item.";
+oException_messages["FORG0004"]	= "fn:one-or-more called with a sequence containing no items.";
+oException_messages["FORG0005"]	= "fn:exactly-one called with a sequence containing zero or more than one item.";
+oException_messages["FORG0006"]	= "Invalid argument type.";
+//
+oException_messages["FODC0001"]	= "No context document.";
+//
+oException_messages["FORX0001"]	= "Invalid regular expression flags.";
+//
+oException_messages["FOCA0002"]	= "Invalid lexical value.";
+//
+oException_messages["FOCH0002"]	= "Unsupported collation.";
+
+oException_messages["FONS0004"]	= "No namespace found for prefix.";
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cLexer(sValue) {
+	var aMatch	= sValue.match(/\$?(?:(?![0-9-])(?:\w[\w.-]*|\*):)?(?![0-9-])(?:\w[\w.-]*|\*)|\(:|:\)|\/\/|\.\.|::|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?|\.\d+(?:[eE][+-]?\d+)?|"[^"]*(?:""[^"]*)*"|'[^']*(?:''[^']*)*'|<<|>>|[!<>]=|(?![0-9-])[\w-]+:\*|\s+|./g);
+	if (aMatch) {
+		var nStack	= 0;
+		for (var nIndex = 0, nLength = aMatch.length; nIndex < nLength; nIndex++)
+			if (aMatch[nIndex] == '(:')
+				nStack++;
+			else
+			if (aMatch[nIndex] == ':)' && nStack)
+				nStack--;
+			else
+			if (!nStack && !/^\s/.test(aMatch[nIndex]))
+				this[this.length++]	= aMatch[nIndex];
+		if (nStack)
+			throw new cException("XPST0003"
+
+			);
+	}
+};
+
+cLexer.prototype.index		= 0;
+cLexer.prototype.length	= 0;
+
+cLexer.prototype.reset	= function() {
+	this.index	= 0;
+};
+
+cLexer.prototype.peek	= function(nOffset) {
+	return this[this.index +(nOffset || 0)] || '';
+};
+
+cLexer.prototype.next	= function(nOffset) {
+	return(this.index+= nOffset || 1) < this.length;
+};
+
+cLexer.prototype.back	= function(nOffset) {
+	return(this.index-= nOffset || 1) > 0;
+};
+
+cLexer.prototype.eof	= function() {
+	return this.index >= this.length;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cDOMAdapter() {
+
+};
+
+// Custom members
+cDOMAdapter.prototype.isNode		= function(oNode) {
+	return oNode &&!!oNode.nodeType;
+};
+
+cDOMAdapter.prototype.getProperty	= function(oNode, sName) {
+	return oNode[sName];
+};
+
+// Standard members
+cDOMAdapter.prototype.isSameNode	= function(oNode, oNode2) {
+	return oNode == oNode2;
+};
+
+cDOMAdapter.prototype.compareDocumentPosition	= function(oNode, oNode2) {
+	return oNode.compareDocumentPosition(oNode2);
+};
+
+cDOMAdapter.prototype.lookupNamespaceURI	= function(oNode, sPrefix) {
+	return oNode.lookupNamespaceURI(sPrefix);
+};
+
+// Document object members
+cDOMAdapter.prototype.getElementById	= function(oNode, sId) {
+	return oNode.getElementById(sId);
+};
+
+// Element/Document object members
+cDOMAdapter.prototype.getElementsByTagNameNS	= function(oNode, sNameSpaceURI, sLocalName) {
+	return oNode.getElementsByTagNameNS(sNameSpaceURI, sLocalName);
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cDynamicContext(oStaticContext, vItem, oScope, oDOMAdapter) {
+	//
+	this.staticContext	= oStaticContext;
+	//
+	this.item		= vItem;
+	//
+	this.scope		= oScope || {};
+	this.stack		= {};
+	//
+	this.DOMAdapter	= oDOMAdapter || new cDOMAdapter;
+	//
+	var oDate	= new cDate,
+		nOffset	= oDate.getTimezoneOffset();
+	this.dateTime	= new cXSDateTime(oDate.getFullYear(), oDate.getMonth() + 1, oDate.getDate(), oDate.getHours(), oDate.getMinutes(), oDate.getSeconds() + oDate.getMilliseconds() / 1000, -nOffset);
+	this.timezone	= new cXSDayTimeDuration(0, cMath.abs(~~(nOffset / 60)), cMath.abs(nOffset % 60), 0, nOffset > 0);
+};
+
+cDynamicContext.prototype.item		= null;
+cDynamicContext.prototype.position	= 0;
+cDynamicContext.prototype.size		= 0;
+//
+cDynamicContext.prototype.scope		= null;
+cDynamicContext.prototype.stack		= null;	// Variables stack
+//
+cDynamicContext.prototype.dateTime	= null;
+cDynamicContext.prototype.timezone	= null;
+//
+cDynamicContext.prototype.staticContext	= null;
+
+// Stack management
+cDynamicContext.prototype.pushVariable	= function(sName, vValue) {
+	if (!this.stack.hasOwnProperty(sName))
+		this.stack[sName]	= [];
+	this.stack[sName].push(this.scope[sName]);
+	this.scope[sName] = vValue;
+};
+
+cDynamicContext.prototype.popVariable	= function(sName) {
+	if (this.stack.hasOwnProperty(sName)) {
+		this.scope[sName] = this.stack[sName].pop();
+		if (!this.stack[sName].length) {
+			delete this.stack[sName];
+			if (typeof this.scope[sName] == "undefined")
+				delete this.scope[sName];
+		}
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cStaticContext() {
+	this.dataTypes	= {};
+	this.documents	= {};
+	this.functions	= {};
+	this.collations	= {};
+	this.collections= {};
+};
+
+cStaticContext.prototype.baseURI	= null;
+//
+cStaticContext.prototype.dataTypes	= null;
+cStaticContext.prototype.documents	= null;
+//
+cStaticContext.prototype.functions	= null;
+cStaticContext.prototype.defaultFunctionNamespace	= null;
+//
+cStaticContext.prototype.collations	= null;
+cStaticContext.prototype.defaultCollationName		= sNS_XPF + "/collation/codepoint";
+//
+cStaticContext.prototype.collections	= null;
+//
+cStaticContext.prototype.namespaceResolver	= null;
+cStaticContext.prototype.defaultElementNamespace	= null;
+
+//
+var rStaticContext_uri	= /^(?:\{([^\}]+)\})?(.+)$/;
+//
+cStaticContext.prototype.setDataType		= function(sUri, fFunction) {
+	var aMatch	= sUri.match(rStaticContext_uri);
+	if (aMatch)
+		if (aMatch[1] != sNS_XSD)
+			this.dataTypes[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getDataType		= function(sUri) {
+	var aMatch	= sUri.match(rStaticContext_uri);
+	if (aMatch)
+		return aMatch[1] == sNS_XSD ? hStaticContext_dataTypes[aMatch[2]] : this.dataTypes[sUri];
+};
+
+cStaticContext.prototype.setDocument		= function(sUri, fFunction) {
+	this.documents[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getDocument		= function(sUri) {
+	return this.documents[sUri];
+};
+
+cStaticContext.prototype.setFunction		= function(sUri, fFunction) {
+	var aMatch	= sUri.match(rStaticContext_uri);
+	if (aMatch)
+		if (aMatch[1] != sNS_XPF)
+			this.functions[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getFunction		= function(sUri) {
+	var aMatch	= sUri.match(rStaticContext_uri);
+	if (aMatch)
+		return aMatch[1] == sNS_XPF ? hStaticContext_functions[aMatch[2]] : this.functions[sUri];
+};
+
+cStaticContext.prototype.setCollation		= function(sUri, fFunction) {
+	this.collations[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getCollation		= function(sUri) {
+	return this.collations[sUri];
+};
+
+cStaticContext.prototype.setCollection	= function(sUri, fFunction) {
+	this.collections[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getCollection	= function(sUri) {
+	return this.collections[sUri];
+};
+
+cStaticContext.prototype.getURIForPrefix	= function(sPrefix) {
+	var oResolver	= this.namespaceResolver,
+		fResolver	= oResolver && oResolver.lookupNamespaceURI ? oResolver.lookupNamespaceURI : oResolver,
+		sNameSpaceURI;
+	if (fResolver instanceof cFunction && (sNameSpaceURI = fResolver.call(oResolver, sPrefix)))
+		return sNameSpaceURI;
+	if (sPrefix == 'fn')
+		return sNS_XPF;
+	if (sPrefix == 'xs')
+		return sNS_XSD;
+	if (sPrefix == "xml")
+		return sNS_XML;
+	if (sPrefix == "xmlns")
+		return sNS_XNS;
+	//
+	throw new cException("XPST0081"
+
+	);
+};
+
+// Static members
+//Converts non-null JavaScript object to XML Schema object
+cStaticContext.js2xs	= function(vItem) {
+	// Convert types from JavaScript to XPath 2.0
+	if (typeof vItem == "boolean")
+		vItem	= new cXSBoolean(vItem);
+	else
+	if (typeof vItem == "number")
+		vItem	=(fIsNaN(vItem) ||!fIsFinite(vItem)) ? new cXSDouble(vItem) : fNumericLiteral_parseValue(cString(vItem));
+	else
+		vItem	= new cXSString(cString(vItem));
+	//
+	return vItem;
+};
+
+// Converts non-null XML Schema object to JavaScript object
+cStaticContext.xs2js	= function(vItem) {
+	if (vItem instanceof cXSBoolean)
+		vItem	= vItem.valueOf();
+	else
+	if (fXSAnyAtomicType_isNumeric(vItem))
+		vItem	= vItem.valueOf();
+	else
+		vItem	= vItem.toString();
+	//
+	return vItem;
+};
+
+// System functions with signatures, operators and types
+var hStaticContext_functions	= {},
+	hStaticContext_signatures	= {},
+	hStaticContext_dataTypes	= {},
+	hStaticContext_operators	= {};
+
+function fStaticContext_defineSystemFunction(sName, aParameters, fFunction) {
+	// Register function
+	hStaticContext_functions[sName]	= fFunction;
+	// Register signature
+	hStaticContext_signatures[sName]	= aParameters;
+};
+
+function fStaticContext_defineSystemDataType(sName, fFunction) {
+	// Register dataType
+	hStaticContext_dataTypes[sName]	= fFunction;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cExpression(sExpression, oStaticContext) {
+	var oLexer	= new cLexer(sExpression),
+		oExpr	= fExpr_parse(oLexer, oStaticContext);
+	//
+	if (!oLexer.eof())
+		throw new cException("XPST0003"
+
+		);
+	//
+	if (!oExpr)
+		throw new cException("XPST0003"
+
+		);
+	this.internalExpression	= oExpr;
+};
+
+cExpression.prototype.internalExpression	= null;
+
+// Public methods
+cExpression.prototype.evaluate	= function(oContext) {
+	return this.internalExpression.evaluate(oContext);
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cStringCollator() {
+
+};
+
+cStringCollator.prototype.equals	= function(sValue1, sValue2) {
+	throw "Not implemented";
+};
+
+cStringCollator.prototype.compare	= function(sValue1, sValue2) {
+	throw "Not implemented";
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSConstants(){};
+
+// XML Schema 1.0 Datatypes
+cXSConstants.ANYSIMPLETYPE_DT		= 1;
+cXSConstants.STRING_DT				= 2;
+cXSConstants.BOOLEAN_DT				= 3;
+cXSConstants.DECIMAL_DT				= 4;
+cXSConstants.FLOAT_DT				= 5;
+cXSConstants.DOUBLE_DT				= 6;
+cXSConstants.DURATION_DT			= 7;
+cXSConstants.DATETIME_DT			= 8;
+cXSConstants.TIME_DT				= 9;
+cXSConstants.DATE_DT				= 10;
+cXSConstants.GYEARMONTH_DT			= 11;
+cXSConstants.GYEAR_DT				= 12;
+cXSConstants.GMONTHDAY_DT			= 13;
+cXSConstants.GDAY_DT				= 14;
+cXSConstants.GMONTH_DT				= 15;
+cXSConstants.HEXBINARY_DT			= 16;
+cXSConstants.BASE64BINARY_DT		= 17;
+cXSConstants.ANYURI_DT				= 18;
+cXSConstants.QNAME_DT				= 19;
+cXSConstants.NOTATION_DT			= 20;
+cXSConstants.NORMALIZEDSTRING_DT	= 21;
+cXSConstants.TOKEN_DT				= 22;
+cXSConstants.LANGUAGE_DT			= 23;
+cXSConstants.NMTOKEN_DT				= 24;
+cXSConstants.NAME_DT				= 25;
+cXSConstants.NCNAME_DT				= 26;
+cXSConstants.ID_DT					= 27;
+cXSConstants.IDREF_DT				= 28;
+cXSConstants.ENTITY_DT				= 29;
+cXSConstants.INTEGER_DT				= 30;
+cXSConstants.NONPOSITIVEINTEGER_DT	= 31;
+cXSConstants.NEGATIVEINTEGER_DT		= 32;
+cXSConstants.LONG_DT				= 33;
+cXSConstants.INT_DT					= 34;
+cXSConstants.SHORT_DT				= 35;
+cXSConstants.BYTE_DT				= 36;
+cXSConstants.NONNEGATIVEINTEGER_DT	= 37;
+cXSConstants.UNSIGNEDLONG_DT		= 38;
+cXSConstants.UNSIGNEDINT_DT			= 39;
+cXSConstants.UNSIGNEDSHORT_DT		= 40;
+cXSConstants.UNSIGNEDBYTE_DT		= 41;
+cXSConstants.POSITIVEINTEGER_DT		= 42;
+cXSConstants.LISTOFUNION_DT			= 43;
+cXSConstants.LIST_DT				= 44;
+cXSConstants.UNAVAILABLE_DT			= 45;
+
+// XML Schema 1.1 Datatypes
+cXSConstants.DATETIMESTAMP_DT		= 46;
+cXSConstants.DAYMONTHDURATION_DT	= 47;
+cXSConstants.DAYTIMEDURATION_DT		= 48;
+cXSConstants.PRECISIONDECIMAL_DT	= 49;
+cXSConstants.ANYATOMICTYPE_DT		= 50;
+cXSConstants.ANYTYPE_DT				= 51;
+
+//
+cXSConstants.XT_YEARMONTHDURATION_DT=-1;
+cXSConstants.XT_UNTYPEDATOMIC_DT	=-2;
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cExpr() {
+	this.items	= [];
+};
+
+cExpr.prototype.items	= null;
+
+// Static members
+function fExpr_parse (oLexer, oStaticContext) {
+	var oItem;
+	if (oLexer.eof() ||!(oItem = fExprSingle_parse(oLexer, oStaticContext)))
+		return;
+
+	// Create expression
+	var oExpr	= new cExpr;
+	oExpr.items.push(oItem);
+	while (oLexer.peek() == ',') {
+		oLexer.next();
+		if (oLexer.eof() ||!(oItem = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oExpr.items.push(oItem);
+	}
+	return oExpr;
+};
+
+// Public members
+cExpr.prototype.evaluate	= function(oContext) {
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = this.items.length; nIndex < nLength; nIndex++)
+		oSequence	= hStaticContext_operators["concatenate"].call(oContext, oSequence, this.items[nIndex].evaluate(oContext));
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cExprSingle() {
+
+};
+
+// Static members
+function fExprSingle_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fIfExpr_parse(oLexer, oStaticContext)
+			|| fForExpr_parse(oLexer, oStaticContext)
+			|| fQuantifiedExpr_parse(oLexer, oStaticContext)
+			|| fOrExpr_parse(oLexer, oStaticContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cForExpr() {
+	this.bindings	= [];
+	this.returnExpr	= null;
+};
+
+cForExpr.prototype.bindings		= null;
+cForExpr.prototype.returnExpr	= null;
+
+// Static members
+function fForExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.peek() == "for" && oLexer.peek(1).substr(0, 1) == '$') {
+		oLexer.next();
+
+		var oForExpr	= new cForExpr,
+			oExpr;
+		do {
+			oForExpr.bindings.push(fSimpleForBinding_parse(oLexer, oStaticContext));
+		}
+		while (oLexer.peek() == ',' && oLexer.next());
+
+		if (oLexer.peek() != "return")
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+
+		oForExpr.returnExpr	= oExpr;
+		return oForExpr;
+	}
+};
+
+// Public members
+// for $x in X, $y in Y, $z in Z return $x + $y + $z
+// for $x in X return for $y in Y return for $z in Z return $x + $y + $z
+cForExpr.prototype.evaluate	= function (oContext) {
+	var oSequence	= [];
+	(function(oSelf, nBinding) {
+		var oBinding	= oSelf.bindings[nBinding++],
+			oSequence1	= oBinding.inExpr.evaluate(oContext),
+			sUri	= (oBinding.namespaceURI ? '{' + oBinding.namespaceURI + '}' : '') + oBinding.localName;
+		for (var nIndex = 0, nLength = oSequence1.length; nIndex < nLength; nIndex++) {
+			oContext.pushVariable(sUri, oSequence1[nIndex]);
+			if (nBinding < oSelf.bindings.length)
+				arguments.callee(oSelf, nBinding);
+			else
+				oSequence	= oSequence.concat(oSelf.returnExpr.evaluate(oContext));
+			oContext.popVariable(sUri);
+		}
+	})(this, 0);
+
+	return oSequence;
+};
+
+//
+function cSimpleForBinding(sPrefix, sLocalName, sNameSpaceURI, oInExpr) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+	this.inExpr		= oInExpr;
+};
+
+cSimpleForBinding.prototype.prefix			= null;
+cSimpleForBinding.prototype.localName		= null;
+cSimpleForBinding.prototype.namespaceURI	= null;
+cSimpleForBinding.prototype.inExpr		= null;
+
+function fSimpleForBinding_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().substr(1).match(rNameTest);
+	if (!aMatch)
+		throw new cException("XPST0003"
+
+		);
+
+	if (aMatch[1] == '*' || aMatch[2] == '*')
+		throw new cException("XPST0003"
+
+		);
+
+	oLexer.next();
+	if (oLexer.peek() != "in")
+		throw new cException("XPST0003"
+
+		);
+
+	oLexer.next();
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cSimpleForBinding(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) : null, oExpr);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cIfExpr(oCondExpr, oThenExpr, oElseExpr) {
+	this.condExpr	= oCondExpr;
+	this.thenExpr		= oThenExpr;
+	this.elseExpr		= oElseExpr;
+};
+
+cIfExpr.prototype.condExpr	= null;
+cIfExpr.prototype.thenExpr	= null;
+cIfExpr.prototype.elseExpr	= null;
+
+// Static members
+function fIfExpr_parse (oLexer, oStaticContext) {
+	var oCondExpr,
+		oThenExpr,
+		oElseExpr;
+	if (oLexer.peek() == "if" && oLexer.peek(1) == '(') {
+		oLexer.next(2);
+		//
+		if (oLexer.eof() ||!(oCondExpr = fExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.peek() != "then")
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.eof() ||!(oThenExpr = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+
+		if (oLexer.peek() != "else")
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.eof() ||!(oElseExpr = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		return new cIfExpr(oCondExpr, oThenExpr, oElseExpr);
+	}
+};
+
+// Public members
+cIfExpr.prototype.evaluate	= function (oContext) {
+	return this[fFunction_sequence_toEBV(this.condExpr.evaluate(oContext), oContext) ? "thenExpr" : "elseExpr"].evaluate(oContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cQuantifiedExpr(sQuantifier) {
+	this.quantifier		= sQuantifier;
+	this.bindings		= [];
+	this.satisfiesExpr	= null;
+};
+
+cQuantifiedExpr.prototype.bindings		= null;
+cQuantifiedExpr.prototype.quantifier	= null;
+cQuantifiedExpr.prototype.satisfiesExpr	= null;
+
+// Static members
+function fQuantifiedExpr_parse (oLexer, oStaticContext) {
+	var sQuantifier	= oLexer.peek();
+	if ((sQuantifier == "some" || sQuantifier == "every") && oLexer.peek(1).substr(0, 1) == '$') {
+		oLexer.next();
+
+		var oQuantifiedExpr	= new cQuantifiedExpr(sQuantifier),
+			oExpr;
+		do {
+			oQuantifiedExpr.bindings.push(fSimpleQuantifiedBinding_parse(oLexer, oStaticContext));
+		}
+		while (oLexer.peek() == ',' && oLexer.next());
+
+		if (oLexer.peek() != "satisfies")
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+
+		oQuantifiedExpr.satisfiesExpr	= oExpr;
+		return oQuantifiedExpr;
+	}
+};
+
+// Public members
+cQuantifiedExpr.prototype.evaluate	= function (oContext) {
+	// TODO: re-factor
+	var bEvery	= this.quantifier == "every",
+		bResult	= bEvery ? true : false;
+	(function(oSelf, nBinding) {
+		var oBinding	= oSelf.bindings[nBinding++],
+			oSequence1	= oBinding.inExpr.evaluate(oContext),
+			sUri	= (oBinding.namespaceURI ? '{' + oBinding.namespaceURI + '}' : '') + oBinding.localName;
+		for (var nIndex = 0, nLength = oSequence1.length; (nIndex < nLength) && (bEvery ? bResult :!bResult); nIndex++) {
+			oContext.pushVariable(sUri, oSequence1[nIndex]);
+			if (nBinding < oSelf.bindings.length)
+				arguments.callee(oSelf, nBinding);
+			else
+				bResult	= fFunction_sequence_toEBV(oSelf.satisfiesExpr.evaluate(oContext), oContext);
+			oContext.popVariable(sUri);
+		}
+	})(this, 0);
+
+	return [new cXSBoolean(bResult)];
+};
+
+
+
+//
+function cSimpleQuantifiedBinding(sPrefix, sLocalName, sNameSpaceURI, oInExpr) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+	this.inExpr		= oInExpr;
+};
+
+cSimpleQuantifiedBinding.prototype.prefix		= null;
+cSimpleQuantifiedBinding.prototype.localName	= null;
+cSimpleQuantifiedBinding.prototype.namespaceURI	= null;
+cSimpleQuantifiedBinding.prototype.inExpr	= null;
+
+function fSimpleQuantifiedBinding_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().substr(1).match(rNameTest);
+	if (!aMatch)
+		throw new cException("XPST0003"
+
+		);
+
+	if (aMatch[1] == '*' || aMatch[2] == '*')
+		throw new cException("XPST0003"
+
+		);
+
+	oLexer.next();
+	if (oLexer.peek() != "in")
+		throw new cException("XPST0003"
+
+		);
+
+	oLexer.next();
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cSimpleQuantifiedBinding(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) : null, oExpr);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cComparisonExpr(oLeft, oRight, sOperator) {
+	this.left	= oLeft;
+	this.right	= oRight;
+	this.operator	= sOperator;
+};
+
+cComparisonExpr.prototype.left	= null;
+cComparisonExpr.prototype.right	= null;
+cComparisonExpr.prototype.operator	= null;
+
+// Static members
+function fComparisonExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oRight;
+	if (oLexer.eof() ||!(oExpr = fRangeExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!(oLexer.peek() in hComparisonExpr_operators))
+		return oExpr;
+
+	// Comparison expression
+	var sOperator	= oLexer.peek();
+	oLexer.next();
+	if (oLexer.eof() ||!(oRight = fRangeExpr_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+	return new cComparisonExpr(oExpr, oRight, sOperator);
+};
+
+// Public members
+cComparisonExpr.prototype.evaluate	= function (oContext) {
+	var oResult	= hComparisonExpr_operators[this.operator](this, oContext);
+	return oResult == null ? [] : [oResult];
+};
+
+// General comparison
+function fComparisonExpr_GeneralComp(oExpr, oContext) {
+	var oLeft	= fFunction_sequence_atomize(oExpr.left.evaluate(oContext), oContext);
+	if (!oLeft.length)
+		return new cXSBoolean(false);
+
+	var oRight	= fFunction_sequence_atomize(oExpr.right.evaluate(oContext), oContext);
+	if (!oRight.length)
+		return new cXSBoolean(false);
+
+	var bResult	= false;
+	for (var nLeftIndex = 0, nLeftLength = oLeft.length, bLeft, vLeft; (nLeftIndex < nLeftLength) &&!bResult; nLeftIndex++) {
+		for (var nRightIndex = 0, nRightLength = oRight.length, bRight, vRight; (nRightIndex < nRightLength) &&!bResult; nRightIndex++) {
+
+			vLeft	= oLeft[nLeftIndex];
+			vRight	= oRight[nRightIndex];
+
+			bLeft	= vLeft instanceof cXSUntypedAtomic;
+			bRight	= vRight instanceof cXSUntypedAtomic;
+
+			if (bLeft && bRight) {
+				// cast xs:untypedAtomic to xs:string
+				vLeft	= cXSString.cast(vLeft);
+				vRight	= cXSString.cast(vRight);
+			}
+			else {
+				//
+				if (bLeft) {
+					// Special: durations
+					if (vRight instanceof cXSDayTimeDuration)
+						vLeft	= cXSDayTimeDuration.cast(vLeft);
+					else
+					if (vRight instanceof cXSYearMonthDuration)
+						vLeft	= cXSYearMonthDuration.cast(vLeft);
+					else
+					//
+					if (vRight.primitiveKind)
+						vLeft	= hStaticContext_dataTypes[vRight.primitiveKind].cast(vLeft);
+				}
+				else
+				if (bRight) {
+					// Special: durations
+					if (vLeft instanceof cXSDayTimeDuration)
+						vRight	= cXSDayTimeDuration.cast(vRight);
+					else
+					if (vLeft instanceof cXSYearMonthDuration)
+						vRight	= cXSYearMonthDuration.cast(vRight);
+					else
+					//
+					if (vLeft.primitiveKind)
+						vRight	= hStaticContext_dataTypes[vLeft.primitiveKind].cast(vRight);
+				}
+
+				// cast xs:anyURI to xs:string
+				if (vLeft instanceof cXSAnyURI)
+					vLeft	= cXSString.cast(vLeft);
+				if (vRight instanceof cXSAnyURI)
+					vRight	= cXSString.cast(vRight);
+			}
+
+			bResult	= hComparisonExpr_ValueComp_operators[hComparisonExpr_GeneralComp_map[oExpr.operator]](vLeft, vRight, oContext).valueOf();
+		}
+	}
+	return new cXSBoolean(bResult);
+};
+
+var hComparisonExpr_GeneralComp_map	= {
+	'=':	'eq',
+	'!=':	'ne',
+	'>':	'gt',
+	'<':	'lt',
+	'>=':	'ge',
+	'<=':	'le'
+};
+
+// Value comparison
+function fComparisonExpr_ValueComp(oExpr, oContext) {
+	var oLeft	= fFunction_sequence_atomize(oExpr.left.evaluate(oContext), oContext);
+	if (!oLeft.length)
+		return null;
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+
+	var oRight	= fFunction_sequence_atomize(oExpr.right.evaluate(oContext), oContext);
+	if (!oRight.length)
+		return null;
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+	);
+
+	var vLeft	= oLeft[0],
+		vRight	= oRight[0];
+
+	// cast xs:untypedAtomic to xs:string
+	if (vLeft instanceof cXSUntypedAtomic)
+		vLeft	= cXSString.cast(vLeft);
+	if (vRight instanceof cXSUntypedAtomic)
+		vRight	= cXSString.cast(vRight);
+
+	// cast xs:anyURI to xs:string
+	if (vLeft instanceof cXSAnyURI)
+		vLeft	= cXSString.cast(vLeft);
+	if (vRight instanceof cXSAnyURI)
+		vRight	= cXSString.cast(vRight);
+
+	//
+	return hComparisonExpr_ValueComp_operators[oExpr.operator](vLeft, vRight, oContext);
+};
+
+//
+var hComparisonExpr_ValueComp_operators	= {};
+hComparisonExpr_ValueComp_operators['eq']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-equal";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-equal";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-equal"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(0));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-equal";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-equal";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-equal";
+	}
+	else
+	if (oLeft instanceof cXSDuration) {
+		if (oRight instanceof cXSDuration)
+			sOperator	= "duration-equal";
+	}
+	else
+	if (oLeft instanceof cXSGYearMonth) {
+		if (oRight instanceof cXSGYearMonth)
+			sOperator	= "gYearMonth-equal";
+	}
+	else
+	if (oLeft instanceof cXSGYear) {
+		if (oRight instanceof cXSGYear)
+			sOperator	= "gYear-equal";
+	}
+	else
+	if (oLeft instanceof cXSGMonthDay) {
+		if (oRight instanceof cXSGMonthDay)
+			sOperator	= "gMonthDay-equal";
+	}
+	else
+	if (oLeft instanceof cXSGMonth) {
+		if (oRight instanceof cXSGMonth)
+			sOperator	= "gMonth-equal";
+	}
+	else
+	if (oLeft instanceof cXSGDay) {
+		if (oRight instanceof cXSGDay)
+			sOperator	= "gDay-equal";
+	}
+	// skipped: xs:anyURI (covered by xs:string)
+	else
+	if (oLeft instanceof cXSQName) {
+		if (oRight instanceof cXSQName)
+			sOperator	= "QName-equal";
+	}
+	else
+	if (oLeft instanceof cXSHexBinary) {
+		if (oRight instanceof cXSHexBinary)
+			sOperator	= "hexBinary-equal";
+	}
+	else
+	if (oLeft instanceof cXSBase64Binary) {
+		if (oRight instanceof cXSBase64Binary)
+			sOperator	= "base64Binary-equal";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	// skipped: xs:NOTATION
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+hComparisonExpr_ValueComp_operators['ne']	= function(oLeft, oRight, oContext) {
+	return new cXSBoolean(!hComparisonExpr_ValueComp_operators['eq'](oLeft, oRight, oContext).valueOf());
+};
+hComparisonExpr_ValueComp_operators['gt']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-greater-than"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(0));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "yearMonthDuration-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "dayTimeDuration-greater-than";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	// skipped: xs:anyURI (covered by xs:string)
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+hComparisonExpr_ValueComp_operators['lt']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-less-than";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-less-than";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-less-than"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(0));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-less-than";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-less-than";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-less-than";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "yearMonthDuration-less-than";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "dayTimeDuration-less-than";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	// skipped: xs:anyURI (covered by xs:string)
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+hComparisonExpr_ValueComp_operators['ge']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-less-than";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-less-than";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-greater-than"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(-1));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-less-than";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-less-than";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-less-than";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "yearMonthDuration-less-than";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "dayTimeDuration-less-than";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return new cXSBoolean(!hStaticContext_operators[sOperator].call(oContext, oLeft, oRight).valueOf());
+
+	// skipped: xs:anyURI (covered by xs:string)
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+hComparisonExpr_ValueComp_operators['le']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-less-than"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(1));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "yearMonthDuration-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "dayTimeDuration-greater-than";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return new cXSBoolean(!hStaticContext_operators[sOperator].call(oContext, oLeft, oRight).valueOf());
+
+	// skipped: xs:anyURI (covered by xs:string)
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+
+// Node comparison
+function fComparisonExpr_NodeComp(oExpr, oContext) {
+	var oLeft	= oExpr.left.evaluate(oContext);
+	if (!oLeft.length)
+		return null;
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+	// Assert item type
+	fFunctionCall_assertSequenceItemType(oContext, oLeft, cXTNode
+
+	);
+
+	var oRight	= oExpr.right.evaluate(oContext);
+	if (!oRight.length)
+		return null;
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+	);
+	// Assert item type
+	fFunctionCall_assertSequenceItemType(oContext, oRight, cXTNode
+
+	);
+
+	return hComparisonExpr_NodeComp_operators[oExpr.operator](oLeft[0], oRight[0], oContext);
+};
+
+var hComparisonExpr_NodeComp_operators	= {};
+hComparisonExpr_NodeComp_operators['is']	= function(oLeft, oRight, oContext) {
+	return hStaticContext_operators["is-same-node"].call(oContext, oLeft, oRight);
+};
+hComparisonExpr_NodeComp_operators['>>']	= function(oLeft, oRight, oContext) {
+	return hStaticContext_operators["node-after"].call(oContext, oLeft, oRight);
+};
+hComparisonExpr_NodeComp_operators['<<']	= function(oLeft, oRight, oContext) {
+	return hStaticContext_operators["node-before"].call(oContext, oLeft, oRight);
+};
+
+// Operators
+var hComparisonExpr_operators	= {
+	// GeneralComp
+	'=':	fComparisonExpr_GeneralComp,
+	'!=':	fComparisonExpr_GeneralComp,
+	'<':	fComparisonExpr_GeneralComp,
+	'<=':	fComparisonExpr_GeneralComp,
+	'>':	fComparisonExpr_GeneralComp,
+	'>=':	fComparisonExpr_GeneralComp,
+	// ValueComp
+	'eq':	fComparisonExpr_ValueComp,
+	'ne':	fComparisonExpr_ValueComp,
+	'lt':	fComparisonExpr_ValueComp,
+	'le':	fComparisonExpr_ValueComp,
+	'gt':	fComparisonExpr_ValueComp,
+	'ge':	fComparisonExpr_ValueComp,
+	// NodeComp
+	'is':	fComparisonExpr_NodeComp,
+	'>>':	fComparisonExpr_NodeComp,
+	'<<':	fComparisonExpr_NodeComp
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cAdditiveExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cAdditiveExpr.prototype.left	= null;
+cAdditiveExpr.prototype.items	= null;
+
+//
+var hAdditiveExpr_operators	= {};
+hAdditiveExpr_operators['+']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '',
+		bReverse	= false;
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-add";
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "add-yearMonthDuration-to-date";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "add-dayTimeDuration-to-date";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSDate) {
+			sOperator	= "add-yearMonthDuration-to-date";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSDateTime) {
+			sOperator	= "add-yearMonthDuration-to-dateTime";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "add-yearMonthDurations";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDate) {
+			sOperator	= "add-dayTimeDuration-to-date";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSTime) {
+			sOperator	= "add-dayTimeDuration-to-time";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSDateTime) {
+			sOperator	= "add-dayTimeDuration-to-dateTime";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "add-dayTimeDurations";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "add-dayTimeDuration-to-time";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "add-yearMonthDuration-to-dateTime";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "add-dayTimeDuration-to-dateTime";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, bReverse ? oRight : oLeft, bReverse ? oLeft : oRight);
+
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hAdditiveExpr_operators['-']	= function (oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-subtract";
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "subtract-dates";
+		else
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "subtract-yearMonthDuration-from-date";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "subtract-dayTimeDuration-from-date";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "subtract-times";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "subtract-dayTimeDuration-from-time";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "subtract-dateTimes";
+		else
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "subtract-yearMonthDuration-from-dateTime";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "subtract-dayTimeDuration-from-dateTime";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "subtract-yearMonthDurations";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "subtract-dayTimeDurations";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+
+// Static members
+function fAdditiveExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fMultiplicativeExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!(oLexer.peek() in hAdditiveExpr_operators))
+		return oExpr;
+
+	// Additive expression
+	var oAdditiveExpr	= new cAdditiveExpr(oExpr),
+		sOperator;
+	while ((sOperator = oLexer.peek()) in hAdditiveExpr_operators) {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fMultiplicativeExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oAdditiveExpr.items.push([sOperator, oExpr]);
+	}
+	return oAdditiveExpr;
+};
+
+// Public members
+cAdditiveExpr.prototype.evaluate	= function (oContext) {
+	var oLeft	= fFunction_sequence_atomize(this.left.evaluate(oContext), oContext);
+
+	if (!oLeft.length)
+		return [];
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+
+	var vLeft	= oLeft[0];
+	if (vLeft instanceof cXSUntypedAtomic)
+		vLeft	= cXSDouble.cast(vLeft);	// cast to xs:double
+
+	for (var nIndex = 0, nLength = this.items.length, oRight, vRight; nIndex < nLength; nIndex++) {
+		oRight	= fFunction_sequence_atomize(this.items[nIndex][1].evaluate(oContext), oContext);
+
+		if (!oRight.length)
+			return [];
+		// Assert cardinality
+		fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+		);
+
+		vRight	= oRight[0];
+		if (vRight instanceof cXSUntypedAtomic)
+			vRight	= cXSDouble.cast(vRight);	// cast to xs:double
+
+		vLeft	= hAdditiveExpr_operators[this.items[nIndex][0]](vLeft, vRight, oContext);
+	}
+	return [vLeft];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cMultiplicativeExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cMultiplicativeExpr.prototype.left	= null;
+cMultiplicativeExpr.prototype.items	= null;
+
+//
+var hMultiplicativeExpr_operators	= {};
+hMultiplicativeExpr_operators['*']		= function (oLeft, oRight, oContext) {
+	var sOperator	= '',
+		bReverse	= false;
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-multiply";
+		else
+		if (oRight instanceof cXSYearMonthDuration) {
+			sOperator	= "multiply-yearMonthDuration";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSDayTimeDuration) {
+			sOperator	= "multiply-dayTimeDuration";
+			bReverse	= true;
+		}
+	}
+	else {
+		if (oLeft instanceof cXSYearMonthDuration) {
+			if (fXSAnyAtomicType_isNumeric(oRight))
+				sOperator	= "multiply-yearMonthDuration";
+		}
+		else
+		if (oLeft instanceof cXSDayTimeDuration) {
+			if (fXSAnyAtomicType_isNumeric(oRight))
+				sOperator	= "multiply-dayTimeDuration";
+		}
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, bReverse ? oRight : oLeft, bReverse ? oLeft : oRight);
+
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hMultiplicativeExpr_operators['div']	= function (oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-divide";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "divide-yearMonthDuration";
+		else
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "divide-yearMonthDuration-by-yearMonthDuration";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "divide-dayTimeDuration";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "divide-dayTimeDuration-by-dayTimeDuration";
+	}
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hMultiplicativeExpr_operators['idiv']	= function (oLeft, oRight, oContext) {
+	if (fXSAnyAtomicType_isNumeric(oLeft) && fXSAnyAtomicType_isNumeric(oRight))
+		return hStaticContext_operators["numeric-integer-divide"].call(oContext, oLeft, oRight);
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hMultiplicativeExpr_operators['mod']	= function (oLeft, oRight, oContext) {
+	if (fXSAnyAtomicType_isNumeric(oLeft) && fXSAnyAtomicType_isNumeric(oRight))
+		return hStaticContext_operators["numeric-mod"].call(oContext, oLeft, oRight);
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+
+// Static members
+function fMultiplicativeExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fUnionExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!(oLexer.peek() in hMultiplicativeExpr_operators))
+		return oExpr;
+
+	// Additive expression
+	var oMultiplicativeExpr	= new cMultiplicativeExpr(oExpr),
+		sOperator;
+	while ((sOperator = oLexer.peek()) in hMultiplicativeExpr_operators) {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fUnionExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oMultiplicativeExpr.items.push([sOperator, oExpr]);
+	}
+	return oMultiplicativeExpr;
+};
+
+// Public members
+cMultiplicativeExpr.prototype.evaluate	= function (oContext) {
+	var oLeft	= fFunction_sequence_atomize(this.left.evaluate(oContext), oContext);
+
+	//
+	if (!oLeft.length)
+		return [];
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+
+	var vLeft	= oLeft[0];
+	if (vLeft instanceof cXSUntypedAtomic)
+		vLeft	= cXSDouble.cast(vLeft);	// cast to xs:double
+
+	for (var nIndex = 0, nLength = this.items.length, oRight, vRight; nIndex < nLength; nIndex++) {
+		oRight	= fFunction_sequence_atomize(this.items[nIndex][1].evaluate(oContext), oContext);
+
+		if (!oRight.length)
+			return [];
+		// Assert cardinality
+		fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+		);
+
+		vRight	= oRight[0];
+		if (vRight instanceof cXSUntypedAtomic)
+			vRight	= cXSDouble.cast(vRight);	// cast to xs:double
+
+		vLeft	= hMultiplicativeExpr_operators[this.items[nIndex][0]](vLeft, vRight, oContext);
+	}
+	return [vLeft];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cUnaryExpr(sOperator, oExpr) {
+	this.operator	= sOperator;
+	this.expression	= oExpr;
+};
+
+cUnaryExpr.prototype.operator	= null;
+cUnaryExpr.prototype.expression	= null;
+
+//
+var hUnaryExpr_operators	= {};
+hUnaryExpr_operators['-']	= function(oRight, oContext) {
+	if (fXSAnyAtomicType_isNumeric(oRight))
+		return hStaticContext_operators["numeric-unary-minus"].call(oContext, oRight);
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hUnaryExpr_operators['+']	= function(oRight, oContext) {
+	if (fXSAnyAtomicType_isNumeric(oRight))
+		return hStaticContext_operators["numeric-unary-plus"].call(oContext, oRight);
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+
+// Static members
+// UnaryExpr	:= ("-" | "+")* ValueExpr
+function fUnaryExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.eof())
+		return;
+	if (!(oLexer.peek() in hUnaryExpr_operators))
+		return fValueExpr_parse(oLexer, oStaticContext);
+
+	// Unary expression
+	var sOperator	= '+',
+		oExpr;
+	while (oLexer.peek() in hUnaryExpr_operators) {
+		if (oLexer.peek() == '-')
+			sOperator	= sOperator == '-' ? '+' : '-';
+		oLexer.next();
+	}
+	if (oLexer.eof() ||!(oExpr = fValueExpr_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+	return new cUnaryExpr(sOperator, oExpr);
+};
+
+cUnaryExpr.prototype.evaluate	= function (oContext) {
+	var oRight	= fFunction_sequence_atomize(this.expression.evaluate(oContext), oContext);
+
+	//
+	if (!oRight.length)
+		return [];
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+	);
+
+	var vRight	= oRight[0];
+	if (vRight instanceof cXSUntypedAtomic)
+		vRight	= cXSDouble.cast(vRight);	// cast to xs:double
+
+	return [hUnaryExpr_operators[this.operator](vRight, oContext)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cValueExpr() {
+
+};
+
+// Static members
+function fValueExpr_parse (oLexer, oStaticContext) {
+	return fPathExpr_parse(oLexer, oStaticContext);
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cOrExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cOrExpr.prototype.left	= null;
+cOrExpr.prototype.items	= null;
+
+// Static members
+function fOrExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fAndExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (oLexer.peek() != "or")
+		return oExpr;
+
+	// Or expression
+	var oOrExpr	= new cOrExpr(oExpr);
+	while (oLexer.peek() == "or") {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fAndExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oOrExpr.items.push(oExpr);
+	}
+	return oOrExpr;
+};
+
+// Public members
+cOrExpr.prototype.evaluate	= function (oContext) {
+	var bValue	= fFunction_sequence_toEBV(this.left.evaluate(oContext), oContext);
+	for (var nIndex = 0, nLength = this.items.length; (nIndex < nLength) && !bValue; nIndex++)
+		bValue	= fFunction_sequence_toEBV(this.items[nIndex].evaluate(oContext), oContext);
+	return [new cXSBoolean(bValue)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cAndExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cAndExpr.prototype.left		= null;
+cAndExpr.prototype.items	= null;
+
+// Static members
+function fAndExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fComparisonExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (oLexer.peek() != "and")
+		return oExpr;
+
+	// And expression
+	var oAndExpr	= new cAndExpr(oExpr);
+	while (oLexer.peek() == "and") {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fComparisonExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oAndExpr.items.push(oExpr);
+	}
+	return oAndExpr;
+};
+
+// Public members
+cAndExpr.prototype.evaluate	= function (oContext) {
+	var bValue	= fFunction_sequence_toEBV(this.left.evaluate(oContext), oContext);
+	for (var nIndex = 0, nLength = this.items.length; (nIndex < nLength) && bValue; nIndex++)
+		bValue	= fFunction_sequence_toEBV(this.items[nIndex].evaluate(oContext), oContext);
+	return [new cXSBoolean(bValue)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cStepExpr() {
+
+};
+
+cStepExpr.prototype.predicates	= null;
+
+// Static members
+function fStepExpr_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fFilterExpr_parse(oLexer, oStaticContext)
+			|| fAxisStep_parse(oLexer, oStaticContext);
+};
+
+function fStepExpr_parsePredicates (oLexer, oStaticContext, oStep) {
+	var oExpr;
+	// Parse predicates
+	while (oLexer.peek() == '[') {
+		oLexer.next();
+
+		if (oLexer.eof() ||!(oExpr = fExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+
+		oStep.predicates.push(oExpr);
+
+		if (oLexer.peek() != ']')
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+	}
+};
+
+// Public members
+cStepExpr.prototype.applyPredicates	= function(oSequence, oContext) {
+	var vContextItem	= oContext.item,
+		nContextPosition= oContext.position,
+		nContextSize	= oContext.size;
+	//
+	for (var nPredicateIndex = 0, oSequence1, nPredicateLength = this.predicates.length; nPredicateIndex < nPredicateLength; nPredicateIndex++) {
+		oSequence1	= oSequence;
+		oSequence	= [];
+		for (var nIndex = 0, oSequence2, nLength = oSequence1.length; nIndex < nLength; nIndex++) {
+			// Set new context
+			oContext.item		= oSequence1[nIndex];
+			oContext.position	= nIndex + 1;
+			oContext.size		= nLength;
+			//
+			oSequence2	= this.predicates[nPredicateIndex].evaluate(oContext);
+			//
+			if (oSequence2.length == 1 && fXSAnyAtomicType_isNumeric(oSequence2[0])) {
+				if (oSequence2[0].valueOf() == nIndex + 1)
+					oSequence.push(oSequence1[nIndex]);
+			}
+			else
+			if (fFunction_sequence_toEBV(oSequence2, oContext))
+				oSequence.push(oSequence1[nIndex]);
+		}
+	}
+	// Restore context
+	oContext.item		= vContextItem;
+	oContext.position	= nContextPosition;
+	oContext.size		= nContextSize;
+	//
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cAxisStep(sAxis, oTest) {
+	this.axis	= sAxis;
+	this.test	= oTest;
+	this.predicates	= [];
+};
+
+cAxisStep.prototype	= new cStepExpr;
+
+cAxisStep.prototype.axis		= null;
+cAxisStep.prototype.test		= null;
+
+//
+var hAxisStep_axises	= {};
+// Forward axis
+hAxisStep_axises["attribute"]			= {};
+hAxisStep_axises["child"]				= {};
+hAxisStep_axises["descendant"]			= {};
+hAxisStep_axises["descendant-or-self"]	= {};
+hAxisStep_axises["following"]			= {};
+hAxisStep_axises["following-sibling"]	= {};
+hAxisStep_axises["self"]				= {};
+// hAxisStep_axises["namespace"]			= {};	// deprecated in 2.0
+// Reverse axis
+hAxisStep_axises["ancestor"]			= {};
+hAxisStep_axises["ancestor-or-self"]	= {};
+hAxisStep_axises["parent"]				= {};
+hAxisStep_axises["preceding"]			= {};
+hAxisStep_axises["preceding-sibling"]	= {};
+
+// Static members
+function fAxisStep_parse (oLexer, oStaticContext) {
+	var sAxis	= oLexer.peek(),
+		oExpr,
+		oStep;
+	if (oLexer.peek(1) == '::') {
+		if (!(sAxis in hAxisStep_axises))
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next(2);
+		if (oLexer.eof() ||!(oExpr = fNodeTest_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		oStep	= new cAxisStep(sAxis, oExpr);
+	}
+	else
+	if (sAxis == '..') {
+		oLexer.next();
+		oStep	= new cAxisStep("parent", new cKindTest("node"));
+	}
+	else
+	if (sAxis == '@') {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fNodeTest_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		oStep	= new cAxisStep("attribute", oExpr);
+	}
+	else {
+		if (oLexer.eof() ||!(oExpr = fNodeTest_parse(oLexer, oStaticContext)))
+			return;
+		oStep	= new cAxisStep(oExpr instanceof cKindTest && oExpr.name == "attribute" ? "attribute" : "child", oExpr);
+	}
+	//
+	fStepExpr_parsePredicates(oLexer, oStaticContext, oStep);
+
+	return oStep;
+};
+
+// Public members
+cAxisStep.prototype.evaluate	= function (oContext) {
+	var oItem	= oContext.item;
+
+	if (!oContext.DOMAdapter.isNode(oItem))
+		throw new cException("XPTY0020");
+
+	var oSequence	= [],
+		fGetProperty= oContext.DOMAdapter.getProperty,
+		nType		= fGetProperty(oItem, "nodeType");
+
+	switch (this.axis) {
+		// Forward axis
+		case "attribute":
+			if (nType == 1)
+				for (var aAttributes = fGetProperty(oItem, "attributes"), nIndex = 0, nLength = aAttributes.length; nIndex < nLength; nIndex++)
+					oSequence.push(aAttributes[nIndex]);
+			break;
+
+		case "child":
+			for (var oNode = fGetProperty(oItem, "firstChild"); oNode; oNode = fGetProperty(oNode, "nextSibling"))
+				oSequence.push(oNode);
+			break;
+
+		case "descendant-or-self":
+			oSequence.push(oItem);
+			// No break left intentionally
+		case "descendant":
+			fAxisStep_getChildrenForward(fGetProperty(oItem, "firstChild"), oSequence, fGetProperty);
+			break;
+
+		case "following":
+			// TODO: Attribute node context
+			for (var oParent = oItem, oSibling; oParent; oParent = fGetProperty(oParent, "parentNode"))
+				if (oSibling = fGetProperty(oParent, "nextSibling"))
+					fAxisStep_getChildrenForward(oSibling, oSequence, fGetProperty);
+			break;
+
+		case "following-sibling":
+			for (var oNode = oItem; oNode = fGetProperty(oNode, "nextSibling");)
+				oSequence.push(oNode);
+			break;
+
+		case "self":
+			oSequence.push(oItem);
+			break;
+
+		// Reverse axis
+		case "ancestor-or-self":
+			oSequence.push(oItem);
+			// No break left intentionally
+		case "ancestor":
+			for (var oNode = nType == 2 ? fGetProperty(oItem, "ownerElement") : oItem; oNode = fGetProperty(oNode, "parentNode");)
+				oSequence.push(oNode);
+			break;
+
+		case "parent":
+			var oParent	= nType == 2 ? fGetProperty(oItem, "ownerElement") : fGetProperty(oItem, "parentNode");
+			if (oParent)
+				oSequence.push(oParent);
+			break;
+
+		case "preceding":
+			// TODO: Attribute node context
+			for (var oParent = oItem, oSibling; oParent; oParent = fGetProperty(oParent, "parentNode"))
+				if (oSibling = fGetProperty(oParent, "previousSibling"))
+					fAxisStep_getChildrenBackward(oSibling, oSequence, fGetProperty);
+			break;
+
+		case "preceding-sibling":
+			for (var oNode = oItem; oNode = fGetProperty(oNode, "previousSibling");)
+				oSequence.push(oNode);
+			break;
+	}
+
+	// Apply test
+	if (oSequence.length && !(this.test instanceof cKindTest && this.test.name == "node")) {
+		var oSequence1	= oSequence;
+		oSequence	= [];
+		for (var nIndex = 0, nLength = oSequence1.length; nIndex < nLength; nIndex++) {
+			if (this.test.test(oSequence1[nIndex], oContext))
+				oSequence.push(oSequence1[nIndex]);
+		}
+	}
+
+	// Apply predicates
+	if (oSequence.length && this.predicates.length)
+		oSequence	= this.applyPredicates(oSequence, oContext);
+
+	// Reverse results if reverse axis
+	switch (this.axis) {
+		case "ancestor":
+		case "ancestor-or-self":
+		case "parent":
+		case "preceding":
+		case "preceding-sibling":
+			oSequence.reverse();
+	}
+
+	return oSequence;
+};
+
+//
+function fAxisStep_getChildrenForward(oNode, oSequence, fGetProperty) {
+	for (var oChild; oNode; oNode = fGetProperty(oNode, "nextSibling")) {
+		oSequence.push(oNode);
+		if (oChild = fGetProperty(oNode, "firstChild"))
+			fAxisStep_getChildrenForward(oChild, oSequence, fGetProperty);
+	}
+};
+
+function fAxisStep_getChildrenBackward(oNode, oSequence, fGetProperty) {
+	for (var oChild; oNode; oNode = fGetProperty(oNode, "previousSibling")) {
+		if (oChild = fGetProperty(oNode, "lastChild"))
+			fAxisStep_getChildrenBackward(oChild, oSequence, fGetProperty);
+		oSequence.push(oNode);
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cPathExpr() {
+	this.items	= [];
+};
+
+cPathExpr.prototype.items	= null;
+
+// Static members
+function fPathExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.eof())
+		return;
+	var sSingleSlash	= '/',
+		sDoubleSlash	= '/' + '/';
+
+	var oPathExpr	= new cPathExpr(),
+		sSlash	= oLexer.peek(),
+		oExpr;
+	// Parse first step
+	if (sSlash == sDoubleSlash || sSlash == sSingleSlash) {
+		oLexer.next();
+		oPathExpr.items.push(new cFunctionCall(null, "root", sNS_XPF));
+		//
+		if (sSlash == sDoubleSlash)
+			oPathExpr.items.push(new cAxisStep("descendant-or-self", new cKindTest("node")));
+	}
+
+	//
+	if (oLexer.eof() ||!(oExpr = fStepExpr_parse(oLexer, oStaticContext))) {
+		if (sSlash == sSingleSlash)
+			return oPathExpr.items[0];	// '/' expression
+		if (sSlash == sDoubleSlash)
+			throw new cException("XPST0003"
+
+			);
+		return;
+	}
+	oPathExpr.items.push(oExpr);
+
+	// Parse other steps
+	while ((sSlash = oLexer.peek()) == sSingleSlash || sSlash == sDoubleSlash) {
+		if (sSlash == sDoubleSlash)
+			oPathExpr.items.push(new cAxisStep("descendant-or-self", new cKindTest("node")));
+		//
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fStepExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		oPathExpr.items.push(oExpr);
+	}
+
+	if (oPathExpr.items.length == 1)
+		return oPathExpr.items[0];
+
+	//
+	return oPathExpr;
+};
+
+// Public members
+cPathExpr.prototype.evaluate	= function (oContext) {
+	var vContextItem	= oContext.item;
+	//
+	var oSequence	= [vContextItem];
+	for (var nItemIndex = 0, nItemLength = this.items.length, oSequence1; nItemIndex < nItemLength; nItemIndex++) {
+		oSequence1	= [];
+		for (var nIndex = 0, nLength = oSequence.length; nIndex < nLength; nIndex++) {
+			// Set new context item
+			oContext.item	= oSequence[nIndex];
+			//
+			for (var nRightIndex = 0, oSequence2 = this.items[nItemIndex].evaluate(oContext), nRightLength = oSequence2.length; nRightIndex < nRightLength; nRightIndex++)
+				if ((nItemIndex < nItemLength - 1) && !oContext.DOMAdapter.isNode(oSequence2[nRightIndex]))
+					throw new cException("XPTY0019");
+				else
+				if (fArray_indexOf(oSequence1, oSequence2[nRightIndex]) ==-1)
+					oSequence1.push(oSequence2[nRightIndex]);
+		}
+		oSequence	= oSequence1;
+	};
+	// Restore context item
+	oContext.item	= vContextItem;
+	//
+	return fFunction_sequence_order(oSequence, oContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cNodeTest() {
+
+};
+
+// Static members
+function fNodeTest_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fKindTest_parse(oLexer, oStaticContext)
+			|| fNameTest_parse(oLexer, oStaticContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cKindTest(sName) {
+	this.name	= sName;
+	this.args	= [];
+};
+
+cKindTest.prototype	= new cNodeTest;
+
+cKindTest.prototype.name	= null;
+cKindTest.prototype.args	= null;
+
+var hKindTest_names	= {};
+//
+hKindTest_names["document-node"]	= {};
+hKindTest_names["element"]			= {};
+hKindTest_names["attribute"]		= {};
+hKindTest_names["processing-instruction"]	= {};
+hKindTest_names["comment"]			= {};
+hKindTest_names["text"]				= {};
+hKindTest_names["node"]				= {};
+//
+hKindTest_names["schema-element"]	= {};
+hKindTest_names["schema-attribute"]	= {};
+
+// Static members
+function fKindTest_parse (oLexer, oStaticContext) {
+	var sName	= oLexer.peek(),
+		oValue;
+	if (oLexer.peek(1) == '(') {
+		//
+		if (!(sName in hKindTest_names))
+			throw new cException("XPST0003"
+
+			);
+
+		//
+		oLexer.next(2);
+		//
+		var oTest	= new cKindTest(sName);
+		if (oLexer.peek() != ')') {
+			if (sName == "document-node") {
+				// TODO: parse test further
+			}
+			else
+			if (sName == "element") {
+				// TODO: parse test further
+			}
+			else
+			if (sName == "attribute") {
+				// TODO: parse test further
+			}
+			else
+			if (sName == "processing-instruction") {
+				oValue = fStringLiteral_parse(oLexer, oStaticContext);
+				if (!oValue) {
+					oValue = new cStringLiteral(new cXSString(oLexer.peek()));
+					oLexer.next();
+				}
+				oTest.args.push(oValue);
+			}
+			else
+			if (sName == "schema-attribute") {
+				// TODO: parse test further
+			}
+			else
+			if (sName == "schema-element") {
+				// TODO: parse test further
+			}
+		}
+		else {
+			if (sName == "schema-attribute")
+				throw new cException("XPST0003"
+
+				);
+			else
+			if (sName == "schema-element")
+				throw new cException("XPST0003"
+
+				);
+		}
+
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+
+		return oTest;
+	}
+};
+
+// Public members
+cKindTest.prototype.test	= function (oNode, oContext) {
+	var fGetProperty	= oContext.DOMAdapter.getProperty,
+		nType	= oContext.DOMAdapter.isNode(oNode) ? fGetProperty(oNode, "nodeType") : 0,
+		sTarget;
+	switch (this.name) {
+		// Node type test
+		case "node":			return !!nType;
+		case "attribute":				if (nType != 2)	return false;	break;
+		case "document-node":	return nType == 9;
+		case "element":			return nType == 1;
+		case "processing-instruction":	if (nType != 7)	return false;	break;
+		case "comment":			return nType == 8;
+		case "text":			return nType == 3 || nType == 4;
+
+		// Schema tests
+		case "schema-attribute":
+			throw "KindTest '" + "schema-attribute" + "' not implemented";
+
+		case "schema-element":
+			throw "KindTest '" + "schema-element" + "' not implemented";
+	}
+
+	// Additional tests
+	if (nType == 2)
+		return fGetProperty(oNode, "prefix") != "xmlns" && fGetProperty(oNode, "localName") != "xmlns";
+	if (nType == 7) {
+		sTarget = fGetProperty(oNode, "target");
+		return this.args.length ? sTarget == this.args[0].value : sTarget != "xml";
+	}
+
+	return true;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cNameTest(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+};
+
+cNameTest.prototype	= new cNodeTest;
+
+cNameTest.prototype.prefix			= null;
+cNameTest.prototype.localName		= null;
+cNameTest.prototype.namespaceURI	= null;
+
+// Static members
+var rNameTest	= /^(?:(?![0-9-])(\w[\w.-]*|\*)\:)?(?![0-9-])(\w[\w.-]*|\*)$/;
+function fNameTest_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().match(rNameTest);
+	if (aMatch) {
+		if (aMatch[1] == '*' && aMatch[2] == '*')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+		return new cNameTest(aMatch[1] || null, aMatch[2], aMatch[1] ? aMatch[1] == '*' ? '*' : oStaticContext.getURIForPrefix(aMatch[1]) || null : oStaticContext.defaultElementNamespace);
+	}
+};
+
+// Public members
+cNameTest.prototype.test	= function (oNode, oContext) {
+	var fGetProperty	= oContext.DOMAdapter.getProperty,
+		nType	= fGetProperty(oNode, "nodeType");
+	if (nType == 1 || nType == 2) {
+		if (this.localName == '*')
+			return (nType == 1 || (fGetProperty(oNode, "prefix") != "xmlns" && fGetProperty(oNode, "localName") != "xmlns")) && (!this.prefix || fGetProperty(oNode, "namespaceURI") == this.namespaceURI);
+		if (this.localName == fGetProperty(oNode, "localName"))
+			return this.namespaceURI == '*' || (nType == 2 && !this.prefix && !fGetProperty(oNode, "prefix")) || fGetProperty(oNode, "namespaceURI") == this.namespaceURI;
+	}
+	//
+	return false;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cPrimaryExpr() {
+
+};
+
+// Static members
+function fPrimaryExpr_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fContextItemExpr_parse(oLexer, oStaticContext)
+			|| fParenthesizedExpr_parse(oLexer, oStaticContext)
+			|| fFunctionCall_parse(oLexer, oStaticContext)
+			|| fVarRef_parse(oLexer, oStaticContext)
+			|| fLiteral_parse(oLexer, oStaticContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cParenthesizedExpr(oExpr) {
+	this.expression	= oExpr;
+};
+
+// Static members
+function fParenthesizedExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.peek() == '(') {
+		oLexer.next();
+		// Check if not empty (allowed)
+		var oExpr	= null;
+		if (oLexer.peek() != ')')
+			oExpr	= fExpr_parse(oLexer, oStaticContext);
+
+		//
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+
+		//
+		return new cParenthesizedExpr(oExpr);
+	}
+};
+
+// Public members
+cParenthesizedExpr.prototype.evaluate	= function (oContext) {
+	return this.expression ? this.expression.evaluate(oContext) : [];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cContextItemExpr() {
+
+};
+
+// Static members
+function fContextItemExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.peek() == '.') {
+		oLexer.next();
+		return new cContextItemExpr;
+	}
+};
+
+// Public members
+cContextItemExpr.prototype.evaluate	= function (oContext) {
+	if (oContext.item == null)
+		throw new cException("XPDY0002"
+
+		);
+	//
+	return [oContext.item];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cLiteral() {
+
+};
+
+cLiteral.prototype.value	= null;
+
+// Static members
+function fLiteral_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fNumericLiteral_parse(oLexer, oStaticContext)
+			|| fStringLiteral_parse(oLexer, oStaticContext);
+};
+
+// Public members
+cLiteral.prototype.evaluate	= function (oContext) {
+	return [this.value];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cNumericLiteral(oValue) {
+	this.value	= oValue;
+};
+
+cNumericLiteral.prototype	= new cLiteral;
+
+// Integer | Decimal | Double
+var rNumericLiteral	= /^[+\-]?(?:(?:(\d+)(?:\.(\d*))?)|(?:\.(\d+)))(?:[eE]([+-])?(\d+))?$/;
+function fNumericLiteral_parse (oLexer, oStaticContext) {
+	var sValue	= oLexer.peek(),
+		vValue	= fNumericLiteral_parseValue(sValue);
+	if (vValue) {
+		oLexer.next();
+		return new cNumericLiteral(vValue);
+	}
+};
+
+function fNumericLiteral_parseValue(sValue) {
+	var aMatch	= sValue.match(rNumericLiteral);
+	if (aMatch) {
+		var cType	= cXSInteger;
+		if (aMatch[5])
+			cType	= cXSDouble;
+		else
+		if (aMatch[2] || aMatch[3])
+			cType	= cXSDecimal;
+		return new cType(+sValue);
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cStringLiteral(oValue) {
+	this.value	= oValue;
+};
+
+cStringLiteral.prototype	= new cLiteral;
+
+var rStringLiteral	= /^'([^']*(?:''[^']*)*)'|"([^"]*(?:""[^"]*)*)"$/;
+function fStringLiteral_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().match(rStringLiteral);
+	if (aMatch) {
+		oLexer.next();
+		return new cStringLiteral(new cXSString(aMatch[1] ? aMatch[1].replace("''", "'") : aMatch[2] ? aMatch[2].replace('""', '"') : ''));
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cFilterExpr(oPrimary) {
+	this.expression	= oPrimary;
+	this.predicates	= [];
+};
+
+cFilterExpr.prototype	= new cStepExpr;
+
+cFilterExpr.prototype.expression	= null;
+
+// Static members
+function fFilterExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fPrimaryExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	var oFilterExpr	= new cFilterExpr(oExpr);
+	// Parse predicates
+	fStepExpr_parsePredicates(oLexer, oStaticContext, oFilterExpr);
+
+	// If no predicates found
+	if (oFilterExpr.predicates.length == 0)
+		return oFilterExpr.expression;
+
+	return oFilterExpr;
+};
+
+// Public members
+cFilterExpr.prototype.evaluate	= function (oContext) {
+	var oSequence	= this.expression.evaluate(oContext);
+	if (this.predicates.length && oSequence.length)
+		oSequence	= this.applyPredicates(oSequence, oContext);
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cVarRef(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+};
+
+cVarRef.prototype.prefix		= null;
+cVarRef.prototype.localName		= null;
+cVarRef.prototype.namespaceURI	= null;
+
+// Static members
+function fVarRef_parse (oLexer, oStaticContext) {
+	if (oLexer.peek().substr(0, 1) == '$') {
+		var aMatch	= oLexer.peek().substr(1).match(rNameTest);
+		if (aMatch) {
+			if (aMatch[1] == '*' || aMatch[2] == '*')
+				throw new cException("XPST0003"
+	
+				);
+
+			var oVarRef	= new cVarRef(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) : null);
+			oLexer.next();
+			return oVarRef;
+		}
+	}
+};
+
+// Public members
+cVarRef.prototype.evaluate	= function (oContext) {
+	var sUri	= (this.namespaceURI ? '{' + this.namespaceURI + '}' : '') + this.localName;
+	if (oContext.scope.hasOwnProperty(sUri))
+		return [oContext.scope[sUri]];
+	//
+	throw new cException("XPST0008"
+
+	);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cFunctionCall(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+	this.args	= [];
+};
+
+cFunctionCall.prototype.prefix			= null;
+cFunctionCall.prototype.localName		= null;
+cFunctionCall.prototype.namespaceURI	= null;
+cFunctionCall.prototype.args	= null;
+
+// Static members
+function fFunctionCall_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().match(rNameTest);
+	if (aMatch && oLexer.peek(1) == '(') {
+		// Reserved "functions"
+		if (!aMatch[1] && (aMatch[2] in hKindTest_names))
+			return fAxisStep_parse(oLexer, oStaticContext);
+		// Other functions
+		if (aMatch[1] == '*' || aMatch[2] == '*')
+			throw new cException("XPST0003"
+
+			);
+		var oFunctionCallExpr	= new cFunctionCall(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) || null : oStaticContext.defaultFunctionNamespace),
+			oExpr;
+		oLexer.next(2);
+		//
+		if (oLexer.peek() != ')') {
+			do {
+				if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+					throw new cException("XPST0003"
+
+					);
+				//
+				oFunctionCallExpr.args.push(oExpr);
+			}
+			while (oLexer.peek() == ',' && oLexer.next());
+			//
+			if (oLexer.peek() != ')')
+				throw new cException("XPST0003"
+
+				);
+		}
+		oLexer.next();
+		return oFunctionCallExpr;
+	}
+};
+
+// Public members
+cFunctionCall.prototype.evaluate	= function (oContext) {
+	var aArguments	= [],
+		aParameters,
+		fFunction;
+
+	// Evaluate arguments
+	for (var nIndex = 0, nLength = this.args.length; nIndex < nLength; nIndex++)
+		aArguments.push(this.args[nIndex].evaluate(oContext));
+
+	var sUri	= (this.namespaceURI ? '{' + this.namespaceURI + '}' : '') + this.localName;
+	// Call function
+	if (this.namespaceURI == sNS_XPF) {
+		if (fFunction = hStaticContext_functions[this.localName]) {
+			// Validate/Cast arguments
+			if (aParameters = hStaticContext_signatures[this.localName])
+				fFunctionCall_prepare(this.localName, aParameters, fFunction, aArguments, oContext);
+			//
+			var vResult	= fFunction.apply(oContext, aArguments);
+			//
+			return vResult == null ? [] : vResult instanceof cArray ? vResult : [vResult];
+		}
+		throw new cException("XPST0017"
+
+		);
+	}
+	else
+	if (this.namespaceURI == sNS_XSD) {
+		if ((fFunction = hStaticContext_dataTypes[this.localName]) && this.localName != "NOTATION" && this.localName != "anyAtomicType") {
+			//
+			fFunctionCall_prepare(this.localName, [[cXSAnyAtomicType, '?']], fFunction, aArguments, oContext);
+			//
+			return aArguments[0] === null ? [] : [fFunction.cast(aArguments[0])];
+		}
+		throw new cException("XPST0017"
+
+		);
+	}
+	else
+	if (fFunction = oContext.staticContext.getFunction(sUri)) {
+		//
+		var vResult	= fFunction.apply(oContext, aArguments);
+		//
+		return vResult == null ? [] : vResult instanceof cArray ? vResult : [vResult];
+	}
+	//
+	throw new cException("XPST0017"
+
+	);
+};
+
+var aFunctionCall_numbers	= ["first", "second", "third", "fourth", "fifth"];
+function fFunctionCall_prepare(sName, aParameters, fFunction, aArguments, oContext) {
+	var oArgument,
+		nArgumentsLength	= aArguments.length,
+		oParameter,
+		nParametersLength	= aParameters.length,
+		nParametersRequired	= 0;
+
+	// Determine amount of parameters required
+	while ((nParametersRequired < aParameters.length) && !aParameters[nParametersRequired][2])
+		nParametersRequired++;
+
+	// Validate arguments length
+	if (nArgumentsLength > nParametersLength)
+		throw new cException("XPST0017"
+
+		);
+	else
+	if (nArgumentsLength < nParametersRequired)
+		throw new cException("XPST0017"
+
+		);
+
+	for (var nIndex = 0; nIndex < nArgumentsLength; nIndex++) {
+		oParameter	= aParameters[nIndex];
+		oArgument	= aArguments[nIndex];
+		// Check sequence cardinality
+		fFunctionCall_assertSequenceCardinality(oContext, oArgument, oParameter[1]
+
+		);
+		// Check sequence items data types consistency
+		fFunctionCall_assertSequenceItemType(oContext, oArgument, oParameter[0]
+
+		);
+		if (oParameter[1] != '+' && oParameter[1] != '*')
+			aArguments[nIndex]	= oArgument.length ? oArgument[0] : null;
+	}
+};
+
+function fFunctionCall_assertSequenceItemType(oContext, oSequence, cItemType
+
+	) {
+	//
+	for (var nIndex = 0, nLength = oSequence.length, nNodeType, vItem; nIndex < nLength; nIndex++) {
+		vItem	= oSequence[nIndex];
+		// Node types
+		if (cItemType == cXTNode || cItemType.prototype instanceof cXTNode) {
+			// Check if is node
+			if (!oContext.DOMAdapter.isNode(vItem))
+				throw new cException("XPTY0004"
+
+				);
+
+			// Check node type
+			if (cItemType != cXTNode) {
+				nNodeType	= oContext.DOMAdapter.getProperty(vItem, "nodeType");
+				if ([null, cXTElement, cXTAttribute, cXTText, cXTText, null, null, cXTProcessingInstruction, cXTComment, cXTDocument, null, null, null][nNodeType] != cItemType)
+					throw new cException("XPTY0004"
+
+					);
+			}
+		}
+		else
+		// Atomic types
+		if (cItemType == cXSAnyAtomicType || cItemType.prototype instanceof cXSAnyAtomicType) {
+			// Atomize item
+			vItem	= fFunction_sequence_atomize([vItem], oContext)[0];
+			// Convert type if necessary
+			if (cItemType != cXSAnyAtomicType) {
+				// Cast item to expected type if it's type is xs:untypedAtomic
+				if (vItem instanceof cXSUntypedAtomic)
+					vItem	= cItemType.cast(vItem);
+				// Cast item to xs:string if it's type is xs:anyURI
+				else
+				if (cItemType == cXSString/* || cItemType.prototype instanceof cXSString*/) {
+					if (vItem instanceof cXSAnyURI)
+						vItem	= cXSString.cast(vItem);
+				}
+				else
+				if (cItemType == cXSDouble/* || cItemType.prototype instanceof cXSDouble*/) {
+					if (fXSAnyAtomicType_isNumeric(vItem))
+						vItem	= cItemType.cast(vItem);
+				}
+			}
+			// Check type
+			if (!(vItem instanceof cItemType))
+				throw new cException("XPTY0004"
+
+				);
+			// Write value back to sequence
+			oSequence[nIndex]	= vItem;
+		}
+	}
+};
+
+function fFunctionCall_assertSequenceCardinality(oContext, oSequence, sCardinality
+
+	) {
+	var nLength	= oSequence.length;
+	// Check cardinality
+	if (sCardinality == '?') {	// =0 or 1
+		if (nLength > 1)
+			throw new cException("XPTY0004"
+
+			);
+	}
+	else
+	if (sCardinality == '+') {	// =1+
+		if (nLength < 1)
+			throw new cException("XPTY0004"
+
+			);
+	}
+	else
+	if (sCardinality != '*') {	// =1 ('*' =0+)
+		if (nLength != 1)
+			throw new cException("XPTY0004"
+
+			);
+	}
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cIntersectExceptExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cIntersectExceptExpr.prototype.left		= null;
+cIntersectExceptExpr.prototype.items	= null;
+
+// Static members
+function fIntersectExceptExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		sOperator;
+	if (oLexer.eof() ||!(oExpr = fInstanceofExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!((sOperator = oLexer.peek()) == "intersect" || sOperator == "except"))
+		return oExpr;
+
+	// IntersectExcept expression
+	var oIntersectExceptExpr	= new cIntersectExceptExpr(oExpr);
+	while ((sOperator = oLexer.peek()) == "intersect" || sOperator == "except") {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fInstanceofExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oIntersectExceptExpr.items.push([sOperator, oExpr]);
+	}
+	return oIntersectExceptExpr;
+};
+
+// Public members
+cIntersectExceptExpr.prototype.evaluate	= function (oContext) {
+	var oSequence	= this.left.evaluate(oContext);
+	for (var nIndex = 0, nLength = this.items.length, oItem; nIndex < nLength; nIndex++)
+		oSequence	= hStaticContext_operators[(oItem = this.items[nIndex])[0]].call(oContext, oSequence, oItem[1].evaluate(oContext));
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cRangeExpr(oLeft, oRight) {
+	this.left	= oLeft;
+	this.right	= oRight;
+};
+
+cRangeExpr.prototype.left	= null;
+cRangeExpr.prototype.right	= null;
+
+// Static members
+function fRangeExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oRight;
+	if (oLexer.eof() ||!(oExpr = fAdditiveExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (oLexer.peek() != "to")
+		return oExpr;
+
+	// Range expression
+	oLexer.next();
+	if (oLexer.eof() ||!(oRight = fAdditiveExpr_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+	return new cRangeExpr(oExpr, oRight);
+};
+
+// Public members
+cRangeExpr.prototype.evaluate	= function (oContext) {
+	//
+	var oLeft	= this.left.evaluate(oContext);
+	if (!oLeft.length)
+		return [];
+	//
+
+
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+	fFunctionCall_assertSequenceItemType(oContext, oLeft, cXSInteger
+
+	);
+
+	var oRight	= this.right.evaluate(oContext);
+	if (!oRight.length)
+		return [];
+
+
+
+	fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+	);
+	fFunctionCall_assertSequenceItemType(oContext, oRight, cXSInteger
+
+	);
+
+	return hStaticContext_operators["to"].call(oContext, oLeft[0], oRight[0]);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cUnionExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cUnionExpr.prototype.left	= null;
+cUnionExpr.prototype.items	= null;
+
+// Static members
+function fUnionExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		sOperator;
+	if (oLexer.eof() ||!(oExpr = fIntersectExceptExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!((sOperator = oLexer.peek()) == '|' || sOperator == "union"))
+		return oExpr;
+
+	// Union expression
+	var oUnionExpr	= new cUnionExpr(oExpr);
+	while ((sOperator = oLexer.peek()) == '|' || sOperator == "union") {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fIntersectExceptExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oUnionExpr.items.push(oExpr);
+	}
+	return oUnionExpr;
+};
+
+// Public members
+cUnionExpr.prototype.evaluate	= function (oContext) {
+	var oSequence	= this.left.evaluate(oContext);
+	for (var nIndex = 0, nLength = this.items.length; nIndex < nLength; nIndex++)
+		oSequence	= hStaticContext_operators["union"].call(oContext, oSequence, this.items[nIndex].evaluate(oContext));
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cInstanceofExpr(oExpr, oType) {
+	this.expression	= oExpr;
+	this.type		= oType;
+};
+
+cInstanceofExpr.prototype.expression	= null;
+cInstanceofExpr.prototype.type			= null;
+
+function fInstanceofExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oType;
+	if (oLexer.eof() ||!(oExpr = fTreatExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	if (!(oLexer.peek() == "instance" && oLexer.peek(1) == "of"))
+		return oExpr;
+
+	oLexer.next(2);
+	if (oLexer.eof() ||!(oType = fSequenceType_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cInstanceofExpr(oExpr, oType);
+};
+
+cInstanceofExpr.prototype.evaluate	= function(oContext) {
+	var oSequence1	= this.expression.evaluate(oContext),
+		oItemType	= this.type.itemType,
+		sOccurence	= this.type.occurence;
+	// Validate empty-sequence()
+	if (!oItemType)
+		return [new cXSBoolean(!oSequence1.length)];
+	// Validate cardinality
+	if (!oSequence1.length)
+		return [new cXSBoolean(sOccurence == '?' || sOccurence == '*')];
+	if (oSequence1.length != 1)
+		if (!(sOccurence == '+' || sOccurence == '*'))
+			return [new cXSBoolean(false)];
+
+	// Validate type
+	if (!oItemType.test)	// item()
+		return [new cXSBoolean(true)];
+
+	var bValue	= true;
+	for (var nIndex = 0, nLength = oSequence1.length; (nIndex < nLength) && bValue; nIndex++)
+		bValue	= oItemType.test.test(oSequence1[nIndex], oContext);
+	//
+	return [new cXSBoolean(bValue)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cTreatExpr(oExpr, oType) {
+	this.expression	= oExpr;
+	this.type		= oType;
+};
+
+cTreatExpr.prototype.expression	= null;
+cTreatExpr.prototype.type		= null;
+
+function fTreatExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oType;
+	if (oLexer.eof() ||!(oExpr = fCastableExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	if (!(oLexer.peek() == "treat" && oLexer.peek(1) == "as"))
+		return oExpr;
+
+	oLexer.next(2);
+	if (oLexer.eof() ||!(oType = fSequenceType_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cTreatExpr(oExpr, oType);
+};
+
+cTreatExpr.prototype.evaluate	= function(oContext) {
+	var oSequence1	= this.expression.evaluate(oContext),
+		oItemType	= this.type.itemType,
+		sOccurence	= this.type.occurence;
+	// Validate empty-sequence()
+	if (!oItemType) {
+		if (oSequence1.length)
+			throw new cException("XPDY0050"
+
+			);
+		return oSequence1;
+	}
+
+	// Validate cardinality
+	if (!(sOccurence == '?' || sOccurence == '*'))
+		if (!oSequence1.length)
+			throw new cException("XPDY0050"
+
+			);
+
+	if (!(sOccurence == '+' || sOccurence == '*'))
+		if (oSequence1.length != 1)
+			throw new cException("XPDY0050"
+
+			);
+
+	// Validate type
+	if (!oItemType.test)	// item()
+		return oSequence1;
+
+	for (var nIndex = 0, nLength = oSequence1.length; nIndex < nLength; nIndex++)
+		if (!oItemType.test.test(oSequence1[nIndex], oContext))
+			throw new cException("XPDY0050"
+
+			);
+
+	//
+	return oSequence1;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cCastableExpr(oExpr, oType) {
+	this.expression	= oExpr;
+	this.type		= oType;
+};
+
+cCastableExpr.prototype.expression	= null;
+cCastableExpr.prototype.type		= null;
+
+function fCastableExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oType;
+	if (oLexer.eof() ||!(oExpr = fCastExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	if (!(oLexer.peek() == "castable" && oLexer.peek(1) == "as"))
+		return oExpr;
+
+	oLexer.next(2);
+	if (oLexer.eof() ||!(oType = fSingleType_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cCastableExpr(oExpr, oType);
+};
+
+cCastableExpr.prototype.evaluate	= function(oContext) {
+	var oSequence1	= this.expression.evaluate(oContext),
+		oItemType	= this.type.itemType,
+		sOccurence	= this.type.occurence;
+
+	if (oSequence1.length > 1)
+		return [new cXSBoolean(false)];
+	else
+	if (!oSequence1.length)
+		return [new cXSBoolean(sOccurence == '?')];
+
+	// Try casting
+	try {
+		oItemType.cast(fFunction_sequence_atomize(oSequence1, oContext)[0]);
+	}
+	catch (e) {
+		if (e.code == "XPST0051")
+			throw e;
+		if (e.code == "XPST0017")
+			throw new cException("XPST0080"
+
+			);
+		//
+		return [new cXSBoolean(false)];
+	}
+
+	return [new cXSBoolean(true)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cCastExpr(oExpr, oType) {
+	this.expression	= oExpr;
+	this.type		= oType;
+};
+
+cCastExpr.prototype.expression	= null;
+cCastExpr.prototype.type		= null;
+
+function fCastExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oType;
+	if (oLexer.eof() ||!(oExpr = fUnaryExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	if (!(oLexer.peek() == "cast" && oLexer.peek(1) == "as"))
+		return oExpr;
+
+	oLexer.next(2);
+	if (oLexer.eof() ||!(oType = fSingleType_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cCastExpr(oExpr, oType);
+};
+
+cCastExpr.prototype.evaluate	= function(oContext) {
+	var oSequence1	= this.expression.evaluate(oContext);
+	// Validate cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oSequence1, this.type.occurence
+
+	);
+	//
+	if (!oSequence1.length)
+		return [];
+	//
+	return [this.type.itemType.cast(fFunction_sequence_atomize(oSequence1, oContext)[0], oContext)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cAtomicType(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+};
+
+cAtomicType.prototype.prefix		= null;
+cAtomicType.prototype.localName		= null;
+cAtomicType.prototype.namespaceURI	= null;
+
+function fAtomicType_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().match(rNameTest);
+	if (aMatch) {
+		if (aMatch[1] == '*' || aMatch[2] == '*')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+		return new cAtomicType(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) : null);
+	}
+};
+
+cAtomicType.prototype.test	= function(vItem, oContext) {
+	// Test
+	var sUri	= (this.namespaceURI ? '{' + this.namespaceURI + '}' : '') + this.localName,
+		cType	= this.namespaceURI == sNS_XSD ? hStaticContext_dataTypes[this.localName] : oContext.staticContext.getDataType(sUri);
+	if (cType)
+		return vItem instanceof cType;
+	//
+	throw new cException("XPST0051"
+
+	);
+};
+
+cAtomicType.prototype.cast	= function(vItem, oContext) {
+	// Cast
+	var sUri	= (this.namespaceURI ? '{' + this.namespaceURI + '}' : '') + this.localName,
+		cType	= this.namespaceURI == sNS_XSD ? hStaticContext_dataTypes[this.localName] : oContext.staticContext.getDataType(sUri);
+	if (cType)
+		return cType.cast(vItem);
+	//
+	throw new cException("XPST0051"
+
+	);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cItemType(oTest) {
+	this.test	= oTest;
+};
+
+cItemType.prototype.test	= null;
+
+function fItemType_parse (oLexer, oStaticContext) {
+	if (oLexer.eof())
+		return;
+
+	var oExpr;
+	if (oLexer.peek() == "item" && oLexer.peek(1) == '(') {
+		oLexer.next(2);
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+		return new cItemType;
+	}
+	// Note! Following step should have been before previous as per spec
+	if (oExpr = fKindTest_parse(oLexer, oStaticContext))
+		return new cItemType(oExpr);
+	if (oExpr = fAtomicType_parse(oLexer, oStaticContext))
+		return new cItemType(oExpr);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cSequenceType(oItemType, sOccurence) {
+	this.itemType	= oItemType	|| null;
+	this.occurence	= sOccurence|| null;
+};
+
+cSequenceType.prototype.itemType	= null;
+cSequenceType.prototype.occurence	= null;
+
+function fSequenceType_parse (oLexer, oStaticContext) {
+	if (oLexer.eof())
+		return;
+
+	if (oLexer.peek() == "empty-sequence" && oLexer.peek(1) == '(') {
+		oLexer.next(2);
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+		return new cSequenceType;	// empty sequence
+	}
+
+	var oExpr,
+		sOccurence;
+	if (!oLexer.eof() && (oExpr = fItemType_parse(oLexer, oStaticContext))) {
+		sOccurence	= oLexer.peek();
+		if (sOccurence == '?' || sOccurence == '*' || sOccurence == '+')
+			oLexer.next();
+		else
+			sOccurence	= null;
+
+		return new cSequenceType(oExpr, sOccurence);
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cSingleType(oItemType, sOccurence) {
+	this.itemType	= oItemType	|| null;
+	this.occurence	= sOccurence|| null;
+};
+
+cSingleType.prototype.itemType	= null;
+cSingleType.prototype.occurence	= null;
+
+function fSingleType_parse (oLexer, oStaticContext) {
+	var oExpr,
+		sOccurence;
+	if (!oLexer.eof() && (oExpr = fAtomicType_parse(oLexer, oStaticContext))) {
+		sOccurence	= oLexer.peek();
+		if (sOccurence == '?')
+			oLexer.next();
+		else
+			sOccurence	= null;
+
+		return new cSingleType(oExpr, sOccurence);
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSAnyType() {
+
+};
+
+cXSAnyType.prototype.builtInKind	= cXSConstants.ANYTYPE_DT;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSAnySimpleType() {
+
+};
+
+cXSAnySimpleType.prototype	= new cXSAnyType;
+
+cXSAnySimpleType.prototype.builtInKind	= cXSConstants.ANYSIMPLETYPE_DT;
+cXSAnySimpleType.prototype.primitiveKind= null;
+
+cXSAnySimpleType.PRIMITIVE_ANYURI		= "anyURI";		//18;
+cXSAnySimpleType.PRIMITIVE_BASE64BINARY	= "base64Binary";	// 17;
+cXSAnySimpleType.PRIMITIVE_BOOLEAN		= "boolean";	// 3;
+cXSAnySimpleType.PRIMITIVE_DATE			= "date";		// 10;
+cXSAnySimpleType.PRIMITIVE_DATETIME		= "dateTime";	// 8;
+cXSAnySimpleType.PRIMITIVE_DECIMAL		= "decimal";	// 4;
+cXSAnySimpleType.PRIMITIVE_DOUBLE		= "double";		// 6;
+cXSAnySimpleType.PRIMITIVE_DURATION		= "duration";	// 7;
+cXSAnySimpleType.PRIMITIVE_FLOAT		= "float";		// 5;
+cXSAnySimpleType.PRIMITIVE_GDAY			= "gDay";		// 14;
+cXSAnySimpleType.PRIMITIVE_GMONTH		= "gMonth";		// 15;
+cXSAnySimpleType.PRIMITIVE_GMONTHDAY	= "gMonthDay";	// 13;
+cXSAnySimpleType.PRIMITIVE_GYEAR		= "gYear";		// 12;
+cXSAnySimpleType.PRIMITIVE_GYEARMONTH	= "gYearMonth";	// 11;
+cXSAnySimpleType.PRIMITIVE_HEXBINARY	= "hexBinary";	// 16;
+cXSAnySimpleType.PRIMITIVE_NOTATION		= "NOTATION";	// 20;
+cXSAnySimpleType.PRIMITIVE_QNAME		= "QName";		// 19;
+cXSAnySimpleType.PRIMITIVE_STRING		= "string";		// 2;
+cXSAnySimpleType.PRIMITIVE_TIME			= "time";		// 9;
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSAnyAtomicType() {
+
+};
+
+cXSAnyAtomicType.prototype	= new cXSAnySimpleType;
+cXSAnyAtomicType.prototype.builtInKind	= cXSConstants.ANYATOMICTYPE_DT;
+
+cXSAnyAtomicType.cast	= function(vValue) {
+	throw new cException("XPST0017"
+
+	);	//  {http://www.w3.org/2001/XMLSchema}anyAtomicType
+};
+
+function fXSAnyAtomicType_isNumeric(vItem) {
+	return vItem instanceof cXSFloat || vItem instanceof cXSDouble || vItem instanceof cXSDecimal;
+};
+
+//
+fStaticContext_defineSystemDataType("anyAtomicType",	cXSAnyAtomicType);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSAnyURI(sScheme, sAuthority, sPath, sQuery, sFragment) {
+	this.scheme		= sScheme;
+	this.authority	= sAuthority;
+	this.path		= sPath;
+	this.query		= sQuery;
+	this.fragment	= sFragment;
+};
+
+cXSAnyURI.prototype	= new cXSAnyAtomicType;
+cXSAnyURI.prototype.builtInKind		= cXSConstants.ANYURI_DT;
+cXSAnyURI.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_ANYURI;
+
+cXSAnyURI.prototype.scheme		= null;
+cXSAnyURI.prototype.authority	= null;
+cXSAnyURI.prototype.path		= null;
+cXSAnyURI.prototype.query		= null;
+cXSAnyURI.prototype.fragment	= null;
+
+cXSAnyURI.prototype.toString	= function() {
+	return (this.scheme ? this.scheme + ':' : '')
+			+ (this.authority ? '/' + '/' + this.authority : '')
+			+ (this.path ? this.path : '')
+			+ (this.query ? '?' + this.query : '')
+			+ (this.fragment ? '#' + this.fragment : '');
+};
+
+var rXSAnyURI	= /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;	// http://tools.ietf.org/html/rfc3986
+cXSAnyURI.cast	= function(vValue) {
+	if (vValue instanceof cXSAnyURI)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch;
+		if (aMatch = fString_trim(vValue).match(rXSAnyURI))
+			return new cXSAnyURI(aMatch[2], aMatch[4], aMatch[5], aMatch[7], aMatch[9]);
+		throw new cException("FORG0001");
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("anyURI",	cXSAnyURI);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSBase64Binary(sValue) {
+	this.value	= sValue;
+};
+
+cXSBase64Binary.prototype	= new cXSAnyAtomicType;
+cXSBase64Binary.prototype.builtInKind	= cXSConstants.BASE64BINARY_DT;
+cXSBase64Binary.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_BASE64BINARY;
+
+cXSBase64Binary.prototype.value	= null;
+
+cXSBase64Binary.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSBase64Binary.prototype.toString	= function() {
+	return this.value;
+};
+
+var rXSBase64Binary		= /^((([A-Za-z0-9+\/]\s*){4})*(([A-Za-z0-9+\/]\s*){3}[A-Za-z0-9+\/]|([A-Za-z0-9+\/]\s*){2}[AEIMQUYcgkosw048]\s*=|[A-Za-z0-9+\/]\s*[AQgw]\s*=\s*=))?$/;
+cXSBase64Binary.cast	= function(vValue) {
+	if (vValue instanceof cXSBase64Binary)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSBase64Binary);
+		if (aMatch)
+			return new cXSBase64Binary(aMatch[0]);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSHexBinary) {
+		var aMatch	= vValue.valueOf().match(/.{2}/g),
+			aValue	= [];
+		for (var nIndex = 0, nLength = aMatch.length; nIndex < nLength; nIndex++)
+			aValue.push(cString.fromCharCode(fWindow_parseInt(aMatch[nIndex], 16)));
+		return new cXSBase64Binary(fWindow_btoa(aValue.join('')));
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("base64Binary",	cXSBase64Binary);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSBoolean(bValue) {
+	this.value	= bValue;
+};
+
+cXSBoolean.prototype	= new cXSAnyAtomicType;
+cXSBoolean.prototype.builtInKind	= cXSConstants.BOOLEAN_DT;
+cXSBoolean.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_BOOLEAN;
+
+cXSBoolean.prototype.value	= null;
+
+cXSBoolean.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSBoolean.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+var rXSBoolean	= /^(0|1|true|false)$/;
+cXSBoolean.cast	= function(vValue) {
+	if (vValue instanceof cXSBoolean)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch;
+		if (aMatch = fString_trim(vValue).match(rXSBoolean))
+			return new cXSBoolean(aMatch[1] == '1' || aMatch[1] == "true");
+		throw new cException("FORG0001");
+	}
+	if (fXSAnyAtomicType_isNumeric(vValue))
+		return new cXSBoolean(vValue != 0);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("boolean",	cXSBoolean);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDate(nYear, nMonth, nDay, nTimezone, bNegative) {
+	this.year		= nYear;
+	this.month		= nMonth;
+	this.day		= nDay;
+	this.timezone	= nTimezone;
+	this.negative	= bNegative;
+};
+
+cXSDate.prototype	= new cXSAnyAtomicType;
+cXSDate.prototype.builtInKind	= cXSConstants.DATE_DT;
+cXSDate.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DATE;
+
+cXSDate.prototype.year		= null;
+cXSDate.prototype.month		= null;
+cXSDate.prototype.day		= null;
+cXSDate.prototype.timezone	= null;
+cXSDate.prototype.negative	= null;
+
+cXSDate.prototype.toString	= function() {
+	return fXSDateTime_getDateComponent(this)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSDate		= /^(-?)([1-9]\d\d\d+|0\d\d\d)-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSDate.cast	= function(vValue) {
+	if (vValue instanceof cXSDate)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDate);
+		if (aMatch) {
+			var nYear	= +aMatch[2],
+				nMonth	= +aMatch[3],
+				nDay	= +aMatch[4];
+			if (nDay - 1 < fXSDate_getDaysForYearMonth(nYear, nMonth))
+				return new cXSDate( nYear,
+									nMonth,
+									nDay,
+									aMatch[5] ? aMatch[5] == 'Z' ? 0 : (aMatch[6] == '-' ? -1 : 1) * (aMatch[7] * 60 + aMatch[8] * 1) : null,
+									aMatch[1] == '-'
+				);
+			//
+			throw new cException("FORG0001"
+
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDateTime)
+		return new cXSDate(vValue.year, vValue.month, vValue.day, vValue.timezone, vValue.negative);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+// Utilities
+var aXSDate_days	= [31,28,31,30,31,30,31,31,30,31,30,31];
+function fXSDate_getDaysForYearMonth(nYear, nMonth) {
+	return nMonth == 2 && (nYear % 400 == 0 || nYear % 100 != 0 && nYear % 4 == 0) ? 29 : aXSDate_days[nMonth - 1];
+};
+
+function fXSDate_normalize(oValue, bDay) {
+	// Adjust day for month/year
+	if (!bDay) {
+		var nDay	= fXSDate_getDaysForYearMonth(oValue.year, oValue.month);
+		if (oValue.day > nDay) {
+			while (oValue.day > nDay) {
+				oValue.month	+= 1;
+				if (oValue.month > 12) {
+					oValue.year		+= 1;
+					if (oValue.year == 0)
+						oValue.year	= 1;
+					oValue.month	= 1;
+				}
+				oValue.day	-= nDay;
+				nDay = fXSDate_getDaysForYearMonth(oValue.year, oValue.month);
+			}
+		}
+		else
+		if (oValue.day < 1) {
+			while (oValue.day < 1) {
+				oValue.month	-= 1;
+				if (oValue.month < 1) {
+					oValue.year		-= 1;
+					if (oValue.year == 0)
+						oValue.year	=-1;
+					oValue.month	= 12;
+				}
+				nDay = fXSDate_getDaysForYearMonth(oValue.year, oValue.month);
+				oValue.day	+= nDay;
+			}
+		}
+	}
+//?	else
+	// Adjust month
+	if (oValue.month > 12) {
+		oValue.year		+= ~~(oValue.month / 12);
+		if (oValue.year == 0)
+			oValue.year	= 1;
+		oValue.month	= oValue.month % 12;
+	}
+	else
+	if (oValue.month < 1) {
+		oValue.year		+= ~~(oValue.month / 12) - 1;
+		if (oValue.year == 0)
+			oValue.year	=-1;
+		oValue.month	= oValue.month % 12 + 12;
+	}
+
+	return oValue;
+};
+
+//
+fStaticContext_defineSystemDataType("date",	cXSDate);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDateTime(nYear, nMonth, nDay, nHours, nMinutes, nSeconds, nTimezone, bNegative) {
+	this.year	= nYear;
+	this.month	= nMonth;
+	this.day	= nDay;
+	this.hours	= nHours;
+	this.minutes	= nMinutes;
+	this.seconds	= nSeconds;
+	this.timezone	= nTimezone;
+	this.negative	= bNegative;
+};
+
+cXSDateTime.prototype	= new cXSAnyAtomicType;
+cXSDateTime.prototype.builtInKind	= cXSConstants.DATETIME_DT;
+cXSDateTime.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DATETIME;
+
+cXSDateTime.prototype.year		= null;
+cXSDateTime.prototype.month		= null;
+cXSDateTime.prototype.day		= null;
+cXSDateTime.prototype.hours		= null;
+cXSDateTime.prototype.minutes	= null;
+cXSDateTime.prototype.seconds	= null;
+cXSDateTime.prototype.timezone	= null;
+cXSDateTime.prototype.negative	= null;
+
+cXSDateTime.prototype.toString	= function() {
+	return fXSDateTime_getDateComponent(this)
+			+ 'T'
+			+ fXSDateTime_getTimeComponent(this)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSDateTime		= /^(-?)([1-9]\d\d\d+|0\d\d\d)-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T(([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(?:\.(\d+))?|(24:00:00)(?:\.(0+))?)(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSDateTime.cast	= function(vValue) {
+	if (vValue instanceof cXSDateTime)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDateTime);
+		if (aMatch) {
+			var nYear	= +aMatch[2],
+				nMonth	= +aMatch[3],
+				nDay	= +aMatch[4],
+				bValue	= !!aMatch[10];
+			if (nDay - 1 < fXSDate_getDaysForYearMonth(nYear, nMonth))
+				return fXSDateTime_normalize(new cXSDateTime( nYear,
+										nMonth,
+										nDay,
+										bValue ? 24 : +aMatch[6],
+										bValue ? 0 : +aMatch[7],
+										cNumber((bValue ? 0 : aMatch[8]) + '.' + (bValue ? 0 : aMatch[9] || 0)),
+										aMatch[12] ? aMatch[12] == 'Z' ? 0 : (aMatch[13] == '-' ? -1 : 1) * (aMatch[14] * 60 + aMatch[15] * 1) : null,
+										aMatch[1] == '-'
+				));
+			//
+			throw new cException("FORG0001"
+
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate)
+		return new cXSDateTime(vValue.year, vValue.month, vValue.day, 0, 0, 0, vValue.timezone, vValue.negative);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+// Utilities
+function fXSDateTime_pad(vValue, nLength) {
+	var sValue	= cString(vValue);
+	if (arguments.length < 2)
+		nLength	= 2;
+	return (sValue.length < nLength + 1 ? new cArray(nLength + 1 - sValue.length).join('0') : '') + sValue;
+};
+
+function fXSDateTime_getTZComponent(oDateTime) {
+	var nTimezone	= oDateTime.timezone;
+	return nTimezone == null
+			? ''
+			: nTimezone
+				? (nTimezone > 0 ? '+' : '-')
+					+ fXSDateTime_pad(cMath.abs(~~(nTimezone / 60)))
+					+ ':'
+					+ fXSDateTime_pad(cMath.abs(nTimezone % 60))
+				: 'Z';
+};
+
+function fXSDateTime_getDateComponent(oDateTime) {
+	return (oDateTime.negative ? '-' : '')
+			+ fXSDateTime_pad(oDateTime.year, 4)
+			+ '-' + fXSDateTime_pad(oDateTime.month)
+			+ '-' + fXSDateTime_pad(oDateTime.day);
+};
+
+function fXSDateTime_getTimeComponent(oDateTime) {
+	var aValue	= cString(oDateTime.seconds).split('.');
+	return fXSDateTime_pad(oDateTime.hours)
+			+ ':' + fXSDateTime_pad(oDateTime.minutes)
+			+ ':' + fXSDateTime_pad(aValue[0])
+			+ (aValue.length > 1 ? '.' + aValue[1] : '');
+};
+
+function fXSDateTime_normalize(oValue) {
+	return fXSDate_normalize(fXSTime_normalize(oValue));
+};
+
+//
+fStaticContext_defineSystemDataType("dateTime",	cXSDateTime);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDecimal(nValue) {
+	this.value	= nValue;
+};
+
+cXSDecimal.prototype	= new cXSAnyAtomicType;
+cXSDecimal.prototype.builtInKind	= cXSConstants.DECIMAL_DT;
+cXSDecimal.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DECIMAL;
+
+cXSDecimal.prototype.value	= null;
+
+cXSDecimal.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSDecimal.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+var rXSDecimal	= /^[+\-]?((\d+(\.\d*)?)|(\.\d+))$/;
+cXSDecimal.cast	= function(vValue) {
+	if (vValue instanceof cXSDecimal)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDecimal);
+		if (aMatch)
+			return new cXSDecimal(+vValue);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBoolean)
+		return new cXSDecimal(vValue * 1);
+	if (fXSAnyAtomicType_isNumeric(vValue)) {
+		if (!fIsNaN(vValue) && fIsFinite(vValue))
+			return new cXSDecimal(+vValue);
+		throw new cException("FOCA0002"
+
+		);
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("decimal",	cXSDecimal);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDouble(nValue) {
+	this.value	= nValue;
+};
+
+cXSDouble.prototype	= new cXSAnyAtomicType;
+cXSDouble.prototype.builtInKind		= cXSConstants.DOUBLE_DT;
+cXSDouble.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DOUBLE;
+
+cXSDouble.prototype.value	= null;
+
+cXSDouble.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSDouble.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+var rXSDouble	= /^([+\-]?((\d+(\.\d*)?)|(\.\d+))([eE][+\-]?\d+)?|(-?INF)|NaN)$/;
+cXSDouble.cast	= function(vValue) {
+	if (vValue instanceof cXSDouble)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDouble);
+		if (aMatch)
+			return new cXSDouble(aMatch[7] ? +aMatch[7].replace("INF", "Infinity") : +vValue);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBoolean)
+		return new cXSDouble(vValue * 1);
+	if (fXSAnyAtomicType_isNumeric(vValue))
+		return new cXSDouble(vValue.value);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("double",	cXSDouble);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDuration(nYear, nMonth, nDay, nHours, nMinutes, nSeconds, bNegative) {
+	this.year	= nYear;
+	this.month	= nMonth;
+	this.day	= nDay;
+	this.hours	= nHours;
+	this.minutes	= nMinutes;
+	this.seconds	= nSeconds;
+	this.negative	= bNegative;
+};
+
+cXSDuration.prototype	= new cXSAnyAtomicType;
+cXSDuration.prototype.builtInKind	= cXSConstants.DURATION_DT;
+cXSDuration.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DURATION;
+
+cXSDuration.prototype.year		= null;
+cXSDuration.prototype.month		= null;
+cXSDuration.prototype.day		= null;
+cXSDuration.prototype.hours		= null;
+cXSDuration.prototype.minutes	= null;
+cXSDuration.prototype.seconds	= null;
+cXSDuration.prototype.negative	= null;
+
+cXSDuration.prototype.toString	= function() {
+	return (this.negative ? '-' : '') + 'P'
+			+ ((fXSDuration_getYearMonthComponent(this) + fXSDuration_getDayTimeComponent(this)) || 'T0S');
+};
+
+var rXSDuration		= /^(-)?P(?:([0-9]+)Y)?(?:([0-9]+)M)?(?:([0-9]+)D)?(?:T(?:([0-9]+)H)?(?:([0-9]+)M)?(?:((?:(?:[0-9]+(?:.[0-9]*)?)|(?:.[0-9]+)))S)?)?$/;
+cXSDuration.cast	= function(vValue) {
+	if (vValue instanceof cXSDuration)
+		return vValue;
+	if (vValue instanceof cXSYearMonthDuration)
+		return new cXSDuration(vValue.year, vValue.month, 0, 0, 0, 0, vValue.negative);
+	if (vValue instanceof cXSDayTimeDuration)
+		return new cXSDuration(0, 0, vValue.day, vValue.hours, vValue.minutes, vValue.seconds, vValue.negative);
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDuration);
+		if (aMatch)
+			return fXSDuration_normalize(new cXSDuration(+aMatch[2] || 0, +aMatch[3] || 0, +aMatch[4] || 0, +aMatch[5] || 0, +aMatch[6] || 0, +aMatch[7] || 0, aMatch[1] == '-'));
+		throw new cException("FORG0001");
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+// Utilities
+function fXSDuration_getYearMonthComponent(oDuration) {
+	return (oDuration.year ? oDuration.year + 'Y' : '')
+			+ (oDuration.month ? oDuration.month + 'M' : '');
+};
+
+function fXSDuration_getDayTimeComponent(oDuration) {
+	return (oDuration.day ? oDuration.day + 'D' : '')
+			+ (oDuration.hours || oDuration.minutes || oDuration.seconds
+				? 'T'
+					+ (oDuration.hours ? oDuration.hours + 'H' : '')
+					+ (oDuration.minutes ? oDuration.minutes + 'M' : '')
+					+ (oDuration.seconds ? oDuration.seconds + 'S' : '')
+				: '');
+};
+
+function fXSDuration_normalize(oDuration) {
+	return fXSYearMonthDuration_normalize(fXSDayTimeDuration_normalize(oDuration));
+};
+
+//
+fStaticContext_defineSystemDataType("duration",	cXSDuration);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSFloat(nValue) {
+	this.value	= nValue;
+};
+
+cXSFloat.prototype	= new cXSAnyAtomicType;
+cXSFloat.prototype.builtInKind		= cXSConstants.FLOAT_DT;
+cXSFloat.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_FLOAT;
+
+cXSFloat.prototype.value	= null;
+
+cXSFloat.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSFloat.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+var rXSFloat	= /^([+\-]?((\d+(\.\d*)?)|(\.\d+))([eE][+\-]?\d+)?|(-?INF)|NaN)$/;
+cXSFloat.cast	= function(vValue) {
+	if (vValue instanceof cXSFloat)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSFloat);
+		if (aMatch)
+			return new cXSFloat(aMatch[7] ? +aMatch[7].replace("INF", "Infinity") : +vValue);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBoolean)
+		return new cXSFloat(vValue * 1);
+	if (fXSAnyAtomicType_isNumeric(vValue))
+		return new cXSFloat(vValue.value);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("float",	cXSFloat);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGDay(nDay, nTimezone) {
+	this.day		= nDay;
+	this.timezone	= nTimezone;
+};
+
+cXSGDay.prototype	= new cXSAnyAtomicType;
+cXSGDay.prototype.builtInKind	= cXSConstants.GDAY_DT;
+cXSGDay.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GDAY;
+
+cXSGDay.prototype.day		= null;
+cXSGDay.prototype.timezone	= null;
+
+cXSGDay.prototype.toString	= function() {
+	return '-'
+			+ '-'
+			+ '-' + fXSDateTime_pad(this.day)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGDay		= /^---(0[1-9]|[12]\d|3[01])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGDay.cast	= function(vValue) {
+	if (vValue instanceof cXSGDay)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGDay);
+		if (aMatch) {
+			var nDay	= +aMatch[1];
+			return new cXSGDay(	nDay,
+								aMatch[2] ? aMatch[2] == 'Z' ? 0 : (aMatch[3] == '-' ? -1 : 1) * (aMatch[4] * 60 + aMatch[5] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGDay(vValue.day, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gDay",	cXSGDay);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGMonth(nMonth, nTimezone) {
+	this.month		= nMonth;
+	this.timezone	= nTimezone;
+};
+
+cXSGMonth.prototype	= new cXSAnyAtomicType;
+cXSGMonth.prototype.builtInKind		= cXSConstants.GMONTH_DT;
+cXSGMonth.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GMONTH;
+
+cXSGMonth.prototype.month		= null;
+cXSGMonth.prototype.timezone	= null;
+
+cXSGMonth.prototype.toString	= function() {
+	return '-'
+			+ '-' + fXSDateTime_pad(this.month)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGMonth	= /^--(0[1-9]|1[0-2])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGMonth.cast	= function(vValue) {
+	if (vValue instanceof cXSGMonth)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGMonth);
+		if (aMatch) {
+			var nMonth	= +aMatch[1];
+			return new cXSGMonth(	nMonth,
+									aMatch[2] ? aMatch[2] == 'Z' ? 0 : (aMatch[3] == '-' ? -1 : 1) * (aMatch[4] * 60 + aMatch[5] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGMonth(vValue.month, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gMonth",	cXSGMonth);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGMonthDay(nMonth, nDay, nTimezone) {
+	this.month		= nMonth;
+	this.day		= nDay;
+	this.timezone	= nTimezone;
+};
+
+cXSGMonthDay.prototype	= new cXSAnyAtomicType;
+cXSGMonthDay.prototype.builtInKind		= cXSConstants.GMONTHDAY_DT;
+cXSGMonthDay.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GMONTHDAY;
+
+cXSGMonthDay.prototype.month	= null;
+cXSGMonthDay.prototype.day		= null;
+cXSGMonthDay.prototype.timezone	= null;
+
+cXSGMonthDay.prototype.toString	= function() {
+	return '-'
+			+ '-' + fXSDateTime_pad(this.month)
+			+ '-' + fXSDateTime_pad(this.day)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGMonthDay	= /^--(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGMonthDay.cast	= function(vValue) {
+	if (vValue instanceof cXSGMonthDay)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGMonthDay);
+		if (aMatch) {
+			var nMonth	= +aMatch[1],
+				nDay	= +aMatch[2];
+			if (nDay - 1 < fXSDate_getDaysForYearMonth(1976, nMonth))
+				return new cXSGMonthDay(	nMonth,
+											nDay,
+											aMatch[3] ? aMatch[3] == 'Z' ? 0 : (aMatch[4] == '-' ? -1 : 1) * (aMatch[5] * 60 + aMatch[6] * 1) : null
+				);
+			//
+			throw new cException("FORG0001"
+
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGMonthDay(vValue.month, vValue.day, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gMonthDay",	cXSGMonthDay);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGYear(nYear, nTimezone) {
+	this.year	= nYear;
+	this.timezone	= nTimezone;
+};
+
+cXSGYear.prototype	= new cXSAnyAtomicType;
+cXSGYear.prototype.builtInKind		= cXSConstants.GYEAR_DT;
+cXSGYear.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GYEAR;
+
+cXSGYear.prototype.year		= null;
+cXSGYear.prototype.timezone	= null;
+
+cXSGYear.prototype.toString	= function() {
+	return fXSDateTime_pad(this.year)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGYear		= /^-?([1-9]\d\d\d+|0\d\d\d)(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGYear.cast	= function(vValue) {
+	if (vValue instanceof cXSGYear)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGYear);
+		if (aMatch) {
+			var nYear	= +aMatch[1];
+			return new cXSGYear(	nYear,
+									aMatch[2] ? aMatch[2] == 'Z' ? 0 : (aMatch[3] == '-' ? -1 : 1) * (aMatch[4] * 60 + aMatch[5] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGYear(vValue.year, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gYear",	cXSGYear);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGYearMonth(nYear, nMonth, nTimezone) {
+	this.year		= nYear;
+	this.month		= nMonth;
+	this.timezone	= nTimezone;
+};
+
+cXSGYearMonth.prototype	= new cXSAnyAtomicType;
+cXSGYearMonth.prototype.builtInKind		= cXSConstants.GYEARMONTH_DT;
+cXSGYearMonth.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GYEARMONTH;
+
+cXSGYearMonth.prototype.year	= null;
+cXSGYearMonth.prototype.month	= null;
+cXSGYearMonth.prototype.timezone= null;
+
+cXSGYearMonth.prototype.toString	= function() {
+	return fXSDateTime_pad(this.year)
+			+ '-' + fXSDateTime_pad(this.month)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGYearMonth	= /^-?([1-9]\d\d\d+|0\d\d\d)-(0[1-9]|1[0-2])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGYearMonth.cast	= function(vValue) {
+	if (vValue instanceof cXSGYearMonth)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGYearMonth);
+		if (aMatch) {
+			var nYear	= +aMatch[1],
+				nMonth	= +aMatch[2];
+			return new cXSGYearMonth(	nYear,
+										nMonth,
+										aMatch[3] ? aMatch[3] == 'Z' ? 0 : (aMatch[4] == '-' ? -1 : 1) * (aMatch[5] * 60 + aMatch[6] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGYearMonth(vValue.year, vValue.month, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gYearMonth",	cXSGYearMonth);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSHexBinary(sValue) {
+	this.value	= sValue;
+};
+
+cXSHexBinary.prototype	= new cXSAnyAtomicType;
+cXSHexBinary.prototype.builtInKind		= cXSConstants.HEXBINARY_DT;
+cXSHexBinary.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_HEXBINARY;
+
+cXSHexBinary.prototype.value	= null;
+
+cXSHexBinary.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSHexBinary.prototype.toString	= function() {
+	return this.value;
+};
+
+var rXSHexBinary	= /^([0-9a-fA-F]{2})*$/;
+cXSHexBinary.cast	= function(vValue) {
+	if (vValue instanceof cXSHexBinary)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSHexBinary);
+		if (aMatch)
+			return new cXSHexBinary(aMatch[0].toUpperCase());
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBase64Binary) {
+		var sValue	= fWindow_atob(vValue.valueOf()),
+			aValue	= [];
+		for (var nIndex = 0, nLength = sValue.length, sLetter; nIndex < nLength; nIndex++) {
+			sLetter = sValue.charCodeAt(nIndex).toString(16);
+			aValue.push(new cArray(3 - sLetter.length).join('0') + sLetter);
+		}
+		return new cXSHexBinary(aValue.join(''));
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("hexBinary",	cXSHexBinary);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNOTATION() {
+
+};
+
+cXSNOTATION.prototype	= new cXSAnyAtomicType;
+cXSNOTATION.prototype.builtInKind	= cXSConstants.NOTATION_DT;
+cXSNOTATION.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_NOTATION;
+
+cXSNOTATION.cast	= function(vValue) {
+	throw new cException("XPST0017"
+
+	);	//  {http://www.w3.org/2001/XMLSchema}NOTATION
+};
+
+//
+fStaticContext_defineSystemDataType("NOTATION",	cXSNOTATION);
+
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSQName(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix	= sPrefix;
+	this.localName	= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+};
+
+cXSQName.prototype	= new cXSAnyAtomicType;
+cXSQName.prototype.builtInKind		= cXSConstants.QNAME_DT;
+cXSQName.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_QNAME;
+
+cXSQName.prototype.prefix	= null;
+cXSQName.prototype.localName	= null;
+cXSQName.prototype.namespaceURI	= null;
+
+cXSQName.prototype.toString	= function() {
+	return (this.prefix ? this.prefix + ':' : '') + this.localName;
+};
+
+var rXSQName	= /^(?:(?![0-9-])(\w[\w.-]*)\:)?(?![0-9-])(\w[\w.-]*)$/;
+cXSQName.cast	= function(vValue) {
+	if (vValue instanceof cXSQName)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSQName);
+		if (aMatch)
+			return new cXSQName(aMatch[1] || null, aMatch[2], null);
+		throw new cException("FORG0001");
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("QName",	cXSQName);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSString(sValue) {
+	this.value	= sValue;
+};
+
+cXSString.prototype	= new cXSAnyAtomicType;
+
+cXSString.prototype.value	= null;
+cXSString.prototype.builtInKind		= cXSConstants.STRING_DT;
+cXSString.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_STRING;
+
+cXSString.prototype.valueOf		= function() {
+	return this.value;
+};
+
+cXSString.prototype.toString	= function() {
+	return this.value;
+};
+
+cXSString.cast	= function(vValue) {
+	return new cXSString(cString(vValue));
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("string",	cXSString);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSTime(nHours, nMinutes, nSeconds, nTimezone) {
+	this.hours	= nHours;
+	this.minutes	= nMinutes;
+	this.seconds	= nSeconds;
+	this.timezone	= nTimezone;
+};
+
+cXSTime.prototype	= new cXSAnyAtomicType;
+cXSTime.prototype.builtInKind	= cXSConstants.TIME_DT;
+cXSTime.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_TIME;
+
+cXSTime.prototype.hours		= null;
+cXSTime.prototype.minutes	= null;
+cXSTime.prototype.seconds	= null;
+cXSTime.prototype.timezone		= null;
+
+cXSTime.prototype.toString	= function() {
+	return fXSDateTime_getTimeComponent(this)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSTime		= /^(([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(?:\.(\d+))?|(24:00:00)(?:\.(0+))?)(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSTime.cast	= function(vValue) {
+	if (vValue instanceof cXSTime)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSTime);
+		if (aMatch) {
+			var bValue	= !!aMatch[6];
+			return new cXSTime(bValue ? 0 : +aMatch[2],
+								bValue ? 0 : +aMatch[3],
+								cNumber((bValue ? 0 : aMatch[4]) + '.' + (bValue ? 0 : aMatch[5] || 0)),
+								aMatch[8] ? aMatch[8] == 'Z' ? 0 : (aMatch[9] == '-' ? -1 : 1) * (aMatch[10] * 60 + aMatch[11] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDateTime)
+		return new cXSTime(vValue.hours, vValue.minutes, vValue.seconds, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+function fXSTime_normalize(oValue) {
+	//
+	if (oValue.seconds >= 60 || oValue.seconds < 0) {
+		oValue.minutes	+= ~~(oValue.seconds / 60) - (oValue.seconds < 0 && oValue.seconds % 60 ? 1 : 0);
+		oValue.seconds	= oValue.seconds % 60 + (oValue.seconds < 0 && oValue.seconds % 60 ? 60 : 0);
+	}
+	//
+	if (oValue.minutes >= 60 || oValue.minutes < 0) {
+		oValue.hours	+= ~~(oValue.minutes / 60) - (oValue.minutes < 0 && oValue.minutes % 60 ? 1 : 0);
+		oValue.minutes	= oValue.minutes % 60 + (oValue.minutes < 0 && oValue.minutes % 60 ? 60 : 0);
+	}
+	//
+	if (oValue.hours >= 24 || oValue.hours < 0) {
+		if (oValue instanceof cXSDateTime)
+			oValue.day		+= ~~(oValue.hours / 24) - (oValue.hours < 0 && oValue.hours % 24 ? 1 : 0);
+		oValue.hours	= oValue.hours % 24 + (oValue.hours < 0 && oValue.hours % 24 ? 24 : 0);
+	}
+	//
+	return oValue;
+};
+
+//
+fStaticContext_defineSystemDataType("time",	cXSTime);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUntypedAtomic(sValue) {
+	this.value	= sValue;
+};
+
+cXSUntypedAtomic.prototype	= new cXSAnyAtomicType;
+cXSUntypedAtomic.prototype.builtInKind	= cXSConstants.XT_UNTYPEDATOMIC_DT;
+
+cXSUntypedAtomic.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+cXSUntypedAtomic.cast	= function(vValue) {
+	if (vValue instanceof cXSUntypedAtomic)
+		return vValue;
+
+	return new cXSUntypedAtomic(cString(vValue));
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("untypedAtomic",	cXSUntypedAtomic);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSYearMonthDuration(nYear, nMonth, bNegative) {
+	cXSDuration.call(this, nYear, nMonth, 0, 0, 0, 0, bNegative);
+};
+
+cXSYearMonthDuration.prototype	= new cXSDuration;
+cXSYearMonthDuration.prototype.builtInKind	= cXSConstants.XT_YEARMONTHDURATION_DT;
+
+cXSYearMonthDuration.prototype.toString	= function() {
+	return (this.negative ? '-' : '') + 'P'
+			+ (fXSDuration_getYearMonthComponent(this) || '0M');
+};
+
+var rXSYearMonthDuration	= /^(-)?P(?:([0-9]+)Y)?(?:([0-9]+)M)?$/;
+cXSYearMonthDuration.cast	= function(vValue) {
+	if (vValue instanceof cXSYearMonthDuration)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSYearMonthDuration);
+		if (aMatch)
+			return fXSYearMonthDuration_normalize(new cXSYearMonthDuration(+aMatch[2] || 0, +aMatch[3] || 0, aMatch[1] == '-'));
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDayTimeDuration)
+		return new cXSYearMonthDuration(0, 0);
+	if (vValue instanceof cXSDuration)
+		return new cXSYearMonthDuration(vValue.year, vValue.month, vValue.negative);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+function fXSYearMonthDuration_normalize(oDuration) {
+	if (oDuration.month >= 12) {
+		oDuration.year	+= ~~(oDuration.month / 12);
+		oDuration.month	%= 12;
+	}
+	return oDuration;
+};
+
+//
+fStaticContext_defineSystemDataType("yearMonthDuration",	cXSYearMonthDuration);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDayTimeDuration(nDay, nHours, nMinutes, nSeconds, bNegative) {
+	cXSDuration.call(this, 0, 0, nDay, nHours, nMinutes, nSeconds, bNegative);
+};
+
+cXSDayTimeDuration.prototype	= new cXSDuration;
+cXSDayTimeDuration.prototype.builtInKind	= cXSConstants.DAYTIMEDURATION_DT;
+
+cXSDayTimeDuration.prototype.toString	= function() {
+	return (this.negative ? '-' : '') + 'P'
+			+ (fXSDuration_getDayTimeComponent(this) || 'T0S');
+};
+
+var rXSDayTimeDuration	= /^(-)?P(?:([0-9]+)D)?(?:T(?:([0-9]+)H)?(?:([0-9]+)M)?(?:((?:(?:[0-9]+(?:.[0-9]*)?)|(?:.[0-9]+)))S)?)?$/;
+cXSDayTimeDuration.cast	= function(vValue) {
+	if (vValue instanceof cXSDayTimeDuration)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDayTimeDuration);
+		if (aMatch)
+			return fXSDayTimeDuration_normalize(new cXSDayTimeDuration(+aMatch[2] || 0, +aMatch[3] || 0, +aMatch[4] || 0, +aMatch[5] || 0, aMatch[1] == '-'));
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSYearMonthDuration)
+		return new cXSDayTimeDuration(0, 0, 0, 0);
+	if (vValue instanceof cXSDuration)
+		return new cXSDayTimeDuration(vValue.day, vValue.hours, vValue.minutes, vValue.seconds, vValue.negative);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+// Utilities
+function fXSDayTimeDuration_normalize(oDuration) {
+	if (oDuration.seconds >= 60) {
+		oDuration.minutes	+= ~~(oDuration.seconds / 60);
+		oDuration.seconds	%= 60;
+	}
+	if (oDuration.minutes >= 60) {
+		oDuration.hours		+= ~~(oDuration.minutes / 60);
+		oDuration.minutes	%= 60;
+	}
+	if (oDuration.hours >= 24) {
+		oDuration.day		+= ~~(oDuration.hours / 24);
+		oDuration.hours		%= 24;
+	}
+	return oDuration;
+};
+
+//
+fStaticContext_defineSystemDataType("dayTimeDuration",	cXSDayTimeDuration);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSInteger.prototype	= new cXSDecimal;
+cXSInteger.prototype.builtInKind	= cXSConstants.INTEGER_DT;
+
+var rXSInteger	= /^[-+]?[0-9]+$/;
+cXSInteger.cast	= function(vValue) {
+	if (vValue instanceof cXSInteger)
+		return new cXSInteger(vValue.value);
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSInteger);
+		if (aMatch)
+			return new cXSInteger(+vValue);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBoolean)
+		return new cXSInteger(vValue * 1);
+	if (fXSAnyAtomicType_isNumeric(vValue)) {
+		if (!fIsNaN(vValue) && fIsFinite(vValue))
+			return new cXSInteger(+vValue);
+		throw new cException("FOCA0002"
+
+		);
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("integer",	cXSInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNonPositiveInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSNonPositiveInteger.prototype	= new cXSInteger;
+cXSNonPositiveInteger.prototype.builtInKind	= cXSConstants.NONPOSITIVEINTEGER_DT;
+
+cXSNonPositiveInteger.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 0)
+		return new cXSNonPositiveInteger(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("nonPositiveInteger",	cXSNonPositiveInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNegativeInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSNegativeInteger.prototype	= new cXSNonPositiveInteger;
+cXSNegativeInteger.prototype.builtInKind	= cXSConstants.NEGATIVEINTEGER_DT;
+
+cXSNegativeInteger.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= -1)
+		return new cXSNegativeInteger(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("negativeInteger",	cXSNegativeInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSLong(nValue) {
+	this.value	= nValue;
+};
+
+cXSLong.prototype	= new cXSInteger;
+cXSLong.prototype.builtInKind	= cXSConstants.LONG_DT;
+
+cXSLong.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 9223372036854775807 && oValue.value >= -9223372036854775808)
+		return new cXSLong(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("long",	cXSLong);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSInt(nValue) {
+	this.value	= nValue;
+};
+
+cXSInt.prototype	= new cXSLong;
+cXSInt.prototype.builtInKind	= cXSConstants.INT_DT;
+
+cXSInt.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 2147483647 && oValue.value >= -2147483648)
+		return new cXSInt(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("int",	cXSInt);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSShort(nValue) {
+	this.value	= nValue;
+};
+
+cXSShort.prototype	= new cXSInt;
+cXSShort.prototype.builtInKind	= cXSConstants.SHORT_DT;
+
+cXSShort.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 32767 && oValue.value >= -32768)
+		return new cXSShort(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("short",	cXSShort);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSByte(nValue) {
+	this.value	= nValue;
+};
+
+cXSByte.prototype	= new cXSShort;
+cXSByte.prototype.builtInKind	= cXSConstants.BYTE_DT;
+
+cXSByte.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 127 && oValue.value >= -128)
+		return new cXSByte(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("byte",	cXSByte);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNonNegativeInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSNonNegativeInteger.prototype	= new cXSInteger;
+cXSNonNegativeInteger.prototype.builtInKind	= cXSConstants.NONNEGATIVEINTEGER_DT;
+
+cXSNonNegativeInteger.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 0)
+		return new cXSNonNegativeInteger(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("nonNegativeInteger",	cXSNonNegativeInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSPositiveInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSPositiveInteger.prototype	= new cXSNonNegativeInteger;
+cXSPositiveInteger.prototype.builtInKind	= cXSConstants.POSITIVEINTEGER_DT;
+
+cXSPositiveInteger.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1)
+		return new cXSPositiveInteger(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("positiveInteger",	cXSPositiveInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUnsignedLong(nValue) {
+	this.value	= nValue;
+};
+
+cXSUnsignedLong.prototype	= new cXSNonNegativeInteger;
+cXSUnsignedLong.prototype.builtInKind	= cXSConstants.UNSIGNEDLONG_DT;
+
+cXSUnsignedLong.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1 && oValue.value <= 18446744073709551615)
+		return new cXSUnsignedLong(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("unsignedLong",	cXSUnsignedLong);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUnsignedInt(nValue) {
+	this.value	= nValue;
+};
+
+cXSUnsignedInt.prototype	= new cXSNonNegativeInteger;
+cXSUnsignedInt.prototype.builtInKind	= cXSConstants.UNSIGNEDINT_DT;
+
+cXSUnsignedInt.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1 && oValue.value <= 4294967295)
+		return new cXSUnsignedInt(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("unsignedInt",	cXSUnsignedInt);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUnsignedShort(nValue) {
+	this.value	= nValue;
+};
+
+cXSUnsignedShort.prototype	= new cXSUnsignedInt;
+cXSUnsignedShort.prototype.builtInKind	= cXSConstants.UNSIGNEDSHORT_DT;
+
+cXSUnsignedShort.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1 && oValue.value <= 65535)
+		return new cXSUnsignedShort(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("unsignedShort",	cXSUnsignedShort);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUnsignedByte(nValue) {
+	this.value	= nValue;
+};
+
+cXSUnsignedByte.prototype	= new cXSUnsignedShort;
+cXSUnsignedByte.prototype.builtInKind	= cXSConstants.UNSIGNEDBYTE_DT;
+
+cXSUnsignedByte.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1 && oValue.value <= 255)
+		return new cXSUnsignedByte(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("unsignedByte",	cXSUnsignedByte);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNormalizedString(sValue) {
+	this.value	= sValue;
+};
+
+cXSNormalizedString.prototype	= new cXSString;
+cXSNormalizedString.prototype.builtInKind	= cXSConstants.NORMALIZEDSTRING_DT;
+
+cXSNormalizedString.cast	= function(vValue) {
+	return new cXSNormalizedString(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("normalizedString",	cXSNormalizedString);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSToken(sValue) {
+	this.value	= sValue;
+};
+
+cXSToken.prototype	= new cXSNormalizedString;
+cXSToken.prototype.builtInKind	= cXSConstants.TOKEN_DT;
+
+cXSToken.cast	= function(vValue) {
+	return new cXSToken(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("token",	cXSToken);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSName(sValue) {
+	this.value	= sValue;
+};
+
+cXSName.prototype	= new cXSToken;
+cXSName.prototype.builtInKind	= cXSConstants.NAME_DT;
+
+cXSName.cast	= function(vValue) {
+	return new cXSName(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("Name",	cXSName);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNCName(sValue) {
+	this.value	= sValue;
+};
+
+cXSNCName.prototype	= new cXSName;
+cXSNCName.prototype.builtInKind	= cXSConstants.NCNAME_DT;
+
+cXSNCName.cast	= function(vValue) {
+	return new cXSNCName(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("NCName",	cXSNCName);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSENTITY(sValue) {
+	this.value	= sValue;
+};
+
+cXSENTITY.prototype	= new cXSNCName;
+cXSENTITY.prototype.builtInKind	= cXSConstants.ENTITY_DT;
+
+cXSENTITY.cast	= function(vValue) {
+	return new cXSENTITY(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("ENTITY",	cXSENTITY);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSID(sValue) {
+	this.value	= sValue;
+};
+
+cXSID.prototype	= new cXSNCName;
+cXSID.prototype.builtInKind	= cXSConstants.ID_DT;
+
+cXSID.cast	= function(vValue) {
+	return new cXSID(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("ID",	cXSID);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSIDREF(sValue) {
+	this.value	= sValue;
+};
+
+cXSIDREF.prototype	= new cXSNCName;
+cXSIDREF.prototype.builtInKind	= cXSConstants.IDREF_DT;
+
+cXSIDREF.cast	= function(vValue) {
+	return new cXSIDREF(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("IDREF",	cXSIDREF);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSLanguage(sValue) {
+	this.value	= sValue;
+};
+
+cXSLanguage.prototype	= new cXSToken;
+cXSLanguage.prototype.builtInKind	= cXSConstants.LANGUAGE_DT;
+
+cXSLanguage.cast	= function(vValue) {
+	return new cXSLanguage(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("language",	cXSLanguage);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNMTOKEN(sValue) {
+	this.value	= sValue;
+};
+
+cXSNMTOKEN.prototype	= new cXSToken;
+cXSNMTOKEN.prototype.builtInKind	= cXSConstants.NMTOKEN_DT;
+
+cXSNMTOKEN.cast	= function(vValue) {
+	return new cXSNMTOKEN(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("NMTOKEN",	cXSNMTOKEN);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTItem() {
+
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTNode() {
+
+};
+
+cXTNode.prototype	= new cXTItem;
+
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTAttribute() {
+
+};
+
+cXTAttribute.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTComment() {
+
+};
+
+cXTComment.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTDocument() {
+
+};
+
+cXTDocument.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTElement() {
+
+};
+
+cXTElement.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTProcessingInstruction() {
+
+};
+
+cXTProcessingInstruction.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTText() {
+
+};
+
+cXTText.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	12.1 Comparisons of base64Binary and hexBinary Values
+		op:hexBinary-equal
+		op:base64Binary-equal
+*/
+hStaticContext_operators["hexBinary-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() == oRight.valueOf());
+};
+
+hStaticContext_operators["base64Binary-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() == oRight.valueOf());
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	9.2 Operators on Boolean Values
+		op:boolean-equal
+		op:boolean-less-than
+		op:boolean-greater-than
+*/
+
+// 9.2 Operators on Boolean Values
+// op:boolean-equal($value1 as xs:boolean, $value2 as xs:boolean) as xs:boolean
+hStaticContext_operators["boolean-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() == oRight.valueOf());
+};
+
+// op:boolean-less-than($arg1 as xs:boolean, $arg2 as xs:boolean) as xs:boolean
+hStaticContext_operators["boolean-less-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() < oRight.valueOf());
+};
+
+// op:boolean-greater-than($arg1 as xs:boolean, $arg2 as xs:boolean) as xs:boolean
+hStaticContext_operators["boolean-greater-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() > oRight.valueOf());
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	10.4 Comparison Operators on Duration, Date and Time Values
+		op:yearMonthDuration-less-than
+		op:yearMonthDuration-greater-than
+		op:dayTimeDuration-less-than
+		op:dayTimeDuration-greater-than
+		op:duration-equal
+		op:dateTime-equal
+		op:dateTime-less-than
+		op:dateTime-greater-than
+		op:date-equal
+		op:date-less-than
+		op:date-greater-than
+		op:time-equal
+		op:time-less-than
+		op:time-greater-than
+		op:gYearMonth-equal
+		op:gYear-equal
+		op:gMonthDay-equal
+		op:gMonth-equal
+		op:gDay-equal
+
+	10.6 Arithmetic Operators on Durations
+		op:add-yearMonthDurations
+		op:subtract-yearMonthDurations
+		op:multiply-yearMonthDuration
+		op:divide-yearMonthDuration
+		op:divide-yearMonthDuration-by-yearMonthDuration
+		op:add-dayTimeDurations
+		op:subtract-dayTimeDurations
+		op:multiply-dayTimeDuration
+		op:divide-dayTimeDuration
+		op:divide-dayTimeDuration-by-dayTimeDuration
+
+
+	10.8 Arithmetic Operators on Durations, Dates and Times
+		op:subtract-dateTimes
+		op:subtract-dates
+		op:subtract-times
+		op:add-yearMonthDuration-to-dateTime
+		op:add-dayTimeDuration-to-dateTime
+		op:subtract-yearMonthDuration-from-dateTime
+		op:subtract-dayTimeDuration-from-dateTime
+		op:add-yearMonthDuration-to-date
+		op:add-dayTimeDuration-to-date
+		op:subtract-yearMonthDuration-from-date
+		op:subtract-dayTimeDuration-from-date
+		op:add-dayTimeDuration-to-time
+		op:subtract-dayTimeDuration-from-time
+
+*/
+
+// 10.4 Comparison Operators on Duration, Date and Time Values
+// op:yearMonthDuration-less-than($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:boolean
+hStaticContext_operators["yearMonthDuration-less-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(fOperator_yearMonthDuration_toMonths(oLeft) < fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:yearMonthDuration-greater-than($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:boolean
+hStaticContext_operators["yearMonthDuration-greater-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(fOperator_yearMonthDuration_toMonths(oLeft) > fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:dayTimeDuration-less-than($arg1 as dayTimeDuration, $arg2 as dayTimeDuration) as xs:boolean
+hStaticContext_operators["dayTimeDuration-less-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(fOperator_dayTimeDuration_toSeconds(oLeft) < fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:dayTimeDuration-greater-than($arg1 as dayTimeDuration, $arg2 as dayTimeDuration) as xs:boolean
+hStaticContext_operators["dayTimeDuration-greater-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(fOperator_dayTimeDuration_toSeconds(oLeft) > fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:duration-equal($arg1 as xs:duration, $arg2 as xs:duration) as xs:boolean
+hStaticContext_operators["duration-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.negative == oRight.negative
+			&& fOperator_yearMonthDuration_toMonths(oLeft) == fOperator_yearMonthDuration_toMonths(oRight)
+			&& fOperator_dayTimeDuration_toSeconds(oLeft) == fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:dateTime-equal($arg1 as xs:dateTime, $arg2 as xs:dateTime) as xs:boolean
+hStaticContext_operators["dateTime-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(oLeft, oRight, 'eq');
+};
+
+// op:dateTime-less-than($arg1 as xs:dateTime, $arg2 as xs:dateTime) as xs:boolean
+hStaticContext_operators["dateTime-less-than"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(oLeft, oRight, 'lt');
+};
+
+//op:dateTime-greater-than($arg1 as xs:dateTime, $arg2 as xs:dateTime) as xs:boolean
+hStaticContext_operators["dateTime-greater-than"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(oLeft, oRight, 'gt');
+};
+
+// op:date-equal($arg1 as xs:date, $arg2 as xs:date) as xs:boolean
+hStaticContext_operators["date-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDates(oLeft, oRight, 'eq');
+};
+
+// op:date-less-than($arg1 as xs:date, $arg2 as xs:date) as xs:boolean
+hStaticContext_operators["date-less-than"]	= function(oLeft, oRight) {
+	return fOperator_compareDates(oLeft, oRight, 'lt');
+};
+
+// op:date-greater-than($arg1 as xs:date, $arg2 as xs:date) as xs:boolean
+hStaticContext_operators["date-greater-than"]	= function(oLeft, oRight) {
+	return fOperator_compareDates(oLeft, oRight, 'gt');
+};
+
+// op:time-equal($arg1 as xs:time, $arg2 as xs:time) as xs:boolean
+hStaticContext_operators["time-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareTimes(oLeft, oRight, 'eq');
+};
+
+// op:time-less-than($arg1 as xs:time, $arg2 as xs:time) as xs:boolean
+hStaticContext_operators["time-less-than"]	= function(oLeft, oRight) {
+	return fOperator_compareTimes(oLeft, oRight, 'lt');
+};
+
+// op:time-greater-than($arg1 as xs:time, $arg2 as xs:time) as xs:boolean
+hStaticContext_operators["time-greater-than"]	= function(oLeft, oRight) {
+	return fOperator_compareTimes(oLeft, oRight, 'gt');
+};
+
+// op:gYearMonth-equal($arg1 as xs:gYearMonth, $arg2 as xs:gYearMonth) as xs:boolean
+hStaticContext_operators["gYearMonth-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(oLeft.year, oLeft.month, fXSDate_getDaysForYearMonth(oLeft.year, oLeft.month), 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(oRight.year, oRight.month, fXSDate_getDaysForYearMonth(oRight.year, oRight.month), 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// op:gYear-equal($arg1 as xs:gYear, $arg2 as xs:gYear) as xs:boolean
+hStaticContext_operators["gYear-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(oLeft.year, 1, 1, 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(oRight.year, 1, 1, 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// op:gMonthDay-equal($arg1 as xs:gMonthDay, $arg2 as xs:gMonthDay) as xs:boolean
+hStaticContext_operators["gMonthDay-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(1972, oLeft.month, oLeft.day, 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(1972, oRight.month, oRight.day, 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// op:gMonth-equal($arg1 as xs:gMonth, $arg2 as xs:gMonth) as xs:boolean
+hStaticContext_operators["gMonth-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(1972, oLeft.month, fXSDate_getDaysForYearMonth(1972, oRight.month), 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(1972, oRight.month, fXSDate_getDaysForYearMonth(1972, oRight.month), 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// op:gDay-equal($arg1 as xs:gDay, $arg2 as xs:gDay) as xs:boolean
+hStaticContext_operators["gDay-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(1972, 12, oLeft.day, 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(1972, 12, oRight.day, 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// 10.6 Arithmetic Operators on Durations
+// op:add-yearMonthDurations($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:yearMonthDuration
+hStaticContext_operators["add-yearMonthDurations"]	= function(oLeft, oRight) {
+	return fOperator_yearMonthDuration_fromMonths(fOperator_yearMonthDuration_toMonths(oLeft) + fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:subtract-yearMonthDurations($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:yearMonthDuration
+hStaticContext_operators["subtract-yearMonthDurations"]	= function(oLeft, oRight) {
+	return fOperator_yearMonthDuration_fromMonths(fOperator_yearMonthDuration_toMonths(oLeft) - fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:multiply-yearMonthDuration($arg1 as xs:yearMonthDuration, $arg2 as xs:double) as xs:yearMonthDuration
+hStaticContext_operators["multiply-yearMonthDuration"]	= function(oLeft, oRight) {
+	return fOperator_yearMonthDuration_fromMonths(fOperator_yearMonthDuration_toMonths(oLeft) * oRight);
+};
+
+// op:divide-yearMonthDuration($arg1 as xs:yearMonthDuration, $arg2 as xs:double) as xs:yearMonthDuration
+hStaticContext_operators["divide-yearMonthDuration"]	= function(oLeft, oRight) {
+	return fOperator_yearMonthDuration_fromMonths(fOperator_yearMonthDuration_toMonths(oLeft) / oRight);
+};
+
+// op:divide-yearMonthDuration-by-yearMonthDuration($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:decimal
+hStaticContext_operators["divide-yearMonthDuration-by-yearMonthDuration"]	= function(oLeft, oRight) {
+	return new cXSDecimal(fOperator_yearMonthDuration_toMonths(oLeft) / fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:add-dayTimeDurations($arg1 as xs:dayTimeDuration, $arg2 as xs:dayTimeDuration) as xs:dayTimeDuration
+hStaticContext_operators["add-dayTimeDurations"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dayTimeDuration_toSeconds(oLeft) + fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:subtract-dayTimeDurations($arg1 as xs:dayTimeDuration, $arg2 as xs:dayTimeDuration) as xs:dayTimeDuration
+hStaticContext_operators["subtract-dayTimeDurations"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dayTimeDuration_toSeconds(oLeft) - fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:multiply-dayTimeDurations($arg1 as xs:dayTimeDuration, $arg2 as xs:double) as xs:dayTimeDuration
+hStaticContext_operators["multiply-dayTimeDuration"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dayTimeDuration_toSeconds(oLeft) * oRight);
+};
+
+// op:divide-dayTimeDurations($arg1 as xs:dayTimeDuration, $arg2 as xs:double) as xs:dayTimeDuration
+hStaticContext_operators["divide-dayTimeDuration"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dayTimeDuration_toSeconds(oLeft) / oRight);
+};
+
+// op:divide-dayTimeDuration-by-dayTimeDuration($arg1 as xs:dayTimeDuration, $arg2 as xs:dayTimeDuration) as xs:decimal
+hStaticContext_operators["divide-dayTimeDuration-by-dayTimeDuration"]	= function(oLeft, oRight) {
+	return new cXSDecimal(fOperator_dayTimeDuration_toSeconds(oLeft) / fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// 10.8 Arithmetic Operators on Durations, Dates and Times
+// op:subtract-dateTimes($arg1 as xs:dateTime, $arg2 as xs:dateTime) as xs:dayTimeDuration
+hStaticContext_operators["subtract-dateTimes"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dateTime_toSeconds(oLeft) - fOperator_dateTime_toSeconds(oRight));
+};
+
+// op:subtract-dates($arg1 as xs:date, $arg2 as xs:date) as xs:dayTimeDuration
+hStaticContext_operators["subtract-dates"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dateTime_toSeconds(oLeft) - fOperator_dateTime_toSeconds(oRight));
+};
+
+// op:subtract-times($arg1 as xs:time, $arg2 as xs:time) as xs:dayTimeDuration
+hStaticContext_operators["subtract-times"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_time_toSeconds(oLeft) - fOperator_time_toSeconds(oRight));
+};
+
+// op:add-yearMonthDuration-to-dateTime($arg1 as xs:dateTime, $arg2 as xs:yearMonthDuration) as xs:dateTime
+hStaticContext_operators["add-yearMonthDuration-to-dateTime"]	= function(oLeft, oRight) {
+	return fOperator_addYearMonthDuration2DateTime(oLeft, oRight, '+');
+};
+
+// op:add-dayTimeDuration-to-dateTime($arg1 as xs:dateTime, $arg2 as xs:dayTimeDuration) as xs:dateTime
+hStaticContext_operators["add-dayTimeDuration-to-dateTime"]	= function(oLeft, oRight) {
+	return fOperator_addDayTimeDuration2DateTime(oLeft, oRight, '+');
+};
+
+// op:subtract-yearMonthDuration-from-dateTime($arg1 as xs:dateTime, $arg2 as xs:yearMonthDuration) as xs:dateTime
+hStaticContext_operators["subtract-yearMonthDuration-from-dateTime"]	= function(oLeft, oRight) {
+	return fOperator_addYearMonthDuration2DateTime(oLeft, oRight, '-');
+};
+
+// op:subtract-dayTimeDuration-from-dateTime($arg1 as xs:dateTime, $arg2 as xs:dayTimeDuration) as xs:dateTime
+hStaticContext_operators["subtract-dayTimeDuration-from-dateTime"]	= function(oLeft, oRight) {
+	return fOperator_addDayTimeDuration2DateTime(oLeft, oRight, '-');
+};
+
+// op:add-yearMonthDuration-to-date($arg1 as xs:date, $arg2 as xs:yearMonthDuration) as xs:date
+hStaticContext_operators["add-yearMonthDuration-to-date"]	= function(oLeft, oRight) {
+	return fOperator_addYearMonthDuration2DateTime(oLeft, oRight, '+');
+};
+
+// op:add-dayTimeDuration-to-date($arg1 as xs:date, $arg2 as xs:dayTimeDuration) as xs:date
+hStaticContext_operators["add-dayTimeDuration-to-date"]	= function(oLeft, oRight) {
+	return fOperator_addDayTimeDuration2DateTime(oLeft, oRight, '+');
+};
+
+// op:subtract-yearMonthDuration-from-date($arg1 as xs:date, $arg2  as xs:yearMonthDuration) as xs:date
+hStaticContext_operators["subtract-yearMonthDuration-from-date"]	= function(oLeft, oRight) {
+	return fOperator_addYearMonthDuration2DateTime(oLeft, oRight, '-');
+};
+
+// op:subtract-dayTimeDuration-from-date($arg1 as xs:date, $arg2  as xs:dayTimeDuration) as xs:date
+hStaticContext_operators["subtract-dayTimeDuration-from-date"]	= function(oLeft, oRight) {
+	return fOperator_addDayTimeDuration2DateTime(oLeft, oRight, '-');
+};
+
+// op:add-dayTimeDuration-to-time($arg1 as xs:time, $arg2  as xs:dayTimeDuration) as xs:time
+hStaticContext_operators["add-dayTimeDuration-to-time"]	= function(oLeft, oRight) {
+	var oValue	= new cXSTime(oLeft.hours, oLeft.minutes, oLeft.seconds, oLeft.timezone);
+	oValue.hours	+= oRight.hours;
+	oValue.minutes	+= oRight.minutes;
+	oValue.seconds	+= oRight.seconds;
+	//
+	return fXSTime_normalize(oValue);
+};
+
+// op:subtract-dayTimeDuration-from-time($arg1 as xs:time, $arg2  as xs:dayTimeDuration) as xs:time
+hStaticContext_operators["subtract-dayTimeDuration-from-time"]	= function(oLeft, oRight) {
+	var oValue	= new cXSTime(oLeft.hours, oLeft.minutes, oLeft.seconds, oLeft.timezone);
+	oValue.hours	-= oRight.hours;
+	oValue.minutes	-= oRight.minutes;
+	oValue.seconds	-= oRight.seconds;
+	//
+	return fXSTime_normalize(oValue);
+};
+
+function fOperator_compareTimes(oLeft, oRight, sComparator) {
+	var nLeft	= fOperator_time_toSeconds(oLeft),
+		nRight	= fOperator_time_toSeconds(oRight);
+	return new cXSBoolean(sComparator == 'lt' ? nLeft < nRight : sComparator == 'gt' ? nLeft > nRight : nLeft == nRight);
+};
+
+function fOperator_compareDates(oLeft, oRight, sComparator) {
+	return fOperator_compareDateTimes(cXSDateTime.cast(oLeft), cXSDateTime.cast(oRight), sComparator);
+};
+
+function fOperator_compareDateTimes(oLeft, oRight, sComparator) {
+	// Adjust object time zone to Z and compare as strings
+	var oTimezone	= new cXSDayTimeDuration(0, 0, 0, 0),
+		sLeft	= fFunction_dateTime_adjustTimezone(oLeft, oTimezone).toString(),
+		sRight	= fFunction_dateTime_adjustTimezone(oRight, oTimezone).toString();
+	return new cXSBoolean(sComparator == 'lt' ? sLeft < sRight : sComparator == 'gt' ? sLeft > sRight : sLeft == sRight);
+};
+
+function fOperator_addYearMonthDuration2DateTime(oLeft, oRight, sOperator) {
+	var oValue;
+	if (oLeft instanceof cXSDate)
+		oValue	= new cXSDate(oLeft.year, oLeft.month, oLeft.day, oLeft.timezone, oLeft.negative);
+	else
+	if (oLeft instanceof cXSDateTime)
+		oValue	= new cXSDateTime(oLeft.year, oLeft.month, oLeft.day, oLeft.hours, oLeft.minutes, oLeft.seconds, oLeft.timezone, oLeft.negative);
+	//
+	oValue.year		= oValue.year + oRight.year * (sOperator == '-' ?-1 : 1);
+	oValue.month	= oValue.month + oRight.month * (sOperator == '-' ?-1 : 1);
+	//
+	fXSDate_normalize(oValue, true);
+	// Correct day if out of month range
+	var nDay	= fXSDate_getDaysForYearMonth(oValue.year, oValue.month);
+	if (oValue.day > nDay)
+		oValue.day	= nDay;
+	//
+	return oValue;
+};
+
+function fOperator_addDayTimeDuration2DateTime(oLeft, oRight, sOperator) {
+	var oValue;
+	if (oLeft instanceof cXSDate) {
+		var nValue	= (oRight.hours * 60 + oRight.minutes) * 60 + oRight.seconds;
+		oValue	= new cXSDate(oLeft.year, oLeft.month, oLeft.day, oLeft.timezone, oLeft.negative);
+		oValue.day	= oValue.day + oRight.day * (sOperator == '-' ?-1 : 1) - 1 * (nValue && sOperator == '-');
+		//
+		fXSDate_normalize(oValue);
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		oValue	= new cXSDateTime(oLeft.year, oLeft.month, oLeft.day, oLeft.hours, oLeft.minutes, oLeft.seconds, oLeft.timezone, oLeft.negative);
+		oValue.seconds	= oValue.seconds + oRight.seconds * (sOperator == '-' ?-1 : 1);
+		oValue.minutes	= oValue.minutes + oRight.minutes * (sOperator == '-' ?-1 : 1);
+		oValue.hours	= oValue.hours + oRight.hours * (sOperator == '-' ?-1 : 1);
+		oValue.day		= oValue.day + oRight.day * (sOperator == '-' ?-1 : 1);
+		//
+		fXSDateTime_normalize(oValue);
+	}
+	return oValue;
+};
+
+// xs:dayTimeDuration to/from seconds
+function fOperator_dayTimeDuration_toSeconds(oDuration) {
+	return (((oDuration.day * 24 + oDuration.hours) * 60 + oDuration.minutes) * 60 + oDuration.seconds) * (oDuration.negative ? -1 : 1);
+};
+
+function fOperator_dayTimeDuration_fromSeconds(nValue) {
+	var bNegative	=(nValue = cMath.round(nValue)) < 0,
+		nDays	= ~~((nValue = cMath.abs(nValue)) / 86400),
+		nHours	= ~~((nValue -= nDays * 3600 * 24) / 3600),
+		nMinutes= ~~((nValue -= nHours * 3600) / 60),
+		nSeconds	= nValue -= nMinutes * 60;
+	return new cXSDayTimeDuration(nDays, nHours, nMinutes, nSeconds, bNegative);
+};
+
+// xs:yearMonthDuration to/from months
+function fOperator_yearMonthDuration_toMonths(oDuration) {
+	return (oDuration.year * 12 + oDuration.month) * (oDuration.negative ? -1 : 1);
+};
+
+function fOperator_yearMonthDuration_fromMonths(nValue) {
+	var nNegative	=(nValue = cMath.round(nValue)) < 0,
+		nYears	= ~~((nValue = cMath.abs(nValue)) / 12),
+		nMonths		= nValue -= nYears * 12;
+	return new cXSYearMonthDuration(nYears, nMonths, nNegative);
+};
+
+// xs:time to seconds
+function fOperator_time_toSeconds(oTime) {
+	return oTime.seconds + (oTime.minutes - (oTime.timezone != null ? oTime.timezone % 60 : 0) + (oTime.hours - (oTime.timezone != null ? ~~(oTime.timezone / 60) : 0)) * 60) * 60;
+};
+
+// This function unlike all other date-related functions rely on interpretor's dateTime handling
+function fOperator_dateTime_toSeconds(oValue) {
+	var oDate	= new cDate((oValue.negative ? -1 : 1) * oValue.year, oValue.month, oValue.day, 0, 0, 0, 0);
+	if (oValue instanceof cXSDateTime) {
+		oDate.setHours(oValue.hours);
+		oDate.setMinutes(oValue.minutes);
+		oDate.setSeconds(oValue.seconds);
+	}
+	if (oValue.timezone != null)
+		oDate.setMinutes(oDate.getMinutes() - oValue.timezone);
+	return oDate.getTime() / 1000;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	14 Functions and Operators on Nodes
+		op:is-same-node
+		op:node-before
+		op:node-after
+*/
+
+// 14 Operators on Nodes
+// op:is-same-node($parameter1 as node(), $parameter2 as node()) as xs:boolean
+hStaticContext_operators["is-same-node"]	= function(oLeft, oRight) {
+	return new cXSBoolean(this.DOMAdapter.isSameNode(oLeft, oRight));
+};
+
+// op:node-before($parameter1 as node(), $parameter2 as node()) as xs:boolean
+hStaticContext_operators["node-before"]	= function(oLeft, oRight) {
+	return new cXSBoolean(!!(this.DOMAdapter.compareDocumentPosition(oLeft, oRight) & 4));
+};
+
+// op:node-after($parameter1 as node(), $parameter2 as node()) as xs:boolean
+hStaticContext_operators["node-after"]	= function(oLeft, oRight) {
+	return new cXSBoolean(!!(this.DOMAdapter.compareDocumentPosition(oLeft, oRight) & 2));
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	13.1 Operators on NOTATION
+		op:NOTATION-equal
+*/
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	6.2 Operators on Numeric Values
+		op:numeric-add
+		op:numeric-subtract
+		op:numeric-multiply
+		op:numeric-divide
+		op:numeric-integer-divide
+		op:numeric-mod
+		op:numeric-unary-plus
+		op:numeric-unary-minus
+
+	6.3 Comparison Operators on Numeric Values
+		op:numeric-equal
+		op:numeric-less-than
+		op:numeric-greater-than
+*/
+
+// 6.2 Operators on Numeric Values
+function fFunctionCall_numeric_getPower(oLeft, oRight) {
+	if (fIsNaN(oLeft) || (cMath.abs(oLeft) == nInfinity) || fIsNaN(oRight) || (cMath.abs(oRight) == nInfinity))
+		return 0;
+	var aLeft	= cString(oLeft).match(rNumericLiteral),
+		aRight	= cString(oRight).match(rNumericLiteral),
+		nPower	= cMath.max(1, (aLeft[2] || aLeft[3] || '').length + (aLeft[5] || 0) * (aLeft[4] == '+' ?-1 : 1), (aRight[2] || aRight[3] || '').length + (aRight[5] || 0) * (aRight[4] == '+' ?-1 : 1));
+	return nPower + (nPower % 2 ? 0 : 1);
+};
+
+// op:numeric-add($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-add"]		= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, ((nLeft * nPower) + (nRight * nPower))/nPower);
+};
+
+// op:numeric-subtract($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-subtract"]	= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, ((nLeft * nPower) - (nRight * nPower))/nPower);
+};
+
+// op:numeric-multiply($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-multiply"]	= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, ((nLeft * nPower) * (nRight * nPower))/(nPower * nPower));
+};
+
+// op:numeric-divide($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-divide"]	= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, (oLeft * nPower) / (oRight * nPower));
+};
+
+// op:numeric-integer-divide($arg1 as numeric, $arg2 as numeric) as xs:integer
+hStaticContext_operators["numeric-integer-divide"]	= function(oLeft, oRight) {
+	var oValue = oLeft / oRight;
+	return new cXSInteger(cMath.floor(oValue) + (oValue < 0));
+};
+
+// op:numeric-mod($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-mod"]	= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, ((nLeft * nPower) % (nRight * nPower)) / nPower);
+};
+
+// op:numeric-unary-plus($arg as numeric) as numeric
+hStaticContext_operators["numeric-unary-plus"]	= function(oRight) {
+	return oRight;
+};
+
+// op:numeric-unary-minus($arg as numeric) as numeric
+hStaticContext_operators["numeric-unary-minus"]	= function(oRight) {
+	oRight.value	*=-1;
+	return oRight;
+};
+
+
+// 6.3 Comparison Operators on Numeric Values
+// op:numeric-equal($arg1 as numeric, $arg2 as numeric) as xs:boolean
+hStaticContext_operators["numeric-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() == oRight.valueOf());
+};
+
+// op:numeric-less-than($arg1 as numeric, $arg2 as numeric) as xs:boolean
+hStaticContext_operators["numeric-less-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() < oRight.valueOf());
+};
+
+// op:numeric-greater-than($arg1 as numeric, $arg2 as numeric) as xs:boolean
+hStaticContext_operators["numeric-greater-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() > oRight.valueOf());
+};
+
+function fOperator_numeric_getResultOfType(oLeft, oRight, nResult) {
+	return new (oLeft instanceof cXSInteger && oRight instanceof cXSInteger && nResult == cMath.round(nResult) ? cXSInteger : cXSDecimal)(nResult);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	11.2 Functions and Operators Related to QNames
+		op:QName-equal
+
+*/
+
+// 11.2 Operators Related to QNames
+// op:QName-equal($arg1 as xs:QName, $arg2 as xs:QName) as xs:boolean
+hStaticContext_operators["QName-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.localName == oRight.localName && oLeft.namespaceURI == oRight.namespaceURI);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	15.1 General Functions and Operators on Sequences
+		op:concatenate
+
+	15.3 Equals, Union, Intersection and Except
+		op:union
+		op:intersect
+		op:except
+
+	15.5 Functions and Operators that Generate Sequences
+		op:to
+
+*/
+
+// 15.1 General Functions and Operators on Sequences
+// op:concatenate($seq1 as item()*, $seq2 as item()*) as item()*
+hStaticContext_operators["concatenate"]	= function(oSequence1, oSequence2) {
+	return oSequence1.concat(oSequence2);
+};
+
+// 15.3 Equals, Union, Intersection and Except
+// op:union($parameter1 as node()*, $parameter2 as node()*) as node()*
+hStaticContext_operators["union"]	= function(oSequence1, oSequence2) {
+	var oSequence	= [];
+	// Process first collection
+	for (var nIndex = 0, nLength = oSequence1.length, oItem; nIndex < nLength; nIndex++) {
+		if (!this.DOMAdapter.isNode(oItem = oSequence1[nIndex]))
+			throw new cException("XPTY0004"
+
+			);	// Required item type of second operand of 'intersect' is node(); supplied value has item type xs:integer
+		//
+		if (fArray_indexOf(oSequence, oItem) ==-1)
+			oSequence.push(oItem);
+	}
+	// Process second collection
+	for (var nIndex = 0, nLength = oSequence2.length, oItem; nIndex < nLength; nIndex++) {
+		if (!this.DOMAdapter.isNode(oItem = oSequence2[nIndex]))
+			throw new cException("XPTY0004"
+
+			);	// Required item type of second operand of 'intersect' is node(); supplied value has item type xs:integer
+		//
+		if (fArray_indexOf(oSequence, oItem) ==-1)
+			oSequence.push(oItem);
+	}
+	return fFunction_sequence_order(oSequence, this);
+};
+
+// op:intersect($parameter1 as node()*, $parameter2 as node()*) as node()*
+hStaticContext_operators["intersect"]	= function(oSequence1, oSequence2) {
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, oItem, bFound; nIndex < nLength; nIndex++) {
+		if (!this.DOMAdapter.isNode(oItem = oSequence1[nIndex]))
+			throw new cException("XPTY0004"
+
+			);	// Required item type of second operand of 'intersect' is node(); supplied value has item type xs:integer
+		//
+		bFound	= false;
+		for (var nRightIndex = 0, nRightLength = oSequence2.length;(nRightIndex < nRightLength) && !bFound; nRightIndex++) {
+			if (!this.DOMAdapter.isNode(oSequence2[nRightIndex]))
+				throw new cException("XPTY0004"
+
+				);
+			bFound = this.DOMAdapter.isSameNode(oSequence2[nRightIndex], oItem);
+		}
+		//
+		if (bFound && fArray_indexOf(oSequence, oItem) ==-1)
+			oSequence.push(oItem);
+	}
+	return fFunction_sequence_order(oSequence, this);
+};
+
+// op:except($parameter1 as node()*, $parameter2 as node()*) as node()*
+hStaticContext_operators["except"]	= function(oSequence1, oSequence2) {
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, oItem, bFound; nIndex < nLength; nIndex++) {
+		if (!this.DOMAdapter.isNode(oItem = oSequence1[nIndex]))
+			throw new cException("XPTY0004"
+
+			);	// Required item type of second operand of 'intersect' is node(); supplied value has item type xs:integer
+		//
+		bFound	= false;
+		for (var nRightIndex = 0, nRightLength = oSequence2.length;(nRightIndex < nRightLength) && !bFound; nRightIndex++) {
+			if (!this.DOMAdapter.isNode(oSequence2[nRightIndex]))
+				throw new cException("XPTY0004"
+
+				);
+			bFound = this.DOMAdapter.isSameNode(oSequence2[nRightIndex], oItem);
+		}
+		//
+		if (!bFound && fArray_indexOf(oSequence, oItem) ==-1)
+			oSequence.push(oItem);
+	}
+	return fFunction_sequence_order(oSequence, this);
+};
+
+// 15.5 Functions and Operators that Generate Sequences
+// op:to($firstval as xs:integer, $lastval as xs:integer) as xs:integer*
+hStaticContext_operators["to"]	= function(oLeft, oRight) {
+	var oSequence	= [];
+	for (var nIndex = oLeft.valueOf(), nLength = oRight.valueOf(); nIndex <= nLength; nIndex++)
+		oSequence.push(new cXSInteger(nIndex));
+	//
+	return oSequence;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	2 Accessors
+		node-name
+		nilled
+		string
+		data
+		base-uri
+		document-uri
+
+*/
+
+// fn:node-name($arg as node()?) as xs:QName?
+fStaticContext_defineSystemFunction("node-name",		[[cXTNode, '?']],	function(oNode) {
+	if (oNode != null) {
+		var fGetProperty	= this.DOMAdapter.getProperty;
+		switch (fGetProperty(oNode, "nodeType")) {
+			case 1:		// ELEMENT_NAME
+			case 2:		// ATTRIBUTE_NODE
+				return new cXSQName(fGetProperty(oNode, "prefix"), fGetProperty(oNode, "localName"), fGetProperty(oNode, "namespaceURI"));
+			case 5:		// ENTITY_REFERENCE_NODE
+				throw "Not implemented";
+			case 6:		// ENTITY_NODE
+				throw "Not implemented";
+			case 7:		// PROCESSING_INSTRUCTION_NODE
+				return new cXSQName(null, fGetProperty(oNode, "target"), null);
+			case 10:	// DOCUMENT_TYPE_NODE
+				return new cXSQName(null, fGetProperty(oNode, "name"), null);
+		}
+	}
+	//
+	return null;
+});
+
+// fn:nilled($arg as node()?) as xs:boolean?
+fStaticContext_defineSystemFunction("nilled",	[[cXTNode, '?']],	function(oNode) {
+	if (oNode != null) {
+		if (this.DOMAdapter.getProperty(oNode, "nodeType") == 1)
+			return new cXSBoolean(false);	// TODO: Determine if node is nilled
+	}
+	//
+	return null;
+});
+
+// fn:string() as xs:string
+// fn:string($arg as item()?) as xs:string
+fStaticContext_defineSystemFunction("string",	[[cXTItem, '?', true]],	function(/*[*/oItem/*]*/) {
+	if (!arguments.length) {
+		if (!this.item)
+			throw new cException("XPDY0002");
+		oItem	= this.item;
+	}
+	return oItem == null ? new cXSString('') : cXSString.cast(fFunction_sequence_atomize([oItem], this)[0]);
+});
+
+// fn:data($arg as item()*) as xs:anyAtomicType*
+fStaticContext_defineSystemFunction("data",	[[cXTItem, '*']],		function(oSequence1) {
+	return fFunction_sequence_atomize(oSequence1, this);
+});
+
+// fn:base-uri() as xs:anyURI?
+// fn:base-uri($arg as node()?) as xs:anyURI?
+fStaticContext_defineSystemFunction("base-uri",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	//
+	return cXSAnyURI.cast(new cXSString(this.DOMAdapter.getProperty(oNode, "baseURI") || ''));
+});
+
+// fn:document-uri($arg as node()?) as xs:anyURI?
+fStaticContext_defineSystemFunction("document-uri",	[[cXTNode, '?']],	function(oNode) {
+	if (oNode != null) {
+		var fGetProperty	= this.DOMAdapter.getProperty;
+		if (fGetProperty(oNode, "nodeType") == 9)
+			return cXSAnyURI.cast(new cXSString(fGetProperty(oNode, "documentURI") || ''));
+	}
+	//
+	return null;
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	8 Functions on anyURI
+		resolve-uri
+*/
+
+// fn:resolve-uri($relative as xs:string?) as xs:anyURI?
+// fn:resolve-uri($relative as xs:string?, $base as xs:string) as xs:anyURI?
+fStaticContext_defineSystemFunction("resolve-uri",	[[cXSString, '?'], [cXSString, '', true]],	function(sUri, sBaseUri) {
+	if (arguments.length < 2) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		sBaseUri	= new cXSString(this.DOMAdapter.getProperty(this.item, "baseURI") || '');
+	}
+
+	if (sUri == null)
+		return null;
+
+	//
+	if (sUri.valueOf() == '' || sUri.valueOf().charAt(0) == '#')
+		return cXSAnyURI.cast(sBaseUri);
+
+	var oUri	= cXSAnyURI.cast(sUri);
+	if (oUri.scheme)
+		return oUri;
+
+	var oBaseUri	= cXSAnyURI.cast(sBaseUri);
+	oUri.scheme	= oBaseUri.scheme;
+
+	if (!oUri.authority) {
+		// authority
+		oUri.authority	= oBaseUri.authority;
+
+		// path
+		if (oUri.path.charAt(0) != '/') {
+			var aUriSegments		= oUri.path.split('/'),
+				aBaseUriSegments	= oBaseUri.path.split('/');
+			aBaseUriSegments.pop();
+
+			var nBaseUriStart	= aBaseUriSegments[0] == '' ? 1 : 0;
+			for (var nIndex = 0, nLength = aUriSegments.length; nIndex < nLength; nIndex++) {
+				if (aUriSegments[nIndex] == '..') {
+					if (aBaseUriSegments.length > nBaseUriStart)
+						aBaseUriSegments.pop();
+					else {
+						aBaseUriSegments.push(aUriSegments[nIndex]);
+						nBaseUriStart++;
+					}
+				}
+				else
+				if (aUriSegments[nIndex] != '.')
+					aBaseUriSegments.push(aUriSegments[nIndex]);
+			}
+			if (aUriSegments[--nIndex] == '..' || aUriSegments[nIndex] == '.')
+				aBaseUriSegments.push('');
+			//
+			oUri.path	= aBaseUriSegments.join('/');
+		}
+	}
+
+	return oUri;
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	9.1 Additional Boolean Constructor Functions
+		true
+		false
+
+	9.3 Functions on Boolean Values
+		not
+*/
+
+// 9.1 Additional Boolean Constructor Functions
+// fn:true() as xs:boolean
+fStaticContext_defineSystemFunction("true",	[],	function() {
+	return new cXSBoolean(true);
+});
+
+// fn:false() as xs:boolean
+fStaticContext_defineSystemFunction("false",	[],	function() {
+	return new cXSBoolean(false);
+});
+
+// 9.3 Functions on Boolean Values
+// fn:not($arg as item()*) as xs:boolean
+fStaticContext_defineSystemFunction("not",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSBoolean(!fFunction_sequence_toEBV(oSequence1, this));
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	16 Context Functions
+		position
+		last
+		current-dateTime
+		current-date
+		current-time
+		implicit-timezone
+		default-collation
+		static-base-uri
+
+*/
+// fn:position() as xs:integer
+fStaticContext_defineSystemFunction("position",	[],	function() {
+	return new cXSInteger(this.position);
+});
+
+// fn:last() as xs:integer
+fStaticContext_defineSystemFunction("last",	[],	function() {
+	return new cXSInteger(this.size);
+});
+
+// fn:current-dateTime() as xs:dateTime (2004-05-12T18:17:15.125Z)
+fStaticContext_defineSystemFunction("current-dateTime",	[],	 function() {
+	return this.dateTime;
+});
+
+// fn:current-date() as xs:date (2004-05-12+01:00)
+fStaticContext_defineSystemFunction("current-date",	[],	function() {
+	return cXSDate.cast(this.dateTime);
+});
+
+// fn:current-time() as xs:time (23:17:00.000-05:00)
+fStaticContext_defineSystemFunction("current-time",	[],	function() {
+	return cXSTime.cast(this.dateTime);
+});
+
+// fn:implicit-timezone() as xs:dayTimeDuration
+fStaticContext_defineSystemFunction("implicit-timezone",	[],	function() {
+	return this.timezone;
+});
+
+// fn:default-collation() as xs:string
+fStaticContext_defineSystemFunction("default-collation",	[],	 function() {
+	return new cXSString(this.staticContext.defaultCollationName);
+});
+
+// fn:static-base-uri() as xs:anyURI?
+fStaticContext_defineSystemFunction("static-base-uri",	[],	function() {
+	return cXSAnyURI.cast(new cXSString(this.staticContext.baseURI || ''));
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	10.5 Component Extraction Functions on Durations, Dates and Times
+		years-from-duration
+		months-from-duration
+		days-from-duration
+		hours-from-duration
+		minutes-from-duration
+		seconds-from-duration
+		year-from-dateTime
+		month-from-dateTime
+		day-from-dateTime
+		hours-from-dateTime
+		minutes-from-dateTime
+		seconds-from-dateTime
+		timezone-from-dateTime
+		year-from-date
+		month-from-date
+		day-from-date
+		timezone-from-date
+		hours-from-time
+		minutes-from-time
+		seconds-from-time
+		timezone-from-time
+
+	10.7 Timezone Adjustment Functions on Dates and Time Values
+		adjust-dateTime-to-timezone
+		adjust-date-to-timezone
+		adjust-time-to-timezone
+*/
+
+// 10.5 Component Extraction Functions on Durations, Dates and Times
+// functions on duration
+// fn:years-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("years-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "year");
+});
+
+// fn:months-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("months-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "month");
+});
+
+// fn:days-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("days-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "day");
+});
+
+// fn:hours-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("hours-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "hours");
+});
+
+// fn:minutes-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("minutes-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "minutes");
+});
+
+// fn:seconds-from-duration($arg as xs:duration?) as xs:decimal?
+fStaticContext_defineSystemFunction("seconds-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "seconds");
+});
+
+// functions on dateTime
+// fn:year-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("year-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime,	"year");
+});
+
+// fn:month-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("month-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "month");
+});
+
+// fn:day-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("day-from-dateTime",			[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "day");
+});
+
+// fn:hours-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("hours-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "hours");
+});
+
+// fn:minutes-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("minutes-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "minutes");
+});
+
+// fn:seconds-from-dateTime($arg as xs:dateTime?) as xs:decimal?
+fStaticContext_defineSystemFunction("seconds-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "seconds");
+});
+
+// fn:timezone-from-dateTime($arg as xs:dateTime?) as xs:dayTimeDuration?
+fStaticContext_defineSystemFunction("timezone-from-dateTime",	[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "timezone");
+});
+
+// functions on date
+// fn:year-from-date($arg as xs:date?) as xs:integer?
+fStaticContext_defineSystemFunction("year-from-date",	[[cXSDate, '?']],	function(oDate) {
+	return fFunction_dateTime_getComponent(oDate, "year");
+});
+
+// fn:month-from-date($arg as xs:date?) as xs:integer?
+fStaticContext_defineSystemFunction("month-from-date",	[[cXSDate, '?']],	function(oDate) {
+	return fFunction_dateTime_getComponent(oDate, "month");
+});
+
+// fn:day-from-date($arg as xs:date?) as xs:integer?
+fStaticContext_defineSystemFunction("day-from-date",		[[cXSDate, '?']],	function(oDate) {
+	return fFunction_dateTime_getComponent(oDate, "day");
+});
+
+// fn:timezone-from-date($arg as xs:date?) as xs:dayTimeDuration?
+fStaticContext_defineSystemFunction("timezone-from-date",	[[cXSDate, '?']],	function(oDate) {
+	return fFunction_dateTime_getComponent(oDate, "timezone");
+});
+
+// functions on time
+// fn:hours-from-time($arg as xs:time?) as xs:integer?
+fStaticContext_defineSystemFunction("hours-from-time",		[[cXSTime, '?']],	function(oTime) {
+	return fFunction_dateTime_getComponent(oTime, "hours");
+});
+
+// fn:minutes-from-time($arg as xs:time?) as xs:integer?
+fStaticContext_defineSystemFunction("minutes-from-time",		[[cXSTime, '?']],	function(oTime) {
+	return fFunction_dateTime_getComponent(oTime, "minutes");
+});
+
+// fn:seconds-from-time($arg as xs:time?) as xs:decimal?
+fStaticContext_defineSystemFunction("seconds-from-time",		[[cXSTime, '?']],	function(oTime) {
+	return fFunction_dateTime_getComponent(oTime, "seconds");
+});
+
+// fn:timezone-from-time($arg as xs:time?) as xs:dayTimeDuration?
+fStaticContext_defineSystemFunction("timezone-from-time",	[[cXSTime, '?']],	function(oTime) {
+	return fFunction_dateTime_getComponent(oTime, "timezone");
+});
+
+
+// 10.7 Timezone Adjustment Functions on Dates and Time Values
+// fn:adjust-dateTime-to-timezone($arg as xs:dateTime?) as xs:dateTime?
+// fn:adjust-dateTime-to-timezone($arg as xs:dateTime?, $timezone as xs:dayTimeDuration?) as xs:dateTime?
+fStaticContext_defineSystemFunction("adjust-dateTime-to-timezone",	[[cXSDateTime, '?'], [cXSDayTimeDuration, '?', true]],	function(oDateTime, oDayTimeDuration) {
+	return fFunction_dateTime_adjustTimezone(oDateTime, arguments.length > 1 && oDayTimeDuration != null ? arguments.length > 1 ? oDayTimeDuration : this.timezone : null);
+});
+
+// fn:adjust-date-to-timezone($arg as xs:date?) as xs:date?
+// fn:adjust-date-to-timezone($arg as xs:date?, $timezone as xs:dayTimeDuration?) as xs:date?
+fStaticContext_defineSystemFunction("adjust-date-to-timezone",		[[cXSDate, '?'], [cXSDayTimeDuration, '?', true]],	function(oDate, oDayTimeDuration) {
+	return fFunction_dateTime_adjustTimezone(oDate, arguments.length > 1 && oDayTimeDuration != null ? arguments.length > 1 ? oDayTimeDuration : this.timezone : null);
+});
+
+// fn:adjust-time-to-timezone($arg as xs:time?) as xs:time?
+// fn:adjust-time-to-timezone($arg as xs:time?, $timezone as xs:dayTimeDuration?) as xs:time?
+fStaticContext_defineSystemFunction("adjust-time-to-timezone",		[[cXSTime, '?'], [cXSDayTimeDuration, '?', true]],	function(oTime, oDayTimeDuration) {
+	return fFunction_dateTime_adjustTimezone(oTime, arguments.length > 1 && oDayTimeDuration != null ? arguments.length > 1 ? oDayTimeDuration : this.timezone : null);
+});
+
+//
+function fFunction_duration_getComponent(oDuration, sName) {
+	if (oDuration == null)
+		return null;
+
+	var nValue	= oDuration[sName] * (oDuration.negative ?-1 : 1);
+	return sName == "seconds" ? new cXSDecimal(nValue) : new cXSInteger(nValue);
+};
+
+//
+function fFunction_dateTime_getComponent(oDateTime, sName) {
+	if (oDateTime == null)
+		return null;
+
+	if (sName == "timezone") {
+		var nTimezone	= oDateTime.timezone;
+		if (nTimezone == null)
+			return null;
+		return new cXSDayTimeDuration(0, cMath.abs(~~(nTimezone / 60)), cMath.abs(nTimezone % 60), 0, nTimezone < 0);
+	}
+	else {
+		var nValue	= oDateTime[sName];
+		if (!(oDateTime instanceof cXSDate)) {
+			if (sName == "hours")
+				if (nValue == 24)
+					nValue	= 0;
+		}
+		if (!(oDateTime instanceof cXSTime))
+			nValue	*= oDateTime.negative ?-1 : 1;
+		return sName == "seconds" ? new cXSDecimal(nValue) : new cXSInteger(nValue);
+	}
+};
+
+//
+function fFunction_dateTime_adjustTimezone(oDateTime, oTimezone) {
+	if (oDateTime == null)
+		return null;
+
+	// Create a copy
+	var oValue;
+	if (oDateTime instanceof cXSDate)
+		oValue	= new cXSDate(oDateTime.year, oDateTime.month, oDateTime.day, oDateTime.timezone, oDateTime.negative);
+	else
+	if (oDateTime instanceof cXSTime)
+		oValue	= new cXSTime(oDateTime.hours, oDateTime.minutes, oDateTime.seconds, oDateTime.timezone, oDateTime.negative);
+	else
+		oValue	= new cXSDateTime(oDateTime.year, oDateTime.month, oDateTime.day, oDateTime.hours, oDateTime.minutes, oDateTime.seconds, oDateTime.timezone, oDateTime.negative);
+
+	//
+	if (oTimezone == null)
+		oValue.timezone	= null;
+	else {
+		var nTimezone	= fOperator_dayTimeDuration_toSeconds(oTimezone) / 60;
+		if (oDateTime.timezone != null) {
+			var nDiff	= nTimezone - oDateTime.timezone;
+			if (oDateTime instanceof cXSDate) {
+				if (nDiff < 0)
+					oValue.day--;
+			}
+			else {
+				oValue.minutes	+= nDiff % 60;
+				oValue.hours	+= ~~(nDiff / 60);
+			}
+			//
+			fXSDateTime_normalize(oValue);
+		}
+		oValue.timezone	= nTimezone;
+	}
+	return oValue;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	14 Functions and Operators on Nodes
+		name
+		local-name
+		namespace-uri
+		number
+		lang
+		root
+
+*/
+
+// 14 Functions on Nodes
+// fn:name() as xs:string
+// fn:name($arg as node()?) as xs:string
+fStaticContext_defineSystemFunction("name",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	else
+	if (oNode == null)
+		return new cXSString('');
+	//
+	var vValue	= hStaticContext_functions["node-name"].call(this, oNode);
+	return new cXSString(vValue == null ? '' : vValue.toString());
+});
+
+// fn:local-name() as xs:string
+// fn:local-name($arg as node()?) as xs:string
+fStaticContext_defineSystemFunction("local-name",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	else
+	if (oNode == null)
+		return new cXSString('');
+	//
+	return new cXSString(this.DOMAdapter.getProperty(oNode, "localName") || '');
+});
+
+// fn:namespace-uri() as xs:anyURI
+// fn:namespace-uri($arg as node()?) as xs:anyURI
+fStaticContext_defineSystemFunction("namespace-uri",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	else
+	if (oNode == null)
+		return cXSAnyURI.cast(new cXSString(''));
+	//
+	return cXSAnyURI.cast(new cXSString(this.DOMAdapter.getProperty(oNode, "namespaceURI") || ''));
+});
+
+// fn:number() as xs:double
+// fn:number($arg as xs:anyAtomicType?) as xs:double
+fStaticContext_defineSystemFunction("number",	[[cXSAnyAtomicType, '?', true]],	function(/*[*/oItem/*]*/) {
+	if (!arguments.length) {
+		if (!this.item)
+			throw new cException("XPDY0002");
+		oItem	= fFunction_sequence_atomize([this.item], this)[0];
+	}
+
+	// If input item cannot be cast to xs:decimal, a NaN should be returned
+	var vValue	= new cXSDouble(nNaN);
+	if (oItem != null) {
+		try {
+			vValue	= cXSDouble.cast(oItem);
+		}
+		catch (e) {
+
+		}
+	}
+	return vValue;
+});
+
+// fn:lang($testlang as xs:string?) as xs:boolean
+// fn:lang($testlang as xs:string?, $node as node()) as xs:boolean
+fStaticContext_defineSystemFunction("lang",	[[cXSString, '?'], [cXTNode, '', true]],	function(sLang, oNode) {
+	if (arguments.length < 2) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+
+	var fGetProperty	= this.DOMAdapter.getProperty;
+	if (fGetProperty(oNode, "nodeType") == 2)
+		oNode	= fGetProperty(oNode, "ownerElement");
+
+	// walk up the tree looking for xml:lang attribute
+	for (var aAttributes; oNode; oNode = fGetProperty(oNode, "parentNode"))
+		if (aAttributes = fGetProperty(oNode, "attributes"))
+			for (var nIndex = 0, nLength = aAttributes.length; nIndex < nLength; nIndex++)
+				if (fGetProperty(aAttributes[nIndex], "nodeName") == "xml:lang")
+					return new cXSBoolean(fGetProperty(aAttributes[nIndex], "value").replace(/-.+/, '').toLowerCase() == sLang.valueOf().replace(/-.+/, '').toLowerCase());
+	//
+	return new cXSBoolean(false);
+});
+
+// fn:root() as node()
+// fn:root($arg as node()?) as node()?
+fStaticContext_defineSystemFunction("root",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	else
+	if (oNode == null)
+		return null;
+
+	var fGetProperty	= this.DOMAdapter.getProperty;
+
+	// If context node is Attribute
+	if (fGetProperty(oNode, "nodeType") == 2)
+		oNode	= fGetProperty(oNode, "ownerElement");
+
+	for (var oParent = oNode; oParent; oParent = fGetProperty(oNode, "parentNode"))
+		oNode	= oParent;
+
+	return oNode;
+});
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	6.4 Functions on Numeric Values
+		abs
+		ceiling
+		floor
+		round
+		round-half-to-even
+*/
+
+// 6.4 Functions on Numeric Values
+// fn:abs($arg as numeric?) as numeric?
+fStaticContext_defineSystemFunction("abs",		[[cXSDouble, '?']],	function(oValue) {
+	return new cXSDecimal(cMath.abs(oValue));
+});
+
+// fn:ceiling($arg as numeric?) as numeric?
+fStaticContext_defineSystemFunction("ceiling",	[[cXSDouble, '?']],	function(oValue) {
+	return new cXSDecimal(cMath.ceil(oValue));
+});
+
+// fn:floor($arg as numeric?) as numeric?
+fStaticContext_defineSystemFunction("floor",		[[cXSDouble, '?']],	function(oValue) {
+	return new cXSDecimal(cMath.floor(oValue));
+});
+
+// fn:round($arg as numeric?) as numeric?
+fStaticContext_defineSystemFunction("round",		[[cXSDouble, '?']],	function(oValue) {
+	return new cXSDecimal(cMath.round(oValue));
+});
+
+// fn:round-half-to-even($arg as numeric?) as numeric?
+// fn:round-half-to-even($arg as numeric?, $precision as xs:integer) as numeric?
+fStaticContext_defineSystemFunction("round-half-to-even",	[[cXSDouble, '?'], [cXSInteger, '', true]],	function(oValue, oPrecision) {
+	var nPrecision	= arguments.length > 1 ? oPrecision.valueOf() : 0;
+
+	//
+	if (nPrecision < 0) {
+		var oPower	= new cXSInteger(cMath.pow(10,-nPrecision)),
+			nRounded= cMath.round(hStaticContext_operators["numeric-divide"].call(this, oValue, oPower)),
+			oRounded= new cXSInteger(nRounded);
+			nDecimal= cMath.abs(hStaticContext_operators["numeric-subtract"].call(this, oRounded, hStaticContext_operators["numeric-divide"].call(this, oValue, oPower)));
+		return hStaticContext_operators["numeric-multiply"].call(this, hStaticContext_operators["numeric-add"].call(this, oRounded, new cXSDecimal(nDecimal == 0.5 && nRounded % 2 ?-1 : 0)), oPower);
+	}
+	else {
+		var oPower	= new cXSInteger(cMath.pow(10, nPrecision)),
+			nRounded= cMath.round(hStaticContext_operators["numeric-multiply"].call(this, oValue, oPower)),
+			oRounded= new cXSInteger(nRounded);
+			nDecimal= cMath.abs(hStaticContext_operators["numeric-subtract"].call(this, oRounded, hStaticContext_operators["numeric-multiply"].call(this, oValue, oPower)));
+		return hStaticContext_operators["numeric-divide"].call(this, hStaticContext_operators["numeric-add"].call(this, oRounded, new cXSDecimal(nDecimal == 0.5 && nRounded % 2 ?-1 : 0)), oPower);
+	}
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	11.1 Additional Constructor Functions for QNames
+		resolve-QName
+		QName
+
+	11.2 Functions and Operators Related to QNames
+		prefix-from-QName
+		local-name-from-QName
+		namespace-uri-from-QName
+		namespace-uri-for-prefix
+		in-scope-prefixes
+
+*/
+
+// 11.1 Additional Constructor Functions for QNames
+// fn:resolve-QName($qname as xs:string?, $element as element()) as xs:QName?
+fStaticContext_defineSystemFunction("resolve-QName",	[[cXSString, '?'], [cXTElement]],	function(oQName, oElement) {
+	if (oQName == null)
+		return null;
+
+	var sQName	= oQName.valueOf(),
+		aMatch	= sQName.match(rXSQName);
+	if (!aMatch)
+		throw new cException("FOCA0002"
+
+		);
+
+	var sPrefix	= aMatch[1] || null,
+		sLocalName	= aMatch[2],
+		sNameSpaceURI = this.DOMAdapter.lookupNamespaceURI(oElement, sPrefix);
+	//
+	if (sPrefix != null &&!sNameSpaceURI)
+		throw new cException("FONS0004"
+
+		);
+
+	return new cXSQName(sPrefix, sLocalName, sNameSpaceURI || null);
+});
+
+// fn:QName($paramURI as xs:string?, $paramQName as xs:string) as xs:QName
+fStaticContext_defineSystemFunction("QName",		[[cXSString, '?'], [cXSString]],	function(oUri, oQName) {
+	var sQName	= oQName.valueOf(),
+		aMatch	= sQName.match(rXSQName);
+
+	if (!aMatch)
+		throw new cException("FOCA0002"
+
+		);
+
+	return new cXSQName(aMatch[1] || null, aMatch[2] || null, oUri == null ? '' : oUri.valueOf());
+});
+
+// 11.2 Functions Related to QNames
+// fn:prefix-from-QName($arg as xs:QName?) as xs:NCName?
+fStaticContext_defineSystemFunction("prefix-from-QName",			[[cXSQName, '?']],	function(oQName) {
+	if (oQName != null) {
+		if (oQName.prefix)
+			return new cXSNCName(oQName.prefix);
+	}
+	//
+	return null;
+});
+
+// fn:local-name-from-QName($arg as xs:QName?) as xs:NCName?
+fStaticContext_defineSystemFunction("local-name-from-QName",		[[cXSQName, '?']],	function(oQName) {
+	if (oQName == null)
+		return null;
+
+	return new cXSNCName(oQName.localName);
+});
+
+// fn:namespace-uri-from-QName($arg as xs:QName?) as xs:anyURI?
+fStaticContext_defineSystemFunction("namespace-uri-from-QName",	[[cXSQName, '?']],	function(oQName) {
+	if (oQName == null)
+		return null;
+
+	return cXSAnyURI.cast(new cXSString(oQName.namespaceURI || ''));
+});
+
+// fn:namespace-uri-for-prefix($prefix as xs:string?, $element as element()) as xs:anyURI?
+fStaticContext_defineSystemFunction("namespace-uri-for-prefix",	[[cXSString, '?'], [cXTElement]],	function(oPrefix, oElement) {
+	var sPrefix	= oPrefix == null ? '' : oPrefix.valueOf(),
+		sNameSpaceURI	= this.DOMAdapter.lookupNamespaceURI(oElement, sPrefix || null);
+
+	return sNameSpaceURI == null ? null : cXSAnyURI.cast(new cXSString(sNameSpaceURI));
+});
+
+// fn:in-scope-prefixes($element as element()) as xs:string*
+fStaticContext_defineSystemFunction("in-scope-prefixes",	[[cXTElement]],	function(oElement) {
+	throw "Function '" + "in-scope-prefixes" + "' not implemented";
+});
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	15.1 General Functions and Operators on Sequences
+		boolean
+		index-of
+		empty
+		exists
+		distinct-values
+		insert-before
+		remove
+		reverse
+		subsequence
+		unordered
+
+	15.2 Functions That Test the Cardinality of Sequences
+		zero-or-one
+		one-or-more
+		exactly-one
+
+	15.3 Equals, Union, Intersection and Except
+		deep-equal
+
+	15.4 Aggregate Functions
+		count
+		avg
+		max
+		min
+		sum
+
+	15.5 Functions and Operators that Generate Sequences
+		id
+		idref
+		doc
+		doc-available
+		collection
+		element-with-id
+
+*/
+
+// 15.1 General Functions and Operators on Sequences
+// fn:boolean($arg as item()*) as xs:boolean
+fStaticContext_defineSystemFunction("boolean",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSBoolean(fFunction_sequence_toEBV(oSequence1, this));
+});
+
+// fn:index-of($seqParam as xs:anyAtomicType*, $srchParam as xs:anyAtomicType) as xs:integer*
+// fn:index-of($seqParam as xs:anyAtomicType*, $srchParam as xs:anyAtomicType, $collation as xs:string) as xs:integer*
+fStaticContext_defineSystemFunction("index-of",	[[cXSAnyAtomicType, '*'], [cXSAnyAtomicType], [cXSString, '', true]],	function(oSequence1, oSearch, oCollation) {
+	if (!oSequence1.length || oSearch == null)
+		return [];
+
+	// TODO: Implement collation
+
+	var vLeft	= oSearch;
+	// Cast to XSString if Untyped
+	if (vLeft instanceof cXSUntypedAtomic)
+		vLeft	= cXSString.cast(vLeft);
+
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+		vRight	= oSequence1[nIndex];
+		// Cast to XSString if Untyped
+		if (vRight instanceof cXSUntypedAtomic)
+			vRight	= cXSString.cast(vRight);
+		//
+		if (vRight.valueOf() === vLeft.valueOf())
+			oSequence.push(new cXSInteger(nIndex + 1));
+	}
+
+	return oSequence;
+});
+
+// fn:empty($arg as item()*) as xs:boolean
+fStaticContext_defineSystemFunction("empty",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSBoolean(!oSequence1.length);
+});
+
+// fn:exists($arg as item()*) as xs:boolean
+fStaticContext_defineSystemFunction("exists",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSBoolean(!!oSequence1.length);
+});
+
+// fn:distinct-values($arg as xs:anyAtomicType*) as xs:anyAtomicType*
+// fn:distinct-values($arg as xs:anyAtomicType*, $collation as xs:string) as xs:anyAtomicType*
+fStaticContext_defineSystemFunction("distinct-values",	[[cXSAnyAtomicType, '*'], [cXSString, '', true]],	function(oSequence1, oCollation) {
+	if (arguments.length > 1)
+		throw "Collation parameter in function '" + "distinct-values" + "' is not implemented";
+
+	if (!oSequence1.length)
+		return null;
+
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, vLeft; nIndex < nLength; nIndex++) {
+		vLeft	= oSequence1[nIndex];
+		// Cast to XSString if Untyped
+		if (vLeft instanceof cXSUntypedAtomic)
+			vLeft	= cXSString.cast(vLeft);
+		for (var nRightIndex = 0, nRightLength = oSequence.length, vRight, bFound = false; (nRightIndex < nRightLength) &&!bFound; nRightIndex++) {
+			vRight	= oSequence[nRightIndex];
+			// Cast to XSString if Untyped
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSString.cast(vRight);
+			//
+			if (vRight.valueOf() === vLeft.valueOf())
+				bFound	= true;
+		}
+		if (!bFound)
+			oSequence.push(oSequence1[nIndex]);
+	}
+
+	return oSequence;
+});
+
+// fn:insert-before($target as item()*, $position as xs:integer, $inserts as item()*) as item()*
+fStaticContext_defineSystemFunction("insert-before",	[[cXTItem, '*'], [cXSInteger], [cXTItem, '*']],	function(oSequence1, oPosition, oSequence3) {
+	if (!oSequence1.length)
+		return oSequence3;
+	if (!oSequence3.length)
+		return oSequence1;
+
+	var nLength 	= oSequence1.length,
+		nPosition	= oPosition.valueOf();
+	if (nPosition < 1)
+		nPosition	= 1;
+	else
+	if (nPosition > nLength)
+		nPosition	= nLength + 1;
+
+	var oSequence	=  [];
+	for (var nIndex = 0; nIndex < nLength; nIndex++) {
+		if (nPosition == nIndex + 1)
+			oSequence	= oSequence.concat(oSequence3);
+		oSequence.push(oSequence1[nIndex]);
+	}
+	if (nPosition == nIndex + 1)
+		oSequence	= oSequence.concat(oSequence3);
+
+	return oSequence;
+});
+
+// fn:remove($target as item()*, $position as xs:integer) as item()*
+fStaticContext_defineSystemFunction("remove",	[[cXTItem, '*'], [cXSInteger]],	function(oSequence1, oPosition) {
+	if (!oSequence1.length)
+		return [];
+
+	var nLength 	= oSequence1.length,
+		nPosition	= oPosition.valueOf();
+
+	if (nPosition < 1 || nPosition > nLength)
+		return oSequence1;
+
+	var oSequence	=  [];
+	for (var nIndex = 0; nIndex < nLength; nIndex++)
+		if (nPosition != nIndex + 1)
+			oSequence.push(oSequence1[nIndex]);
+
+	return oSequence;
+});
+
+// fn:reverse($arg as item()*) as item()*
+fStaticContext_defineSystemFunction("reverse",	[[cXTItem, '*']],	function(oSequence1) {
+	oSequence1.reverse();
+
+	return oSequence1;
+});
+
+// fn:subsequence($sourceSeq as item()*, $startingLoc as xs:double) as item()*
+// fn:subsequence($sourceSeq as item()*, $startingLoc as xs:double, $length as xs:double) as item()*
+fStaticContext_defineSystemFunction("subsequence",	[[cXTItem, '*'], [cXSDouble, ''], [cXSDouble, '', true]],	function(oSequence1, oStart, oLength) {
+	var nPosition	= cMath.round(oStart),
+		nLength		= arguments.length > 2 ? cMath.round(oLength) : oSequence1.length - nPosition + 1;
+
+	// TODO: Handle out-of-range position and length values
+	return oSequence1.slice(nPosition - 1, nPosition - 1 + nLength);
+});
+
+// fn:unordered($sourceSeq as item()*) as item()*
+fStaticContext_defineSystemFunction("unordered",	[[cXTItem, '*']],	function(oSequence1) {
+	return oSequence1;
+});
+
+
+// 15.2 Functions That Test the Cardinality of Sequences
+// fn:zero-or-one($arg as item()*) as item()?
+fStaticContext_defineSystemFunction("zero-or-one",	[[cXTItem, '*']],	function(oSequence1) {
+	if (oSequence1.length > 1)
+		throw new cException("FORG0003");
+
+	return oSequence1;
+});
+
+// fn:one-or-more($arg as item()*) as item()+
+fStaticContext_defineSystemFunction("one-or-more",	[[cXTItem, '*']],	function(oSequence1) {
+	if (!oSequence1.length)
+		throw new cException("FORG0004");
+
+	return oSequence1;
+});
+
+// fn:exactly-one($arg as item()*) as item()
+fStaticContext_defineSystemFunction("exactly-one",	[[cXTItem, '*']],	function(oSequence1) {
+	if (oSequence1.length != 1)
+		throw new cException("FORG0005");
+
+	return oSequence1;
+});
+
+
+// 15.3 Equals, Union, Intersection and Except
+// fn:deep-equal($parameter1 as item()*, $parameter2 as item()*) as xs:boolean
+// fn:deep-equal($parameter1 as item()*, $parameter2 as item()*, $collation as string) as xs:boolean
+fStaticContext_defineSystemFunction("deep-equal",	[[cXTItem, '*'], [cXTItem, '*'], [cXSString, '', true]],	function(oSequence1, oSequence2, oCollation) {
+	throw "Function '" + "deep-equal" + "' not implemented";
+});
+
+
+// 15.4 Aggregate Functions
+// fn:count($arg as item()*) as xs:integer
+fStaticContext_defineSystemFunction("count",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSInteger(oSequence1.length);
+});
+
+// fn:avg($arg as xs:anyAtomicType*) as xs:anyAtomicType?
+fStaticContext_defineSystemFunction("avg",	[[cXSAnyAtomicType, '*']],	function(oSequence1) {
+	if (!oSequence1.length)
+		return null;
+
+	//
+	try {
+		var vValue	= oSequence1[0];
+		if (vValue instanceof cXSUntypedAtomic)
+			vValue	= cXSDouble.cast(vValue);
+		for (var nIndex = 1, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+			vRight	= oSequence1[nIndex];
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSDouble.cast(vRight);
+			vValue	= hAdditiveExpr_operators['+'](vValue, vRight, this);
+		}
+		return hMultiplicativeExpr_operators['div'](vValue, new cXSInteger(nLength), this);
+	}
+	catch (e) {
+		// XPTY0004: Arithmetic operator is not defined for provided arguments
+		throw e.code != "XPTY0004" ? e : new cException("FORG0006"
+
+		);
+	}
+});
+
+// fn:max($arg as xs:anyAtomicType*) as xs:anyAtomicType?
+// fn:max($arg as xs:anyAtomicType*, $collation as string) as xs:anyAtomicType?
+fStaticContext_defineSystemFunction("max",	[[cXSAnyAtomicType, '*'], [cXSString, '', true]],	function(oSequence1, oCollation) {
+	if (!oSequence1.length)
+		return null;
+
+	// TODO: Implement collation
+
+	//
+	try {
+		var vValue	= oSequence1[0];
+		if (vValue instanceof cXSUntypedAtomic)
+			vValue	= cXSDouble.cast(vValue);
+		for (var nIndex = 1, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+			vRight	= oSequence1[nIndex];
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSDouble.cast(vRight);
+			if (hComparisonExpr_ValueComp_operators['ge'](vRight, vValue, this).valueOf())
+				vValue	= vRight;
+		}
+		return vValue;
+	}
+	catch (e) {
+		// XPTY0004: Cannot compare {type1} with {type2}
+		throw e.code != "XPTY0004" ? e : new cException("FORG0006"
+
+		);
+	}
+});
+
+// fn:min($arg as xs:anyAtomicType*) as xs:anyAtomicType?
+// fn:min($arg as xs:anyAtomicType*, $collation as string) as xs:anyAtomicType?
+fStaticContext_defineSystemFunction("min",	[[cXSAnyAtomicType, '*'], [cXSString, '', true]],	function(oSequence1, oCollation) {
+	if (!oSequence1.length)
+		return null;
+
+	// TODO: Implement collation
+
+	//
+	try {
+		var vValue	= oSequence1[0];
+		if (vValue instanceof cXSUntypedAtomic)
+			vValue	= cXSDouble.cast(vValue);
+		for (var nIndex = 1, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+			vRight	= oSequence1[nIndex];
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSDouble.cast(vRight);
+			if (hComparisonExpr_ValueComp_operators['le'](vRight, vValue, this).valueOf())
+				vValue	= vRight;
+			}
+		return vValue;
+	}
+	catch (e) {
+		// Cannot compare {type1} with {type2}
+		throw e.code != "XPTY0004" ? e : new cException("FORG0006"
+
+		);
+	}
+});
+
+// fn:sum($arg as xs:anyAtomicType*) as xs:anyAtomicType
+// fn:sum($arg as xs:anyAtomicType*, $zero as xs:anyAtomicType?) as xs:anyAtomicType?
+fStaticContext_defineSystemFunction("sum",	[[cXSAnyAtomicType, '*'], [cXSAnyAtomicType, '?', true]],	function(oSequence1, oZero) {
+	if (!oSequence1.length) {
+		if (arguments.length > 1)
+			return oZero;
+		else
+			return new cXSDouble(0);
+
+		return null;
+	}
+
+	// TODO: Implement collation
+
+	//
+	try {
+		var vValue	= oSequence1[0];
+		if (vValue instanceof cXSUntypedAtomic)
+			vValue	= cXSDouble.cast(vValue);
+		for (var nIndex = 1, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+			vRight	= oSequence1[nIndex];
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSDouble.cast(vRight);
+			vValue	= hAdditiveExpr_operators['+'](vValue, vRight, this);
+		}
+		return vValue;
+	}
+	catch (e) {
+		// XPTY0004: Arithmetic operator is not defined for provided arguments
+		throw e.code != "XPTY0004" ? e : new cException("FORG0006"
+
+		);
+	}
+});
+
+
+// 15.5 Functions and Operators that Generate Sequences
+// fn:id($arg as xs:string*) as element()*
+// fn:id($arg as xs:string*, $node as node()) as element()*
+fStaticContext_defineSystemFunction("id",	[[cXSString, '*'], [cXTNode, '', true]],	function(oSequence1, oNode) {
+	if (arguments.length < 2) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+
+	// Get root node and check if it is Document
+	var oDocument	= hStaticContext_functions["root"].call(this, oNode);
+	if (this.DOMAdapter.getProperty(oDocument, "nodeType") != 9)
+		throw new cException("FODC0001");
+
+	// Search for elements
+	var oSequence	= [];
+	for (var nIndex = 0; nIndex < oSequence1.length; nIndex++)
+		for (var nRightIndex = 0, aValue = fString_trim(oSequence1[nIndex]).split(/\s+/), nRightLength = aValue.length; nRightIndex < nRightLength; nRightIndex++)
+			if ((oNode = this.DOMAdapter.getElementById(oDocument, aValue[nRightIndex])) && fArray_indexOf(oSequence, oNode) ==-1)
+				oSequence.push(oNode);
+	//
+	return fFunction_sequence_order(oSequence, this);
+});
+
+// fn:idref($arg as xs:string*) as node()*
+// fn:idref($arg as xs:string*, $node as node()) as node()*
+fStaticContext_defineSystemFunction("idref",	[[cXSString, '*'], [cXTNode, '', true]],	function(oSequence1, oNode) {
+	throw "Function '" + "idref" + "' not implemented";
+});
+
+// fn:doc($uri as xs:string?) as document-node()?
+fStaticContext_defineSystemFunction("doc",			[[cXSString, '?', true]],	function(oUri) {
+	throw "Function '" + "doc" + "' not implemented";
+});
+
+// fn:doc-available($uri as xs:string?) as xs:boolean
+fStaticContext_defineSystemFunction("doc-available",	[[cXSString, '?', true]],	function(oUri) {
+	throw "Function '" + "doc-available" + "' not implemented";
+});
+
+// fn:collection() as node()*
+// fn:collection($arg as xs:string?) as node()*
+fStaticContext_defineSystemFunction("collection",	[[cXSString, '?', true]],	function(oUri) {
+	throw "Function '" + "collection" + "' not implemented";
+});
+
+// fn:element-with-id($arg as xs:string*) as element()*
+// fn:element-with-id($arg as xs:string*, $node as node()) as element()*
+fStaticContext_defineSystemFunction("element-with-id",	[[cXSString, '*'], [cXTNode, '', true]],	function(oSequence1, oNode) {
+	throw "Function '" + "element-with-id" + "' not implemented";
+});
+
+// EBV calculation
+function fFunction_sequence_toEBV(oSequence1, oContext) {
+	if (!oSequence1.length)
+		return false;
+
+	var oItem	= oSequence1[0];
+	if (oContext.DOMAdapter.isNode(oItem))
+		return true;
+
+	if (oSequence1.length == 1) {
+		if (oItem instanceof cXSBoolean)
+			return oItem.value.valueOf();
+		if (oItem instanceof cXSString)
+			return !!oItem.valueOf().length;
+		if (fXSAnyAtomicType_isNumeric(oItem))
+			return !(fIsNaN(oItem.valueOf()) || oItem.valueOf() == 0);
+
+		throw new cException("FORG0006"
+
+		);
+	}
+
+	throw new cException("FORG0006"
+
+	);
+};
+
+function fFunction_sequence_atomize(oSequence1, oContext) {
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, oItem, vItem; nIndex < nLength; nIndex++) {
+		oItem	= oSequence1[nIndex];
+		vItem	= null;
+		// Untyped
+		if (oItem == null)
+			vItem	= null;
+		// Node type
+		else
+		if (oContext.DOMAdapter.isNode(oItem)) {
+			var fGetProperty	= oContext.DOMAdapter.getProperty;
+			switch (fGetProperty(oItem, "nodeType")) {
+				case 1:	// ELEMENT_NODE
+					vItem	= new cXSUntypedAtomic(fGetProperty(oItem, "textContent"));
+					break;
+				case 2:	// ATTRIBUTE_NODE
+					vItem	= new cXSUntypedAtomic(fGetProperty(oItem, "value"));
+					break;
+				case 3:	// TEXT_NODE
+				case 4:	// CDATA_SECTION_NODE
+				case 8:	// COMMENT_NODE
+					vItem	= new cXSUntypedAtomic(fGetProperty(oItem, "data"));
+					break;
+				case 7:	// PROCESSING_INSTRUCTION_NODE
+					vItem	= new cXSUntypedAtomic(fGetProperty(oItem, "data"));
+					break;
+				case 9:	// DOCUMENT_NODE
+					var oNode	= fGetProperty(oItem, "documentElement");
+					vItem	= new cXSUntypedAtomic(oNode ? fGetProperty(oNode, "textContent") : '');
+					break;
+			}
+		}
+		// Base types
+		else
+		if (oItem instanceof cXSAnyAtomicType)
+			vItem	= oItem;
+
+		//
+		if (vItem != null)
+			oSequence.push(vItem);
+	}
+
+	return oSequence;
+};
+
+// Orders items in sequence in document order
+function fFunction_sequence_order(oSequence1, oContext) {
+	return oSequence1.sort(function(oNode, oNode2) {
+		var nPosition	= oContext.DOMAdapter.compareDocumentPosition(oNode, oNode2);
+		return nPosition & 2 ? 1 : nPosition & 4 ?-1 : 0;
+	});
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	7.2 Functions to Assemble and Disassemble Strings
+		codepoints-to-string
+		string-to-codepoints
+
+	7.3 Equality and Comparison of Strings
+		compare
+		codepoint-equal
+
+	7.4 Functions on String Values
+		concat
+		string-join
+		substring
+		string-length
+		normalize-space
+		normalize-unicode
+		upper-case
+		lower-case
+		translate
+		encode-for-uri
+		iri-to-uri
+		escape-html-uri
+
+	7.5 Functions Based on Substring Matching
+		contains
+		starts-with
+		ends-with
+		substring-before
+		substring-after
+
+	7.6 String Functions that Use Pattern Matching
+		matches
+		replace
+		tokenize
+*/
+
+// 7.2 Functions to Assemble and Disassemble Strings
+// fn:codepoints-to-string($arg as xs:integer*) as xs:string
+fStaticContext_defineSystemFunction("codepoints-to-string",	[[cXSInteger, '*']],	function(oSequence1) {
+	var aValue	= [];
+	for (var nIndex = 0, nLength = oSequence1.length; nIndex < nLength; nIndex++)
+		aValue.push(cString.fromCharCode(oSequence1[nIndex]));
+
+	return new cXSString(aValue.join(''));
+});
+
+// fn:string-to-codepoints($arg as xs:string?) as xs:integer*
+fStaticContext_defineSystemFunction("string-to-codepoints",	[[cXSString, '?']],	function(oValue) {
+	if (oValue == null)
+		return null;
+
+	var sValue	= oValue.valueOf();
+	if (sValue == '')
+		return [];
+
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = sValue.length; nIndex < nLength; nIndex++)
+		oSequence.push(new cXSInteger(sValue.charCodeAt(nIndex)));
+
+	return oSequence;
+});
+
+// 7.3 Equality and Comparison of Strings
+// fn:compare($comparand1 as xs:string?, $comparand2 as xs:string?) as xs:integer?
+// fn:compare($comparand1 as xs:string?, $comparand2 as xs:string?, $collation as xs:string) as xs:integer?
+fStaticContext_defineSystemFunction("compare",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue1, oValue2, oCollation) {
+	if (oValue1 == null || oValue2 == null)
+		return null;
+
+	var sCollation	= this.staticContext.defaultCollationName,
+		vCollation;
+	if (arguments.length > 2)
+		sCollation	= oCollation.valueOf();
+
+	vCollation	= sCollation == sNS_XPF + "/collation/codepoint" ? oCodepointStringCollator : this.staticContext.getCollation(sCollation);
+	if (!vCollation)
+		throw new cException("FOCH0002"
+
+		);
+
+	return new cXSInteger(vCollation.compare(oValue1.valueOf(), oValue2.valueOf()));
+});
+
+// fn:codepoint-equal($comparand1 as xs:string?, $comparand2  as xs:string?) as xs:boolean?
+fStaticContext_defineSystemFunction("codepoint-equal",	[[cXSString, '?'], [cXSString, '?']],	function(oValue1, oValue2) {
+	if (oValue1 == null || oValue2 == null)
+		return null;
+
+	// TODO: Check if JS uses 'Unicode code point collation' here
+
+	return new cXSBoolean(oValue1.valueOf() == oValue2.valueOf());
+});
+
+
+// 7.4 Functions on String Values
+// fn:concat($arg1 as xs:anyAtomicType?, $arg2 as xs:anyAtomicType?, ...) as xs:string
+fStaticContext_defineSystemFunction("concat",	null,	function() {
+	// check arguments length
+	if (arguments.length < 2)
+		throw new cException("XPST0017"
+
+		);
+
+	var aValue	= [];
+	for (var nIndex = 0, nLength = arguments.length, oSequence; nIndex < nLength; nIndex++) {
+		oSequence	= arguments[nIndex];
+		// Assert cardinality
+		fFunctionCall_assertSequenceCardinality(this, oSequence, '?'
+
+		);
+		//
+		if (oSequence.length)
+			aValue[aValue.length]	= cXSString.cast(fFunction_sequence_atomize(oSequence, this)[0]).valueOf();
+	}
+
+	return new cXSString(aValue.join(''));
+});
+
+// fn:string-join($arg1 as xs:string*, $arg2 as xs:string) as xs:string
+fStaticContext_defineSystemFunction("string-join",	[[cXSString, '*'], [cXSString]],	function(oSequence1, oValue) {
+	return new cXSString(oSequence1.join(oValue));
+});
+
+// fn:substring($sourceString as xs:string?, $startingLoc as xs:double) as xs:string
+// fn:substring($sourceString as xs:string?, $startingLoc as xs:double, $length as xs:double) as xs:string
+fStaticContext_defineSystemFunction("substring",	[[cXSString, '?'], [cXSDouble], [cXSDouble, '', true]],	function(oValue, oStart, oLength) {
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		nStart	= cMath.round(oStart) - 1,
+		nEnd	= arguments.length > 2 ? nStart + cMath.round(oLength) : sValue.length;
+
+	// TODO: start can be negative
+	return new cXSString(nEnd > nStart ? sValue.substring(nStart, nEnd) : '');
+});
+
+// fn:string-length() as xs:integer
+// fn:string-length($arg as xs:string?) as xs:integer
+fStaticContext_defineSystemFunction("string-length",	[[cXSString, '?', true]],	function(oValue) {
+	if (!arguments.length) {
+		if (!this.item)
+			throw new cException("XPDY0002");
+		oValue	= cXSString.cast(fFunction_sequence_atomize([this.item], this)[0]);
+	}
+	return new cXSInteger(oValue == null ? 0 : oValue.valueOf().length);
+});
+
+// fn:normalize-space() as xs:string
+// fn:normalize-space($arg as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("normalize-space",	[[cXSString, '?', true]],	function(oValue) {
+	if (!arguments.length) {
+		if (!this.item)
+			throw new cException("XPDY0002");
+		oValue	= cXSString.cast(fFunction_sequence_atomize([this.item], this)[0]);
+	}
+	return new cXSString(oValue == null ? '' : fString_trim(oValue).replace(/\s\s+/g, ' '));
+});
+
+// fn:normalize-unicode($arg as xs:string?) as xs:string
+// fn:normalize-unicode($arg as xs:string?, $normalizationForm as xs:string) as xs:string
+fStaticContext_defineSystemFunction("normalize-unicode",	[[cXSString, '?'], [cXSString, '', true]],	function(oValue, oNormalization) {
+	throw "Function '" + "normalize-unicode" + "' not implemented";
+});
+
+// fn:upper-case($arg as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("upper-case",	[[cXSString, '?']],	function(oValue) {
+	return new cXSString(oValue == null ? '' : oValue.valueOf().toUpperCase());
+});
+
+// fn:lower-case($arg as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("lower-case",	[[cXSString, '?']],	function(oValue) {
+	return new cXSString(oValue == null ? '' : oValue.valueOf().toLowerCase());
+});
+
+// fn:translate($arg as xs:string?, $mapString as xs:string, $transString as xs:string) as xs:string
+fStaticContext_defineSystemFunction("translate",	[[cXSString, '?'], [cXSString], [cXSString]],	function(oValue, oMap, oTranslate) {
+	if (oValue == null)
+		return new cXSString('');
+
+	var aValue	= oValue.valueOf().split(''),
+		aMap	= oMap.valueOf().split(''),
+		aTranslate	= oTranslate.valueOf().split(''),
+		nTranslateLength	= aTranslate.length,
+		aReturn	= [];
+	for (var nIndex = 0, nLength = aValue.length, nPosition; nIndex < nLength; nIndex++)
+		if ((nPosition = aMap.indexOf(aValue[nIndex])) ==-1)
+			aReturn[aReturn.length]	= aValue[nIndex];
+		else
+		if (nPosition < nTranslateLength)
+			aReturn[aReturn.length]	= aTranslate[nPosition];
+
+	return new cXSString(aReturn.join(''));
+});
+
+// fn:encode-for-uri($uri-part as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("encode-for-uri",	[[cXSString, '?']],	function(oValue) {
+	return new cXSString(oValue == null ? '' : window.encodeURIComponent(oValue));
+});
+
+// fn:iri-to-uri($iri as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("iri-to-uri",		[[cXSString, '?']],	function(oValue) {
+	return new cXSString(oValue == null ? '' : window.encodeURI(window.decodeURI(oValue)));
+});
+
+// fn:escape-html-uri($uri as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("escape-html-uri",	[[cXSString, '?']],	function(oValue) {
+	if (oValue == null || oValue.valueOf() == '')
+		return new cXSString('');
+	// Encode
+	var aValue	= oValue.valueOf().split('');
+	for (var nIndex = 0, nLength = aValue.length, nCode; nIndex < nLength; nIndex++)
+		if ((nCode = aValue[nIndex].charCodeAt(0)) < 32 || nCode > 126)
+			aValue[nIndex]	= window.encodeURIComponent(aValue[nIndex]);
+	return new cXSString(aValue.join(''));
+});
+
+
+// 7.5 Functions Based on Substring Matching
+// fn:contains($arg1 as xs:string?, $arg2 as xs:string?) as xs:boolean
+// fn:contains($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:boolean
+fStaticContext_defineSystemFunction("contains",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "contains" + "' is not implemented";
+	return new cXSBoolean((oValue == null ? '' : oValue.valueOf()).indexOf(oSearch == null ? '' : oSearch.valueOf()) >= 0);
+});
+
+// fn:starts-with($arg1 as xs:string?, $arg2 as xs:string?) as xs:boolean
+// fn:starts-with($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:boolean
+fStaticContext_defineSystemFunction("starts-with",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "starts-with" + "' is not implemented";
+	return new cXSBoolean((oValue == null ? '' : oValue.valueOf()).indexOf(oSearch == null ? '' : oSearch.valueOf()) == 0);
+});
+
+// fn:ends-with($arg1 as xs:string?, $arg2 as xs:string?) as xs:boolean
+// fn:ends-with($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:boolean
+fStaticContext_defineSystemFunction("ends-with",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "ends-with" + "' is not implemented";
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		sSearch	= oSearch == null ? '' : oSearch.valueOf();
+
+	return new cXSBoolean(sValue.indexOf(sSearch) == sValue.length - sSearch.length);
+});
+
+// fn:substring-before($arg1 as xs:string?, $arg2 as xs:string?) as xs:string
+// fn:substring-before($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:string
+fStaticContext_defineSystemFunction("substring-before",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "substring-before" + "' is not implemented";
+
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		sSearch	= oSearch == null ? '' : oSearch.valueOf(),
+		nPosition;
+
+	return new cXSString((nPosition = sValue.indexOf(sSearch)) >= 0 ? sValue.substring(0, nPosition) : '');
+});
+
+// fn:substring-after($arg1 as xs:string?, $arg2 as xs:string?) as xs:string
+// fn:substring-after($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:string
+fStaticContext_defineSystemFunction("substring-after",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "substring-after" + "' is not implemented";
+
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		sSearch	= oSearch == null ? '' : oSearch.valueOf(),
+		nPosition;
+
+	return new cXSString((nPosition = sValue.indexOf(sSearch)) >= 0 ? sValue.substring(nPosition + sSearch.length) : '');
+});
+
+
+// 7.6 String Functions that Use Pattern Matching
+function fFunction_string_createRegExp(sValue, sFlags) {
+	var d1	= '\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF',
+		d2	= '\u0370-\u037D\u037F-\u1FFF\u200C-\u200D',
+		d3	= '\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD',
+		c	= 'A-Z_a-z\\-.0-9\u00B7' + d1 + '\u0300-\u036F' + d2 + '\u203F-\u2040' + d3,
+		i	= 'A-Z_a-z' + d1 + d2 + d3;
+
+	sValue	= sValue
+				.replace(/\[\\i-\[:\]\]/g, '[' + i + ']')
+				.replace(/\[\\c-\[:\]\]/g, '[' + c + ']')
+				.replace(/\\i/g, '[:' + i + ']')
+				.replace(/\\I/g, '[^:' + i + ']')
+				.replace(/\\c/g, '[:' + c + ']')
+				.replace(/\\C/g, '[^:' + c + ']');
+
+	// Check if all flags are legal
+	if (sFlags && !sFlags.match(/^[smix]+$/))
+		throw new cException("FORX0001");	// Invalid character '{%0}' in regular expression flags
+
+	var bFlagS	= sFlags.indexOf('s') >= 0,
+		bFlagX	= sFlags.indexOf('x') >= 0;
+	if (bFlagS || bFlagX) {
+		// Strip 's' and 'x' from flags
+		sFlags	= sFlags.replace(/[sx]/g, '');
+		var aValue	= [],
+			rValue	= /\s/;
+		for (var nIndex = 0, nLength = sValue.length, bValue = false, sCharCurr, sCharPrev = ''; nIndex < nLength; nIndex++) {
+			sCharCurr	= sValue.charAt(nIndex);
+			if (sCharPrev != '\\') {
+				if (sCharCurr == '[')
+					bValue	= true;
+				else
+				if (sCharCurr == ']')
+					bValue	= false;
+			}
+			// Replace '\s' for flag 'x' if not in []
+			if (bValue || !(bFlagX && rValue.test(sCharCurr))) {
+				// Replace '.' for flag 's' if not in []
+				if (!bValue && (bFlagS && sCharCurr == '.' && sCharPrev != '\\'))
+					aValue[aValue.length]	= '(?:.|\\s)';
+				else
+					aValue[aValue.length]	= sCharCurr;
+			}
+			sCharPrev	= sCharCurr;
+		}
+		sValue	= aValue.join('');
+	}
+
+	return new cRegExp(sValue, sFlags + 'g');
+};
+
+// fn:matches($input as xs:string?, $pattern as xs:string) as xs:boolean
+// fn:matches($input as xs:string?, $pattern as xs:string, $flags as xs:string) as xs:boolean
+fStaticContext_defineSystemFunction("matches",	[[cXSString, '?'], [cXSString], [cXSString, '', true]],	function(oValue, oPattern, oFlags) {
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		rRegExp	= fFunction_string_createRegExp(oPattern.valueOf(), arguments.length > 2 ? oFlags.valueOf() : '');
+
+	return new cXSBoolean(rRegExp.test(sValue));
+});
+
+// fn:replace($input as xs:string?, $pattern as xs:string, $replacement as xs:string) as xs:string
+// fn:replace($input as xs:string?, $pattern as xs:string, $replacement as xs:string, $flags as xs:string) as xs:string
+fStaticContext_defineSystemFunction("replace",	[[cXSString, '?'], [cXSString],  [cXSString], [cXSString, '', true]],	function(oValue, oPattern, oReplacement, oFlags) {
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		rRegExp	= fFunction_string_createRegExp(oPattern.valueOf(), arguments.length > 3 ? oFlags.valueOf() : '');
+
+	return new cXSBoolean(sValue.replace(rRegExp, oReplacement.valueOf()));
+});
+
+// fn:tokenize($input as xs:string?, $pattern as xs:string) as xs:string*
+// fn:tokenize($input as xs:string?, $pattern as xs:string, $flags as xs:string) as xs:string*
+fStaticContext_defineSystemFunction("tokenize",	[[cXSString, '?'], [cXSString], [cXSString, '', true]],	function(oValue, oPattern, oFlags) {
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		rRegExp	= fFunction_string_createRegExp(oPattern.valueOf(), arguments.length > 2 ? oFlags.valueOf() : '');
+
+	var oSequence	= [];
+	for (var nIndex = 0, aValue = sValue.split(rRegExp), nLength = aValue.length; nIndex < nLength; nIndex++)
+		oSequence.push(new cXSString(aValue[nIndex]));
+
+	return oSequence;
+});
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	4 The Trace Function
+		trace
+*/
+
+// fn:trace($value as item()*, $label as xs:string) as item()*
+fStaticContext_defineSystemFunction("trace",		[[cXTItem, '*'], [cXSString]],	function(oSequence1, oLabel) {
+	var oConsole	= window.console;
+	if (oConsole && oConsole.log)
+		oConsole.log(oLabel.valueOf(), oSequence1);
+	return oSequence1;
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+var oCodepointStringCollator	= new cStringCollator;
+
+oCodepointStringCollator.equals	= function(sValue1, sValue2) {
+	return sValue1 == sValue2;
+};
+
+oCodepointStringCollator.compare	= function(sValue1, sValue2) {
+	return sValue1 == sValue2 ? 0 : sValue1 > sValue2 ? 1 :-1;
+};
+function cLXDOMAdapter() {
+
+};
+
+cLXDOMAdapter.prototype	= new cDOMAdapter;
+
+var oLXDOMAdapter_staticContext	= new cStaticContext;
+
+cLXDOMAdapter.prototype.getProperty	= function(oNode, sName) {
+		if (sName in oNode)
+		return oNode[sName];
+
+		if (sName == "baseURI") {
+		var sBaseURI	= '',
+			fResolveUri	= oLXDOMAdapter_staticContext.getFunction('{' + "http://www.w3.org/2005/xpath-functions" + '}' + "resolve-uri"),
+			cXSString	= oLXDOMAdapter_staticContext.getDataType('{' + "http://www.w3.org/2001/XMLSchema" + '}' + "string");
+
+		for (var oParent = oNode, sUri; oParent; oParent = oParent.parentNode)
+			if (oParent.nodeType == 1  && (sUri = oParent.getAttribute("xml:base")))
+				sBaseURI	= fResolveUri(new cXSString(sUri), new cXSString(sBaseURI)).toString();
+				return sBaseURI;
+	}
+	else
+	if (sName == "textContent") {
+		var aText = [];
+		(function(oNode) {
+			for (var nIndex = 0, oChild; oChild = oNode.childNodes[nIndex]; nIndex++)
+				if (oChild.nodeType == 3  || oChild.nodeType == 4 )
+					aText.push(oChild.data);
+				else
+				if (oChild.nodeType == 1  && oChild.firstChild)
+					arguments.callee(oChild);
+		})(oNode);
+		return aText.join('');
+	}
+};
+
+cLXDOMAdapter.prototype.compareDocumentPosition	= function(oNode, oChild) {
+		if ("compareDocumentPosition" in oNode)
+		return oNode.compareDocumentPosition(oChild);
+
+		if (oChild == oNode)
+		return 0;
+
+		var oAttr1	= null,
+		oAttr2	= null,
+		aAttributes,
+		oAttr, oElement, nIndex, nLength;
+	if (oNode.nodeType == 2 ) {
+		oAttr1	= oNode;
+		oNode	= this.getProperty(oAttr1, "ownerElement");
+	}
+	if (oChild.nodeType == 2 ) {
+		oAttr2	= oChild;
+		oChild	= this.getProperty(oAttr2, "ownerElement");
+	}
+
+		if (oAttr1 && oAttr2 && oNode && oNode == oChild) {
+		for (nIndex = 0, aAttributes = this.getProperty(oNode, "attributes"), nLength = aAttributes.length; nIndex < nLength; nIndex++) {
+			oAttr	= aAttributes[nIndex];
+			if (oAttr == oAttr1)
+				return 32  | 4 ;
+			if (oAttr == oAttr2)
+				return 32  | 2 ;
+		}
+	}
+
+		var aChain1	= [], nLength1, oNode1,
+		aChain2	= [], nLength2, oNode2;
+		if (oAttr1)
+		aChain1.push(oAttr1);
+	for (oElement = oNode; oElement; oElement = oElement.parentNode)
+		aChain1.push(oElement);
+	if (oAttr2)
+		aChain2.push(oAttr2);
+	for (oElement = oChild; oElement; oElement = oElement.parentNode)
+		aChain2.push(oElement);
+		if (((oNode.ownerDocument || oNode) != (oChild.ownerDocument || oChild)) || (aChain1[aChain1.length - 1] != aChain2[aChain2.length - 1]))
+		return 32  | 1 ;
+		for (nIndex = cMath.min(nLength1 = aChain1.length, nLength2 = aChain2.length); nIndex; --nIndex)
+		if ((oNode1 = aChain1[--nLength1]) != (oNode2 = aChain2[--nLength2])) {
+						if (oNode1.nodeType == 2 )
+				return 4 ;
+			if (oNode2.nodeType == 2 )
+				return 2 ;
+						if (!oNode2.nextSibling)
+				return 4 ;
+			if (!oNode1.nextSibling)
+				return 2 ;
+			for (oElement = oNode2.previousSibling; oElement; oElement = oElement.previousSibling)
+				if (oElement == oNode1)
+					return 4 ;
+			return 2 ;
+		}
+		return nLength1 < nLength2 ? 4  | 16  : 2  | 8 ;
+};
+
+cLXDOMAdapter.prototype.lookupNamespaceURI	= function(oNode, sPrefix) {
+		if ("lookupNamespaceURI" in oNode)
+		return oNode.lookupNamespaceURI(sPrefix);
+
+		for (; oNode && oNode.nodeType != 9  ; oNode = oNode.parentNode)
+		if (sPrefix == this.getProperty(oChild, "prefix"))
+			return this.getProperty(oNode, "namespaceURI");
+		else
+		if (oNode.nodeType == 1)				for (var oAttributes = this.getProperty(oNode, "attributes"), nIndex = 0, nLength = oAttributes.length, sName = "xmlns" + ':' + sPrefix; nIndex < nLength; nIndex++)
+				if (this.getProperty(oAttributes[nIndex], "nodeName") == sName)
+					return this.getProperty(oAttributes[nIndex], "value");
+	return null;
+};
+
+cLXDOMAdapter.prototype.getElementsByTagNameNS	= function(oNode, sNameSpaceURI, sLocalName) {
+		if ("getElementsByTagNameNS" in oNode)
+		return oNode.getElementsByTagNameNS(sNameSpaceURI, sLocalName);
+
+		var aElements	= [],
+		bNameSpaceURI	= '*' == sNameSpaceURI,
+		bLocalName		= '*' == sLocalName;
+	(function(oNode) {
+		for (var nIndex = 0, oChild; oChild = oNode.childNodes[nIndex]; nIndex++)
+			if (oChild.nodeType == 1) {					if ((bLocalName || sLocalName == this.getProperty(oChild, "localName")) && (bNameSpaceURI || sNameSpaceURI == this.getProperty(oChild, "namespaceURI")))
+					aElements[aElements.length]	= oChild;
+				if (oChild.firstChild)
+					arguments.callee(oChild);
+			}
+	})(oNode);
+	return aElements;
+};
+
+var oMSHTMLDOMAdapter	= new cLXDOMAdapter;
+
+oMSHTMLDOMAdapter.getProperty	= function(oNode, sName) {
+	if (sName == "localName") {
+		if (oNode.nodeType == 1)
+			return oNode.nodeName.toLowerCase();
+	}
+	if (sName == "prefix")
+		return null;
+	if (sName == "namespaceURI")
+		return oNode.nodeType == 1 ? "http://www.w3.org/1999/xhtml" : null;
+	if (sName == "textContent")
+		return oNode.innerText;
+	if (sName == "attributes" && oNode.nodeType == 1) {
+		var aAttributes	= [];
+		for (var nIndex = 0, oAttributes = oNode.attributes, nLength = oAttributes.length, oNode2, oAttribute; nIndex < nLength; nIndex++) {
+			oNode2	= oAttributes[nIndex];
+			if (oNode2.specified) {
+				oAttribute	= new cAttr;
+				oAttribute.ownerElement	= oNode;
+				oAttribute.ownerDocument= oNode.ownerDocument;
+				oAttribute.specified	= true;
+				oAttribute.value		=
+				oAttribute.nodeValue	= oNode2.nodeValue;
+				oAttribute.name			=
+				oAttribute.nodeName		=
+								oAttribute.localName	= oNode2.nodeName.toLowerCase();
+								aAttributes[aAttributes.length]	= oAttribute;
+			}
+		}
+		return aAttributes;
+	}
+		return cLXDOMAdapter.prototype.getProperty.call(this, oNode, sName);
+};
+
+
+var oMSXMLDOMAdapter	= new cLXDOMAdapter;
+
+oMSXMLDOMAdapter.getProperty	= function(oNode, sName) {
+	if (sName == "localName") {
+		if (oNode.nodeType == 7)
+			return null;
+		if (oNode.nodeType == 1)
+			return oNode.baseName;
+	}
+	if (sName == "prefix" || sName == "namespaceURI")
+		return oNode[sName] || null;
+	if (sName == "textContent")
+		return oNode.text;
+	if (sName == "attributes" && oNode.nodeType == 1) {
+		var aAttributes	= [];
+		for (var nIndex = 0, oAttributes = oNode.attributes, nLength = oAttributes.length, oNode2, oAttribute; nIndex < nLength; nIndex++) {
+			oNode2	= oAttributes[nIndex];
+			if (oNode2.specified) {
+				oAttribute	= new cAttr;
+				oAttribute.nodeType		= 2;
+				oAttribute.ownerElement	= oNode;
+				oAttribute.ownerDocument= oNode.ownerDocument;
+				oAttribute.specified	= true;
+				oAttribute.value		=
+				oAttribute.nodeValue	= oNode2.nodeValue;
+				oAttribute.name			=
+				oAttribute.nodeName		= oNode2.nodeName;
+								oAttribute.localName	= oNode2.baseName;
+				oAttribute.prefix		= oNode2.prefix || null;
+				oAttribute.namespaceURI	= oNode2.namespaceURI || null;
+								aAttributes[aAttributes.length]	= oAttribute;
+			}
+		}
+		return aAttributes;
+	}
+		return cLXDOMAdapter.prototype.getProperty.call(this, oNode, sName);
+};
+
+oMSXMLDOMAdapter.getElementById	= function(oDocument, sId) {
+	return oDocument.nodeFromID(sId);
+};
+
+function cEvaluator() {
+
+};
+
+cEvaluator.prototype.defaultOL2DOMAdapter		= new cLXDOMAdapter;
+cEvaluator.prototype.defaultOL2HTMLDOMAdapter	= new cLXDOMAdapter;
+
+cEvaluator.prototype.defaultHTMLStaticContext	= new cStaticContext;
+cEvaluator.prototype.defaultHTMLStaticContext.baseURI	= window.document.location.href;
+cEvaluator.prototype.defaultHTMLStaticContext.defaultFunctionNamespace	= "http://www.w3.org/2005/xpath-functions";
+cEvaluator.prototype.defaultHTMLStaticContext.defaultElementNamespace	= "http://www.w3.org/1999/xhtml";
+
+cEvaluator.prototype.defaultXMLStaticContext	= new cStaticContext;
+cEvaluator.prototype.defaultXMLStaticContext.defaultFunctionNamespace	= "http://www.w3.org/2005/xpath-functions";
+
+cEvaluator.prototype.bOldMS		= !!window.document.namespaces && !window.document.createElementNS;
+cEvaluator.prototype.bOldW3		= !cEvaluator.prototype.bOldMS && window.document.documentElement.namespaceURI != "http://www.w3.org/1999/xhtml";
+
+cEvaluator.prototype.defaultDOMAdapter		= new cDOMAdapter;
+
+cEvaluator.prototype.compile	= function(sExpression, oStaticContext) {
+    return new cExpression(sExpression, oStaticContext);
+};
+
+cEvaluator.prototype.evaluate	= function(oQuery, sExpression, fNSResolver) {
+	if (! (oQuery instanceof window.jQuery))
+        oQuery = new window.jQuery(oQuery)
+
+    if (typeof sExpression == "undefined" || sExpression === null)
+        sExpression	= '';
+
+    var oNode	= oQuery[0];
+    if (typeof oNode == "undefined")
+        oNode	= null;
+
+    var oStaticContext	= oNode && (oNode.nodeType == 9 ? oNode : oNode.ownerDocument).createElement("div").tagName == "DIV" ? this.defaultHTMLStaticContext : this.defaultXMLStaticContext;
+
+    oStaticContext.namespaceResolver	= fNSResolver;
+
+    var oExpression	= new cExpression(cString(sExpression), oStaticContext);
+
+    oStaticContext.namespaceResolver	= null;
+
+    var aSequence,
+        oSequence	= new window.jQuery,
+        oAdapter	= this.defaultOL2DOMAdapter;
+
+    if (this.bOldMS)
+        oAdapter	= oStaticContext == this.defaultHTMLStaticContext ? oMSHTMLDOMAdapter : oMSXMLDOMAdapter;
+    else
+    if (this.bOldW3 && oStaticContext == this.defaultHTMLStaticContext)
+        oAdapter	= this.defaultOL2HTMLDOMAdapter;
+
+    aSequence	= oExpression.evaluate(new cDynamicContext(oStaticContext, oNode, null, oAdapter));
+    for (var nIndex = 0, nLength = aSequence.length, oItem; nIndex < nLength; nIndex++)
+        oSequence.push(oAdapter.isNode(oItem = aSequence[nIndex]) ? oItem : cStaticContext.xs2js(oItem));
+
+    return oSequence;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+var oXPathEvaluator	= new cEvaluator,
+    oXPathClasses	= oXPathEvaluator.classes = {};
+
+//
+oXPathClasses.Exception		= cException;
+oXPathClasses.Expression	= cExpression;
+oXPathClasses.DOMAdapter	= cDOMAdapter;
+oXPathClasses.StaticContext	= cStaticContext;
+oXPathClasses.DynamicContext= cDynamicContext;
+oXPathClasses.StringCollator= cStringCollator;
+
+// Publish object
+window.xpath	= oXPathEvaluator;
+
+})()

+ 2 - 2
src/js/operations/Base.js

@@ -22,7 +22,7 @@ var Base = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to: function(input, args) {
+    runTo: function(input, args) {
         if (!input) {
             throw ("Error: Input must be a number");
         }
@@ -41,7 +41,7 @@ var Base = {
      * @param {Object[]} args
      * @returns {number}
      */
-    run_from: function(input, args) {
+    runFrom: function(input, args) {
         var radix = args[0] || Base.DEFAULT_RADIX;
         if (radix < 2 || radix > 36) {
             throw "Error: Radix argument must be between 2 and 36";

+ 58 - 58
src/js/operations/Base64.js

@@ -36,13 +36,13 @@ var Base64 = {
     /**
      * To Base64 operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to: function(input, args) {
+    runTo: function(input, args) {
         var alphabet = args[0] || Base64.ALPHABET;
-        return Utils.to_base64(input, alphabet);
+        return Utils.toBase64(input, alphabet);
     },
 
 
@@ -57,13 +57,13 @@ var Base64 = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from: function(input, args) {
+    runFrom: function(input, args) {
         var alphabet = args[0] || Base64.ALPHABET,
-            remove_non_alph_chars = args[1];
+            removeNonAlphChars = args[1];
 
-        return Utils.from_base64(input, alphabet, "byte_array", remove_non_alph_chars);
+        return Utils.fromBase64(input, alphabet, "byteArray", removeNonAlphChars);
     },
 
 
@@ -76,15 +76,15 @@ var Base64 = {
     /**
      * To Base32 operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_32: function(input, args) {
+    runTo32: function(input, args) {
         if (!input) return "";
 
         var alphabet = args[0] ?
-                Utils.expand_alph_range(args[0]).join("") : "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
+                Utils.expandAlphRange(args[0]).join("") : "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
             output = "",
             chr1, chr2, chr3, chr4, chr5,
             enc1, enc2, enc3, enc4, enc5, enc6, enc7, enc8,
@@ -130,21 +130,21 @@ var Base64 = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from_32: function(input, args) {
+    runFrom32: function(input, args) {
         if (!input) return [];
 
         var alphabet = args[0] ?
-                Utils.expand_alph_range(args[0]).join("") : "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
-            remove_non_alph_chars = args[0];
+                Utils.expandAlphRange(args[0]).join("") : "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
+            removeNonAlphChars = args[0];
 
         var output = [],
             chr1, chr2, chr3, chr4, chr5,
             enc1, enc2, enc3, enc4, enc5, enc6, enc7, enc8,
             i = 0;
 
-        if (remove_non_alph_chars) {
+        if (removeNonAlphChars) {
             var re = new RegExp("[^" + alphabet.replace(/[\]\\\-^]/g, "\\$&") + "]", "g");
             input = input.replace(re, "");
         }
@@ -190,21 +190,21 @@ var Base64 = {
     /**
      * Show Base64 offsets operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {html}
      */
-    run_offsets: function(input, args) {
+    runOffsets: function(input, args) {
         var alphabet = args[0] || Base64.ALPHABET,
-            show_variable = args[1],
-            offset0 = Utils.to_base64(input, alphabet),
-            offset1 = Utils.to_base64([0].concat(input), alphabet),
-            offset2 = Utils.to_base64([0, 0].concat(input), alphabet),
+            showVariable = args[1],
+            offset0 = Utils.toBase64(input, alphabet),
+            offset1 = Utils.toBase64([0].concat(input), alphabet),
+            offset2 = Utils.toBase64([0, 0].concat(input), alphabet),
             len0 = offset0.indexOf("="),
             len1 = offset1.indexOf("="),
             len2 = offset2.indexOf("="),
             script = "<script type='application/javascript'>$('[data-toggle=\"tooltip\"]').tooltip()</script>",
-            static_section = "",
+            staticSection = "",
             padding = "";
 
         if (input.length < 1) {
@@ -213,28 +213,28 @@ var Base64 = {
 
         // Highlight offset 0
         if (len0 % 4 === 2) {
-            static_section = offset0.slice(0, -3);
+            staticSection = offset0.slice(0, -3);
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64(static_section, alphabet).slice(0, -2)) + "'>" +
-                static_section + "</span>" +
+                Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" +
+                staticSection + "</span>" +
                 "<span class='hlgreen'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
                 "<span class='hlred'>" + offset0.substr(offset0.length - 2) + "</span>";
         } else if (len0 % 4 === 3) {
-            static_section = offset0.slice(0, -2);
+            staticSection = offset0.slice(0, -2);
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64(static_section, alphabet).slice(0, -1)) + "'>" +
-                static_section + "</span>" +
+                Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" +
+                staticSection + "</span>" +
                 "<span class='hlgreen'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
                 "<span class='hlred'>" + offset0.substr(offset0.length - 1) + "</span>";
         } else {
-            static_section = offset0;
+            staticSection = offset0;
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64(static_section, alphabet)) + "'>" +
-                static_section + "</span>";
+                Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet)) + "'>" +
+                staticSection + "</span>";
         }
 
-        if (!show_variable) {
-            offset0 = static_section;
+        if (!showVariable) {
+            offset0 = staticSection;
         }
 
 
@@ -243,28 +243,28 @@ var Base64 = {
             "<span class='hlgreen'>" + offset1.substr(1, 1) + "</span>";
         offset1 = offset1.substr(2);
         if (len1 % 4 === 2) {
-            static_section = offset1.slice(0, -3);
+            staticSection = offset1.slice(0, -3);
             offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64("AA" + static_section, alphabet).slice(1, -2)) + "'>" +
-                static_section + "</span>" +
+                Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" +
+                staticSection + "</span>" +
                 "<span class='hlgreen'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
                 "<span class='hlred'>" + offset1.substr(offset1.length - 2) + "</span>";
         } else if (len1 % 4 === 3) {
-            static_section = offset1.slice(0, -2);
+            staticSection = offset1.slice(0, -2);
             offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64("AA" + static_section, alphabet).slice(1, -1)) + "'>" +
-                static_section + "</span>" +
+                Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" +
+                staticSection + "</span>" +
                 "<span class='hlgreen'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
                 "<span class='hlred'>" + offset1.substr(offset1.length - 1) + "</span>";
         } else {
-            static_section = offset1;
+            staticSection = offset1;
             offset1 = padding +  "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64("AA" + static_section, alphabet).slice(1)) + "'>" +
-                static_section + "</span>";
+                Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1)) + "'>" +
+                staticSection + "</span>";
         }
 
-        if (!show_variable) {
-            offset1 = static_section;
+        if (!showVariable) {
+            offset1 = staticSection;
         }
 
         // Highlight offset 2
@@ -272,31 +272,31 @@ var Base64 = {
             "<span class='hlgreen'>" + offset2.substr(2, 1) + "</span>";
         offset2 = offset2.substr(3);
         if (len2 % 4 === 2) {
-            static_section = offset2.slice(0, -3);
+            staticSection = offset2.slice(0, -3);
             offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64("AAA" + static_section, alphabet).slice(2, -2)) + "'>" +
-                static_section + "</span>" +
+                Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
+                staticSection + "</span>" +
                 "<span class='hlgreen'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
                 "<span class='hlred'>" + offset2.substr(offset2.length - 2) + "</span>";
         } else if (len2 % 4 === 3) {
-            static_section = offset2.slice(0, -2);
+            staticSection = offset2.slice(0, -2);
             offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64("AAA" + static_section, alphabet).slice(2, -2)) + "'>" +
-                static_section + "</span>" +
+                Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
+                staticSection + "</span>" +
                 "<span class='hlgreen'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
                 "<span class='hlred'>" + offset2.substr(offset2.length - 1) + "</span>";
         } else {
-            static_section = offset2;
+            staticSection = offset2;
             offset2 = padding +  "<span data-toggle='tooltip' data-placement='top' title='" +
-                Utils.escape_html(Utils.from_base64("AAA" + static_section, alphabet).slice(2)) + "'>" +
-                static_section + "</span>";
+                Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2)) + "'>" +
+                staticSection + "</span>";
         }
 
-        if (!show_variable) {
-            offset2 = static_section;
+        if (!showVariable) {
+            offset2 = staticSection;
         }
 
-        return (show_variable ? "Characters highlighted in <span class='hlgreen'>green</span> could change if the input is surrounded by more data." +
+        return (showVariable ? "Characters highlighted in <span class='hlgreen'>green</span> could change if the input is surrounded by more data." +
             "\nCharacters highlighted in <span class='hlred'>red</span> are for padding purposes only." +
             "\nUnhighlighted characters are <span data-toggle='tooltip' data-placement='top' title='Tooltip on left'>static</span>." +
             "\nHover over the static sections to see what they decode to on their own.\n" +
@@ -317,7 +317,7 @@ var Base64 = {
      * @param {Object[]} args
      * @returns {Object[]} pos
      */
-    highlight_to: function(pos, args) {
+    highlightTo: function(pos, args) {
         pos[0].start = Math.floor(pos[0].start / 3 * 4);
         pos[0].end = Math.ceil(pos[0].end / 3 * 4);
         return pos;
@@ -332,7 +332,7 @@ var Base64 = {
      * @param {Object[]} args
      * @returns {Object[]} pos
      */
-    highlight_from: function(pos, args) {
+    highlightFrom: function(pos, args) {
         pos[0].start = Math.ceil(pos[0].start / 4 * 3);
         pos[0].end = Math.floor(pos[0].end / 4 * 3);
         return pos;

+ 56 - 56
src/js/operations/BitwiseOp.js

@@ -15,14 +15,14 @@ var BitwiseOp = {
      * Runs bitwise operations across the input data.
      *
      * @private
-     * @param {byte_array} input
-     * @param {byte_array} key
+     * @param {byteArray} input
+     * @param {byteArray} key
      * @param {function} func - The bitwise calculation to carry out
-     * @param {boolean} null_preserving
+     * @param {boolean} nullPreserving
      * @param {string} scheme
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    _bit_op: function (input, key, func, null_preserving, scheme) {
+    _bitOp: function (input, key, func, nullPreserving, scheme) {
         if (!key || !key.length) key = [0];
         var result = [],
             x = null,
@@ -32,9 +32,9 @@ var BitwiseOp = {
         for (var i = 0; i < input.length; i++) {
             k = key[i % key.length];
             o = input[i];
-            x = null_preserving && (o === 0 || o === k) ? o : func(o, k);
+            x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
             result.push(x);
-            if (scheme !== "Standard" && !(null_preserving && (o === 0 || o === k))) {
+            if (scheme !== "Standard" && !(nullPreserving && (o === 0 || o === k))) {
                 switch (scheme) {
                     case "Input differential":
                         key[i % key.length] = x;
@@ -69,18 +69,18 @@ var BitwiseOp = {
     /**
      * XOR operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_xor: function (input, args) {
+    runXor: function (input, args) {
         var key = Utils.format[args[0].option].parse(args[0].string || ""),
             scheme = args[1],
-            null_preserving = args[2];
+            nullPreserving = args[2];
         
-        key = Utils.word_array_to_byte_array(key);
+        key = Utils.wordArrayToByteArray(key);
             
-        return BitwiseOp._bit_op(input, key, BitwiseOp._xor, null_preserving, scheme);
+        return BitwiseOp._bitOp(input, key, BitwiseOp._xor, nullPreserving, scheme);
     },
     
     
@@ -113,42 +113,42 @@ var BitwiseOp = {
     /**
      * XOR Brute Force operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_xor_brute: function (input, args) {
-        var key_length = parseInt(args[0], 10),
-            sample_length = args[1],
-            sample_offset = args[2],
-            null_preserving = args[3],
+    runXorBrute: function (input, args) {
+        var keyLength = parseInt(args[0], 10),
+            sampleLength = args[1],
+            sampleOffset = args[2],
+            nullPreserving = args[3],
             differential = args[4],
             crib = args[5],
-            print_key = args[6],
-            output_hex = args[7],
+            printKey = args[6],
+            outputHex = args[7],
             regex;
         
         var output = "",
             result,
-            result_utf8;
+            resultUtf8;
         
-        input = input.slice(sample_offset, sample_offset + sample_length);
+        input = input.slice(sampleOffset, sampleOffset + sampleLength);
         
         if (crib !== "") {
             regex = new RegExp(crib, "im");
         }
         
         
-        for (var key = 1, l = Math.pow(256, key_length); key < l; key++) {
-            result = BitwiseOp._bit_op(input, Utils.hex_to_byte_array(key.toString(16)), BitwiseOp._xor, null_preserving, differential);
-            result_utf8 = Utils.byte_array_to_utf8(result);
-            if (crib !== "" && result_utf8.search(regex) === -1) continue;
-            if (print_key) output += "Key = " + Utils.hex(key, (2*key_length)) + ": ";
-            if (output_hex)
-                output += Utils.byte_array_to_hex(result) + "\n";
+        for (var key = 1, l = Math.pow(256, keyLength); key < l; key++) {
+            result = BitwiseOp._bitOp(input, Utils.hexToByteArray(key.toString(16)), BitwiseOp._xor, nullPreserving, differential);
+            resultUtf8 = Utils.byteArrayToUtf8(result);
+            if (crib !== "" && resultUtf8.search(regex) === -1) continue;
+            if (printKey) output += "Key = " + Utils.hex(key, (2*keyLength)) + ": ";
+            if (outputHex)
+                output += Utils.byteArrayToHex(result) + "\n";
             else
-                output += Utils.printable(result_utf8, false) + "\n";
-            if (print_key) output += "\n";
+                output += Utils.printable(resultUtf8, false) + "\n";
+            if (printKey) output += "\n";
         }
         return output;
     },
@@ -157,72 +157,72 @@ var BitwiseOp = {
     /**
      * NOT operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_not: function (input, args) {
-        return BitwiseOp._bit_op(input, null, BitwiseOp._not);
+    runNot: function (input, args) {
+        return BitwiseOp._bitOp(input, null, BitwiseOp._not);
     },
     
     
     /**
      * AND operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_and: function (input, args) {
+    runAnd: function (input, args) {
         var key = Utils.format[args[0].option].parse(args[0].string || "");
-        key = Utils.word_array_to_byte_array(key);
+        key = Utils.wordArrayToByteArray(key);
         
-        return BitwiseOp._bit_op(input, key, BitwiseOp._and);
+        return BitwiseOp._bitOp(input, key, BitwiseOp._and);
     },
     
     
     /**
      * OR operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_or: function (input, args) {
+    runOr: function (input, args) {
         var key = Utils.format[args[0].option].parse(args[0].string || "");
-        key = Utils.word_array_to_byte_array(key);
+        key = Utils.wordArrayToByteArray(key);
         
-        return BitwiseOp._bit_op(input, key, BitwiseOp._or);
+        return BitwiseOp._bitOp(input, key, BitwiseOp._or);
     },
     
     
     /**
      * ADD operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_add: function (input, args) {
+    runAdd: function (input, args) {
         var key = Utils.format[args[0].option].parse(args[0].string || "");
-        key = Utils.word_array_to_byte_array(key);
+        key = Utils.wordArrayToByteArray(key);
         
-        return BitwiseOp._bit_op(input, key, BitwiseOp._add);
+        return BitwiseOp._bitOp(input, key, BitwiseOp._add);
     },
     
     
     /**
      * SUB operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_sub: function (input, args) {
+    runSub: function (input, args) {
         var key = Utils.format[args[0].option].parse(args[0].string || "");
-        key = Utils.word_array_to_byte_array(key);
+        key = Utils.wordArrayToByteArray(key);
         
-        return BitwiseOp._bit_op(input, key, BitwiseOp._sub);
+        return BitwiseOp._bitOp(input, key, BitwiseOp._sub);
     },
     
     

+ 61 - 61
src/js/operations/ByteRepr.js

@@ -30,13 +30,13 @@ var ByteRepr = {
     /**
      * To Hex operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_hex: function(input, args) {
-        var delim = Utils.char_rep[args[0] || "Space"];
-        return Utils.to_hex(input, delim, 2);
+    runToHex: function(input, args) {
+        var delim = Utils.charRep[args[0] || "Space"];
+        return Utils.toHex(input, delim, 2);
     },
 
 
@@ -45,11 +45,11 @@ var ByteRepr = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from_hex: function(input, args) {
+    runFromHex: function(input, args) {
         var delim = args[0] || "Space";
-        return Utils.from_hex(input, delim, 2);
+        return Utils.fromHex(input, delim, 2);
     },
 
 
@@ -66,8 +66,8 @@ var ByteRepr = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_charcode: function(input, args) {
-        var delim = Utils.char_rep[args[0] || "Space"],
+    runToCharcode: function(input, args) {
+        var delim = Utils.charRep[args[0] || "Space"],
             base = args[1],
             output = "",
             padding = 2,
@@ -87,11 +87,11 @@ var ByteRepr = {
                 else if (ordinal < 4294967296) padding = 8;
                 else padding = 2;
 
-                if (padding > 2) app.options.attempt_highlight = false;
+                if (padding > 2) app.options.attemptHighlight = false;
 
                 output += Utils.hex(ordinal, padding) + delim;
             } else {
-                app.options.attempt_highlight = false;
+                app.options.attemptHighlight = false;
                 output += ordinal.toString(base) + delim;
             }
         }
@@ -105,10 +105,10 @@ var ByteRepr = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from_charcode: function(input, args) {
-        var delim = Utils.char_rep[args[0] || "Space"],
+    runFromCharcode: function(input, args) {
+        var delim = Utils.charRep[args[0] || "Space"],
             base = args[1],
             bites = input.split(delim),
             i = 0;
@@ -118,7 +118,7 @@ var ByteRepr = {
         }
 
         if (base !== 16) {
-            app.options.attempt_highlight = false;
+            app.options.attemptHighlight = false;
         }
 
         // Split into groups of 2 if the whole string is concatenated and
@@ -134,7 +134,7 @@ var ByteRepr = {
         for (i = 0; i < bites.length; i++) {
             latin1 += Utils.chr(parseInt(bites[i], base));
         }
-        return Utils.str_to_byte_array(latin1);
+        return Utils.strToByteArray(latin1);
     },
 
 
@@ -147,8 +147,8 @@ var ByteRepr = {
      * @param {Object[]} args
      * @returns {Object[]} pos
      */
-    highlight_to: function(pos, args) {
-        var delim = Utils.char_rep[args[0] || "Space"],
+    highlightTo: function(pos, args) {
+        var delim = Utils.charRep[args[0] || "Space"],
             len = delim === "\r\n" ? 1 : delim.length;
 
         pos[0].start = pos[0].start * (2 + len);
@@ -172,8 +172,8 @@ var ByteRepr = {
      * @param {Object[]} args
      * @returns {Object[]} pos
      */
-    highlight_from: function(pos, args) {
-        var delim = Utils.char_rep[args[0] || "Space"],
+    highlightFrom: function(pos, args) {
+        var delim = Utils.charRep[args[0] || "Space"],
             len = delim === "\r\n" ? 1 : delim.length,
             width = len + 2;
 
@@ -194,12 +194,12 @@ var ByteRepr = {
     /**
      * To Decimal operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_decimal: function(input, args) {
-        var delim = Utils.char_rep[args[0]];
+    runToDecimal: function(input, args) {
+        var delim = Utils.charRep[args[0]];
         return input.join(delim);
     },
 
@@ -209,16 +209,16 @@ var ByteRepr = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from_decimal: function(input, args) {
-        var delim = Utils.char_rep[args[0]];
-        var byte_str = input.split(delim), output = [];
-        if (byte_str[byte_str.length-1] === "")
-            byte_str = byte_str.slice(0, byte_str.length-1);
-
-        for (var i = 0; i < byte_str.length; i++) {
-            output[i] = parseInt(byte_str[i], 10);
+    runFromDecimal: function(input, args) {
+        var delim = Utils.charRep[args[0]];
+        var byteStr = input.split(delim), output = [];
+        if (byteStr[byteStr.length-1] === "")
+            byteStr = byteStr.slice(0, byteStr.length-1);
+
+        for (var i = 0; i < byteStr.length; i++) {
+            output[i] = parseInt(byteStr[i], 10);
         }
         return output;
     },
@@ -227,12 +227,12 @@ var ByteRepr = {
     /**
      * To Binary operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_binary: function(input, args) {
-        var delim = Utils.char_rep[args[0] || "Space"],
+    runToBinary: function(input, args) {
+        var delim = Utils.charRep[args[0] || "Space"],
             output = "",
             padding = 8;
 
@@ -253,18 +253,18 @@ var ByteRepr = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from_binary: function(input, args) {
+    runFromBinary: function(input, args) {
         if (args[0] !== "None") {
-            var delim_regex = Utils.regex_rep[args[0] || "Space"];
-            input = input.replace(delim_regex, "");
+            var delimRegex = Utils.regexRep[args[0] || "Space"];
+            input = input.replace(delimRegex, "");
         }
 
         var output = [];
-        var byte_len = 8;
-        for (var i = 0; i < input.length; i += byte_len) {
-            output.push(parseInt(input.substr(i, byte_len), 2));
+        var byteLen = 8;
+        for (var i = 0; i < input.length; i += byteLen) {
+            output.push(parseInt(input.substr(i, byteLen), 2));
         }
         return output;
     },
@@ -279,8 +279,8 @@ var ByteRepr = {
      * @param {Object[]} args
      * @returns {Object[]} pos
      */
-    highlight_to_binary: function(pos, args) {
-        var delim = Utils.char_rep[args[0] || "Space"];
+    highlightToBinary: function(pos, args) {
+        var delim = Utils.charRep[args[0] || "Space"];
         pos[0].start = pos[0].start * (8 + delim.length);
         pos[0].end = pos[0].end * (8 + delim.length) - delim.length;
         return pos;
@@ -296,8 +296,8 @@ var ByteRepr = {
      * @param {Object[]} args
      * @returns {Object[]} pos
      */
-    highlight_from_binary: function(pos, args) {
-        var delim = Utils.char_rep[args[0] || "Space"];
+    highlightFromBinary: function(pos, args) {
+        var delim = Utils.charRep[args[0] || "Space"];
         pos[0].start = pos[0].start === 0 ? 0 : Math.floor(pos[0].start / (8 + delim.length));
         pos[0].end = pos[0].end === 0 ? 0 : Math.ceil(pos[0].end / (8 + delim.length));
         return pos;
@@ -318,40 +318,40 @@ var ByteRepr = {
     /**
      * To Hex Content operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_hex_content: function(input, args) {
+    runToHexContent: function(input, args) {
         var convert = args[0];
         var spaces = args[1];
         if (convert === "All chars") {
-            var result = "|" + Utils.to_hex(input) + "|";
+            var result = "|" + Utils.toHex(input) + "|";
             if (!spaces) result = result.replace(/ /g, "");
             return result;
         }
 
         var output = "",
-            in_hex = false,
-            convert_spaces = convert === "Only special chars including spaces",
+            inHex = false,
+            convertSpaces = convert === "Only special chars including spaces",
             b;
         for (var i = 0; i < input.length; i++) {
             b = input[i];
-            if ((b === 32 && convert_spaces) || (b < 48 && b !== 32) || (b > 57 && b < 65) || (b > 90 && b < 97) || b > 122) {
-                if (!in_hex) {
+            if ((b === 32 && convertSpaces) || (b < 48 && b !== 32) || (b > 57 && b < 65) || (b > 90 && b < 97) || b > 122) {
+                if (!inHex) {
                     output += "|";
-                    in_hex = true;
+                    inHex = true;
                 } else if (spaces) output += " ";
-                output += Utils.to_hex([b]);
+                output += Utils.toHex([b]);
             } else {
-                if (in_hex) {
+                if (inHex) {
                     output += "|";
-                    in_hex = false;
+                    inHex = false;
                 }
                 output += Utils.chr(input[i]);
             }
         }
-        if (in_hex) output += "|";
+        if (inHex) output += "|";
         return output;
     },
 
@@ -361,9 +361,9 @@ var ByteRepr = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from_hex_content: function(input, args) {
+    runFromHexContent: function(input, args) {
         var regex = /\|([a-f\d ]{2,})\|/gi;
         var output = [], m, i = 0;
         while ((m = regex.exec(input))) {
@@ -372,7 +372,7 @@ var ByteRepr = {
                 output.push(Utils.ord(input[i++]));
 
             // Add match
-            var bytes = Utils.from_hex(m[1]);
+            var bytes = Utils.fromHex(m[1]);
             if (bytes) {
                 for (var a = 0; a < bytes.length;)
                     output.push(bytes[a++]);

+ 8 - 8
src/js/operations/CharEnc.js

@@ -25,21 +25,21 @@ var CharEnc = {
      * @returns {string}
      */
     run: function(input, args) {
-        var input_format = args[0],
-            output_format = args[1];
+        var inputFormat = args[0],
+            outputFormat = args[1];
             
-        if (input_format === "Windows-1251") {
-            input = Utils.win1251_to_unicode(input);
+        if (inputFormat === "Windows-1251") {
+            input = Utils.win1251ToUnicode(input);
             input = CryptoJS.enc.Utf8.parse(input);
         } else {
-            input = Utils.format[input_format].parse(input);
+            input = Utils.format[inputFormat].parse(input);
         }
         
-        if (output_format === "Windows-1251") {
+        if (outputFormat === "Windows-1251") {
             input = CryptoJS.enc.Utf8.stringify(input);
-            return Utils.unicode_to_win1251(input);
+            return Utils.unicodeToWin1251(input);
         } else {
-            return Utils.format[output_format].stringify(input);
+            return Utils.format[outputFormat].stringify(input);
         }
     },
     

+ 76 - 16
src/js/operations/Checksum.js

@@ -9,14 +9,34 @@
  */
 var Checksum = {
 
+    /**
+     * Fletcher-8 Checksum operation.
+     *
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runFletcher8: function(input, args) {
+        var a = 0,
+            b = 0;
+        
+        for (var i = 0; i < input.length; i++) {
+            a = (a + input[i]) % 0xf;
+            b = (b + a) % 0xf;
+        }
+        
+        return Utils.hex(((b << 4) | a) >>> 0, 2);
+    },
+
+
     /**
      * Fletcher-16 Checksum operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_fletcher16: function(input, args) {
+    runFletcher16: function(input, args) {
         var a = 0,
             b = 0;
         
@@ -27,16 +47,56 @@ var Checksum = {
         
         return Utils.hex(((b << 8) | a) >>> 0, 4);
     },
+
+
+    /**
+     * Fletcher-32 Checksum operation.
+     *
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runFletcher32: function(input, args) {
+        var a = 0,
+            b = 0;
+        
+        for (var i = 0; i < input.length; i++) {
+            a = (a + input[i]) % 0xffff;
+            b = (b + a) % 0xffff;
+        }
+        
+        return Utils.hex(((b << 16) | a) >>> 0, 8);
+    },
+
+
+    /**
+     * Fletcher-64 Checksum operation.
+     *
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runFletcher64: function(input, args) {
+        var a = 0,
+            b = 0;
+        
+        for (var i = 0; i < input.length; i++) {
+            a = (a + input[i]) % 0xffffffff;
+            b = (b + a) % 0xffffffff;
+        }
+        
+        return Utils.hex(b >>> 0, 8) + Utils.hex(a >>> 0, 8);
+    },
     
     
     /**
      * Adler-32 Checksum operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_adler32: function(input, args) {
+    runAdler32: function(input, args) {
         var MOD_ADLER = 65521,
             a = 1,
             b = 0;
@@ -56,16 +116,16 @@ var Checksum = {
     /**
      * CRC-32 Checksum operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_crc32: function(input, args) {
-        var crc_table = window.crc_table || (window.crc_table = Checksum._gen_crc_table()),
+    runCRC32: function(input, args) {
+        var crcTable = window.crcTable || (window.crcTable = Checksum._genCRCTable()),
             crc = 0 ^ (-1);
         
         for (var i = 0; i < input.length; i++) {
-            crc = (crc >>> 8) ^ crc_table[(crc ^ input[i]) & 0xff];
+            crc = (crc >>> 8) ^ crcTable[(crc ^ input[i]) & 0xff];
         }
         
         return Utils.hex((crc ^ (-1)) >>> 0);
@@ -76,20 +136,20 @@ var Checksum = {
      * TCP/IP Checksum operation.
      *
      * @author GCHQ Contributor [1]
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      *
      * @example
      * // returns '3f2c'
-     * Checksum.run_tcp_ip([0x45,0x00,0x00,0x87,0xa3,0x1b,0x40,0x00,0x40,0x06,
+     * Checksum.runTcpIp([0x45,0x00,0x00,0x87,0xa3,0x1b,0x40,0x00,0x40,0x06,
      *                      0x00,0x00,0xac,0x11,0x00,0x04,0xac,0x11,0x00,0x03])
      *
      * // returns 'a249'
-     * Checksum.run_tcp_ip([0x45,0x00,0x01,0x11,0x3f,0x74,0x40,0x00,0x40,0x06,
+     * Checksum.runTcpIp([0x45,0x00,0x01,0x11,0x3f,0x74,0x40,0x00,0x40,0x06,
      *                      0x00,0x00,0xac,0x11,0x00,0x03,0xac,0x11,0x00,0x04])
      */
-    run_tcp_ip: function(input, args) {
+    runTCPIP: function(input, args) {
         var csum = 0;
         
         for (var i = 0; i < input.length; i++) {
@@ -112,19 +172,19 @@ var Checksum = {
      * @private
      * @returns {array}
      */
-    _gen_crc_table: function() {
+    _genCRCTable: function() {
         var c,
-            crc_table = [];
+            crcTable = [];
         
         for (var n = 0; n < 256; n++) {
             c = n;
             for (var k = 0; k < 8; k++) {
                 c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
             }
-            crc_table[n] = c;
+            crcTable[n] = c;
         }
         
-        return crc_table;
+        return crcTable;
     },
 
 };

+ 101 - 64
src/js/operations/Cipher.js

@@ -53,7 +53,7 @@ var Cipher = {
      *
      * @private
      * @param {function} algo - The CryptoJS algorithm to use
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {function} args
      * @returns {string}
      */
@@ -63,8 +63,8 @@ var Cipher = {
             salt = Utils.format[args[2].option].parse(args[2].string || ""),
             mode = CryptoJS.mode[args[3]],
             padding = CryptoJS.pad[args[4]],
-            result_option = args[5].toLowerCase(),
-            output_format = args[6];
+            resultOption = args[5].toLowerCase(),
+            outputFormat = args[6];
 
         if (iv.sigBytes === 0) {
             // Use passphrase rather than key. Need to convert it to a string.
@@ -79,13 +79,13 @@ var Cipher = {
         });
 
         var result = "";
-        if (result_option === "show all") {
-            result += "Key:  " + encrypted.key.toString(Utils.format[output_format]);
-            result += "\nIV:   " + encrypted.iv.toString(Utils.format[output_format]);
-            if (encrypted.salt) result += "\nSalt: " + encrypted.salt.toString(Utils.format[output_format]);
-            result += "\n\nCiphertext: " + encrypted.ciphertext.toString(Utils.format[output_format]);
+        if (resultOption === "show all") {
+            result += "Key:  " + encrypted.key.toString(Utils.format[outputFormat]);
+            result += "\nIV:   " + encrypted.iv.toString(Utils.format[outputFormat]);
+            if (encrypted.salt) result += "\nSalt: " + encrypted.salt.toString(Utils.format[outputFormat]);
+            result += "\n\nCiphertext: " + encrypted.ciphertext.toString(Utils.format[outputFormat]);
         } else {
-            result = encrypted[result_option].toString(Utils.format[output_format]);
+            result = encrypted[resultOption].toString(Utils.format[outputFormat]);
         }
 
         return result;
@@ -97,7 +97,7 @@ var Cipher = {
      *
      * @private
      * @param {function} algo - The CryptoJS algorithm to use
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {function} args
      * @returns {string}
      */
@@ -107,15 +107,15 @@ var Cipher = {
             salt = Utils.format[args[2].option].parse(args[2].string || ""),
             mode = CryptoJS.mode[args[3]],
             padding = CryptoJS.pad[args[4]],
-            input_format = args[5],
-            output_format = args[6];
+            inputFormat = args[5],
+            outputFormat = args[6];
 
         // The ZeroPadding option causes a crash when the input length is 0
         if (!input.length) {
             return "No input";
         }
 
-        var ciphertext = Utils.format[input_format].parse(input);
+        var ciphertext = Utils.format[inputFormat].parse(input);
 
         if (iv.sigBytes === 0) {
             // Use passphrase rather than key. Need to convert it to a string.
@@ -133,7 +133,7 @@ var Cipher = {
 
         var result;
         try {
-            result = decrypted.toString(Utils.format[output_format]);
+            result = decrypted.toString(Utils.format[outputFormat]);
         } catch (err) {
             result = "Decrypt error: " + err.message;
         }
@@ -149,7 +149,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_aes_enc: function (input, args) {
+    runAesEnc: function (input, args) {
         return Cipher._enc(CryptoJS.AES, input, args);
     },
 
@@ -161,7 +161,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_aes_dec: function (input, args) {
+    runAesDec: function (input, args) {
         return Cipher._dec(CryptoJS.AES, input, args);
     },
 
@@ -173,7 +173,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_des_enc: function (input, args) {
+    runDesEnc: function (input, args) {
         return Cipher._enc(CryptoJS.DES, input, args);
     },
 
@@ -185,7 +185,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_des_dec: function (input, args) {
+    runDesDec: function (input, args) {
         return Cipher._dec(CryptoJS.DES, input, args);
     },
 
@@ -197,7 +197,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_triple_des_enc: function (input, args) {
+    runTripleDesEnc: function (input, args) {
         return Cipher._enc(CryptoJS.TripleDES, input, args);
     },
 
@@ -209,7 +209,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_triple_des_dec: function (input, args) {
+    runTripleDesDec: function (input, args) {
         return Cipher._dec(CryptoJS.TripleDES, input, args);
     },
 
@@ -221,7 +221,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_rabbit_enc: function (input, args) {
+    runRabbitEnc: function (input, args) {
         return Cipher._enc(CryptoJS.Rabbit, input, args);
     },
 
@@ -233,7 +233,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_rabbit_dec: function (input, args) {
+    runRabbitDec: function (input, args) {
         return Cipher._dec(CryptoJS.Rabbit, input, args);
     },
 
@@ -256,20 +256,20 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_blowfish_enc: function (input, args) {
+    runBlowfishEnc: function (input, args) {
         var key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
             mode = args[1],
-            output_format = args[2];
+            outputFormat = args[2];
 
         if (key.length === 0) return "Enter a key";
 
-        var enc_hex = blowfish.encrypt(input, key, {
+        var encHex = blowfish.encrypt(input, key, {
                 outputType: 1,
                 cipherMode: Cipher.BLOWFISH_MODES.indexOf(mode)
             }),
-            enc = CryptoJS.enc.Hex.parse(enc_hex);
+            enc = CryptoJS.enc.Hex.parse(encHex);
 
-        return enc.toString(Utils.format[output_format]);
+        return enc.toString(Utils.format[outputFormat]);
     },
 
 
@@ -280,14 +280,14 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_blowfish_dec: function (input, args) {
+    runBlowfishDec: function (input, args) {
         var key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
             mode = args[1],
-            input_format = args[2];
+            inputFormat = args[2];
 
         if (key.length === 0) return "Enter a key";
 
-        input = Utils.format[input_format].parse(input);
+        input = Utils.format[inputFormat].parse(input);
 
         return blowfish.decrypt(input.toString(CryptoJS.enc.Base64), key, {
             outputType: 0, // This actually means inputType. The library is weird.
@@ -314,16 +314,16 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_pbkdf2: function (input, args) {
-        var key_size = args[0] / 32,
+    runPbkdf2: function (input, args) {
+        var keySize = args[0] / 32,
             iterations = args[1],
             salt = CryptoJS.enc.Hex.parse(args[2] || ""),
-            input_format = args[3],
-            output_format = args[4],
-            passphrase = Utils.format[input_format].parse(input),
-            key = CryptoJS.PBKDF2(passphrase, salt, { keySize: key_size, iterations: iterations });
+            inputFormat = args[3],
+            outputFormat = args[4],
+            passphrase = Utils.format[inputFormat].parse(input),
+            key = CryptoJS.PBKDF2(passphrase, salt, { keySize: keySize, iterations: iterations });
 
-        return key.toString(Utils.format[output_format]);
+        return key.toString(Utils.format[outputFormat]);
     },
 
 
@@ -334,16 +334,16 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_evpkdf: function (input, args) {
-        var key_size = args[0] / 32,
+    runEvpkdf: function (input, args) {
+        var keySize = args[0] / 32,
             iterations = args[1],
             salt = CryptoJS.enc.Hex.parse(args[2] || ""),
-            input_format = args[3],
-            output_format = args[4],
-            passphrase = Utils.format[input_format].parse(input),
-            key = CryptoJS.EvpKDF(passphrase, salt, { keySize: key_size, iterations: iterations });
+            inputFormat = args[3],
+            outputFormat = args[4],
+            passphrase = Utils.format[inputFormat].parse(input),
+            key = CryptoJS.EvpKDF(passphrase, salt, { keySize: keySize, iterations: iterations });
 
-        return key.toString(Utils.format[output_format]);
+        return key.toString(Utils.format[outputFormat]);
     },
 
 
@@ -354,7 +354,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_rc4: function (input, args) {
+    runRc4: function (input, args) {
         var message = Utils.format[args[1]].parse(input),
             passphrase = Utils.format[args[0].option].parse(args[0].string),
             encrypted = CryptoJS.RC4.encrypt(message, passphrase);
@@ -376,7 +376,7 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_rc4drop: function (input, args) {
+    runRc4drop: function (input, args) {
         var message = Utils.format[args[1]].parse(input),
             passphrase = Utils.format[args[0].option].parse(args[0].string),
             drop = args[3],
@@ -394,13 +394,13 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_vigenere_enc: function (input, args) {
+    runVigenereEnc: function (input, args) {
         var alphabet = "abcdefghijklmnopqrstuvwxyz",
             key = args[0].toLowerCase(),
             output = "",
             fail = 0,
-            key_index,
-            msg_index,
+            keyIndex,
+            msgIndex,
             chr;
 
         if (!key) return "No key entered";
@@ -412,17 +412,17 @@ var Cipher = {
                 // for chars not in alphabet
                 chr = key[(i - fail) % key.length];
                 // Get the location in the vigenere square of the key char
-                key_index = alphabet.indexOf(chr);
+                keyIndex = alphabet.indexOf(chr);
                 // Get the location in the vigenere square of the message char
-                msg_index = alphabet.indexOf(input[i]);
+                msgIndex = alphabet.indexOf(input[i]);
                 // Get the encoded letter by finding the sum of indexes modulo 26 and finding
                 // the letter corresponding to that
-                output += alphabet[(key_index + msg_index) % 26];
+                output += alphabet[(keyIndex + msgIndex) % 26];
             } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
                 chr = key[(i - fail) % key.length].toLowerCase();
-                key_index = alphabet.indexOf(chr);
-                msg_index = alphabet.indexOf(input[i].toLowerCase());
-                output += alphabet[(key_index + msg_index) % 26].toUpperCase();
+                keyIndex = alphabet.indexOf(chr);
+                msgIndex = alphabet.indexOf(input[i].toLowerCase());
+                output += alphabet[(keyIndex + msgIndex) % 26].toUpperCase();
             } else {
                 output += input[i];
                 fail++;
@@ -441,13 +441,13 @@ var Cipher = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_vigenere_dec: function (input, args) {
+    runVigenereDec: function (input, args) {
         var alphabet = "abcdefghijklmnopqrstuvwxyz",
             key = args[0].toLowerCase(),
             output = "",
             fail = 0,
-            key_index,
-            msg_index,
+            keyIndex,
+            msgIndex,
             chr;
 
         if (!key) return "No key entered";
@@ -456,16 +456,16 @@ var Cipher = {
         for (var i = 0; i < input.length; i++) {
             if (alphabet.indexOf(input[i]) >= 0) {
                 chr = key[(i - fail) % key.length];
-                key_index = alphabet.indexOf(chr);
-                msg_index = alphabet.indexOf(input[i]);
+                keyIndex = alphabet.indexOf(chr);
+                msgIndex = alphabet.indexOf(input[i]);
                 // Subtract indexes from each other, add 26 just in case the value is negative,
                 // modulo to remove if neccessary
-                output += alphabet[(msg_index - key_index + alphabet.length ) % 26];
+                output += alphabet[(msgIndex - keyIndex + alphabet.length ) % 26];
             } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
                 chr = key[(i - fail) % key.length].toLowerCase();
-                key_index = alphabet.indexOf(chr);
-                msg_index = alphabet.indexOf(input[i].toLowerCase());
-                output += alphabet[(msg_index + alphabet.length - key_index) % 26].toUpperCase();
+                keyIndex = alphabet.indexOf(chr);
+                msgIndex = alphabet.indexOf(input[i].toLowerCase());
+                output += alphabet[(msgIndex + alphabet.length - keyIndex) % 26].toUpperCase();
             } else {
                 output += input[i];
                 fail++;
@@ -475,6 +475,43 @@ var Cipher = {
         return output;
     },
 
+
+    /**
+     * @constant
+     * @default
+     */
+    SUBS_PLAINTEXT: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+    /**
+     * @constant
+     * @default
+     */
+    SUBS_CIPHERTEXT: "XYZABCDEFGHIJKLMNOPQRSTUVW",
+
+    /**
+     * Substitute operation.
+     *
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {byteArray}
+     */
+    runSubstitute: function (input, args) {
+        var plaintext = Utils.strToByteArray(Utils.expandAlphRange(args[0]).join()),
+            ciphertext = Utils.strToByteArray(Utils.expandAlphRange(args[1]).join()),
+            output = [],
+            index = -1;
+
+        if (plaintext.length !== ciphertext.length) {
+            output = Utils.strToByteArray("Warning: Plaintext and Ciphertext lengths differ\n\n");
+        }
+
+        for (var i = 0; i < input.length; i++) {
+            index = plaintext.indexOf(input[i]);
+            output.push(index > -1 && index < ciphertext.length ? ciphertext[index] : input[i]);
+        }
+
+        return output;
+    },
+
 };
 
 

+ 152 - 37
src/js/operations/Code.js

@@ -1,4 +1,4 @@
-/* globals prettyPrintOne, vkbeautify */
+/* globals prettyPrintOne, vkbeautify, xpath */
 
 /**
  * Code operations.
@@ -29,10 +29,10 @@ var Code = {
      * @param {Object[]} args
      * @returns {html}
      */
-    run_syntax_highlight: function(input, args) {
+    runSyntaxHighlight: function(input, args) {
         var language = args[0],
-            line_nums = args[1];
-        return "<code class='prettyprint'>" + prettyPrintOne(Utils.escape_html(input), language, line_nums) + "</code>";
+            lineNums = args[1];
+        return "<code class='prettyprint'>" + prettyPrintOne(Utils.escapeHtml(input), language, lineNums) + "</code>";
     },
 
 
@@ -49,9 +49,9 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_xml_beautify: function(input, args) {
-        var indent_str = args[0];
-        return vkbeautify.xml(input, indent_str);
+    runXmlBeautify: function(input, args) {
+        var indentStr = args[0];
+        return vkbeautify.xml(input, indentStr);
     },
 
 
@@ -62,10 +62,10 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_json_beautify: function(input, args) {
-        var indent_str = args[0];
+    runJsonBeautify: function(input, args) {
+        var indentStr = args[0];
         if (!input) return "";
-        return vkbeautify.json(input, indent_str);
+        return vkbeautify.json(input, indentStr);
     },
 
 
@@ -76,9 +76,9 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_css_beautify: function(input, args) {
-        var indent_str = args[0];
-        return vkbeautify.css(input, indent_str);
+    runCssBeautify: function(input, args) {
+        var indentStr = args[0];
+        return vkbeautify.css(input, indentStr);
     },
 
 
@@ -89,9 +89,9 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sql_beautify: function(input, args) {
-        var indent_str = args[0];
-        return vkbeautify.sql(input, indent_str);
+    runSqlBeautify: function(input, args) {
+        var indentStr = args[0];
+        return vkbeautify.sql(input, indentStr);
     },
 
 
@@ -108,9 +108,9 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_xml_minify: function(input, args) {
-        var preserve_comments = args[0];
-        return vkbeautify.xmlmin(input, preserve_comments);
+    runXmlMinify: function(input, args) {
+        var preserveComments = args[0];
+        return vkbeautify.xmlmin(input, preserveComments);
     },
 
 
@@ -121,7 +121,7 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_json_minify: function(input, args) {
+    runJsonMinify: function(input, args) {
         if (!input) return "";
         return vkbeautify.jsonmin(input);
     },
@@ -134,9 +134,9 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_css_minify: function(input, args) {
-        var preserve_comments = args[0];
-        return vkbeautify.cssmin(input, preserve_comments);
+    runCssMinify: function(input, args) {
+        var preserveComments = args[0];
+        return vkbeautify.cssmin(input, preserveComments);
     },
 
 
@@ -147,7 +147,7 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sql_minify: function(input, args) {
+    runSqlMinify: function(input, args) {
         return vkbeautify.sqlmin(input);
     },
 
@@ -175,48 +175,48 @@ var Code = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_generic_beautify: function(input, args) {
+    runGenericBeautify: function(input, args) {
         var code = input,
             t = 0,
-            preserved_tokens = [],
+            preservedTokens = [],
             m;
 
         // Remove strings
         var sstrings = /'([^'\\]|\\.)*'/g;
         while ((m = sstrings.exec(code))) {
-            code = preserve_token(code, m, t++);
+            code = preserveToken(code, m, t++);
             sstrings.lastIndex = m.index;
         }
 
         var dstrings = /"([^"\\]|\\.)*"/g;
         while ((m = dstrings.exec(code))) {
-            code = preserve_token(code, m, t++);
+            code = preserveToken(code, m, t++);
             dstrings.lastIndex = m.index;
         }
 
         // Remove comments
         var scomments = /\/\/[^\n\r]*/g;
         while ((m = scomments.exec(code))) {
-            code = preserve_token(code, m, t++);
+            code = preserveToken(code, m, t++);
             scomments.lastIndex = m.index;
         }
 
         var mcomments = /\/\*[\s\S]*?\*\//gm;
         while ((m = mcomments.exec(code))) {
-            code = preserve_token(code, m, t++);
+            code = preserveToken(code, m, t++);
             mcomments.lastIndex = m.index;
         }
 
         var hcomments = /(^|\n)#[^\n\r#]+/g;
         while ((m = hcomments.exec(code))) {
-            code = preserve_token(code, m, t++);
+            code = preserveToken(code, m, t++);
             hcomments.lastIndex = m.index;
         }
 
         // Remove regexes
         var regexes = /\/.*?[^\\]\/[gim]{0,3}/gi;
         while ((m = regexes.exec(code))) {
-            code = preserve_token(code, m, t++);
+            code = preserveToken(code, m, t++);
             regexes.lastIndex = m.index;
         }
 
@@ -287,21 +287,136 @@ var Code = {
 
 
         // Replace preserved tokens
-        var ptokens = /###preserved_token(\d+)###/g;
+        var ptokens = /###preservedToken(\d+)###/g;
         while ((m = ptokens.exec(code))) {
             var ti = parseInt(m[1], 10);
-            code = code.substring(0, m.index) + preserved_tokens[ti] + code.substring(m.index + m[0].length);
+            code = code.substring(0, m.index) + preservedTokens[ti] + code.substring(m.index + m[0].length);
             ptokens.lastIndex = m.index;
         }
 
         return code;
 
-        function preserve_token(str, match, t) {
-            preserved_tokens[t] = match[0];
+        function preserveToken(str, match, t) {
+            preservedTokens[t] = match[0];
             return str.substring(0, match.index) +
-                "###preserved_token" + t + "###" +
+                "###preservedToken" + t + "###" +
                 str.substring(match.index + match[0].length);
         }
     },
 
+
+    /**
+     * @constant
+     * @default
+     */
+    XPATH_INITIAL: "",
+
+    /**
+     * @constant
+     * @default
+     */
+    XPATH_DELIMITER: "\\n",
+
+    /**
+     * XPath expression operation.
+     *
+     * @author Mikescher (https://github.com/Mikescher | https://mikescher.com)
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runXpath:function(input, args) {
+        var query = args[0],
+            delimiter = args[1];
+
+        var xml;
+        try {
+            xml = $.parseXML(input);
+        } catch (err) {
+            return "Invalid input XML.";
+        }
+
+        var result;
+        try {
+            result = xpath.evaluate(xml, query);
+        } catch (err) {
+            return "Invalid XPath. Details:\n" + err.message;
+        }
+
+        var serializer = new XMLSerializer();
+        var nodeToString = function(node) {
+            switch (node.nodeType) {
+                case Node.ELEMENT_NODE: return serializer.serializeToString(node);
+                case Node.ATTRIBUTE_NODE: return node.value;
+                case Node.COMMENT_NODE: return node.data;
+                case Node.DOCUMENT_NODE: return serializer.serializeToString(node);
+                default: throw new Error("Unknown Node Type: " + node.nodeType);
+            }
+        };
+
+        return Object.keys(result).map(function(key) {
+            return result[key];
+        }).slice(0, -1) // all values except last (length)
+        .map(nodeToString)
+        .join(delimiter);
+    },
+
+
+    /**
+     * @constant
+     * @default
+     */
+    CSS_SELECTOR_INITIAL: "",
+
+    /**
+     * @constant
+     * @default
+     */
+    CSS_QUERY_DELIMITER: "\\n",
+
+    /**
+     * CSS selector operation.
+     *
+     * @author Mikescher (https://github.com/Mikescher | https://mikescher.com)
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runCssQuery: function(input, args) {
+        var query = args[0],
+            delimiter = args[1];
+
+        var html;
+        try {
+            html = $.parseHTML(input);
+        } catch (err) {
+            return "Invalid input HTML.";
+        }
+
+        var result;
+        try {
+            result = $(html).find(query);
+        } catch (err) {
+            return "Invalid CSS Selector. Details:\n" + err.message;
+        }
+
+        var nodeToString = function(node) {
+            switch (node.nodeType) {
+                case Node.ELEMENT_NODE: return node.outerHTML;
+                case Node.ATTRIBUTE_NODE: return node.value;
+                case Node.COMMENT_NODE: return node.data;
+                case Node.TEXT_NODE: return node.wholeText;
+                case Node.DOCUMENT_NODE: return node.outerHTML;
+                default: throw new Error("Unknown Node Type: " + node.nodeType);
+            }
+        };
+
+        return Array.apply(null, Array(result.length))
+            .map(function(_, i) {
+                return result[i];
+            })
+            .map(nodeToString)
+            .join(delimiter);
+    },
+
 };

+ 39 - 39
src/js/operations/Compress.js

@@ -44,11 +44,11 @@ var Compress = {
     /**
      * Raw Deflate operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_raw_deflate: function(input, args) {
+    runRawDeflate: function(input, args) {
         var deflate = new Zlib.RawDeflate(input, {
             compressionType: Compress.RAW_COMPRESSION_TYPE_LOOKUP[args[0]]
         });
@@ -81,20 +81,20 @@ var Compress = {
      * @default
      */
     RAW_BUFFER_TYPE_LOOKUP: {
-        "Adaptive"  : Zlib.RawInflate.BufferType.ADAPTIVE,
-        "Block"     : Zlib.RawInflate.BufferType.BLOCK,
+        "Adaptive" : Zlib.RawInflate.BufferType.ADAPTIVE,
+        "Block"    : Zlib.RawInflate.BufferType.BLOCK,
     },
     
     /**
      * Raw Inflate operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_raw_inflate: function(input, args) {
+    runRawInflate: function(input, args) {
         // Deal with character encoding issues
-        input = Utils.str_to_byte_array(Utils.byte_array_to_utf8(input));
+        input = Utils.strToByteArray(Utils.byteArrayToUtf8(input));
         var inflate = new Zlib.RawInflate(input, {
                 index: args[0],
                 bufferSize: args[1],
@@ -140,11 +140,11 @@ var Compress = {
     /**
      * Zlib Deflate operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_zlib_deflate: function(input, args) {
+    runZlibDeflate: function(input, args) {
         var deflate = new Zlib.Deflate(input, {
             compressionType: Compress.ZLIB_COMPRESSION_TYPE_LOOKUP[args[0]]
         });
@@ -164,13 +164,13 @@ var Compress = {
     /**
      * Zlib Inflate operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_zlib_inflate: function(input, args) {
+    runZlibInflate: function(input, args) {
         // Deal with character encoding issues
-        input = Utils.str_to_byte_array(Utils.byte_array_to_utf8(input));
+        input = Utils.strToByteArray(Utils.byteArrayToUtf8(input));
         var inflate = new Zlib.Inflate(input, {
             index: args[0],
             bufferSize: args[1],
@@ -191,11 +191,11 @@ var Compress = {
     /**
      * Gzip operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_gzip: function(input, args) {
+    runGzip: function(input, args) {
         var filename = args[1],
             comment = args[2],
             options = {
@@ -224,13 +224,13 @@ var Compress = {
     /**
      * Gunzip operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_gunzip: function(input, args) {
+    runGunzip: function(input, args) {
         // Deal with character encoding issues
-        input = Utils.str_to_byte_array(Utils.byte_array_to_utf8(input));
+        input = Utils.strToByteArray(Utils.byteArrayToUtf8(input));
         var gunzip = new Zlib.Gunzip(input);
         return Array.prototype.slice.call(gunzip.decompress());
     },
@@ -262,15 +262,15 @@ var Compress = {
     /**
      * Zip operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_pkzip: function(input, args) {
-        var password = Utils.str_to_byte_array(args[2]),
+    runPkzip: function(input, args) {
+        var password = Utils.strToByteArray(args[2]),
             options = {
-                filename: Utils.str_to_byte_array(args[0]),
-                comment: Utils.str_to_byte_array(args[1]),
+                filename: Utils.strToByteArray(args[0]),
+                comment: Utils.strToByteArray(args[1]),
                 compressionMethod: Compress.ZIP_COMPRESSION_METHOD_LOOKUP[args[3]],
                 os: Compress.ZIP_OS_LOOKUP[args[4]],
                 deflateOption: {
@@ -295,13 +295,13 @@ var Compress = {
     /**
      * Unzip operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_pkunzip: function(input, args) {
+    runPkunzip: function(input, args) {
         var options = {
-                password: Utils.str_to_byte_array(args[0]),
+                password: Utils.strToByteArray(args[0]),
                 verify: args[1]
             },
             file = "",
@@ -313,7 +313,7 @@ var Compress = {
         
         window.uzip = unzip;
         for (var i = 0; i < filenames.length; i++) {
-            file = Utils.byte_array_to_utf8(unzip.decompress(filenames[i]));
+            file = Utils.byteArrayToUtf8(unzip.decompress(filenames[i]));
             output += "<div class='panel panel-default'>" +
                 "<div class='panel-heading' role='tab' id='heading" + i + "'>" +
                 "<h4 class='panel-title'>" +
@@ -322,7 +322,7 @@ var Compress = {
                 filenames[i] + "<span class='pull-right'>" + file.length.toLocaleString() + " bytes</span></a></h4></div>" +
                 "<div id='collapse" + i + "' class='panel-collapse collapse' role='tabpanel' aria-labelledby='heading" + i + "'>" +
                 "<div class='panel-body'>" +
-                Utils.escape_html(file) + "</div></div></div>";
+                Utils.escapeHtml(file) + "</div></div></div>";
         }
         
         return output + "</div>";
@@ -332,17 +332,17 @@ var Compress = {
     /**
      * Bzip2 Decompress operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_bzip2_decompress: function(input, args) {
+    runBzip2Decompress: function(input, args) {
         var compressed = new Uint8Array(input),
-            bzip2_reader,
+            bzip2Reader,
             plain = "";
             
-        bzip2_reader = bzip2.array(compressed);
-        plain = bzip2.simple(bzip2_reader);
+        bzip2Reader = bzip2.array(compressed);
+        plain = bzip2.simple(bzip2Reader);
         return plain;
     },
     

+ 25 - 25
src/js/operations/Convert.js

@@ -64,12 +64,12 @@ var Convert = {
      * @param {Object[]} args
      * @returns {number}
      */
-    run_distance: function (input, args) {
-        var input_units = args[0],
-            output_units = args[1];
+    runDistance: function (input, args) {
+        var inputUnits = args[0],
+            outputUnits = args[1];
 
-        input = input * Convert.DISTANCE_FACTOR[input_units];
-        return input / Convert.DISTANCE_FACTOR[output_units];
+        input = input * Convert.DISTANCE_FACTOR[inputUnits];
+        return input / Convert.DISTANCE_FACTOR[outputUnits];
         // TODO Remove rounding errors (e.g. 1.000000000001)
     },
 
@@ -145,12 +145,12 @@ var Convert = {
      * @param {Object[]} args
      * @returns {number}
      */
-    run_data_size: function (input, args) {
-        var input_units = args[0],
-            output_units = args[1];
+    runDataSize: function (input, args) {
+        var inputUnits = args[0],
+            outputUnits = args[1];
 
-        input = input * Convert.DATA_FACTOR[input_units];
-        return input / Convert.DATA_FACTOR[output_units];
+        input = input * Convert.DATA_FACTOR[inputUnits];
+        return input / Convert.DATA_FACTOR[outputUnits];
     },
 
 
@@ -225,12 +225,12 @@ var Convert = {
      * @param {Object[]} args
      * @returns {number}
      */
-    run_area: function (input, args) {
-        var input_units = args[0],
-            output_units = args[1];
+    runArea: function (input, args) {
+        var inputUnits = args[0],
+            outputUnits = args[1];
 
-        input = input * Convert.AREA_FACTOR[input_units];
-        return input / Convert.AREA_FACTOR[output_units];
+        input = input * Convert.AREA_FACTOR[inputUnits];
+        return input / Convert.AREA_FACTOR[outputUnits];
     },
 
 
@@ -336,12 +336,12 @@ var Convert = {
      * @param {Object[]} args
      * @returns {number}
      */
-    run_mass: function (input, args) {
-        var input_units = args[0],
-            output_units = args[1];
+    runMass: function (input, args) {
+        var inputUnits = args[0],
+            outputUnits = args[1];
 
-        input = input * Convert.MASS_FACTOR[input_units];
-        return input / Convert.MASS_FACTOR[output_units];
+        input = input * Convert.MASS_FACTOR[inputUnits];
+        return input / Convert.MASS_FACTOR[outputUnits];
     },
 
 
@@ -401,12 +401,12 @@ var Convert = {
      * @param {Object[]} args
      * @returns {number}
      */
-    run_speed: function (input, args) {
-        var input_units = args[0],
-            output_units = args[1];
+    runSpeed: function (input, args) {
+        var inputUnits = args[0],
+            outputUnits = args[1];
 
-        input = input * Convert.SPEED_FACTOR[input_units];
-        return input / Convert.SPEED_FACTOR[output_units];
+        input = input * Convert.SPEED_FACTOR[inputUnits];
+        return input / Convert.SPEED_FACTOR[outputUnits];
     },
 
 };

+ 13 - 13
src/js/operations/DateTime.js

@@ -24,7 +24,7 @@ var DateTime = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_from_unix_timestamp: function(input, args) {
+    runFromUnixTimestamp: function(input, args) {
         var units = args[0],
             d;
         
@@ -55,7 +55,7 @@ var DateTime = {
      * @param {Object[]} args
      * @returns {number}
      */
-    run_to_unix_timestamp: function(input, args) {
+    runToUnixTimestamp: function(input, args) {
         var units = args[0],
             d = moment(input);
         
@@ -130,21 +130,21 @@ var DateTime = {
      * @param {Object[]} args
      * @returns {html}
      */
-    run_translate_format: function(input, args) {
-        var input_format = args[1],
-            input_timezone = args[2],
-            output_format = args[3],
-            output_timezone = args[4],
+    runTranslateFormat: function(input, args) {
+        var inputFormat = args[1],
+            inputTimezone = args[2],
+            outputFormat = args[3],
+            outputTimezone = args[4],
             date;
 
         try {
-            date = moment.tz(input, input_format, input_timezone);
+            date = moment.tz(input, inputFormat, inputTimezone);
             if (!date || date.format() === "Invalid date") throw Error;
         } catch(err) {
             return "Invalid format.\n\n" + DateTime.FORMAT_EXAMPLES;
         }
         
-        return date.tz(output_timezone).format(output_format);
+        return date.tz(outputTimezone).format(outputFormat);
     },
     
     
@@ -155,14 +155,14 @@ var DateTime = {
      * @param {Object[]} args
      * @returns {html}
      */
-    run_parse: function(input, args) {
-        var input_format = args[1],
-            input_timezone = args[2],
+    runParse: function(input, args) {
+        var inputFormat = args[1],
+            inputTimezone = args[2],
             date,
             output = "";
             
         try {
-            date = moment.tz(input, input_format, input_timezone);
+            date = moment.tz(input, inputFormat, inputTimezone);
             if (!date || date.format() === "Invalid date") throw Error;
         } catch(err) {
             return "Invalid format.\n\n" + DateTime.FORMAT_EXAMPLES;

+ 15 - 15
src/js/operations/Endian.js

@@ -32,39 +32,39 @@ var Endian = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_swap_endianness: function(input, args) {
-        var data_format = args[0],
-            word_length = args[1],
-            pad_incomplete_words = args[2],
+    runSwapEndianness: function(input, args) {
+        var dataFormat = args[0],
+            wordLength = args[1],
+            padIncompleteWords = args[2],
             data = [],
             result = [],
             words = [],
             i = 0,
             j = 0;
             
-        if (word_length <= 0) {
+        if (wordLength <= 0) {
             return "Word length must be greater than 0";
         }
             
         // Convert input to raw data based on specified data format
-        switch (data_format) {
+        switch (dataFormat) {
             case "Hex":
-                data = Utils.from_hex(input);
+                data = Utils.fromHex(input);
                 break;
             case "Raw":
-                data = Utils.str_to_byte_array(input);
+                data = Utils.strToByteArray(input);
                 break;
             default:
                 data = input;
         }
         
         // Split up into words
-        for (i = 0; i < data.length; i += word_length) {
-            var word = data.slice(i, i + word_length);
+        for (i = 0; i < data.length; i += wordLength) {
+            var word = data.slice(i, i + wordLength);
             
             // Pad word if too short
-            if (pad_incomplete_words && word.length < word_length){
-                for (j = word.length; j < word_length; j++) {
+            if (padIncompleteWords && word.length < wordLength){
+                for (j = word.length; j < wordLength; j++) {
                     word.push(0);
                 }
             }
@@ -81,11 +81,11 @@ var Endian = {
         }
         
         // Convert data back to specified data format
-        switch (data_format) {
+        switch (dataFormat) {
             case "Hex":
-                return Utils.to_hex(result);
+                return Utils.toHex(result);
             case "Raw":
-                return Utils.byte_array_to_utf8(result);
+                return Utils.byteArrayToUtf8(result);
             default:
                 return result;
         }

+ 25 - 25
src/js/operations/Entropy.js

@@ -18,14 +18,14 @@ var Entropy = {
     /**
      * Entropy operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {html}
      */
-    run_entropy: function(input, args) {
-        var chunk_size = args[0],
+    runEntropy: function(input, args) {
+        var chunkSize = args[0],
             output = "",
-            entropy = Entropy._calc_entropy(input);
+            entropy = Entropy._calcEntropy(input);
         
         output += "Shannon entropy: " + entropy + "\n" +
             "<br><canvas id='chart-area'></canvas><br>\n" +
@@ -35,14 +35,14 @@ var Entropy = {
             "The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.\n\n" +
             "<br><script>\
                 var canvas = document.getElementById('chart-area'),\
-                    parent_rect = canvas.parentNode.getBoundingClientRect(),\
+                    parentRect = canvas.parentNode.getBoundingClientRect(),\
                     entropy = " + entropy + ",\
-                    height = parent_rect.height * 0.25;\
+                    height = parentRect.height * 0.25;\
                 \
-                canvas.width = parent_rect.width * 0.95;\
+                canvas.width = parentRect.width * 0.95;\
                 canvas.height = height > 150 ? 150 : height;\
                 \
-                CanvasComponents.draw_scale_bar(canvas, entropy, 8, [\
+                CanvasComponents.drawScaleBar(canvas, entropy, 8, [\
                     {\
                         label: 'English text',\
                         min: 3.5,\
@@ -55,11 +55,11 @@ var Entropy = {
                 ]);\
             </script>";
         
-        var chunk_entropy = 0;
-        if (chunk_size !== 0) {
-            for (var i = 0; i < input.length; i += chunk_size) {
-                chunk_entropy = Entropy._calc_entropy(input.slice(i, i+chunk_size));
-                output += "Bytes " + i + " to " + (i+chunk_size) + ": " + chunk_entropy + "\n";
+        var chunkEntropy = 0;
+        if (chunkSize !== 0) {
+            for (var i = 0; i < input.length; i += chunkSize) {
+                chunkEntropy = Entropy._calcEntropy(input.slice(i, i+chunkSize));
+                output += "Bytes " + i + " to " + (i+chunkSize) + ": " + chunkEntropy + "\n";
             }
         } else {
             output += "Chunk size cannot be 0.";
@@ -78,17 +78,17 @@ var Entropy = {
     /**
      * Frequency distribution operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {html}
      */
-    run_freq_distrib: function (input, args) {
+    runFreqDistrib: function (input, args) {
         if (!input.length) return "No data";
         
         var distrib = new Array(256),
             percentages = new Array(256),
             len = input.length,
-            show_zeroes = args[0];
+            showZeroes = args[0];
         
         // Initialise distrib to 0
         for (var i = 0; i < 256; i++) {
@@ -115,19 +115,19 @@ var Entropy = {
             "\n\nByte   Percentage\n" +
             "<script>\
                 var canvas = document.getElementById('chart-area'),\
-                    parent_rect = canvas.parentNode.getBoundingClientRect(),\
+                    parentRect = canvas.parentNode.getBoundingClientRect(),\
                     scores = " + JSON.stringify(percentages) + ";\
                 \
-                canvas.width = parent_rect.width * 0.95;\
-                canvas.height = parent_rect.height * 0.9;\
+                canvas.width = parentRect.width * 0.95;\
+                canvas.height = parentRect.height * 0.9;\
                 \
-                CanvasComponents.draw_bar_chart(canvas, scores, 'Byte', 'Frequency %', 16, 6);\
+                CanvasComponents.drawBarChart(canvas, scores, 'Byte', 'Frequency %', 16, 6);\
             </script>";
                 
         for (i = 0; i < 256; i++) {
-            if (distrib[i] || show_zeroes) {
+            if (distrib[i] || showZeroes) {
                 output += " " + Utils.hex(i, 2) + "    (" +
-                        Utils.pad_right(percentages[i].toFixed(2).replace(".00", "") + "%)", 8) +
+                        Utils.padRight(percentages[i].toFixed(2).replace(".00", "") + "%)", 8) +
                         Array(Math.ceil(percentages[i])+1).join("|") + "\n";
             }
         }
@@ -140,13 +140,13 @@ var Entropy = {
      * Calculates the Shannon entropy for a given chunk of data.
      *
      * @private
-     * @param {byte_array} data
+     * @param {byteArray} data
      * @returns {number}
      */
-    _calc_entropy: function(data) {
+    _calcEntropy: function(data) {
         var prob = [],
             uniques = data.unique(),
-            str = Utils.byte_array_to_chars(data);
+            str = Utils.byteArrayToChars(data);
             
         for (var i = 0; i < uniques.length; i++) {
             prob.push(str.count(Utils.chr(uniques[i])) / data.length);

+ 69 - 69
src/js/operations/Extract.js

@@ -10,29 +10,29 @@
 var Extract = {
 
     /**
-     * Runs search operations across the input data using refular expressions.
+     * Runs search operations across the input data using regular expressions.
      *
      * @private
      * @param {string} input
-     * @param {RegExp} search_regex
-     * @param {RegExp} remove_regex - A regular expression defining results to remove from the
+     * @param {RegExp} searchRegex
+     * @param {RegExp} removeRegex - A regular expression defining results to remove from the
      *      final list
-     * @param {boolean} include_total - Whether or not to include the total number of results
+     * @param {boolean} includeTotal - Whether or not to include the total number of results
      * @returns {string}
      */
-    _search: function(input, search_regex, remove_regex, include_total) {
+    _search: function(input, searchRegex, removeRegex, includeTotal) {
         var output = "",
             total = 0,
             match;
             
-        while ((match = search_regex.exec(input))) {
-            if (remove_regex && remove_regex.test(match[0]))
+        while ((match = searchRegex.exec(input))) {
+            if (removeRegex && removeRegex.test(match[0]))
                 continue;
             total++;
             output += match[0] + "\n";
         }
         
-        if (include_total)
+        if (includeTotal)
             output = "Total found: " + total + "\n\n" + output;
             
         return output;
@@ -57,13 +57,13 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_strings: function(input, args) {
-        var min_len = args[0] || Extract.MIN_STRING_LEN,
-            display_total = args[1],
+    runStrings: function(input, args) {
+        var minLen = args[0] || Extract.MIN_STRING_LEN,
+            displayTotal = args[1],
             strings = "[A-Z\\d/\\-:.,_$%'\"()<>= !\\[\\]{}@]",
-            regex = new RegExp(strings + "{" + min_len + ",}", "ig");
+            regex = new RegExp(strings + "{" + minLen + ",}", "ig");
             
-        return Extract._search(input, regex, null, display_total);
+        return Extract._search(input, regex, null, displayTotal);
     },
     
     
@@ -90,37 +90,37 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_ip: function(input, args) {
-        var include_ipv4  = args[0],
-            include_ipv6  = args[1],
-            remove_local  = args[2],
-            display_total = args[3],
+    runIp: function(input, args) {
+        var includeIpv4  = args[0],
+            includeIpv6  = args[1],
+            removeLocal  = args[2],
+            displayTotal = args[3],
             ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?",
             ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})((([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})",
             ips  = "";
         
-        if (include_ipv4 && include_ipv6) {
+        if (includeIpv4 && includeIpv6) {
             ips = ipv4 + "|" + ipv6;
-        } else if (include_ipv4) {
+        } else if (includeIpv4) {
             ips = ipv4;
-        } else if (include_ipv6) {
+        } else if (includeIpv6) {
             ips = ipv6;
         }
         
         if (ips) {
             var regex = new RegExp(ips, "ig");
             
-            if (remove_local) {
+            if (removeLocal) {
                 var ten = "10\\..+",
                     oneninetwo = "192\\.168\\..+",
                     oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
                     onetwoseven = "127\\..+",
-                    remove_regex = new RegExp("^(?:" + ten + "|" + oneninetwo +
+                    removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
                         "|" + oneseventwo + "|" + onetwoseven + ")");
                         
-                return Extract._search(input, regex, remove_regex, display_total);
+                return Extract._search(input, regex, removeRegex, displayTotal);
             } else {
-                return Extract._search(input, regex, null, display_total);
+                return Extract._search(input, regex, null, displayTotal);
             }
         } else {
             return "";
@@ -135,11 +135,11 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_email: function(input, args) {
-        var display_total = args[0],
+    runEmail: function(input, args) {
+        var displayTotal = args[0],
             regex = /\w[-.\w]*@[-\w]+(?:\.[-\w]+)*\.[A-Z]{2,4}/ig;
             
-        return Extract._search(input, regex, null, display_total);
+        return Extract._search(input, regex, null, displayTotal);
     },
     
     
@@ -150,11 +150,11 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_mac: function(input, args) {
-        var display_total = args[0],
+    runMac: function(input, args) {
+        var displayTotal = args[0],
             regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig;
             
-        return Extract._search(input, regex, null, display_total);
+        return Extract._search(input, regex, null, displayTotal);
     },
     
     
@@ -165,8 +165,8 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_urls: function(input, args) {
-        var display_total = args[0],
+    runUrls: function(input, args) {
+        var displayTotal = args[0],
             protocol = "[A-Z]+://",
             hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
             port = ":\\d+",
@@ -175,7 +175,7 @@ var Extract = {
         path += "(?:[.!,?]+[^.!,?;\"'<>()\\[\\]{}\\s\\x7F-\\xFF]+)*";
         var regex = new RegExp(protocol + hostname + "(?:" + port +
             ")?(?:" + path + ")?", "ig");
-        return Extract._search(input, regex, null, display_total);
+        return Extract._search(input, regex, null, displayTotal);
     },
     
     
@@ -186,14 +186,14 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_domains: function(input, args) {
-        var display_total = args[0],
+    runDomains: function(input, args) {
+        var displayTotal = args[0],
             protocol = "https?://",
             hostname = "[-\\w\\.]+",
             tld = "\\.(?:com|net|org|biz|info|co|uk|onion|int|mobi|name|edu|gov|mil|eu|ac|ae|af|de|ca|ch|cn|cy|es|gb|hk|il|in|io|tv|me|nl|no|nz|ro|ru|tr|us|az|ir|kz|uz|pk)+",
             regex = new RegExp("(?:" + protocol + ")?" + hostname + tld, "ig");
         
-        return Extract._search(input, regex, null, display_total);
+        return Extract._search(input, regex, null, displayTotal);
     },
     
     
@@ -215,29 +215,29 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_file_paths: function(input, args) {
-        var include_win_path = args[0],
-            include_unix_path = args[1],
-            display_total = args[2],
-            win_drive = "[A-Z]:\\\\",
-            win_name = "[A-Z\\d][A-Z\\d\\- '_\\(\\)]{0,61}",
-            win_ext = "[A-Z\\d]{1,6}",
-            win_path = win_drive + "(?:" + win_name + "\\\\?)*" + win_name +
-                "(?:\\." + win_ext + ")?",
-            unix_path = "(?:/[A-Z\\d.][A-Z\\d\\-.]{0,61})+",
-            file_paths = "";
+    runFilePaths: function(input, args) {
+        var includeWinPath = args[0],
+            includeUnixPath = args[1],
+            displayTotal = args[2],
+            winDrive = "[A-Z]:\\\\",
+            winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)]{0,61}",
+            winExt = "[A-Z\\d]{1,6}",
+            winPath = winDrive + "(?:" + winName + "\\\\?)*" + winName +
+                "(?:\\." + winExt + ")?",
+            unixPath = "(?:/[A-Z\\d.][A-Z\\d\\-.]{0,61})+",
+            filePaths = "";
         
-        if (include_win_path && include_unix_path) {
-            file_paths = win_path + "|" + unix_path;
-        } else if (include_win_path) {
-            file_paths = win_path;
-        } else if (include_unix_path) {
-            file_paths = unix_path;
+        if (includeWinPath && includeUnixPath) {
+            filePaths = winPath + "|" + unixPath;
+        } else if (includeWinPath) {
+            filePaths = winPath;
+        } else if (includeUnixPath) {
+            filePaths = unixPath;
         }
         
-        if (file_paths) {
-            var regex = new RegExp(file_paths, "ig");
-            return Extract._search(input, regex, null, display_total);
+        if (filePaths) {
+            var regex = new RegExp(filePaths, "ig");
+            return Extract._search(input, regex, null, displayTotal);
         } else {
             return "";
         }
@@ -251,14 +251,14 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_dates: function(input, args) {
-        var display_total = args[0],
+    runDates: function(input, args) {
+        var displayTotal = args[0],
             date1 = "(?:19|20)\\d\\d[- /.](?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])", // yyyy-mm-dd
             date2 = "(?:0[1-9]|[12][0-9]|3[01])[- /.](?:0[1-9]|1[012])[- /.](?:19|20)\\d\\d", // dd/mm/yyyy
             date3 = "(?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])[- /.](?:19|20)\\d\\d", // mm/dd/yyyy
             regex = new RegExp(date1 + "|" + date2 + "|" + date3, "ig");
             
-        return Extract._search(input, regex, null, display_total);
+        return Extract._search(input, regex, null, displayTotal);
     },
     
     
@@ -269,29 +269,29 @@ var Extract = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_all_idents: function(input, args) {
+    runAllIdents: function(input, args) {
         var output = "";
         output += "IP addresses\n";
-        output += Extract.run_ip(input, [true, true, false]);
+        output += Extract.runIp(input, [true, true, false]);
         
         output += "\nEmail addresses\n";
-        output += Extract.run_email(input, []);
+        output += Extract.runEmail(input, []);
         
         output += "\nMAC addresses\n";
-        output += Extract.run_mac(input, []);
+        output += Extract.runMac(input, []);
         
         output += "\nURLs\n";
-        output += Extract.run_urls(input, []);
+        output += Extract.runUrls(input, []);
         
         output += "\nDomain names\n";
-        output += Extract.run_domains(input, []);
+        output += Extract.runDomains(input, []);
         
         output += "\nFile paths\n";
-        output += Extract.run_file_paths(input, [true, true]);
+        output += Extract.runFilePaths(input, [true, true]);
         
         output += "\nDates\n";
-        output += Extract.run_dates(input, []);
+        output += Extract.runDates(input, []);
         return output;
     },
-    
+
 };

+ 19 - 19
src/js/operations/FileType.js

@@ -12,12 +12,12 @@ var FileType = {
     /**
      * Detect File Type operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_detect: function(input, args) {
-        var type = FileType._magic_type(input);
+    runDetect: function(input, args) {
+        var type = FileType._magicType(input);
 
         if (!type) {
             return "Unknown file type. Have you tried checking the entropy of this data to determine whether it might be encrypted or compressed?";
@@ -43,26 +43,26 @@ var FileType = {
     /**
      * Scan for Embedded Files operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_scan_for_embedded_files: function(input, args) {
+    runScanForEmbeddedFiles: function(input, args) {
         var output = "Scanning data for 'magic bytes' which may indicate embedded files. The following results may be false positives and should not be treat as reliable. Any suffiently long file is likely to contain these magic bytes coincidentally.\n",
             type,
-            ignore_common = args[0],
-            common_exts = ["ico", "ttf", ""],
-            num_found = 0,
-            num_common_found = 0;
+            ignoreCommon = args[0],
+            commonExts = ["ico", "ttf", ""],
+            numFound = 0,
+            numCommonFound = 0;
 
         for (var i = 0; i < input.length; i++) {
-            type = FileType._magic_type(input.slice(i));
+            type = FileType._magicType(input.slice(i));
             if (type) {
-                if (ignore_common && common_exts.indexOf(type.ext) > -1) {
-                    num_common_found++;
+                if (ignoreCommon && commonExts.indexOf(type.ext) > -1) {
+                    numCommonFound++;
                     continue;
                 }
-                num_found++;
+                numFound++;
                 output += "\nOffset " + i + " (0x" + Utils.hex(i) + "):\n" +
                     "  File extension: " + type.ext + "\n" +
                     "  MIME type:      " + type.mime + "\n";
@@ -73,13 +73,13 @@ var FileType = {
             }
         }
 
-        if (num_found === 0) {
+        if (numFound === 0) {
             output += "\nNo embedded files were found.";
         }
 
-        if (num_common_found > 0) {
-            output += "\n\n" + num_common_found;
-            output += num_common_found === 1 ?
+        if (numCommonFound > 0) {
+            output += "\n\n" + numCommonFound;
+            output += numCommonFound === 1 ?
                 " file type was detected that has a common byte sequence. This is likely to be a false positive." :
                 " file types were detected that have common byte sequences. These are likely to be false positives.";
             output += " Run this operation with the 'Ignore common byte sequences' option unchecked to see details.";
@@ -94,13 +94,13 @@ var FileType = {
      * extension and mime type.
      *
      * @private
-     * @param {byte_array} buf
+     * @param {byteArray} buf
      * @returns {Object} type
      * @returns {string} type.ext - File extension
      * @returns {string} type.mime - Mime type
      * @returns {string} [type.desc] - Description
      */
-    _magic_type: function (buf) {
+    _magicType: function (buf) {
         if (!(buf && buf.length > 1)) {
             return null;
         }

+ 31 - 31
src/js/operations/HTML.js

@@ -27,35 +27,35 @@ var HTML = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_entity: function(input, args) {
-        var convert_all = args[0],
+    runToEntity: function(input, args) {
+        var convertAll = args[0],
             numeric = args[1] === "Numeric entities",
             hexa = args[1] === "Hex entities";
 
-        var charcodes = Utils.str_to_charcode(input);
+        var charcodes = Utils.strToCharcode(input);
         var output = "";
 
         for (var i = 0; i < charcodes.length; i++) {
-            if (convert_all && numeric) {
+            if (convertAll && numeric) {
                 output += "&#" + charcodes[i] + ";";
-            } else if (convert_all && hexa) {
+            } else if (convertAll && hexa) {
                 output += "&#x" + Utils.hex(charcodes[i]) + ";";
-            } else if (convert_all) {
-                output += HTML._byte_to_entity[charcodes[i]] || "&#" + charcodes[i] + ";";
+            } else if (convertAll) {
+                output += HTML._byteToEntity[charcodes[i]] || "&#" + charcodes[i] + ";";
             } else if (numeric) {
-                if (charcodes[i] > 255 || HTML._byte_to_entity.hasOwnProperty(charcodes[i])) {
+                if (charcodes[i] > 255 || HTML._byteToEntity.hasOwnProperty(charcodes[i])) {
                     output += "&#" + charcodes[i] + ";";
                 } else {
                     output += Utils.chr(charcodes[i]);
                 }
             } else if (hexa) {
-                if (charcodes[i] > 255 || HTML._byte_to_entity.hasOwnProperty(charcodes[i])) {
+                if (charcodes[i] > 255 || HTML._byteToEntity.hasOwnProperty(charcodes[i])) {
                     output += "&#x" + Utils.hex(charcodes[i]) + ";";
                 } else {
                     output += Utils.chr(charcodes[i]);
                 }
             } else {
-                output += HTML._byte_to_entity[charcodes[i]] || (
+                output += HTML._byteToEntity[charcodes[i]] || (
                     charcodes[i] > 255 ?
                         "&#" + charcodes[i] + ";" :
                         Utils.chr(charcodes[i])
@@ -73,7 +73,7 @@ var HTML = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_from_entity: function(input, args) {
+    runFromEntity: function(input, args) {
         var regex = /&(#?x?[a-zA-Z0-9]{1,8});/g,
             output = "",
             m,
@@ -85,7 +85,7 @@ var HTML = {
                 output += input[i++];
 
             // Add match
-            var bite = HTML._entity_to_byte[m[1]];
+            var bite = HTML._entityToByte[m[1]];
             if (bite) {
                 output += Utils.chr(bite);
             } else if (!bite && m[1][0] === "#" && m[1].length > 1 && /^#\d{1,5}$/.test(m[1])) {
@@ -130,17 +130,17 @@ var HTML = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_strip_tags: function(input, args) {
-        var remove_indentation = args[0],
-            remove_line_breaks = args[1];
+    runStripTags: function(input, args) {
+        var removeIndentation = args[0],
+            removeLineBreaks = args[1];
 
-        input = Utils.strip_html_tags(input);
+        input = Utils.stripHtmlTags(input);
 
-        if (remove_indentation) {
+        if (removeIndentation) {
             input = input.replace(/\n[ \f\t]+/g, "\n");
         }
 
-        if (remove_line_breaks) {
+        if (removeLineBreaks) {
             input = input.replace(/^\s*\n/, "") // first line
                          .replace(/(\n\s*){2,}/g, "\n"); // all others
         }
@@ -156,7 +156,7 @@ var HTML = {
      * @param {Object[]} args
      * @returns {html}
      */
-    run_parse_colour_code: function(input, args) {
+    runParseColourCode: function(input, args) {
         var m = null,
             r = 0, g = 0, b = 0, a = 1;
 
@@ -177,7 +177,7 @@ var HTML = {
             var h_ = parseFloat(m[1]) / 360,
                 s_ = parseFloat(m[2]) / 100,
                 l_ = parseFloat(m[3]) / 100,
-                rgb_ = HTML._hsl_to_rgb(h_, s_, l_);
+                rgb_ = HTML._hslToRgb(h_, s_, l_);
 
             r = rgb_[0];
             g = rgb_[1];
@@ -195,7 +195,7 @@ var HTML = {
             b = Math.round(255 * (1 - y_) * (1 - k_));
         }
 
-        var hsl_ = HTML._rgb_to_hsl(r, g, b),
+        var hsl_ = HTML._rgbToHsl(r, g, b),
             h = Math.round(hsl_[0] * 360),
             s = Math.round(hsl_[1] * 100),
             l = Math.round(hsl_[2] * 100),
@@ -210,9 +210,9 @@ var HTML = {
         k = k.toFixed(2);
 
         var hex = "#" +
-                Utils.pad_left(Math.round(r).toString(16), 2) +
-                Utils.pad_left(Math.round(g).toString(16), 2) +
-                Utils.pad_left(Math.round(b).toString(16), 2),
+                Utils.padLeft(Math.round(r).toString(16), 2) +
+                Utils.padLeft(Math.round(g).toString(16), 2) +
+                Utils.padLeft(Math.round(b).toString(16), 2),
             rgb  = "rgb(" + r + ", " + g + ", " + b + ")",
             rgba = "rgba(" + r + ", " + g + ", " + b + ", " + a + ")",
             hsl  = "hsl(" + h + ", " + s + "%, " + l + "%)",
@@ -237,7 +237,7 @@ var HTML = {
                     var color = e.color.toRGB();\
                     document.getElementById('input-text').value = 'rgba(' +\
                         color.r + ', ' + color.g + ', ' + color.b + ', ' + color.a + ')';\
-                    window.app.auto_bake();\
+                    window.app.autoBake();\
                 });\
             </script>";
     },
@@ -246,7 +246,7 @@ var HTML = {
 
     /**
      * Converts an HSL color value to RGB. Conversion formula
-     * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
+     * adapted from http://en.wikipedia.org/wiki/HSL_colorSpace.
      * Assumes h, s, and l are contained in the set [0, 1] and
      * returns r, g, and b in the set [0, 255].
      *
@@ -258,7 +258,7 @@ var HTML = {
      * @param {number} l - The lightness
      * @return {Array} The RGB representation
      */
-    _hsl_to_rgb: function(h, s, l){
+    _hslToRgb: function(h, s, l){
         var r, g, b;
 
         if (s === 0){
@@ -286,7 +286,7 @@ var HTML = {
 
     /**
      * Converts an RGB color value to HSL. Conversion formula
-     * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
+     * adapted from http://en.wikipedia.org/wiki/HSL_colorSpace.
      * Assumes r, g, and b are contained in the set [0, 255] and
      * returns h, s, and l in the set [0, 1].
      *
@@ -298,7 +298,7 @@ var HTML = {
      * @param {number} b - The blue color value
      * @return {Array} The HSL representation
      */
-    _rgb_to_hsl: function(r, g, b) {
+    _rgbToHsl: function(r, g, b) {
         r /= 255; g /= 255; b /= 255;
         var max = Math.max(r, g, b),
             min = Math.min(r, g, b),
@@ -327,7 +327,7 @@ var HTML = {
      * @private
      * @constant
      */
-    _byte_to_entity: {
+    _byteToEntity: {
         34 : "&quot;",
         38 : "&amp;",
         39 : "&apos;",
@@ -591,7 +591,7 @@ var HTML = {
      * @private
      * @constant
      */
-    _entity_to_byte : {
+    _entityToByte : {
         "quot" : 34,
         "amp" : 38,
         "apos" : 39,

+ 6 - 6
src/js/operations/HTTP.js

@@ -18,11 +18,11 @@ var HTTP = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_strip_headers: function(input, args) {
-        var header_end = input.indexOf("\r\n\r\n") +
-            (header_end < 0) ? input.indexOf("\n\n") + 2 : header_end + 4;
+    runStripHeaders: function(input, args) {
+        var headerEnd = input.indexOf("\r\n\r\n") +
+            (headerEnd < 0) ? input.indexOf("\n\n") + 2 : headerEnd + 4;
             
-        return (header_end < 2) ? input : input.slice(header_end, input.length);
+        return (headerEnd < 2) ? input : input.slice(headerEnd, input.length);
     },
     
     
@@ -33,8 +33,8 @@ var HTTP = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse_user_agent: function(input, args) {
-        var ua = UAS_parser.parse(input);
+    runParseUserAgent: function(input, args) {
+        var ua = UAS_parser.parse(input); // eslint-disable-line camelcase
         
         return "Type: " + ua.type + "\n" +
             "Family: " + ua.uaFamily + "\n" +

+ 95 - 53
src/js/operations/Hash.js

@@ -1,4 +1,4 @@
-/* globals CryptoJS, Checksum */
+/* globals CryptoApi, CryptoJS, Checksum */
 
 /**
  * Hashing operations.
@@ -10,6 +10,30 @@
  * @namespace
  */
 var Hash = {
+
+    /**
+     * MD2 operation.
+     *
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runMD2: function (input, args) {
+        return Utils.toHexFast(CryptoApi.hash("md2", input, {}));
+    },
+
+
+    /**
+     * MD4 operation.
+     *
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runMD4: function (input, args) {
+        return Utils.toHexFast(CryptoApi.hash("md4", input, {}));
+    },
+
     
     /**
      * MD5 operation.
@@ -18,10 +42,22 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_md5: function (input, args) {
+    runMD5: function (input, args) {
         input = CryptoJS.enc.Latin1.parse(input); // Cast to WordArray
         return CryptoJS.MD5(input).toString(CryptoJS.enc.Hex);
     },
+
+
+    /**
+     * SHA0 operation.
+     *
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runSHA0: function (input, args) {
+        return Utils.toHexFast(CryptoApi.hash("sha0", input, {}));
+    },
     
     
     /**
@@ -31,7 +67,7 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sha1: function (input, args) {
+    runSHA1: function (input, args) {
         input = CryptoJS.enc.Latin1.parse(input);
         return CryptoJS.SHA1(input).toString(CryptoJS.enc.Hex);
     },
@@ -44,7 +80,7 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sha224: function (input, args) {
+    runSHA224: function (input, args) {
         input = CryptoJS.enc.Latin1.parse(input);
         return CryptoJS.SHA224(input).toString(CryptoJS.enc.Hex);
     },
@@ -57,7 +93,7 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sha256: function (input, args) {
+    runSHA256: function (input, args) {
         input = CryptoJS.enc.Latin1.parse(input);
         return CryptoJS.SHA256(input).toString(CryptoJS.enc.Hex);
     },
@@ -70,7 +106,7 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sha384: function (input, args) {
+    runSHA384: function (input, args) {
         input = CryptoJS.enc.Latin1.parse(input);
         return CryptoJS.SHA384(input).toString(CryptoJS.enc.Hex);
     },
@@ -83,7 +119,7 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sha512: function (input, args) {
+    runSHA512: function (input, args) {
         input = CryptoJS.enc.Latin1.parse(input);
         return CryptoJS.SHA512(input).toString(CryptoJS.enc.Hex);
     },
@@ -102,11 +138,11 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sha3: function (input, args) {
+    runSHA3: function (input, args) {
         input = CryptoJS.enc.Latin1.parse(input);
-        var sha3_length = args[0],
+        var sha3Length = args[0],
             options = {
-                outputLength: parseInt(sha3_length, 10)
+                outputLength: parseInt(sha3Length, 10)
             };
         return CryptoJS.SHA3(input, options).toString(CryptoJS.enc.Hex);
     },
@@ -119,7 +155,7 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_ripemd160: function (input, args) {
+    runRIPEMD160: function (input, args) {
         input = CryptoJS.enc.Latin1.parse(input);
         return CryptoJS.RIPEMD160(input).toString(CryptoJS.enc.Hex);
     },
@@ -138,8 +174,8 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_hmac: function (input, args) {
-        var hash_func = args[1];
+    runHMAC: function (input, args) {
+        var hashFunc = args[1];
         input = CryptoJS.enc.Latin1.parse(input);
         var execute = {
             "MD5": CryptoJS.HmacMD5(input, args[0]),
@@ -151,7 +187,7 @@ var Hash = {
             "SHA3": CryptoJS.HmacSHA3(input, args[0]),
             "RIPEMD-160": CryptoJS.HmacRIPEMD160(input, args[0]),
         };
-        return execute[hash_func].toString(CryptoJS.enc.Hex);
+        return execute[hashFunc].toString(CryptoJS.enc.Hex);
     },
     
     
@@ -162,23 +198,29 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_all: function (input, args) {
-        var byte_array = Utils.str_to_byte_array(input),
-            output = "MD5:         " + Hash.run_md5(input, []) +
-                "\nSHA1:        " + Hash.run_sha1(input, []) +
-                "\nSHA2 224:    " + Hash.run_sha224(input, []) +
-                "\nSHA2 256:    " + Hash.run_sha256(input, []) +
-                "\nSHA2 384:    " + Hash.run_sha384(input, []) +
-                "\nSHA2 512:    " + Hash.run_sha512(input, []) +
-                "\nSHA3 224:    " + Hash.run_sha3(input, ["224"]) +
-                "\nSHA3 256:    " + Hash.run_sha3(input, ["256"]) +
-                "\nSHA3 384:    " + Hash.run_sha3(input, ["384"]) +
-                "\nSHA3 512:    " + Hash.run_sha3(input, ["512"]) +
-                "\nRIPEMD-160:  " + Hash.run_ripemd160(input, []) +
+    runAll: function (input, args) {
+        var byteArray = Utils.strToByteArray(input),
+            output = "MD2:         " + Hash.runMD2(input, []) +
+                "\nMD4:         " + Hash.runMD4(input, []) +
+                "\nMD5:         " + Hash.runMD5(input, []) +
+                "\nSHA0:        " + Hash.runSHA0(input, []) +
+                "\nSHA1:        " + Hash.runSHA1(input, []) +
+                "\nSHA2 224:    " + Hash.runSHA224(input, []) +
+                "\nSHA2 256:    " + Hash.runSHA256(input, []) +
+                "\nSHA2 384:    " + Hash.runSHA384(input, []) +
+                "\nSHA2 512:    " + Hash.runSHA512(input, []) +
+                "\nSHA3 224:    " + Hash.runSHA3(input, ["224"]) +
+                "\nSHA3 256:    " + Hash.runSHA3(input, ["256"]) +
+                "\nSHA3 384:    " + Hash.runSHA3(input, ["384"]) +
+                "\nSHA3 512:    " + Hash.runSHA3(input, ["512"]) +
+                "\nRIPEMD-160:  " + Hash.runRIPEMD160(input, []) +
                 "\n\nChecksums:" +
-                "\nFletcher-16: " + Checksum.run_fletcher16(byte_array, []) +
-                "\nAdler-32:    " + Checksum.run_adler32(byte_array, []) +
-                "\nCRC-32:      " + Checksum.run_crc32(byte_array, []);
+                "\nFletcher-8:  " + Checksum.runFletcher8(byteArray, []) +
+                "\nFletcher-16: " + Checksum.runFletcher16(byteArray, []) +
+                "\nFletcher-32: " + Checksum.runFletcher32(byteArray, []) +
+                "\nFletcher-64: " + Checksum.runFletcher64(byteArray, []) +
+                "\nAdler-32:    " + Checksum.runAdler32(byteArray, []) +
+                "\nCRC-32:      " + Checksum.runCRC32(byteArray, []);
                 
         return output;
     },
@@ -191,38 +233,38 @@ var Hash = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_analyse: function(input, args) {
+    runAnalyse: function(input, args) {
         input = input.replace(/\s/g, "");
     
         var output = "",
-            byte_length = input.length / 2,
-            bit_length = byte_length * 8,
-            possible_hash_functions = [];
+            byteLength = input.length / 2,
+            bitLength = byteLength * 8,
+            possibleHashFunctions = [];
         
         if (!/^[a-f0-9]+$/i.test(input)) {
             return "Invalid hash";
         }
         
         output += "Hash length: " + input.length + "\n" +
-            "Byte length: " + byte_length + "\n" +
-            "Bit length:  " + bit_length + "\n\n" +
+            "Byte length: " + byteLength + "\n" +
+            "Bit length:  " + bitLength + "\n\n" +
             "Based on the length, this hash could have been generated by one of the following hashing functions:\n";
                 
-        switch (bit_length) {
+        switch (bitLength) {
             case 4:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "Fletcher-4",
                     "Luhn algorithm",
                     "Verhoeff algorithm",
                 ];
                 break;
             case 8:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "Fletcher-8",
                 ];
                 break;
             case 16:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "BSD checksum",
                     "CRC-16",
                     "SYSV checksum",
@@ -230,21 +272,21 @@ var Hash = {
                 ];
                 break;
             case 32:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "CRC-32",
                     "Fletcher-32",
                     "Adler-32",
                 ];
                 break;
             case 64:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "CRC-64",
                     "RIPEMD-64",
                     "SipHash",
                 ];
                 break;
             case 128:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "MD5",
                     "MD4",
                     "MD2",
@@ -255,7 +297,7 @@ var Hash = {
                 ];
                 break;
             case 160:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "SHA-1",
                     "SHA-0",
                     "FSB-160",
@@ -266,13 +308,13 @@ var Hash = {
                 ];
                 break;
             case 192:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "Tiger",
                     "HAVAL-192",
                 ];
                 break;
             case 224:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "SHA-224",
                     "SHA3-224",
                     "ECOH-224",
@@ -281,7 +323,7 @@ var Hash = {
                 ];
                 break;
             case 256:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "SHA-256",
                     "SHA3-256",
                     "BLAKE-256",
@@ -296,12 +338,12 @@ var Hash = {
                 ];
                 break;
             case 320:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "RIPEMD-320",
                 ];
                 break;
             case 384:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "SHA-384",
                     "SHA3-384",
                     "ECOH-384",
@@ -309,7 +351,7 @@ var Hash = {
                 ];
                 break;
             case 512:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "SHA-512",
                     "SHA3-512",
                     "BLAKE-512",
@@ -324,18 +366,18 @@ var Hash = {
                 ];
                 break;
             case 1024:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "Fowler-Noll-Vo",
                 ];
                 break;
             default:
-                possible_hash_functions = [
+                possibleHashFunctions = [
                     "Unknown"
                 ];
                 break;
         }
         
-        return output + possible_hash_functions.join("\n");
+        return output + possibleHashFunctions.join("\n");
     },
     
 };

+ 28 - 28
src/js/operations/Hexdump.js

@@ -30,14 +30,14 @@ var Hexdump = {
     /**
      * To Hexdump operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to: function(input, args) {
+    runTo: function(input, args) {
         var length = args[0] || Hexdump.WIDTH;
-        var upper_case = args[1];
-        var include_final_length = args[2];
+        var upperCase = args[1];
+        var includeFinalLength = args[2];
         
         var output = "", padding = 2;
         for (var i = 0; i < input.length; i += length) {
@@ -47,18 +47,18 @@ var Hexdump = {
                 hexa += Utils.hex(buff[j], padding) + " ";
             }
             
-            var line_no = Utils.hex(i, 8);
+            var lineNo = Utils.hex(i, 8);
             
-            if (upper_case) {
+            if (upperCase) {
                 hexa = hexa.toUpperCase();
-                line_no = line_no.toUpperCase();
+                lineNo = lineNo.toUpperCase();
             }
             
-            output += line_no + "  " +
-                Utils.pad_right(hexa, (length*(padding+1))) +
-                " |" + Utils.pad_right(Utils.printable(Utils.byte_array_to_chars(buff)), buff.length) + "|\n";
+            output += lineNo + "  " +
+                Utils.padRight(hexa, (length*(padding+1))) +
+                " |" + Utils.padRight(Utils.printable(Utils.byteArrayToChars(buff)), buff.length) + "|\n";
                 
-            if (include_final_length && i+buff.length === input.length) {
+            if (includeFinalLength && i+buff.length === input.length) {
                 output += Utils.hex(i+buff.length, 8) + "\n";
             }
         }
@@ -72,15 +72,15 @@ var Hexdump = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from: function(input, args) {
+    runFrom: function(input, args) {
         var output = [],
             regex = /^\s*(?:[\dA-F]{4,16}:?)?\s*((?:[\dA-F]{2}\s){1,8}(?:\s|[\dA-F]{2}-)(?:[\dA-F]{2}\s){1,8}|(?:[\dA-F]{2}\s|[\dA-F]{4}\s)+)/igm,
             block, line;
             
         while ((block = regex.exec(input))) {
-            line = Utils.from_hex(block[1].replace(/-/g, " "));
+            line = Utils.fromHex(block[1].replace(/-/g, " "));
             for (var i = 0; i < line.length; i++) {
                 output.push(line[i]);
             }
@@ -90,7 +90,7 @@ var Hexdump = {
         var w = (width - 13) / 4;
         // w should be the specified width of the hexdump and therefore a round number
         if (Math.floor(w) !== w || input.indexOf("\r") !== -1 || output.indexOf(13) !== -1) {
-            app.options.attempt_highlight = false;
+            app.options.attemptHighlight = false;
         }
         return output;
     },
@@ -105,7 +105,7 @@ var Hexdump = {
      * @param {Object[]} args
      * @returns {Object[]} pos
      */
-    highlight_to: function(pos, args) {
+    highlightTo: function(pos, args) {
         // Calculate overall selection
         var w = args[0] || 16,
             width = 14 + (w*4),
@@ -125,32 +125,32 @@ var Hexdump = {
         pos[0].end = line*width + 10 + offset*3 - 1;
         
         // Set up multiple selections for bytes
-        var start_line_num = Math.floor(pos[0].start / width);
-        var end_line_num = Math.floor(pos[0].end / width);
+        var startLineNum = Math.floor(pos[0].start / width);
+        var endLineNum = Math.floor(pos[0].end / width);
         
-        if (start_line_num === end_line_num) {
+        if (startLineNum === endLineNum) {
             pos.push(pos[0]);
         } else {
             start = pos[0].start;
-            end = (start_line_num+1) * width - w - 5;
+            end = (startLineNum+1) * width - w - 5;
             pos.push({ start: start, end: end });
             while (end < pos[0].end) {
-                start_line_num++;
-                start = start_line_num * width + 10;
-                end = (start_line_num+1) * width - w - 5;
+                startLineNum++;
+                start = startLineNum * width + 10;
+                end = (startLineNum+1) * width - w - 5;
                 if (end > pos[0].end) end = pos[0].end;
                 pos.push({ start: start, end: end });
             }
         }
         
         // Set up multiple selections for ASCII
-        var len = pos.length, line_num = 0;
+        var len = pos.length, lineNum = 0;
         start = 0;
         end = 0;
         for (var i = 1; i < len; i++) {
-            line_num = Math.floor(pos[i].start / width);
-            start = (((pos[i].start - (line_num * width)) - 10) / 3) + (width - w -2) + (line_num * width);
-            end = (((pos[i].end + 1 - (line_num * width)) - 10) / 3) + (width - w -2) + (line_num * width);
+            lineNum = Math.floor(pos[i].start / width);
+            start = (((pos[i].start - (lineNum * width)) - 10) / 3) + (width - w -2) + (lineNum * width);
+            end = (((pos[i].end + 1 - (lineNum * width)) - 10) / 3) + (width - w -2) + (lineNum * width);
             pos.push({ start: start, end: end });
         }
         return pos;
@@ -166,7 +166,7 @@ var Hexdump = {
      * @param {Object[]} args
      * @returns {Object[]} pos
      */
-    highlight_from: function(pos, args) {
+    highlightFrom: function(pos, args) {
         var w = args[0] || 16;
         var width = 14 + (w*4);
         

+ 213 - 213
src/js/operations/IP.js

@@ -34,26 +34,26 @@ var IP = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse_ip_range: function (input, args) {
-        var include_network_info = args[0],
-            enumerate_addresses = args[1],
-            allow_large_list = args[2];
+    runParseIpRange: function (input, args) {
+        var includeNetworkInfo = args[0],
+            enumerateAddresses = args[1],
+            allowLargeList = args[2];
         
         // Check what type of input we are looking at
-        var ipv4_cidr_regex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\/(\d\d?)\s*$/,
-            ipv4_range_regex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*-\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
-            ipv6_cidr_regex = /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\/(\d\d?\d?)\s*$/i,
-            ipv6_range_regex = /^\s*(((?=.*::)(?!.*::[^-]+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*-\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\17)::|:\b|(?![\dA-F])))|(?!\16\17)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
+        var ipv4CidrRegex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\/(\d\d?)\s*$/,
+            ipv4RangeRegex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*-\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
+            ipv6CidrRegex = /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\/(\d\d?\d?)\s*$/i,
+            ipv6RangeRegex = /^\s*(((?=.*::)(?!.*::[^-]+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*-\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\17)::|:\b|(?![\dA-F])))|(?!\16\17)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
             match;
         
-        if ((match = ipv4_cidr_regex.exec(input))) {
-            return IP._ipv4_cidr_range(match, include_network_info, enumerate_addresses, allow_large_list);
-        } else if ((match = ipv4_range_regex.exec(input))) {
-            return IP._ipv4_hyphenated_range(match, include_network_info, enumerate_addresses, allow_large_list);
-        } else if ((match = ipv6_cidr_regex.exec(input))) {
-            return IP._ipv6_cidr_range(match, include_network_info);
-        } else if ((match = ipv6_range_regex.exec(input))) {
-            return IP._ipv6_hyphenated_range(match, include_network_info);
+        if ((match = ipv4CidrRegex.exec(input))) {
+            return IP._ipv4CidrRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList);
+        } else if ((match = ipv4RangeRegex.exec(input))) {
+            return IP._ipv4HyphenatedRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList);
+        } else if ((match = ipv6CidrRegex.exec(input))) {
+            return IP._ipv6CidrRange(match, includeNetworkInfo);
+        } else if ((match = ipv6RangeRegex.exec(input))) {
+            return IP._ipv6HyphenatedRange(match, includeNetworkInfo);
         } else {
             return "Invalid input.\n\nEnter either a CIDR range (e.g. 10.0.0.0/24) or a hyphenated range (e.g. 10.0.0.0 - 10.0.1.0). IPv6 also supported.";
         }
@@ -64,12 +64,12 @@ var IP = {
      * @constant
      * @default
      */
-    IPv4_REGEX: /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
+    IPV4_REGEX: /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
     /**
      * @constant
      * @default
      */
-    IPv6_REGEX: /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
+    IPV6_REGEX: /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
     
     /**
      * Parse IPv6 address operation.
@@ -78,14 +78,14 @@ var IP = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse_ipv6: function (input, args) {
+    runParseIpv6: function (input, args) {
         var match,
             output = "";
         
-        if ((match = IP.IPv6_REGEX.exec(input))) {
-            var ipv6 = IP._str_to_ipv6(match[1]),
-                longhand = IP._ipv6_to_str(ipv6),
-                shorthand = IP._ipv6_to_str(ipv6, true);
+        if ((match = IP.IPV6_REGEX.exec(input))) {
+            var ipv6 = IP._strToIpv6(match[1]),
+                longhand = IP._ipv6ToStr(ipv6),
+                shorthand = IP._ipv6ToStr(ipv6, true);
                 
             output += "Longhand:  " + longhand + "\nShorthand: " + shorthand + "\n";
             
@@ -102,13 +102,13 @@ var IP = {
                 ipv6[3] === 0 && ipv6[4] === 0 && ipv6[5] === 0xffff) {
                 // IPv4-mapped IPv6 address
                 output += "\nIPv4-mapped IPv6 address detected. IPv6 clients will be handled natively by default, and IPv4 clients appear as IPv6 clients at their IPv4-mapped IPv6 address.";
-                output += "\nMapped IPv4 address: " + IP._ipv4_to_str((ipv6[6] << 16) + ipv6[7]);
+                output += "\nMapped IPv4 address: " + IP._ipv4ToStr((ipv6[6] << 16) + ipv6[7]);
                 output += "\nIPv4-mapped IPv6 addresses range: ::ffff:0:0/96";
             } else if (ipv6[0] === 0 && ipv6[1] === 0 && ipv6[2] === 0 &&
                 ipv6[3] === 0 && ipv6[4] === 0xffff && ipv6[5] === 0) {
                 // IPv4-translated address
                 output += "\nIPv4-translated address detected. Used by Stateless IP/ICMP Translation (SIIT). See RFCs 6145 and 6052 for more details.";
-                output += "\nTranslated IPv4 address: " + IP._ipv4_to_str((ipv6[6] << 16) + ipv6[7]);
+                output += "\nTranslated IPv4 address: " + IP._ipv4ToStr((ipv6[6] << 16) + ipv6[7]);
                 output += "\nIPv4-translated addresses range: ::ffff:0:0:0/96";
             } else if (ipv6[0] === 0x100) {
                 // Discard prefix per RFC 6666
@@ -118,50 +118,50 @@ var IP = {
                 ipv6[3] === 0 && ipv6[4] === 0 && ipv6[5] === 0) {
                 // IPv4/IPv6 translation per RFC 6052
                 output += "\n'Well-Known' prefix for IPv4/IPv6 translation detected. See RFC 6052 for more details.";
-                output += "\nTranslated IPv4 address: " + IP._ipv4_to_str((ipv6[6] << 16) + ipv6[7]);
+                output += "\nTranslated IPv4 address: " + IP._ipv4ToStr((ipv6[6] << 16) + ipv6[7]);
                 output += "\n'Well-Known prefix range: 64:ff9b::/96";
             } else if (ipv6[0] === 0x2001 && ipv6[1] === 0) {
                 // Teredo tunneling
                 output += "\nTeredo tunneling IPv6 address detected\n";
-                var server_ipv4  = (ipv6[2] << 16) + ipv6[3],
-                    udp_port     = (~ipv6[5]) & 0xffff,
-                    client_ipv4  = ~((ipv6[6] << 16) + ipv6[7]),
-                    flag_cone    = (ipv6[4] >>> 15) & 1,
-                    flag_r       = (ipv6[4] >>> 14) & 1,
-                    flag_random1 = (ipv6[4] >>> 10) & 15,
-                    flag_ug      = (ipv6[4] >>> 8) & 3,
-                    flag_random2 = ipv6[4] & 255;
+                var serverIpv4  = (ipv6[2] << 16) + ipv6[3],
+                    udpPort     = (~ipv6[5]) & 0xffff,
+                    clientIpv4  = ~((ipv6[6] << 16) + ipv6[7]),
+                    flagCone    = (ipv6[4] >>> 15) & 1,
+                    flagR       = (ipv6[4] >>> 14) & 1,
+                    flagRandom1 = (ipv6[4] >>> 10) & 15,
+                    flagUg      = (ipv6[4] >>> 8) & 3,
+                    flagRandom2 = ipv6[4] & 255;
                 
-                output += "\nServer IPv4 address: " + IP._ipv4_to_str(server_ipv4) +
-                    "\nClient IPv4 address: " + IP._ipv4_to_str(client_ipv4) +
-                    "\nClient UDP port:     " + udp_port +
+                output += "\nServer IPv4 address: " + IP._ipv4ToStr(serverIpv4) +
+                    "\nClient IPv4 address: " + IP._ipv4ToStr(clientIpv4) +
+                    "\nClient UDP port:     " + udpPort +
                     "\nFlags:" +
-                    "\n\tCone:    " + flag_cone;
+                    "\n\tCone:    " + flagCone;
                     
-                if (flag_cone) {
+                if (flagCone) {
                     output += " (Client is behind a cone NAT)";
                 } else {
                     output += " (Client is not behind a cone NAT)";
                 }
                 
-                output += "\n\tR:       " + flag_r;
+                output += "\n\tR:       " + flagR;
                 
-                if (flag_r) {
+                if (flagR) {
                     output += " Error: This flag should be set to 0. See RFC 5991 and RFC 4380.";
                 }
                     
-                output += "\n\tRandom1: " + Utils.bin(flag_random1, 4) +
-                    "\n\tUG:      " + Utils.bin(flag_ug, 2);
+                output += "\n\tRandom1: " + Utils.bin(flagRandom1, 4) +
+                    "\n\tUG:      " + Utils.bin(flagUg, 2);
                         
-                if (flag_ug) {
+                if (flagUg) {
                     output += " Error: This flag should be set to 00. See RFC 4380.";
                 }
                     
-                output += "\n\tRandom2: " + Utils.bin(flag_random2, 8);
+                output += "\n\tRandom2: " + Utils.bin(flagRandom2, 8);
                 
-                if (!flag_r && !flag_ug && flag_random1 && flag_random2) {
+                if (!flagR && !flagUg && flagRandom1 && flagRandom2) {
                     output += "\n\nThis is a valid Teredo address which complies with RFC 4380 and RFC 5991.";
-                } else if (!flag_r && !flag_ug) {
+                } else if (!flagR && !flagUg) {
                     output += "\n\nThis is a valid Teredo address which complies with RFC 4380, however it does not comply with RFC 5991 (Teredo Security Updates) as there are no randomised bits in the flag field.";
                 } else {
                     output += "\n\nThis is an invalid Teredo address.";
@@ -187,15 +187,15 @@ var IP = {
                 output += "\n6to4 transition IPv6 address detected. See RFC 3056 for more details." +
                     "\n6to4 prefix range: 2002::/16";
                 
-                var v4_addr = IP._ipv4_to_str((ipv6[1] << 16) + ipv6[2]),
-                    sla_id = ipv6[3],
-                    interface_id_str = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16),
-                    interface_id = new BigInteger(interface_id_str, 16);
+                var v4Addr = IP._ipv4ToStr((ipv6[1] << 16) + ipv6[2]),
+                    slaId = ipv6[3],
+                    interfaceIdStr = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16),
+                    interfaceId = new BigInteger(interfaceIdStr, 16);
                 
-                output += "\n\nEncapsulated IPv4 address: " + v4_addr +
-                    "\nSLA ID: " + sla_id +
-                    "\nInterface ID (base 16): " + interface_id_str +
-                    "\nInterface ID (base 10): " + interface_id.toString();
+                output += "\n\nEncapsulated IPv4 address: " + v4Addr +
+                    "\nSLA ID: " + slaId +
+                    "\nInterface ID (base 16): " + interfaceIdStr +
+                    "\nInterface ID (base 10): " + interfaceId.toString();
             } else if (ipv6[0] >= 0xfc00 && ipv6[0] <= 0xfdff) {
                 // Unique local address
                 output += "\nThis is a unique local address comparable to the IPv4 private addresses 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. See RFC 4193 for more details.";
@@ -229,9 +229,9 @@ var IP = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_change_ip_format: function(input, args) {
-        var in_format  = args[0],
-            out_format = args[1],
+    runChangeIpFormat: function(input, args) {
+        var inFormat = args[0],
+            outFormat = args[1],
             lines = input.split("\n"),
             output = "",
             j = 0;
@@ -239,54 +239,54 @@ var IP = {
         
         for (var i = 0; i < lines.length; i++) {
             if (lines[i] === "") continue;
-            var ba_ip = [];
+            var baIp = [];
             
-            if (in_format === out_format) {
+            if (inFormat === outFormat) {
                 output += lines[i] + "\n";
                 continue;
             }
             
             // Convert to byte array IP from input format
-            switch (in_format) {
+            switch (inFormat) {
                 case "Dotted Decimal":
                     var octets = lines[i].split(".");
                     for (j = 0; j < octets.length; j++) {
-                        ba_ip.push(parseInt(octets[j], 10));
+                        baIp.push(parseInt(octets[j], 10));
                     }
                     break;
                 case "Decimal":
                     var decimal = lines[i].toString();
-                    ba_ip.push(decimal >> 24 & 255);
-                    ba_ip.push(decimal >> 16 & 255);
-                    ba_ip.push(decimal >> 8 & 255);
-                    ba_ip.push(decimal & 255);
+                    baIp.push(decimal >> 24 & 255);
+                    baIp.push(decimal >> 16 & 255);
+                    baIp.push(decimal >> 8 & 255);
+                    baIp.push(decimal & 255);
                     break;
                 case "Hex":
-                    ba_ip = Utils.hex_to_byte_array(lines[i]);
+                    baIp = Utils.hexToByteArray(lines[i]);
                     break;
                 default:
                     throw "Unsupported input IP format";
             }
             
             // Convert byte array IP to output format
-            switch (out_format) {
+            switch (outFormat) {
                 case "Dotted Decimal":
-                    var dd_ip = "";
-                    for (j = 0; j < ba_ip.length; j++) {
-                        dd_ip += ba_ip[j] + ".";
+                    var ddIp = "";
+                    for (j = 0; j < baIp.length; j++) {
+                        ddIp += baIp[j] + ".";
                     }
-                    output += dd_ip.slice(0, dd_ip.length-1) + "\n";
+                    output += ddIp.slice(0, ddIp.length-1) + "\n";
                     break;
                 case "Decimal":
-                    var dec_ip = ((ba_ip[0] << 24) | (ba_ip[1] << 16) | (ba_ip[2] << 8) | ba_ip[3]) >>> 0;
-                    output += dec_ip.toString() + "\n";
+                    var decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0;
+                    output += decIp.toString() + "\n";
                     break;
                 case "Hex":
-                    var hex_ip = "";
-                    for (j = 0; j < ba_ip.length; j++) {
-                        hex_ip += Utils.hex(ba_ip[j]);
+                    var hexIp = "";
+                    for (j = 0; j < baIp.length; j++) {
+                        hexIp += Utils.hex(baIp[j]);
                     }
-                    output += hex_ip + "\n";
+                    output += hexIp + "\n";
                     break;
                 default:
                     throw "Unsupported output IP format";
@@ -320,20 +320,20 @@ var IP = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_group_ips: function(input, args) {
-        var delim = Utils.char_rep[args[0]],
+    runGroupIps: function(input, args) {
+        var delim = Utils.charRep[args[0]],
             cidr = args[1],
-            only_subnets = args[2],
-            ipv4_mask = cidr < 32 ? ~(0xFFFFFFFF >>> cidr) : 0xFFFFFFFF,
-            ipv6_mask = IP._gen_ipv6_mask(cidr),
+            onlySubnets = args[2],
+            ipv4Mask = cidr < 32 ? ~(0xFFFFFFFF >>> cidr) : 0xFFFFFFFF,
+            ipv6Mask = IP._genIpv6Mask(cidr),
             ips = input.split(delim),
-            ipv4_networks = {},
-            ipv6_networks = {},
+            ipv4Networks = {},
+            ipv6Networks = {},
             match = null,
             output = "",
             ip = null,
             network = null,
-            network_str = "";
+            networkStr = "";
             
         if (cidr < 0 || cidr > 127) {
             return "CIDR must be less than 32 for IPv4 or 128 for IPv6";
@@ -341,57 +341,57 @@ var IP = {
             
         // Parse all IPs and add to network dictionary
         for (var i = 0; i < ips.length; i++) {
-            if ((match = IP.IPv4_REGEX.exec(ips[i]))) {
-                ip = IP._str_to_ipv4(match[1]) >>> 0;
-                network = ip & ipv4_mask;
+            if ((match = IP.IPV4_REGEX.exec(ips[i]))) {
+                ip = IP._strToIpv4(match[1]) >>> 0;
+                network = ip & ipv4Mask;
                 
-                if (ipv4_networks.hasOwnProperty(network)) {
-                    ipv4_networks[network].push(ip);
+                if (ipv4Networks.hasOwnProperty(network)) {
+                    ipv4Networks[network].push(ip);
                 } else {
-                    ipv4_networks[network] = [ip];
+                    ipv4Networks[network] = [ip];
                 }
-            } else if ((match = IP.IPv6_REGEX.exec(ips[i]))) {
-                ip = IP._str_to_ipv6(match[1]);
+            } else if ((match = IP.IPV6_REGEX.exec(ips[i]))) {
+                ip = IP._strToIpv6(match[1]);
                 network = [];
-                network_str = "";
+                networkStr = "";
                 
                 for (var j = 0; j < 8; j++) {
-                    network.push(ip[j] & ipv6_mask[j]);
+                    network.push(ip[j] & ipv6Mask[j]);
                 }
                 
-                network_str = IP._ipv6_to_str(network, true);
+                networkStr = IP._ipv6ToStr(network, true);
                 
-                if (ipv6_networks.hasOwnProperty(network_str)) {
-                    ipv6_networks[network_str].push(ip);
+                if (ipv6Networks.hasOwnProperty(networkStr)) {
+                    ipv6Networks[networkStr].push(ip);
                 } else {
-                    ipv6_networks[network_str] = [ip];
+                    ipv6Networks[networkStr] = [ip];
                 }
             }
         }
         
         // Sort IPv4 network dictionaries and print
-        for (network in ipv4_networks) {
-            ipv4_networks[network] = ipv4_networks[network].sort();
+        for (network in ipv4Networks) {
+            ipv4Networks[network] = ipv4Networks[network].sort();
             
-            output += IP._ipv4_to_str(network) + "/" + cidr + "\n";
+            output += IP._ipv4ToStr(network) + "/" + cidr + "\n";
             
-            if (!only_subnets) {
-                for (i = 0; i < ipv4_networks[network].length; i++) {
-                    output += "  " + IP._ipv4_to_str(ipv4_networks[network][i]) + "\n";
+            if (!onlySubnets) {
+                for (i = 0; i < ipv4Networks[network].length; i++) {
+                    output += "  " + IP._ipv4ToStr(ipv4Networks[network][i]) + "\n";
                 }
                 output += "\n";
             }
         }
         
         // Sort IPv6 network dictionaries and print
-        for (network_str in ipv6_networks) {
-            //ipv6_networks[network_str] = ipv6_networks[network_str].sort();  TODO
+        for (networkStr in ipv6Networks) {
+            //ipv6Networks[networkStr] = ipv6Networks[networkStr].sort();  TODO
             
-            output += network_str + "/" + cidr + "\n";
+            output += networkStr + "/" + cidr + "\n";
             
-            if (!only_subnets) {
-                for (i = 0; i < ipv6_networks[network_str].length; i++) {
-                    output += "  " + IP._ipv6_to_str(ipv6_networks[network_str][i], true) + "\n";
+            if (!onlySubnets) {
+                for (i = 0; i < ipv6Networks[networkStr].length; i++) {
+                    output += "  " + IP._ipv6ToStr(ipv6Networks[networkStr][i], true) + "\n";
                 }
                 output += "\n";
             }
@@ -413,35 +413,35 @@ var IP = {
      *
      * @private
      * @param {RegExp} cidr
-     * @param {boolean} include_network_info
-     * @param {boolean} enumerate_addresses
-     * @param {boolean} allow_large_list
+     * @param {boolean} includeNetworkInfo
+     * @param {boolean} enumerateAddresses
+     * @param {boolean} allowLargeList
      * @returns {string}
      */
-    _ipv4_cidr_range: function(cidr, include_network_info, enumerate_addresses, allow_large_list) {
+    _ipv4CidrRange: function(cidr, includeNetworkInfo, enumerateAddresses, allowLargeList) {
         var output = "",
-            network = IP._str_to_ipv4(cidr[1]),
-            cidr_range = parseInt(cidr[2], 10);
+            network = IP._strToIpv4(cidr[1]),
+            cidrRange = parseInt(cidr[2], 10);
             
-        if (cidr_range < 0 || cidr_range > 31) {
+        if (cidrRange < 0 || cidrRange > 31) {
             return "IPv4 CIDR must be less than 32";
         }
         
-        var mask = ~(0xFFFFFFFF >>> cidr_range),
+        var mask = ~(0xFFFFFFFF >>> cidrRange),
             ip1 = network & mask,
             ip2 = ip1 | ~mask;
         
-        if (include_network_info) {
-            output += "Network: " + IP._ipv4_to_str(network) + "\n";
-            output += "CIDR: " + cidr_range + "\n";
-            output += "Mask: " + IP._ipv4_to_str(mask) + "\n";
-            output += "Range: " + IP._ipv4_to_str(ip1) + " - " + IP._ipv4_to_str(ip2) + "\n";
+        if (includeNetworkInfo) {
+            output += "Network: " + IP._ipv4ToStr(network) + "\n";
+            output += "CIDR: " + cidrRange + "\n";
+            output += "Mask: " + IP._ipv4ToStr(mask) + "\n";
+            output += "Range: " + IP._ipv4ToStr(ip1) + " - " + IP._ipv4ToStr(ip2) + "\n";
             output += "Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
         }
         
-        if (enumerate_addresses) {
-            if (cidr_range >= 16 || allow_large_list) {
-                output += IP._generate_ipv4_range(ip1, ip2).join("\n");
+        if (enumerateAddresses) {
+            if (cidrRange >= 16 || allowLargeList) {
+                output += IP._generateIpv4Range(ip1, ip2).join("\n");
             } else {
                 output += IP._LARGE_RANGE_ERROR;
             }
@@ -455,42 +455,42 @@ var IP = {
      *
      * @private
      * @param {RegExp} cidr
-     * @param {boolean} include_network_info
+     * @param {boolean} includeNetworkInfo
      * @returns {string}
      */
-    _ipv6_cidr_range: function(cidr, include_network_info) {
+    _ipv6CidrRange: function(cidr, includeNetworkInfo) {
         var output = "",
-            network = IP._str_to_ipv6(cidr[1]),
-            cidr_range = parseInt(cidr[cidr.length-1], 10);
+            network = IP._strToIpv6(cidr[1]),
+            cidrRange = parseInt(cidr[cidr.length-1], 10);
             
-        if (cidr_range < 0 || cidr_range > 127) {
+        if (cidrRange < 0 || cidrRange > 127) {
             return "IPv6 CIDR must be less than 128";
         }
         
-        var mask = IP._gen_ipv6_mask(cidr_range),
+        var mask = IP._genIpv6Mask(cidrRange),
             ip1 = new Array(8),
             ip2 = new Array(8),
-            total_diff = "",
+            totalDiff = "",
             total = new Array(128);
             
         for (var i = 0; i < 8; i++) {
             ip1[i] = network[i] & mask[i];
             ip2[i] = ip1[i] | (~mask[i] & 0x0000FFFF);
-            total_diff = (ip2[i] - ip1[i]).toString(2);
+            totalDiff = (ip2[i] - ip1[i]).toString(2);
             
-            if (total_diff !== "0") {
-                for (var n = 0; n < total_diff.length; n++) {
-                    total[i*16 + 16-(total_diff.length-n)] = total_diff[n];
+            if (totalDiff !== "0") {
+                for (var n = 0; n < totalDiff.length; n++) {
+                    total[i*16 + 16-(totalDiff.length-n)] = totalDiff[n];
                 }
             }
         }
 
-        if (include_network_info) {
-            output += "Network: " + IP._ipv6_to_str(network) + "\n";
-            output += "Shorthand: " + IP._ipv6_to_str(network, true) + "\n";
-            output += "CIDR: " + cidr_range + "\n";
-            output += "Mask: " + IP._ipv6_to_str(mask) + "\n";
-            output += "Range: " + IP._ipv6_to_str(ip1) + " - " + IP._ipv6_to_str(ip2) + "\n";
+        if (includeNetworkInfo) {
+            output += "Network: " + IP._ipv6ToStr(network) + "\n";
+            output += "Shorthand: " + IP._ipv6ToStr(network, true) + "\n";
+            output += "CIDR: " + cidrRange + "\n";
+            output += "Mask: " + IP._ipv6ToStr(mask) + "\n";
+            output += "Range: " + IP._ipv6ToStr(ip1) + " - " + IP._ipv6ToStr(ip2) + "\n";
             output += "Total addresses in range: " + (parseInt(total.join(""), 2) + 1) + "\n\n";
         }
         
@@ -505,7 +505,7 @@ var IP = {
      * @param {number} cidr
      * @returns {number[]}
      */
-    _gen_ipv6_mask: function(cidr) {
+    _genIpv6Mask: function(cidr) {
         var mask = new Array(8),
             shift;
             
@@ -529,15 +529,15 @@ var IP = {
      *
      * @private
      * @param {RegExp} range
-     * @param {boolean} include_network_info
-     * @param {boolean} enumerate_addresses
-     * @param {boolean} allow_large_list
+     * @param {boolean} includeNetworkInfo
+     * @param {boolean} enumerateAddresses
+     * @param {boolean} allowLargeList
      * @returns {string}
      */
-    _ipv4_hyphenated_range: function(range, include_network_info, enumerate_addresses, allow_large_list) {
+    _ipv4HyphenatedRange: function(range, includeNetworkInfo, enumerateAddresses, allowLargeList) {
         var output = "",
-            ip1 = IP._str_to_ipv4(range[1]),
-            ip2 = IP._str_to_ipv4(range[2]);
+            ip1 = IP._strToIpv4(range[1]),
+            ip2 = IP._strToIpv4(range[2]);
         
         // Calculate mask
         var diff = ip1 ^ ip2,
@@ -552,23 +552,23 @@ var IP = {
         
         mask = ~mask >>> 0;
         var network = ip1 & mask,
-            sub_ip1 = network & mask,
-            sub_ip2 = sub_ip1 | ~mask;
+            subIp1 = network & mask,
+            subIp2 = subIp1 | ~mask;
         
-        if (include_network_info) {
+        if (includeNetworkInfo) {
             output += "Minimum subnet required to hold this range:\n";
-            output += "\tNetwork: " + IP._ipv4_to_str(network) + "\n";
+            output += "\tNetwork: " + IP._ipv4ToStr(network) + "\n";
             output += "\tCIDR: " + cidr + "\n";
-            output += "\tMask: " + IP._ipv4_to_str(mask) + "\n";
-            output += "\tSubnet range: " + IP._ipv4_to_str(sub_ip1) + " - " + IP._ipv4_to_str(sub_ip2) + "\n";
-            output += "\tTotal addresses in subnet: " + (((sub_ip2 - sub_ip1) >>> 0) + 1) + "\n\n";
-            output += "Range: " + IP._ipv4_to_str(ip1) + " - " + IP._ipv4_to_str(ip2) + "\n";
+            output += "\tMask: " + IP._ipv4ToStr(mask) + "\n";
+            output += "\tSubnet range: " + IP._ipv4ToStr(subIp1) + " - " + IP._ipv4ToStr(subIp2) + "\n";
+            output += "\tTotal addresses in subnet: " + (((subIp2 - subIp1) >>> 0) + 1) + "\n\n";
+            output += "Range: " + IP._ipv4ToStr(ip1) + " - " + IP._ipv4ToStr(ip2) + "\n";
             output += "Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
         }
         
-        if (enumerate_addresses) {
-            if (((ip2 - ip1) >>> 0) <= 65536 || allow_large_list) {
-                output += IP._generate_ipv4_range(ip1, ip2).join("\n");
+        if (enumerateAddresses) {
+            if (((ip2 - ip1) >>> 0) <= 65536 || allowLargeList) {
+                output += IP._generateIpv4Range(ip1, ip2).join("\n");
             } else {
                 output += IP._LARGE_RANGE_ERROR;
             }
@@ -582,13 +582,13 @@ var IP = {
      *
      * @private
      * @param {RegExp} range
-     * @param {boolean} include_network_info
+     * @param {boolean} includeNetworkInfo
      * @returns {string}
      */
-    _ipv6_hyphenated_range: function(range, include_network_info) {
+    _ipv6HyphenatedRange: function(range, includeNetworkInfo) {
         var output = "",
-            ip1 = IP._str_to_ipv6(range[1]),
-            ip2 = IP._str_to_ipv6(range[14]);
+            ip1 = IP._strToIpv6(range[1]),
+            ip2 = IP._strToIpv6(range[14]);
         
         var t = "",
             total = new Array(128);
@@ -606,9 +606,9 @@ var IP = {
             }
         }
         
-        if (include_network_info) {
-            output += "Range: " + IP._ipv6_to_str(ip1) + " - " + IP._ipv6_to_str(ip2) + "\n";
-            output += "Shorthand range: " + IP._ipv6_to_str(ip1, true) + " - " + IP._ipv6_to_str(ip2, true) + "\n";
+        if (includeNetworkInfo) {
+            output += "Range: " + IP._ipv6ToStr(ip1) + " - " + IP._ipv6ToStr(ip2) + "\n";
+            output += "Shorthand range: " + IP._ipv6ToStr(ip1, true) + " - " + IP._ipv6ToStr(ip2, true) + "\n";
             output += "Total addresses in range: " + (parseInt(total.join(""), 2) + 1) + "\n\n";
         }
         
@@ -620,36 +620,36 @@ var IP = {
      * Converts an IPv4 address from string format to numerical format.
      *
      * @private
-     * @param {string} ip_str
+     * @param {string} ipStr
      * @returns {number}
      *
      * @example
      * // returns 168427520
-     * IP._str_to_ipv4("10.10.0.0");
+     * IP._strToIpv4("10.10.0.0");
      */
-    _str_to_ipv4: function (ip_str) {
-        var blocks = ip_str.split("."),
-            num_blocks = parse_blocks(blocks),
+    _strToIpv4: function (ipStr) {
+        var blocks = ipStr.split("."),
+            numBlocks = parseBlocks(blocks),
             result = 0;
             
-        result += num_blocks[0] << 24;
-        result += num_blocks[1] << 16;
-        result += num_blocks[2] << 8;
-        result += num_blocks[3];
+        result += numBlocks[0] << 24;
+        result += numBlocks[1] << 16;
+        result += numBlocks[2] << 8;
+        result += numBlocks[3];
         
         return result;
         
-        function parse_blocks(blocks) {
+        function parseBlocks(blocks) {
             if (blocks.length !== 4)
                 throw "More than 4 blocks.";
                 
-            var num_blocks = [];
+            var numBlocks = [];
             for (var i = 0; i < 4; i++) {
-                num_blocks[i] = parseInt(blocks[i], 10);
-                if (num_blocks[i] < 0 || num_blocks[i] > 255)
+                numBlocks[i] = parseInt(blocks[i], 10);
+                if (numBlocks[i] < 0 || numBlocks[i] > 255)
                     throw "Block out of range.";
             }
-            return num_blocks;
+            return numBlocks;
         }
     },
     
@@ -658,18 +658,18 @@ var IP = {
      * Converts an IPv4 address from numerical format to string format.
      *
      * @private
-     * @param {number} ip_int
+     * @param {number} ipInt
      * @returns {string}
      *
      * @example
      * // returns "10.10.0.0"
-     * IP._ipv4_to_str(168427520);
+     * IP._ipv4ToStr(168427520);
      */
-    _ipv4_to_str: function(ip_int) {
-        var blockA = (ip_int >> 24) & 255,
-            blockB = (ip_int >> 16) & 255,
-            blockC = (ip_int >> 8) & 255,
-            blockD = ip_int & 255;
+    _ipv4ToStr: function(ipInt) {
+        var blockA = (ipInt >> 24) & 255,
+            blockB = (ipInt >> 16) & 255,
+            blockC = (ipInt >> 8) & 255,
+            blockD = ipInt & 255;
         
         return blockA + "." + blockB + "." + blockC + "." + blockD;
     },
@@ -679,40 +679,40 @@ var IP = {
      * Converts an IPv6 address from string format to numerical array format.
      *
      * @private
-     * @param {string} ip_str
+     * @param {string} ipStr
      * @returns {number[]}
      *
      * @example
      * // returns [65280, 0, 0, 0, 0, 0, 4369, 8738]
-     * IP._str_to_ipv6("ff00::1111:2222");
+     * IP._strToIpv6("ff00::1111:2222");
      */
-    _str_to_ipv6: function(ip_str) {
-        var blocks = ip_str.split(":"),
-            num_blocks = parse_blocks(blocks),
+    _strToIpv6: function(ipStr) {
+        var blocks = ipStr.split(":"),
+            numBlocks = parseBlocks(blocks),
             j = 0,
             ipv6 = new Array(8);
         
         for (var i = 0; i < 8; i++) {
-            if (isNaN(num_blocks[j])) {
+            if (isNaN(numBlocks[j])) {
                 ipv6[i] = 0;
-                if (i === (8-num_blocks.slice(j).length)) j++;
+                if (i === (8-numBlocks.slice(j).length)) j++;
             } else {
-                ipv6[i] = num_blocks[j];
+                ipv6[i] = numBlocks[j];
                 j++;
             }
         }
         return ipv6;
         
-        function parse_blocks(blocks) {
+        function parseBlocks(blocks) {
             if (blocks.length < 3 || blocks.length > 8)
                 throw "Badly formatted IPv6 address.";
-            var num_blocks = [];
+            var numBlocks = [];
             for (var i = 0; i < blocks.length; i++) {
-                num_blocks[i] = parseInt(blocks[i], 16);
-                if (num_blocks[i] < 0 || num_blocks[i] > 65535)
+                numBlocks[i] = parseInt(blocks[i], 16);
+                if (numBlocks[i] < 0 || numBlocks[i] > 65535)
                     throw "Block out of range.";
             }
-            return num_blocks;
+            return numBlocks;
         }
     },
     
@@ -727,12 +727,12 @@ var IP = {
      *
      * @example
      * // returns "ff00::1111:2222"
-     * IP._ipv6_to_str([65280, 0, 0, 0, 0, 0, 4369, 8738], true);
+     * IP._ipv6ToStr([65280, 0, 0, 0, 0, 0, 4369, 8738], true);
      *
      * // returns "ff00:0000:0000:0000:0000:0000:1111:2222"
-     * IP._ipv6_to_str([65280, 0, 0, 0, 0, 0, 4369, 8738], false);
+     * IP._ipv6ToStr([65280, 0, 0, 0, 0, 0, 4369, 8738], false);
      */
-    _ipv6_to_str: function(ipv6, compact) {
+    _ipv6ToStr: function(ipv6, compact) {
         var output = "",
             i = 0;
             
@@ -779,18 +779,18 @@ var IP = {
      *
      * @private
      * @param {number} ip
-     * @param {number} end_ip
+     * @param {number} endIp
      * @returns {string[]}
      *
      * @example
      * // returns ["0.0.0.1", "0.0.0.2", "0.0.0.3"]
-     * IP._generate_ipv4_range(1, 3);
+     * IP._generateIpv4Range(1, 3);
      */
-    _generate_ipv4_range: function(ip, end_ip) {
+    _generateIpv4Range: function(ip, endIp) {
         var range = [];
-        if (end_ip >= ip) {
-            for (; ip <= end_ip; ip++) {
-                range.push(IP._ipv4_to_str(ip));
+        if (endIp >= ip) {
+            for (; ip <= endIp; ip++) {
+                range.push(IP._ipv4ToStr(ip));
             }
         } else {
             range[0] = "Second IP address smaller than first.";

+ 22 - 22
src/js/operations/JS.js

@@ -44,19 +44,19 @@ var JS = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse: function (input, args) {
-        var parse_loc = args[0],
-            parse_range = args[1],
-            parse_tokens = args[2],
-            parse_comment = args[3],
-            parse_tolerant = args[4],
+    runParse: function (input, args) {
+        var parseLoc = args[0],
+            parseRange = args[1],
+            parseTokens = args[2],
+            parseComment = args[3],
+            parseTolerant = args[4],
             result = {},
             options = {
-                loc:      parse_loc,
-                range:    parse_range,
-                tokens:   parse_tokens,
-                comment:  parse_comment,
-                tolerant: parse_tolerant
+                loc:      parseLoc,
+                range:    parseRange,
+                tokens:   parseTokens,
+                comment:  parseComment,
+                tolerant: parseTolerant
             };
             
         result = esprima.parse(input, options);
@@ -92,11 +92,11 @@ var JS = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_beautify: function(input, args) {
-        var beautify_indent = args[0] || JS.BEAUTIFY_INDENT,
+    runBeautify: function(input, args) {
+        var beautifyIndent = args[0] || JS.BEAUTIFY_INDENT,
             quotes = args[1].toLowerCase(),
-            beautify_semicolons = args[2],
-            beautify_comment = args[3],
+            beautifySemicolons = args[2],
+            beautifyComment = args[3],
             result = "",
             AST;
             
@@ -110,12 +110,12 @@ var JS = {
             var options = {
                 format: {
                     indent: {
-                        style: beautify_indent
+                        style: beautifyIndent
                     },
                     quotes: quotes,
-                    semicolons: beautify_semicolons,
+                    semicolons: beautifySemicolons,
                 },
-                comment: beautify_comment
+                comment: beautifyComment
             };
             
             if (options.comment)
@@ -137,13 +137,13 @@ var JS = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_minify: function(input, args) {
+    runMinify: function(input, args) {
         var result = "",
             AST = esprima.parse(input),
-            optimised_AST = esmangle.optimize(AST, null),
-            mangled_AST = esmangle.mangle(optimised_AST);
+            optimisedAST = esmangle.optimize(AST, null),
+            mangledAST = esmangle.mangle(optimisedAST);
             
-        result = escodegen.generate(mangled_AST, {
+        result = escodegen.generate(mangledAST, {
             format: {
                 renumber:    true,
                 hexadecimal: true,

+ 23 - 23
src/js/operations/MAC.js

@@ -42,15 +42,15 @@ var MAC = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_format: function(input, args) {
+    runFormat: function(input, args) {
         if (!input) return "";
     
-        var output_case = args[0],
-            no_delim = args[1],
-            dash_delim = args[2],
-            colon_delim = args[3],
-            cisco_style = args[4],
-            output_list = [],
+        var outputCase = args[0],
+            noDelim = args[1],
+            dashDelim = args[2],
+            colonDelim = args[3],
+            ciscoStyle = args[4],
+            outputList = [],
             macs = input.toLowerCase().split(/[,\s\r\n]+/);
 
         macs.forEach(function(mac) {
@@ -59,30 +59,30 @@ var MAC = {
                 macColon = cleanMac.replace(/(.{2}(?=.))/g, "$1:"),
                 macCisco = cleanMac.replace(/(.{4}(?=.))/g, "$1.");
                 
-            if (output_case === "Lower only") {
-                if (no_delim) output_list.push(cleanMac);
-                if (dash_delim) output_list.push(macHyphen);
-                if (colon_delim) output_list.push(macColon);
-                if (cisco_style) output_list.push(macCisco);
-            } else if (output_case === "Upper only") {
-                if (no_delim) output_list.push(cleanMac.toUpperCase());
-                if (dash_delim) output_list.push(macHyphen.toUpperCase());
-                if (colon_delim) output_list.push(macColon.toUpperCase());
-                if (cisco_style) output_list.push(macCisco.toUpperCase());
+            if (outputCase === "Lower only") {
+                if (noDelim) outputList.push(cleanMac);
+                if (dashDelim) outputList.push(macHyphen);
+                if (colonDelim) outputList.push(macColon);
+                if (ciscoStyle) outputList.push(macCisco);
+            } else if (outputCase === "Upper only") {
+                if (noDelim) outputList.push(cleanMac.toUpperCase());
+                if (dashDelim) outputList.push(macHyphen.toUpperCase());
+                if (colonDelim) outputList.push(macColon.toUpperCase());
+                if (ciscoStyle) outputList.push(macCisco.toUpperCase());
             } else {
-                if (no_delim) output_list.push(cleanMac, cleanMac.toUpperCase());
-                if (dash_delim) output_list.push(macHyphen, macHyphen.toUpperCase());
-                if (colon_delim) output_list.push(macColon, macColon.toUpperCase());
-                if (cisco_style) output_list.push(macCisco, macCisco.toUpperCase());
+                if (noDelim) outputList.push(cleanMac, cleanMac.toUpperCase());
+                if (dashDelim) outputList.push(macHyphen, macHyphen.toUpperCase());
+                if (colonDelim) outputList.push(macColon, macColon.toUpperCase());
+                if (ciscoStyle) outputList.push(macCisco, macCisco.toUpperCase());
             }
             
-            output_list.push(
+            outputList.push(
                 "" // Empty line to delimit groups
             );
         });
 
         // Return the data as a string
-        return output_list.join("\n");
+        return outputList.join("\n");
     },
 
 };

+ 7 - 7
src/js/operations/OS.js

@@ -16,7 +16,7 @@ var OS = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse_unix_perms: function(input, args) {
+    runParseUnixPerms: function(input, args) {
         var perms = {
                 d : false,  // directory
                 sl : false, // symbolic link
@@ -158,12 +158,12 @@ var OS = {
             return "Invalid input format.\nPlease enter the permissions in either octal (e.g. 755) or textual (e.g. drwxr-xr-x) format.";
         }
 
-        output += "Textual representation: " + OS._perms_to_str(perms);
-        output += "\nOctal representation:   " + OS._perms_to_octal(perms);
+        output += "Textual representation: " + OS._permsToStr(perms);
+        output += "\nOctal representation:   " + OS._permsToOctal(perms);
 
         // File type
         if (textual) {
-            output += "\nFile type: " + OS._ft_from_perms(perms);
+            output += "\nFile type: " + OS._ftFromPerms(perms);
         }
 
         // setuid, setgid
@@ -201,7 +201,7 @@ var OS = {
      * @param {Object} perms
      * @returns {string}
      */
-    _perms_to_str: function(perms) {
+    _permsToStr: function(perms) {
         var str = "",
             type = "-";
 
@@ -262,7 +262,7 @@ var OS = {
      * @param {Object} perms
      * @returns {string}
      */
-    _perms_to_octal: function(perms) {
+    _permsToOctal: function(perms) {
         var d = 0,
             u = 0,
             g = 0,
@@ -295,7 +295,7 @@ var OS = {
      * @param {Object} perms
      * @returns {string}
      */
-    _ft_from_perms: function(perms) {
+    _ftFromPerms: function(perms) {
         if (perms.d) return "Directory";
         if (perms.sl) return "Symbolic link";
         if (perms.np) return "Named pipe";

+ 101 - 101
src/js/operations/PublicKey.js

@@ -24,15 +24,15 @@ var PublicKey = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse_x509: function (input, args) {
+    runParseX509: function (input, args) {
         var cert = new X509(),
-            input_format = args[0];
+            inputFormat = args[0];
             
         if (!input.length) {
             return "No input";
         }
         
-        switch (input_format) {
+        switch (inputFormat) {
             case "DER Hex":
                 input = input.replace(/\s/g, "");
                 cert.hex = input;
@@ -43,11 +43,11 @@ var PublicKey = {
                 cert.pem = input;
                 break;
             case "Base64":
-                cert.hex = Utils.to_hex(Utils.from_base64(input, null, "byte_array"), "");
+                cert.hex = Utils.toHex(Utils.fromBase64(input, null, "byteArray"), "");
                 cert.pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(cert.hex, "CERTIFICATE");
                 break;
             case "Raw":
-                cert.hex = Utils.to_hex(Utils.str_to_byte_array(input), "");
+                cert.hex = Utils.toHex(Utils.strToByteArray(input), "");
                 cert.pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(cert.hex, "CERTIFICATE");
                 break;
             default:
@@ -58,108 +58,108 @@ var PublicKey = {
             sn = cert.getSerialNumberHex(),
             algorithm = KJUR.asn1.x509.OID.oid2name(KJUR.asn1.ASN1Util.oidHexToInt(ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [0, 2, 0]))),
             issuer = cert.getIssuerString(),
-            not_before = cert.getNotBefore(),
-            not_after = cert.getNotAfter(),
+            notBefore = cert.getNotBefore(),
+            notAfter = cert.getNotAfter(),
             subject = cert.getSubjectString(),
-            pk_algorithm = KJUR.asn1.x509.OID.oid2name(KJUR.asn1.ASN1Util.oidHexToInt(ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [0, 6, 0, 0]))),
+            pkAlgorithm = KJUR.asn1.x509.OID.oid2name(KJUR.asn1.ASN1Util.oidHexToInt(ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [0, 6, 0, 0]))),
             pk = X509.getPublicKeyFromCertPEM(cert.pem),
-            pk_fields = [],
-            pk_str = "",
-            cert_sig_alg = KJUR.asn1.x509.OID.oid2name(KJUR.asn1.ASN1Util.oidHexToInt(ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [1, 0]))),
-            cert_sig = ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [2]).substr(2),
-            sig_str = "",
+            pkFields = [],
+            pkStr = "",
+            certSigAlg = KJUR.asn1.x509.OID.oid2name(KJUR.asn1.ASN1Util.oidHexToInt(ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [1, 0]))),
+            certSig = ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [2]).substr(2),
+            sigStr = "",
             extensions = ASN1HEX.dump(ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [0, 7]));
         
         // Public Key fields
         if (pk.type === "EC") { // ECDSA
-            pk_fields.push({
+            pkFields.push({
                 key: "Curve Name",
                 value: pk.curveName
             });
-            pk_fields.push({
+            pkFields.push({
                 key: "Length",
                 value: (((new BigInteger(pk.pubKeyHex, 16)).bitLength()-3) /2) + " bits"
             });
-            pk_fields.push({
+            pkFields.push({
                 key: "pub",
-                value: PublicKey._format_byte_str(pk.pubKeyHex, 16, 18)
+                value: PublicKey._formatByteStr(pk.pubKeyHex, 16, 18)
             });
         } else if (pk.type === "DSA") { // DSA
-            pk_fields.push({
+            pkFields.push({
                 key: "pub",
-                value: PublicKey._format_byte_str(pk.y.toString(16), 16, 18)
+                value: PublicKey._formatByteStr(pk.y.toString(16), 16, 18)
             });
-            pk_fields.push({
+            pkFields.push({
                 key: "P",
-                value: PublicKey._format_byte_str(pk.p.toString(16), 16, 18)
+                value: PublicKey._formatByteStr(pk.p.toString(16), 16, 18)
             });
-            pk_fields.push({
+            pkFields.push({
                 key: "Q",
-                value: PublicKey._format_byte_str(pk.q.toString(16), 16, 18)
+                value: PublicKey._formatByteStr(pk.q.toString(16), 16, 18)
             });
-            pk_fields.push({
+            pkFields.push({
                 key: "G",
-                value: PublicKey._format_byte_str(pk.g.toString(16), 16, 18)
+                value: PublicKey._formatByteStr(pk.g.toString(16), 16, 18)
             });
         } else if (pk.e) { // RSA
-            pk_fields.push({
+            pkFields.push({
                 key: "Length",
                 value: pk.n.bitLength() + " bits"
             });
-            pk_fields.push({
+            pkFields.push({
                 key: "Modulus",
-                value: PublicKey._format_byte_str(pk.n.toString(16), 16, 18)
+                value: PublicKey._formatByteStr(pk.n.toString(16), 16, 18)
             });
-            pk_fields.push({
+            pkFields.push({
                 key: "Exponent",
                 value: pk.e + " (0x" + pk.e.toString(16) + ")"
             });
         } else {
-            pk_fields.push({
+            pkFields.push({
                 key: "Error",
                 value: "Unknown Public Key type"
             });
         }
         
         // Signature fields
-        if (ASN1HEX.dump(cert_sig).indexOf("SEQUENCE") === 0) { // DSA or ECDSA
-            sig_str = "  r:              " + PublicKey._format_byte_str(ASN1HEX.getDecendantHexVByNthList(cert_sig, 0, [0]), 16, 18) + "\n" +
-                "  s:              " + PublicKey._format_byte_str(ASN1HEX.getDecendantHexVByNthList(cert_sig, 0, [1]), 16, 18) + "\n";
+        if (ASN1HEX.dump(certSig).indexOf("SEQUENCE") === 0) { // DSA or ECDSA
+            sigStr = "  r:              " + PublicKey._formatByteStr(ASN1HEX.getDecendantHexVByNthList(certSig, 0, [0]), 16, 18) + "\n" +
+                "  s:              " + PublicKey._formatByteStr(ASN1HEX.getDecendantHexVByNthList(certSig, 0, [1]), 16, 18) + "\n";
         } else { // RSA
-            sig_str = "  Signature:      " + PublicKey._format_byte_str(cert_sig, 16, 18) + "\n";
+            sigStr = "  Signature:      " + PublicKey._formatByteStr(certSig, 16, 18) + "\n";
         }
         
         // Format Public Key fields
-        for (var i = 0; i < pk_fields.length; i++) {
-            pk_str += "  " + pk_fields[i].key + ":" +
-                Utils.pad_left(
-                    pk_fields[i].value + "\n",
-                    18 - (pk_fields[i].key.length + 3) + pk_fields[i].value.length + 1,
+        for (var i = 0; i < pkFields.length; i++) {
+            pkStr += "  " + pkFields[i].key + ":" +
+                Utils.padLeft(
+                    pkFields[i].value + "\n",
+                    18 - (pkFields[i].key.length + 3) + pkFields[i].value.length + 1,
                     " "
                 );
         }
         
-        var issuer_str = PublicKey._format_dn_str(issuer, 2),
-            nb_date = PublicKey._format_date(not_before),
-            na_date = PublicKey._format_date(not_after),
-            subject_str = PublicKey._format_dn_str(subject, 2);
+        var issuerStr = PublicKey._formatDnStr(issuer, 2),
+            nbDate = PublicKey._formatDate(notBefore),
+            naDate = PublicKey._formatDate(notAfter),
+            subjectStr = PublicKey._formatDnStr(subject, 2);
         
         var output = "Version:          " + (parseInt(version, 16) + 1) + " (0x" + version + ")\n" +
             "Serial number:    " + new BigInteger(sn, 16).toString() + " (0x" + sn + ")\n" +
             "Algorithm ID:     " + algorithm + "\n" +
             "Validity\n" +
-            "  Not Before:     " + nb_date + " (dd-mm-yy hh:mm:ss) (" + not_before + ")\n" +
-            "  Not After:      " + na_date + " (dd-mm-yy hh:mm:ss) (" + not_after + ")\n" +
+            "  Not Before:     " + nbDate + " (dd-mm-yy hh:mm:ss) (" + notBefore + ")\n" +
+            "  Not After:      " + naDate + " (dd-mm-yy hh:mm:ss) (" + notAfter + ")\n" +
             "Issuer\n" +
-            issuer_str +
+            issuerStr +
             "Subject\n" +
-            subject_str +
+            subjectStr +
             "Public Key\n" +
-            "  Algorithm:      " + pk_algorithm + "\n" +
-            pk_str +
+            "  Algorithm:      " + pkAlgorithm + "\n" +
+            pkStr +
             "Certificate Signature\n" +
-            "  Algorithm:      " + cert_sig_alg + "\n" +
-            sig_str +
+            "  Algorithm:      " + certSigAlg + "\n" +
+            sigStr +
             "\nExtensions (parsed ASN.1)\n" +
             extensions;
         
@@ -174,7 +174,7 @@ var PublicKey = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_pem_to_hex: function(input, args) {
+    runPemToHex: function(input, args) {
         if (input.indexOf("-----BEGIN") < 0) {
             // Add header so that the KEYUTIL function works
             input = "-----BEGIN CERTIFICATE-----" + input;
@@ -200,7 +200,7 @@ var PublicKey = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_hex_to_pem: function(input, args) {
+    runHexToPem: function(input, args) {
         return KJUR.asn1.ASN1Util.getPEMStringFromHex(input.replace(/\s/g, ""), args[0]);
     },
     
@@ -212,7 +212,7 @@ var PublicKey = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_hex_to_object_identifier: function(input, args) {
+    runHexToObjectIdentifier: function(input, args) {
         return KJUR.asn1.ASN1Util.oidHexToInt(input.replace(/\s/g, ""));
     },
     
@@ -224,7 +224,7 @@ var PublicKey = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_object_identifier_to_hex: function(input, args) {
+    runObjectIdentifierToHex: function(input, args) {
         return KJUR.asn1.ASN1Util.oidIntToHex(input);
     },
     
@@ -242,11 +242,11 @@ var PublicKey = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse_asn1_hex_string: function(input, args) {
-        var truncate_len = args[1],
+    runParseAsn1HexString: function(input, args) {
+        var truncateLen = args[1],
             index = args[0];
         return ASN1HEX.dump(input.replace(/\s/g, ""), {
-            "ommit_long_octet": truncate_len
+            "ommitLongOctet": truncateLen
         }, index);
     },
     
@@ -255,14 +255,14 @@ var PublicKey = {
      * Formats Distinguished Name (DN) strings.
      *
      * @private
-     * @param {string} dn_str
+     * @param {string} dnStr
      * @param {number} indent
      * @returns {string}
      */
-    _format_dn_str: function(dn_str, indent) {
+    _formatDnStr: function(dnStr, indent) {
         var output = "",
-            fields = dn_str.split(",/|"),
-            max_key_len = 0,
+            fields = dnStr.split(",/|"),
+            maxKeyLen = 0,
             key,
             value,
             str;
@@ -272,7 +272,7 @@ var PublicKey = {
             
             key = fields[i].split("=")[0];
                 
-            max_key_len = key.length > max_key_len ? key.length : max_key_len;
+            maxKeyLen = key.length > maxKeyLen ? key.length : maxKeyLen;
         }
         
         for (i = 0; i < fields.length; i++) {
@@ -280,9 +280,9 @@ var PublicKey = {
             
             key = fields[i].split("=")[0];
             value = fields[i].split("=")[1];
-            str = Utils.pad_right(key, max_key_len) + " = " + value + "\n";
+            str = Utils.padRight(key, maxKeyLen) + " = " + value + "\n";
             
-            output += Utils.pad_left(str, indent + str.length, " ");
+            output += Utils.padLeft(str, indent + str.length, " ");
         }
         
         return output;
@@ -293,22 +293,22 @@ var PublicKey = {
      * Formats byte strings by adding line breaks and delimiters.
      *
      * @private
-     * @param {string} byte_str
+     * @param {string} byteStr
      * @param {number} length - Line width
      * @param {number} indent
      * @returns {string}
      */
-    _format_byte_str: function(byte_str, length, indent) {
-        byte_str = Utils.to_hex(Utils.from_hex(byte_str), ":");
+    _formatByteStr: function(byteStr, length, indent) {
+        byteStr = Utils.toHex(Utils.fromHex(byteStr), ":");
         length = length * 3;
         var output = "";
         
-        for (var i = 0; i < byte_str.length; i += length) {
-            var str = byte_str.slice(i, i + length) + "\n";
+        for (var i = 0; i < byteStr.length; i += length) {
+            var str = byteStr.slice(i, i + length) + "\n";
             if (i === 0) {
                 output += str;
             } else {
-                output += Utils.pad_left(str, indent + str.length, " ");
+                output += Utils.padLeft(str, indent + str.length, " ");
             }
         }
         
@@ -320,16 +320,16 @@ var PublicKey = {
      * Formats dates.
      *
      * @private
-     * @param {string} date_str
+     * @param {string} dateStr
      * @returns {string}
      */
-    _format_date: function(date_str) {
-        return date_str[4] + date_str[5] + "/" +
-            date_str[2] + date_str[3] + "/" +
-            date_str[0] + date_str[1] + " " +
-            date_str[6] + date_str[7] + ":" +
-            date_str[8] + date_str[9] + ":" +
-            date_str[10] + date_str[11];
+    _formatDate: function(dateStr) {
+        return dateStr[4] + dateStr[5] + "/" +
+            dateStr[2] + dateStr[3] + "/" +
+            dateStr[0] + dateStr[1] + " " +
+            dateStr[6] + dateStr[7] + ":" +
+            dateStr[8] + dateStr[9] + ":" +
+            dateStr[10] + dateStr[11];
     },
     
 };
@@ -388,9 +388,9 @@ X509.DN_ATTRHEX = {
     // "06032a864886f70d010104" : "md5withRSAEncryption",
     // "06032a864886f70d010105" : "SHA-1WithRSAEncryption",
     // "06032a8648ce380403" : "id-dsa-with-sha-1",
-    // "06032b06010505070302" : "id_kp_clientAuth",
-    // "06032b06010505070304" : "id_kp_securityemail",
-    "06032b06010505070201" : "id_certificatePolicies",
+    // "06032b06010505070302" : "idKpClientAuth",
+    // "06032b06010505070304" : "idKpSecurityemail",
+    "06032b06010505070201" : "idCertificatePolicies",
     "06036086480186f8420101" : "netscape-cert-type",
     "06036086480186f8420102" : "netscape-base-url",
     "06036086480186f8420103" : "netscape-revocation-url",
@@ -867,25 +867,25 @@ X509.DN_ATTRHEX = {
     "06036086480186f8450107010101" : "Unknown Verisign policy qualifier",
     "06036086480186f8450107010102" : "Unknown Verisign policy qualifier",
     "0603678105" : "TCPA",
-    "060367810501" : "tcpa_specVersion",
-    "060367810502" : "tcpa_attribute",
-    "06036781050201" : "tcpa_at_tpmManufacturer",
-    "0603678105020a" : "tcpa_at_securityQualities",
-    "0603678105020b" : "tcpa_at_tpmProtectionProfile",
-    "0603678105020c" : "tcpa_at_tpmSecurityTarget",
-    "0603678105020d" : "tcpa_at_foundationProtectionProfile",
-    "0603678105020e" : "tcpa_at_foundationSecurityTarget",
-    "0603678105020f" : "tcpa_at_tpmIdLabel",
-    "06036781050202" : "tcpa_at_tpmModel",
-    "06036781050203" : "tcpa_at_tpmVersion",
-    "06036781050204" : "tcpa_at_platformManufacturer",
-    "06036781050205" : "tcpa_at_platformModel",
-    "06036781050206" : "tcpa_at_platformVersion",
-    "06036781050207" : "tcpa_at_componentManufacturer",
-    "06036781050208" : "tcpa_at_componentModel",
-    "06036781050209" : "tcpa_at_componentVersion",
-    "060367810503" : "tcpa_protocol",
-    "06036781050301" : "tcpa_prtt_tpmIdProtocol",
+    "060367810501" : "tcpaSpecVersion",
+    "060367810502" : "tcpaAttribute",
+    "06036781050201" : "tcpaAtTpmManufacturer",
+    "0603678105020a" : "tcpaAtSecurityQualities",
+    "0603678105020b" : "tcpaAtTpmProtectionProfile",
+    "0603678105020c" : "tcpaAtTpmSecurityTarget",
+    "0603678105020d" : "tcpaAtFoundationProtectionProfile",
+    "0603678105020e" : "tcpaAtFoundationSecurityTarget",
+    "0603678105020f" : "tcpaAtTpmIdLabel",
+    "06036781050202" : "tcpaAtTpmModel",
+    "06036781050203" : "tcpaAtTpmVersion",
+    "06036781050204" : "tcpaAtPlatformManufacturer",
+    "06036781050205" : "tcpaAtPlatformModel",
+    "06036781050206" : "tcpaAtPlatformVersion",
+    "06036781050207" : "tcpaAtComponentManufacturer",
+    "06036781050208" : "tcpaAtComponentModel",
+    "06036781050209" : "tcpaAtComponentVersion",
+    "060367810503" : "tcpaProtocol",
+    "06036781050301" : "tcpaPrttTpmIdProtocol",
     "0603672a00" : "contentType",
     "0603672a0000" : "PANData",
     "0603672a0001" : "PANToken",

+ 2 - 2
src/js/operations/Punycode.js

@@ -24,7 +24,7 @@ var Punycode = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_ascii: function(input, args) {
+    runToAscii: function(input, args) {
         var idn = args[0];
         
         if (idn) {
@@ -42,7 +42,7 @@ var Punycode = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to_unicode: function(input, args) {
+    runToUnicode: function(input, args) {
         var idn = args[0];
         
         if (idn) {

+ 7 - 7
src/js/operations/QuotedPrintable.js

@@ -35,11 +35,11 @@ var QuotedPrintable = {
     /**
      * To Quoted Printable operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to: function (input, args) {
+    runTo: function (input, args) {
         var mimeEncodedStr = QuotedPrintable.mimeEncode(input);
         
         // fix line breaks
@@ -58,9 +58,9 @@ var QuotedPrintable = {
      *
      * @param {string} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_from: function (input, args) {
+    runFrom: function (input, args) {
         var str = input.replace(/\=(?:\r?\n|$)/g, "");
         return QuotedPrintable.mimeDecode(str);
     },
@@ -70,7 +70,7 @@ var QuotedPrintable = {
      * Decodes mime-encoded data.
      *
      * @param {string} str
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
     mimeDecode: function(str) {
         var encodedBytesCount = (str.match(/\=[\da-fA-F]{2}/g) || []).length,
@@ -96,7 +96,7 @@ var QuotedPrintable = {
     /**
      * Encodes mime data.
      *
-     * @param {byte_array} buffer
+     * @param {byteArray} buffer
      * @returns {string}
      */
     mimeEncode: function(buffer) {
@@ -130,7 +130,7 @@ var QuotedPrintable = {
      *
      * @private
      * @param {number} nr
-     * @param {byte_array[]} ranges
+     * @param {byteArray[]} ranges
      * @returns {bolean}
      */
     _checkRanges: function(nr, ranges) {

+ 40 - 40
src/js/operations/Rotate.js

@@ -26,10 +26,10 @@ var Rotate = {
      * Runs rotation operations across the input data.
      *
      * @private
-     * @param {byte_array} data
+     * @param {byteArray} data
      * @param {number} amount
      * @param {function} algo - The rotation operation to carry out
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
     _rot: function(data, amount, algo) {
         var result = [];
@@ -47,13 +47,13 @@ var Rotate = {
     /**
      * Rotate right operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_rotr: function(input, args) {
+    runRotr: function(input, args) {
         if (args[1]) {
-            return Rotate._rotr_whole(input, args[0]);
+            return Rotate._rotrWhole(input, args[0]);
         } else {
             return Rotate._rot(input, args[0], Rotate._rotr);
         }
@@ -63,13 +63,13 @@ var Rotate = {
     /**
      * Rotate left operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_rotl: function(input, args) {
+    runRotl: function(input, args) {
         if (args[1]) {
-            return Rotate._rotl_whole(input, args[0]);
+            return Rotate._rotlWhole(input, args[0]);
         } else {
             return Rotate._rot(input, args[0], Rotate._rotl);
         }
@@ -95,16 +95,16 @@ var Rotate = {
     /**
      * ROT13 operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_rot13: function(input, args) {
+    runRot13: function(input, args) {
         var amount = args[2],
             output = input,
             chr,
-            rot13_lowercase = args[0],
-            rot13_upperacse = args[1];
+            rot13Lowercase = args[0],
+            rot13Upperacse = args[1];
             
         if (amount) {
             if (amount < 0) {
@@ -113,10 +113,10 @@ var Rotate = {
             
             for (var i = 0; i < input.length; i++) {
                 chr = input[i];
-                if (rot13_upperacse && chr >= 65 && chr <= 90) { // Upper case
+                if (rot13Upperacse && chr >= 65 && chr <= 90) { // Upper case
                     chr = (chr - 65 + amount) % 26;
                     output[i] = chr + 65;
-                } else if (rot13_lowercase && chr >= 97 && chr <= 122) { // Lower case
+                } else if (rot13Lowercase && chr >= 97 && chr <= 122) { // Lower case
                     chr = (chr - 97 + amount) % 26;
                     output[i] = chr + 97;
                 }
@@ -136,11 +136,11 @@ var Rotate = {
      * ROT47 operation.
      *
      * @author Matt C [matt@artemisbot.pw]
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_rot47: function(input, args) {
+    runRot47: function(input, args) {
         var amount = args[0],
             output = input,
             chr;
@@ -193,23 +193,23 @@ var Rotate = {
      * from the end of the array to the beginning.
      *
      * @private
-     * @param {byte_array} data
+     * @param {byteArray} data
      * @param {number} amount
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    _rotr_whole: function(data, amount) {
-        var carry_bits = 0,
-            new_byte,
+    _rotrWhole: function(data, amount) {
+        var carryBits = 0,
+            newByte,
             result = [];
         
         amount = amount % 8;
         for (var i = 0; i < data.length; i++) {
-            var old_byte = data[i] >>> 0;
-            new_byte = (old_byte >> amount) | carry_bits;
-            carry_bits = (old_byte & (Math.pow(2, amount)-1)) << (8-amount);
-            result.push(new_byte);
+            var oldByte = data[i] >>> 0;
+            newByte = (oldByte >> amount) | carryBits;
+            carryBits = (oldByte & (Math.pow(2, amount)-1)) << (8-amount);
+            result.push(newByte);
         }
-        result[0] |= carry_bits;
+        result[0] |= carryBits;
         return result;
     },
     
@@ -219,23 +219,23 @@ var Rotate = {
      * from the beginning of the array to the end.
      *
      * @private
-     * @param {byte_array} data
+     * @param {byteArray} data
      * @param {number} amount
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    _rotl_whole: function(data, amount) {
-        var carry_bits = 0,
-            new_byte,
+    _rotlWhole: function(data, amount) {
+        var carryBits = 0,
+            newByte,
             result = [];
             
         amount = amount % 8;
         for (var i = data.length-1; i >= 0; i--) {
-            var old_byte = data[i];
-            new_byte = ((old_byte << amount) | carry_bits) & 0xFF;
-            carry_bits = (old_byte >> (8-amount)) & (Math.pow(2, amount)-1);
-            result[i] = (new_byte);
+            var oldByte = data[i];
+            newByte = ((oldByte << amount) | carryBits) & 0xFF;
+            carryBits = (oldByte >> (8-amount)) & (Math.pow(2, amount)-1);
+            result[i] = (newByte);
         }
-        result[data.length-1] = result[data.length-1] | carry_bits;
+        result[data.length-1] = result[data.length-1] | carryBits;
         return result;
     },
 

+ 19 - 19
src/js/operations/SeqUtils.js

@@ -32,21 +32,21 @@ var SeqUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_sort: function (input, args) {
-        var delim = Utils.char_rep[args[0]],
-            sort_reverse = args[1],
+    runSort: function (input, args) {
+        var delim = Utils.charRep[args[0]],
+            sortReverse = args[1],
             order = args[2],
             sorted = input.split(delim);
             
         if (order === "Alphabetical (case sensitive)") {
             sorted = sorted.sort();
         } else if (order === "Alphabetical (case insensitive)") {
-            sorted = sorted.sort(SeqUtils._case_insensitive_sort);
+            sorted = sorted.sort(SeqUtils._caseInsensitiveSort);
         } else if (order === "IP address") {
-            sorted = sorted.sort(SeqUtils._ip_sort);
+            sorted = sorted.sort(SeqUtils._ipSort);
         }
             
-        if (sort_reverse) sorted.reverse();
+        if (sortReverse) sorted.reverse();
         return sorted.join(delim);
     },
     
@@ -58,8 +58,8 @@ var SeqUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_unique: function (input, args) {
-        var delim = Utils.char_rep[args[0]];
+    runUnique: function (input, args) {
+        var delim = Utils.charRep[args[0]];
         return input.split(delim).unique().join(delim);
     },
     
@@ -77,7 +77,7 @@ var SeqUtils = {
      * @param {Object[]} args
      * @returns {number}
      */
-    run_count: function(input, args) {
+    runCount: function(input, args) {
         var search = args[0].string,
             type = args[0].option;
             
@@ -91,7 +91,7 @@ var SeqUtils = {
             }
         } else if (search) {
             if (type.indexOf("Extended") === 0) {
-                search = Utils.parse_escaped_chars(search);
+                search = Utils.parseEscapedChars(search);
             }
             return input.count(search);
         } else {
@@ -109,11 +109,11 @@ var SeqUtils = {
     /**
      * Reverse operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_reverse: function (input, args) {
+    runReverse: function (input, args) {
         if (args[0] === "Line") {
             var lines = [],
                 line = [],
@@ -146,7 +146,7 @@ var SeqUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_add_line_numbers: function(input, args) {
+    runAddLineNumbers: function(input, args) {
         var lines = input.split("\n"),
             output = "",
             width = lines.length.toString().length;
@@ -165,7 +165,7 @@ var SeqUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_remove_line_numbers: function(input, args) {
+    runRemoveLineNumbers: function(input, args) {
         return input.replace(/^[ \t]{0,5}\d+[\s:|\-,.)\]]/gm, "");
     },
     
@@ -177,8 +177,8 @@ var SeqUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_expand_alph_range: function(input, args) {
-        return Utils.expand_alph_range(input).join(args[0]);
+    runExpandAlphRange: function(input, args) {
+        return Utils.expandAlphRange(input).join(args[0]);
     },
     
     
@@ -190,7 +190,7 @@ var SeqUtils = {
      * @param {string} b
      * @returns {number}
      */
-    _case_insensitive_sort: function(a, b) {
+    _caseInsensitiveSort: function(a, b) {
         return a.toLowerCase().localeCompare(b.toLowerCase());
     },
     
@@ -203,7 +203,7 @@ var SeqUtils = {
      * @param {string} b
      * @returns {number}
      */
-    _ip_sort: function(a, b) {
+    _ipSort: function(a, b) {
         var a_ = a.split("."),
             b_ = b.split(".");
         

+ 91 - 65
src/js/operations/StrUtils.js

@@ -97,30 +97,30 @@ var StrUtils = {
      * @param {Object[]} args
      * @returns {html}
      */
-    run_regex: function(input, args) {
-        var user_regex = args[1],
+    runRegex: function(input, args) {
+        var userRegex = args[1],
             i = args[2],
             m = args[3],
-            display_total = args[4],
-            output_format = args[5],
+            displayTotal = args[4],
+            outputFormat = args[5],
             modifiers = "g";
         
         if (i) modifiers += "i";
         if (m) modifiers += "m";
         
-        if (user_regex && user_regex !== "^" && user_regex !== "$") {
+        if (userRegex && userRegex !== "^" && userRegex !== "$") {
             try {
-                var regex = new RegExp(user_regex, modifiers);
+                var regex = new RegExp(userRegex, modifiers);
                 
-                switch (output_format) {
+                switch (outputFormat) {
                     case "Highlight matches":
-                        return StrUtils._regex_highlight(input, regex, display_total);
+                        return StrUtils._regexHighlight(input, regex, displayTotal);
                     case "List matches":
-                        return Utils.escape_html(StrUtils._regex_list(input, regex, display_total, true, false));
+                        return Utils.escapeHtml(StrUtils._regexList(input, regex, displayTotal, true, false));
                     case "List capture groups":
-                        return Utils.escape_html(StrUtils._regex_list(input, regex, display_total, false, true));
+                        return Utils.escapeHtml(StrUtils._regexList(input, regex, displayTotal, false, true));
                     case "List matches with capture groups":
-                        return Utils.escape_html(StrUtils._regex_list(input, regex, display_total, true, true));
+                        return Utils.escapeHtml(StrUtils._regexList(input, regex, displayTotal, true, true));
                     default:
                         return "Error: Invalid output format";
                 }
@@ -128,7 +128,7 @@ var StrUtils = {
                 return "Invalid regex. Details: " + err.message;
             }
         } else {
-            return Utils.escape_html(input);
+            return Utils.escapeHtml(input);
         }
     },
 
@@ -146,7 +146,7 @@ var StrUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_upper: function (input, args) {
+    runUpper: function (input, args) {
         var scope = args[0];
         
         switch (scope) {
@@ -177,7 +177,7 @@ var StrUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_lower: function (input, args) {
+    runLower: function (input, args) {
         return input.toLowerCase();
     },
     
@@ -210,7 +210,7 @@ var StrUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_find_replace: function(input, args) {
+    runFindReplace: function(input, args) {
         var find = args[0].string,
             type = args[0].option,
             replace = args[1],
@@ -226,7 +226,7 @@ var StrUtils = {
         if (type === "Regex") {
             find = new RegExp(find, modifiers);
         } else if (type.indexOf("Extended") === 0) {
-            find = Utils.parse_escaped_chars(find);
+            find = Utils.parseEscapedChars(find);
         }
         
         return input.replace(find, replace, modifiers);
@@ -254,12 +254,38 @@ var StrUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_split: function(input, args) {
-        var split_delim = args[0] || StrUtils.SPLIT_DELIM,
-            join_delim = Utils.char_rep[args[1]],
-            sections = input.split(split_delim);
+    runSplit: function(input, args) {
+        var splitDelim = args[0] || StrUtils.SPLIT_DELIM,
+            joinDelim = Utils.charRep[args[1]],
+            sections = input.split(splitDelim);
             
-        return sections.join(join_delim);
+        return sections.join(joinDelim);
+    },
+
+
+    /**
+     * Filter operation.
+     *
+     * @author Mikescher (https://github.com/Mikescher | https://mikescher.com)
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runFilter: function(input, args) {
+        var delim = Utils.charRep[args[0]],
+            reverse = args[2];
+
+        try {
+            var regex = new RegExp(args[1]);
+        } catch (err) {
+            return "Invalid regex. Details: " + err.message;
+        }
+
+        var regexFilter = function(value) {
+            return reverse ^ regex.test(value);
+        };
+
+        return input.split(delim).filter(regexFilter).join(delim);
     },
     
     
@@ -281,13 +307,13 @@ var StrUtils = {
      * @param {Object[]} args
      * @returns {html}
      */
-    run_diff: function(input, args) {
-        var sample_delim = args[0],
-            diff_by = args[1],
-            show_added = args[2],
-            show_removed = args[3],
-            ignore_whitespace = args[4],
-            samples = input.split(sample_delim),
+    runDiff: function(input, args) {
+        var sampleDelim = args[0],
+            diffBy = args[1],
+            showAdded = args[2],
+            showRemoved = args[3],
+            ignoreWhitespace = args[4],
+            samples = input.split(sampleDelim),
             output = "",
             diff;
             
@@ -295,19 +321,19 @@ var StrUtils = {
             return "Incorrect number of samples, perhaps you need to modify the sample delimiter or add more samples?";
         }
         
-        switch (diff_by) {
+        switch (diffBy) {
             case "Character":
                 diff = JsDiff.diffChars(samples[0], samples[1]);
                 break;
             case "Word":
-                if (ignore_whitespace) {
+                if (ignoreWhitespace) {
                     diff = JsDiff.diffWords(samples[0], samples[1]);
                 } else {
                     diff = JsDiff.diffWordsWithSpace(samples[0], samples[1]);
                 }
                 break;
             case "Line":
-                if (ignore_whitespace) {
+                if (ignoreWhitespace) {
                     diff = JsDiff.diffTrimmedLines(samples[0], samples[1]);
                 } else {
                     diff = JsDiff.diffLines(samples[0], samples[1]);
@@ -328,11 +354,11 @@ var StrUtils = {
         
         for (var i = 0; i < diff.length; i++) {
             if (diff[i].added) {
-                if (show_added) output += "<span class='hlgreen'>" + Utils.escape_html(diff[i].value) + "</span>";
+                if (showAdded) output += "<span class='hlgreen'>" + Utils.escapeHtml(diff[i].value) + "</span>";
             } else if (diff[i].removed) {
-                if (show_removed) output += "<span class='hlred'>" + Utils.escape_html(diff[i].value) + "</span>";
+                if (showRemoved) output += "<span class='hlred'>" + Utils.escapeHtml(diff[i].value) + "</span>";
             } else {
-                output += Utils.escape_html(diff[i].value);
+                output += Utils.escapeHtml(diff[i].value);
             }
         }
         
@@ -353,14 +379,14 @@ var StrUtils = {
      * @param {Object[]} args
      * @returns {html}
      */
-    run_offset_checker: function(input, args) {
-        var sample_delim = args[0],
-            samples = input.split(sample_delim),
+    runOffsetChecker: function(input, args) {
+        var sampleDelim = args[0],
+            samples = input.split(sampleDelim),
             outputs = [],
             i = 0,
             s = 0,
             match = false,
-            in_match = false,
+            inMatch = false,
             chr;
             
         if (!samples || samples.length < 2) {
@@ -389,34 +415,34 @@ var StrUtils = {
             // Write output for each sample
             for (s = 0; s < samples.length; s++) {
                 if (samples[s].length <= i) {
-                    if (in_match) outputs[s] += "</span>";
-                    if (s === samples.length - 1) in_match = false;
+                    if (inMatch) outputs[s] += "</span>";
+                    if (s === samples.length - 1) inMatch = false;
                     continue;
                 }
                 
-                if (match && !in_match) {
-                    outputs[s] += "<span class='hlgreen'>" + Utils.escape_html(samples[s][i]);
+                if (match && !inMatch) {
+                    outputs[s] += "<span class='hlgreen'>" + Utils.escapeHtml(samples[s][i]);
                     if (samples[s].length === i + 1) outputs[s] += "</span>";
-                    if (s === samples.length - 1) in_match = true;
-                } else if (!match && in_match) {
-                    outputs[s] += "</span>" + Utils.escape_html(samples[s][i]);
-                    if (s === samples.length - 1) in_match = false;
+                    if (s === samples.length - 1) inMatch = true;
+                } else if (!match && inMatch) {
+                    outputs[s] += "</span>" + Utils.escapeHtml(samples[s][i]);
+                    if (s === samples.length - 1) inMatch = false;
                 } else {
-                    outputs[s] += Utils.escape_html(samples[s][i]);
-                    if (in_match && samples[s].length === i + 1) {
+                    outputs[s] += Utils.escapeHtml(samples[s][i]);
+                    if (inMatch && samples[s].length === i + 1) {
                         outputs[s] += "</span>";
-                        if (samples[s].length - 1 !== i) in_match = false;
+                        if (samples[s].length - 1 !== i) inMatch = false;
                     }
                 }
                 
                 if (samples[0].length - 1 === i) {
-                    if (in_match) outputs[s] += "</span>";
-                    outputs[s] += Utils.escape_html(samples[s].substring(i + 1));
+                    if (inMatch) outputs[s] += "</span>";
+                    outputs[s] += Utils.escapeHtml(samples[s].substring(i + 1));
                 }
             }
         }
         
-        return outputs.join(sample_delim);
+        return outputs.join(sampleDelim);
     },
     
     
@@ -427,8 +453,8 @@ var StrUtils = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse_escaped_string: function(input, args) {
-        return Utils.parse_escaped_chars(input);
+    runParseEscapedString: function(input, args) {
+        return Utils.parseEscapedChars(input);
     },
     
     
@@ -438,10 +464,10 @@ var StrUtils = {
      * @private
      * @param {string} input
      * @param {RegExp} regex
-     * @param {boolean} display_total
+     * @param {boolean} displayTotal
      * @returns {string}
      */
-    _regex_highlight: function(input, regex, display_total) {
+    _regexHighlight: function(input, regex, displayTotal) {
         var output = "",
             m,
             hl = 1,
@@ -450,10 +476,10 @@ var StrUtils = {
         
         while ((m = regex.exec(input))) {
             // Add up to match
-            output += Utils.escape_html(input.slice(i, m.index));
+            output += Utils.escapeHtml(input.slice(i, m.index));
             
             // Add match with highlighting
-            output += "<span class='hl"+hl+"'>" + Utils.escape_html(m[0]) + "</span>";
+            output += "<span class='hl"+hl+"'>" + Utils.escapeHtml(m[0]) + "</span>";
             
             // Switch highlight
             hl = hl === 1 ? 2 : 1;
@@ -463,9 +489,9 @@ var StrUtils = {
         }
         
         // Add all after final match
-        output += Utils.escape_html(input.slice(i, input.length));
+        output += Utils.escapeHtml(input.slice(i, input.length));
         
-        if (display_total)
+        if (displayTotal)
             output = "Total found: " + total + "\n\n" + output;
 
         return output;
@@ -478,12 +504,12 @@ var StrUtils = {
      * @private
      * @param {string} input
      * @param {RegExp} regex
-     * @param {boolean} display_total
+     * @param {boolean} displayTotal
      * @param {boolean} matches - Display full match
-     * @param {boolean} capture_groups - Display each of the capture groups separately
+     * @param {boolean} captureGroups - Display each of the capture groups separately
      * @returns {string}
      */
-    _regex_list: function(input, regex, display_total, matches, capture_groups) {
+    _regexList: function(input, regex, displayTotal, matches, captureGroups) {
         var output = "",
             total = 0,
             match;
@@ -493,7 +519,7 @@ var StrUtils = {
             if (matches) {
                 output += match[0] + "\n";
             }
-            if (capture_groups) {
+            if (captureGroups) {
                 for (var i = 1; i < match.length; i++) {
                     if (matches) {
                         output += "  Group " + i + ": ";
@@ -503,7 +529,7 @@ var StrUtils = {
             }
         }
         
-        if (display_total)
+        if (displayTotal)
             output = "Total found: " + total + "\n\n" + output;
             
         return output;

+ 29 - 29
src/js/operations/Tidy.js

@@ -47,21 +47,21 @@ var Tidy = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_remove_whitespace: function (input, args) {
-        var remove_spaces = args[0],
-            remove_cariage_returns = args[1],
-            remove_line_feeds = args[2],
-            remove_tabs = args[3],
-            remove_form_feeds = args[4],
-            remove_full_stops = args[5],
+    runRemoveWhitespace: function (input, args) {
+        var removeSpaces = args[0],
+            removeCariageReturns = args[1],
+            removeLineFeeds = args[2],
+            removeTabs = args[3],
+            removeFormFeeds = args[4],
+            removeFullStops = args[5],
             data = input;
             
-        if (remove_spaces) data = data.replace(/ /g, "");
-        if (remove_cariage_returns) data = data.replace(/\r/g, "");
-        if (remove_line_feeds) data = data.replace(/\n/g, "");
-        if (remove_tabs) data = data.replace(/\t/g, "");
-        if (remove_form_feeds) data = data.replace(/\f/g, "");
-        if (remove_full_stops) data = data.replace(/\./g, "");
+        if (removeSpaces) data = data.replace(/ /g, "");
+        if (removeCariageReturns) data = data.replace(/\r/g, "");
+        if (removeLineFeeds) data = data.replace(/\n/g, "");
+        if (removeTabs) data = data.replace(/\t/g, "");
+        if (removeFormFeeds) data = data.replace(/\f/g, "");
+        if (removeFullStops) data = data.replace(/\./g, "");
         return data;
     },
     
@@ -69,11 +69,11 @@ var Tidy = {
     /**
      * Remove null bytes operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_remove_nulls: function (input, args) {
+    runRemoveNulls: function (input, args) {
         var output = [];
         for (var i = 0; i < input.length; i++) {
             if (input[i] !== 0) output.push(input[i]);
@@ -101,19 +101,19 @@ var Tidy = {
     /**
      * Drop bytes operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_drop_bytes: function(input, args) {
+    runDropBytes: function(input, args) {
         var start = args[0],
             length = args[1],
-            apply_to_each_line = args[2];
+            applyToEachLine = args[2];
             
         if (start < 0 || length < 0)
             throw "Error: Invalid value";
             
-        if (!apply_to_each_line)
+        if (!applyToEachLine)
             return input.slice(0, start).concat(input.slice(start+length, input.length));
             
         // Split input into lines
@@ -153,19 +153,19 @@ var Tidy = {
     /**
      * Take bytes operation.
      *
-     * @param {byte_array} input
+     * @param {byteArray} input
      * @param {Object[]} args
-     * @returns {byte_array}
+     * @returns {byteArray}
      */
-    run_take_bytes: function(input, args) {
+    runTakeBytes: function(input, args) {
         var start = args[0],
             length = args[1],
-            apply_to_each_line = args[2];
+            applyToEachLine = args[2];
             
         if (start < 0 || length < 0)
             throw "Error: Invalid value";
             
-        if (!apply_to_each_line)
+        if (!applyToEachLine)
             return input.slice(start, start+length);
             
         // Split input into lines
@@ -214,7 +214,7 @@ var Tidy = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_pad: function(input, args) {
+    runPad: function(input, args) {
         var position = args[0],
             len = args[1],
             chr = args[2],
@@ -224,11 +224,11 @@ var Tidy = {
             
         if (position === "Start") {
             for (i = 0; i < lines.length; i++) {
-                output += Utils.pad_left(lines[i], lines[i].length+len, chr) + "\n";
+                output += Utils.padLeft(lines[i], lines[i].length+len, chr) + "\n";
             }
         } else if (position === "End") {
             for (i = 0; i < lines.length; i++) {
-                output += Utils.pad_right(lines[i], lines[i].length+len, chr) + "\n";
+                output += Utils.padRight(lines[i], lines[i].length+len, chr) + "\n";
             }
         }
         

+ 16 - 16
src/js/operations/URL.js

@@ -25,9 +25,9 @@ var URL_ = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_to: function(input, args) {
-        var encode_all = args[0];
-        return encode_all ? URL_._encode_all_chars(input) : encodeURI(input);
+    runTo: function(input, args) {
+        var encodeAll = args[0];
+        return encodeAll ? URL_._encodeAllChars(input) : encodeURI(input);
     },
     
     
@@ -38,7 +38,7 @@ var URL_ = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_from: function(input, args) {
+    runFrom: function(input, args) {
         var data = input.replace(/\+/g, "%20");
         try {
             return decodeURIComponent(data);
@@ -55,7 +55,7 @@ var URL_ = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_parse: function(input, args) {
+    runParse: function(input, args) {
         var a = document.createElement("a");
         
         // Overwrite base href which will be the current CyberChef URL to reduce confusion.
@@ -70,7 +70,7 @@ var URL_ = {
                 if (a.port) output += "Port:\t\t" + a.port + "\n";
             }
             
-            if (a.pathname) {
+            if (a.pathname && a.pathname !== window.location.pathname) {
                 var pathname = a.pathname;
                 if (pathname.indexOf(window.location.pathname) === 0)
                     pathname = pathname.replace(window.location.pathname, "");
@@ -78,22 +78,22 @@ var URL_ = {
                     output += "Path name:\t" + pathname + "\n";
             }
             
-            if (a.hash) {
+            if (a.hash && a.hash !== window.location.hash) {
                 output += "Hash:\t\t" + a.hash + "\n";
             }
             
-            if (a.search) {
+            if (a.search && a.search !== window.location.search) {
                 output += "Arguments:\n";
                 var args_ = (a.search.slice(1, a.search.length)).split("&");
-                var split_args = [], padding = 0;
+                var splitArgs = [], padding = 0;
                 for (var i = 0; i < args_.length; i++) {
-                    split_args.push(args_[i].split("="));
-                    padding = (split_args[i][0].length > padding) ? split_args[i][0].length : padding;
+                    splitArgs.push(args_[i].split("="));
+                    padding = (splitArgs[i][0].length > padding) ? splitArgs[i][0].length : padding;
                 }
-                for (i = 0; i < split_args.length; i++) {
-                    output += "\t" + Utils.pad_right(split_args[i][0], padding);
-                    if (split_args[i].length > 1 && split_args[i][1].length)
-                        output += " = " + split_args[i][1] + "\n";
+                for (i = 0; i < splitArgs.length; i++) {
+                    output += "\t" + Utils.padRight(splitArgs[i][0], padding);
+                    if (splitArgs[i].length > 1 && splitArgs[i][1].length)
+                        output += " = " + splitArgs[i][1] + "\n";
                     else output += "\n";
                 }
             }
@@ -112,7 +112,7 @@ var URL_ = {
      * @param {string} str
      * @returns {string}
      */
-    _encode_all_chars: function(str) {
+    _encodeAllChars: function(str) {
         //TODO Do this programatically
         return encodeURIComponent(str)
             .replace(/!/g, "%21")

+ 1 - 1
src/js/operations/UUID.js

@@ -16,7 +16,7 @@ var UUID = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_generate_v4: function(input, args) {
+    runGenerateV4: function(input, args) {
         if (typeof(window.crypto) !== "undefined" && typeof(window.crypto.getRandomValues) !== "undefined") {
             var buf = new Uint32Array(4),
                 i = 0;

+ 3 - 3
src/js/operations/Unicode.js

@@ -22,8 +22,8 @@ var Unicode = {
      * @param {Object[]} args
      * @returns {string}
      */
-    run_unescape: function(input, args) {
-        var prefix = Unicode._prefix_to_regex[args[0]],
+    runUnescape: function(input, args) {
+        var prefix = Unicode._prefixToRegex[args[0]],
             regex = new RegExp(prefix+"([a-f\\d]{4,6})", "ig"),
             output = "",
             m,
@@ -53,7 +53,7 @@ var Unicode = {
      * @private
      * @constant
      */
-    _prefix_to_regex: {
+    _prefixToRegex: {
         "\\u": "\\\\u",
         "%u": "%u",
         "U+": "U\\+"

+ 119 - 118
src/js/views/html/ControlsWaiter.js

@@ -19,15 +19,15 @@ var ControlsWaiter = function(app, manager) {
  * Adjusts the display properties of the control buttons so that they fit within the current width
  * without wrapping or overflowing.
  */
-ControlsWaiter.prototype.adjust_width = function() {
-    var controls       = document.getElementById("controls"),
-        step           = document.getElementById("step"),
-        clr_breaks     = document.getElementById("clr-breaks"),
-        save_img       = document.querySelector("#save img"),
-        load_img       = document.querySelector("#load img"),
-        step_img       = document.querySelector("#step img"),
-        clr_recip_img  = document.querySelector("#clr-recipe img"),
-        clr_breaks_img = document.querySelector("#clr-breaks img");
+ControlsWaiter.prototype.adjustWidth = function() {
+    var controls     = document.getElementById("controls"),
+        step         = document.getElementById("step"),
+        clrBreaks    = document.getElementById("clr-breaks"),
+        saveImg      = document.querySelector("#save img"),
+        loadImg      = document.querySelector("#load img"),
+        stepImg      = document.querySelector("#step img"),
+        clrRecipImg  = document.querySelector("#clr-recipe img"),
+        clrBreaksImg = document.querySelector("#clr-breaks img");
     
     if (controls.clientWidth < 470) {
         step.childNodes[1].nodeValue = " Step";
@@ -36,23 +36,23 @@ ControlsWaiter.prototype.adjust_width = function() {
     }
         
     if (controls.clientWidth < 400) {
-        save_img.style.display = "none";
-        load_img.style.display = "none";
-        step_img.style.display = "none";
-        clr_recip_img.style.display = "none";
-        clr_breaks_img.style.display = "none";
+        saveImg.style.display = "none";
+        loadImg.style.display = "none";
+        stepImg.style.display = "none";
+        clrRecipImg.style.display = "none";
+        clrBreaksImg.style.display = "none";
     } else {
-        save_img.style.display = "inline";
-        load_img.style.display = "inline";
-        step_img.style.display = "inline";
-        clr_recip_img.style.display = "inline";
-        clr_breaks_img.style.display = "inline";
+        saveImg.style.display = "inline";
+        loadImg.style.display = "inline";
+        stepImg.style.display = "inline";
+        clrRecipImg.style.display = "inline";
+        clrBreaksImg.style.display = "inline";
     }
     
     if (controls.clientWidth < 330) {
-        clr_breaks.childNodes[1].nodeValue = " Clear breaks";
+        clrBreaks.childNodes[1].nodeValue = " Clear breaks";
     } else {
-        clr_breaks.childNodes[1].nodeValue = " Clear breakpoints";
+        clrBreaks.childNodes[1].nodeValue = " Clear breakpoints";
     }
 };
 
@@ -62,11 +62,11 @@ ControlsWaiter.prototype.adjust_width = function() {
  *
  * @param {boolean} value - The new value for Auto Bake.
  */
-ControlsWaiter.prototype.set_auto_bake = function(value) {
-    var auto_bake_checkbox = document.getElementById("auto-bake");
+ControlsWaiter.prototype.setAutoBake = function(value) {
+    var autoBakeCheckbox = document.getElementById("auto-bake");
     
-    if (auto_bake_checkbox.checked !== value) {
-        auto_bake_checkbox.click();
+    if (autoBakeCheckbox.checked !== value) {
+        autoBakeCheckbox.click();
     }
 };
 
@@ -74,7 +74,7 @@ ControlsWaiter.prototype.set_auto_bake = function(value) {
 /**
  * Handler to trigger baking.
  */
-ControlsWaiter.prototype.bake_click = function() {
+ControlsWaiter.prototype.bakeClick = function() {
     this.app.bake();
     $("#output-text").selectRange(0);
 };
@@ -83,7 +83,7 @@ ControlsWaiter.prototype.bake_click = function() {
 /**
  * Handler for the 'Step through' command. Executes the next step of the recipe.
  */
-ControlsWaiter.prototype.step_click = function() {
+ControlsWaiter.prototype.stepClick = function() {
     this.app.bake(true);
     $("#output-text").selectRange(0);
 };
@@ -92,18 +92,18 @@ ControlsWaiter.prototype.step_click = function() {
 /**
  * Handler for changes made to the Auto Bake checkbox.
  */
-ControlsWaiter.prototype.auto_bake_change = function() {
-    var auto_bake_label    = document.getElementById("auto-bake-label"),
-        auto_bake_checkbox = document.getElementById("auto-bake");
+ControlsWaiter.prototype.autoBakeChange = function() {
+    var autoBakeLabel    = document.getElementById("auto-bake-label"),
+        autoBakeCheckbox = document.getElementById("auto-bake");
         
-    this.app.auto_bake_ = auto_bake_checkbox.checked;
+    this.app.autoBake_ = autoBakeCheckbox.checked;
     
-    if (auto_bake_checkbox.checked) {
-        auto_bake_label.classList.remove("btn-default");
-        auto_bake_label.classList.add("btn-success");
+    if (autoBakeCheckbox.checked) {
+        autoBakeLabel.classList.remove("btn-default");
+        autoBakeLabel.classList.add("btn-success");
     } else {
-        auto_bake_label.classList.remove("btn-success");
-        auto_bake_label.classList.add("btn-default");
+        autoBakeLabel.classList.remove("btn-success");
+        autoBakeLabel.classList.add("btn-default");
     }
 };
 
@@ -111,8 +111,8 @@ ControlsWaiter.prototype.auto_bake_change = function() {
 /**
  * Handler for the 'Clear recipe' command. Removes all operations from the recipe.
  */
-ControlsWaiter.prototype.clear_recipe_click = function() {
-    this.manager.recipe.clear_recipe();
+ControlsWaiter.prototype.clearRecipeClick = function() {
+    this.manager.recipe.clearRecipe();
 };
 
 
@@ -120,8 +120,8 @@ ControlsWaiter.prototype.clear_recipe_click = function() {
  * Handler for the 'Clear breakpoints' command. Removes all breakpoints from operations in the
  * recipe.
  */
-ControlsWaiter.prototype.clear_breaks_click = function() {
-    var bps = document.querySelectorAll("#rec_list li.operation .breakpoint");
+ControlsWaiter.prototype.clearBreaksClick = function() {
+    var bps = document.querySelectorAll("#rec-list li.operation .breakpoint");
     
     for (var i = 0; i < bps.length; i++) {
         bps[i].setAttribute("break", "false");
@@ -133,49 +133,49 @@ ControlsWaiter.prototype.clear_breaks_click = function() {
 /**
  * Populates the save disalog box with a URL incorporating the recipe and input.
  *
- * @param {Object[]} [recipe_config] - The recipe configuration object array.
+ * @param {Object[]} [recipeConfig] - The recipe configuration object array.
  */
-ControlsWaiter.prototype.initialise_save_link = function(recipe_config) {
-    recipe_config = recipe_config || this.app.get_recipe_config();
+ControlsWaiter.prototype.initialiseSaveLink = function(recipeConfig) {
+    recipeConfig = recipeConfig || this.app.getRecipeConfig();
     
-    var include_recipe = document.getElementById("save-link-recipe-checkbox").checked,
-        include_input = document.getElementById("save-link-input-checkbox").checked,
-        save_link_el = document.getElementById("save-link"),
-        save_link = this.generate_state_url(include_recipe, include_input, recipe_config);
+    var includeRecipe = document.getElementById("save-link-recipe-checkbox").checked,
+        includeInput = document.getElementById("save-link-input-checkbox").checked,
+        saveLinkEl = document.getElementById("save-link"),
+        saveLink = this.generateStateUrl(includeRecipe, includeInput, recipeConfig);
     
-    save_link_el.innerHTML = Utils.truncate(save_link, 120);
-    save_link_el.setAttribute("href", save_link);
+    saveLinkEl.innerHTML = Utils.truncate(saveLink, 120);
+    saveLinkEl.setAttribute("href", saveLink);
 };
 
 
 /**
  * Generates a URL containing the current recipe and input state.
  *
- * @param {boolean} include_recipe - Whether to include the recipe in the URL.
- * @param {boolean} include_input - Whether to include the input in the URL.
- * @param {Object[]} [recipe_config] - The recipe configuration object array.
+ * @param {boolean} includeRecipe - Whether to include the recipe in the URL.
+ * @param {boolean} includeInput - Whether to include the input in the URL.
+ * @param {Object[]} [recipeConfig] - The recipe configuration object array.
  * @returns {string}
  */
-ControlsWaiter.prototype.generate_state_url = function(include_recipe, include_input, recipe_config) {
-    recipe_config = recipe_config || this.app.get_recipe_config();
+ControlsWaiter.prototype.generateStateUrl = function(includeRecipe, includeInput, recipeConfig) {
+    recipeConfig = recipeConfig || this.app.getRecipeConfig();
     
     var link = window.location.protocol + "//" +
                 window.location.host +
                 window.location.pathname,
-        recipe_str = JSON.stringify(recipe_config),
-        input_str = Utils.to_base64(this.app.get_input(), "A-Za-z0-9+/"); // B64 alphabet with no padding
+        recipeStr = JSON.stringify(recipeConfig),
+        inputStr = Utils.toBase64(this.app.getInput(), "A-Za-z0-9+/"); // B64 alphabet with no padding
         
-    include_recipe = include_recipe && (recipe_config.length > 0);
-    include_input = include_input && (input_str.length > 0) && (input_str.length < 8000);
+    includeRecipe = includeRecipe && (recipeConfig.length > 0);
+    includeInput = includeInput && (inputStr.length > 0) && (inputStr.length < 8000);
 
-    if (include_recipe) {
-        link += "?recipe=" + encodeURIComponent(recipe_str);
+    if (includeRecipe) {
+        link += "?recipe=" + encodeURIComponent(recipeStr);
     }
     
-    if (include_recipe && include_input) {
-        link += "&input=" + encodeURIComponent(input_str);
-    } else if (include_input) {
-        link += "?input=" + encodeURIComponent(input_str);
+    if (includeRecipe && includeInput) {
+        link += "&input=" + encodeURIComponent(inputStr);
+    } else if (includeInput) {
+        link += "?input=" + encodeURIComponent(inputStr);
     }
     
     return link;
@@ -185,10 +185,10 @@ ControlsWaiter.prototype.generate_state_url = function(include_recipe, include_i
 /**
  * Handler for changes made to the save dialog text area. Re-initialises the save link.
  */
-ControlsWaiter.prototype.save_text_change = function() {
+ControlsWaiter.prototype.saveTextChange = function() {
     try {
-        var recipe_config = JSON.parse(document.getElementById("save-text").value);
-        this.initialise_save_link(recipe_config);
+        var recipeConfig = JSON.parse(document.getElementById("save-text").value);
+        this.initialiseSaveLink(recipeConfig);
     } catch(err) {}
 };
 
@@ -196,12 +196,13 @@ ControlsWaiter.prototype.save_text_change = function() {
 /**
  * Handler for the 'Save' command. Pops up the save dialog box.
  */
-ControlsWaiter.prototype.save_click = function() {
-    var recipe_config = this.app.get_recipe_config();
-    var recipe_str = JSON.stringify(recipe_config).replace(/},{/g, "},\n{");
-    document.getElementById("save-text").value = recipe_str;
+ControlsWaiter.prototype.saveClick = function() {
+    var recipeConfig = this.app.getRecipeConfig(),
+        recipeStr = JSON.stringify(recipeConfig).replace(/},{/g, "},\n{");
+        
+    document.getElementById("save-text").value = recipeStr;
     
-    this.initialise_save_link(recipe_config);
+    this.initialiseSaveLink(recipeConfig);
     $("#save-modal").modal();
 };
 
@@ -209,24 +210,24 @@ ControlsWaiter.prototype.save_click = function() {
 /**
  * Handler for the save link recipe checkbox change event.
  */
-ControlsWaiter.prototype.slr_check_change = function() {
-    this.initialise_save_link();
+ControlsWaiter.prototype.slrCheckChange = function() {
+    this.initialiseSaveLink();
 };
 
 
 /**
  * Handler for the save link input checkbox change event.
  */
-ControlsWaiter.prototype.sli_check_change = function() {
-    this.initialise_save_link();
+ControlsWaiter.prototype.sliCheckChange = function() {
+    this.initialiseSaveLink();
 };
 
 
 /**
  * Handler for the 'Load' command. Pops up the load dialog box.
  */
-ControlsWaiter.prototype.load_click = function() {
-    this.populate_load_recipes_list();
+ControlsWaiter.prototype.loadClick = function() {
+    this.populateLoadRecipesList();
     $("#load-modal").modal();
 };
 
@@ -234,88 +235,88 @@ ControlsWaiter.prototype.load_click = function() {
 /**
  * Saves the recipe specified in the save textarea to local storage.
  */
-ControlsWaiter.prototype.save_button_click = function() {
-    var recipe_name = document.getElementById("save-name").value,
-        recipe_str  = document.getElementById("save-text").value;
+ControlsWaiter.prototype.saveButtonClick = function() {
+    var recipeName = document.getElementById("save-name").value,
+        recipeStr  = document.getElementById("save-text").value;
     
-    if (!recipe_name) {
+    if (!recipeName) {
         this.app.alert("Please enter a recipe name", "danger", 2000);
         return;
     }
     
-    var saved_recipes = localStorage.saved_recipes ?
-            JSON.parse(localStorage.saved_recipes) : [],
-        recipe_id = localStorage.recipe_id || 0;
+    var savedRecipes = localStorage.savedRecipes ?
+            JSON.parse(localStorage.savedRecipes) : [],
+        recipeId = localStorage.recipeId || 0;
     
-    saved_recipes.push({
-        id: ++recipe_id,
-        name: recipe_name,
-        recipe: recipe_str
+    savedRecipes.push({
+        id: ++recipeId,
+        name: recipeName,
+        recipe: recipeStr
     });
     
-    localStorage.saved_recipes = JSON.stringify(saved_recipes);
-    localStorage.recipe_id = recipe_id;
+    localStorage.savedRecipes = JSON.stringify(savedRecipes);
+    localStorage.recipeId = recipeId;
     
-    this.app.alert("Recipe saved as \"" + recipe_name + "\".", "success", 2000);
+    this.app.alert("Recipe saved as \"" + recipeName + "\".", "success", 2000);
 };
 
 
 /**
  * Populates the list of saved recipes in the load dialog box from local storage.
  */
-ControlsWaiter.prototype.populate_load_recipes_list = function() {
-    var load_name_el = document.getElementById("load-name");
+ControlsWaiter.prototype.populateLoadRecipesList = function() {
+    var loadNameEl = document.getElementById("load-name");
         
     // Remove current recipes from select
-    var i = load_name_el.options.length;
+    var i = loadNameEl.options.length;
     while (i--) {
-        load_name_el.remove(i);
+        loadNameEl.remove(i);
     }
 
     // Add recipes to select
-    var saved_recipes = localStorage.saved_recipes ?
-            JSON.parse(localStorage.saved_recipes) : [];
+    var savedRecipes = localStorage.savedRecipes ?
+            JSON.parse(localStorage.savedRecipes) : [];
     
-    for (i = 0; i < saved_recipes.length; i++) {
+    for (i = 0; i < savedRecipes.length; i++) {
         var opt = document.createElement("option");
-        opt.value = saved_recipes[i].id;
-        opt.innerHTML = saved_recipes[i].name;
+        opt.value = savedRecipes[i].id;
+        opt.innerHTML = savedRecipes[i].name;
         
-        load_name_el.appendChild(opt);
+        loadNameEl.appendChild(opt);
     }
     
     // Populate textarea with first recipe
-    document.getElementById("load-text").value = saved_recipes.length ? saved_recipes[0].recipe : "";
+    document.getElementById("load-text").value = savedRecipes.length ? savedRecipes[0].recipe : "";
 };
 
 
 /**
  * Removes the currently selected recipe from local storage.
  */
-ControlsWaiter.prototype.load_delete_click = function() {
-    var id = document.getElementById("load-name").value,
-        saved_recipes = localStorage.saved_recipes ?
-            JSON.parse(localStorage.saved_recipes) : [];
+ControlsWaiter.prototype.loadDeleteClick = function() {
+    var id = parseInt(document.getElementById("load-name").value, 10),
+        savedRecipes = localStorage.savedRecipes ?
+            JSON.parse(localStorage.savedRecipes) : [];
         
-    saved_recipes = saved_recipes.filter(function(r) {
+    savedRecipes = savedRecipes.filter(function(r) {
         return r.id !== id;
     });
     
-    localStorage.saved_recipes = JSON.stringify(saved_recipes);
-    this.populate_load_recipes_list();
+    localStorage.savedRecipes = JSON.stringify(savedRecipes);
+    this.populateLoadRecipesList();
 };
 
 
 /**
  * Displays the selected recipe in the load text box.
  */
-ControlsWaiter.prototype.load_name_change = function(e) {
+ControlsWaiter.prototype.loadNameChange = function(e) {
     var el = e.target,
-        saved_recipes = localStorage.saved_recipes ?
-            JSON.parse(localStorage.saved_recipes) : [],
+        savedRecipes = localStorage.savedRecipes ?
+            JSON.parse(localStorage.savedRecipes) : [],
         id = parseInt(el.value, 10);
         
-    var recipe = saved_recipes.filter(function(r) {
+    var recipe = savedRecipes.filter(function(r) {
         return r.id === id;
     })[0];
     
@@ -326,12 +327,12 @@ ControlsWaiter.prototype.load_name_change = function(e) {
 /**
  * Loads the selected recipe and populates the Recipe with its operations.
  */
-ControlsWaiter.prototype.load_button_click = function() {
+ControlsWaiter.prototype.loadButtonClick = function() {
     try {
-        var recipe_config = JSON.parse(document.getElementById("load-text").value);
-        this.app.set_recipe_config(recipe_config);
+        var recipeConfig = JSON.parse(document.getElementById("load-text").value);
+        this.app.setRecipeConfig(recipeConfig);
 
-        $("#rec_list [data-toggle=popover]").popover();
+        $("#rec-list [data-toggle=popover]").popover();
     } catch(e) {
         this.app.alert("Invalid recipe", "danger", 2000);
     }

+ 170 - 169
src/js/views/html/HTMLApp.js

@@ -11,22 +11,22 @@
  * @constructor
  * @param {CatConf[]} categories - The list of categories and operations to be populated.
  * @param {Object.<string, OpConf>} operations - The list of operation configuration objects.
- * @param {String[]} default_favourites - A list of default favourite operations.
+ * @param {String[]} defaultFavourites - A list of default favourite operations.
  * @param {Object} options - Default setting for app options.
  */
-var HTMLApp = function(categories, operations, default_favourites, default_options) {
+var HTMLApp = function(categories, operations, defaultFavourites, defaultOptions) {
     this.categories  = categories;
     this.operations  = operations;
-    this.dfavourites = default_favourites;
-    this.doptions    = default_options;
-    this.options     = Utils.extend({}, default_options);
+    this.dfavourites = defaultFavourites;
+    this.doptions    = defaultOptions;
+    this.options     = Utils.extend({}, defaultOptions);
 
     this.chef        = new Chef();
     this.manager     = new Manager(this);
 
-    this.auto_bake_  = false;
+    this.autoBake_   = false;
     this.progress    = 0;
-    this.ing_id      = 0;
+    this.ingId       = 0;
 
     window.chef      = this.chef;
 };
@@ -39,13 +39,13 @@ var HTMLApp = function(categories, operations, default_favourites, default_optio
  */
 HTMLApp.prototype.setup = function() {
     document.dispatchEvent(this.manager.appstart);
-    this.initialise_splitter();
-    this.load_local_storage();
-    this.populate_operations_list();
+    this.initialiseSplitter();
+    this.loadLocalStorage();
+    this.populateOperationsList();
     this.manager.setup();
-    this.reset_layout();
-    this.set_compile_message();
-    this.load_URI_params();
+    this.resetLayout();
+    this.setCompileMessage();
+    this.loadURIParams();
 };
 
 
@@ -54,10 +54,10 @@ HTMLApp.prototype.setup = function() {
  *
  * @param {Error} err
  */
-HTMLApp.prototype.handle_error = function(err) {
+HTMLApp.prototype.handleError = function(err) {
     console.error(err);
-    var msg = err.display_str || err.toString();
-    this.alert(msg, "danger", this.options.error_timeout, !this.options.show_errors);
+    var msg = err.displayStr || err.toString();
+    this.alert(msg, "danger", this.options.errorTimeout, !this.options.showErrors);
 };
 
 
@@ -72,32 +72,32 @@ HTMLApp.prototype.bake = function(step) {
 
     try {
         response = this.chef.bake(
-            this.get_input(),         // The user's input
-            this.get_recipe_config(), // The configuration of the recipe
+            this.getInput(),         // The user's input
+            this.getRecipeConfig(), // The configuration of the recipe
             this.options,             // Options set by the user
             this.progress,            // The current position in the recipe
             step                      // Whether or not to take one step or execute the whole recipe
         );
     } catch (err) {
-        this.handle_error(err);
+        this.handleError(err);
     }
 
     if (!response) return;
 
     if (response.error) {
-        this.handle_error(response.error);
+        this.handleError(response.error);
     }
 
     this.options  = response.options;
-    this.dish_str = response.type === "html" ? Utils.strip_html_tags(response.result, true) : response.result;
+    this.dishStr  = response.type === "html" ? Utils.stripHtmlTags(response.result, true) : response.result;
     this.progress = response.progress;
-    this.manager.recipe.update_breakpoint_indicator(response.progress);
+    this.manager.recipe.updateBreakpointIndicator(response.progress);
     this.manager.output.set(response.result, response.type, response.duration);
 
     // If baking took too long, disable auto-bake
-    if (response.duration > this.options.auto_bake_threshold && this.auto_bake_) {
-        this.manager.controls.set_auto_bake(false);
-        this.alert("Baking took longer than " + this.options.auto_bake_threshold +
+    if (response.duration > this.options.autoBakeThreshold && this.autoBake_) {
+        this.manager.controls.setAutoBake(false);
+        this.alert("Baking took longer than " + this.options.autoBakeThreshold +
             "ms, Auto Bake has been disabled.", "warning", 5000);
     }
 };
@@ -106,8 +106,8 @@ HTMLApp.prototype.bake = function(step) {
 /**
  * Runs Auto Bake if it is set.
  */
-HTMLApp.prototype.auto_bake = function() {
-    if (this.auto_bake_) {
+HTMLApp.prototype.autoBake = function() {
+    if (this.autoBake_) {
         this.bake();
     }
 };
@@ -122,15 +122,15 @@ HTMLApp.prototype.auto_bake = function() {
  *
  * @returns {number} - The number of miliseconds it took to run the silent bake.
  */
-HTMLApp.prototype.silent_bake = function() {
-    var start_time = new Date().getTime(),
-        recipe_config = this.get_recipe_config();
+HTMLApp.prototype.silentBake = function() {
+    var startTime = new Date().getTime(),
+        recipeConfig = this.getRecipeConfig();
 
-    if (this.auto_bake_) {
-        this.chef.silent_bake(recipe_config);
+    if (this.autoBake_) {
+        this.chef.silentBake(recipeConfig);
     }
 
-    return new Date().getTime() - start_time;
+    return new Date().getTime() - startTime;
 };
 
 
@@ -139,11 +139,11 @@ HTMLApp.prototype.silent_bake = function() {
  *
  * @returns {string}
  */
-HTMLApp.prototype.get_input = function() {
+HTMLApp.prototype.getInput = function() {
     var input = this.manager.input.get();
 
     // Save to session storage in case we need to restore it later
-    sessionStorage.setItem("input_length", input.length);
+    sessionStorage.setItem("inputLength", input.length);
     sessionStorage.setItem("input", input);
 
     return input;
@@ -155,8 +155,8 @@ HTMLApp.prototype.get_input = function() {
  *
  * @param {string} input - The string to set the input to
  */
-HTMLApp.prototype.set_input = function(input) {
-    sessionStorage.setItem("input_length", input.length);
+HTMLApp.prototype.setInput = function(input) {
+    sessionStorage.setItem("inputLength", input.length);
     sessionStorage.setItem("input", input);
     this.manager.input.set(input);
 };
@@ -168,32 +168,32 @@ HTMLApp.prototype.set_input = function(input) {
  *
  * @fires Manager#oplistcreate
  */
-HTMLApp.prototype.populate_operations_list = function() {
+HTMLApp.prototype.populateOperationsList = function() {
     // Move edit button away before we overwrite it
     document.body.appendChild(document.getElementById("edit-favourites"));
 
     var html = "";
 
     for (var i = 0; i < this.categories.length; i++) {
-        var cat_conf = this.categories[i],
+        var catConf = this.categories[i],
             selected = i === 0,
-            cat = new HTMLCategory(cat_conf.name, selected);
+            cat = new HTMLCategory(catConf.name, selected);
 
-        for (var j = 0; j < cat_conf.ops.length; j++) {
-            var op_name = cat_conf.ops[j],
-                op = new HTMLOperation(op_name, this.operations[op_name], this, this.manager);
-            cat.add_operation(op);
+        for (var j = 0; j < catConf.ops.length; j++) {
+            var opName = catConf.ops[j],
+                op = new HTMLOperation(opName, this.operations[opName], this, this.manager);
+            cat.addOperation(op);
         }
 
-        html += cat.to_html();
+        html += cat.toHtml();
     }
 
     document.getElementById("categories").innerHTML = html;
 
-    var op_lists = document.querySelectorAll("#categories .op_list");
+    var opLists = document.querySelectorAll("#categories .op-list");
 
-    for (i = 0; i < op_lists.length; i++) {
-        op_lists[i].dispatchEvent(this.manager.oplistcreate);
+    for (i = 0; i < opLists.length; i++) {
+        opLists[i].dispatchEvent(this.manager.oplistcreate);
     }
 
     // Add edit button to first category (Favourites)
@@ -204,20 +204,23 @@ HTMLApp.prototype.populate_operations_list = function() {
 /**
  * Sets up the adjustable splitter to allow the user to resize areas of the page.
  */
-HTMLApp.prototype.initialise_splitter = function() {
-    Split(["#operations", "#recipe", "#IO"], {
+HTMLApp.prototype.initialiseSplitter = function() {
+    this.columnSplitter = Split(["#operations", "#recipe", "#IO"], {
         sizes: [20, 30, 50],
-        minSize: [240, 325, 500],
+        minSize: [240, 325, 440],
         gutterSize: 4,
-        onDrag: this.manager.controls.adjust_width.bind(this.manager.controls)
+        onDrag: function() {
+            this.manager.controls.adjustWidth();
+            this.manager.output.adjustWidth();
+        }.bind(this)
     });
 
-    Split(["#input", "#output"], {
+    this.ioSplitter = Split(["#input", "#output"], {
         direction: "vertical",
         gutterSize: 4,
     });
 
-    this.reset_layout();
+    this.resetLayout();
 };
 
 
@@ -225,16 +228,16 @@ HTMLApp.prototype.initialise_splitter = function() {
  * Loads the information previously saved to the HTML5 local storage object so that user options
  * and favourites can be restored.
  */
-HTMLApp.prototype.load_local_storage = function() {
+HTMLApp.prototype.loadLocalStorage = function() {
     // Load options
-    var l_options;
+    var lOptions;
     if (localStorage.options !== undefined) {
-        l_options = JSON.parse(localStorage.options);
+        lOptions = JSON.parse(localStorage.options);
     }
-    this.manager.options.load(l_options);
+    this.manager.options.load(lOptions);
 
     // Load favourites
-    this.load_favourites();
+    this.loadFavourites();
 };
 
 
@@ -243,21 +246,21 @@ HTMLApp.prototype.load_local_storage = function() {
  * Favourites category with them.
  * If the user currently has no saved favourites, the defaults from the view constructor are used.
  */
-HTMLApp.prototype.load_favourites = function() {
+HTMLApp.prototype.loadFavourites = function() {
     var favourites = localStorage.favourites &&
         localStorage.favourites.length > 2 ?
         JSON.parse(localStorage.favourites) :
         this.dfavourites;
 
-    favourites = this.valid_favourites(favourites);
-    this.save_favourites(favourites);
+    favourites = this.validFavourites(favourites);
+    this.saveFavourites(favourites);
 
-    var fav_cat = this.categories.filter(function(c) {
+    var favCat = this.categories.filter(function(c) {
         return c.name === "Favourites";
     })[0];
 
-    if (fav_cat) {
-        fav_cat.ops = favourites;
+    if (favCat) {
+        favCat.ops = favourites;
     } else {
         this.categories.unshift({
             name: "Favourites",
@@ -274,17 +277,17 @@ HTMLApp.prototype.load_favourites = function() {
  * @param {string[]} favourites - A list of the user's favourite operations
  * @returns {string[]} A list of the valid favourites
  */
-HTMLApp.prototype.valid_favourites = function(favourites) {
-    var valid_favs = [];
+HTMLApp.prototype.validFavourites = function(favourites) {
+    var validFavs = [];
     for (var i = 0; i < favourites.length; i++) {
         if (this.operations.hasOwnProperty(favourites[i])) {
-            valid_favs.push(favourites[i]);
+            validFavs.push(favourites[i]);
         } else {
-            this.alert("The operation \"" + Utils.escape_html(favourites[i]) +
+            this.alert("The operation \"" + Utils.escapeHtml(favourites[i]) +
                 "\" is no longer available. It has been removed from your favourites.", "info");
         }
     }
-    return valid_favs;
+    return validFavs;
 };
 
 
@@ -293,8 +296,8 @@ HTMLApp.prototype.valid_favourites = function(favourites) {
  *
  * @param {string[]} favourites - A list of the user's favourite operations
  */
-HTMLApp.prototype.save_favourites = function(favourites) {
-    localStorage.setItem("favourites", JSON.stringify(this.valid_favourites(favourites)));
+HTMLApp.prototype.saveFavourites = function(favourites) {
+    localStorage.setItem("favourites", JSON.stringify(this.validFavourites(favourites)));
 };
 
 
@@ -302,11 +305,11 @@ HTMLApp.prototype.save_favourites = function(favourites) {
  * Resets favourite operations back to the default as specified in the view constructor and
  * refreshes the operation list.
  */
-HTMLApp.prototype.reset_favourites = function() {
-    this.save_favourites(this.dfavourites);
-    this.load_favourites();
-    this.populate_operations_list();
-    this.manager.recipe.initialise_operation_drag_n_drop();
+HTMLApp.prototype.resetFavourites = function() {
+    this.saveFavourites(this.dfavourites);
+    this.loadFavourites();
+    this.populateOperationsList();
+    this.manager.recipe.initialiseOperationDragNDrop();
 };
 
 
@@ -315,7 +318,7 @@ HTMLApp.prototype.reset_favourites = function() {
  *
  * @param {string} name - The name of the operation
  */
-HTMLApp.prototype.add_favourite = function(name) {
+HTMLApp.prototype.addFavourite = function(name) {
     var favourites = JSON.parse(localStorage.favourites);
 
     if (favourites.indexOf(name) >= 0) {
@@ -324,19 +327,19 @@ HTMLApp.prototype.add_favourite = function(name) {
     }
 
     favourites.push(name);
-    this.save_favourites(favourites);
-    this.load_favourites();
-    this.populate_operations_list();
-    this.manager.recipe.initialise_operation_drag_n_drop();
+    this.saveFavourites(favourites);
+    this.loadFavourites();
+    this.populateOperationsList();
+    this.manager.recipe.initialiseOperationDragNDrop();
 };
 
 
 /**
  * Checks for input and recipe in the URI parameters and loads them if present.
  */
-HTMLApp.prototype.load_URI_params = function() {
+HTMLApp.prototype.loadURIParams = function() {
     // Load query string from URI
-    this.query_string = (function(a) {
+    this.queryString = (function(a) {
         if (a === "") return {};
         var b = {};
         for (var i = 0; i < a.length; i++) {
@@ -351,46 +354,46 @@ HTMLApp.prototype.load_URI_params = function() {
     })(window.location.search.substr(1).split("&"));
 
     // Turn off auto-bake while loading
-    var auto_bake_val = this.auto_bake_;
-    this.auto_bake_ = false;
+    var autoBakeVal = this.autoBake_;
+    this.autoBake_ = false;
 
     // Read in recipe from query string
-    if (this.query_string.recipe) {
+    if (this.queryString.recipe) {
         try {
-            var recipe_config = JSON.parse(this.query_string.recipe);
-            this.set_recipe_config(recipe_config);
+            var recipeConfig = JSON.parse(this.queryString.recipe);
+            this.setRecipeConfig(recipeConfig);
         } catch(err) {}
-    } else if (this.query_string.op) {
+    } else if (this.queryString.op) {
         // If there's no recipe, look for single operations
-        this.manager.recipe.clear_recipe();
+        this.manager.recipe.clearRecipe();
         try {
-            this.manager.recipe.add_operation(this.query_string.op);
+            this.manager.recipe.addOperation(this.queryString.op);
         } catch(err) {
             // If no exact match, search for nearest match and add that
-            var matched_ops = this.manager.ops.filter_operations(this.query_string.op, false);
-            if (matched_ops.length) {
-                this.manager.recipe.add_operation(matched_ops[0].name);
+            var matchedOps = this.manager.ops.filterOperations(this.queryString.op, false);
+            if (matchedOps.length) {
+                this.manager.recipe.addOperation(matchedOps[0].name);
             }
 
             // Populate search with the string
             var search = document.getElementById("search");
 
-            search.value = this.query_string.op;
+            search.value = this.queryString.op;
             search.dispatchEvent(new Event("search"));
         }
     }
 
     // Read in input data from query string
-    if (this.query_string.input) {
+    if (this.queryString.input) {
         try {
-            var input_data = Utils.from_base64(this.query_string.input);
-            this.set_input(input_data);
+            var inputData = Utils.fromBase64(this.queryString.input);
+            this.setInput(inputData);
         } catch(err) {}
     }
 
     // Restore auto-bake state
-    this.auto_bake_ = auto_bake_val;
-    this.auto_bake();
+    this.autoBake_ = autoBakeVal;
+    this.autoBake();
 };
 
 
@@ -399,8 +402,8 @@ HTMLApp.prototype.load_URI_params = function() {
  *
  * @returns {number}
  */
-HTMLApp.prototype.next_ing_id = function() {
-    return this.ing_id++;
+HTMLApp.prototype.nextIngId = function() {
+    return this.ingId++;
 };
 
 
@@ -409,48 +412,48 @@ HTMLApp.prototype.next_ing_id = function() {
  *
  * @returns {Object[]}
  */
-HTMLApp.prototype.get_recipe_config = function() {
-    var recipe_config = this.manager.recipe.get_config();
-    sessionStorage.setItem("recipe_config", JSON.stringify(recipe_config));
-    return recipe_config;
+HTMLApp.prototype.getRecipeConfig = function() {
+    var recipeConfig = this.manager.recipe.getConfig();
+    sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
+    return recipeConfig;
 };
 
 
 /**
  * Given a recipe configuration, sets the recipe to that configuration.
  *
- * @param {Object[]} recipe_config - The recipe configuration
+ * @param {Object[]} recipeConfig - The recipe configuration
  */
-HTMLApp.prototype.set_recipe_config = function(recipe_config) {
-    sessionStorage.setItem("recipe_config", JSON.stringify(recipe_config));
-    document.getElementById("rec_list").innerHTML = null;
+HTMLApp.prototype.setRecipeConfig = function(recipeConfig) {
+    sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
+    document.getElementById("rec-list").innerHTML = null;
 
-    for (var i = 0; i < recipe_config.length; i++) {
-        var item = this.manager.recipe.add_operation(recipe_config[i].op);
+    for (var i = 0; i < recipeConfig.length; i++) {
+        var item = this.manager.recipe.addOperation(recipeConfig[i].op);
 
         // Populate arguments
         var args = item.querySelectorAll(".arg");
         for (var j = 0; j < args.length; j++) {
             if (args[j].getAttribute("type") === "checkbox") {
                 // checkbox
-                args[j].checked = recipe_config[i].args[j];
+                args[j].checked = recipeConfig[i].args[j];
             } else if (args[j].classList.contains("toggle-string")) {
-                // toggle_string
-                args[j].value = recipe_config[i].args[j].string;
+                // toggleString
+                args[j].value = recipeConfig[i].args[j].string;
                 args[j].previousSibling.children[0].innerHTML =
-                    Utils.escape_html(recipe_config[i].args[j].option) +
+                    Utils.escapeHtml(recipeConfig[i].args[j].option) +
                     " <span class='caret'></span>";
             } else {
                 // all others
-                args[j].value = recipe_config[i].args[j];
+                args[j].value = recipeConfig[i].args[j];
             }
         }
 
         // Set disabled and breakpoint
-        if (recipe_config[i].disabled) {
+        if (recipeConfig[i].disabled) {
             item.querySelector(".disable-icon").click();
         }
-        if (recipe_config[i].breakpoint) {
+        if (recipeConfig[i].breakpoint) {
             item.querySelector(".breakpoint").click();
         }
 
@@ -462,33 +465,31 @@ HTMLApp.prototype.set_recipe_config = function(recipe_config) {
 /**
  * Resets the splitter positions to default.
  */
-HTMLApp.prototype.reset_layout = function() {
-    document.getElementById("operations").style.width = "calc(20% - 2px)";
-    document.getElementById("recipe").style.width = "calc(30% - 4px)";
-    document.getElementById("IO").style.width = "calc(50% - 2px)";
-    document.getElementById("input").style.height = "calc(50% - 2px)";
-    document.getElementById("output").style.height = "calc(50% - 2px)";
-
-    this.manager.controls.adjust_width();
+HTMLApp.prototype.resetLayout = function() {
+    this.columnSplitter.setSizes([20, 30, 50]);
+    this.ioSplitter.setSizes([50, 50]);
+
+    this.manager.controls.adjustWidth();
+    this.manager.output.adjustWidth();
 };
 
 
 /**
  * Sets the compile message.
  */
-HTMLApp.prototype.set_compile_message = function() {
+HTMLApp.prototype.setCompileMessage = function() {
     // Display time since last build and compile message
     var now = new Date(),
-        time_since_compile = Utils.fuzzy_time(now.getTime() - window.compile_time),
-        compile_info = "<span style=\"font-weight: normal\">Last build: " +
-            time_since_compile.substr(0, 1).toUpperCase() + time_since_compile.substr(1) + " ago";
+        timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime),
+        compileInfo = "<span style=\"font-weight: normal\">Last build: " +
+            timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1) + " ago";
 
-    if (window.compile_message !== "") {
-        compile_info += " - " + window.compile_message;
+    if (window.compileMessage !== "") {
+        compileInfo += " - " + window.compileMessage;
     }
 
-    compile_info += "</span>";
-    document.getElementById("notice").innerHTML = compile_info;
+    compileInfo += "</span>";
+    document.getElementById("notice").innerHTML = compileInfo;
 };
 
 
@@ -524,32 +525,32 @@ HTMLApp.prototype.alert = function(str, style, timeout, silent) {
     style = style || "danger";
     timeout = timeout || 0;
 
-    var alert_el = document.getElementById("alert"),
-        alert_content = document.getElementById("alert-content");
+    var alertEl = document.getElementById("alert"),
+        alertContent = document.getElementById("alert-content");
 
-    alert_el.classList.remove("alert-danger");
-    alert_el.classList.remove("alert-warning");
-    alert_el.classList.remove("alert-info");
-    alert_el.classList.remove("alert-success");
-    alert_el.classList.add("alert-" + style);
+    alertEl.classList.remove("alert-danger");
+    alertEl.classList.remove("alert-warning");
+    alertEl.classList.remove("alert-info");
+    alertEl.classList.remove("alert-success");
+    alertEl.classList.add("alert-" + style);
 
     // If the box hasn't been closed, append to it rather than replacing
-    if (alert_el.style.display === "block") {
-        alert_content.innerHTML +=
+    if (alertEl.style.display === "block") {
+        alertContent.innerHTML +=
             "<br><br>[" + time.toLocaleTimeString() + "] " + str;
     } else {
-        alert_content.innerHTML =
+        alertContent.innerHTML =
             "[" + time.toLocaleTimeString() + "] " + str;
     }
 
     // Stop the animation if it is in progress
     $("#alert").stop();
-    alert_el.style.display = "block";
-    alert_el.style.opacity = 1;
+    alertEl.style.display = "block";
+    alertEl.style.opacity = 1;
 
     if (timeout > 0) {
-        clearTimeout(this.alert_timeout);
-        this.alert_timeout = setTimeout(function(){
+        clearTimeout(this.alertTimeout);
+        this.alertTimeout = setTimeout(function(){
             $("#alert").slideUp(100);
         }, timeout);
     }
@@ -575,20 +576,20 @@ HTMLApp.prototype.confirm = function(title, body, callback, scope) {
     document.getElementById("confirm-body").innerHTML = body;
     document.getElementById("confirm-modal").style.display = "block";
 
-    this.confirm_closed = false;
+    this.confirmClosed = false;
     $("#confirm-modal").modal()
         .one("show.bs.modal", function(e) {
-            this.confirm_closed = false;
+            this.confirmClosed = false;
         }.bind(this))
         .one("click", "#confirm-yes", function() {
-            this.confirm_closed = true;
+            this.confirmClosed = true;
             callback.bind(scope)(true);
             $("#confirm-modal").modal("hide");
         }.bind(this))
         .one("hide.bs.modal", function(e) {
-            if (!this.confirm_closed)
+            if (!this.confirmClosed)
                 callback.bind(scope)(false);
-            this.confirm_closed = true;
+            this.confirmClosed = true;
         }.bind(this));
 };
 
@@ -597,7 +598,7 @@ HTMLApp.prototype.confirm = function(title, body, callback, scope) {
  * Handler for the alert close button click event.
  * Closes the alert box.
  */
-HTMLApp.prototype.alert_close_click = function() {
+HTMLApp.prototype.alertCloseClick = function() {
     document.getElementById("alert").style.display = "none";
 };
 
@@ -609,13 +610,13 @@ HTMLApp.prototype.alert_close_click = function() {
  * @listens Manager#statechange
  * @param {event} e
  */
-HTMLApp.prototype.state_change = function(e) {
-    this.auto_bake();
+HTMLApp.prototype.stateChange = function(e) {
+    this.autoBake();
 
     // Update the current history state (not creating a new one)
-    if (this.options.update_url) {
-        this.last_state_url = this.manager.controls.generate_state_url(true, true);
-        window.history.replaceState({}, "CyberChef", this.last_state_url);
+    if (this.options.updateUrl) {
+        this.lastStateUrl = this.manager.controls.generateStateUrl(true, true);
+        window.history.replaceState({}, "CyberChef", this.lastStateUrl);
     }
 };
 
@@ -626,9 +627,9 @@ HTMLApp.prototype.state_change = function(e) {
  *
  * @param {event} e
  */
-HTMLApp.prototype.pop_state = function(e) {
-    if (window.location.href.split("#")[0] !== this.last_state_url) {
-        this.load_URI_params();
+HTMLApp.prototype.popState = function(e) {
+    if (window.location.href.split("#")[0] !== this.lastStateUrl) {
+        this.loadURIParams();
     }
 };
 
@@ -636,11 +637,11 @@ HTMLApp.prototype.pop_state = function(e) {
 /**
  * Function to call an external API from this view.
  */
-HTMLApp.prototype.call_api = function(url, type, data, data_type, content_type) {
+HTMLApp.prototype.callApi = function(url, type, data, dataType, contentType) {
     type = type || "POST";
     data = data || {};
-    data_type = data_type || undefined;
-    content_type = content_type || "application/json";
+    dataType = dataType || undefined;
+    contentType = contentType || "application/json";
 
     var response = null,
         success = false;
@@ -650,8 +651,8 @@ HTMLApp.prototype.call_api = function(url, type, data, data_type, content_type)
         async: false,
         type: type,
         data: data,
-        dataType: data_type,
-        contentType: content_type,
+        dataType: dataType,
+        contentType: contentType,
         success: function(data) {
             success = true;
             response = data;

+ 10 - 10
src/js/views/html/HTMLCategory.js

@@ -12,7 +12,7 @@
 var HTMLCategory = function(name, selected) {
     this.name = name;
     this.selected = selected;
-    this.op_list = [];
+    this.opList = [];
 };
 
 
@@ -21,8 +21,8 @@ var HTMLCategory = function(name, selected) {
  *
  * @param {HTMLOperation} operation - The operation to add.
  */
-HTMLCategory.prototype.add_operation = function(operation) {
-    this.op_list.push(operation);
+HTMLCategory.prototype.addOperation = function(operation) {
+    this.opList.push(operation);
 };
 
 
@@ -31,18 +31,18 @@ HTMLCategory.prototype.add_operation = function(operation) {
  *
  * @returns {string}
  */
-HTMLCategory.prototype.to_html = function() {
-    var cat_name = "cat" + this.name.replace(/[\s/-:_]/g, "");
+HTMLCategory.prototype.toHtml = function() {
+    var catName = "cat" + this.name.replace(/[\s/-:_]/g, "");
     var html = "<div class='panel category'>\
         <a class='category-title' data-toggle='collapse'\
-            data-parent='#categories' href='#" + cat_name + "'>\
+            data-parent='#categories' href='#" + catName + "'>\
             " + this.name + "\
         </a>\
-        <div id='" + cat_name + "' class='panel-collapse collapse\
-        " + (this.selected ? " in" : "") + "'><ul class='op_list'>";
+        <div id='" + catName + "' class='panel-collapse collapse\
+        " + (this.selected ? " in" : "") + "'><ul class='op-list'>";
     
-    for (var i = 0; i < this.op_list.length; i++) {
-        html += this.op_list[i].to_stub_html();
+    for (var i = 0; i < this.opList.length; i++) {
+        html += this.opList[i].toStubHtml();
     }
     
     html += "</ul></div></div>";

+ 37 - 37
src/js/views/html/HTMLIngredient.js

@@ -18,11 +18,11 @@ var HTMLIngredient = function(config, app, manager) {
     this.type = config.type;
     this.value = config.value;
     this.disabled = config.disabled || false;
-    this.disable_args = config.disable_args || false;
+    this.disableArgs = config.disableArgs || false;
     this.placeholder = config.placeholder || false;
     this.target = config.target;
-    this.toggle_values = config.toggle_values;
-    this.id = "ing-" + this.app.next_ing_id();
+    this.toggleValues = config.toggleValues;
+    this.id = "ing-" + this.app.nextIngId();
 };
 
 
@@ -31,12 +31,12 @@ var HTMLIngredient = function(config, app, manager) {
  *
  * @returns {string}
  */
-HTMLIngredient.prototype.to_html = function() {
+HTMLIngredient.prototype.toHtml = function() {
     var inline = (this.type === "boolean" ||
                   this.type === "number" ||
                   this.type === "option" ||
-                  this.type === "short_string" ||
-                  this.type === "binary_short_string"),
+                  this.type === "shortString" ||
+                  this.type === "binaryShortString"),
         html = inline ? "" : "<div class='clearfix'>&nbsp;</div>",
         i, m;
     
@@ -46,50 +46,50 @@ HTMLIngredient.prototype.to_html = function() {
     
     switch (this.type) {
         case "string":
-        case "binary_string":
-        case "byte_array":
-            html += "<input type='text' id='" + this.id + "' class='arg arg-input' arg_name='" +
+        case "binaryString":
+        case "byteArray":
+            html += "<input type='text' id='" + this.id + "' class='arg arg-input' arg-name='" +
                 this.name + "' value='" + this.value + "'" +
                 (this.disabled ? " disabled='disabled'" : "") +
                 (this.placeholder ? " placeholder='" + this.placeholder + "'" : "") + ">";
             break;
-        case "short_string":
-        case "binary_short_string":
+        case "shortString":
+        case "binaryShortString":
             html += "<input type='text' id='" + this.id +
-                "'class='arg arg-input short-string' arg_name='" + this.name + "'value='" +
+                "'class='arg arg-input short-string' arg-name='" + this.name + "'value='" +
                 this.value + "'" + (this.disabled ? " disabled='disabled'" : "") +
                 (this.placeholder ? " placeholder='" + this.placeholder + "'" : "") + ">";
             break;
-        case "toggle_string":
+        case "toggleString":
             html += "<div class='input-group'><div class='input-group-btn'>\
                 <button type='button' class='btn btn-default dropdown-toggle' data-toggle='dropdown'\
                 aria-haspopup='true' aria-expanded='false'" +
-                (this.disabled ? " disabled='disabled'" : "") + ">" + this.toggle_values[0] +
+                (this.disabled ? " disabled='disabled'" : "") + ">" + this.toggleValues[0] +
                 " <span class='caret'></span></button><ul class='dropdown-menu'>";
-            for (i = 0; i < this.toggle_values.length; i++) {
-                html += "<li><a href='#'>" + this.toggle_values[i] + "</a></li>";
+            for (i = 0; i < this.toggleValues.length; i++) {
+                html += "<li><a href='#'>" + this.toggleValues[i] + "</a></li>";
             }
             html += "</ul></div><input type='text' class='arg arg-input toggle-string'" +
                 (this.disabled ? " disabled='disabled'" : "") +
                 (this.placeholder ? " placeholder='" + this.placeholder + "'" : "") + "></div>";
             break;
         case "number":
-            html += "<input type='number' id='" + this.id + "'class='arg arg-input' arg_name='" +
+            html += "<input type='number' id='" + this.id + "'class='arg arg-input' arg-name='" +
                 this.name + "'value='" + this.value + "'" +
                 (this.disabled ? " disabled='disabled'" : "") +
                 (this.placeholder ? " placeholder='" + this.placeholder + "'" : "") + ">";
             break;
         case "boolean":
-            html += "<input type='checkbox' id='" + this.id + "'class='arg' arg_name='" +
+            html += "<input type='checkbox' id='" + this.id + "'class='arg' arg-name='" +
                 this.name + "'" + (this.value ? " checked='checked' " : "") +
                 (this.disabled ? " disabled='disabled'" : "") + ">";
             
-            if (this.disable_args) {
-                this.manager.add_dynamic_listener("#" + this.id, "click", this.toggle_disable_args, this);
+            if (this.disableArgs) {
+                this.manager.addDynamicListener("#" + this.id, "click", this.toggleDisableArgs, this);
             }
             break;
         case "option":
-            html += "<select class='arg' id='" + this.id + "'arg_name='" + this.name + "'" +
+            html += "<select class='arg' id='" + this.id + "'arg-name='" + this.name + "'" +
                 (this.disabled ? " disabled='disabled'" : "") + ">";
             for (i = 0; i < this.value.length; i++) {
                 if ((m = this.value[i].match(/\[([a-z0-9 -()^]+)\]/i))) {
@@ -102,8 +102,8 @@ HTMLIngredient.prototype.to_html = function() {
             }
             html += "</select>";
             break;
-        case "populate_option":
-            html += "<select class='arg' id='" + this.id + "'arg_name='" + this.name + "'" +
+        case "populateOption":
+            html += "<select class='arg' id='" + this.id + "'arg-name='" + this.name + "'" +
                 (this.disabled ? " disabled='disabled'" : "") + ">";
             for (i = 0; i < this.value.length; i++) {
                 if ((m = this.value[i].name.match(/\[([a-z0-9 -()^]+)\]/i))) {
@@ -117,9 +117,9 @@ HTMLIngredient.prototype.to_html = function() {
             }
             html += "</select>";
             
-            this.manager.add_dynamic_listener("#" + this.id, "change", this.populate_option_change, this);
+            this.manager.addDynamicListener("#" + this.id, "change", this.populateOptionChange, this);
             break;
-        case "editable_option":
+        case "editableOption":
             html += "<div class='editable-option'>";
             html += "<select class='editable-option-select' id='sel-" + this.id + "'" +
                 (this.disabled ? " disabled='disabled'" : "") + ">";
@@ -128,16 +128,16 @@ HTMLIngredient.prototype.to_html = function() {
             }
             html += "</select>";
             html += "<input class='arg arg-input editable-option-input' id='" + this.id +
-                "'arg_name='" + this.name + "'" + " value='" + this.value[0].value + "'" +
+                "'arg-name='" + this.name + "'" + " value='" + this.value[0].value + "'" +
                 (this.disabled ? " disabled='disabled'" : "") +
                 (this.placeholder ? " placeholder='" + this.placeholder + "'" : "") + ">";
             html += "</div>";
             
             
-            this.manager.add_dynamic_listener("#sel-" + this.id, "change", this.editable_option_change, this);
+            this.manager.addDynamicListener("#sel-" + this.id, "change", this.editableOptionChange, this);
             break;
         case "text":
-            html += "<textarea id='" + this.id + "' class='arg' arg_name='" +
+            html += "<textarea id='" + this.id + "' class='arg' arg-name='" +
                 this.name + "'" + (this.disabled ? " disabled='disabled'" : "") +
                 (this.placeholder ? " placeholder='" + this.placeholder + "'" : "") + ">" +
                 this.value + "</textarea>";
@@ -153,18 +153,18 @@ HTMLIngredient.prototype.to_html = function() {
 
 /**
  * Handler for argument disable toggle.
- * Toggles disabled state for all arguments in the disable_args list for this ingredient.
+ * Toggles disabled state for all arguments in the disableArgs list for this ingredient.
  *
  * @param {event} e
  */
-HTMLIngredient.prototype.toggle_disable_args = function(e) {
+HTMLIngredient.prototype.toggleDisableArgs = function(e) {
     var el = e.target,
         op = el.parentNode.parentNode,
         args = op.querySelectorAll(".arg-group"),
         els;
         
-    for (var i = 0; i < this.disable_args.length; i++) {
-        els = args[this.disable_args[i]].querySelectorAll("input, select, button");
+    for (var i = 0; i < this.disableArgs.length; i++) {
+        els = args[this.disableArgs[i]].querySelectorAll("input, select, button");
         
         for (var j = 0; j < els.length; j++) {
             if (els[j].getAttribute("disabled")) {
@@ -175,7 +175,7 @@ HTMLIngredient.prototype.toggle_disable_args = function(e) {
         }
     }
     
-    this.manager.recipe.ing_change();
+    this.manager.recipe.ingChange();
 };
 
 
@@ -185,14 +185,14 @@ HTMLIngredient.prototype.toggle_disable_args = function(e) {
  *
  * @param {event} e
  */
-HTMLIngredient.prototype.populate_option_change = function(e) {
+HTMLIngredient.prototype.populateOptionChange = function(e) {
     var el = e.target,
         op = el.parentNode.parentNode,
         target = op.querySelectorAll(".arg-group")[this.target].querySelector("input, select, textarea");
 
     target.value = el.childNodes[el.selectedIndex].getAttribute("populate-value");
     
-    this.manager.recipe.ing_change();
+    this.manager.recipe.ingChange();
 };
 
 
@@ -202,11 +202,11 @@ HTMLIngredient.prototype.populate_option_change = function(e) {
  *
  * @param {event} e
  */
-HTMLIngredient.prototype.editable_option_change = function(e) {
+HTMLIngredient.prototype.editableOptionChange = function(e) {
     var select = e.target,
         input = select.nextSibling;
 
     input.value = select.childNodes[select.selectedIndex].value;
     
-    this.manager.recipe.ing_change();
+    this.manager.recipe.ingChange();
 };

+ 20 - 20
src/js/views/html/HTMLOperation.js

@@ -17,13 +17,13 @@ var HTMLOperation = function(name, config, app, manager) {
     
     this.name        = name;
     this.description = config.description;
-    this.manual_bake = config.manual_bake || false;
+    this.manualBake  = config.manualBake || false;
     this.config      = config;
-    this.ing_list    = [];
+    this.ingList     = [];
     
     for (var i = 0; i < config.args.length; i++) {
         var ing = new HTMLIngredient(config.args[i], this.app, this.manager);
-        this.ing_list.push(ing);
+        this.ingList.push(ing);
     }
 };
 
@@ -43,7 +43,7 @@ HTMLOperation.REMOVE_ICON = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABwkl
  *
  * @returns {string}
  */
-HTMLOperation.prototype.to_stub_html = function(remove_icon) {
+HTMLOperation.prototype.toStubHtml = function(removeIcon) {
     var html = "<li class='operation'";
     
     if (this.description) {
@@ -53,7 +53,7 @@ HTMLOperation.prototype.to_stub_html = function(remove_icon) {
     
     html += ">" + this.name;
     
-    if (remove_icon) {
+    if (removeIcon) {
         html += "<img src='data:image/png;base64," + HTMLOperation.REMOVE_ICON +
             "' class='op-icon remove-icon'>";
     }
@@ -73,11 +73,11 @@ HTMLOperation.prototype.to_stub_html = function(remove_icon) {
  *
  * @returns {string}
  */
-HTMLOperation.prototype.to_full_html = function() {
+HTMLOperation.prototype.toFullHtml = function() {
     var html = "<div class='arg-title'>" + this.name + "</div>";
 
-    for (var i = 0; i < this.ing_list.length; i++) {
-        html += this.ing_list[i].to_html();
+    for (var i = 0; i < this.ingList.length; i++) {
+        html += this.ingList[i].toHtml();
     }
     
     html += "<div class='recip-icons'>\
@@ -95,20 +95,20 @@ HTMLOperation.prototype.to_full_html = function() {
 /**
  * Highlights the searched string in the name and description of the operation.
  *
- * @param {string} search_str
- * @param {number} name_pos - The position of the search string in the operation name
- * @param {number} desc_pos - The position of the search string in the operation description
+ * @param {string} searchStr
+ * @param {number} namePos - The position of the search string in the operation name
+ * @param {number} descPos - The position of the search string in the operation description
  */
-HTMLOperation.prototype.highlight_search_string = function(search_str, name_pos, desc_pos) {
-    if (name_pos >= 0) {
-        this.name = this.name.slice(0, name_pos) + "<b><u>" +
-            this.name.slice(name_pos, name_pos + search_str.length) + "</u></b>" +
-            this.name.slice(name_pos + search_str.length);
+HTMLOperation.prototype.highlightSearchString = function(searchStr, namePos, descPos) {
+    if (namePos >= 0) {
+        this.name = this.name.slice(0, namePos) + "<b><u>" +
+            this.name.slice(namePos, namePos + searchStr.length) + "</u></b>" +
+            this.name.slice(namePos + searchStr.length);
     }
     
-    if (this.description && desc_pos >= 0) {
-        this.description = this.description.slice(0, desc_pos) + "<b><u>" +
-            this.description.slice(desc_pos, desc_pos + search_str.length) + "</u></b>" +
-            this.description.slice(desc_pos + search_str.length);
+    if (this.description && descPos >= 0) {
+        this.description = this.description.slice(0, descPos) + "<b><u>" +
+            this.description.slice(descPos, descPos + searchStr.length) + "</u></b>" +
+            this.description.slice(descPos + searchStr.length);
     }
 };

+ 88 - 88
src/js/views/html/HighlighterWaiter.js

@@ -11,8 +11,8 @@
 var HighlighterWaiter = function(app) {
     this.app = app;
 
-    this.mouse_button_down = false;
-    this.mouse_target = null;
+    this.mouseButtonDown = false;
+    this.mouseTarget = null;
 };
 
 
@@ -37,7 +37,7 @@ HighlighterWaiter.OUTPUT = 1;
  * @private
  * @returns {boolean}
  */
-HighlighterWaiter.prototype._is_selection_backwards = function() {
+HighlighterWaiter.prototype._isSelectionBackwards = function() {
     var backwards = false,
         sel = window.getSelection();
 
@@ -60,7 +60,7 @@ HighlighterWaiter.prototype._is_selection_backwards = function() {
  * @param {number} offset - The offset since the last HTML element.
  * @returns {number}
  */
-HighlighterWaiter.prototype._get_output_html_offset = function(node, offset) {
+HighlighterWaiter.prototype._getOutputHtmlOffset = function(node, offset) {
     var sel = window.getSelection(),
         range = document.createRange();
 
@@ -81,7 +81,7 @@ HighlighterWaiter.prototype._get_output_html_offset = function(node, offset) {
  * @returns {number} pos.start
  * @returns {number} pos.end
  */
-HighlighterWaiter.prototype._get_output_html_selection_offsets = function() {
+HighlighterWaiter.prototype._getOutputHtmlSelectionOffsets = function() {
     var sel = window.getSelection(),
         range,
         start = 0,
@@ -90,9 +90,9 @@ HighlighterWaiter.prototype._get_output_html_selection_offsets = function() {
 
     if (sel.rangeCount) {
         range = sel.getRangeAt(sel.rangeCount - 1);
-        backwards = this._is_selection_backwards();
-        start = this._get_output_html_offset(range.startContainer, range.startOffset);
-        end = this._get_output_html_offset(range.endContainer, range.endOffset);
+        backwards = this._isSelectionBackwards();
+        start = this._getOutputHtmlOffset(range.startContainer, range.startOffset);
+        end = this._getOutputHtmlOffset(range.endContainer, range.endOffset);
         sel.removeAllRanges();
         sel.addRange(range);
 
@@ -117,7 +117,7 @@ HighlighterWaiter.prototype._get_output_html_selection_offsets = function() {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.input_scroll = function(e) {
+HighlighterWaiter.prototype.inputScroll = function(e) {
     var el = e.target;
     document.getElementById("input-highlighter").scrollTop = el.scrollTop;
     document.getElementById("input-highlighter").scrollLeft = el.scrollLeft;
@@ -130,7 +130,7 @@ HighlighterWaiter.prototype.input_scroll = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.output_scroll = function(e) {
+HighlighterWaiter.prototype.outputScroll = function(e) {
     var el = e.target;
     document.getElementById("output-highlighter").scrollTop = el.scrollTop;
     document.getElementById("output-highlighter").scrollLeft = el.scrollLeft;
@@ -143,18 +143,18 @@ HighlighterWaiter.prototype.output_scroll = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.input_mousedown = function(e) {
-    this.mouse_button_down = true;
-    this.mouse_target = HighlighterWaiter.INPUT;
-    this.remove_highlights();
+HighlighterWaiter.prototype.inputMousedown = function(e) {
+    this.mouseButtonDown = true;
+    this.mouseTarget = HighlighterWaiter.INPUT;
+    this.removeHighlights();
 
     var el = e.target,
         start = el.selectionStart,
         end = el.selectionEnd;
 
     if (start !== 0 || end !== 0) {
-        document.getElementById("input-selection-info").innerHTML = this.selection_info(start, end);
-        this.highlight_output([{start: start, end: end}]);
+        document.getElementById("input-selection-info").innerHTML = this.selectionInfo(start, end);
+        this.highlightOutput([{start: start, end: end}]);
     }
 };
 
@@ -165,18 +165,18 @@ HighlighterWaiter.prototype.input_mousedown = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.output_mousedown = function(e) {
-    this.mouse_button_down = true;
-    this.mouse_target = HighlighterWaiter.OUTPUT;
-    this.remove_highlights();
+HighlighterWaiter.prototype.outputMousedown = function(e) {
+    this.mouseButtonDown = true;
+    this.mouseTarget = HighlighterWaiter.OUTPUT;
+    this.removeHighlights();
 
     var el = e.target,
         start = el.selectionStart,
         end = el.selectionEnd;
 
     if (start !== 0 || end !== 0) {
-        document.getElementById("output-selection-info").innerHTML = this.selection_info(start, end);
-        this.highlight_input([{start: start, end: end}]);
+        document.getElementById("output-selection-info").innerHTML = this.selectionInfo(start, end);
+        this.highlightInput([{start: start, end: end}]);
     }
 };
 
@@ -187,13 +187,13 @@ HighlighterWaiter.prototype.output_mousedown = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.output_html_mousedown = function(e) {
-    this.mouse_button_down = true;
-    this.mouse_target = HighlighterWaiter.OUTPUT;
+HighlighterWaiter.prototype.outputHtmlMousedown = function(e) {
+    this.mouseButtonDown = true;
+    this.mouseTarget = HighlighterWaiter.OUTPUT;
 
-    var sel = this._get_output_html_selection_offsets();
+    var sel = this._getOutputHtmlSelectionOffsets();
     if (sel.start !== 0 || sel.end !== 0) {
-        document.getElementById("output-selection-info").innerHTML = this.selection_info(sel.start, sel.end);
+        document.getElementById("output-selection-info").innerHTML = this.selectionInfo(sel.start, sel.end);
     }
 };
 
@@ -203,8 +203,8 @@ HighlighterWaiter.prototype.output_html_mousedown = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.input_mouseup = function(e) {
-    this.mouse_button_down = false;
+HighlighterWaiter.prototype.inputMouseup = function(e) {
+    this.mouseButtonDown = false;
 };
 
 
@@ -213,8 +213,8 @@ HighlighterWaiter.prototype.input_mouseup = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.output_mouseup = function(e) {
-    this.mouse_button_down = false;
+HighlighterWaiter.prototype.outputMouseup = function(e) {
+    this.mouseButtonDown = false;
 };
 
 
@@ -223,8 +223,8 @@ HighlighterWaiter.prototype.output_mouseup = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.output_html_mouseup = function(e) {
-    this.mouse_button_down = false;
+HighlighterWaiter.prototype.outputHtmlMouseup = function(e) {
+    this.mouseButtonDown = false;
 };
 
 
@@ -234,11 +234,11 @@ HighlighterWaiter.prototype.output_html_mouseup = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.input_mousemove = function(e) {
+HighlighterWaiter.prototype.inputMousemove = function(e) {
     // Check that the left mouse button is pressed
-    if (!this.mouse_button_down ||
+    if (!this.mouseButtonDown ||
         e.which !== 1 ||
-        this.mouse_target !== HighlighterWaiter.INPUT)
+        this.mouseTarget !== HighlighterWaiter.INPUT)
         return;
 
     var el = e.target,
@@ -246,8 +246,8 @@ HighlighterWaiter.prototype.input_mousemove = function(e) {
         end = el.selectionEnd;
 
     if (start !== 0 || end !== 0) {
-        document.getElementById("input-selection-info").innerHTML = this.selection_info(start, end);
-        this.highlight_output([{start: start, end: end}]);
+        document.getElementById("input-selection-info").innerHTML = this.selectionInfo(start, end);
+        this.highlightOutput([{start: start, end: end}]);
     }
 };
 
@@ -258,11 +258,11 @@ HighlighterWaiter.prototype.input_mousemove = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.output_mousemove = function(e) {
+HighlighterWaiter.prototype.outputMousemove = function(e) {
     // Check that the left mouse button is pressed
-    if (!this.mouse_button_down ||
+    if (!this.mouseButtonDown ||
         e.which !== 1 ||
-        this.mouse_target !== HighlighterWaiter.OUTPUT)
+        this.mouseTarget !== HighlighterWaiter.OUTPUT)
         return;
 
     var el = e.target,
@@ -270,8 +270,8 @@ HighlighterWaiter.prototype.output_mousemove = function(e) {
         end = el.selectionEnd;
 
     if (start !== 0 || end !== 0) {
-        document.getElementById("output-selection-info").innerHTML = this.selection_info(start, end);
-        this.highlight_input([{start: start, end: end}]);
+        document.getElementById("output-selection-info").innerHTML = this.selectionInfo(start, end);
+        this.highlightInput([{start: start, end: end}]);
     }
 };
 
@@ -282,16 +282,16 @@ HighlighterWaiter.prototype.output_mousemove = function(e) {
  *
  * @param {event} e
  */
-HighlighterWaiter.prototype.output_html_mousemove = function(e) {
+HighlighterWaiter.prototype.outputHtmlMousemove = function(e) {
     // Check that the left mouse button is pressed
-    if (!this.mouse_button_down ||
+    if (!this.mouseButtonDown ||
         e.which !== 1 ||
-        this.mouse_target !== HighlighterWaiter.OUTPUT)
+        this.mouseTarget !== HighlighterWaiter.OUTPUT)
         return;
 
-    var sel = this._get_output_html_selection_offsets();
+    var sel = this._getOutputHtmlSelectionOffsets();
     if (sel.start !== 0 || sel.end !== 0) {
-        document.getElementById("output-selection-info").innerHTML = this.selection_info(sel.start, sel.end);
+        document.getElementById("output-selection-info").innerHTML = this.selectionInfo(sel.start, sel.end);
     }
 };
 
@@ -304,21 +304,21 @@ HighlighterWaiter.prototype.output_html_mousemove = function(e) {
  * @param {number} end - The end offset.
  * @returns {string}
  */
-HighlighterWaiter.prototype.selection_info = function(start, end) {
+HighlighterWaiter.prototype.selectionInfo = function(start, end) {
     var width = end.toString().length;
     width = width < 2 ? 2 : width;
-    var start_str = Utils.pad(start.toString(), width, " ").replace(/ /g, "&nbsp;"),
-        end_str   = Utils.pad(end.toString(), width, " ").replace(/ /g, "&nbsp;"),
-        len_str   = Utils.pad((end-start).toString(), width, " ").replace(/ /g, "&nbsp;");
+    var startStr = Utils.pad(start.toString(), width, " ").replace(/ /g, "&nbsp;"),
+        endStr   = Utils.pad(end.toString(), width, " ").replace(/ /g, "&nbsp;"),
+        lenStr   = Utils.pad((end-start).toString(), width, " ").replace(/ /g, "&nbsp;");
 
-    return "start: " + start_str + "<br>end: " + end_str + "<br>length: " + len_str;
+    return "start: " + startStr + "<br>end: " + endStr + "<br>length: " + lenStr;
 };
 
 
 /**
  * Removes highlighting and selection information.
  */
-HighlighterWaiter.prototype.remove_highlights = function() {
+HighlighterWaiter.prototype.removeHighlights = function() {
     document.getElementById("input-highlighter").innerHTML = "";
     document.getElementById("output-highlighter").innerHTML = "";
     document.getElementById("input-selection-info").innerHTML = "";
@@ -335,25 +335,25 @@ HighlighterWaiter.prototype.remove_highlights = function() {
  * @returns {function} highlights[].b
  * @returns {Object[]} highlights[].args
  */
-HighlighterWaiter.prototype.generate_highlight_list = function() {
-    var recipe_config = this.app.get_recipe_config(),
+HighlighterWaiter.prototype.generateHighlightList = function() {
+    var recipeConfig = this.app.getRecipeConfig(),
         highlights = [];
 
-    for (var i = 0; i < recipe_config.length; i++) {
-        if (recipe_config[i].disabled) continue;
+    for (var i = 0; i < recipeConfig.length; i++) {
+        if (recipeConfig[i].disabled) continue;
 
         // If any breakpoints are set, do not attempt to highlight
-        if (recipe_config[i].breakpoint) return false;
+        if (recipeConfig[i].breakpoint) return false;
 
-        var op = this.app.operations[recipe_config[i].op];
+        var op = this.app.operations[recipeConfig[i].op];
 
         // If any of the operations do not support highlighting, fail immediately.
         if (op.highlight === false || op.highlight === undefined) return false;
 
         highlights.push({
             f: op.highlight,
-            b: op.highlight_reverse,
-            args: recipe_config[i].args
+            b: op.highlightReverse,
+            args: recipeConfig[i].args
         });
     }
 
@@ -372,10 +372,10 @@ HighlighterWaiter.prototype.generate_highlight_list = function() {
  * @param {number} pos.start - The start offset.
  * @param {number} pos.end - The end offset.
  */
-HighlighterWaiter.prototype.highlight_output = function(pos) {
-    var highlights = this.generate_highlight_list();
+HighlighterWaiter.prototype.highlightOutput = function(pos) {
+    var highlights = this.generateHighlightList();
 
-    if (!highlights || !this.app.auto_bake_) {
+    if (!highlights || !this.app.autoBake_) {
         return false;
     }
 
@@ -388,7 +388,7 @@ HighlighterWaiter.prototype.highlight_output = function(pos) {
         }
     }
 
-    document.getElementById("output-selection-info").innerHTML = this.selection_info(pos[0].start, pos[0].end);
+    document.getElementById("output-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
     this.highlight(
         document.getElementById("output-text"),
         document.getElementById("output-highlighter"),
@@ -407,10 +407,10 @@ HighlighterWaiter.prototype.highlight_output = function(pos) {
  * @param {number} pos.start - The start offset.
  * @param {number} pos.end - The end offset.
  */
-HighlighterWaiter.prototype.highlight_input = function(pos) {
-    var highlights = this.generate_highlight_list();
+HighlighterWaiter.prototype.highlightInput = function(pos) {
+    var highlights = this.generateHighlightList();
 
-    if (!highlights || !this.app.auto_bake_) {
+    if (!highlights || !this.app.autoBake_) {
         return false;
     }
 
@@ -423,7 +423,7 @@ HighlighterWaiter.prototype.highlight_input = function(pos) {
         }
     }
 
-    document.getElementById("input-selection-info").innerHTML = this.selection_info(pos[0].start, pos[0].end);
+    document.getElementById("input-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
     this.highlight(
         document.getElementById("input-text"),
         document.getElementById("input-highlighter"),
@@ -442,17 +442,17 @@ HighlighterWaiter.prototype.highlight_input = function(pos) {
  * @param {number} pos.end - The end offset.
  */
 HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
-    if (!this.app.options.show_highlighter) return false;
-    if (!this.app.options.attempt_highlight) return false;
+    if (!this.app.options.showHighlighter) return false;
+    if (!this.app.options.attemptHighlight) return false;
 
     // Check if there is a carriage return in the output dish as this will not
     // be displayed by the HTML textarea and will mess up highlighting offsets.
-    if (!this.app.dish_str || this.app.dish_str.indexOf("\r") >= 0) return false;
+    if (!this.app.dishStr || this.app.dishStr.indexOf("\r") >= 0) return false;
 
-    var start_placeholder = "[start_highlight]",
-        start_placeholder_regex = /\[start_highlight\]/g,
-        end_placeholder = "[end_highlight]",
-        end_placeholder_regex = /\[end_highlight\]/g,
+    var startPlaceholder = "[startHighlight]",
+        startPlaceholderRegex = /\[startHighlight\]/g,
+        endPlaceholder = "[endHighlight]",
+        endPlaceholderRegex = /\[endHighlight\]/g,
         text = textarea.value;
 
     // Put placeholders in position
@@ -461,33 +461,33 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
     if (pos.length === 1) {
         if (pos[0].end < pos[0].start) return;
         text = text.slice(0, pos[0].start) +
-            start_placeholder + text.slice(pos[0].start, pos[0].end) + end_placeholder +
+            startPlaceholder + text.slice(pos[0].start, pos[0].end) + endPlaceholder +
             text.slice(pos[0].end, text.length);
     } else {
         // O(n^2) - Can anyone improve this without overwriting placeholders?
         var result = "",
-            end_placed = true;
+            endPlaced = true;
 
         for (var i = 0; i < text.length; i++) {
             for (var j = 1; j < pos.length; j++) {
                 if (pos[j].end < pos[j].start) continue;
                 if (pos[j].start === i) {
-                    result += start_placeholder;
-                    end_placed = false;
+                    result += startPlaceholder;
+                    endPlaced = false;
                 }
                 if (pos[j].end === i) {
-                    result += end_placeholder;
-                    end_placed = true;
+                    result += endPlaceholder;
+                    endPlaced = true;
                 }
             }
             result += text[i];
         }
-        if (!end_placed) result += end_placeholder;
+        if (!endPlaced) result += endPlaceholder;
         text = result;
     }
 
-    var css_class = "hl1";
-    //if (colour) css_class += "-"+colour;
+    var cssClass = "hl1";
+    //if (colour) cssClass += "-"+colour;
 
     // Remove HTML tags
     text = text.replace(/&/g, "&amp;")
@@ -495,8 +495,8 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
                 .replace(/>/g, "&gt;")
                 .replace(/\n/g, "&#10;")
                 // Convert placeholders to tags
-                .replace(start_placeholder_regex, "<span class=\""+css_class+"\">")
-                .replace(end_placeholder_regex, "</span>") + "&nbsp;";
+                .replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
+                .replace(endPlaceholderRegex, "</span>") + "&nbsp;";
 
     // Adjust width to allow for scrollbars
     highlighter.style.width = textarea.clientWidth + "px";

+ 29 - 29
src/js/views/html/InputWaiter.js

@@ -14,7 +14,7 @@ var InputWaiter = function(app, manager) {
     this.manager = manager;
     
     // Define keys that don't change the input so we don't have to autobake when they are pressed
-    this.bad_keys = [
+    this.badKeys = [
         16, //Shift
         17, //Ctrl
         18, //Alt
@@ -62,14 +62,14 @@ InputWaiter.prototype.set = function(input) {
  * @param {number} length - The length of the current input string
  * @param {number} lines - The number of the lines in the current input string
  */
-InputWaiter.prototype.set_input_info = function(length, lines) {
+InputWaiter.prototype.setInputInfo = function(length, lines) {
     var width = length.toString().length;
     width = width < 2 ? 2 : width;
     
-    var length_str = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
-    var lines_str  = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
+    var lengthStr = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
+    var linesStr  = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
         
-    document.getElementById("input-info").innerHTML = "length: " + length_str + "<br>lines: " + lines_str;
+    document.getElementById("input-info").innerHTML = "length: " + lengthStr + "<br>lines: " + linesStr;
 };
 
 
@@ -81,21 +81,21 @@ InputWaiter.prototype.set_input_info = function(length, lines) {
  *
  * @fires Manager#statechange
  */
-InputWaiter.prototype.input_change = function(e) {
+InputWaiter.prototype.inputChange = function(e) {
     // Remove highlighting from input and output panes as the offsets might be different now
-    this.manager.highlighter.remove_highlights();
+    this.manager.highlighter.removeHighlights();
     
     // Reset recipe progress as any previous processing will be redundant now
     this.app.progress = 0;
     
     // Update the input metadata info
-    var input_text = this.get(),
-        lines = input_text.count("\n") + 1;
+    var inputText = this.get(),
+        lines = inputText.count("\n") + 1;
         
-    this.set_input_info(input_text.length, lines);
+    this.setInputInfo(inputText.length, lines);
     
     
-    if (this.bad_keys.indexOf(e.keyCode) < 0) {
+    if (this.badKeys.indexOf(e.keyCode) < 0) {
         // Fire the statechange event as the input has been modified
         window.dispatchEvent(this.manager.statechange);
     }
@@ -108,7 +108,7 @@ InputWaiter.prototype.input_change = function(e) {
  *
  * @param {event} e
  */
-InputWaiter.prototype.input_dragover = function(e) {
+InputWaiter.prototype.inputDragover = function(e) {
     // This will be set if we're dragging an operation
     if (e.dataTransfer.effectAllowed === "move")
         return false;
@@ -125,7 +125,7 @@ InputWaiter.prototype.input_dragover = function(e) {
  *
  * @param {event} e
  */
-InputWaiter.prototype.input_dragleave = function(e) {
+InputWaiter.prototype.inputDragleave = function(e) {
     e.stopPropagation();
     e.preventDefault();
     e.target.classList.remove("dropping-file");
@@ -138,7 +138,7 @@ InputWaiter.prototype.input_dragleave = function(e) {
  *
  * @param {event} e
  */
-InputWaiter.prototype.input_drop = function(e) {
+InputWaiter.prototype.inputDrop = function(e) {
     // This will be set if we're dragging an operation
     if (e.dataTransfer.effectAllowed === "move")
         return false;
@@ -150,29 +150,29 @@ InputWaiter.prototype.input_drop = function(e) {
         file = e.dataTransfer.files[0],
         text = e.dataTransfer.getData("Text"),
         reader = new FileReader(),
-        input_charcode = "",
+        inputCharcode = "",
         offset = 0,
         CHUNK_SIZE = 20480; // 20KB
     
-    var set_input = function() {
-        if (input_charcode.length > 100000 && this.app.auto_bake_) {
-            this.manager.controls.set_auto_bake(false);
+    var setInput = function() {
+        if (inputCharcode.length > 100000 && this.app.autoBake_) {
+            this.manager.controls.setAutoBake(false);
             this.app.alert("Turned off Auto Bake as the input is large", "warning", 5000);
         }
         
-        this.set(input_charcode);
-        var recipe_config = this.app.get_recipe_config();
-        if (!recipe_config[0] || recipe_config[0].op !== "From Hex") {
-            recipe_config.unshift({op:"From Hex", args:["Space"]});
-            this.app.set_recipe_config(recipe_config);
+        this.set(inputCharcode);
+        var recipeConfig = this.app.getRecipeConfig();
+        if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") {
+            recipeConfig.unshift({op:"From Hex", args:["Space"]});
+            this.app.setRecipeConfig(recipeConfig);
         }
         
-        el.classList.remove("loading_file");
+        el.classList.remove("loadingFile");
     }.bind(this);
     
     var seek = function() {
         if (offset >= file.size) {
-            set_input();
+            setInput();
             return;
         }
         el.value = "Processing... " + Math.round(offset / file.size * 100) + "%";
@@ -182,7 +182,7 @@ InputWaiter.prototype.input_drop = function(e) {
     
     reader.onload = function(e) {
         var data = new Uint8Array(reader.result);
-        input_charcode += Utils.to_hex_fast(data);
+        inputCharcode += Utils.toHexFast(data);
         offset += CHUNK_SIZE;
         seek();
     };
@@ -191,7 +191,7 @@ InputWaiter.prototype.input_drop = function(e) {
     el.classList.remove("dropping-file");
     
     if (file) {
-        el.classList.add("loading_file");
+        el.classList.add("loadingFile");
         seek();
     } else if (text) {
         this.set(text);
@@ -205,8 +205,8 @@ InputWaiter.prototype.input_drop = function(e) {
  *
  * @fires Manager#statechange
  */
-InputWaiter.prototype.clear_io_click = function() {
-    this.manager.highlighter.remove_highlights();
+InputWaiter.prototype.clearIoClick = function() {
+    this.manager.highlighter.removeHighlights();
     document.getElementById("input-text").value = "";
     document.getElementById("output-text").value = "";
     document.getElementById("input-info").innerHTML = "";

+ 94 - 93
src/js/views/html/Manager.js

@@ -45,9 +45,9 @@ var Manager = function(app) {
     this.seasonal    = new SeasonalWaiter(this.app, this);
     
     // Object to store dynamic handlers to fire on elements that may not exist yet
-    this.dynamic_handlers = {};
+    this.dynamicHandlers = {};
     
-    this.initialise_event_listeners();
+    this.initialiseEventListeners();
 };
 
 
@@ -55,8 +55,8 @@ var Manager = function(app) {
  * Sets up the various components and listeners.
  */
 Manager.prototype.setup = function() {
-    this.recipe.initialise_operation_drag_n_drop();
-    this.controls.auto_bake_change();
+    this.recipe.initialiseOperationDragNDrop();
+    this.controls.autoBakeChange();
     this.seasonal.load();
 };
 
@@ -64,86 +64,87 @@ Manager.prototype.setup = function() {
 /**
  * Main function to handle the creation of the event listeners.
  */
-Manager.prototype.initialise_event_listeners = function() {
+Manager.prototype.initialiseEventListeners = function() {
     // Global
-    window.addEventListener("resize", this.window.window_resize.bind(this.window));
-    window.addEventListener("blur", this.window.window_blur.bind(this.window));
-    window.addEventListener("focus", this.window.window_focus.bind(this.window));
-    window.addEventListener("statechange", this.app.state_change.bind(this.app));
-    window.addEventListener("popstate", this.app.pop_state.bind(this.app));
+    window.addEventListener("resize", this.window.windowResize.bind(this.window));
+    window.addEventListener("blur", this.window.windowBlur.bind(this.window));
+    window.addEventListener("focus", this.window.windowFocus.bind(this.window));
+    window.addEventListener("statechange", this.app.stateChange.bind(this.app));
+    window.addEventListener("popstate", this.app.popState.bind(this.app));
     
     // Controls
-    document.getElementById("bake").addEventListener("click", this.controls.bake_click.bind(this.controls));
-    document.getElementById("auto-bake").addEventListener("change", this.controls.auto_bake_change.bind(this.controls));
-    document.getElementById("step").addEventListener("click", this.controls.step_click.bind(this.controls));
-    document.getElementById("clr-recipe").addEventListener("click", this.controls.clear_recipe_click.bind(this.controls));
-    document.getElementById("clr-breaks").addEventListener("click", this.controls.clear_breaks_click.bind(this.controls));
-    document.getElementById("save").addEventListener("click", this.controls.save_click.bind(this.controls));
-    document.getElementById("save-button").addEventListener("click", this.controls.save_button_click.bind(this.controls));
-    document.getElementById("save-link-recipe-checkbox").addEventListener("change", this.controls.slr_check_change.bind(this.controls));
-    document.getElementById("save-link-input-checkbox").addEventListener("change", this.controls.sli_check_change.bind(this.controls));
-    document.getElementById("load").addEventListener("click", this.controls.load_click.bind(this.controls));
-    document.getElementById("load-delete-button").addEventListener("click", this.controls.load_delete_click.bind(this.controls));
-    document.getElementById("load-name").addEventListener("change", this.controls.load_name_change.bind(this.controls));
-    document.getElementById("load-button").addEventListener("click", this.controls.load_button_click.bind(this.controls));
-    this.add_multi_event_listener("#save-text", "keyup paste", this.controls.save_text_change, this.controls);
+    document.getElementById("bake").addEventListener("click", this.controls.bakeClick.bind(this.controls));
+    document.getElementById("auto-bake").addEventListener("change", this.controls.autoBakeChange.bind(this.controls));
+    document.getElementById("step").addEventListener("click", this.controls.stepClick.bind(this.controls));
+    document.getElementById("clr-recipe").addEventListener("click", this.controls.clearRecipeClick.bind(this.controls));
+    document.getElementById("clr-breaks").addEventListener("click", this.controls.clearBreaksClick.bind(this.controls));
+    document.getElementById("save").addEventListener("click", this.controls.saveClick.bind(this.controls));
+    document.getElementById("save-button").addEventListener("click", this.controls.saveButtonClick.bind(this.controls));
+    document.getElementById("save-link-recipe-checkbox").addEventListener("change", this.controls.slrCheckChange.bind(this.controls));
+    document.getElementById("save-link-input-checkbox").addEventListener("change", this.controls.sliCheckChange.bind(this.controls));
+    document.getElementById("load").addEventListener("click", this.controls.loadClick.bind(this.controls));
+    document.getElementById("load-delete-button").addEventListener("click", this.controls.loadDeleteClick.bind(this.controls));
+    document.getElementById("load-name").addEventListener("change", this.controls.loadNameChange.bind(this.controls));
+    document.getElementById("load-button").addEventListener("click", this.controls.loadButtonClick.bind(this.controls));
+    this.addMultiEventListener("#save-text", "keyup paste", this.controls.saveTextChange, this.controls);
     
     // Operations
-    this.add_multi_event_listener("#search", "keyup paste search", this.ops.search_operations, this.ops);
-    this.add_dynamic_listener(".op_list li.operation", "dblclick", this.ops.operation_dblclick, this.ops);
-    document.getElementById("edit-favourites").addEventListener("click", this.ops.edit_favourites_click.bind(this.ops));
-    document.getElementById("save-favourites").addEventListener("click", this.ops.save_favourites_click.bind(this.ops));
-    document.getElementById("reset-favourites").addEventListener("click", this.ops.reset_favourites_click.bind(this.ops));
-    this.add_dynamic_listener(".op_list .op-icon", "mouseover", this.ops.op_icon_mouseover, this.ops);
-    this.add_dynamic_listener(".op_list .op-icon", "mouseleave", this.ops.op_icon_mouseleave, this.ops);
-    this.add_dynamic_listener(".op_list", "oplistcreate", this.ops.op_list_create, this.ops);
-    this.add_dynamic_listener("li.operation", "operationadd", this.recipe.op_add.bind(this.recipe));
+    this.addMultiEventListener("#search", "keyup paste search", this.ops.searchOperations, this.ops);
+    this.addDynamicListener(".op-list li.operation", "dblclick", this.ops.operationDblclick, this.ops);
+    document.getElementById("edit-favourites").addEventListener("click", this.ops.editFavouritesClick.bind(this.ops));
+    document.getElementById("save-favourites").addEventListener("click", this.ops.saveFavouritesClick.bind(this.ops));
+    document.getElementById("reset-favourites").addEventListener("click", this.ops.resetFavouritesClick.bind(this.ops));
+    this.addDynamicListener(".op-list .op-icon", "mouseover", this.ops.opIconMouseover, this.ops);
+    this.addDynamicListener(".op-list .op-icon", "mouseleave", this.ops.opIconMouseleave, this.ops);
+    this.addDynamicListener(".op-list", "oplistcreate", this.ops.opListCreate, this.ops);
+    this.addDynamicListener("li.operation", "operationadd", this.recipe.opAdd.bind(this.recipe));
     
     // Recipe
-    this.add_dynamic_listener(".arg", "keyup", this.recipe.ing_change, this.recipe);
-    this.add_dynamic_listener(".arg", "change", this.recipe.ing_change, this.recipe);
-    this.add_dynamic_listener(".disable-icon", "click", this.recipe.disable_click, this.recipe);
-    this.add_dynamic_listener(".breakpoint", "click", this.recipe.breakpoint_click, this.recipe);
-    this.add_dynamic_listener("#rec_list li.operation", "dblclick", this.recipe.operation_dblclick, this.recipe);
-    this.add_dynamic_listener("#rec_list li.operation > div", "dblclick", this.recipe.operation_child_dblclick, this.recipe);
-    this.add_dynamic_listener("#rec_list .input-group .dropdown-menu a", "click", this.recipe.dropdown_toggle_click, this.recipe);
-    this.add_dynamic_listener("#rec_list", "operationremove", this.recipe.op_remove.bind(this.recipe));
+    this.addDynamicListener(".arg", "keyup", this.recipe.ingChange, this.recipe);
+    this.addDynamicListener(".arg", "change", this.recipe.ingChange, this.recipe);
+    this.addDynamicListener(".disable-icon", "click", this.recipe.disableClick, this.recipe);
+    this.addDynamicListener(".breakpoint", "click", this.recipe.breakpointClick, this.recipe);
+    this.addDynamicListener("#rec-list li.operation", "dblclick", this.recipe.operationDblclick, this.recipe);
+    this.addDynamicListener("#rec-list li.operation > div", "dblclick", this.recipe.operationChildDblclick, this.recipe);
+    this.addDynamicListener("#rec-list .input-group .dropdown-menu a", "click", this.recipe.dropdownToggleClick, this.recipe);
+    this.addDynamicListener("#rec-list", "operationremove", this.recipe.opRemove.bind(this.recipe));
     
     // Input
-    this.add_multi_event_listener("#input-text", "keyup paste", this.input.input_change, this.input);
-    document.getElementById("reset-layout").addEventListener("click", this.app.reset_layout.bind(this.app));
-    document.getElementById("clr-io").addEventListener("click", this.input.clear_io_click.bind(this.input));
-    document.getElementById("input-text").addEventListener("dragover", this.input.input_dragover.bind(this.input));
-    document.getElementById("input-text").addEventListener("dragleave", this.input.input_dragleave.bind(this.input));
-    document.getElementById("input-text").addEventListener("drop", this.input.input_drop.bind(this.input));
-    document.getElementById("input-text").addEventListener("scroll", this.highlighter.input_scroll.bind(this.highlighter));
-    document.getElementById("input-text").addEventListener("mouseup", this.highlighter.input_mouseup.bind(this.highlighter));
-    document.getElementById("input-text").addEventListener("mousemove", this.highlighter.input_mousemove.bind(this.highlighter));
-    this.add_multi_event_listener("#input-text", "mousedown dblclick select",  this.highlighter.input_mousedown, this.highlighter);
+    this.addMultiEventListener("#input-text", "keyup paste", this.input.inputChange, this.input);
+    document.getElementById("reset-layout").addEventListener("click", this.app.resetLayout.bind(this.app));
+    document.getElementById("clr-io").addEventListener("click", this.input.clearIoClick.bind(this.input));
+    document.getElementById("input-text").addEventListener("dragover", this.input.inputDragover.bind(this.input));
+    document.getElementById("input-text").addEventListener("dragleave", this.input.inputDragleave.bind(this.input));
+    document.getElementById("input-text").addEventListener("drop", this.input.inputDrop.bind(this.input));
+    document.getElementById("input-text").addEventListener("scroll", this.highlighter.inputScroll.bind(this.highlighter));
+    document.getElementById("input-text").addEventListener("mouseup", this.highlighter.inputMouseup.bind(this.highlighter));
+    document.getElementById("input-text").addEventListener("mousemove", this.highlighter.inputMousemove.bind(this.highlighter));
+    this.addMultiEventListener("#input-text", "mousedown dblclick select",  this.highlighter.inputMousedown, this.highlighter);
     
     // Output
-    document.getElementById("save-to-file").addEventListener("click", this.output.save_click.bind(this.output));
-    document.getElementById("switch").addEventListener("click", this.output.switch_click.bind(this.output));
-    document.getElementById("undo-switch").addEventListener("click", this.output.undo_switch_click.bind(this.output));
-    document.getElementById("output-text").addEventListener("scroll", this.highlighter.output_scroll.bind(this.highlighter));
-    document.getElementById("output-text").addEventListener("mouseup", this.highlighter.output_mouseup.bind(this.highlighter));
-    document.getElementById("output-text").addEventListener("mousemove", this.highlighter.output_mousemove.bind(this.highlighter));
-    document.getElementById("output-html").addEventListener("mouseup", this.highlighter.output_html_mouseup.bind(this.highlighter));
-    document.getElementById("output-html").addEventListener("mousemove", this.highlighter.output_html_mousemove.bind(this.highlighter));
-    this.add_multi_event_listener("#output-text", "mousedown dblclick select",  this.highlighter.output_mousedown, this.highlighter);
-    this.add_multi_event_listener("#output-html", "mousedown dblclick select",  this.highlighter.output_html_mousedown, this.highlighter);
+    document.getElementById("save-to-file").addEventListener("click", this.output.saveClick.bind(this.output));
+    document.getElementById("switch").addEventListener("click", this.output.switchClick.bind(this.output));
+    document.getElementById("undo-switch").addEventListener("click", this.output.undoSwitchClick.bind(this.output));
+    document.getElementById("maximise-output").addEventListener("click", this.output.maximiseOutputClick.bind(this.output));
+    document.getElementById("output-text").addEventListener("scroll", this.highlighter.outputScroll.bind(this.highlighter));
+    document.getElementById("output-text").addEventListener("mouseup", this.highlighter.outputMouseup.bind(this.highlighter));
+    document.getElementById("output-text").addEventListener("mousemove", this.highlighter.outputMousemove.bind(this.highlighter));
+    document.getElementById("output-html").addEventListener("mouseup", this.highlighter.outputHtmlMouseup.bind(this.highlighter));
+    document.getElementById("output-html").addEventListener("mousemove", this.highlighter.outputHtmlMousemove.bind(this.highlighter));
+    this.addMultiEventListener("#output-text", "mousedown dblclick select",  this.highlighter.outputMousedown, this.highlighter);
+    this.addMultiEventListener("#output-html", "mousedown dblclick select",  this.highlighter.outputHtmlMousedown, this.highlighter);
     
     // Options
-    document.getElementById("options").addEventListener("click", this.options.options_click.bind(this.options));
-    document.getElementById("reset-options").addEventListener("click", this.options.reset_options_click.bind(this.options));
-    $(document).on("switchChange.bootstrapSwitch", ".option-item input:checkbox", this.options.switch_change.bind(this.options));
-    $(document).on("switchChange.bootstrapSwitch", ".option-item input:checkbox", this.options.set_word_wrap.bind(this.options));
-    this.add_dynamic_listener(".option-item input[type=number]", "keyup", this.options.number_change, this.options);
-    this.add_dynamic_listener(".option-item input[type=number]", "change", this.options.number_change, this.options);
-    this.add_dynamic_listener(".option-item select", "change", this.options.select_change, this.options);
+    document.getElementById("options").addEventListener("click", this.options.optionsClick.bind(this.options));
+    document.getElementById("reset-options").addEventListener("click", this.options.resetOptionsClick.bind(this.options));
+    $(document).on("switchChange.bootstrapSwitch", ".option-item input:checkbox", this.options.switchChange.bind(this.options));
+    $(document).on("switchChange.bootstrapSwitch", ".option-item input:checkbox", this.options.setWordWrap.bind(this.options));
+    this.addDynamicListener(".option-item input[type=number]", "keyup", this.options.numberChange, this.options);
+    this.addDynamicListener(".option-item input[type=number]", "change", this.options.numberChange, this.options);
+    this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options);
     
     // Misc
-    document.getElementById("alert-close").addEventListener("click", this.app.alert_close_click.bind(this.app));
+    document.getElementById("alert-close").addEventListener("click", this.app.alertCloseClick.bind(this.app));
 };
 
 
@@ -151,19 +152,19 @@ Manager.prototype.initialise_event_listeners = function() {
  * Adds an event listener to each element in the specified group.
  *
  * @param {string} selector - A selector string for the element group to add the event to, see
- *   this.get_all()
- * @param {string} event_type - The event to listen for
+ *   this.getAll()
+ * @param {string} eventType - The event to listen for
  * @param {function} callback - The function to execute when the event is triggered
  * @param {Object} [scope=this] - The object to bind to the callback function
  *
  * @example
  * // Calls the clickable function whenever any element with the .clickable class is clicked
- * this.add_listeners(".clickable", "click", this.clickable, this);
+ * this.addListeners(".clickable", "click", this.clickable, this);
  */
-Manager.prototype.add_listeners = function(selector, event_type, callback, scope) {
+Manager.prototype.addListeners = function(selector, eventType, callback, scope) {
     scope = scope || this;
     [].forEach.call(document.querySelectorAll(selector), function(el) {
-        el.addEventListener(event_type, callback.bind(scope));
+        el.addEventListener(eventType, callback.bind(scope));
     });
 };
 
@@ -172,17 +173,17 @@ Manager.prototype.add_listeners = function(selector, event_type, callback, scope
  * Adds multiple event listeners to the specified element.
  *
  * @param {string} selector - A selector string for the element to add the events to
- * @param {string} event_types - A space-separated string of all the event types to listen for
+ * @param {string} eventTypes - A space-separated string of all the event types to listen for
  * @param {function} callback - The function to execute when the events are triggered
  * @param {Object} [scope=this] - The object to bind to the callback function
  *
  * @example
  * // Calls the search function whenever the the keyup, paste or search events are triggered on the
  * // search element
- * this.add_multi_event_listener("search", "keyup paste search", this.search, this);
+ * this.addMultiEventListener("search", "keyup paste search", this.search, this);
  */
-Manager.prototype.add_multi_event_listener = function(selector, event_types, callback, scope) {
-    var evs = event_types.split(" ");
+Manager.prototype.addMultiEventListener = function(selector, eventTypes, callback, scope) {
+    var evs = eventTypes.split(" ");
     for (var i = 0; i < evs.length; i++) {
         document.querySelector(selector).addEventListener(evs[i], callback.bind(scope));
     }
@@ -193,19 +194,19 @@ Manager.prototype.add_multi_event_listener = function(selector, event_types, cal
  * Adds multiple event listeners to each element in the specified group.
  *
  * @param {string} selector - A selector string for the element group to add the events to
- * @param {string} event_types - A space-separated string of all the event types to listen for
+ * @param {string} eventTypes - A space-separated string of all the event types to listen for
  * @param {function} callback - The function to execute when the events are triggered
  * @param {Object} [scope=this] - The object to bind to the callback function
  *
  * @example
  * // Calls the save function whenever the the keyup or paste events are triggered on any element
  * // with the .saveable class
- * this.add_multi_event_listener(".saveable", "keyup paste", this.save, this);
+ * this.addMultiEventListener(".saveable", "keyup paste", this.save, this);
  */
-Manager.prototype.add_multi_event_listeners = function(selector, event_types, callback, scope) {
-    var evs = event_types.split(" ");
+Manager.prototype.addMultiEventListeners = function(selector, eventTypes, callback, scope) {
+    var evs = eventTypes.split(" ");
     for (var i = 0; i < evs.length; i++) {
-        this.add_listeners(selector, evs[i], callback, scope);
+        this.addListeners(selector, evs[i], callback, scope);
     }
 };
 
@@ -215,28 +216,28 @@ Manager.prototype.add_multi_event_listeners = function(selector, event_types, ca
  * may not exist in the DOM yet.
  *
  * @param {string} selector - A selector string for the element(s) to add the event to
- * @param {string} event_type - The event(s) to listen for
+ * @param {string} eventType - The event(s) to listen for
  * @param {function} callback - The function to execute when the event(s) is/are triggered
  * @param {Object} [scope=this] - The object to bind to the callback function
  *
  * @example
  * // Pops up an alert whenever any button is clicked, even if it is added to the DOM after this
  * // listener is created
- * this.add_dynamic_listener("button", "click", alert, this);
+ * this.addDynamicListener("button", "click", alert, this);
  */
-Manager.prototype.add_dynamic_listener = function(selector, event_type, callback, scope) {
-    var event_config = {
+Manager.prototype.addDynamicListener = function(selector, eventType, callback, scope) {
+    var eventConfig = {
         selector: selector,
         callback: callback.bind(scope || this)
     };
     
-    if (this.dynamic_handlers.hasOwnProperty(event_type)) {
+    if (this.dynamicHandlers.hasOwnProperty(eventType)) {
         // Listener already exists, add new handler to the appropriate list
-        this.dynamic_handlers[event_type].push(event_config);
+        this.dynamicHandlers[eventType].push(eventConfig);
     } else {
-        this.dynamic_handlers[event_type] = [event_config];
+        this.dynamicHandlers[eventType] = [eventConfig];
         // Set up listener for this new type
-        document.addEventListener(event_type, this.dynamic_listener_handler.bind(this));
+        document.addEventListener(eventType, this.dynamicListenerHandler.bind(this));
     }
 };
 
@@ -247,8 +248,8 @@ Manager.prototype.add_dynamic_listener = function(selector, event_type, callback
  *
  * @param {Event} e - The event to be handled
  */
-Manager.prototype.dynamic_listener_handler = function(e) {
-    var handlers = this.dynamic_handlers[e.type],
+Manager.prototype.dynamicListenerHandler = function(e) {
+    var handlers = this.dynamicHandlers[e.type],
         matches = e.target.matches ||
             e.target.webkitMatchesSelector ||
             e.target.mozMatchesSelector ||

+ 74 - 74
src/js/views/html/OperationsWaiter.js

@@ -16,7 +16,7 @@ var OperationsWaiter = function(app, manager) {
     this.manager = manager;
     
     this.options = {};
-    this.remove_intent = false;
+    this.removeIntent = false;
 };
 
 
@@ -26,17 +26,17 @@ var OperationsWaiter = function(app, manager) {
  *
  * @param {event} e
  */
-OperationsWaiter.prototype.search_operations = function(e) {
+OperationsWaiter.prototype.searchOperations = function(e) {
     var ops, selected;
     
     if (e.type === "search") { // Search
         e.preventDefault();
         ops = document.querySelectorAll("#search-results li");
         if (ops.length) {
-            selected = this.get_selected_op(ops);
+            selected = this.getSelectedOp(ops);
             if (selected > -1) {
-                this.manager.recipe.add_operation(ops[selected].innerHTML);
-                this.app.auto_bake();
+                this.manager.recipe.addOperation(ops[selected].innerHTML);
+                this.app.autoBake();
             }
         }
     }
@@ -47,7 +47,7 @@ OperationsWaiter.prototype.search_operations = function(e) {
         e.preventDefault();
         ops = document.querySelectorAll("#search-results li");
         if (ops.length) {
-            selected = this.get_selected_op(ops);
+            selected = this.getSelectedOp(ops);
             if (selected > -1) {
                 ops[selected].classList.remove("selected-op");
             }
@@ -58,7 +58,7 @@ OperationsWaiter.prototype.search_operations = function(e) {
         e.preventDefault();
         ops = document.querySelectorAll("#search-results li");
         if (ops.length) {
-            selected = this.get_selected_op(ops);
+            selected = this.getSelectedOp(ops);
             if (selected > -1) {
                 ops[selected].classList.remove("selected-op");
             }
@@ -66,26 +66,26 @@ OperationsWaiter.prototype.search_operations = function(e) {
             ops[selected-1].classList.add("selected-op");
         }
     } else {
-        var search_results_el = document.getElementById("search-results"),
+        var searchResultsEl = document.getElementById("search-results"),
             el = e.target,
             str = el.value;
         
-        while (search_results_el.firstChild) {
-            $(search_results_el.firstChild).popover("destroy");
-            search_results_el.removeChild(search_results_el.firstChild);
+        while (searchResultsEl.firstChild) {
+            $(searchResultsEl.firstChild).popover("destroy");
+            searchResultsEl.removeChild(searchResultsEl.firstChild);
         }
         
         $("#categories .in").collapse("hide");
         if (str) {
-            var matched_ops = this.filter_operations(str, true),
-                matched_ops_html = "";
+            var matchedOps = this.filterOperations(str, true),
+                matchedOpsHtml = "";
             
-            for (var i = 0; i < matched_ops.length; i++) {
-                matched_ops_html += matched_ops[i].to_stub_html();
+            for (var i = 0; i < matchedOps.length; i++) {
+                matchedOpsHtml += matchedOps[i].toStubHtml();
             }
             
-            search_results_el.innerHTML = matched_ops_html;
-            search_results_el.dispatchEvent(this.manager.oplistcreate);
+            searchResultsEl.innerHTML = matchedOpsHtml;
+            searchResultsEl.dispatchEvent(this.manager.oplistcreate);
         }
     }
 };
@@ -94,37 +94,37 @@ OperationsWaiter.prototype.search_operations = function(e) {
 /**
  * Filters operations based on the search string and returns the matching ones.
  *
- * @param {string} search_str
+ * @param {string} searchStr
  * @param {boolean} highlight - Whether or not to highlight the matching string in the operation
  *   name and description
  * @returns {string[]}
  */
-OperationsWaiter.prototype.filter_operations = function(search_str, highlight) {
-    var matched_ops = [],
-        matched_descs = [];
+OperationsWaiter.prototype.filterOperations = function(searchStr, highlight) {
+    var matchedOps = [],
+        matchedDescs = [];
     
-    search_str = search_str.toLowerCase();
+    searchStr = searchStr.toLowerCase();
     
-    for (var op_name in this.app.operations) {
-        var op = this.app.operations[op_name],
-            name_pos = op_name.toLowerCase().indexOf(search_str),
-            desc_pos = op.description.toLowerCase().indexOf(search_str);
+    for (var opName in this.app.operations) {
+        var op = this.app.operations[opName],
+            namePos = opName.toLowerCase().indexOf(searchStr),
+            descPos = op.description.toLowerCase().indexOf(searchStr);
         
-        if (name_pos >= 0 || desc_pos >= 0) {
-            var operation = new HTMLOperation(op_name, this.app.operations[op_name], this.app, this.manager);
+        if (namePos >= 0 || descPos >= 0) {
+            var operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
             if (highlight) {
-                operation.highlight_search_string(search_str, name_pos, desc_pos);
+                operation.highlightSearchString(searchStr, namePos, descPos);
             }
             
-            if (name_pos < 0) {
-                matched_ops.push(operation);
+            if (namePos < 0) {
+                matchedOps.push(operation);
             } else {
-                matched_descs.push(operation);
+                matchedDescs.push(operation);
             }
         }
     }
     
-    return matched_descs.concat(matched_ops);
+    return matchedDescs.concat(matchedOps);
 };
 
 
@@ -135,7 +135,7 @@ OperationsWaiter.prototype.filter_operations = function(search_str, highlight) {
  * @param {element[]} ops
  * @returns {number}
  */
-OperationsWaiter.prototype.get_selected_op = function(ops) {
+OperationsWaiter.prototype.getSelectedOp = function(ops) {
     for (var i = 0; i < ops.length; i++) {
         if (ops[i].classList.contains("selected-op")) {
             return i;
@@ -151,8 +151,8 @@ OperationsWaiter.prototype.get_selected_op = function(ops) {
  * @listens Manager#oplistcreate
  * @param {event} e
  */
-OperationsWaiter.prototype.op_list_create = function(e) {
-    this.manager.recipe.create_sortable_seed_list(e.target);
+OperationsWaiter.prototype.opListCreate = function(e) {
+    this.manager.recipe.createSortableSeedList(e.target);
     $("[data-toggle=popover]").popover();
 };
 
@@ -163,11 +163,11 @@ OperationsWaiter.prototype.op_list_create = function(e) {
  *
  * @param {event} e
  */
-OperationsWaiter.prototype.operation_dblclick = function(e) {
+OperationsWaiter.prototype.operationDblclick = function(e) {
     var li = e.target;
     
-    this.manager.recipe.add_operation(li.textContent);
-    this.app.auto_bake();
+    this.manager.recipe.addOperation(li.textContent);
+    this.app.autoBake();
 };
 
 
@@ -177,46 +177,46 @@ OperationsWaiter.prototype.operation_dblclick = function(e) {
  *
  * @param {event} e
  */
-OperationsWaiter.prototype.edit_favourites_click = function(e) {
+OperationsWaiter.prototype.editFavouritesClick = function(e) {
     e.preventDefault();
     e.stopPropagation();
     
     // Add favourites to modal
-    var fav_cat = this.app.categories.filter(function(c) {
+    var favCat = this.app.categories.filter(function(c) {
         return c.name === "Favourites";
     })[0];
     
     var html = "";
-    for (var i = 0; i < fav_cat.ops.length; i++) {
-        var op_name = fav_cat.ops[i];
-        var operation = new HTMLOperation(op_name, this.app.operations[op_name], this.app, this.manager);
-        html += operation.to_stub_html(true);
+    for (var i = 0; i < favCat.ops.length; i++) {
+        var opName = favCat.ops[i];
+        var operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
+        html += operation.toStubHtml(true);
     }
     
-    var edit_favourites_list = document.getElementById("edit-favourites-list");
-    edit_favourites_list.innerHTML = html;
-    this.remove_intent = false;
+    var editFavouritesList = document.getElementById("edit-favourites-list");
+    editFavouritesList.innerHTML = html;
+    this.removeIntent = false;
     
-    var editable_list = Sortable.create(edit_favourites_list, {
+    var editableList = Sortable.create(editFavouritesList, {
         filter: ".remove-icon",
         onFilter: function (evt) {
-            var el = editable_list.closest(evt.item);
+            var el = editableList.closest(evt.item);
             if (el) {
                 $(el).popover("destroy");
                 el.parentNode.removeChild(el);
             }
         },
         onEnd: function(evt) {
-            if (this.remove_intent) evt.item.remove();
+            if (this.removeIntent) evt.item.remove();
         }.bind(this),
     });
     
-    Sortable.utils.on(edit_favourites_list, "dragleave", function() {
-        this.remove_intent = true;
+    Sortable.utils.on(editFavouritesList, "dragleave", function() {
+        this.removeIntent = true;
     }.bind(this));
     
-    Sortable.utils.on(edit_favourites_list, "dragover", function() {
-        this.remove_intent = false;
+    Sortable.utils.on(editFavouritesList, "dragover", function() {
+        this.removeIntent = false;
     }.bind(this));
     
     $("#edit-favourites-list [data-toggle=popover]").popover();
@@ -228,18 +228,18 @@ OperationsWaiter.prototype.edit_favourites_click = function(e) {
  * Handler for save favourites click events.
  * Saves the selected favourites and reloads them.
  */
-OperationsWaiter.prototype.save_favourites_click = function() {
-    var favourites_list = [],
+OperationsWaiter.prototype.saveFavouritesClick = function() {
+    var favouritesList = [],
         favs = document.querySelectorAll("#edit-favourites-list li");
     
     for (var i = 0; i < favs.length; i++) {
-        favourites_list.push(favs[i].textContent);
+        favouritesList.push(favs[i].textContent);
     }
 
-    this.app.save_favourites(favourites_list);
-    this.app.load_favourites();
-    this.app.populate_operations_list();
-    this.manager.recipe.initialise_operation_drag_n_drop();
+    this.app.saveFavourites(favouritesList);
+    this.app.loadFavourites();
+    this.app.populateOperationsList();
+    this.manager.recipe.initialiseOperationDragNDrop();
 };
 
 
@@ -247,37 +247,37 @@ OperationsWaiter.prototype.save_favourites_click = function() {
  * Handler for reset favourites click events.
  * Resets favourites to their defaults.
  */
-OperationsWaiter.prototype.reset_favourites_click = function() {
-    this.app.reset_favourites();
+OperationsWaiter.prototype.resetFavouritesClick = function() {
+    this.app.resetFavourites();
 };
 
 
 /**
- * Handler for op_icon mouseover events.
+ * Handler for opIcon mouseover events.
  * Hides any popovers already showing on the operation so that there aren't two at once.
  *
  * @param {event} e
  */
-OperationsWaiter.prototype.op_icon_mouseover = function(e) {
-    var op_el = e.target.parentNode;
+OperationsWaiter.prototype.opIconMouseover = function(e) {
+    var opEl = e.target.parentNode;
     if (e.target.getAttribute("data-toggle") === "popover") {
-        $(op_el).popover("hide");
+        $(opEl).popover("hide");
     }
 };
 
 
 /**
- * Handler for op_icon mouseleave events.
+ * Handler for opIcon mouseleave events.
  * If this icon created a popover and we're moving back to the operation element, display the
  *   operation popover again.
  *
  * @param {event} e
  */
-OperationsWaiter.prototype.op_icon_mouseleave = function(e) {
-    var op_el = e.target.parentNode,
-        to_el = e.toElement || e.relatedElement;
+OperationsWaiter.prototype.opIconMouseleave = function(e) {
+    var opEl = e.target.parentNode,
+        toEl = e.toElement || e.relatedElement;
     
-    if (e.target.getAttribute("data-toggle") === "popover" && to_el === op_el) {
-        $(op_el).popover("show");
+    if (e.target.getAttribute("data-toggle") === "popover" && toEl === opEl) {
+        $(opEl).popover("show");
     }
 };

+ 8 - 8
src/js/views/html/OptionsWaiter.js

@@ -52,7 +52,7 @@ OptionsWaiter.prototype.load = function(options) {
  * Handler for options click events.
  * Dispays the options pane.
  */
-OptionsWaiter.prototype.options_click = function() {
+OptionsWaiter.prototype.optionsClick = function() {
     $("#options-modal").modal();
 };
 
@@ -61,7 +61,7 @@ OptionsWaiter.prototype.options_click = function() {
  * Handler for reset options click events.
  * Resets options back to their default values.
  */
-OptionsWaiter.prototype.reset_options_click = function() {
+OptionsWaiter.prototype.resetOptionsClick = function() {
     this.load(this.app.doptions);
 };
 
@@ -73,7 +73,7 @@ OptionsWaiter.prototype.reset_options_click = function() {
  * @param {event} e
  * @param {boolean} state
  */
-OptionsWaiter.prototype.switch_change = function(e, state) {
+OptionsWaiter.prototype.switchChange = function(e, state) {
     var el = e.target,
         option = el.getAttribute("option");
         
@@ -88,7 +88,7 @@ OptionsWaiter.prototype.switch_change = function(e, state) {
  *
  * @param {event} e
  */
-OptionsWaiter.prototype.number_change = function(e) {
+OptionsWaiter.prototype.numberChange = function(e) {
     var el = e.target,
         option = el.getAttribute("option");
         
@@ -103,7 +103,7 @@ OptionsWaiter.prototype.number_change = function(e) {
  *
  * @param {event} e
  */
-OptionsWaiter.prototype.select_change = function(e) {
+OptionsWaiter.prototype.selectChange = function(e) {
     var el = e.target,
         option = el.getAttribute("option");
         
@@ -113,16 +113,16 @@ OptionsWaiter.prototype.select_change = function(e) {
 
 
 /**
- * Sets or unsets word wrap on the input and output depending on the word_wrap option value.
+ * Sets or unsets word wrap on the input and output depending on the wordWrap option value.
  */
-OptionsWaiter.prototype.set_word_wrap = function() {
+OptionsWaiter.prototype.setWordWrap = function() {
     document.getElementById("input-text").classList.remove("word-wrap");
     document.getElementById("output-text").classList.remove("word-wrap");
     document.getElementById("output-html").classList.remove("word-wrap");
     document.getElementById("input-highlighter").classList.remove("word-wrap");
     document.getElementById("output-highlighter").classList.remove("word-wrap");
     
-    if (!this.app.options.word_wrap) {
+    if (!this.app.options.wordWrap) {
         document.getElementById("input-text").classList.add("word-wrap");
         document.getElementById("output-text").classList.add("word-wrap");
         document.getElementById("output-html").classList.add("word-wrap");

+ 87 - 38
src/js/views/html/OutputWaiter.js

@@ -28,47 +28,47 @@ OutputWaiter.prototype.get = function() {
 /**
  * Sets the output in the output textarea.
  *
- * @param {string} data_str - The output string/HTML
+ * @param {string} dataStr - The output string/HTML
  * @param {string} type - The data type of the output
  * @param {number} duration - The length of time (ms) it took to generate the output
  */
-OutputWaiter.prototype.set = function(data_str, type, duration) {
-    var output_text = document.getElementById("output-text"),
-        output_html = document.getElementById("output-html"),
-        output_highlighter = document.getElementById("output-highlighter"),
-        input_highlighter = document.getElementById("input-highlighter");
+OutputWaiter.prototype.set = function(dataStr, type, duration) {
+    var outputText = document.getElementById("output-text"),
+        outputHtml = document.getElementById("output-html"),
+        outputHighlighter = document.getElementById("output-highlighter"),
+        inputHighlighter = document.getElementById("input-highlighter");
 
     if (type === "html") {
-        output_text.style.display = "none";
-        output_html.style.display = "block";
-        output_highlighter.display = "none";
-        input_highlighter.display = "none";
+        outputText.style.display = "none";
+        outputHtml.style.display = "block";
+        outputHighlighter.display = "none";
+        inputHighlighter.display = "none";
         
-        output_text.value = "";
-        output_html.innerHTML = data_str;
+        outputText.value = "";
+        outputHtml.innerHTML = dataStr;
         
         // Execute script sections
-        var script_elements = output_html.querySelectorAll("script");
-        for (var i = 0; i < script_elements.length; i++) {
+        var scriptElements = outputHtml.querySelectorAll("script");
+        for (var i = 0; i < scriptElements.length; i++) {
             try {
-                eval(script_elements[i].innerHTML); // eslint-disable-line no-eval
+                eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval
             } catch (err) {
                 console.error(err);
             }
         }
     } else {
-        output_text.style.display = "block";
-        output_html.style.display = "none";
-        output_highlighter.display = "block";
-        input_highlighter.display = "block";
+        outputText.style.display = "block";
+        outputHtml.style.display = "none";
+        outputHighlighter.display = "block";
+        inputHighlighter.display = "block";
         
-        output_text.value = Utils.printable(data_str, true);
-        output_html.innerHTML = "";
+        outputText.value = Utils.printable(dataStr, true);
+        outputHtml.innerHTML = "";
     }
     
-    this.manager.highlighter.remove_highlights();
-    var lines = data_str.count("\n") + 1;
-    this.set_output_info(data_str.length, lines, duration);
+    this.manager.highlighter.removeHighlights();
+    var lines = dataStr.count("\n") + 1;
+    this.setOutputInfo(dataStr.length, lines, duration);
 };
 
 
@@ -79,28 +79,54 @@ OutputWaiter.prototype.set = function(data_str, type, duration) {
  * @param {number} lines - The number of the lines in the current output string
  * @param {number} duration - The length of time (ms) it took to generate the output
  */
-OutputWaiter.prototype.set_output_info = function(length, lines, duration) {
+OutputWaiter.prototype.setOutputInfo = function(length, lines, duration) {
     var width = length.toString().length;
     width = width < 4 ? 4 : width;
     
-    var length_str = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
-    var lines_str  = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
-    var time_str   = Utils.pad(duration.toString() + "ms", width, " ").replace(/ /g, "&nbsp;");
+    var lengthStr = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
+    var linesStr  = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
+    var timeStr   = Utils.pad(duration.toString() + "ms", width, " ").replace(/ /g, "&nbsp;");
     
-    document.getElementById("output-info").innerHTML = "time: " + time_str +
-        "<br>length: " + length_str +
-        "<br>lines: " + lines_str;
+    document.getElementById("output-info").innerHTML = "time: " + timeStr +
+        "<br>length: " + lengthStr +
+        "<br>lines: " + linesStr;
     document.getElementById("input-selection-info").innerHTML = "";
     document.getElementById("output-selection-info").innerHTML = "";
 };
 
 
+/**
+ * Adjusts the display properties of the output buttons so that they fit within the current width
+ * without wrapping or overflowing.
+ */
+OutputWaiter.prototype.adjustWidth = function() {
+    var output         = document.getElementById("output"),
+        saveToFile     = document.getElementById("save-to-file"),
+        switchIO       = document.getElementById("switch"),
+        undoSwitch     = document.getElementById("undo-switch"),
+        maximiseOutput = document.getElementById("maximise-output");
+    
+    if (output.clientWidth < 680) {
+        saveToFile.childNodes[1].nodeValue = "";
+        switchIO.childNodes[1].nodeValue = "";
+        undoSwitch.childNodes[1].nodeValue = "";
+        maximiseOutput.childNodes[1].nodeValue = "";
+    } else {
+        saveToFile.childNodes[1].nodeValue = " Save to file";
+        switchIO.childNodes[1].nodeValue = " Move output to input";
+        undoSwitch.childNodes[1].nodeValue = " Undo";
+        maximiseOutput.childNodes[1].nodeValue =
+            maximiseOutput.getAttribute("title") === "Maximise" ? " Max" : " Restore";
+    }
+};
+
+
 /**
  * Handler for save click events.
  * Saves the current output to a file, downloaded as a URL octet stream.
  */
-OutputWaiter.prototype.save_click = function() {
-    var data = Utils.to_base64(this.app.dish_str),
+OutputWaiter.prototype.saveClick = function() {
+    var data = Utils.toBase64(this.app.dishStr),
         filename = window.prompt("Please enter a filename:", "download.dat");
         
     if (filename) {
@@ -122,10 +148,10 @@ OutputWaiter.prototype.save_click = function() {
  * Handler for switch click events.
  * Moves the current output into the input textarea.
  */
-OutputWaiter.prototype.switch_click = function() {
-    this.switch_orig_data = this.manager.input.get();
+OutputWaiter.prototype.switchClick = function() {
+    this.switchOrigData = this.manager.input.get();
     document.getElementById("undo-switch").disabled = false;
-    this.app.set_input(this.app.dish_str);
+    this.app.setInput(this.app.dishStr);
 };
 
 
@@ -133,7 +159,30 @@ OutputWaiter.prototype.switch_click = function() {
  * Handler for undo switch click events.
  * Removes the output from the input and replaces the input that was removed.
  */
-OutputWaiter.prototype.undo_switch_click = function() {
-    this.app.set_input(this.switch_orig_data);
+OutputWaiter.prototype.undoSwitchClick = function() {
+    this.app.setInput(this.switchOrigData);
     document.getElementById("undo-switch").disabled = true;
 };
+
+
+/**
+ * Handler for maximise output click events.
+ * Resizes the output frame to be as large as possible, or restores it to its original size.
+ */
+OutputWaiter.prototype.maximiseOutputClick = function(e) {
+    var el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;
+
+    if (el.getAttribute("title") === "Maximise") {
+        this.app.columnSplitter.collapse(0);
+        this.app.columnSplitter.collapse(1);
+        this.app.ioSplitter.collapse(0);
+
+        el.setAttribute("title", "Restore");
+        el.innerHTML = "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAlUlEQVQ4y93RwQpBQRQG4C9ba1fxBteGPIj38BTejFJKLFnwCJIiCsW1mcV0k9yx82/OzGK+OXMGOpiiLTFjFNiilQI0sQ7IJiAjLKsgGVYB2YdaVO0kwy46/BVQi9ZDNPyQWen2ub/KufS8y7shfkq9tF9U7SC+/YluKvAI9YZeFeCECXJcA3JHP2WgMXJM/ZUcBwxeM+YuSWTgMtUAAAAASUVORK5CYII='> Restore";
+        this.adjustWidth();
+    } else {
+        el.setAttribute("title", "Maximise");
+        el.innerHTML = "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAi0lEQVQ4y83TMQrCQBCF4S+5g4rJEdJ7KE+RQ1lrIQQCllroEULuoM0Ww3a7aXwwLAzMPzDvLcz4hnooUItT1rsoVNy+4lgLWNL7RlcCmDBij2eCfNCrUITc0dRCrhj8m5otw0O6SV8LuAV3uhrAAa8sJ2Np7KPFawhgscVLjH9bCDhjt8WNKft88w/HjCvuVqu53QAAAABJRU5ErkJggg=='> Max";
+        this.app.resetLayout();
+    }
+};

+ 72 - 72
src/js/views/html/RecipeWaiter.js

@@ -14,79 +14,79 @@
 var RecipeWaiter = function(app, manager) {
     this.app = app;
     this.manager = manager;
-    this.remove_intent = false;
+    this.removeIntent = false;
 };
 
 
 /**
  * Sets up the drag and drop capability for operations in the operations and recipe areas.
  */
-RecipeWaiter.prototype.initialise_operation_drag_n_drop = function() {
-    var rec_list = document.getElementById("rec_list");
+RecipeWaiter.prototype.initialiseOperationDragNDrop = function() {
+    var recList = document.getElementById("rec-list");
     
     
     // Recipe list
-    Sortable.create(rec_list, {
+    Sortable.create(recList, {
         group: "recipe",
         sort: true,
         animation: 0,
         delay: 0,
         filter: ".arg-input,.arg", // Relies on commenting out a line in Sortable.js which calls evt.preventDefault()
-        setData: function(dataTransfer, drag_el) {
-            dataTransfer.setData("Text", drag_el.querySelector(".arg-title").textContent);
+        setData: function(dataTransfer, dragEl) {
+            dataTransfer.setData("Text", dragEl.querySelector(".arg-title").textContent);
         },
         onEnd: function(evt) {
-            if (this.remove_intent) {
+            if (this.removeIntent) {
                 evt.item.remove();
                 evt.target.dispatchEvent(this.manager.operationremove);
             }
         }.bind(this)
     });
     
-    Sortable.utils.on(rec_list, "dragover", function() {
-        this.remove_intent = false;
+    Sortable.utils.on(recList, "dragover", function() {
+        this.removeIntent = false;
     }.bind(this));
     
-    Sortable.utils.on(rec_list, "dragleave", function() {
-        this.remove_intent = true;
+    Sortable.utils.on(recList, "dragleave", function() {
+        this.removeIntent = true;
         this.app.progress = 0;
     }.bind(this));
 
-    Sortable.utils.on(rec_list, "touchend", function(e) {
+    Sortable.utils.on(recList, "touchend", function(e) {
         var loc = e.changedTouches[0],
             target = document.elementFromPoint(loc.clientX, loc.clientY);
 
-        this.remove_intent = !rec_list.contains(target);
+        this.removeIntent = !recList.contains(target);
     }.bind(this));
     
     // Favourites category
-    document.querySelector("#categories a").addEventListener("dragover", this.fav_dragover.bind(this));
-    document.querySelector("#categories a").addEventListener("dragleave", this.fav_dragleave.bind(this));
-    document.querySelector("#categories a").addEventListener("drop", this.fav_drop.bind(this));
+    document.querySelector("#categories a").addEventListener("dragover", this.favDragover.bind(this));
+    document.querySelector("#categories a").addEventListener("dragleave", this.favDragleave.bind(this));
+    document.querySelector("#categories a").addEventListener("drop", this.favDrop.bind(this));
 };
 
 
 /**
  * Creates a drag-n-droppable seed list of operations.
  *
- * @param {element} list_el - The list the initialise
+ * @param {element} listEl - The list the initialise
  */
-RecipeWaiter.prototype.create_sortable_seed_list = function(list_el) {
-    Sortable.create(list_el, {
+RecipeWaiter.prototype.createSortableSeedList = function(listEl) {
+    Sortable.create(listEl, {
         group: {
             name: "recipe",
             pull: "clone",
             put: false
         },
         sort: false,
-        setData: function(dataTransfer, drag_el) {
-            dataTransfer.setData("Text", drag_el.textContent);
+        setData: function(dataTransfer, dragEl) {
+            dataTransfer.setData("Text", dragEl.textContent);
         },
         onStart: function(evt) {
             $(evt.item).popover("destroy");
             evt.item.setAttribute("data-toggle", "popover-disabled");
         },
-        onEnd: this.op_sort_end.bind(this)
+        onEnd: this.opSortEnd.bind(this)
     });
 };
 
@@ -99,9 +99,9 @@ RecipeWaiter.prototype.create_sortable_seed_list = function(list_el) {
  * @fires Manager#operationadd
  * @param {event} evt
  */
-RecipeWaiter.prototype.op_sort_end = function(evt) {
-    if (this.remove_intent) {
-        if (evt.item.parentNode.id === "rec_list") {
+RecipeWaiter.prototype.opSortEnd = function(evt) {
+    if (this.removeIntent) {
+        if (evt.item.parentNode.id === "rec-list") {
             evt.item.remove();
         }
         return;
@@ -112,11 +112,11 @@ RecipeWaiter.prototype.op_sort_end = function(evt) {
     $(evt.clone).popover();
     $(evt.clone).children("[data-toggle=popover]").popover();
     
-    if (evt.item.parentNode.id !== "rec_list") {
+    if (evt.item.parentNode.id !== "rec-list") {
         return;
     }
     
-    this.build_recipe_operation(evt.item);
+    this.buildRecipeOperation(evt.item);
     evt.item.dispatchEvent(this.manager.operationadd);
 };
 
@@ -128,7 +128,7 @@ RecipeWaiter.prototype.op_sort_end = function(evt) {
  *
  * @param {event} e
  */
-RecipeWaiter.prototype.fav_dragover = function(e) {
+RecipeWaiter.prototype.favDragover = function(e) {
     if (e.dataTransfer.effectAllowed !== "move")
         return false;
     
@@ -153,7 +153,7 @@ RecipeWaiter.prototype.fav_dragover = function(e) {
  *
  * @param {event} e
  */
-RecipeWaiter.prototype.fav_dragleave = function(e) {
+RecipeWaiter.prototype.favDragleave = function(e) {
     e.stopPropagation();
     e.preventDefault();
     document.querySelector("#categories a").classList.remove("favourites-hover");
@@ -166,13 +166,13 @@ RecipeWaiter.prototype.fav_dragleave = function(e) {
  *
  * @param {event} e
  */
-RecipeWaiter.prototype.fav_drop = function(e) {
+RecipeWaiter.prototype.favDrop = function(e) {
     e.stopPropagation();
     e.preventDefault();
     e.target.classList.remove("favourites-hover");
     
-    var op_name = e.dataTransfer.getData("Text");
-    this.app.add_favourite(op_name);
+    var opName = e.dataTransfer.getData("Text");
+    this.app.addFavourite(opName);
 };
 
 
@@ -181,7 +181,7 @@ RecipeWaiter.prototype.fav_drop = function(e) {
  *
  * @fires Manager#statechange
  */
-RecipeWaiter.prototype.ing_change = function() {
+RecipeWaiter.prototype.ingChange = function() {
     window.dispatchEvent(this.manager.statechange);
 };
 
@@ -193,7 +193,7 @@ RecipeWaiter.prototype.ing_change = function() {
  * @fires Manager#statechange
  * @param {event} e
  */
-RecipeWaiter.prototype.disable_click = function(e) {
+RecipeWaiter.prototype.disableClick = function(e) {
     var icon = e.target;
     
     if (icon.getAttribute("disabled") === "false") {
@@ -218,7 +218,7 @@ RecipeWaiter.prototype.disable_click = function(e) {
  * @fires Manager#statechange
  * @param {event} e
  */
-RecipeWaiter.prototype.breakpoint_click = function(e) {
+RecipeWaiter.prototype.breakpointClick = function(e) {
     var bp = e.target;
 
     if (bp.getAttribute("break") === "false") {
@@ -240,7 +240,7 @@ RecipeWaiter.prototype.breakpoint_click = function(e) {
  * @fires Manager#statechange
  * @param {event} e
  */
-RecipeWaiter.prototype.operation_dblclick = function(e) {
+RecipeWaiter.prototype.operationDblclick = function(e) {
     e.target.remove();
     window.dispatchEvent(this.manager.statechange);
 };
@@ -253,7 +253,7 @@ RecipeWaiter.prototype.operation_dblclick = function(e) {
  * @fires Manager#statechange
  * @param {event} e
  */
-RecipeWaiter.prototype.operation_child_dblclick = function(e) {
+RecipeWaiter.prototype.operationChildDblclick = function(e) {
     e.target.parentNode.remove();
     window.dispatchEvent(this.manager.statechange);
 };
@@ -262,31 +262,31 @@ RecipeWaiter.prototype.operation_child_dblclick = function(e) {
 /**
  * Generates a configuration object to represent the current recipe.
  *
- * @returns {recipe_config}
+ * @returns {recipeConfig}
  */
-RecipeWaiter.prototype.get_config = function() {
-    var config = [], ingredients, ing_list, disabled, bp, item,
-        operations = document.querySelectorAll("#rec_list li.operation");
+RecipeWaiter.prototype.getConfig = function() {
+    var config = [], ingredients, ingList, disabled, bp, item,
+        operations = document.querySelectorAll("#rec-list li.operation");
     
     for (var i = 0; i < operations.length; i++) {
         ingredients = [];
         disabled = operations[i].querySelector(".disable-icon");
         bp = operations[i].querySelector(".breakpoint");
-        ing_list = operations[i].querySelectorAll(".arg");
+        ingList = operations[i].querySelectorAll(".arg");
         
-        for (var j = 0; j < ing_list.length; j++) {
-            if (ing_list[j].getAttribute("type") === "checkbox") {
+        for (var j = 0; j < ingList.length; j++) {
+            if (ingList[j].getAttribute("type") === "checkbox") {
                 // checkbox
-                ingredients[j] = ing_list[j].checked;
-            } else if (ing_list[j].classList.contains("toggle-string")) {
-                // toggle_string
+                ingredients[j] = ingList[j].checked;
+            } else if (ingList[j].classList.contains("toggle-string")) {
+                // toggleString
                 ingredients[j] = {
-                    option: ing_list[j].previousSibling.children[0].textContent.slice(0, -1),
-                    string: ing_list[j].value
+                    option: ingList[j].previousSibling.children[0].textContent.slice(0, -1),
+                    string: ingList[j].value
                 };
             } else {
                 // all others
-                ingredients[j] = ing_list[j].value;
+                ingredients[j] = ingList[j].value;
             }
         }
         
@@ -315,8 +315,8 @@ RecipeWaiter.prototype.get_config = function() {
  *
  * @param {number} position
  */
-RecipeWaiter.prototype.update_breakpoint_indicator = function(position) {
-    var operations = document.querySelectorAll("#rec_list li.operation");
+RecipeWaiter.prototype.updateBreakpointIndicator = function(position) {
+    var operations = document.querySelectorAll("#rec-list li.operation");
     for (var i = 0; i < operations.length; i++) {
         if (i === position) {
             operations[i].classList.add("break");
@@ -333,19 +333,19 @@ RecipeWaiter.prototype.update_breakpoint_indicator = function(position) {
  *
  * @param {element} el - The operation stub element from the operations pane
  */
-RecipeWaiter.prototype.build_recipe_operation = function(el) {
-    var op_name = el.textContent;
-    var op = new HTMLOperation(op_name, this.app.operations[op_name], this.app, this.manager);
-    el.innerHTML = op.to_full_html();
+RecipeWaiter.prototype.buildRecipeOperation = function(el) {
+    var opName = el.textContent;
+    var op = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
+    el.innerHTML = op.toFullHtml();
     
-    if (this.app.operations[op_name].flow_control) {
+    if (this.app.operations[opName].flowControl) {
         el.classList.add("flow-control-op");
     }
     
     // Disable auto-bake if this is a manual op - this should be moved to the 'operationadd'
     // handler after event restructuring
-    if (op.manual_bake && this.app.auto_bake_) {
-        this.manager.controls.set_auto_bake(false);
+    if (op.manualBake && this.app.autoBake_) {
+        this.manager.controls.setAutoBake(false);
         this.app.alert("Auto-Bake is disabled by default when using this operation.", "info", 5000);
     }
 };
@@ -357,13 +357,13 @@ RecipeWaiter.prototype.build_recipe_operation = function(el) {
  * @param {string} name - The name of the operation to add
  * @returns {element}
  */
-RecipeWaiter.prototype.add_operation = function(name) {
+RecipeWaiter.prototype.addOperation = function(name) {
     var item = document.createElement("li");
     
     item.classList.add("operation");
     item.innerHTML = name;
-    this.build_recipe_operation(item);
-    document.getElementById("rec_list").appendChild(item);
+    this.buildRecipeOperation(item);
+    document.getElementById("rec-list").appendChild(item);
     
     item.dispatchEvent(this.manager.operationadd);
     return item;
@@ -375,27 +375,27 @@ RecipeWaiter.prototype.add_operation = function(name) {
  *
  * @fires Manager#operationremove
  */
-RecipeWaiter.prototype.clear_recipe = function() {
-    var rec_list = document.getElementById("rec_list");
-    while (rec_list.firstChild) {
-        rec_list.removeChild(rec_list.firstChild);
+RecipeWaiter.prototype.clearRecipe = function() {
+    var recList = document.getElementById("rec-list");
+    while (recList.firstChild) {
+        recList.removeChild(recList.firstChild);
     }
-    rec_list.dispatchEvent(this.manager.operationremove);
+    recList.dispatchEvent(this.manager.operationremove);
 };
 
 
 /**
- * Handler for operation dropdown events from toggle_string arguments.
+ * Handler for operation dropdown events from toggleString arguments.
  * Sets the selected option as the name of the button.
  *
  * @param {event} e
  */
-RecipeWaiter.prototype.dropdown_toggle_click = function(e) {
+RecipeWaiter.prototype.dropdownToggleClick = function(e) {
     var el = e.target,
         button = el.parentNode.parentNode.previousSibling;
         
     button.innerHTML = el.textContent + " <span class='caret'></span>";
-    this.ing_change();
+    this.ingChange();
 };
 
 
@@ -406,7 +406,7 @@ RecipeWaiter.prototype.dropdown_toggle_click = function(e) {
  * @fires Manager#statechange
  * @param {event} e
  */
-RecipeWaiter.prototype.op_add = function(e) {
+RecipeWaiter.prototype.opAdd = function(e) {
     window.dispatchEvent(this.manager.statechange);
 };
 
@@ -418,6 +418,6 @@ RecipeWaiter.prototype.op_add = function(e) {
  * @fires Manager#statechange
  * @param {event} e
  */
-RecipeWaiter.prototype.op_remove = function(e) {
+RecipeWaiter.prototype.opRemove = function(e) {
     window.dispatchEvent(this.manager.statechange);
 };

File diff suppressed because it is too large
+ 9 - 9
src/js/views/html/SeasonalWaiter.js


+ 9 - 9
src/js/views/html/WindowWaiter.js

@@ -18,9 +18,9 @@ var WindowWaiter = function(app) {
  * Resets the layout of CyberChef's panes after 200ms (so that continuous resizing doesn't cause
  * continuous resetting).
  */
-WindowWaiter.prototype.window_resize = function() {
-    clearTimeout(this.reset_layout_timeout);
-    this.reset_layout_timeout = setTimeout(this.app.reset_layout.bind(this.app), 200);
+WindowWaiter.prototype.windowResize = function() {
+    clearTimeout(this.resetLayoutTimeout);
+    this.resetLayoutTimeout = setTimeout(this.app.resetLayout.bind(this.app), 200);
 };
 
 
@@ -29,8 +29,8 @@ WindowWaiter.prototype.window_resize = function() {
  * Saves the current time so that we can calculate how long the window was unfocussed for when
  * focus is returned.
  */
-WindowWaiter.prototype.window_blur = function() {
-    this.window_blur_time = new Date().getTime();
+WindowWaiter.prototype.windowBlur = function() {
+    this.windowBlurTime = new Date().getTime();
 };
 
 
@@ -44,9 +44,9 @@ WindowWaiter.prototype.window_blur = function() {
  * This will stop baking taking a long time when the CyberChef browser tab has been unfocused for
  * a long time and the browser has swapped out all its memory.
  */
-WindowWaiter.prototype.window_focus = function() {
-    var unfocused_time = new Date().getTime() - this.window_blur_time;
-    if (unfocused_time > 60000) {
-        this.app.silent_bake();
+WindowWaiter.prototype.windowFocus = function() {
+    var unfocusedTime = new Date().getTime() - this.windowBlurTime;
+    if (unfocusedTime > 60000) {
+        this.app.silentBake();
     }
 };

+ 14 - 14
src/js/views/html/main.js

@@ -10,7 +10,7 @@
  * Main function used to build the CyberChef web app.
  */
 var main = function() {
-    var default_favourites = [
+    var defaultFavourites = [
         "To Base64",
         "From Base64",
         "To Hex",
@@ -23,27 +23,27 @@ var main = function() {
         "Fork"
     ];
     
-    var default_options = {
-        update_url          : true,
-        show_highlighter    : true,
-        treat_as_utf8       : true,
-        word_wrap           : true,
-        show_errors         : true,
-        error_timeout       : 4000,
-        auto_bake_threshold : 200,
-        attempt_highlight   : true,
-        snow                : false,
+    var defaultOptions = {
+        updateUrl         : true,
+        showHighlighter   : true,
+        treatAsUtf8       : true,
+        wordWrap          : true,
+        showErrors        : true,
+        errorTimeout      : 4000,
+        autoBakeThreshold : 200,
+        attemptHighlight  : true,
+        snow              : false,
     };
 
     document.removeEventListener("DOMContentLoaded", main, false);
-    window.app = new HTMLApp(Categories, OperationConfig, default_favourites, default_options);
+    window.app = new HTMLApp(Categories, OperationConfig, defaultFavourites, defaultOptions);
     window.app.setup();
 };
 
 // Fix issues with browsers that don't support console.log()
 window.console = console || {log: function() {}, error: function() {}};
 
-window.compile_time = moment.tz("<%= grunt.template.today() %>", "ddd MMM D YYYY HH:mm:ss", "UTC").valueOf();
-window.compile_message = "<%= compile_msg %>";
+window.compileTime = moment.tz("<%= grunt.template.today() %>", "ddd MMM D YYYY HH:mm:ss", "UTC").valueOf();
+window.compileMessage = "<%= compileMsg %>";
 
 document.addEventListener("DOMContentLoaded", main, false);

BIN
src/static/images/fork_me.png


BIN
src/static/images/maximise-16x16.png


BIN
src/static/images/restore-16x16.png


+ 21 - 6
src/static/stats.txt

@@ -1,3 +1,4 @@
+<<<<<<< HEAD
 203	source files
 <<<<<<< HEAD
 <<<<<<< HEAD
@@ -23,14 +24,24 @@
 95316	lines
 3.4M	size
 >>>>>>> master
+=======
+211	source files
+114840	lines
+4.3M	size
+
+141	JavaScript source files
+105680	lines
+3.7M	size
+>>>>>>> master
 
-78	third party JavaScript source files
-76377	lines
-2.7M	size
+83	third party JavaScript source files
+86258	lines
+3.0M	size
 
 58	first party JavaScript source files
 <<<<<<< HEAD
 <<<<<<< HEAD
+<<<<<<< HEAD
 18934	lines
 729K	size
 =======
@@ -41,9 +52,13 @@
 18939	lines
 724K	size
 >>>>>>> master
+=======
+19422	lines
+732K	size
+>>>>>>> master
 
-3.2M	uncompressed JavaScript size
-1.7M	compressed JavaScript size
+3.4M	uncompressed JavaScript size
+1.9M	compressed JavaScript size
 
 15	categories
-155	operations
+165	operations

Some files were not shown because too many files changed in this diff