diff --git a/.gitignore b/.gitignore
index 482be5c7..93f13619 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,2 @@
node_modules
npm-debug.log
-build/dev
-docs/*
-!docs/*.conf.json
-!docs/*.ico
diff --git a/build/prod/.htaccess b/.htaccess
similarity index 100%
rename from build/prod/.htaccess
rename to .htaccess
diff --git a/Gruntfile.js b/Gruntfile.js
deleted file mode 100755
index 2963e138..00000000
--- a/Gruntfile.js
+++ /dev/null
@@ -1,444 +0,0 @@
-module.exports = function(grunt) {
- grunt.file.defaultEncoding = "utf8";
- grunt.file.preserveBOM = false;
-
- // 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"]);
-
- grunt.registerTask("prod",
- "Creates a production-ready build. Use the --msg flag to add a compile message.",
- ["jshint", "exec:stats", "clean", "jsdoc", "concat", "copy", "cssmin", "uglify:prod", "inline", "htmlmin", "chmod"]);
-
- grunt.registerTask("docs",
- "Compiles documentation in the /docs directory.",
- ["clean:docs", "jsdoc", "chmod:docs"]);
-
- 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"]);
-
- grunt.registerTask("default",
- "Lints the code base and shows stats",
- ["jshint", "exec:stats", "exec:display_stats"]);
-
- grunt.registerTask("doc", "docs");
- grunt.registerTask("lint", "jshint");
-
-
- // Load tasks provided by each plugin
- grunt.loadNpmTasks("grunt-contrib-jshint");
- grunt.loadNpmTasks("grunt-jsdoc");
- grunt.loadNpmTasks("grunt-contrib-clean");
- grunt.loadNpmTasks("grunt-contrib-concat");
- grunt.loadNpmTasks("grunt-contrib-copy");
- grunt.loadNpmTasks("grunt-contrib-uglify");
- grunt.loadNpmTasks("grunt-contrib-cssmin");
- grunt.loadNpmTasks("grunt-contrib-htmlmin");
- grunt.loadNpmTasks("grunt-inline-alt");
- grunt.loadNpmTasks("grunt-chmod");
- grunt.loadNpmTasks("grunt-exec");
- grunt.loadNpmTasks("grunt-contrib-watch");
-
-
- // JS includes
- var js_files = [
- // Third party framework libraries
- "src/js/lib/jquery-2.1.1.js",
- "src/js/lib/bootstrap-3.3.6.js",
- "src/js/lib/split.js",
- "src/js/lib/bootstrap-switch.js",
- "src/js/lib/yahoo.js",
- "src/js/lib/snowfall.jquery.js",
-
- // Third party operation libraries
- "src/js/lib/cryptojs/core.js",
- "src/js/lib/cryptojs/x64-core.js",
- "src/js/lib/cryptojs/enc-base64.js",
- "src/js/lib/cryptojs/enc-utf16.js",
- "src/js/lib/cryptojs/md5.js",
- "src/js/lib/cryptojs/evpkdf.js",
- "src/js/lib/cryptojs/cipher-core.js",
- "src/js/lib/cryptojs/mode-cfb.js",
- "src/js/lib/cryptojs/mode-ctr-gladman.js",
- "src/js/lib/cryptojs/mode-ctr.js",
- "src/js/lib/cryptojs/mode-ecb.js",
- "src/js/lib/cryptojs/mode-ofb.js",
- "src/js/lib/cryptojs/format-hex.js",
- "src/js/lib/cryptojs/lib-typedarrays.js",
- "src/js/lib/cryptojs/pad-ansix923.js",
- "src/js/lib/cryptojs/pad-iso10126.js",
- "src/js/lib/cryptojs/pad-iso97971.js",
- "src/js/lib/cryptojs/pad-nopadding.js",
- "src/js/lib/cryptojs/pad-zeropadding.js",
- "src/js/lib/cryptojs/aes.js",
- "src/js/lib/cryptojs/hmac.js",
- "src/js/lib/cryptojs/rabbit-legacy.js",
- "src/js/lib/cryptojs/rabbit.js",
- "src/js/lib/cryptojs/ripemd160.js",
- "src/js/lib/cryptojs/sha1.js",
- "src/js/lib/cryptojs/sha256.js",
- "src/js/lib/cryptojs/sha224.js",
- "src/js/lib/cryptojs/sha512.js",
- "src/js/lib/cryptojs/sha384.js",
- "src/js/lib/cryptojs/sha3.js",
- "src/js/lib/cryptojs/tripledes.js",
- "src/js/lib/cryptojs/rc4.js",
- "src/js/lib/cryptojs/pbkdf2.js",
- "src/js/lib/jsbn/jsbn.js",
- "src/js/lib/jsbn/jsbn2.js",
- "src/js/lib/jsbn/base64.js",
- "src/js/lib/jsbn/ec.js",
- "src/js/lib/jsbn/prng4.js",
- "src/js/lib/jsbn/rng.js",
- "src/js/lib/jsbn/rsa.js",
- "src/js/lib/jsbn/sec.js",
- "src/js/lib/jsrasign/asn1-1.0.js",
- "src/js/lib/jsrasign/asn1hex-1.1.js",
- "src/js/lib/jsrasign/asn1x509-1.0.js",
- "src/js/lib/jsrasign/base64x-1.1.js",
- "src/js/lib/jsrasign/crypto-1.1.js",
- "src/js/lib/jsrasign/dsa-modified-1.0.js",
- "src/js/lib/jsrasign/ecdsa-modified-1.0.js",
- "src/js/lib/jsrasign/ecparam-1.0.js",
- "src/js/lib/jsrasign/keyutil-1.0.js",
- "src/js/lib/jsrasign/x509-1.1.js",
- "src/js/lib/blowfish.dojo.js",
- "src/js/lib/rawdeflate.js",
- "src/js/lib/rawinflate.js",
- "src/js/lib/zip.js",
- "src/js/lib/unzip.js",
- "src/js/lib/zlib_and_gzip.js",
- "src/js/lib/bzip2.js",
- "src/js/lib/punycode.js",
- "src/js/lib/uas_parser.js",
- "src/js/lib/esprima.js",
- "src/js/lib/escodegen.browser.js",
- "src/js/lib/esmangle.min.js",
- "src/js/lib/diff.js",
- "src/js/lib/moment.js",
- "src/js/lib/moment-timezone.js",
- "src/js/lib/prettify.js",
- "src/js/lib/vkbeautify.js",
- "src/js/lib/Sortable.js",
- "src/js/lib/bootstrap-colorpicker.js",
-
- // Custom libraries
- "src/js/lib/canvas_components.js",
-
- // Utility functions
- "src/js/core/Utils.js",
-
- // Operation objects
- "src/js/operations/*.js",
-
- // Core framework objects
- "src/js/core/*.js",
- "src/js/config/Categories.js",
- "src/js/config/OperationConfig.js",
-
- // HTML view objects
- "src/js/views/html/*.js",
- "!src/js/views/html/main.js",
-
- // Start the app!
- "src/js/views/html/main.js",
- ];
-
- var banner = '/**\n\
- * CyberChef - The Cyber Swiss Army Knife\n\
- *\n\
- * @copyright Crown Copyright 2016\n\
- * @license Apache-2.0\n\
- *\n\
- * Copyright 2016 Crown Copyright\n\
- *\n\
- * Licensed under the Apache License, Version 2.0 (the "License");\n\
- * you may not use this file except in compliance with the License.\n\
- * You may obtain a copy of the License at\n\
- *\n\
- * http://www.apache.org/licenses/LICENSE-2.0\n\
- *\n\
- * Unless required by applicable law or agreed to in writing, software\n\
- * distributed under the License is distributed on an "AS IS" BASIS,\n\
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\
- * See the License for the specific language governing permissions and\n\
- * limitations under the License.\n\
- */\n';
-
- var template_options = {
- data: {
- compile_msg: grunt.option("compile-msg") || grunt.option("msg") || "",
- codebase_stats: grunt.file.read("src/static/stats.txt").split("\n").join(" ")
- }
- };
-
- // Project configuration
- grunt.initConfig({
- jshint: {
- options: {
- jshintrc: "src/js/.jshintrc"
- },
- gruntfile: ["Gruntfile.js"],
- core: ["src/js/core/**/*.js"],
- config: ["src/js/config/**/*.js"],
- views: ["src/js/views/**/*.js"],
- operations: ["src/js/operations/**/*.js"],
- },
- jsdoc: {
- options: {
- destination: "docs",
- template: "node_modules/ink-docstrap/template",
- recurse: true,
- readme: "./README.md",
- configure: "docs/jsdoc.conf.json"
- },
- all: {
- src: [
- "src/js/**/*.js",
- "!src/js/lib/**/*",
- ],
- }
- },
- clean: {
- dev: ["build/dev/*"],
- prod: ["build/prod/*"],
- docs: ["docs/*", "!docs/*.conf.json", "!docs/*.ico"],
- },
- concat: {
- options: {
- process: template_options
- },
- css: {
- options: {
- banner: banner.replace(/\/\*\*/g, "/*!"),
- process: function(content, srcpath) {
- // Change special comments from /** to /*! to comply with cssmin
- content = content.replace(/^\/\*\* /g, "/*! ");
- return grunt.template.process(content);
- }
- },
- src: [
- "src/css/lib/**/*.css",
- "src/css/structure/**/*.css",
- "src/css/themes/classic.css"
- ],
- dest: "build/dev/styles.css"
- },
- js: {
- options: {
- banner: '"use strict";\n'
- },
- src: js_files,
- dest: "build/dev/scripts.js"
- }
- },
- copy: {
- html_dev: {
- options: {
- process: function(content, srcpath) {
- return grunt.template.process(content, template_options);
- }
- },
- src: "src/html/index.html",
- dest: "build/dev/index.html"
- },
- html_prod: {
- options: {
- process: function(content, srcpath) {
- return grunt.template.process(content, template_options);
- }
- },
- src: "src/html/index.html",
- dest: "build/prod/index.html"
- },
- html_inline: {
- options: {
- process: function(content, srcpath) {
- // TODO: Do all this in Jade
- content = content.replace(
- 'Download CyberChef',
- 'Compile time: ' + grunt.template.today("dd/mm/yyyy HH:MM:ss") + ' UTC');
- return grunt.template.process(content, template_options);
- }
- },
- src: "src/html/index.html",
- dest: "build/prod/cyberchef.htm"
- },
- static_dev: {
- files: [
- {
- expand: true,
- cwd: "src/static/",
- src: [
- "**/*",
- "**/.*",
- "!stats.txt"
- ],
- dest: "build/dev/"
- }
- ]
- },
- static_prod: {
- files: [
- {
- expand: true,
- cwd: "src/static/",
- src: [
- "**/*",
- "**/.*",
- "!stats.txt"
- ],
- dest: "build/prod/"
- }
- ]
- }
- },
- uglify: {
- options: {
- preserveComments: function(node, comment) {
- if (comment.value.indexOf("* @license") === 0) return true;
- return false;
- },
- screwIE8: true,
- ASCIIOnly: true,
- beautify: {
- beautify: false,
- inline_script: true,
- ascii_only: true,
- screw_ie8: true
- },
- compress: {
- screw_ie8: true
- },
- banner: banner
- },
- prod: {
- src: "build/dev/scripts.js",
- dest: "build/prod/scripts.js"
- }
- },
- cssmin: {
- prod: {
- src: "build/dev/styles.css",
- dest: "build/prod/styles.css"
- }
- },
- htmlmin: {
- prod: {
- options: {
- removeComments: true,
- collapseWhitespace: true,
- minifyJS: true,
- minifyCSS: true
- },
- src: "build/prod/index.html",
- dest: "build/prod/index.html"
- },
- inline: {
- options: {
- removeComments: true,
- collapseWhitespace: true,
- minifyJS: false,
- minifyCSS: false
- },
- src: "build/prod/cyberchef.htm",
- dest: "build/prod/cyberchef.htm"
- }
- },
- inline: {
- options: {
- tag: "",
- inlineTagAttributes: {
- js: "type='application/javascript'",
- css: "type='text/css'"
- }
- },
- prod: {
- src: "build/prod/cyberchef.htm",
- dest: "build/prod/cyberchef.htm"
- }
- },
- chmod: {
- build: {
- options: {
- mode: "755",
- },
- src: ["build/**/*", "build/**/.htaccess", "build/"]
- },
- docs: {
- options: {
- mode: "755",
- },
- src: ["docs/**/*", "docs/"]
- }
- },
- exec: {
- repo_size: {
- command: [
- "git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
- "du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
- ].join(";"),
- stderr: false
- },
- stats: {
- command: "rm src/static/stats.txt;" +
- [
- "ls src/ -R1 | grep '^$' -v | grep ':$' -v | wc -l | xargs printf '%b\tsource files\n'",
- "find src/ -regex '.*\..*' -print | xargs cat | wc -l | xargs printf '%b\tlines\n'",
- "du -hs src/ | pcregrep -o '^[^\t]*' | xargs printf '%b\tsize\n'",
-
- "ls src/js/ -R1 | grep '\.js$' | wc -l | xargs printf '\n%b\tJavaScript source files\n'",
- "find src/js/ -regex '.*\.js' -print | xargs cat | wc -l | xargs printf '%b\tlines\n'",
- "find src/js/ -regex '.*\.js' -exec du -hcs {} \+ | tail -n1 | egrep -o '^[^\t]*' | xargs printf '%b\tsize\n'",
-
- "find src/js/ -regex '.*/lib/.*\.js' -print | wc -l | xargs printf '\n%b\tthird party JavaScript source files\n'",
- "find src/js/ -regex '.*/lib/.*\.js' -print | xargs cat | wc -l | xargs printf '%b\tlines\n'",
- "find src/js/ -regex '.*/lib/.*\.js' -exec du -hcs {} \+ | tail -n1 | egrep -o '^[^\t]*' | xargs printf '%b\tsize\n'",
-
- "find src/js/ -regex '.*\.js' -not -regex '.*/lib/.*' -print | wc -l | xargs printf '\n%b\tfirst party JavaScript source files\n'",
- "find src/js/ -regex '.*\.js' -not -regex '.*/lib/.*' -print | xargs cat | wc -l | xargs printf '%b\tlines\n'",
- "find src/js/ -regex '.*\.js' -not -regex '.*/lib/.*' -exec du -hcs {} \+ | tail -n1 | egrep -o '^[^\t]*' | xargs printf '%b\tsize\n'",
-
- "du build/dev/scripts.js -h | egrep -o '^[^\t]*' | xargs printf '\n%b\tuncompressed JavaScript size\n'",
- "du build/prod/scripts.js -h | egrep -o '^[^\t]*' | xargs printf '%b\tcompressed JavaScript size\n'",
-
- "grep -E '^\\s+name: ' src/js/config/Categories.js | wc -l | xargs printf '\n%b\tcategories\n'",
- "grep -E '^\\s+\"[A-Za-z0-9 \\-]+\": {' src/js/config/OperationConfig.js | wc -l | xargs printf '%b\toperations\n'",
-
- ].join(" >> src/static/stats.txt;") + " >> src/static/stats.txt;",
- stderr: false
- },
- display_stats: {
- command: "cat src/static/stats.txt"
- },
- clean_git: {
- command: "git gc --prune=now --aggressive"
- },
- },
- watch: {
- css: {
- files: "src/css/**/*.css",
- tasks: ["concat:css", "chmod:build"]
- },
- js: {
- files: "src/js/**/*.js",
- tasks: ["concat:js_all", "chmod:build"]
- },
- html: {
- files: "src/html/**/*.html",
- tasks: ["copy:html_dev", "chmod:build"]
- },
- static: {
- files: ["src/static/**/*", "src/static/**/.*"],
- tasks: ["copy:static_dev", "chmod:build"]
- },
- grunt: {
- files: "Gruntfile.js",
- tasks: ["clean:dev", "concat:css", "concat:js_all", "copy:html_dev", "copy:static_dev", "chmod:build"]
- }
- },
- });
-
-};
diff --git a/README.md b/README.md
deleted file mode 100755
index c49873d6..00000000
--- a/README.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# CyberChef
-
-####*The Cyber Swiss Army Knife*
-
-CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include creating hexdumps, simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, data compression and decompression, calculating hashes and checksums, IPv6 and X.509 parsing, and much more.
-
-The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years. Every effort has been made to structure the code in a readable and extendable format, however it should be noted that the analyst is not a professional developer and the code has not been peer-reviewed for compliance with a formal specification.
-
-## Live demo
-
-CyberChef is still under active development. As a result, it shouldn't be considered a finished product. There is still testing and bug fixing to do, new features to be added and additional documentation to write. Please contribute!
-
-Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness.
-
-[A live demo can be found here][1] - have fun!
-Note: Use Chrome or Firefox, see the Browser Support section below for details.
-
-
-## How it works
-
-There are four main areas in CyberChef:
-
- 1. The **input** box in the top right, where you can paste, type or drag the data you want to operate on.
- 2. The **output** box in the bottom right, where the outcome of the specified processing will be displayed.
- 3. The **operations** list on the far left, where you can find all the operations that CyberChef is capable of in categorised lists, or by searching.
- 4. The **recipe** area in the middle, where you drag the operations that you want to use and specify arguments and options.
-
-You can use as many operations as you like in simple or complex ways. Some examples are as follows:
-
- - [Decode a Base64-encoded string][2]
- - [Convert a date and time to a different time zone][3]
- - [Parse a Teredo IPv6 address][4]
- - [Convert data from a hexdump, then decompress][5]
- - [Display multiple timestamps as full dates][6]
- - [Carry out different operations on data of different types][7]
-
-
-## Features
-
- - Drag and drop
- - Operations can be dragged in and out of the recipe list, or reorganised.
- - Files can be dragged over the input box to load them directly.
- - Auto Bake
- - Whenever you modify the input or the recipe, CyberChef will automatically “bake” for you and produce the output immediately.
- - This can be turned off and operated manually if it is affecting performance (if the input is very large, for instance).
- - If any bake takes longer than 200 milliseconds, auto bake will be switched off automatically to prevent further performance issues.
- - Breakpoints
- - You can set breakpoints on any operation in your recipe to pause execution before running it.
- - You can also step through the recipe one operation at a time to see what the data looks like at each stage.
- - Save and load recipes
- - If you come up with an awesome recipe that you know you’ll want to use again, just click save and add it to your local storage. It'll be waiting for you next time you visit CyberChef.
- - You can also copy a URL which includes your recipe and input which can be shared with others.
- - Search
- - If you know the name of the operation you want or a word associated with it, start typing it into the search field and any matching operations will immediately be shown.
- - Highlighting
- - When you highlight text in the input or output, the offset and length values will be displayed and, if possible, the corresponding data will be highlighted in the output or input respectively (example: [highlight the word 'question' in the input to see where it appears in the output][8]).
- - Save to file and load from file
- - You can save the output to a file at any time or load a file by dragging and dropping it into the input field (note that files larger than about 500kb may cause your browser to hang or even crash due to the way that browsers handle large amounts of textual data).
- - CyberChef is entirely client-side
- - It should be noted that none of your input or recipe configuration is ever sent to the CyberChef web server - all processing is carried out within your browser, on your own computer.
- - Due to this feature, CyberChef can be compiled into a single HTML file. You can download this file and drop it into a virtual machine, share it with other people, or use it independently on your desktop.
-
-
-## Browser support
-
-CyberChef works well in modern versions of Google Chrome and Mozilla Firefox.
-
-To aid in the efficient development of new features and operations, there has been no attempt to maintain support for any version of Microsoft Internet Explorer.
-
-Microsoft Edge is currently unsupported, but if anyone would like to contribute compatibility fixes, they would be appreciated.
-
-
-## Contributing
-
-An installation walkthrough, how-to guides for adding new operations, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](#### TO BE REPLACED ####).
-
- - Sign the [GCHQ Contributor Licence Agreement](https://github.com/gchq/Gaffer/wiki/GCHQ-OSS-Contributor-License-Agreement-V1.0)
- - Push your changes to your fork.
- - Submit a pull request.
-
-
- [1]: https://gchq.github.io/cyberchef
- [2]: https://gchq.github.io/cyberchef/?recipe=%5B%7B%22op%22%3A%22From%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%2Ctrue%5D%7D%5D&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1
- [3]: https://gchq.github.io/cyberchef/?recipe=%5B%7B%22op%22%3A%22Translate%20DateTime%20Format%22%2C%22args%22%3A%5B%22Standard%20date%20and%20time%22%2C%22DD%2FMM%2FYYYY%20HH%3Amm%3Ass%22%2C%22UTC%22%2C%22dddd%20Do%20MMMM%20YYYY%20HH%3Amm%3Ass%20Z%20z%22%2C%22Australia%2FQueensland%22%5D%7D%5D&input=MTUvMDYvMjAxNSAyMDo0NTowMA
- [4]: https://gchq.github.io/cyberchef/?recipe=%5B%7B%22op%22%3A%22Parse%20IPv6%20address%22%2C%22args%22%3A%5B%5D%7D%5D&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy
- [5]: https://gchq.github.io/cyberchef/?recipe=%5B%7B%22op%22%3A%22From%20Hexdump%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22Gunzip%22%2C%22args%22%3A%5B%5D%7D%5D&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu%2Fy7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb%2F3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw
- [6]: https://gchq.github.io/cyberchef/?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22From%20UNIX%20Timestamp%22%2C%22args%22%3A%5B%22Seconds%20(s)%22%5D%7D%5D&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA
- [7]: https://gchq.github.io/cyberchef/?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22Conditional%20Jump%22%2C%22args%22%3A%5B%221%22%2C%222%22%2C%2210%22%5D%7D%2C%7B%22op%22%3A%22To%20Hex%22%2C%22args%22%3A%5B%22Space%22%5D%7D%2C%7B%22op%22%3A%22Return%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22To%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%5D%7D%5D&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA
- [8]: https://gchq.github.io/cyberchef/?recipe=%5B%7B%22op%22%3A%22XOR%22%2C%22args%22%3A%5B%22de%20ad%20be%20ef%22%2C%22Hex%22%2Cfalse%2Cfalse%5D%7D%2C%7B%22op%22%3A%22To%20Hexdump%22%2C%22args%22%3A%5B%2216%22%2Cfalse%2Cfalse%5D%7D%5D&input=VGhlIGFuc3dlciB0byB0aGUgdWx0aW1hdGUgcXVlc3Rpb24gb2YgbGlmZSwgdGhlIFVuaXZlcnNlLCBhbmQgZXZlcnl0aGluZyBpcyA0Mi4
\ No newline at end of file
diff --git a/build/prod/cyberchef.htm b/cyberchef.htm
similarity index 100%
rename from build/prod/cyberchef.htm
rename to cyberchef.htm
diff --git a/docs/Base.html b/docs/Base.html
new file mode 100755
index 00000000..27990a08
--- /dev/null
+++ b/docs/Base.html
@@ -0,0 +1,786 @@
+
+
+
+
response.progress - The position that we have got to in the recipe
+
+
+
+
+
+
+ Type
+
+
+
+number
+
+
+
+
+
+
+
+
+
+
+
response.options - The app options object (which may have been changed)
+
+
+
+
+
+
+ Type
+
+
+
+number
+
+
+
+
+
+
+
+
+
+
+
response.duration - The number of ms it took to execute the recipe
+
+
+
+
+
+
+ Type
+
+
+
+number
+
+
+
+
+
+
+
+
+
+
+
response.error - The error object thrown by a failed operation (false if no error)
+
+
+
+
+
+
+ Type
+
+
+
+number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
silent_bake(recipe_config)
+
+
+
+
+
+
+
+
When a browser tab is unfocused and the browser has to run lots of dynamic content in other tabs, it swaps out the memory for that tab. If the CyberChef tab has been unfocused for more than a minute, we run a silent bake which will force the browser to load and cache all the relevant JavaScript code needed to do a real bake.
+
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.
+
The output will not be modified (hence "silent" bake).
+
This will only actually execute the recipe if auto-bake is enabled, otherwise it will just load the recipe, ingredients and dish.
I'm not proud of this code, but seriously, try writing a generic lexer and parser that correctly generates an AST for multiple different languages. I have tried, and I can tell you it's pretty much impossible.
+
This basically works. That'll have to be good enough. It's not meant to produce working code, just slightly more readable code.
["[Metric]","Metres per second (m/s)","Kilometres per hour (km/h)","[/Metric]","[Imperial]","Miles per hour (mph)","Knots (kn)","[/Imperial]","[Comparisons]","Human hair growth rate","Bamboo growth rate","World's fastest snail","Usain Bolt's top speed","Jet airliner cruising speed","Concorde","SR-71 Blackbird","Space Shuttle","International Space Station","[/Comparisons]","[Scientific]","Sound in standard atmosphere","Sound in water","Lunar escape velocity","Earth escape velocity","Earth's solar orbit","Solar system's Milky Way orbit","Milky Way relative to the cosmic microwave background","Solar escape velocity","Neutron star escape velocity (0.3c)","Light in a diamond (0.4136c)","Signal in an optical fibre (0.667c)","Light (c)","[/Scientific]"]
["{\"name\":\"Standard date and time\",\"value\":\"DD/MM/YYYY HH:mm:ss\"}","{\"name\":\"American-style date and time\",\"value\":\"MM/DD/YYYY HH:mm:ss\"}","{\"name\":\"International date and time\",\"value\":\"YYYY-MM-DD HH:mm:ss\"}","{\"name\":\"Verbose date and time\",\"value\":\"dddd Do MMMM YYYY HH:mm:ss Z z\"}","{\"name\":\"UNIX timestamp (seconds)\",\"value\":\"X\"}","{\"name\":\"UNIX timestamp offset (milliseconds)\",\"value\":\"x\"}","{\"name\":\"Automatic\",\"value\":\"\"}"]
Converts an HSL color value to RGB. Conversion formula adapted from http://en.wikipedia.org/wiki/HSL_color_space. Assumes h, s, and l are contained in the set [0, 1] and returns r, g, and b in the set [0, 255].
Converts an RGB color value to HSL. Conversion formula adapted from http://en.wikipedia.org/wiki/HSL_color_space. Assumes r, g, and b are contained in the set [0, 255] and returns h, s, and l in the set [0, 1].
Runs a silent bake forcing the browser to load and cache all the relevant JavaScript code needed to do a real bake.
+
The output will not be modified (hence "silent" bake). This will only actually execute the recipe if auto-bake is enabled, otherwise it will just load the recipe, ingredients and dish.
Loads the user's favourite operations from the HTML5 local storage object and populates the Favourites category with them. If the user currently has no saved favourites, the defaults from the view constructor are used.
Filters the list of favourite operations that the user had stored and removes any that are no longer available. The user is notified if this is the case.
// Pops up a red box with the message "[current time] Error: Something has gone wrong!"
+// that will need to be dismissed by the user.
+this.alert("Error: Something has gone wrong!", "danger", 0);
+
+// Pops up a blue information box with the message "[current time] Happy Christmas!"
+// that will disappear after 5 seconds.
+this.alert("Happy Christmas!", "info", 5000);
+
+
+
+
+
+
+
+
+
+
confirm(title, body, callback [, scope])
+
+
+
+
+
+
+
+
Pops up a box asking the user a question and sending the answer to a specified callback function.
+
+
+
+
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+
+
Name
+
+
+
Type
+
+
+
Argument
+
+
+
+
Default
+
+
+
Description
+
+
+
+
+
+
+
+
+
title
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
The title of the box
+
+
+
+
+
+
+
body
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
The question (HTML supported)
+
+
+
+
+
+
+
callback
+
+
+
+
+
+function
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
A function accepting one boolean argument which handles the response e.g. function(answer) {...}
// Pops up a box asking if the user would like a cookie. Prints the answer to the console.
+this.confirm("Question", "Would you like a cookie?", function(answer) {console.log(answer);});
+
+
+
+
+
+
+
+
+
+
alert_close_click()
+
+
+
+
+
+
+
+
Handler for the alert close button click event. Closes the alert box.
The specified range contains more than 65,536 addresses. Running this query could crash your browser. If you want to run it, select the "Allow large queries" option. You are advised to turn off "Auto Bake" whilst editing large ranges.
// Calls the clickable function whenever any element with the .clickable class is clicked
+this.add_listeners(".clickable", "click", this.clickable, this);
// 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);
// 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);
// 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);
+
+
+
+
+
+
+
+
+
+
dynamic_listener_handler(e)
+
+
+
+
+
+
+
+
Handler for dynamic events. This function is called for any dynamic event and decides which callback(s) to execute based on the type and selector.
Finds the operation which has been selected using keyboard shortcuts. This will have the class 'selected-op' set. Returns the index of the operation within the given list.
Handler for op_icon mouseleave events. If this icon created a popover and we're moving back to the operation element, display the operation popover again.
Handler for operation sort end events. Removes the operation from the list if it has been dropped outside. If not, adds it to the list at the appropriate place and initialises it.
Handler for favourite dragover events. If the element being dragged is an operation, displays a visual cue so that the user knows it can be dropped here.
// returns "îáíîâëåííàÿ òåõíè÷êà ïî Áîèíãó. îðèãèíàë ó ìåíÿ. çàáåðåòå êîãäà áóäåòå â ÊÈ"
+Utils.unicode_to_win1251("обновленная техничка по Боингу. оригинал у меня. заберете когда будете в КИ");
+
+
+
+
+
+
+
+
+
+
<static> win1251_to_unicode(win1251_str)
+
+
+
+
+
+
+
+
Converts a Windows-1251 string to Unicode encoding
// returns "обновленная техничка по Боингу. оригинал у меня. заберете когда будете в КИ"
+Utils.unicode_to_win1251("îáíîâëåííàÿ òåõíè÷êà ïî Áîèíãó. îðèãèíàë ó ìåíÿ. çàáåðåòå êîãäà áóäåòå â ÊÈ");
+
+
+
+
+
+
+
+
+
+
<static> to_base64(data [, alphabet])
+
+
+
+
+
+
+
+
Base64's the input byte array using the given alphabet, returning a string.
When a browser tab is unfocused and the browser has to run lots of dynamic content in other tabs, it swaps out the memory for that tab. If the CyberChef tab has been unfocused for more than a minute, we run a silent bake which will force the browser to load and cache all the relevant JavaScript code needed to do a real bake. 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.
/*
* Tell JSHint to ignore "'Object' is not defined" errors in this file, as it references every
* single operation object by definition.
*/
@@ -43,11 +137,11 @@
* @license Apache-2.0
*
* @constant
- * @type {Object.}
+ * @type {Object.<string, OpConf>}
*/
var OperationConfig = {
"Fork": {
- description: "Split the input data up based on the specified delimiter and run all subsequent operations on each branch separately.
For example, to decode multiple Base64 strings, enter them all on separate lines then add the 'Fork' and 'From Base64' operations to the recipe. Each string will be decoded separately.",
+ description: "Split the input data up based on the specified delimiter and run all subsequent operations on each branch separately.<br><br>For example, to decode multiple Base64 strings, enter them all on separate lines then add the 'Fork' and 'From Base64' operations to the recipe. Each string will be decoded separately.",
run: FlowControl.run_fork,
input_type: "string",
output_type: "string",
@@ -125,7 +219,7 @@ var OperationConfig = {
args: []
},
"From Base64": {
- description: "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.
This operation decodes data from an ASCII Base64 string back into its raw format.
e.g. aGVsbG8= becomes hello",
+ description: "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.<br><br>This operation decodes data from an ASCII Base64 string back into its raw format.<br><br>e.g. <code>aGVsbG8=</code> becomes <code>hello</code>",
run: Base64.run_from,
highlight: Base64.highlight_from,
highlight_reverse: Base64.highlight_to,
@@ -138,14 +232,14 @@ var OperationConfig = {
value: Base64.ALPHABET_OPTIONS
},
{
- name: "Remove non‑alphabet chars",
+ name: "Remove non‑alphabet chars",
type: "boolean",
value: Base64.REMOVE_NON_ALPH_CHARS
}
]
},
"To Base64": {
- description: "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.
This operation encodes data in an ASCII Base64 string.
e.g. hello becomes aGVsbG8=",
+ description: "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.<br><br>This operation encodes data in an ASCII Base64 string.<br><br>e.g. <code>hello</code> becomes <code>aGVsbG8=</code>",
run: Base64.run_to,
highlight: Base64.highlight_to,
highlight_reverse: Base64.highlight_from,
@@ -171,7 +265,7 @@ var OperationConfig = {
value: Base64.BASE32_ALPHABET
},
{
- name: "Remove non‑alphabet chars",
+ name: "Remove non‑alphabet chars",
type: "boolean",
value: Base64.REMOVE_NON_ALPH_CHARS
}
@@ -191,7 +285,7 @@ var OperationConfig = {
]
},
"Show Base64 offsets": {
- description: "When a string is within a block of data and the whole block is Base64'd, the string itself could be represented in Base64 in three distinct ways depending on its offset within the block.
This operation shows all possible offsets for a given string so that each possible encoding can be considered.",
+ description: "When a string is within a block of data and the whole block is Base64'd, the string itself could be represented in Base64 in three distinct ways depending on its offset within the block.<br><br>This operation shows all possible offsets for a given string so that each possible encoding can be considered.",
run: Base64.run_offsets,
input_type: "byte_array",
output_type: "html",
@@ -209,7 +303,7 @@ var OperationConfig = {
]
},
"XOR": {
- description: "XOR the input with the given key. e.g. fe023da5
Options Null preserving: If the current byte is 0x00 or the same as the key, skip it.
Differential: Set the key to the value of the previously decoded byte.",
+ description: "XOR the input with the given key.<br>e.g. <code>fe023da5</code><br><br><strong>Options</strong><br><u>Null preserving:</u> If the current byte is 0x00 or the same as the key, skip it.<br><br><u>Differential:</u> Set the key to the value of the previously decoded byte.",
run: BitwiseOp.run_xor,
highlight: true,
highlight_reverse: true,
@@ -235,7 +329,7 @@ var OperationConfig = {
]
},
"XOR Brute Force": {
- description: "Enumerate all possible XOR solutions. Current maximum key length is 2 due to browser performance.
Optionally enter a regex string that you expect to find in the plaintext to filter results (crib).",
+ description: "Enumerate all possible XOR solutions. Current maximum key length is 2 due to browser performance.<br><br>Optionally enter a regex string that you expect to find in the plaintext to filter results (crib).",
run: BitwiseOp.run_xor_brute,
input_type: "byte_array",
output_type: "string",
@@ -292,7 +386,7 @@ var OperationConfig = {
args: []
},
"AND": {
- description: "AND the input with the given key. e.g. fe023da5",
+ description: "AND the input with the given key.<br>e.g. <code>fe023da5</code>",
run: BitwiseOp.run_and,
highlight: true,
highlight_reverse: true,
@@ -308,7 +402,7 @@ var OperationConfig = {
]
},
"OR": {
- description: "OR the input with the given key. e.g. fe023da5",
+ description: "OR the input with the given key.<br>e.g. <code>fe023da5</code>",
run: BitwiseOp.run_or,
highlight: true,
highlight_reverse: true,
@@ -324,7 +418,7 @@ var OperationConfig = {
]
},
"ADD": {
- description: "ADD the input with the given key (e.g. fe023da5), MOD 255",
+ description: "ADD the input with the given key (e.g. <code>fe023da5</code>), MOD 255",
run: BitwiseOp.run_add,
highlight: true,
highlight_reverse: true,
@@ -340,7 +434,7 @@ var OperationConfig = {
]
},
"SUB": {
- description: "SUB the input with the given key (e.g. fe023da5), MOD 255",
+ description: "SUB the input with the given key (e.g. <code>fe023da5</code>), MOD 255",
run: BitwiseOp.run_sub,
highlight: true,
highlight_reverse: true,
@@ -356,7 +450,7 @@ var OperationConfig = {
]
},
"From Hex": {
- description: "Converts a hexadecimal byte string back into a its raw value.
e.g. ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a becomes the UTF-8 encoded string Γειά σου",
+ description: "Converts a hexadecimal byte string back into a its raw value.<br><br>e.g. <code>ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a</code> becomes the UTF-8 encoded string <code>Γειά σου</code>",
run: ByteRepr.run_from_hex,
highlight: ByteRepr.highlight_from,
highlight_reverse: ByteRepr.highlight_to,
@@ -371,7 +465,7 @@ var OperationConfig = {
]
},
"To Hex": {
- description: "Converts the input string to hexadecimal bytes separated by the specified delimiter.
e.g. The UTF-8 encoded string Γειά σου becomes ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a",
+ description: "Converts the input string to hexadecimal bytes separated by the specified delimiter.<br><br>e.g. The UTF-8 encoded string <code>Γειά σου</code> becomes <code>ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a</code>",
run: ByteRepr.run_to_hex,
highlight: ByteRepr.highlight_to,
highlight_reverse: ByteRepr.highlight_from,
@@ -386,7 +480,7 @@ var OperationConfig = {
]
},
"From Charcode": {
- description: "Converts unicode character codes back into text.
e.g. 0393 03b5 03b9 03ac 20 03c3 03bf 03c5 becomes Γειά σου",
+ description: "Converts unicode character codes back into text.<br><br>e.g. <code>0393 03b5 03b9 03ac 20 03c3 03bf 03c5</code> becomes <code>Γειά σου</code>",
run: ByteRepr.run_from_charcode,
highlight: ByteRepr.highlight_from,
highlight_reverse: ByteRepr.highlight_to,
@@ -406,7 +500,7 @@ var OperationConfig = {
]
},
"To Charcode": {
- description: "Converts text to its unicode character code equivalent.
e.g. Γειά σου becomes 0393 03b5 03b9 03ac 20 03c3 03bf 03c5",
+ description: "Converts text to its unicode character code equivalent.<br><br>e.g. <code>Γειά σου</code> becomes <code>0393 03b5 03b9 03ac 20 03c3 03bf 03c5</code>",
run: ByteRepr.run_to_charcode,
highlight: ByteRepr.highlight_to,
highlight_reverse: ByteRepr.highlight_from,
@@ -426,7 +520,7 @@ var OperationConfig = {
]
},
"From Binary": {
- description: "Converts a binary string back into its raw form.
e.g. 01001000 01101001 becomes Hi",
+ description: "Converts a binary string back into its raw form.<br><br>e.g. <code>01001000 01101001</code> becomes <code>Hi</code>",
run: ByteRepr.run_from_binary,
highlight: ByteRepr.highlight_from_binary,
highlight_reverse: ByteRepr.highlight_to_binary,
@@ -441,7 +535,7 @@ var OperationConfig = {
]
},
"To Binary": {
- description: "Displays the input data as a binary string.
e.g. Hi becomes 01001000 01101001",
+ description: "Displays the input data as a binary string.<br><br>e.g. <code>Hi</code> becomes <code>01001000 01101001</code>",
run: ByteRepr.run_to_binary,
highlight: ByteRepr.highlight_to_binary,
highlight_reverse: ByteRepr.highlight_from_binary,
@@ -456,7 +550,7 @@ var OperationConfig = {
]
},
"From Decimal": {
- description: "Converts the data from an ordinal integer array back into its raw form.
e.g. 72 101 108 108 111 becomes Hello",
+ description: "Converts the data from an ordinal integer array back into its raw form.<br><br>e.g. <code>72 101 108 108 111</code> becomes <code>Hello</code>",
run: ByteRepr.run_from_decimal,
input_type: "string",
output_type: "byte_array",
@@ -469,7 +563,7 @@ var OperationConfig = {
]
},
"To Decimal": {
- description: "Converts the input data to an ordinal integer array.
e.g. Hello becomes 72 101 108 108 111",
+ description: "Converts the input data to an ordinal integer array.<br><br>e.g. <code>Hello</code> becomes <code>72 101 108 108 111</code>",
run: ByteRepr.run_to_decimal,
input_type: "byte_array",
output_type: "string",
@@ -542,14 +636,14 @@ var OperationConfig = {
]
},
"From HTML Entity": {
- description: "Converts HTML entities back to characters
e.g. & becomes &", // tags required to stop the browser just printing &
+ description: "Converts HTML entities back to characters<br><br>e.g. <code>&<span>amp;</span></code> becomes <code>&</code>", // <span> tags required to stop the browser just printing &
run: HTML.run_from_entity,
input_type: "string",
output_type: "string",
args: []
},
"To HTML Entity": {
- description: "Converts characters to HTML entities
e.g. & becomes &", // tags required to stop the browser just printing &
+ description: "Converts characters to HTML entities<br><br>e.g. <code>&</code> becomes <code>&<span>amp;</span></code>", // <span> tags required to stop the browser just printing &
run: HTML.run_to_entity,
input_type: "string",
output_type: "string",
@@ -585,14 +679,14 @@ var OperationConfig = {
]
},
"URL Decode": {
- description: "Converts URI/URL percent-encoded characters back to their raw values.
e.g. %3d becomes =",
+ description: "Converts URI/URL percent-encoded characters back to their raw values.<br><br>e.g. <code>%3d</code> becomes <code>=</code>",
run: URL_.run_from,
input_type: "string",
output_type: "string",
args: []
},
"URL Encode": {
- description: "Encodes problematic characters into percent-encoding, a format supported by URIs/URLs.
e.g. = becomes %3d",
+ description: "Encodes problematic characters into percent-encoding, a format supported by URIs/URLs.<br><br>e.g. <code>=</code> becomes <code>%3d</code>",
run: URL_.run_to,
input_type: "string",
output_type: "string",
@@ -612,7 +706,7 @@ var OperationConfig = {
args: []
},
"Unescape Unicode Characters": {
- description: "Converts unicode-escaped character notation back into raw characters.
Supports the prefixes:
\\u
%u
U+
e.g. \\u03c3\\u03bf\\u03c5 becomes σου",
+ description: "Converts unicode-escaped character notation back into raw characters.<br><br>Supports the prefixes:<ul><li><code>\\u</code></li><li><code>%u</code></li><li><code>U+</code></li></ul>e.g. <code>\\u03c3\\u03bf\\u03c5</code> becomes <code>σου</code>",
run: Unicode.run_unescape,
input_type: "string",
output_type: "string",
@@ -632,14 +726,14 @@ var OperationConfig = {
args: []
},
"To Quoted Printable": {
- description: "Quoted-Printable, or QP encoding, is an encoding using printable ASCII characters (alphanumeric and the equals sign '=') to transmit 8-bit data over a 7-bit data path or, generally, over a medium which is not 8-bit clean. It is defined as a MIME content transfer encoding for use in e-mail.
QP works by using the equals sign '=' as an escape character. It also limits line length to 76, as some software has limits on line length.",
+ description: "Quoted-Printable, or QP encoding, is an encoding using printable ASCII characters (alphanumeric and the equals sign '=') to transmit 8-bit data over a 7-bit data path or, generally, over a medium which is not 8-bit clean. It is defined as a MIME content transfer encoding for use in e-mail.<br><br>QP works by using the equals sign '=' as an escape character. It also limits line length to 76, as some software has limits on line length.",
run: QuotedPrintable.run_to,
input_type: "byte_array",
output_type: "string",
args: []
},
"From Punycode": {
- description: "Punycode is a way to represent Unicode with the limited character subset of ASCII supported by the Domain Name System.
e.g. mnchen-3ya decodes to münchen",
+ description: "Punycode is a way to represent Unicode with the limited character subset of ASCII supported by the Domain Name System.<br><br>e.g. <code>mnchen-3ya</code> decodes to <code>münchen</code>",
run: Punycode.run_to_unicode,
input_type: "string",
output_type: "string",
@@ -652,7 +746,7 @@ var OperationConfig = {
]
},
"To Punycode": {
- description: "Punycode is a way to represent Unicode with the limited character subset of ASCII supported by the Domain Name System.
e.g. münchen encodes to mnchen-3ya",
+ description: "Punycode is a way to represent Unicode with the limited character subset of ASCII supported by the Domain Name System.<br><br>e.g. <code>münchen</code> encodes to <code>mnchen-3ya</code>",
run: Punycode.run_to_ascii,
input_type: "string",
output_type: "string",
@@ -665,14 +759,14 @@ var OperationConfig = {
]
},
"From Hex Content": {
- description: "Translates hexadecimal bytes in text back to raw bytes.
e.g. foo|3d|bar becomes foo=bar.",
+ description: "Translates hexadecimal bytes in text back to raw bytes.<br><br>e.g. <code>foo|3d|bar</code> becomes <code>foo=bar</code>.",
run: ByteRepr.run_from_hex_content,
input_type: "string",
output_type: "byte_array",
args: []
},
"To Hex Content": {
- description: "Converts special characters in a string to hexadecimal.
e.g. foo=bar becomes foo|3d|bar.",
+ description: "Converts special characters in a string to hexadecimal.<br><br>e.g. <code>foo=bar</code> becomes <code>foo|3d|bar</code>.",
run: ByteRepr.run_to_hex_content,
input_type: "byte_array",
output_type: "string",
@@ -690,7 +784,7 @@ var OperationConfig = {
]
},
"Change IP format": {
- description: "Convert an IP address from one format to another, e.g. 172.20.23.54 to ac141736",
+ description: "Convert an IP address from one format to another, e.g. <code>172.20.23.54</code> to <code>ac141736</code>",
run: IP.run_change_ip_format,
input_type: "string",
output_type: "string",
@@ -708,7 +802,7 @@ var OperationConfig = {
]
},
"Parse IP range": {
- description: "Given a CIDR range (e.g. 10.0.0.0/24) or a hyphenated range (e.g. 10.0.0.0 - 10.0.1.0), this operation provides network information and enumerates all IP addresses in the range.
IPv6 is supported but will not be enumerated.",
+ description: "Given a CIDR range (e.g. <code>10.0.0.0/24</code>) or a hyphenated range (e.g. <code>10.0.0.0 - 10.0.1.0</code>), this operation provides network information and enumerates all IP addresses in the range.<br><br>IPv6 is supported but will not be enumerated.",
run: IP.run_parse_ip_range,
input_type: "string",
output_type: "string",
@@ -754,14 +848,14 @@ var OperationConfig = {
]
},
"Parse IPv6 address": {
- description: "Displays the longhand and shorthand versions of a valid IPv6 address.
Recognises all reserved ranges and parses encapsulated or tunnelled addresses including Teredo and 6to4.",
+ description: "Displays the longhand and shorthand versions of a valid IPv6 address.<br><br>Recognises all reserved ranges and parses encapsulated or tunnelled addresses including Teredo and 6to4.",
run: IP.run_parse_ipv6,
input_type: "string",
output_type: "string",
args: []
},
"Text encoding": {
- description: "Translates the data between different character encodings.
Supported charsets are:
UTF8
UTF16
UTF16LE (little-endian)
UTF16BE (big-endian)
Hex
Base64
Latin1 (ISO-8859-1)
Windows-1251
",
+ description: "Translates the data between different character encodings.<br><br>Supported charsets are:<ul><li>UTF8</li><li>UTF16</li><li>UTF16LE (little-endian)</li><li>UTF16BE (big-endian)</li><li>Hex</li><li>Base64</li><li>Latin1 (ISO-8859-1)</li><li>Windows-1251</li></ul>",
run: CharEnc.run,
input_type: "string",
output_type: "string",
@@ -779,7 +873,7 @@ var OperationConfig = {
]
},
"AES Decrypt": {
- description: "To successfully decrypt AES, you need either:
The passphrase
Or the key and IV
The IV should be the first 16 bytes of encrypted material.",
+ description: "To successfully decrypt AES, you need either:<ul><li>The passphrase</li><li>Or the key and IV</li></ul>The IV should be the first 16 bytes of encrypted material.",
run: Cipher.run_aes_dec,
input_type: "string",
output_type: "string",
@@ -826,7 +920,7 @@ var OperationConfig = {
]
},
"AES Encrypt": {
- description: "Input: Either enter a passphrase (which will be used to derive a key using the OpenSSL KDF) or both the key and IV.
Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.
AES-128, AES-192, and AES-256 are supported. The variant will be chosen based on the size of the key passed in. If a passphrase is used, a 256-bit key will be generated.",
+ description: "Input: Either enter a passphrase (which will be used to derive a key using the OpenSSL KDF) or both the key and IV.<br><br>Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br>AES-128, AES-192, and AES-256 are supported. The variant will be chosen based on the size of the key passed in. If a passphrase is used, a 256-bit key will be generated.",
run: Cipher.run_aes_enc,
input_type: "string",
output_type: "string",
@@ -873,7 +967,7 @@ var OperationConfig = {
]
},
"DES Decrypt": {
- description: "To successfully decrypt DES, you need either:
The passphrase
Or the key and IV
The IV should be the first 8 bytes of encrypted material.",
+ description: "To successfully decrypt DES, you need either:<ul><li>The passphrase</li><li>Or the key and IV</li></ul>The IV should be the first 8 bytes of encrypted material.",
run: Cipher.run_des_dec,
input_type: "string",
output_type: "string",
@@ -920,7 +1014,7 @@ var OperationConfig = {
]
},
"DES Encrypt": {
- description: "Input: Either enter a passphrase (which will be used to derive a key using the OpenSSL KDF) or both the key and IV.
DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.",
+ description: "Input: Either enter a passphrase (which will be used to derive a key using the OpenSSL KDF) or both the key and IV.<br><br>DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.",
run: Cipher.run_des_enc,
input_type: "string",
output_type: "string",
@@ -967,7 +1061,7 @@ var OperationConfig = {
]
},
"Triple DES Decrypt": {
- description: "To successfully decrypt Triple DES, you need either:
The passphrase
Or the key and IV
The IV should be the first 8 bytes of encrypted material.",
+ description: "To successfully decrypt Triple DES, you need either:<ul><li>The passphrase</li><li>Or the key and IV</li></ul>The IV should be the first 8 bytes of encrypted material.",
run: Cipher.run_triple_des_dec,
input_type: "string",
output_type: "string",
@@ -1014,7 +1108,7 @@ var OperationConfig = {
]
},
"Triple DES Encrypt": {
- description: "Input: Either enter a passphrase (which will be used to derive a key using the OpenSSL KDF) or both the key and IV.
Triple DES applies DES three times to each block to increase key size.",
+ description: "Input: Either enter a passphrase (which will be used to derive a key using the OpenSSL KDF) or both the key and IV.<br><br>Triple DES applies DES three times to each block to increase key size.",
run: Cipher.run_triple_des_enc,
input_type: "string",
output_type: "string",
@@ -1109,7 +1203,7 @@ var OperationConfig = {
]
},
"Rabbit Decrypt": {
- description: "To successfully decrypt Rabbit, you need either:
The passphrase
Or the key and IV (This is currently broken. You need the key and salt at the moment.)
The IV should be the first 8 bytes of encrypted material.",
+ description: "To successfully decrypt Rabbit, you need either:<ul><li>The passphrase</li><li>Or the key and IV (This is currently broken. You need the key and salt at the moment.)</li></ul>The IV should be the first 8 bytes of encrypted material.",
run: Cipher.run_rabbit_dec,
input_type: "string",
output_type: "string",
@@ -1156,7 +1250,7 @@ var OperationConfig = {
]
},
"Rabbit Encrypt": {
- description: "Input: Either enter a passphrase (which will be used to derive a key using the OpenSSL KDF) or both the key and IV.
Rabbit is a high-performance stream cipher and a finalist in the eSTREAM Portfolio. It is one of the four designs selected after a 3 1/2 year process where 22 designs were evaluated.",
+ description: "Input: Either enter a passphrase (which will be used to derive a key using the OpenSSL KDF) or both the key and IV.<br><br>Rabbit is a high-performance stream cipher and a finalist in the eSTREAM Portfolio. It is one of the four designs selected after a 3 1/2 year process where 22 designs were evaluated.",
run: Cipher.run_rabbit_enc,
input_type: "string",
output_type: "string",
@@ -1260,7 +1354,7 @@ var OperationConfig = {
]
},
"Derive PBKDF2 key": {
- description: "PBKDF2 is a password-based key derivation function. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can't be used directly as a cryptographic key, some processing is required.
A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack.
Enter your passphrase as the input and then set the relevant options to generate a key.",
+ description: "PBKDF2 is a password-based key derivation function. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can't be used directly as a cryptographic key, some processing is required.<br><br>A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack.<br><br>Enter your passphrase as the input and then set the relevant options to generate a key.",
run: Cipher.run_pbkdf2,
input_type: "string",
output_type: "string",
@@ -1293,7 +1387,7 @@ var OperationConfig = {
]
},
"Derive EVP key": {
- description: "EVP is a password-based key derivation function used extensively in OpenSSL. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can't be used directly as a cryptographic key, some processing is required.
A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack.
Enter your passphrase as the input and then set the relevant options to generate a key.",
+ description: "EVP is a password-based key derivation function used extensively in OpenSSL. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can't be used directly as a cryptographic key, some processing is required.<br><br>A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack.<br><br>Enter your passphrase as the input and then set the relevant options to generate a key.",
run: Cipher.run_evpkdf,
input_type: "string",
output_type: "string",
@@ -1405,7 +1499,7 @@ var OperationConfig = {
args: []
},
"Format MAC addresses": {
- description: "Displays given MAC addresses in multiple different formats.
Expects addresses in a list separated by newlines, spaces or commas.
WARNING: There are no validity checks.",
+ description: "Displays given MAC addresses in multiple different formats.<br><br>Expects addresses in a list separated by newlines, spaces or commas.<br><br>WARNING: There are no validity checks.",
run: MAC.run_format,
input_type: "string",
output_type: "string",
@@ -1451,7 +1545,7 @@ var OperationConfig = {
]
},
"Remove whitespace": {
- description: "Optionally removes all spaces, carriage returns, line feeds, tabs and form feeds from the input data.
This operation also supports the removal of full stops which are sometimes used to represent non-printable bytes in ASCII output.",
+ description: "Optionally removes all spaces, carriage returns, line feeds, tabs and form feeds from the input data.<br><br>This operation also supports the removal of full stops which are sometimes used to represent non-printable bytes in ASCII output.",
run: Tidy.run_remove_whitespace,
input_type: "string",
output_type: "string",
@@ -1489,7 +1583,7 @@ var OperationConfig = {
]
},
"Remove null bytes": {
- description: "Removes all null bytes (0x00) from the input.",
+ description: "Removes all null bytes (<code>0x00</code>) from the input.",
run: Tidy.run_remove_nulls,
input_type: "byte_array",
output_type: "byte_array",
@@ -1578,7 +1672,7 @@ var OperationConfig = {
]
},
"Sort": {
- description: "Alphabetically sorts strings separated by the specified delimiter.
The IP address option supports IPv4 only.",
+ description: "Alphabetically sorts strings separated by the specified delimiter.<br><br>The IP address option supports IPv4 only.",
run: SeqUtils.run_sort,
input_type: "string",
output_type: "string",
@@ -1642,7 +1736,7 @@ var OperationConfig = {
args: []
},
"Find / Replace": {
- description: "Replaces all occurrences of the first string with the second.
The three match options are only relevant to regex search strings.",
+ description: "Replaces all occurrences of the first string with the second.<br><br>The three match options are only relevant to regex search strings.",
run: StrUtils.run_find_replace,
manual_bake: true,
input_type: "string",
@@ -1738,7 +1832,7 @@ var OperationConfig = {
]
},
"Extract IP addresses": {
- description: "Extracts all IPv4 and IPv6 addresses.
Warning: Given a string 710.65.0.456, this will match 10.65.0.45 so always check the original input!",
+ description: "Extracts all IPv4 and IPv6 addresses.<br><br>Warning: Given a string <code>710.65.0.456</code>, this will match <code>10.65.0.45</code> so always check the original input!",
run: Extract.run_ip,
input_type: "string",
output_type: "string",
@@ -1805,7 +1899,7 @@ var OperationConfig = {
]
},
"Extract domains": {
- description: "Extracts domain names with common Top-Level Domains (TLDs). Note that this will not include paths. Use Extract URLs to find entire URLs.",
+ description: "Extracts domain names with common Top-Level Domains (TLDs).<br>Note that this will not include paths. Use <strong>Extract URLs</strong> to find entire URLs.",
run: Extract.run_domains,
input_type: "string",
output_type: "string",
@@ -1818,7 +1912,7 @@ var OperationConfig = {
]
},
"Extract file paths": {
- description: "Extracts anything that looks like a Windows or UNIX file path.
Note that if UNIX is selected, there will likely be a lot of false positives.",
+ description: "Extracts anything that looks like a Windows or UNIX file path.<br><br>Note that if UNIX is selected, there will likely be a lot of false positives.",
run: Extract.run_file_paths,
input_type: "string",
output_type: "string",
@@ -1841,7 +1935,7 @@ var OperationConfig = {
]
},
"Extract dates": {
- description: "Extracts dates in the following formats
yyyy-mm-dd
dd/mm/yyyy
mm/dd/yyyy
Dividers can be any of /, -, . or space",
+ description: "Extracts dates in the following formats<ul><li><code>yyyy-mm-dd</code></li><li><code>dd/mm/yyyy</code></li><li><code>mm/dd/yyyy</code></li></ul>Dividers can be any of /, -, . or space",
run: Extract.run_dates,
input_type: "string",
output_type: "string",
@@ -1894,7 +1988,7 @@ var OperationConfig = {
]
},
"From UNIX Timestamp": {
- description: "Converts a UNIX timestamp to a datetime string.
e.g. 978346800 becomes Mon 1 January 2001 11:00:00 UTC",
+ description: "Converts a UNIX timestamp to a datetime string.<br><br>e.g. <code>978346800</code> becomes <code>Mon 1 January 2001 11:00:00 UTC</code>",
run: DateTime.run_from_unix_timestamp,
input_type: "number",
output_type: "string",
@@ -1907,7 +2001,7 @@ var OperationConfig = {
]
},
"To UNIX Timestamp": {
- description: "Parses a datetime string and returns the corresponding UNIX timestamp.
e.g. Mon 1 January 2001 11:00:00 UTC becomes 978346800",
+ description: "Parses a datetime string and returns the corresponding UNIX timestamp.<br><br>e.g. <code>Mon 1 January 2001 11:00:00 UTC</code> becomes <code>978346800</code>",
run: DateTime.run_to_unix_timestamp,
input_type: "string",
output_type: "number",
@@ -1920,7 +2014,7 @@ var OperationConfig = {
]
},
"Translate DateTime Format": {
- description: "Parses a datetime string in one format and re-writes it in another.
Run with no input to see the relevant format string examples.",
+ description: "Parses a datetime string in one format and re-writes it in another.<br><br>Run with no input to see the relevant format string examples.",
run: DateTime.run_translate_format,
input_type: "string",
output_type: "html",
@@ -1954,7 +2048,7 @@ var OperationConfig = {
]
},
"Parse DateTime": {
- description: "Parses a DateTime string in your specified format and displays it in whichever timezone you choose with the following information:
Date
Time
Period (AM/PM)
Timezone
UTC offset
Daylight Saving Time
Leap year
Days in this month
Day of year
Week number
Quarter
Run with no input to see format string examples if required.",
+ description: "Parses a DateTime string in your specified format and displays it in whichever timezone you choose with the following information:<ul><li>Date</li><li>Time</li><li>Period (AM/PM)</li><li>Timezone</li><li>UTC offset</li><li>Daylight Saving Time</li><li>Leap year</li><li>Days in this month</li><li>Day of year</li><li>Week number</li><li>Quarter</li></ul>Run with no input to see format string examples if required.",
run: DateTime.run_parse,
input_type: "string",
output_type: "html",
@@ -2195,7 +2289,7 @@ var OperationConfig = {
args: []
},
"Zip": {
- description: "Compresses data using the PKZIP algorithm with the given filename.
No support for multiple files at this time.",
+ description: "Compresses data using the PKZIP algorithm with the given filename.<br><br>No support for multiple files at this time.",
run: Compress.run_pkzip,
input_type: "byte_array",
output_type: "byte_array",
@@ -2258,7 +2352,7 @@ var OperationConfig = {
args: []
},
"Generic Code Beautify": {
- description: "Attempts to pretty print C-style languages such as C, C++, C#, Java, PHP, JavaScript etc.
This will not do a perfect job, and the resulting code may not work any more. This operation is designed purely to make obfuscated or minified code more easy to read and understand.
Things which will not work properly:
For loop formatting
Do-While loop formatting
Switch/Case indentation
Certain bit shift operators
",
+ description: "Attempts to pretty print C-style languages such as C, C++, C#, Java, PHP, JavaScript etc.<br><br>This will not do a perfect job, and the resulting code may not work any more. This operation is designed purely to make obfuscated or minified code more easy to read and understand.<br><br>Things which will not work properly:<ul><li>For loop formatting</li><li>Do-While loop formatting</li><li>Switch/Case indentation</li><li>Certain bit shift operators</li></ul>",
run: Code.run_generic_beautify,
input_type: "string",
output_type: "string",
@@ -2432,14 +2526,14 @@ var OperationConfig = {
args: []
},
"MD5": {
- description: "MD5 (Message-Digest 5) is a widely used hash function. It has been used in a variety of security applications and is also commonly used to check the integrity of files.
However, MD5 is not collision resistant and it isn't suitable for applications like SSL/TLS certificates or digital signatures that rely on this property.",
+ description: "MD5 (Message-Digest 5) is a widely used hash function. It has been used in a variety of security applications and is also commonly used to check the integrity of files.<br><br>However, MD5 is not collision resistant and it isn't suitable for applications like SSL/TLS certificates or digital signatures that rely on this property.",
run: Hash.run_md5,
input_type: "string",
output_type: "string",
args: []
},
"SHA1": {
- description: "The SHA (Secure Hash Algorithm) hash functions were designed by the NSA. SHA-1 is the most established of the existing SHA hash functions and it is used in a variety of security applications and protocols.
However, SHA-1's collision resistance has been weakening as new attacks are discovered or improved.",
+ description: "The SHA (Secure Hash Algorithm) hash functions were designed by the NSA. SHA-1 is the most established of the existing SHA hash functions and it is used in a variety of security applications and protocols.<br><br>However, SHA-1's collision resistance has been weakening as new attacks are discovered or improved.",
run: Hash.run_sha1,
input_type: "string",
output_type: "string",
@@ -2487,7 +2581,7 @@ var OperationConfig = {
]
},
"RIPEMD-160": {
- description: "RIPEMD (RACE Integrity Primitives Evaluation Message Digest) is a family of cryptographic hash functions developed in Leuven, Belgium, by Hans Dobbertin, Antoon Bosselaers and Bart Preneel at the COSIC research group at the Katholieke Universiteit Leuven, and first published in 1996.
RIPEMD was based upon the design principles used in MD4, and is similar in performance to the more popular SHA-1.
RIPEMD-160 is an improved, 160-bit version of the original RIPEMD, and the most common version in the family.",
+ description: "RIPEMD (RACE Integrity Primitives Evaluation Message Digest) is a family of cryptographic hash functions developed in Leuven, Belgium, by Hans Dobbertin, Antoon Bosselaers and Bart Preneel at the COSIC research group at the Katholieke Universiteit Leuven, and first published in 1996.<br><br>RIPEMD was based upon the design principles used in MD4, and is similar in performance to the more popular SHA-1.<br><br>RIPEMD-160 is an improved, 160-bit version of the original RIPEMD, and the most common version in the family.",
run: Hash.run_ripemd160,
input_type: "string",
output_type: "string",
@@ -2512,21 +2606,21 @@ var OperationConfig = {
]
},
"Fletcher-16 Checksum": {
- description: "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.
The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.",
+ description: "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.",
run: Checksum.run_fletcher16,
input_type: "byte_array",
output_type: "string",
args: []
},
"Adler-32 Checksum": {
- description: "Adler-32 is a checksum algorithm which was invented by Mark Adler in 1995, and is a modification of the Fletcher checksum. Compared to a cyclic redundancy check of the same length, it trades reliability for speed (preferring the latter).
Adler-32 is more reliable than Fletcher-16, and slightly less reliable than Fletcher-32.",
+ description: "Adler-32 is a checksum algorithm which was invented by Mark Adler in 1995, and is a modification of the Fletcher checksum. Compared to a cyclic redundancy check of the same length, it trades reliability for speed (preferring the latter).<br><br>Adler-32 is more reliable than Fletcher-16, and slightly less reliable than Fletcher-32.",
run: Checksum.run_adler32,
input_type: "byte_array",
output_type: "string",
args: []
},
"CRC-32 Checksum": {
- description: "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.
The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.",
+ description: "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.",
run: Checksum.run_crc32,
input_type: "byte_array",
output_type: "string",
@@ -2573,7 +2667,7 @@ var OperationConfig = {
args: []
},
"Parse X.509 certificate": {
- description: "X.509 is an ITU-T standard for a public key infrastructure (PKI) and Privilege Management Infrastructure (PMI). It is commonly involved with SSL/TLS security.
This operation displays the contents of a certificate in a human readable format, similar to the openssl command line tool.",
+ description: "X.509 is an ITU-T standard for a public key infrastructure (PKI) and Privilege Management Infrastructure (PMI). It is commonly involved with SSL/TLS security.<br><br>This operation displays the contents of a certificate in a human readable format, similar to the openssl command line tool.",
run: PublicKey.run_parse_x509,
input_type: "string",
output_type: "string",
@@ -2620,7 +2714,7 @@ var OperationConfig = {
args: []
},
"Parse ASN.1 hex string": {
- description: "Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking.
This operation parses arbitrary ASN.1 data and presents the resulting tree.",
+ description: "Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking.<br><br>This operation parses arbitrary ASN.1 data and presents the resulting tree.",
run: PublicKey.run_parse_asn1_hex_string,
input_type: "string",
output_type: "string",
@@ -2638,14 +2732,14 @@ var OperationConfig = {
]
},
"Detect File Type": {
- description: "Attempts to guess the MIME (Multipurpose Internet Mail Extensions) type of the data based on 'magic bytes'.
Currently supports the following file types: 7z, amr, avi, bmp, bz2, class, cr2, crx, dex, dmg, doc, elf, eot, epub, exe, flac, flv, gif, gz, ico, iso, jpg, jxr, m4a, m4v, mid, mkv, mov, mp3, mp4, mpg, ogg, otf, pdf, png, ppt, ps, psd, rar, rtf, sqlite, swf, tar, tar.z, tif, ttf, utf8, vmdk, wav, webm, webp, wmv, woff, woff2, xls, xz, zip.",
+ description: "Attempts to guess the MIME (Multipurpose Internet Mail Extensions) type of the data based on 'magic bytes'.<br><br>Currently supports the following file types: 7z, amr, avi, bmp, bz2, class, cr2, crx, dex, dmg, doc, elf, eot, epub, exe, flac, flv, gif, gz, ico, iso, jpg, jxr, m4a, m4v, mid, mkv, mov, mp3, mp4, mpg, ogg, otf, pdf, png, ppt, ps, psd, rar, rtf, sqlite, swf, tar, tar.z, tif, ttf, utf8, vmdk, wav, webm, webp, wmv, woff, woff2, xls, xz, zip.",
run: FileType.run_detect,
input_type: "byte_array",
output_type: "string",
args: []
},
"Scan for Embedded Files": {
- description: "Scans the data for potential embedded files by looking for magic bytes at all offsets. This operation is prone to false positives.
WARNING: Files over about 100KB in size will take a VERY long time to process.",
+ description: "Scans the data for potential embedded files by looking for magic bytes at all offsets. This operation is prone to false positives.<br><br>WARNING: Files over about 100KB in size will take a VERY long time to process.",
run: FileType.run_scan_for_embedded_files,
input_type: "byte_array",
output_type: "string",
@@ -2658,7 +2752,7 @@ var OperationConfig = {
]
},
"Expand alphabet range": {
- description: "Expand an alphabet range string into a list of the characters in that range.
e.g. a-z becomes abcdefghijklmnopqrstuvwxyz.",
+ description: "Expand an alphabet range string into a list of the characters in that range.<br><br>e.g. <code>a-z</code> becomes <code>abcdefghijklmnopqrstuvwxyz</code>.",
run: SeqUtils.run_expand_alph_range,
input_type: "string",
output_type: "string",
@@ -2704,7 +2798,7 @@ var OperationConfig = {
]
},
"Parse UNIX file permissions": {
- description: "Given a UNIX/Linux file permission string in octal or textual format, this operation explains which permissions are granted to which user groups.
Input should be in either octal (e.g. 755) or textual (e.g. drwxr-xr-x) format.",
+ description: "Given a UNIX/Linux file permission string in octal or textual format, this operation explains which permissions are granted to which user groups.<br><br>Input should be in either octal (e.g. <code>755</code>) or textual (e.g. <code>drwxr-xr-x</code>) format.",
run: OS.run_parse_unix_perms,
input_type: "string",
output_type: "string",
@@ -2756,7 +2850,7 @@ var OperationConfig = {
]
},
"Parse escaped string": {
- description: "Replaces escaped characters with the bytes they represent.
e.g.Hello\\nWorld becomes Hello World",
+ description: "Replaces escaped characters with the bytes they represent.<br><br>e.g.<code>Hello\\nWorld</code> becomes <code>Hello<br>World</code>",
run: StrUtils.run_parse_escaped_string,
input_type: "string",
output_type: "string",
@@ -2770,17 +2864,153 @@ var OperationConfig = {
args: []
},
"Parse colour code": {
- description: "Converts a colour code in a standard format to other standard formats and displays the colour itself.
Example inputs
#d9edf7
rgba(217,237,247,1)
hsla(200,65%,91%,1)
cmyk(0.12, 0.04, 0.00, 0.03)
",
+ description: "Converts a colour code in a standard format to other standard formats and displays the colour itself.<br><br><strong>Example inputs</strong><ul><li><code>#d9edf7</code></li><li><code>rgba(217,237,247,1)</code></li><li><code>hsla(200,65%,91%,1)</code></li><li><code>cmyk(0.12, 0.04, 0.00, 0.03)</code></li></ul>",
run: HTML.run_parse_colour_code,
input_type: "string",
output_type: "html",
args: []
},
"Generate UUID": {
- description: "Generates an RFC 4122 version 4 compliant Universally Unique Identifier (UUID), also known as a Globally Unique Identifier (GUID).
A version 4 UUID relies on random numbers, in this case generated using window.crypto if available and falling back to Math.random if not.",
+ description: "Generates an RFC 4122 version 4 compliant Universally Unique Identifier (UUID), also known as a Globally Unique Identifier (GUID).<br><br>A version 4 UUID relies on random numbers, in this case generated using <code>window.crypto</code> if available and falling back to <code>Math.random</code> if not.",
run: UUID.run_generate_v4,
input_type: "string",
output_type: "string",
args: []
}
-};
\ No newline at end of file
+};
/**
+ * The main controller for CyberChef.
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ *
+ * @class
+ */
+var Chef = function() {
+ this.dish = new Dish();
+};
+
+
+/**
+ * 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 {Object} options - The options object storing various user choices
+ * @param {boolean} options.attemp_highlight - 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
+ *
+ * @returns {Object} response
+ * @returns {string} response.result - The output of the recipe
+ * @returns {string} response.type - The data type of the result
+ * @returns {number} response.progress - The position that we have got to in the recipe
+ * @returns {number} response.options - The app options object (which may have been changed)
+ * @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;
+
+ // Reset attempt_highlight flag
+ if (options.hasOwnProperty("attempt_highlight")) {
+ options.attempt_highlight = true;
+ }
+
+ if (contains_fc) options.attempt_highlight = false;
+
+ // Clean up progress
+ if (progress >= recipe_config.length) {
+ progress = 0;
+ }
+
+ if (step) {
+ // Unset breakpoint on this step
+ recipe.set_breakpoint(progress, false);
+ // Set breakpoint on next step
+ recipe.set_breakpoint(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);
+ progress = 0;
+ }
+
+ // If starting from scratch, load data
+ if (progress === 0) {
+ this.dish.set(input_text, Dish.STRING);
+ }
+
+ try {
+ progress = recipe.execute(this.dish, progress);
+ } catch (err) {
+ // We can't throw the error from here as we will return in the finally block and ignore it
+ // so we return the error in the result instead.
+ error = err;
+ progress = err.progress;
+ } finally {
+ return {
+ result: this.dish.type == Dish.HTML ?
+ this.dish.get(Dish.HTML) :
+ this.dish.get(Dish.STRING),
+ type: Dish.enum_lookup(this.dish.type),
+ progress: progress,
+ options: options,
+ duration: new Date().getTime() - start_time,
+ error: error
+ };
+ }
+};
+
+
+/**
+ * When a browser tab is unfocused and the browser has to run lots of dynamic content in other tabs,
+ * it swaps out the memory for that tab. If the CyberChef tab has been unfocused for more than a
+ * minute, we run a silent bake which will force the browser to load and cache all the relevant
+ * JavaScript code needed to do a real bake.
+ *
+ * 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.
+ *
+ * The output will not be modified (hence "silent" bake).
+ *
+ * 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
+ * @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);
+
+ try {
+ recipe.execute(dish);
+ } catch(err) {
+ // Suppress all errors
+ }
+ return new Date().getTime() - start_time;
+};
+
/**
+ * The data being operated on by each operation.
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ *
+ * @class
+ * @param {byte_array|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) {
+ this.value = value || typeof value == "string" ? value : null;
+ this.type = type || Dish.BYTE_ARRAY;
+};
+
+
+/**
+ * Dish data type enum for byte arrays.
+ * @readonly
+ * @enum
+ */
+Dish.BYTE_ARRAY = 0;
+/**
+ * Dish data type enum for strings.
+ * @readonly
+ * @enum
+ */
+Dish.STRING = 1;
+/**
+ * Dish data type enum for numbers.
+ * @readonly
+ * @enum
+ */
+Dish.NUMBER = 2;
+/**
+ * Dish data type enum for HTML.
+ * @readonly
+ * @enum
+ */
+Dish.HTML = 3;
+
+
+/**
+ * Returns the data type enum for the given type string.
+ *
+ * @static
+ * @param {string} type_str - 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":
+ case "Byte array":
+ return Dish.BYTE_ARRAY;
+ case "string":
+ case "String":
+ return Dish.STRING;
+ case "number":
+ case "Number":
+ return Dish.NUMBER;
+ case "html":
+ case "HTML":
+ return Dish.HTML;
+ default:
+ throw "Invalid data type string. No matching enum.";
+ }
+};
+
+
+/**
+ * Returns the data type string for the given type enum.
+ *
+ * @static
+ * @param {string} type_enum - The enum value of the data type.
+ * @returns {number} The data type as a string.
+ */
+Dish.enum_lookup = function(type_enum) {
+ switch (type_enum) {
+ case Dish.BYTE_ARRAY:
+ return "byte_array";
+ case Dish.STRING:
+ return "string";
+ case Dish.NUMBER:
+ return "number";
+ case Dish.HTML:
+ return "html";
+ default:
+ throw "Invalid data type enum. No matching type.";
+ }
+};
+
+
+/**
+ * Sets the data value and type and then validates them.
+ *
+ * @param {byte_array|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) {
+ this.value = value;
+ this.type = type;
+
+ if (!this.valid()) {
+ var sample = Utils.truncate(JSON.stringify(this.value), 13);
+ throw "Data is not a valid " + Dish.enum_lookup(type) + ": " + sample;
+ }
+};
+
+
+/**
+ * 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.
+ */
+Dish.prototype.get = function(type) {
+ if (this.type != type) {
+ this.translate(type);
+ }
+ return this.value;
+};
+
+
+/**
+ * Translates the data to the given type format.
+ *
+ * @param {number} to_type - The data type of value, see Dish enums.
+ */
+Dish.prototype.translate = function(to_type) {
+ // Convert data to intermediate byte_array type
+ switch (this.type) {
+ case Dish.STRING:
+ this.value = this.value ? Utils.str_to_byte_array(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.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.type = Dish.BYTE_ARRAY;
+ break;
+ default:
+ break;
+ }
+
+ // Convert from byte_array to to_type
+ switch (to_type) {
+ case Dish.STRING:
+ case Dish.HTML:
+ this.value = this.value ? Utils.byte_array_to_utf8(this.value) : "";
+ this.type = Dish.STRING;
+ break;
+ case Dish.NUMBER:
+ this.value = this.value ? parseFloat(Utils.byte_array_to_utf8(this.value)) : 0;
+ this.type = Dish.NUMBER;
+ break;
+ default:
+ break;
+ }
+};
+
+
+/**
+ * Validates that the value is the type that has been specified.
+ * May have to disable parts of BYTE_ARRAY validation if it effects performance.
+ *
+ * @returns {boolean} Whether the data is valid or not.
+*/
+Dish.prototype.valid = function() {
+ switch (this.type) {
+ case Dish.BYTE_ARRAY:
+ if (!(this.value instanceof Array)) {
+ return false;
+ }
+
+ // Check that every value is a number between 0 - 255
+ for (var i = 0; i < this.value.length; i++) {
+ if (typeof this.value[i] != "number" ||
+ this.value[i] < 0 ||
+ this.value[i] > 255) {
+ return false;
+ }
+ }
+ return true;
+ case Dish.STRING:
+ case Dish.HTML:
+ if (typeof this.value == "string") {
+ return true;
+ }
+ return false;
+ case Dish.NUMBER:
+ if (typeof this.value == "number") {
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+};
+
/**
+ * Flow Control operations.
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ *
+ * @namespace
+ */
+var FlowControl = {
+
+ /**
+ * @constant
+ * @default
+ */
+ FORK_DELIM: "\\n",
+ /**
+ * @constant
+ * @default
+ */
+ MERGE_DELIM: "\\n",
+
+ /**
+ * Fork operation.
+ *
+ * @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.
+ * @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 = [];
+
+ if (input)
+ inputs = input.split(split_delim);
+
+ // Create sub_op_list 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()) {
+ break;
+ } else {
+ sub_op_list.push(op_list[i]);
+ }
+ }
+
+ var recipe = new Recipe(),
+ output = "",
+ progress;
+
+ recipe.add_operations(sub_op_list);
+
+ // 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;
+ }
+
+ state.dish.set(output, output_type);
+ state.progress += progress;
+ return state;
+ },
+
+
+ /**
+ * Merge operation.
+ *
+ * @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.
+ * @returns {Object} The updated state of the recipe.
+ */
+ run_merge: function(state) {
+ // No need to actually do anything here. The fork operation will
+ // merge when it sees this operation.
+ return state;
+ },
+
+
+ /**
+ * @constant
+ * @default
+ */
+ JUMP_NUM: 0,
+ /**
+ * @constant
+ * @default
+ */
+ MAX_JUMPS: 10,
+
+ /**
+ * Jump operation.
+ *
+ * @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.
+ * @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];
+
+ if (state.num_jumps >= max_jumps) {
+ throw "Reached maximum jumps, sorry!";
+ }
+
+ state.progress += jump_num;
+ state.num_jumps++;
+ return state;
+ },
+
+
+ /**
+ * Conditional Jump operation.
+ *
+ * @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.
+ * @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];
+
+ if (state.num_jumps >= max_jumps) {
+ throw "Reached maximum jumps, sorry!";
+ }
+
+ if (regex_str !== "" && dish.get(Dish.STRING).search(regex_str) > -1) {
+ state.progress += jump_num;
+ state.num_jumps++;
+ }
+
+ return state;
+ },
+
+
+ /**
+ * Return operation.
+ *
+ * @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.
+ * @returns {Object} The updated state of the recipe.
+ */
+ run_return: function(state) {
+ state.progress = state.op_list.length;
+ return state;
+ },
+
+};
+
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include creating hexdumps, simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, data compression and decompression, calculating hashes and checksums, IPv6 and X.509 parsing, and much more.
+
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years. Every effort has been made to structure the code in a readable and extendable format, however it should be noted that the analyst is not a professional developer and the code has not been peer-reviewed for compliance with a formal specification.
+
Live demo
CyberChef is still under active development. As a result, it shouldn't be considered a finished product. There is still testing and bug fixing to do, new features to be added and additional documentation to write. Please contribute!
+
Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness.
+
A live demo can be found here - have fun! Note: Use Chrome or Firefox, see the Browser Support section below for details.
+
How it works
There are four main areas in CyberChef:
+
+
The input box in the top right, where you can paste, type or drag the data you want to operate on.
+
The output box in the bottom right, where the outcome of the specified processing will be displayed.
+
The operations list on the far left, where you can find all the operations that CyberChef is capable of in categorised lists, or by searching.
+
The recipe area in the middle, where you drag the operations that you want to use and specify arguments and options.
+
+
You can use as many operations as you like in simple or complex ways. Some examples are as follows:
Operations can be dragged in and out of the recipe list, or reorganised.
+
Files can be dragged over the input box to load them directly.
+
+
+
Auto Bake
+
Whenever you modify the input or the recipe, CyberChef will automatically “bake” for you and produce the output immediately.
+
This can be turned off and operated manually if it is affecting performance (if the input is very large, for instance).
+
If any bake takes longer than 200 milliseconds, auto bake will be switched off automatically to prevent further performance issues.
+
+
+
Breakpoints
+
You can set breakpoints on any operation in your recipe to pause execution before running it.
+
You can also step through the recipe one operation at a time to see what the data looks like at each stage.
+
+
+
Save and load recipes
+
If you come up with an awesome recipe that you know you’ll want to use again, just click save and add it to your local storage. It'll be waiting for you next time you visit CyberChef.
+
You can also copy a URL which includes your recipe and input which can be shared with others.
+
+
+
Search
+
If you know the name of the operation you want or a word associated with it, start typing it into the search field and any matching operations will immediately be shown.
You can save the output to a file at any time or load a file by dragging and dropping it into the input field (note that files larger than about 500kb may cause your browser to hang or even crash due to the way that browsers handle large amounts of textual data).
+
+
+
CyberChef is entirely client-side
+
It should be noted that none of your input or recipe configuration is ever sent to the CyberChef web server - all processing is carried out within your browser, on your own computer.
+
Due to this feature, CyberChef can be compiled into a single HTML file. You can download this file and drop it into a virtual machine, share it with other people, or use it independently on your desktop.
+
+
+
+
Browser support
CyberChef works well in modern versions of Google Chrome and Mozilla Firefox.
+
To aid in the efficient development of new features and operations, there has been no attempt to maintain support for any version of Microsoft Internet Explorer.
+
Microsoft Edge is currently unsupported, but if anyone would like to contribute compatibility fixes, they would be appreciated.
+
Contributing
An installation walkthrough, how-to guides for adding new operations, descriptions of the repository structure, available data types and coding conventions can all be found in the project wiki pages.
/* globals app */
/**
* Byte representation operations.
@@ -73,18 +167,18 @@ var ByteRepr = {
padding = 2,
ordinal;
- if (base < 2 || base > 36) {
+ if (base < 2 || base > 36) {
throw "Error: Base argument must be between 2 and 36";
}
- for (var i = 0; i < input.length; i++) {
+ for (var i = 0; i < input.length; i++) {
ordinal = Utils.ord(input[i]);
if (base == 16) {
- if (ordinal < 256) padding = 2;
- else if (ordinal < 65536) padding = 4;
- else if (ordinal < 16777216) padding = 6;
- else if (ordinal < 4294967296) padding = 8;
+ if (ordinal < 256) padding = 2;
+ else if (ordinal < 65536) padding = 4;
+ else if (ordinal < 16777216) padding = 6;
+ else if (ordinal < 4294967296) padding = 8;
else padding = 2;
if (padding > 2) app.options.attempt_highlight = false;
@@ -113,7 +207,7 @@ var ByteRepr = {
bites = input.split(delim),
i = 0;
- if (base < 2 || base > 36) {
+ if (base < 2 || base > 36) {
throw "Error: Base argument must be between 2 and 36";
}
@@ -123,15 +217,15 @@ var ByteRepr = {
// Split into groups of 2 if the whole string is concatenated and
// too long to be a single character
- if (bites.length == 1 && input.length > 17) {
+ if (bites.length == 1 && input.length > 17) {
bites = [];
- for (i = 0; i < input.length; i += 2) {
+ for (i = 0; i < input.length; i += 2) {
bites.push(input.slice(i, i+2));
}
}
var latin1 = "";
- for (i = 0; i < bites.length; i++) {
+ for (i = 0; i < bites.length; i++) {
latin1 += Utils.chr(parseInt(bites[i], base));
}
return Utils.str_to_byte_array(latin1);
@@ -217,7 +311,7 @@ var ByteRepr = {
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++) {
+ for (var i = 0; i < byte_str.length; i++) {
output[i] = parseInt(byte_str[i]);
}
return output;
@@ -236,7 +330,7 @@ var ByteRepr = {
output = "",
padding = 8;
- for (var i = 0; i < input.length; i++) {
+ for (var i = 0; i < input.length; i++) {
output += Utils.pad(input[i].toString(2), padding) + delim;
}
@@ -263,7 +357,7 @@ var ByteRepr = {
var output = [];
var byte_len = 8;
- for (var i = 0; i < input.length; i += byte_len) {
+ for (var i = 0; i < input.length; i += byte_len) {
output.push(parseInt(input.substr(i, byte_len), 2));
}
return output;
@@ -335,9 +429,9 @@ var ByteRepr = {
in_hex = false,
convert_spaces = convert == "Only special chars including spaces",
b;
- for (var i = 0; i < input.length; i++) {
+ 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 ((b == 32 && convert_spaces) || (b < 48 && b != 32) || (b > 57 && b < 65) || (b > 90 && b < 97) || b > 122) {
if (!in_hex) {
output += "|";
in_hex = true;
@@ -368,27 +462,164 @@ var ByteRepr = {
var output = [], m, i = 0;
while (!!(m = regex.exec(input))) {
// Add up to match
- for (; i < m.index;)
+ for (; i < m.index;)
output.push(Utils.ord(input[i++]));
// Add match
var bytes = Utils.from_hex(m[1]);
if (bytes) {
- for (var a = 0; a < bytes.length;)
+ for (var a = 0; a < bytes.length;)
output.push(bytes[a++]);
} else {
// Not valid hex, print as normal
- for (; i < regex.lastIndex;)
+ for (; i < regex.lastIndex;)
output.push(Utils.ord(input[i++]));
}
i = regex.lastIndex;
}
// Add all after final match
- for (; i < input.length;)
+ for (; i < input.length;)
output.push(Utils.ord(input[i++]));
return output;
},
};
+
/* globals X509, KJUR, ASN1HEX, KEYUTIL, BigInteger */
/**
* Public Key operations.
@@ -130,7 +224,7 @@ var PublicKey = {
}
// Format Public Key fields
- for (var i = 0; i < pk_fields.length; i++) {
+ for (var i = 0; i < pk_fields.length; i++) {
pk_str += " " + pk_fields[i].key + ":" +
Utils.pad_left(
pk_fields[i].value + "\n",
@@ -176,11 +270,11 @@ var PublicKey = {
* @returns {string}
*/
run_pem_to_hex: function(input, args) {
- if (input.indexOf("-----BEGIN") < 0) {
+ if (input.indexOf("-----BEGIN") < 0) {
// Add header so that the KEYUTIL function works
input = "-----BEGIN CERTIFICATE-----" + input;
}
- if (input.indexOf("-----END") < 0) {
+ if (input.indexOf("-----END") < 0) {
// Add footer so that the KEYUTIL function works
input = input + "-----END CERTIFICATE-----";
}
@@ -268,7 +362,7 @@ var PublicKey = {
value,
str;
- for (var i = 0; i < fields.length; i++) {
+ for (var i = 0; i < fields.length; i++) {
if (!fields[i].length) continue;
key = fields[i].split("=")[0];
@@ -276,7 +370,7 @@ var PublicKey = {
max_key_len = key.length > max_key_len ? key.length : max_key_len;
}
- for (i = 0; i < fields.length; i++) {
+ for (i = 0; i < fields.length; i++) {
if (!fields[i].length) continue;
key = fields[i].split("=")[0];
@@ -304,7 +398,7 @@ var PublicKey = {
length = length * 3;
var output = "";
- for (var i = 0; i < byte_str.length; i += length) {
+ for (var i = 0; i < byte_str.length; i += length) {
var str = byte_str.slice(i, i + length) + "\n";
if (i === 0) {
output += str;
@@ -346,7 +440,7 @@ var PublicKey = {
X509.hex2dn = function(hDN) {
var s = "";
var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
- for (var i = 0; i < a.length; i++) {
+ for (var i = 0; i < a.length; i++) {
var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
s = s + ",/|" + X509.hex2rdn(hRDN);
}
@@ -1050,4 +1144,140 @@ X509.DN_ATTRHEX = {
'0603550801' : 'X.500-Alg-Encryption',
'060355080101' : 'rsa',
'0603604c0101' : 'DPC'
-};
\ No newline at end of file
+};
/**
+ * Waiter to handle events related to the window object.
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ *
+ * @constructor
+ * @param {HTMLApp} app - The main view object for CyberChef.
+ */
+var WindowWaiter = function(app) {
+ this.app = app;
+};
+
+
+/**
+ * Handler for window resize events.
+ * 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);
+};
+
+
+/**
+ * Handler for window blur events.
+ * 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();
+};
+
+
+/**
+ * Handler for window focus events.
+ *
+ * When a browser tab is unfocused and the browser has to run lots of dynamic content in other
+ * tabs, it swaps out the memory for that tab.
+ * If the CyberChef tab has been unfocused for more than a minute, we run a silent bake which will
+ * force the browser to load and cache all the relevant JavaScript code needed to do a real bake.
+ * 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();
+ }
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/prod/images/breakpoint-16x16.png b/images/breakpoint-16x16.png
similarity index 100%
rename from build/prod/images/breakpoint-16x16.png
rename to images/breakpoint-16x16.png
diff --git a/build/prod/images/bug-16x16.png b/images/bug-16x16.png
similarity index 100%
rename from build/prod/images/bug-16x16.png
rename to images/bug-16x16.png
diff --git a/build/prod/images/clean-16x16.png b/images/clean-16x16.png
similarity index 100%
rename from build/prod/images/clean-16x16.png
rename to images/clean-16x16.png
diff --git a/build/prod/images/code-16x16.png b/images/code-16x16.png
similarity index 100%
rename from build/prod/images/code-16x16.png
rename to images/code-16x16.png
diff --git a/build/prod/images/cook_female-32x32.png b/images/cook_female-32x32.png
similarity index 100%
rename from build/prod/images/cook_female-32x32.png
rename to images/cook_female-32x32.png
diff --git a/build/prod/images/cook_male-32x32.png b/images/cook_male-32x32.png
similarity index 100%
rename from build/prod/images/cook_male-32x32.png
rename to images/cook_male-32x32.png
diff --git a/build/prod/images/cyberchef-128x128.png b/images/cyberchef-128x128.png
similarity index 100%
rename from build/prod/images/cyberchef-128x128.png
rename to images/cyberchef-128x128.png
diff --git a/build/prod/images/cyberchef-16x16.png b/images/cyberchef-16x16.png
similarity index 100%
rename from build/prod/images/cyberchef-16x16.png
rename to images/cyberchef-16x16.png
diff --git a/build/prod/images/cyberchef-256x256.png b/images/cyberchef-256x256.png
similarity index 100%
rename from build/prod/images/cyberchef-256x256.png
rename to images/cyberchef-256x256.png
diff --git a/build/prod/images/cyberchef-32x32.png b/images/cyberchef-32x32.png
similarity index 100%
rename from build/prod/images/cyberchef-32x32.png
rename to images/cyberchef-32x32.png
diff --git a/build/prod/images/cyberchef-512x512.png b/images/cyberchef-512x512.png
similarity index 100%
rename from build/prod/images/cyberchef-512x512.png
rename to images/cyberchef-512x512.png
diff --git a/build/prod/images/cyberchef-64x64.png b/images/cyberchef-64x64.png
similarity index 100%
rename from build/prod/images/cyberchef-64x64.png
rename to images/cyberchef-64x64.png
diff --git a/build/prod/images/disable_deselected-16x16.png b/images/disable_deselected-16x16.png
similarity index 100%
rename from build/prod/images/disable_deselected-16x16.png
rename to images/disable_deselected-16x16.png
diff --git a/build/prod/images/disable_selected-16x16.png b/images/disable_selected-16x16.png
similarity index 100%
rename from build/prod/images/disable_selected-16x16.png
rename to images/disable_selected-16x16.png
diff --git a/build/prod/images/download-24x24.png b/images/download-24x24.png
similarity index 100%
rename from build/prod/images/download-24x24.png
rename to images/download-24x24.png
diff --git a/build/prod/images/erase-16x16.png b/images/erase-16x16.png
similarity index 100%
rename from build/prod/images/erase-16x16.png
rename to images/erase-16x16.png
diff --git a/build/prod/images/favicon.ico b/images/favicon.ico
similarity index 100%
rename from build/prod/images/favicon.ico
rename to images/favicon.ico
diff --git a/build/prod/images/favourite-16x16.png b/images/favourite-16x16.png
similarity index 100%
rename from build/prod/images/favourite-16x16.png
rename to images/favourite-16x16.png
diff --git a/build/prod/images/favourite-24x24.png b/images/favourite-24x24.png
similarity index 100%
rename from build/prod/images/favourite-24x24.png
rename to images/favourite-24x24.png
diff --git a/build/prod/images/help-16x16.png b/images/help-16x16.png
similarity index 100%
rename from build/prod/images/help-16x16.png
rename to images/help-16x16.png
diff --git a/build/prod/images/help-22x22.png b/images/help-22x22.png
similarity index 100%
rename from build/prod/images/help-22x22.png
rename to images/help-22x22.png
diff --git a/build/prod/images/info-16x16.png b/images/info-16x16.png
similarity index 100%
rename from build/prod/images/info-16x16.png
rename to images/info-16x16.png
diff --git a/build/prod/images/layout-16x16.png b/images/layout-16x16.png
similarity index 100%
rename from build/prod/images/layout-16x16.png
rename to images/layout-16x16.png
diff --git a/build/prod/images/mail-16x16.png b/images/mail-16x16.png
similarity index 100%
rename from build/prod/images/mail-16x16.png
rename to images/mail-16x16.png
diff --git a/build/prod/images/open_yellow-16x16.png b/images/open_yellow-16x16.png
similarity index 100%
rename from build/prod/images/open_yellow-16x16.png
rename to images/open_yellow-16x16.png
diff --git a/build/prod/images/open_yellow-24x24.png b/images/open_yellow-24x24.png
similarity index 100%
rename from build/prod/images/open_yellow-24x24.png
rename to images/open_yellow-24x24.png
diff --git a/build/prod/images/recycle-16x16.png b/images/recycle-16x16.png
similarity index 100%
rename from build/prod/images/recycle-16x16.png
rename to images/recycle-16x16.png
diff --git a/build/prod/images/remove-16x16.png b/images/remove-16x16.png
similarity index 100%
rename from build/prod/images/remove-16x16.png
rename to images/remove-16x16.png
diff --git a/build/prod/images/save-16x16.png b/images/save-16x16.png
similarity index 100%
rename from build/prod/images/save-16x16.png
rename to images/save-16x16.png
diff --git a/build/prod/images/save-22x22.png b/images/save-22x22.png
similarity index 100%
rename from build/prod/images/save-22x22.png
rename to images/save-22x22.png
diff --git a/build/prod/images/save_as-16x16.png b/images/save_as-16x16.png
similarity index 100%
rename from build/prod/images/save_as-16x16.png
rename to images/save_as-16x16.png
diff --git a/build/prod/images/settings-22x22.png b/images/settings-22x22.png
similarity index 100%
rename from build/prod/images/settings-22x22.png
rename to images/settings-22x22.png
diff --git a/build/prod/images/speech-16x16.png b/images/speech-16x16.png
similarity index 100%
rename from build/prod/images/speech-16x16.png
rename to images/speech-16x16.png
diff --git a/build/prod/images/stats-16x16.png b/images/stats-16x16.png
similarity index 100%
rename from build/prod/images/stats-16x16.png
rename to images/stats-16x16.png
diff --git a/build/prod/images/step-16x16.png b/images/step-16x16.png
similarity index 100%
rename from build/prod/images/step-16x16.png
rename to images/step-16x16.png
diff --git a/build/prod/images/switch-16x16.png b/images/switch-16x16.png
similarity index 100%
rename from build/prod/images/switch-16x16.png
rename to images/switch-16x16.png
diff --git a/build/prod/images/thumb_down-16x16.png b/images/thumb_down-16x16.png
similarity index 100%
rename from build/prod/images/thumb_down-16x16.png
rename to images/thumb_down-16x16.png
diff --git a/build/prod/images/thumb_up-16x16.png b/images/thumb_up-16x16.png
similarity index 100%
rename from build/prod/images/thumb_up-16x16.png
rename to images/thumb_up-16x16.png
diff --git a/build/prod/images/undo-16x16.png b/images/undo-16x16.png
similarity index 100%
rename from build/prod/images/undo-16x16.png
rename to images/undo-16x16.png
diff --git a/build/prod/index.html b/index.html
similarity index 97%
rename from build/prod/index.html
rename to index.html
index b5050adb..dc92708a 100755
--- a/build/prod/index.html
+++ b/index.html
@@ -18,4 +18,17 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-CyberChef Edit
Yes! Just drag your file over the input box and drop it. The contents of the file will be converted into hexadecimal and the 'From Hex' operation will be added to the beginning of the recipe (if it's not already there). This is so that special characters like carriage returns aren't removed by your browser.
Please note that loading large files is likely to cause a crash. There's not a lot that can be done about this - browsers just aren't very good at handling and displaying large amounts of data.
Maybe you have 10 timestamps that you want to parse or 16 encoded strings that all have the same key.
The 'Fork' operation (found in the 'Flow control' category) splits up the input line by line and runs all subsequent operations on each line separately. Each output is then displayed on a separate line. These delimiters can be changed, so if your inputs are separated by commas, you can change the split delimiter to a comma instead.
A simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.
Why
Digital data comes in all shapes, sizes and formats in the modern world – CyberChef helps to make sense of this data all on one easy-to-use platform.
How
The interface is designed with simplicity at its heart. Complex techniques are now as trivial as drag-and-drop. Simple functions can be combined to build up a "recipe", potentially resulting in complex analysis, which can be shared with other users and used with their input.
For those comfortable writing code, CyberChef is a quick and efficient way to prototype solutions to a problem which can then be scripted once proven to work.
Who
It is expected that CyberChef will be useful for cybersecurity and antivirus companies. It should also appeal to the academic world and any individuals or companies involved in the analysis of digital data, be that software developers, analysts, mathematicians or casual puzzle solvers.
Aim
It is hoped that by releasing CyberChef through GitHub, contributions can be added which can be rolled out into future versions of the tool.
There are around 150 useful operations in CyberChef for anyone working on anything vaguely Internet-related, whether you just want to convert a timestamp to a different format, decompress gzipped data, create a SHA3 hash, or parse an X.509 certificate to find out who issued it.
Yes! Just drag your file over the input box and drop it. The contents of the file will be converted into hexadecimal and the 'From Hex' operation will be added to the beginning of the recipe (if it's not already there). This is so that special characters like carriage returns aren't removed by your browser.
Please note that loading large files is likely to cause a crash. There's not a lot that can be done about this - browsers just aren't very good at handling and displaying large amounts of data.
Maybe you have 10 timestamps that you want to parse or 16 encoded strings that all have the same key.
The 'Fork' operation (found in the 'Flow control' category) splits up the input line by line and runs all subsequent operations on each line separately. Each output is then displayed on a separate line. These delimiters can be changed, so if your inputs are separated by commas, you can change the split delimiter to a comma instead.
A simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.
Why
Digital data comes in all shapes, sizes and formats in the modern world – CyberChef helps to make sense of this data all on one easy-to-use platform.
How
The interface is designed with simplicity at its heart. Complex techniques are now as trivial as drag-and-drop. Simple functions can be combined to build up a "recipe", potentially resulting in complex analysis, which can be shared with other users and used with their input.
For those comfortable writing code, CyberChef is a quick and efficient way to prototype solutions to a problem which can then be scripted once proven to work.
Who
It is expected that CyberChef will be useful for cybersecurity and antivirus companies. It should also appeal to the academic world and any individuals or companies involved in the analysis of digital data, be that software developers, analysts, mathematicians or casual puzzle solvers.
Aim
It is hoped that by releasing CyberChef through GitHub, contributions can be added which can be rolled out into future versions of the tool.
There are around 150 useful operations in CyberChef for anyone working on anything vaguely Internet-related, whether you just want to convert a timestamp to a different format, decompress gzipped data, create a SHA3 hash, or parse an X.509 certificate to find out who issued it.
Yes! Just drag your file over the input box and drop it. The contents of the file will be converted into hexadecimal and the 'From Hex' operation will be added to the beginning of the recipe (if it's not already there). This is so that special characters like carriage returns aren't removed by your browser.
-
Please note that loading large files is likely to cause a crash. There's not a lot that can be done about this - browsers just aren't very good at handling and displaying large amounts of data.
Maybe you have 10 timestamps that you want to parse or 16 encoded strings that all have the same key.
-
The 'Fork' operation (found in the 'Flow control' category) splits up the input line by line and runs all subsequent operations on each line separately. Each output is then displayed on a separate line. These delimiters can be changed, so if your inputs are separated by commas, you can change the split delimiter to a comma instead.
If you're a nerd like me, you might find statistics really fun! Here's some about the CyberChef code base:
-
<%= codebase_stats %>
-
-
-
What
-
A simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.
-
-
Why
-
Digital data comes in all shapes, sizes and formats in the modern world – CyberChef helps to make sense of this data all on one easy-to-use platform.
-
-
How
-
The interface is designed with simplicity at its heart. Complex techniques are now as trivial as drag-and-drop. Simple functions can be combined to build up a "recipe", potentially resulting in complex analysis, which can be shared with other users and used with their input.
-
For those comfortable writing code, CyberChef is a quick and efficient way to prototype solutions to a problem which can then be scripted once proven to work.
-
-
Who
-
It is expected that CyberChef will be useful for cybersecurity and antivirus companies. It should also appeal to the academic world and any individuals or companies involved in the analysis of digital data, be that software developers, analysts, mathematicians or casual puzzle solvers.
-
-
Aim
-
It is hoped that by releasing CyberChef through GitHub, contributions can be added which can be rolled out into future versions of the tool.
-
-
-
There are around 150 useful operations in CyberChef for anyone working on anything vaguely Internet-related, whether you just want to convert a timestamp to a different format, decompress gzipped data, create a SHA3 hash, or parse an X.509 certificate to find out who issued it.
-
It’s the Cyber Swiss Army Knife.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/js/.jshintrc b/src/js/.jshintrc
deleted file mode 100755
index 7dc0b5ac..00000000
--- a/src/js/.jshintrc
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "strict": "implied",
- "multistr": true,
- "browser": true,
- "typed": true,
- "jquery": true,
- "node": true,
- "undef": true,
- "globals": {
- /* core/* */
- "Chef": true,
- "Dish": true,
- "Recipe": true,
- "Ingredient": true,
- "Operation": true,
- "Utils": true,
-
- /* config/* */
- "Categories": true,
- "OperationConfig": true,
-
- /* views/html/* */
- "HTMLApp": true,
- "HTMLCategory": true,
- "HTMLOperation": true,
- "HTMLIngredient": true,
- "Manager": true,
- "ControlsWaiter": true,
- "HighlighterWaiter": true,
- "InputWaiter": true,
- "OperationsWaiter": true,
- "OptionsWaiter": true,
- "OutputWaiter": true,
- "RecipeWaiter": true,
- "SeasonalWaiter": true,
- "WindowWaiter": true
- }
-}
diff --git a/src/js/config/Categories.js b/src/js/config/Categories.js
deleted file mode 100755
index 02c2b1f5..00000000
--- a/src/js/config/Categories.js
+++ /dev/null
@@ -1,266 +0,0 @@
-/**
- * Type definition for a CatConf.
- *
- * @typedef {Object} CatConf
- * @property {string} name - The display name for the category
- * @property {string[]} ops - A list of the operations to be included in this category
- */
-
-
-/**
- * Categories of operations.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @constant
- * @type {CatConf[]}
- */
-var Categories = [
- {
- name: "Favourites",
- ops: []
- },
- {
- name: "Data format",
- ops: [
- "To Hexdump",
- "From Hexdump",
- "To Hex",
- "From Hex",
- "To Charcode",
- "From Charcode",
- "To Decimal",
- "From Decimal",
- "To Binary",
- "From Binary",
- "To Base64",
- "From Base64",
- "Show Base64 offsets",
- "To Base32",
- "From Base32",
- "To Base",
- "From Base",
- "To HTML Entity",
- "From HTML Entity",
- "URL Encode",
- "URL Decode",
- "Unescape Unicode Characters",
- "To Quoted Printable",
- "From Quoted Printable",
- "To Punycode",
- "From Punycode",
- "To Hex Content",
- "From Hex Content",
- "PEM to Hex",
- "Hex to PEM",
- "Parse ASN.1 hex string",
- "Change IP format",
- "Text encoding",
- "Swap endianness",
- ]
- },
- {
- name: "Encryption / Encoding",
- ops: [
- "AES Encrypt",
- "AES Decrypt",
- "Blowfish Encrypt",
- "Blowfish Decrypt",
- "DES Encrypt",
- "DES Decrypt",
- "Triple DES Encrypt",
- "Triple DES Decrypt",
- "Rabbit Encrypt",
- "Rabbit Decrypt",
- "RC4",
- "RC4 Drop",
- "ROT13",
- "XOR",
- "XOR Brute Force",
- "Derive PBKDF2 key",
- "Derive EVP key",
- ]
- },
- {
- name: "Public Key",
- ops: [
- "Parse X.509 certificate",
- "Parse ASN.1 hex string",
- "PEM to Hex",
- "Hex to PEM",
- "Hex to Object Identifier",
- "Object Identifier to Hex",
- ]
- },
- {
- name: "Logical operations",
- ops: [
- "XOR",
- "XOR Brute Force",
- "OR",
- "NOT",
- "AND",
- "ADD",
- "SUB",
- "Rotate left",
- "Rotate right",
- "ROT13",
- ]
- },
- {
- name: "Networking",
- ops: [
- "Strip HTTP headers",
- "Parse User Agent",
- "Parse IP range",
- "Parse IPv6 address",
- "Parse URI",
- "URL Encode",
- "URL Decode",
- "Format MAC addresses",
- "Change IP format",
- "Group IP addresses",
- ]
- },
- {
- name: "Language",
- ops: [
- "Text encoding",
- "Unescape Unicode Characters",
- ]
- },
- {
- name: "Utils",
- ops: [
- "Diff",
- "Remove whitespace",
- "Remove null bytes",
- "To Upper case",
- "To Lower case",
- "Add line numbers",
- "Remove line numbers",
- "Reverse",
- "Sort",
- "Unique",
- "Split",
- "Count occurrences",
- "Expand alphabet range",
- "Parse escaped string",
- "Drop bytes",
- "Take bytes",
- "Pad lines",
- "Find / Replace",
- "Regular expression",
- "Offset checker",
- "Convert distance",
- "Convert area",
- "Convert mass",
- "Convert speed",
- "Convert data units",
- "Parse UNIX file permissions",
- "Swap endianness",
- "Parse colour code",
- ]
- },
- {
- name: "Date / Time",
- ops: [
- "Parse DateTime",
- "Translate DateTime Format",
- "From UNIX Timestamp",
- "To UNIX Timestamp",
- "Extract dates",
- ]
- },
- {
- name: "Extractors",
- ops: [
- "Strings",
- "Extract IP addresses",
- "Extract email addresses",
- "Extract MAC addresses",
- "Extract URLs",
- "Extract domains",
- "Extract file paths",
- "Extract dates",
- "Regular expression",
- ]
- },
- {
- name: "Compression",
- ops: [
- "Raw Deflate",
- "Raw Inflate",
- "Zlib Deflate",
- "Zlib Inflate",
- "Gzip",
- "Gunzip",
- "Zip",
- "Unzip",
- "Bzip2 Decompress",
- ]
- },
- {
- name: "Hashing",
- ops: [
- "Analyse hash",
- "Generate all hashes",
- "MD5",
- "SHA1",
- "SHA224",
- "SHA256",
- "SHA384",
- "SHA512",
- "SHA3",
- "RIPEMD-160",
- "HMAC",
- "Fletcher-16 Checksum",
- "Adler-32 Checksum",
- "CRC-32 Checksum",
- "TCP/IP Checksum",
- ]
- },
- {
- name: "Code tidy",
- ops: [
- "Syntax highlighter",
- "Generic Code Beautify",
- "JavaScript Parser",
- "JavaScript Beautify",
- "JavaScript Minify",
- "JSON Beautify",
- "JSON Minify",
- "XML Beautify",
- "XML Minify",
- "SQL Beautify",
- "SQL Minify",
- "CSS Beautify",
- "CSS Minify",
- "Strip HTML tags",
- "Diff",
- ]
- },
- {
- name: "Other",
- ops: [
- "Entropy",
- "Frequency distribution",
- "Detect File Type",
- "Scan for Embedded Files",
- "Generate UUID",
- "Numberwang",
- ]
- },
- {
- name: "Flow control",
- ops: [
- "Fork",
- "Merge",
- "Jump",
- "Conditional Jump",
- "Return",
- ]
- },
-];
diff --git a/src/js/core/Chef.js b/src/js/core/Chef.js
deleted file mode 100755
index 459cdcf9..00000000
--- a/src/js/core/Chef.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * The main controller for CyberChef.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @class
- */
-var Chef = function() {
- this.dish = new Dish();
-};
-
-
-/**
- * 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 {Object} options - The options object storing various user choices
- * @param {boolean} options.attemp_highlight - 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
- *
- * @returns {Object} response
- * @returns {string} response.result - The output of the recipe
- * @returns {string} response.type - The data type of the result
- * @returns {number} response.progress - The position that we have got to in the recipe
- * @returns {number} response.options - The app options object (which may have been changed)
- * @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;
-
- // Reset attempt_highlight flag
- if (options.hasOwnProperty("attempt_highlight")) {
- options.attempt_highlight = true;
- }
-
- if (contains_fc) options.attempt_highlight = false;
-
- // Clean up progress
- if (progress >= recipe_config.length) {
- progress = 0;
- }
-
- if (step) {
- // Unset breakpoint on this step
- recipe.set_breakpoint(progress, false);
- // Set breakpoint on next step
- recipe.set_breakpoint(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);
- progress = 0;
- }
-
- // If starting from scratch, load data
- if (progress === 0) {
- this.dish.set(input_text, Dish.STRING);
- }
-
- try {
- progress = recipe.execute(this.dish, progress);
- } catch (err) {
- // We can't throw the error from here as we will return in the finally block and ignore it
- // so we return the error in the result instead.
- error = err;
- progress = err.progress;
- } finally {
- return {
- result: this.dish.type == Dish.HTML ?
- this.dish.get(Dish.HTML) :
- this.dish.get(Dish.STRING),
- type: Dish.enum_lookup(this.dish.type),
- progress: progress,
- options: options,
- duration: new Date().getTime() - start_time,
- error: error
- };
- }
-};
-
-
-/**
- * When a browser tab is unfocused and the browser has to run lots of dynamic content in other tabs,
- * it swaps out the memory for that tab. If the CyberChef tab has been unfocused for more than a
- * minute, we run a silent bake which will force the browser to load and cache all the relevant
- * JavaScript code needed to do a real bake.
- *
- * 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.
- *
- * The output will not be modified (hence "silent" bake).
- *
- * 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
- * @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);
-
- try {
- recipe.execute(dish);
- } catch(err) {
- // Suppress all errors
- }
- return new Date().getTime() - start_time;
-};
diff --git a/src/js/core/Dish.js b/src/js/core/Dish.js
deleted file mode 100755
index c69ebef3..00000000
--- a/src/js/core/Dish.js
+++ /dev/null
@@ -1,202 +0,0 @@
-/**
- * The data being operated on by each operation.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @class
- * @param {byte_array|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) {
- this.value = value || typeof value == "string" ? value : null;
- this.type = type || Dish.BYTE_ARRAY;
-};
-
-
-/**
- * Dish data type enum for byte arrays.
- * @readonly
- * @enum
- */
-Dish.BYTE_ARRAY = 0;
-/**
- * Dish data type enum for strings.
- * @readonly
- * @enum
- */
-Dish.STRING = 1;
-/**
- * Dish data type enum for numbers.
- * @readonly
- * @enum
- */
-Dish.NUMBER = 2;
-/**
- * Dish data type enum for HTML.
- * @readonly
- * @enum
- */
-Dish.HTML = 3;
-
-
-/**
- * Returns the data type enum for the given type string.
- *
- * @static
- * @param {string} type_str - 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":
- case "Byte array":
- return Dish.BYTE_ARRAY;
- case "string":
- case "String":
- return Dish.STRING;
- case "number":
- case "Number":
- return Dish.NUMBER;
- case "html":
- case "HTML":
- return Dish.HTML;
- default:
- throw "Invalid data type string. No matching enum.";
- }
-};
-
-
-/**
- * Returns the data type string for the given type enum.
- *
- * @static
- * @param {string} type_enum - The enum value of the data type.
- * @returns {number} The data type as a string.
- */
-Dish.enum_lookup = function(type_enum) {
- switch (type_enum) {
- case Dish.BYTE_ARRAY:
- return "byte_array";
- case Dish.STRING:
- return "string";
- case Dish.NUMBER:
- return "number";
- case Dish.HTML:
- return "html";
- default:
- throw "Invalid data type enum. No matching type.";
- }
-};
-
-
-/**
- * Sets the data value and type and then validates them.
- *
- * @param {byte_array|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) {
- this.value = value;
- this.type = type;
-
- if (!this.valid()) {
- var sample = Utils.truncate(JSON.stringify(this.value), 13);
- throw "Data is not a valid " + Dish.enum_lookup(type) + ": " + sample;
- }
-};
-
-
-/**
- * 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.
- */
-Dish.prototype.get = function(type) {
- if (this.type != type) {
- this.translate(type);
- }
- return this.value;
-};
-
-
-/**
- * Translates the data to the given type format.
- *
- * @param {number} to_type - The data type of value, see Dish enums.
- */
-Dish.prototype.translate = function(to_type) {
- // Convert data to intermediate byte_array type
- switch (this.type) {
- case Dish.STRING:
- this.value = this.value ? Utils.str_to_byte_array(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.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.type = Dish.BYTE_ARRAY;
- break;
- default:
- break;
- }
-
- // Convert from byte_array to to_type
- switch (to_type) {
- case Dish.STRING:
- case Dish.HTML:
- this.value = this.value ? Utils.byte_array_to_utf8(this.value) : "";
- this.type = Dish.STRING;
- break;
- case Dish.NUMBER:
- this.value = this.value ? parseFloat(Utils.byte_array_to_utf8(this.value)) : 0;
- this.type = Dish.NUMBER;
- break;
- default:
- break;
- }
-};
-
-
-/**
- * Validates that the value is the type that has been specified.
- * May have to disable parts of BYTE_ARRAY validation if it effects performance.
- *
- * @returns {boolean} Whether the data is valid or not.
-*/
-Dish.prototype.valid = function() {
- switch (this.type) {
- case Dish.BYTE_ARRAY:
- if (!(this.value instanceof Array)) {
- return false;
- }
-
- // Check that every value is a number between 0 - 255
- for (var i = 0; i < this.value.length; i++) {
- if (typeof this.value[i] != "number" ||
- this.value[i] < 0 ||
- this.value[i] > 255) {
- return false;
- }
- }
- return true;
- case Dish.STRING:
- case Dish.HTML:
- if (typeof this.value == "string") {
- return true;
- }
- return false;
- case Dish.NUMBER:
- if (typeof this.value == "number") {
- return true;
- }
- return false;
- default:
- return false;
- }
-};
diff --git a/src/js/core/FlowControl.js b/src/js/core/FlowControl.js
deleted file mode 100755
index 51af24a0..00000000
--- a/src/js/core/FlowControl.js
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * Flow Control operations.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @namespace
- */
-var FlowControl = {
-
- /**
- * @constant
- * @default
- */
- FORK_DELIM: "\\n",
- /**
- * @constant
- * @default
- */
- MERGE_DELIM: "\\n",
-
- /**
- * Fork operation.
- *
- * @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.
- * @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 = [];
-
- if (input)
- inputs = input.split(split_delim);
-
- // Create sub_op_list 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()) {
- break;
- } else {
- sub_op_list.push(op_list[i]);
- }
- }
-
- var recipe = new Recipe(),
- output = "",
- progress;
-
- recipe.add_operations(sub_op_list);
-
- // 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;
- }
-
- state.dish.set(output, output_type);
- state.progress += progress;
- return state;
- },
-
-
- /**
- * Merge operation.
- *
- * @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.
- * @returns {Object} The updated state of the recipe.
- */
- run_merge: function(state) {
- // No need to actually do anything here. The fork operation will
- // merge when it sees this operation.
- return state;
- },
-
-
- /**
- * @constant
- * @default
- */
- JUMP_NUM: 0,
- /**
- * @constant
- * @default
- */
- MAX_JUMPS: 10,
-
- /**
- * Jump operation.
- *
- * @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.
- * @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];
-
- if (state.num_jumps >= max_jumps) {
- throw "Reached maximum jumps, sorry!";
- }
-
- state.progress += jump_num;
- state.num_jumps++;
- return state;
- },
-
-
- /**
- * Conditional Jump operation.
- *
- * @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.
- * @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];
-
- if (state.num_jumps >= max_jumps) {
- throw "Reached maximum jumps, sorry!";
- }
-
- if (regex_str !== "" && dish.get(Dish.STRING).search(regex_str) > -1) {
- state.progress += jump_num;
- state.num_jumps++;
- }
-
- return state;
- },
-
-
- /**
- * Return operation.
- *
- * @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.
- * @returns {Object} The updated state of the recipe.
- */
- run_return: function(state) {
- state.progress = state.op_list.length;
- return state;
- },
-
-};
diff --git a/src/js/core/Ingredient.js b/src/js/core/Ingredient.js
deleted file mode 100755
index df551b6f..00000000
--- a/src/js/core/Ingredient.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * The arguments to operations.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @class
- * @param {Object} ingredient_config
- */
-var Ingredient = function(ingredient_config) {
- this.name = "";
- this.type = "";
- this.value = null;
-
- if (ingredient_config) {
- this._parse_config(ingredient_config);
- }
-};
-
-
-/**
- * Reads and parses the given config.
- *
- * @private
- * @param {Object} ingredient_config
- */
-Ingredient.prototype._parse_config = function(ingredient_config) {
- this.name = ingredient_config.name;
- this.type = ingredient_config.type;
-};
-
-
-/**
- * Returns the value of the Ingredient as it should be displayed in a recipe config.
- *
- * @returns {*}
- */
-Ingredient.prototype.get_config = function() {
- return this.value;
-};
-
-
-/**
- * Sets the value of the Ingredient.
- *
- * @param {*} value
- */
-Ingredient.prototype.set_value = function(value) {
- this.value = Ingredient.prepare(value, this.type);
-};
-
-
-/**
- * Most values will be strings when they are entered. This function converts them to the correct
- * type.
- *
- * @static
- * @param {*} data
- * @param {string} type - The name of the data type.
-*/
-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":
- if (typeof data == "string") {
- data = data.replace(/\s+/g, '');
- return Utils.hex_to_byte_array(data);
- } else {
- return data;
- }
- break;
- case "number":
- var number = parseFloat(data);
- if (isNaN(number)) {
- var sample = Utils.truncate(data.toString(), 10);
- throw "Invalid ingredient value. Not a number: " + sample;
- }
- return number;
- default:
- return data;
- }
-};
diff --git a/src/js/core/Operation.js b/src/js/core/Operation.js
deleted file mode 100755
index 26a1e279..00000000
--- a/src/js/core/Operation.js
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * The Operation specified by the user to be run.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @class
- * @param {string} operation_name
- * @param {Object} operation_config
- */
-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 = [];
-
- if (operation_config) {
- this._parse_config(operation_config);
- }
-};
-
-
-/**
- * Reads and parses the given config.
- *
- * @private
- * @param {Object} operation_config
- */
-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);
- }
-};
-
-
-/**
- * Returns the value of the Operation as it should be displayed in a recipe config.
- *
- * @returns {Object}
- */
-Operation.prototype.get_config = function() {
- var ingredient_config = [];
-
- for (var o = 0; o < this.ing_list.length; o++) {
- ingredient_config.push(this.ing_list[o].get_config());
- }
-
- var operation_config = {
- "op": this.name,
- "args": ingredient_config
- };
-
- return operation_config;
-};
-
-
-/**
- * Adds a new Ingredient to this Operation.
- *
- * @param {Ingredient} ingredient
- */
-Operation.prototype.add_ingredient = function(ingredient) {
- this.ing_list.push(ingredient);
-};
-
-
-/**
- * Set the Ingredient values for this Operation.
- *
- * @param {Object[]} ing_values
- */
-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]);
- }
-};
-
-
-/**
- * Get the Ingredient values for this Operation.
- *
- * @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);
- }
- return ing_values;
-};
-
-
-/**
- * Set whether this Operation has a breakpoint.
- *
- * @param {boolean} value
- */
-Operation.prototype.set_breakpoint = function(value) {
- this.breakpoint = !!value;
-};
-
-
-/**
- * Returns true if this Operation has a breakpoint set.
- *
- * @returns {boolean}
- */
-Operation.prototype.is_breakpoint = function() {
- return this.breakpoint;
-};
-
-
-/**
- * Set whether this Operation is disabled.
- *
- * @param {boolean} value
- */
-Operation.prototype.set_disabled = function(value) {
- this.disabled = !!value;
-};
-
-
-/**
- * Returns true if this Operation is disabled.
- *
- * @returns {boolean}
- */
-Operation.prototype.is_disabled = function() {
- return this.disabled;
-};
-
-
-/**
- * Returns true if this Operation is a flow control.
- *
- * @returns {boolean}
- */
-Operation.prototype.is_flow_control = function() {
- return this.flow_control;
-};
diff --git a/src/js/core/Recipe.js b/src/js/core/Recipe.js
deleted file mode 100755
index b93d7560..00000000
--- a/src/js/core/Recipe.js
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * The Recipe controls a list of Operations and the Dish they operate on.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @class
- * @param {Object} recipe_config
- */
-var Recipe = function(recipe_config) {
- this.op_list = [];
-
- if (recipe_config) {
- this._parse_config(recipe_config);
- }
-};
-
-
-/**
- * Reads and parses the given config.
- *
- * @private
- * @param {Object} recipe_config
- */
-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);
- }
-};
-
-
-/**
- * Returns the value of the Recipe as it should be displayed in a recipe config.
- *
- * @returns {*}
- */
-Recipe.prototype.get_config = function() {
- var recipe_config = [];
-
- for (var o = 0; o < this.op_list.length; o++) {
- recipe_config.push(this.op_list[o].get_config());
- }
-
- return recipe_config;
-};
-
-
-/**
- * Adds a new Operation to this Recipe.
- *
- * @param {Operation} operation
- */
-Recipe.prototype.add_operation = function(operation) {
- this.op_list.push(operation);
-};
-
-
-/**
- * Adds a list of Operations to this Recipe.
- *
- * @param {Operation[]} operations
- */
-Recipe.prototype.add_operations = function(operations) {
- this.op_list = this.op_list.concat(operations);
-};
-
-
-/**
- * Set a breakpoint on a specified Operation.
- *
- * @param {number} position - The index of the Operation
- * @param {boolean} value
- */
-Recipe.prototype.set_breakpoint = function(position, value) {
- try {
- this.op_list[position].set_breakpoint(value);
- } catch (err) {
- // Ignore index error
- }
-};
-
-
-/**
- * Remove breakpoints on all Operations in the Recipe up to the specified position. Used by Flow
- * Control Fork operation.
- *
- * @param {number} pos
- */
-Recipe.prototype.remove_breaks_up_to = function(pos) {
- for (var i = 0; i < pos; i++) {
- this.op_list[i].set_breakpoint(false);
- }
-};
-
-
-/**
- * Returns true if there is an Flow Control Operation in this Recipe.
- *
- * @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;
- }
- return false;
-};
-
-
-/**
- * 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
- * @returns (number}
- */
-Recipe.prototype.last_op_index = function(start_index) {
- var i = start_index + 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;
- }
-
- return i-1;
-};
-
-
-/**
- * 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
- * @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;
-
- for (var i = start_from; i < this.op_list.length; i++) {
- op = this.op_list[i];
- if (op.is_disabled()) {
- continue;
- }
- if (op.is_breakpoint()) {
- return i;
- }
-
- try {
- input = dish.get(op.input_type);
-
- if (op.is_flow_control()) {
- // Package up the current state
- var state = {
- "progress" : i,
- "dish" : dish,
- "op_list" : this.op_list,
- "num_jumps" : num_jumps
- };
-
- state = op.run(state);
- i = state.progress;
- num_jumps = state.num_jumps;
- } else {
- output = op.run(input, op.get_ing_values());
- dish.set(output, op.output_type);
- }
- } 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 +
- ".
Message: " + e.message;
- } else {
- e.display_str += e.message;
- }
-
- throw e;
- }
- }
-
- return this.op_list.length;
-};
-
-
-/**
- * Returns the recipe configuration in string format.
- *
- * @returns {string}
- */
-Recipe.prototype.to_string = function() {
- return JSON.stringify(this.get_config());
-};
-
-
-/**
- * Creates a Recipe from a given configuration string.
- *
- * @param {string} recipe_str
- */
-Recipe.prototype.from_string = function(recipe_str) {
- var recipe_config = JSON.parse(recipe_str);
- this._parse_config(recipe_config);
-};
diff --git a/src/js/lib/Sortable.js b/src/js/lib/Sortable.js
deleted file mode 100755
index 5c99c709..00000000
--- a/src/js/lib/Sortable.js
+++ /dev/null
@@ -1,1271 +0,0 @@
-/** @license
-========================================================================
- Sortable
- @author RubaXa
- @license MIT
-*/
-
-(function (factory) {
- "use strict";
-
- if (typeof define === "function" && define.amd) {
- define(factory);
- }
- else if (typeof module != "undefined" && typeof module.exports != "undefined") {
- module.exports = factory();
- }
- else if (typeof Package !== "undefined") {
- Sortable = factory(); // export for Meteor.js
- }
- else {
- /* jshint sub:true */
- window["Sortable"] = factory();
- }
-})(function () {
- "use strict";
-
- if (typeof window == "undefined" || typeof window.document == "undefined") {
- return function() {
- throw new Error( "Sortable.js requires a window with a document" );
- }
- }
-
- var dragEl,
- parentEl,
- ghostEl,
- cloneEl,
- rootEl,
- nextEl,
-
- scrollEl,
- scrollParentEl,
-
- lastEl,
- lastCSS,
- lastParentCSS,
-
- oldIndex,
- newIndex,
-
- activeGroup,
- autoScroll = {},
-
- tapEvt,
- touchEvt,
-
- moved,
-
- /** @const */
- RSPACE = /\s+/g,
-
- expando = 'Sortable' + (new Date).getTime(),
-
- win = window,
- document = win.document,
- parseInt = win.parseInt,
-
- supportDraggable = !!('draggable' in document.createElement('div')),
- supportCssPointerEvents = (function (el) {
- el = document.createElement('x');
- el.style.cssText = 'pointer-events:auto';
- return el.style.pointerEvents === 'auto';
- })(),
-
- _silent = false,
-
- abs = Math.abs,
- slice = [].slice,
-
- touchDragOverListeners = [],
-
- _autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
- // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
- if (rootEl && options.scroll) {
- var el,
- rect,
- sens = options.scrollSensitivity,
- speed = options.scrollSpeed,
-
- x = evt.clientX,
- y = evt.clientY,
-
- winWidth = window.innerWidth,
- winHeight = window.innerHeight,
-
- vx,
- vy
- ;
-
- // Delect scrollEl
- if (scrollParentEl !== rootEl) {
- scrollEl = options.scroll;
- scrollParentEl = rootEl;
-
- if (scrollEl === true) {
- scrollEl = rootEl;
-
- do {
- if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
- (scrollEl.offsetHeight < scrollEl.scrollHeight)
- ) {
- break;
- }
- /* jshint boss:true */
- } while (scrollEl = scrollEl.parentNode);
- }
- }
-
- if (scrollEl) {
- el = scrollEl;
- rect = scrollEl.getBoundingClientRect();
- vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
- vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
- }
-
-
- if (!(vx || vy)) {
- vx = (winWidth - x <= sens) - (x <= sens);
- vy = (winHeight - y <= sens) - (y <= sens);
-
- /* jshint expr:true */
- (vx || vy) && (el = win);
- }
-
-
- if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
- autoScroll.el = el;
- autoScroll.vx = vx;
- autoScroll.vy = vy;
-
- clearInterval(autoScroll.pid);
-
- if (el) {
- autoScroll.pid = setInterval(function () {
- if (el === win) {
- win.scrollTo(win.pageXOffset + vx * speed, win.pageYOffset + vy * speed);
- } else {
- vy && (el.scrollTop += vy * speed);
- vx && (el.scrollLeft += vx * speed);
- }
- }, 24);
- }
- }
- }
- }, 30),
-
- _prepareGroup = function (options) {
- var group = options.group;
-
- if (!group || typeof group != 'object') {
- group = options.group = {name: group};
- }
-
- ['pull', 'put'].forEach(function (key) {
- if (!(key in group)) {
- group[key] = true;
- }
- });
-
- options.groups = ' ' + group.name + (group.put.join ? ' ' + group.put.join(' ') : '') + ' ';
- }
- ;
-
-
-
- /**
- * @class Sortable
- * @param {HTMLElement} el
- * @param {Object} [options]
- */
- function Sortable(el, options) {
- if (!(el && el.nodeType && el.nodeType === 1)) {
- throw 'Sortable: `el` must be HTMLElement, and not ' + {}.toString.call(el);
- }
-
- this.el = el; // root element
- this.options = options = _extend({}, options);
-
-
- // Export instance
- el[expando] = this;
-
-
- // Default options
- var defaults = {
- group: Math.random(),
- sort: true,
- disabled: false,
- store: null,
- handle: null,
- scroll: true,
- scrollSensitivity: 30,
- scrollSpeed: 10,
- draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
- ghostClass: 'sortable-ghost',
- chosenClass: 'sortable-chosen',
- ignore: 'a, img',
- filter: null,
- animation: 0,
- setData: function (dataTransfer, dragEl) {
- dataTransfer.setData('Text', dragEl.textContent);
- },
- dropBubble: false,
- dragoverBubble: false,
- dataIdAttr: 'data-id',
- delay: 0,
- forceFallback: false,
- fallbackClass: 'sortable-fallback',
- fallbackOnBody: false
- };
-
-
- // Set default options
- for (var name in defaults) {
- !(name in options) && (options[name] = defaults[name]);
- }
-
- _prepareGroup(options);
-
- // Bind all private methods
- for (var fn in this) {
- if (fn.charAt(0) === '_') {
- this[fn] = this[fn].bind(this);
- }
- }
-
- // Setup drag mode
- this.nativeDraggable = options.forceFallback ? false : supportDraggable;
-
- // Bind events
- _on(el, 'mousedown', this._onTapStart);
- _on(el, 'touchstart', this._onTapStart);
-
- if (this.nativeDraggable) {
- _on(el, 'dragover', this);
- _on(el, 'dragenter', this);
- }
-
- touchDragOverListeners.push(this._onDragOver);
-
- // Restore sorting
- options.store && this.sort(options.store.get(this));
- }
-
-
- Sortable.prototype = /** @lends Sortable.prototype */ {
- constructor: Sortable,
-
- _onTapStart: function (/** Event|TouchEvent */evt) {
- var _this = this,
- el = this.el,
- options = this.options,
- type = evt.type,
- touch = evt.touches && evt.touches[0],
- target = (touch || evt).target,
- originalTarget = target,
- filter = options.filter;
-
-
- if (type === 'mousedown' && evt.button !== 0 || options.disabled) {
- return; // only left button or enabled
- }
-
- target = _closest(target, options.draggable, el);
-
- if (!target) {
- return;
- }
-
- // get the index of the dragged element within its parent
- oldIndex = _index(target, options.draggable);
-
- // Check filter
- if (typeof filter === 'function') {
- if (filter.call(this, evt, target, this)) {
- _dispatchEvent(_this, originalTarget, 'filter', target, el, oldIndex);
- evt.preventDefault();
- return; // cancel dnd
- }
- }
- else if (filter) {
- filter = filter.split(',').some(function (criteria) {
- criteria = _closest(originalTarget, criteria.trim(), el);
-
- if (criteria) {
- _dispatchEvent(_this, criteria, 'filter', target, el, oldIndex);
- return true;
- }
- });
-
- if (filter) {
- //evt.preventDefault();
- return; // cancel dnd
- }
- }
-
-
- if (options.handle && !_closest(originalTarget, options.handle, el)) {
- return;
- }
-
-
- // Prepare `dragstart`
- this._prepareDragStart(evt, touch, target);
- },
-
- _prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target) {
- var _this = this,
- el = _this.el,
- options = _this.options,
- ownerDocument = el.ownerDocument,
- dragStartFn;
-
- if (target && !dragEl && (target.parentNode === el)) {
- tapEvt = evt;
-
- rootEl = el;
- dragEl = target;
- parentEl = dragEl.parentNode;
- nextEl = dragEl.nextSibling;
- activeGroup = options.group;
-
- dragStartFn = function () {
- // Delayed drag has been triggered
- // we can re-enable the events: touchmove/mousemove
- _this._disableDelayedDrag();
-
- // Make the element draggable
- dragEl.draggable = true;
-
- // Chosen item
- _toggleClass(dragEl, _this.options.chosenClass, true);
-
- // Bind the events: dragstart/dragend
- _this._triggerDragStart(touch);
- };
-
- // Disable "draggable"
- options.ignore.split(',').forEach(function (criteria) {
- _find(dragEl, criteria.trim(), _disableDraggable);
- });
-
- _on(ownerDocument, 'mouseup', _this._onDrop);
- _on(ownerDocument, 'touchend', _this._onDrop);
- _on(ownerDocument, 'touchcancel', _this._onDrop);
-
- if (options.delay) {
- // If the user moves the pointer or let go the click or touch
- // before the delay has been reached:
- // disable the delayed drag
- _on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
- _on(ownerDocument, 'touchend', _this._disableDelayedDrag);
- _on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
- _on(ownerDocument, 'mousemove', _this._disableDelayedDrag);
- _on(ownerDocument, 'touchmove', _this._disableDelayedDrag);
-
- _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
- } else {
- dragStartFn();
- }
- }
- },
-
- _disableDelayedDrag: function () {
- var ownerDocument = this.el.ownerDocument;
-
- clearTimeout(this._dragStartTimer);
- _off(ownerDocument, 'mouseup', this._disableDelayedDrag);
- _off(ownerDocument, 'touchend', this._disableDelayedDrag);
- _off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
- _off(ownerDocument, 'mousemove', this._disableDelayedDrag);
- _off(ownerDocument, 'touchmove', this._disableDelayedDrag);
- },
-
- _triggerDragStart: function (/** Touch */touch) {
- if (touch) {
- // Touch device support
- tapEvt = {
- target: dragEl,
- clientX: touch.clientX,
- clientY: touch.clientY
- };
-
- this._onDragStart(tapEvt, 'touch');
- }
- else if (!this.nativeDraggable) {
- this._onDragStart(tapEvt, true);
- }
- else {
- _on(dragEl, 'dragend', this);
- _on(rootEl, 'dragstart', this._onDragStart);
- }
-
- try {
- if (document.selection) {
- document.selection.empty();
- } else {
- window.getSelection().removeAllRanges();
- }
- } catch (err) {
- }
- },
-
- _dragStarted: function () {
- if (rootEl && dragEl) {
- // Apply effect
- _toggleClass(dragEl, this.options.ghostClass, true);
-
- Sortable.active = this;
-
- // Drag start event
- _dispatchEvent(this, rootEl, 'start', dragEl, rootEl, oldIndex);
- }
- },
-
- _emulateDragOver: function () {
- if (touchEvt) {
- if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) {
- return;
- }
-
- this._lastX = touchEvt.clientX;
- this._lastY = touchEvt.clientY;
-
- if (!supportCssPointerEvents) {
- _css(ghostEl, 'display', 'none');
- }
-
- var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY),
- parent = target,
- groupName = ' ' + this.options.group.name + '',
- i = touchDragOverListeners.length;
-
- if (parent) {
- do {
- if (parent[expando] && parent[expando].options.groups.indexOf(groupName) > -1) {
- while (i--) {
- touchDragOverListeners[i]({
- clientX: touchEvt.clientX,
- clientY: touchEvt.clientY,
- target: target,
- rootEl: parent
- });
- }
-
- break;
- }
-
- target = parent; // store last element
- }
- /* jshint boss:true */
- while (parent = parent.parentNode);
- }
-
- if (!supportCssPointerEvents) {
- _css(ghostEl, 'display', '');
- }
- }
- },
-
-
- _onTouchMove: function (/**TouchEvent*/evt) {
- if (tapEvt) {
- // only set the status to dragging, when we are actually dragging
- if (!Sortable.active) {
- this._dragStarted();
- }
-
- // as well as creating the ghost element on the document body
- this._appendGhost();
-
- var touch = evt.touches ? evt.touches[0] : evt,
- dx = touch.clientX - tapEvt.clientX,
- dy = touch.clientY - tapEvt.clientY,
- translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
-
- moved = true;
- touchEvt = touch;
-
- _css(ghostEl, 'webkitTransform', translate3d);
- _css(ghostEl, 'mozTransform', translate3d);
- _css(ghostEl, 'msTransform', translate3d);
- _css(ghostEl, 'transform', translate3d);
-
- evt.preventDefault();
- }
- },
-
- _appendGhost: function () {
- if (!ghostEl) {
- var rect = dragEl.getBoundingClientRect(),
- css = _css(dragEl),
- options = this.options,
- ghostRect;
-
- ghostEl = dragEl.cloneNode(true);
-
- _toggleClass(ghostEl, options.ghostClass, false);
- _toggleClass(ghostEl, options.fallbackClass, true);
-
- _css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
- _css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
- _css(ghostEl, 'width', rect.width);
- _css(ghostEl, 'height', rect.height);
- _css(ghostEl, 'opacity', '0.8');
- _css(ghostEl, 'position', 'fixed');
- _css(ghostEl, 'zIndex', '100000');
- _css(ghostEl, 'pointerEvents', 'none');
-
- options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl);
-
- // Fixing dimensions.
- ghostRect = ghostEl.getBoundingClientRect();
- _css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
- _css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
- }
- },
-
- _onDragStart: function (/**Event*/evt, /**boolean*/useFallback) {
- var dataTransfer = evt.dataTransfer,
- options = this.options;
-
- this._offUpEvents();
-
- if (activeGroup.pull == 'clone') {
- cloneEl = dragEl.cloneNode(true);
- _css(cloneEl, 'display', 'none');
- rootEl.insertBefore(cloneEl, dragEl);
- }
-
- if (useFallback) {
-
- if (useFallback === 'touch') {
- // Bind touch events
- _on(document, 'touchmove', this._onTouchMove);
- _on(document, 'touchend', this._onDrop);
- _on(document, 'touchcancel', this._onDrop);
- } else {
- // Old brwoser
- _on(document, 'mousemove', this._onTouchMove);
- _on(document, 'mouseup', this._onDrop);
- }
-
- this._loopId = setInterval(this._emulateDragOver, 50);
- }
- else {
- if (dataTransfer) {
- dataTransfer.effectAllowed = 'move';
- options.setData && options.setData.call(this, dataTransfer, dragEl);
- }
-
- _on(document, 'drop', this);
- setTimeout(this._dragStarted, 0);
- }
- },
-
- _onDragOver: function (/**Event*/evt) {
- var el = this.el,
- target,
- dragRect,
- revert,
- options = this.options,
- group = options.group,
- groupPut = group.put,
- isOwner = (activeGroup === group),
- canSort = options.sort;
-
- if (evt.preventDefault !== void 0) {
- evt.preventDefault();
- !options.dragoverBubble && evt.stopPropagation();
- }
-
- moved = true;
-
- if (activeGroup && !options.disabled &&
- (isOwner
- ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
- : activeGroup.pull && groupPut && (
- (activeGroup.name === group.name) || // by Name
- (groupPut.indexOf && ~groupPut.indexOf(activeGroup.name)) // by Array
- )
- ) &&
- (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback
- ) {
- // Smart auto-scrolling
- _autoScroll(evt, options, this.el);
-
- if (_silent) {
- return;
- }
-
- target = _closest(evt.target, options.draggable, el);
- dragRect = dragEl.getBoundingClientRect();
-
- if (revert) {
- _cloneHide(true);
-
- if (cloneEl || nextEl) {
- rootEl.insertBefore(dragEl, cloneEl || nextEl);
- }
- else if (!canSort) {
- rootEl.appendChild(dragEl);
- }
-
- return;
- }
-
-
- if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
- (el === evt.target) && (target = _ghostIsLast(el, evt))
- ) {
-
- if (target) {
- if (target.animated) {
- return;
- }
-
- targetRect = target.getBoundingClientRect();
- }
-
- _cloneHide(isOwner);
-
- if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect) !== false) {
- if (!dragEl.contains(el)) {
- el.appendChild(dragEl);
- parentEl = el; // actualization
- }
-
- this._animate(dragRect, dragEl);
- target && this._animate(targetRect, target);
- }
- }
- else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) {
- if (lastEl !== target) {
- lastEl = target;
- lastCSS = _css(target);
- lastParentCSS = _css(target.parentNode);
- }
-
-
- var targetRect = target.getBoundingClientRect(),
- width = targetRect.right - targetRect.left,
- height = targetRect.bottom - targetRect.top,
- floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display)
- || (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0),
- isWide = (target.offsetWidth > dragEl.offsetWidth),
- isLong = (target.offsetHeight > dragEl.offsetHeight),
- halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
- nextSibling = target.nextElementSibling,
- moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect),
- after
- ;
-
- if (moveVector !== false) {
- _silent = true;
- setTimeout(_unsilent, 30);
-
- _cloneHide(isOwner);
-
- if (moveVector === 1 || moveVector === -1) {
- after = (moveVector === 1);
- }
- else if (floating) {
- var elTop = dragEl.offsetTop,
- tgTop = target.offsetTop;
-
- if (elTop === tgTop) {
- after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide;
- } else {
- after = tgTop > elTop;
- }
- } else {
- after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
- }
-
- if (!dragEl.contains(el)) {
- if (after && !nextSibling) {
- el.appendChild(dragEl);
- } else {
- target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
- }
- }
-
- parentEl = dragEl.parentNode; // actualization
-
- this._animate(dragRect, dragEl);
- this._animate(targetRect, target);
- }
- }
- }
- },
-
- _animate: function (prevRect, target) {
- var ms = this.options.animation;
-
- if (ms) {
- var currentRect = target.getBoundingClientRect();
-
- _css(target, 'transition', 'none');
- _css(target, 'transform', 'translate3d('
- + (prevRect.left - currentRect.left) + 'px,'
- + (prevRect.top - currentRect.top) + 'px,0)'
- );
-
- target.offsetWidth; // repaint
-
- _css(target, 'transition', 'all ' + ms + 'ms');
- _css(target, 'transform', 'translate3d(0,0,0)');
-
- clearTimeout(target.animated);
- target.animated = setTimeout(function () {
- _css(target, 'transition', '');
- _css(target, 'transform', '');
- target.animated = false;
- }, ms);
- }
- },
-
- _offUpEvents: function () {
- var ownerDocument = this.el.ownerDocument;
-
- _off(document, 'touchmove', this._onTouchMove);
- _off(ownerDocument, 'mouseup', this._onDrop);
- _off(ownerDocument, 'touchend', this._onDrop);
- _off(ownerDocument, 'touchcancel', this._onDrop);
- },
-
- _onDrop: function (/**Event*/evt) {
- var el = this.el,
- options = this.options;
-
- clearInterval(this._loopId);
- clearInterval(autoScroll.pid);
- clearTimeout(this._dragStartTimer);
-
- // Unbind events
- _off(document, 'mousemove', this._onTouchMove);
-
- if (this.nativeDraggable) {
- _off(document, 'drop', this);
- _off(el, 'dragstart', this._onDragStart);
- }
-
- this._offUpEvents();
-
- if (evt) {
- if (moved) {
- evt.preventDefault();
- !options.dropBubble && evt.stopPropagation();
- }
-
- ghostEl && ghostEl.parentNode.removeChild(ghostEl);
-
- if (dragEl) {
- if (this.nativeDraggable) {
- _off(dragEl, 'dragend', this);
- }
-
- _disableDraggable(dragEl);
-
- // Remove class's
- _toggleClass(dragEl, this.options.ghostClass, false);
- _toggleClass(dragEl, this.options.chosenClass, false);
-
- if (rootEl !== parentEl) {
- newIndex = _index(dragEl, options.draggable);
-
- if (newIndex >= 0) {
- // drag from one list and drop into another
- _dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
- _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
-
- // Add event
- _dispatchEvent(null, parentEl, 'add', dragEl, rootEl, oldIndex, newIndex);
-
- // Remove event
- _dispatchEvent(this, rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex);
- }
- }
- else {
- // Remove clone
- cloneEl && cloneEl.parentNode.removeChild(cloneEl);
-
- if (dragEl.nextSibling !== nextEl) {
- // Get the index of the dragged element within its parent
- newIndex = _index(dragEl, options.draggable);
-
- if (newIndex >= 0) {
- // drag & drop within the same list
- _dispatchEvent(this, rootEl, 'update', dragEl, rootEl, oldIndex, newIndex);
- _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
- }
- }
- }
-
- if (Sortable.active) {
- if (newIndex === null || newIndex === -1) {
- newIndex = oldIndex;
- }
-
- _dispatchEvent(this, rootEl, 'end', dragEl, rootEl, oldIndex, newIndex);
-
- // Save sorting
- this.save();
- }
- }
-
- }
- this._nulling();
- },
-
- _nulling: function() {
- // Nulling
- rootEl =
- dragEl =
- parentEl =
- ghostEl =
- nextEl =
- cloneEl =
-
- scrollEl =
- scrollParentEl =
-
- tapEvt =
- touchEvt =
-
- moved =
- newIndex =
-
- lastEl =
- lastCSS =
-
- activeGroup =
- Sortable.active = null;
- },
-
- handleEvent: function (/**Event*/evt) {
- var type = evt.type;
-
- if (type === 'dragover' || type === 'dragenter') {
- if (dragEl) {
- this._onDragOver(evt);
- _globalDragOver(evt);
- }
- }
- else if (type === 'drop' || type === 'dragend') {
- this._onDrop(evt);
- }
- },
-
-
- /**
- * Serializes the item into an array of string.
- * @returns {String[]}
- */
- toArray: function () {
- var order = [],
- el,
- children = this.el.children,
- i = 0,
- n = children.length,
- options = this.options;
-
- for (; i < n; i++) {
- el = children[i];
- if (_closest(el, options.draggable, this.el)) {
- order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
- }
- }
-
- return order;
- },
-
-
- /**
- * Sorts the elements according to the array.
- * @param {String[]} order order of the items
- */
- sort: function (order) {
- var items = {}, rootEl = this.el;
-
- this.toArray().forEach(function (id, i) {
- var el = rootEl.children[i];
-
- if (_closest(el, this.options.draggable, rootEl)) {
- items[id] = el;
- }
- }, this);
-
- order.forEach(function (id) {
- if (items[id]) {
- rootEl.removeChild(items[id]);
- rootEl.appendChild(items[id]);
- }
- });
- },
-
-
- /**
- * Save the current sorting
- */
- save: function () {
- var store = this.options.store;
- store && store.set(this);
- },
-
-
- /**
- * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
- * @param {HTMLElement} el
- * @param {String} [selector] default: `options.draggable`
- * @returns {HTMLElement|null}
- */
- closest: function (el, selector) {
- return _closest(el, selector || this.options.draggable, this.el);
- },
-
-
- /**
- * Set/get option
- * @param {string} name
- * @param {*} [value]
- * @returns {*}
- */
- option: function (name, value) {
- var options = this.options;
-
- if (value === void 0) {
- return options[name];
- } else {
- options[name] = value;
-
- if (name === 'group') {
- _prepareGroup(options);
- }
- }
- },
-
-
- /**
- * Destroy
- */
- destroy: function () {
- var el = this.el;
-
- el[expando] = null;
-
- _off(el, 'mousedown', this._onTapStart);
- _off(el, 'touchstart', this._onTapStart);
-
- if (this.nativeDraggable) {
- _off(el, 'dragover', this);
- _off(el, 'dragenter', this);
- }
-
- // Remove draggable attributes
- Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
- el.removeAttribute('draggable');
- });
-
- touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);
-
- this._onDrop();
-
- this.el = el = null;
- }
- };
-
-
- function _cloneHide(state) {
- if (cloneEl && (cloneEl.state !== state)) {
- _css(cloneEl, 'display', state ? 'none' : '');
- !state && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl);
- cloneEl.state = state;
- }
- }
-
-
- function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) {
- if (el) {
- ctx = ctx || document;
-
- do {
- if (
- (selector === '>*' && el.parentNode === ctx)
- || _matches(el, selector)
- ) {
- return el;
- }
- }
- while (el !== ctx && (el = el.parentNode));
- }
-
- return null;
- }
-
-
- function _globalDragOver(/**Event*/evt) {
- if (evt.dataTransfer) {
- evt.dataTransfer.dropEffect = 'move';
- }
- evt.preventDefault();
- }
-
-
- function _on(el, event, fn) {
- el.addEventListener(event, fn, false);
- }
-
-
- function _off(el, event, fn) {
- el.removeEventListener(event, fn, false);
- }
-
-
- function _toggleClass(el, name, state) {
- if (el) {
- if (el.classList) {
- el.classList[state ? 'add' : 'remove'](name);
- }
- else {
- var className = (' ' + el.className + ' ').replace(RSPACE, ' ').replace(' ' + name + ' ', ' ');
- el.className = (className + (state ? ' ' + name : '')).replace(RSPACE, ' ');
- }
- }
- }
-
-
- function _css(el, prop, val) {
- var style = el && el.style;
-
- if (style) {
- if (val === void 0) {
- if (document.defaultView && document.defaultView.getComputedStyle) {
- val = document.defaultView.getComputedStyle(el, '');
- }
- else if (el.currentStyle) {
- val = el.currentStyle;
- }
-
- return prop === void 0 ? val : val[prop];
- }
- else {
- if (!(prop in style)) {
- prop = '-webkit-' + prop;
- }
-
- style[prop] = val + (typeof val === 'string' ? '' : 'px');
- }
- }
- }
-
-
- function _find(ctx, tagName, iterator) {
- if (ctx) {
- var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
-
- if (iterator) {
- for (; i < n; i++) {
- iterator(list[i], i);
- }
- }
-
- return list;
- }
-
- return [];
- }
-
-
-
- function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) {
- var evt = document.createEvent('Event'),
- options = (sortable || rootEl[expando]).options,
- onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
-
- evt.initEvent(name, true, true);
-
- evt.to = rootEl;
- evt.from = fromEl || rootEl;
- evt.item = targetEl || rootEl;
- evt.clone = cloneEl;
-
- evt.oldIndex = startIndex;
- evt.newIndex = newIndex;
-
- rootEl.dispatchEvent(evt);
-
- if (options[onName]) {
- options[onName].call(sortable, evt);
- }
- }
-
-
- function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect) {
- var evt,
- sortable = fromEl[expando],
- onMoveFn = sortable.options.onMove,
- retVal;
-
- evt = document.createEvent('Event');
- evt.initEvent('move', true, true);
-
- evt.to = toEl;
- evt.from = fromEl;
- evt.dragged = dragEl;
- evt.draggedRect = dragRect;
- evt.related = targetEl || toEl;
- evt.relatedRect = targetRect || toEl.getBoundingClientRect();
-
- fromEl.dispatchEvent(evt);
-
- if (onMoveFn) {
- retVal = onMoveFn.call(sortable, evt);
- }
-
- return retVal;
- }
-
-
- function _disableDraggable(el) {
- el.draggable = false;
- }
-
-
- function _unsilent() {
- _silent = false;
- }
-
-
- /** @returns {HTMLElement|false} */
- function _ghostIsLast(el, evt) {
- var lastEl = el.lastElementChild,
- rect = lastEl.getBoundingClientRect();
-
- return ((evt.clientY - (rect.top + rect.height) > 5) || (evt.clientX - (rect.right + rect.width) > 5)) && lastEl; // min delta
- }
-
-
- /**
- * Generate id
- * @param {HTMLElement} el
- * @returns {String}
- * @private
- */
- function _generateId(el) {
- var str = el.tagName + el.className + el.src + el.href + el.textContent,
- i = str.length,
- sum = 0;
-
- while (i--) {
- sum += str.charCodeAt(i);
- }
-
- return sum.toString(36);
- }
-
- /**
- * Returns the index of an element within its parent for a selected set of
- * elements
- * @param {HTMLElement} el
- * @param {selector} selector
- * @return {number}
- */
- function _index(el, selector) {
- var index = 0;
-
- if (!el || !el.parentNode) {
- return -1;
- }
-
- while (el && (el = el.previousElementSibling)) {
- if (el.nodeName.toUpperCase() !== 'TEMPLATE'
- && _matches(el, selector)) {
- index++;
- }
- }
-
- return index;
- }
-
- function _matches(/**HTMLElement*/el, /**String*/selector) {
- if (el) {
- selector = selector.split('.');
-
- var tag = selector.shift().toUpperCase(),
- re = new RegExp('\\s(' + selector.join('|') + ')(?=\\s)', 'g');
-
- return (
- (tag === '' || el.nodeName.toUpperCase() == tag) &&
- (!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length)
- );
- }
-
- return false;
- }
-
- function _throttle(callback, ms) {
- var args, _this;
-
- return function () {
- if (args === void 0) {
- args = arguments;
- _this = this;
-
- setTimeout(function () {
- if (args.length === 1) {
- callback.call(_this, args[0]);
- } else {
- callback.apply(_this, args);
- }
-
- args = void 0;
- }, ms);
- }
- };
- }
-
- function _extend(dst, src) {
- if (dst && src) {
- for (var key in src) {
- if (src.hasOwnProperty(key)) {
- dst[key] = src[key];
- }
- }
- }
-
- return dst;
- }
-
-
- // Export utils
- Sortable.utils = {
- on: _on,
- off: _off,
- css: _css,
- find: _find,
- is: function (el, selector) {
- return !!_closest(el, selector, el);
- },
- extend: _extend,
- throttle: _throttle,
- closest: _closest,
- toggleClass: _toggleClass,
- index: _index
- };
-
-
- /**
- * Create sortable instance
- * @param {HTMLElement} el
- * @param {Object} [options]
- */
- Sortable.create = function (el, options) {
- return new Sortable(el, options);
- };
-
-
- // Export
- Sortable.version = '1.4.2';
- return Sortable;
-});
\ No newline at end of file
diff --git a/src/js/lib/blowfish.dojo.js b/src/js/lib/blowfish.dojo.js
deleted file mode 100755
index af81ef7c..00000000
--- a/src/js/lib/blowfish.dojo.js
+++ /dev/null
@@ -1,649 +0,0 @@
-/** @license
-========================================================================
- Blowfish.js from Dojo Toolkit 1.8.1
- Cut of by Sladex (xslade@gmail.com)
-
- Created based on the C# implementation by Marcus Hahn (http://www.hotpixel.net/)
- Unsigned math based on Paul Johnstone and Peter Wood patches.
- 2005-12-08
-
- The Dojo Toolkit (including this package) is dual licensed under BSD 3-Clause and AFL.
- The Dojo Toolkit is Copyright (c) 2005-2016, The Dojo Foundation. All rights reserved.
-*/
-
-
-/*
- * Blowfish.js from Dojo Toolkit 1.8.1
- * Cut of by Sladex (xslade@gmail.com)
- *
- * Usage:
- * blowfish.encrypt(String 'subj to encrypt', String 'key', Object {outputType: 1, cipherMode: 0});
- *
- */
-
-
-(function(global){
-
-var crypto = {};
-
-
-
-/* dojo-release-1.8.1/dojox/encoding/crypto/_base.js.uncompressed.js */
-
-crypto.cipherModes = {
- // summary:
- // Enumeration for various cipher modes.
- ECB:0, CBC:1, PCBC:2, CFB:3, OFB:4, CTR:5
-};
-crypto.outputTypes = {
- // summary:
- // Enumeration for input and output encodings.
- Base64:0, Hex:1, String:2, Raw:3
-};
-
-
-
-/* dojo-release-1.8.1/dojox/encoding/base64.js.uncompressed.js */
-
-var base64 = {};
-var p="=";
-var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-base64.encode=function(/* byte[] */ba){
- // summary:
- // Encode an array of bytes as a base64-encoded string
- var s=[], l=ba.length;
- var rm=l%3;
- var x=l-rm;
- for (var i=0; i>>18)&0x3f));
- s.push(tab.charAt((t>>>12)&0x3f));
- s.push(tab.charAt((t>>>6)&0x3f));
- s.push(tab.charAt(t&0x3f));
- }
- // deal with trailers, based on patch from Peter Wood.
- switch(rm){
- case 2:{
- var t=ba[i++]<<16|ba[i++]<<8;
- s.push(tab.charAt((t>>>18)&0x3f));
- s.push(tab.charAt((t>>>12)&0x3f));
- s.push(tab.charAt((t>>>6)&0x3f));
- s.push(p);
- break;
- }
- case 1:{
- var t=ba[i++]<<16;
- s.push(tab.charAt((t>>>18)&0x3f));
- s.push(tab.charAt((t>>>12)&0x3f));
- s.push(p);
- s.push(p);
- break;
- }
- }
- return s.join(""); // string
-};
-
-base64.decode=function(/* string */str){
- // summary:
- // Convert a base64-encoded string to an array of bytes
- var s=str.split(""), out=[];
- var l=s.length;
- while(s[--l]==p){ } // strip off trailing padding
- for (var i=0; i>>16)&0xff);
- out.push((t>>>8)&0xff);
- out.push(t&0xff);
- }
- // strip off any null bytes
- while(out[out.length-1]==0){ out.pop(); }
- return out; // byte[]
-};
-
-
-
-/* dojo-release-1.8.1/dojo/_base/lang.js.uncompressed.js */
-
-var lang = {};
-lang.isString = function(it){
- // summary:
- // Return true if it is a String
- // it: anything
- // Item to test.
- return (typeof it == "string" || it instanceof String); // Boolean
-};
-
-
-
-/* dojo-release-1.8.1/dojo/_base/array.js.uncompressed.js */
-
-var arrayUtil = {};
-arrayUtil.map = function(arr, callback, thisObject, Ctr){
- // summary:
- // applies callback to each element of arr and returns
- // an Array with the results
- // arr: Array|String
- // the array to iterate on. If a string, operates on
- // individual characters.
- // callback: Function|String
- // a function is invoked with three arguments, (item, index,
- // array), and returns a value
- // thisObject: Object?
- // may be used to scope the call to callback
- // returns: Array
- // description:
- // This function corresponds to the JavaScript 1.6 Array.map() method, with one difference: when
- // run over sparse arrays, this implementation passes the "holes" in the sparse array to
- // the callback function with a value of undefined. JavaScript 1.6's map skips the holes in the sparse array.
- // For more details, see:
- // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
- // example:
- // | // returns [2, 3, 4, 5]
- // | array.map([1, 2, 3, 4], function(item){ return item+1 });
-
- // TODO: why do we have a non-standard signature here? do we need "Ctr"?
- var i = 0, l = arr && arr.length || 0, out = new (Ctr || Array)(l);
- if(l && typeof arr == "string") arr = arr.split("");
- if(typeof callback == "string") callback = cache[callback] || buildFn(callback);
- if(thisObject){
- for(; i < l; ++i){
- out[i] = callback.call(thisObject, arr[i], i, arr);
- }
- }else{
- for(; i < l; ++i){
- out[i] = callback(arr[i], i, arr);
- }
- }
- return out; // Array
-};
-
-
-
-/* dojo-release-1.8.1/dojox/encoding/crypto/Blowfish.js.uncompressed.js */
-
-/* Blowfish
- * Created based on the C# implementation by Marcus Hahn (http://www.hotpixel.net/)
- * Unsigned math based on Paul Johnstone and Peter Wood patches.
- * 2005-12-08
- */
-crypto.Blowfish = new function(){
- // summary:
- // Object for doing Blowfish encryption/decryption.
- var POW2=Math.pow(2,2);
- var POW3=Math.pow(2,3);
- var POW4=Math.pow(2,4);
- var POW8=Math.pow(2,8);
- var POW16=Math.pow(2,16);
- var POW24=Math.pow(2,24);
- var iv=null; // CBC mode initialization vector
- var boxes={
- p:[
- 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
- 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
- 0x9216d5d9, 0x8979fb1b
- ],
- s0:[
- 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
- 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
- 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
- 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
- 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
- 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
- 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
- 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
- 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
- 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
- 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
- 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
- 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
- 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
- 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
- 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
- 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
- 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
- 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
- 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
- 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
- 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
- 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
- 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
- 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
- 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
- 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
- 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
- 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
- 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
- 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
- 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
- ],
- s1:[
- 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
- 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
- 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
- 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
- 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
- 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
- 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
- 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
- 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
- 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
- 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
- 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
- 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
- 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
- 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
- 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
- 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
- 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
- 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
- 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
- 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
- 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
- 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
- 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
- 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
- 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
- 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
- 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
- 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
- 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
- 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
- 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
- ],
- s2:[
- 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
- 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
- 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
- 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
- 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
- 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
- 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
- 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
- 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
- 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
- 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
- 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
- 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
- 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
- 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
- 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
- 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
- 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
- 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
- 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
- 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
- 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
- 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
- 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
- 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
- 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
- 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
- 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
- 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
- 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
- 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
- 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
- ],
- s3:[
- 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
- 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
- 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
- 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
- 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
- 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
- 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
- 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
- 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
- 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
- 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
- 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
- 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
- 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
- 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
- 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
- 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
- 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
- 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
- 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
- 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
- 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
- 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
- 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
- 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
- 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
- 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
- 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
- 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
- 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
- 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
- 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
- ]
- }
-////////////////////////////////////////////////////////////////////////////
-// fixes based on patch submitted by Peter Wood (#5791)
- function add(x,y){
- return (((x>>0x10)+(y>>0x10)+(((x&0xffff)+(y&0xffff))>>0x10))<<0x10)|(((x&0xffff)+(y&0xffff))&0xffff);
- }
- function xor(x,y){
- return (((x>>0x10)^(y>>0x10))<<0x10)|(((x&0xffff)^(y&0xffff))&0xffff);
- }
-
- function $(v, box){
- var d=box.s3[v&0xff]; v>>=8;
- var c=box.s2[v&0xff]; v>>=8;
- var b=box.s1[v&0xff]; v>>=8;
- var a=box.s0[v&0xff];
-
- var r = (((a>>0x10)+(b>>0x10)+(((a&0xffff)+(b&0xffff))>>0x10))<<0x10)|(((a&0xffff)+(b&0xffff))&0xffff);
- r = (((r>>0x10)^(c>>0x10))<<0x10)|(((r&0xffff)^(c&0xffff))&0xffff);
- return (((r>>0x10)+(d>>0x10)+(((r&0xffff)+(d&0xffff))>>0x10))<<0x10)|(((r&0xffff)+(d&0xffff))&0xffff);
- }
-////////////////////////////////////////////////////////////////////////////
- function eb(o, box){
- // TODO: see if this can't be made more efficient
- var l=o.left;
- var r=o.right;
- l=xor(l,box.p[0]);
- r=xor(r,xor($(l,box),box.p[1]));
- l=xor(l,xor($(r,box),box.p[2]));
- r=xor(r,xor($(l,box),box.p[3]));
- l=xor(l,xor($(r,box),box.p[4]));
- r=xor(r,xor($(l,box),box.p[5]));
- l=xor(l,xor($(r,box),box.p[6]));
- r=xor(r,xor($(l,box),box.p[7]));
- l=xor(l,xor($(r,box),box.p[8]));
- r=xor(r,xor($(l,box),box.p[9]));
- l=xor(l,xor($(r,box),box.p[10]));
- r=xor(r,xor($(l,box),box.p[11]));
- l=xor(l,xor($(r,box),box.p[12]));
- r=xor(r,xor($(l,box),box.p[13]));
- l=xor(l,xor($(r,box),box.p[14]));
- r=xor(r,xor($(l,box),box.p[15]));
- l=xor(l,xor($(r,box),box.p[16]));
- o.right=l;
- o.left=xor(r,box.p[17]);
- }
-
- function db(o, box){
- var l=o.left;
- var r=o.right;
- l=xor(l,box.p[17]);
- r=xor(r,xor($(l,box),box.p[16]));
- l=xor(l,xor($(r,box),box.p[15]));
- r=xor(r,xor($(l,box),box.p[14]));
- l=xor(l,xor($(r,box),box.p[13]));
- r=xor(r,xor($(l,box),box.p[12]));
- l=xor(l,xor($(r,box),box.p[11]));
- r=xor(r,xor($(l,box),box.p[10]));
- l=xor(l,xor($(r,box),box.p[9]));
- r=xor(r,xor($(l,box),box.p[8]));
- l=xor(l,xor($(r,box),box.p[7]));
- r=xor(r,xor($(l,box),box.p[6]));
- l=xor(l,xor($(r,box),box.p[5]));
- r=xor(r,xor($(l,box),box.p[4]));
- l=xor(l,xor($(r,box),box.p[3]));
- r=xor(r,xor($(l,box),box.p[2]));
- l=xor(l,xor($(r,box),box.p[1]));
- o.right=l;
- o.left=xor(r,box.p[0]);
- }
-
- // Note that we aren't caching contexts here; it might take a little longer
- // but we should be more secure this way.
- function init(key){
- var k=key;
- if(lang.isString(k)){
- k = arrayUtil.map(k.split(""), function(item){
- return item.charCodeAt(0) & 0xff;
- });
- }
-
- // init the boxes
- var pos=0, data=0, res={ left:0, right:0 }, i, j, l;
- var box = {
- p: arrayUtil.map(boxes.p.slice(0), function(item){
- var l=k.length, j;
- for(j=0; j<4; j++){ data=(data*POW8)|k[pos++ % l]; }
- return (((item>>0x10)^(data>>0x10))<<0x10)|(((item&0xffff)^(data&0xffff))&0xffff);
- }),
- s0:boxes.s0.slice(0),
- s1:boxes.s1.slice(0),
- s2:boxes.s2.slice(0),
- s3:boxes.s3.slice(0)
- };
-
- // encrypt p and the s boxes
- for(i=0, l=box.p.length; i> 3, pos=0, o={}, isCBC=(mode==crypto.cipherModes.CBC);
- var vector={left:iv.left||null, right:iv.right||null};
- for(var i=0; i>0x10)^(vector.left>>0x10))<<0x10)|(((o.left&0xffff)^(vector.left&0xffff))&0xffff);
- o.right=(((o.right>>0x10)^(vector.right>>0x10))<<0x10)|(((o.right&0xffff)^(vector.right&0xffff))&0xffff);
- }
-
- eb(o, bx); // encrypt the block
-
- if(isCBC){
- vector.left=o.left;
- vector.right=o.right;
- }
-
- cipher.push((o.left>>24)&0xff);
- cipher.push((o.left>>16)&0xff);
- cipher.push((o.left>>8)&0xff);
- cipher.push(o.left&0xff);
- cipher.push((o.right>>24)&0xff);
- cipher.push((o.right>>16)&0xff);
- cipher.push((o.right>>8)&0xff);
- cipher.push(o.right&0xff);
- pos+=8;
- }
-
- switch(out){
- case crypto.outputTypes.Hex:{
- return arrayUtil.map(cipher, function(item){
- return (item<=0xf?'0':'')+item.toString(16);
- }).join(""); // string
- }
- case crypto.outputTypes.String:{
- return cipher.join(""); // string
- }
- case crypto.outputTypes.Raw:{
- return cipher; // array
- }
- default:{
- return base64.encode(cipher); // string
- }
- }
- };
-
- this.decrypt = function(/* string */ciphertext, /* string */key, /* object? */ao){
- // summary:
- // decrypts ciphertext using key; allows specification of how ciphertext is encoded via ao.
- var ip=crypto.outputTypes.Base64;
- var mode=crypto.cipherModes.ECB;
- if (ao){
- if (ao.outputType) ip=ao.outputType;
- if (ao.cipherMode) mode=ao.cipherMode;
- }
- var bx = init(key);
- var pt=[];
-
- var c=null;
- switch(ip){
- case crypto.outputTypes.Hex:{
- c = [];
- for(var i=0, l=ciphertext.length-1; i> 3, pos=0, o={}, isCBC=(mode==crypto.cipherModes.CBC);
- var vector={left:iv.left||null, right:iv.right||null};
- for(var i=0; i>0x10)^(vector.left>>0x10))<<0x10)|(((o.left&0xffff)^(vector.left&0xffff))&0xffff);
- o.right=(((o.right>>0x10)^(vector.right>>0x10))<<0x10)|(((o.right&0xffff)^(vector.right&0xffff))&0xffff);
- vector.left=left;
- vector.right=right;
- }
-
- pt.push((o.left>>24)&0xff);
- pt.push((o.left>>16)&0xff);
- pt.push((o.left>>8)&0xff);
- pt.push(o.left&0xff);
- pt.push((o.right>>24)&0xff);
- pt.push((o.right>>16)&0xff);
- pt.push((o.right>>8)&0xff);
- pt.push(o.right&0xff);
- pos+=8;
- }
-
- // check for padding, and remove.
- if(pt[pt.length-1]==pt[pt.length-2]||pt[pt.length-1]==0x01){
- var n=pt[pt.length-1];
- pt.splice(pt.length-n, n);
- }
-
- // convert to string
- return arrayUtil.map(pt, function(item){
- return String.fromCharCode(item);
- }).join(""); // string
- };
-
- this.setIV("0000000000000000", crypto.outputTypes.Hex);
-}();
-
-
-
-if (typeof exports != 'undefined') {
- exports.blowfish = crypto.Blowfish;
-} else {
- global.blowfish = crypto.Blowfish;
-}
-
-}(this));
\ No newline at end of file
diff --git a/src/js/lib/bootstrap-3.3.6.js b/src/js/lib/bootstrap-3.3.6.js
deleted file mode 100755
index a8a273d1..00000000
--- a/src/js/lib/bootstrap-3.3.6.js
+++ /dev/null
@@ -1,2372 +0,0 @@
-/** @license
-========================================================================
- Bootstrap v3.3.6 (http://getbootstrap.com)
- Copyright 2011-2016 Twitter, Inc.
- Licensed under the MIT license
-*/
-
-if (typeof jQuery === 'undefined') {
- throw new Error('Bootstrap\'s JavaScript requires jQuery')
-}
-
-+function ($) {
- 'use strict';
- var version = $.fn.jquery.split(' ')[0].split('.')
- if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 2)) {
- throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3')
- }
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: transition.js v3.3.6
- * http://getbootstrap.com/javascript/#transitions
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
- // ============================================================
-
- function transitionEnd() {
- var el = document.createElement('bootstrap')
-
- var transEndEventNames = {
- WebkitTransition : 'webkitTransitionEnd',
- MozTransition : 'transitionend',
- OTransition : 'oTransitionEnd otransitionend',
- transition : 'transitionend'
- }
-
- for (var name in transEndEventNames) {
- if (el.style[name] !== undefined) {
- return { end: transEndEventNames[name] }
- }
- }
-
- return false // explicit for ie8 ( ._.)
- }
-
- // http://blog.alexmaccaw.com/css-transitions
- $.fn.emulateTransitionEnd = function (duration) {
- var called = false
- var $el = this
- $(this).one('bsTransitionEnd', function () { called = true })
- var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
- setTimeout(callback, duration)
- return this
- }
-
- $(function () {
- $.support.transition = transitionEnd()
-
- if (!$.support.transition) return
-
- $.event.special.bsTransitionEnd = {
- bindType: $.support.transition.end,
- delegateType: $.support.transition.end,
- handle: function (e) {
- if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
- }
- }
- })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: alert.js v3.3.6
- * http://getbootstrap.com/javascript/#alerts
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // ALERT CLASS DEFINITION
- // ======================
-
- var dismiss = '[data-dismiss="alert"]'
- var Alert = function (el) {
- $(el).on('click', dismiss, this.close)
- }
-
- Alert.VERSION = '3.3.6'
-
- Alert.TRANSITION_DURATION = 150
-
- Alert.prototype.close = function (e) {
- var $this = $(this)
- var selector = $this.attr('data-target')
-
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
- }
-
- var $parent = $(selector)
-
- if (e) e.preventDefault()
-
- if (!$parent.length) {
- $parent = $this.closest('.alert')
- }
-
- $parent.trigger(e = $.Event('close.bs.alert'))
-
- if (e.isDefaultPrevented()) return
-
- $parent.removeClass('in')
-
- function removeElement() {
- // detach from parent, fire event then clean up data
- $parent.detach().trigger('closed.bs.alert').remove()
- }
-
- $.support.transition && $parent.hasClass('fade') ?
- $parent
- .one('bsTransitionEnd', removeElement)
- .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
- removeElement()
- }
-
-
- // ALERT PLUGIN DEFINITION
- // =======================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.alert')
-
- if (!data) $this.data('bs.alert', (data = new Alert(this)))
- if (typeof option == 'string') data[option].call($this)
- })
- }
-
- var old = $.fn.alert
-
- $.fn.alert = Plugin
- $.fn.alert.Constructor = Alert
-
-
- // ALERT NO CONFLICT
- // =================
-
- $.fn.alert.noConflict = function () {
- $.fn.alert = old
- return this
- }
-
-
- // ALERT DATA-API
- // ==============
-
- $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: button.js v3.3.6
- * http://getbootstrap.com/javascript/#buttons
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // BUTTON PUBLIC CLASS DEFINITION
- // ==============================
-
- var Button = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, Button.DEFAULTS, options)
- this.isLoading = false
- }
-
- Button.VERSION = '3.3.6'
-
- Button.DEFAULTS = {
- loadingText: 'loading...'
- }
-
- Button.prototype.setState = function (state) {
- var d = 'disabled'
- var $el = this.$element
- var val = $el.is('input') ? 'val' : 'html'
- var data = $el.data()
-
- state += 'Text'
-
- if (data.resetText == null) $el.data('resetText', $el[val]())
-
- // push to event loop to allow forms to submit
- setTimeout($.proxy(function () {
- $el[val](data[state] == null ? this.options[state] : data[state])
-
- if (state == 'loadingText') {
- this.isLoading = true
- $el.addClass(d).attr(d, d)
- } else if (this.isLoading) {
- this.isLoading = false
- $el.removeClass(d).removeAttr(d)
- }
- }, this), 0)
- }
-
- Button.prototype.toggle = function () {
- var changed = true
- var $parent = this.$element.closest('[data-toggle="buttons"]')
-
- if ($parent.length) {
- var $input = this.$element.find('input')
- if ($input.prop('type') == 'radio') {
- if ($input.prop('checked')) changed = false
- $parent.find('.active').removeClass('active')
- this.$element.addClass('active')
- } else if ($input.prop('type') == 'checkbox') {
- if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
- this.$element.toggleClass('active')
- }
- $input.prop('checked', this.$element.hasClass('active'))
- if (changed) $input.trigger('change')
- } else {
- this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
- this.$element.toggleClass('active')
- }
- }
-
-
- // BUTTON PLUGIN DEFINITION
- // ========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.button')
- var options = typeof option == 'object' && option
-
- if (!data) $this.data('bs.button', (data = new Button(this, options)))
-
- if (option == 'toggle') data.toggle()
- else if (option) data.setState(option)
- })
- }
-
- var old = $.fn.button
-
- $.fn.button = Plugin
- $.fn.button.Constructor = Button
-
-
- // BUTTON NO CONFLICT
- // ==================
-
- $.fn.button.noConflict = function () {
- $.fn.button = old
- return this
- }
-
-
- // BUTTON DATA-API
- // ===============
-
- $(document)
- .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
- var $btn = $(e.target).closest('.btn')
- Plugin.call($btn, 'toggle')
- if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
- // Prevent double click on radios, and the double selections (so cancellation) on checkboxes
- e.preventDefault()
- // The target component still receive the focus
- if ($btn.is('input,button')) $btn.trigger('focus')
- else $btn.find('input:visible,button:visible').first().trigger('focus')
- }
- })
- .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
- $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
- })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: carousel.js v3.3.6
- * http://getbootstrap.com/javascript/#carousel
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // CAROUSEL CLASS DEFINITION
- // =========================
-
- var Carousel = function (element, options) {
- this.$element = $(element)
- this.$indicators = this.$element.find('.carousel-indicators')
- this.options = options
- this.paused = null
- this.sliding = null
- this.interval = null
- this.$active = null
- this.$items = null
-
- this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
-
- this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
- .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
- .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
- }
-
- Carousel.VERSION = '3.3.6'
-
- Carousel.TRANSITION_DURATION = 600
-
- Carousel.DEFAULTS = {
- interval: 5000,
- pause: 'hover',
- wrap: true,
- keyboard: true
- }
-
- Carousel.prototype.keydown = function (e) {
- if (/input|textarea/i.test(e.target.tagName)) return
- switch (e.which) {
- case 37: this.prev(); break
- case 39: this.next(); break
- default: return
- }
-
- e.preventDefault()
- }
-
- Carousel.prototype.cycle = function (e) {
- e || (this.paused = false)
-
- this.interval && clearInterval(this.interval)
-
- this.options.interval
- && !this.paused
- && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
-
- return this
- }
-
- Carousel.prototype.getItemIndex = function (item) {
- this.$items = item.parent().children('.item')
- return this.$items.index(item || this.$active)
- }
-
- Carousel.prototype.getItemForDirection = function (direction, active) {
- var activeIndex = this.getItemIndex(active)
- var willWrap = (direction == 'prev' && activeIndex === 0)
- || (direction == 'next' && activeIndex == (this.$items.length - 1))
- if (willWrap && !this.options.wrap) return active
- var delta = direction == 'prev' ? -1 : 1
- var itemIndex = (activeIndex + delta) % this.$items.length
- return this.$items.eq(itemIndex)
- }
-
- Carousel.prototype.to = function (pos) {
- var that = this
- var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
-
- if (pos > (this.$items.length - 1) || pos < 0) return
-
- if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
- if (activeIndex == pos) return this.pause().cycle()
-
- return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
- }
-
- Carousel.prototype.pause = function (e) {
- e || (this.paused = true)
-
- if (this.$element.find('.next, .prev').length && $.support.transition) {
- this.$element.trigger($.support.transition.end)
- this.cycle(true)
- }
-
- this.interval = clearInterval(this.interval)
-
- return this
- }
-
- Carousel.prototype.next = function () {
- if (this.sliding) return
- return this.slide('next')
- }
-
- Carousel.prototype.prev = function () {
- if (this.sliding) return
- return this.slide('prev')
- }
-
- Carousel.prototype.slide = function (type, next) {
- var $active = this.$element.find('.item.active')
- var $next = next || this.getItemForDirection(type, $active)
- var isCycling = this.interval
- var direction = type == 'next' ? 'left' : 'right'
- var that = this
-
- if ($next.hasClass('active')) return (this.sliding = false)
-
- var relatedTarget = $next[0]
- var slideEvent = $.Event('slide.bs.carousel', {
- relatedTarget: relatedTarget,
- direction: direction
- })
- this.$element.trigger(slideEvent)
- if (slideEvent.isDefaultPrevented()) return
-
- this.sliding = true
-
- isCycling && this.pause()
-
- if (this.$indicators.length) {
- this.$indicators.find('.active').removeClass('active')
- var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
- $nextIndicator && $nextIndicator.addClass('active')
- }
-
- var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
- if ($.support.transition && this.$element.hasClass('slide')) {
- $next.addClass(type)
- $next[0].offsetWidth // force reflow
- $active.addClass(direction)
- $next.addClass(direction)
- $active
- .one('bsTransitionEnd', function () {
- $next.removeClass([type, direction].join(' ')).addClass('active')
- $active.removeClass(['active', direction].join(' '))
- that.sliding = false
- setTimeout(function () {
- that.$element.trigger(slidEvent)
- }, 0)
- })
- .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
- } else {
- $active.removeClass('active')
- $next.addClass('active')
- this.sliding = false
- this.$element.trigger(slidEvent)
- }
-
- isCycling && this.cycle()
-
- return this
- }
-
-
- // CAROUSEL PLUGIN DEFINITION
- // ==========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.carousel')
- var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
- var action = typeof option == 'string' ? option : options.slide
-
- if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
- if (typeof option == 'number') data.to(option)
- else if (action) data[action]()
- else if (options.interval) data.pause().cycle()
- })
- }
-
- var old = $.fn.carousel
-
- $.fn.carousel = Plugin
- $.fn.carousel.Constructor = Carousel
-
-
- // CAROUSEL NO CONFLICT
- // ====================
-
- $.fn.carousel.noConflict = function () {
- $.fn.carousel = old
- return this
- }
-
-
- // CAROUSEL DATA-API
- // =================
-
- var clickHandler = function (e) {
- var href
- var $this = $(this)
- var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
- if (!$target.hasClass('carousel')) return
- var options = $.extend({}, $target.data(), $this.data())
- var slideIndex = $this.attr('data-slide-to')
- if (slideIndex) options.interval = false
-
- Plugin.call($target, options)
-
- if (slideIndex) {
- $target.data('bs.carousel').to(slideIndex)
- }
-
- e.preventDefault()
- }
-
- $(document)
- .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
- .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
-
- $(window).on('load', function () {
- $('[data-ride="carousel"]').each(function () {
- var $carousel = $(this)
- Plugin.call($carousel, $carousel.data())
- })
- })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: collapse.js v3.3.6
- * http://getbootstrap.com/javascript/#collapse
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-/* jshint latedef: false */
-
-+function ($) {
- 'use strict';
-
- // COLLAPSE PUBLIC CLASS DEFINITION
- // ================================
-
- var Collapse = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, Collapse.DEFAULTS, options)
- this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
- '[data-toggle="collapse"][data-target="#' + element.id + '"]')
- this.transitioning = null
-
- if (this.options.parent) {
- this.$parent = this.getParent()
- } else {
- this.addAriaAndCollapsedClass(this.$element, this.$trigger)
- }
-
- if (this.options.toggle) this.toggle()
- }
-
- Collapse.VERSION = '3.3.6'
-
- Collapse.TRANSITION_DURATION = 350
-
- Collapse.DEFAULTS = {
- toggle: true
- }
-
- Collapse.prototype.dimension = function () {
- var hasWidth = this.$element.hasClass('width')
- return hasWidth ? 'width' : 'height'
- }
-
- Collapse.prototype.show = function () {
- if (this.transitioning || this.$element.hasClass('in')) return
-
- var activesData
- var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
-
- if (actives && actives.length) {
- activesData = actives.data('bs.collapse')
- if (activesData && activesData.transitioning) return
- }
-
- var startEvent = $.Event('show.bs.collapse')
- this.$element.trigger(startEvent)
- if (startEvent.isDefaultPrevented()) return
-
- if (actives && actives.length) {
- Plugin.call(actives, 'hide')
- activesData || actives.data('bs.collapse', null)
- }
-
- var dimension = this.dimension()
-
- this.$element
- .removeClass('collapse')
- .addClass('collapsing')[dimension](0)
- .attr('aria-expanded', true)
-
- this.$trigger
- .removeClass('collapsed')
- .attr('aria-expanded', true)
-
- this.transitioning = 1
-
- var complete = function () {
- this.$element
- .removeClass('collapsing')
- .addClass('collapse in')[dimension]('')
- this.transitioning = 0
- this.$element
- .trigger('shown.bs.collapse')
- }
-
- if (!$.support.transition) return complete.call(this)
-
- var scrollSize = $.camelCase(['scroll', dimension].join('-'))
-
- this.$element
- .one('bsTransitionEnd', $.proxy(complete, this))
- .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
- }
-
- Collapse.prototype.hide = function () {
- if (this.transitioning || !this.$element.hasClass('in')) return
-
- var startEvent = $.Event('hide.bs.collapse')
- this.$element.trigger(startEvent)
- if (startEvent.isDefaultPrevented()) return
-
- var dimension = this.dimension()
-
- this.$element[dimension](this.$element[dimension]())[0].offsetHeight
-
- this.$element
- .addClass('collapsing')
- .removeClass('collapse in')
- .attr('aria-expanded', false)
-
- this.$trigger
- .addClass('collapsed')
- .attr('aria-expanded', false)
-
- this.transitioning = 1
-
- var complete = function () {
- this.transitioning = 0
- this.$element
- .removeClass('collapsing')
- .addClass('collapse')
- .trigger('hidden.bs.collapse')
- }
-
- if (!$.support.transition) return complete.call(this)
-
- this.$element
- [dimension](0)
- .one('bsTransitionEnd', $.proxy(complete, this))
- .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
- }
-
- Collapse.prototype.toggle = function () {
- this[this.$element.hasClass('in') ? 'hide' : 'show']()
- }
-
- Collapse.prototype.getParent = function () {
- return $(this.options.parent)
- .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
- .each($.proxy(function (i, element) {
- var $element = $(element)
- this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
- }, this))
- .end()
- }
-
- Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
- var isOpen = $element.hasClass('in')
-
- $element.attr('aria-expanded', isOpen)
- $trigger
- .toggleClass('collapsed', !isOpen)
- .attr('aria-expanded', isOpen)
- }
-
- function getTargetFromTrigger($trigger) {
- var href
- var target = $trigger.attr('data-target')
- || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
-
- return $(target)
- }
-
-
- // COLLAPSE PLUGIN DEFINITION
- // ==========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.collapse')
- var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
-
- if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
- if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- var old = $.fn.collapse
-
- $.fn.collapse = Plugin
- $.fn.collapse.Constructor = Collapse
-
-
- // COLLAPSE NO CONFLICT
- // ====================
-
- $.fn.collapse.noConflict = function () {
- $.fn.collapse = old
- return this
- }
-
-
- // COLLAPSE DATA-API
- // =================
-
- $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
- var $this = $(this)
-
- if (!$this.attr('data-target')) e.preventDefault()
-
- var $target = getTargetFromTrigger($this)
- var data = $target.data('bs.collapse')
- var option = data ? 'toggle' : $this.data()
-
- Plugin.call($target, option)
- })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: dropdown.js v3.3.6
- * http://getbootstrap.com/javascript/#dropdowns
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // DROPDOWN CLASS DEFINITION
- // =========================
-
- var backdrop = '.dropdown-backdrop'
- var toggle = '[data-toggle="dropdown"]'
- var Dropdown = function (element) {
- $(element).on('click.bs.dropdown', this.toggle)
- }
-
- Dropdown.VERSION = '3.3.6'
-
- function getParent($this) {
- var selector = $this.attr('data-target')
-
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
- }
-
- var $parent = selector && $(selector)
-
- return $parent && $parent.length ? $parent : $this.parent()
- }
-
- function clearMenus(e) {
- if (e && e.which === 3) return
- $(backdrop).remove()
- $(toggle).each(function () {
- var $this = $(this)
- var $parent = getParent($this)
- var relatedTarget = { relatedTarget: this }
-
- if (!$parent.hasClass('open')) return
-
- if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
-
- $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
-
- if (e.isDefaultPrevented()) return
-
- $this.attr('aria-expanded', 'false')
- $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
- })
- }
-
- Dropdown.prototype.toggle = function (e) {
- var $this = $(this)
-
- if ($this.is('.disabled, :disabled')) return
-
- var $parent = getParent($this)
- var isActive = $parent.hasClass('open')
-
- clearMenus()
-
- if (!isActive) {
- if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
- // if mobile we use a backdrop because click events don't delegate
- $(document.createElement('div'))
- .addClass('dropdown-backdrop')
- .insertAfter($(this))
- .on('click', clearMenus)
- }
-
- var relatedTarget = { relatedTarget: this }
- $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
-
- if (e.isDefaultPrevented()) return
-
- $this
- .trigger('focus')
- .attr('aria-expanded', 'true')
-
- $parent
- .toggleClass('open')
- .trigger($.Event('shown.bs.dropdown', relatedTarget))
- }
-
- return false
- }
-
- Dropdown.prototype.keydown = function (e) {
- if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
-
- var $this = $(this)
-
- e.preventDefault()
- e.stopPropagation()
-
- if ($this.is('.disabled, :disabled')) return
-
- var $parent = getParent($this)
- var isActive = $parent.hasClass('open')
-
- if (!isActive && e.which != 27 || isActive && e.which == 27) {
- if (e.which == 27) $parent.find(toggle).trigger('focus')
- return $this.trigger('click')
- }
-
- var desc = ' li:not(.disabled):visible a'
- var $items = $parent.find('.dropdown-menu' + desc)
-
- if (!$items.length) return
-
- var index = $items.index(e.target)
-
- if (e.which == 38 && index > 0) index-- // up
- if (e.which == 40 && index < $items.length - 1) index++ // down
- if (!~index) index = 0
-
- $items.eq(index).trigger('focus')
- }
-
-
- // DROPDOWN PLUGIN DEFINITION
- // ==========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.dropdown')
-
- if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
- if (typeof option == 'string') data[option].call($this)
- })
- }
-
- var old = $.fn.dropdown
-
- $.fn.dropdown = Plugin
- $.fn.dropdown.Constructor = Dropdown
-
-
- // DROPDOWN NO CONFLICT
- // ====================
-
- $.fn.dropdown.noConflict = function () {
- $.fn.dropdown = old
- return this
- }
-
-
- // APPLY TO STANDARD DROPDOWN ELEMENTS
- // ===================================
-
- $(document)
- .on('click.bs.dropdown.data-api', clearMenus)
- .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
- .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
- .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
- .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: modal.js v3.3.6
- * http://getbootstrap.com/javascript/#modals
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // MODAL CLASS DEFINITION
- // ======================
-
- var Modal = function (element, options) {
- this.options = options
- this.$body = $(document.body)
- this.$element = $(element)
- this.$dialog = this.$element.find('.modal-dialog')
- this.$backdrop = null
- this.isShown = null
- this.originalBodyPad = null
- this.scrollbarWidth = 0
- this.ignoreBackdropClick = false
-
- if (this.options.remote) {
- this.$element
- .find('.modal-content')
- .load(this.options.remote, $.proxy(function () {
- this.$element.trigger('loaded.bs.modal')
- }, this))
- }
- }
-
- Modal.VERSION = '3.3.6'
-
- Modal.TRANSITION_DURATION = 300
- Modal.BACKDROP_TRANSITION_DURATION = 150
-
- Modal.DEFAULTS = {
- backdrop: true,
- keyboard: true,
- show: true
- }
-
- Modal.prototype.toggle = function (_relatedTarget) {
- return this.isShown ? this.hide() : this.show(_relatedTarget)
- }
-
- Modal.prototype.show = function (_relatedTarget) {
- var that = this
- var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
-
- this.$element.trigger(e)
-
- if (this.isShown || e.isDefaultPrevented()) return
-
- this.isShown = true
-
- this.checkScrollbar()
- this.setScrollbar()
- this.$body.addClass('modal-open')
-
- this.escape()
- this.resize()
-
- this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
-
- this.$dialog.on('mousedown.dismiss.bs.modal', function () {
- that.$element.one('mouseup.dismiss.bs.modal', function (e) {
- if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
- })
- })
-
- this.backdrop(function () {
- var transition = $.support.transition && that.$element.hasClass('fade')
-
- if (!that.$element.parent().length) {
- that.$element.appendTo(that.$body) // don't move modals dom position
- }
-
- that.$element
- .show()
- .scrollTop(0)
-
- that.adjustDialog()
-
- if (transition) {
- that.$element[0].offsetWidth // force reflow
- }
-
- that.$element.addClass('in')
-
- that.enforceFocus()
-
- var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
-
- transition ?
- that.$dialog // wait for modal to slide in
- .one('bsTransitionEnd', function () {
- that.$element.trigger('focus').trigger(e)
- })
- .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
- that.$element.trigger('focus').trigger(e)
- })
- }
-
- Modal.prototype.hide = function (e) {
- if (e) e.preventDefault()
-
- e = $.Event('hide.bs.modal')
-
- this.$element.trigger(e)
-
- if (!this.isShown || e.isDefaultPrevented()) return
-
- this.isShown = false
-
- this.escape()
- this.resize()
-
- $(document).off('focusin.bs.modal')
-
- this.$element
- .removeClass('in')
- .off('click.dismiss.bs.modal')
- .off('mouseup.dismiss.bs.modal')
-
- this.$dialog.off('mousedown.dismiss.bs.modal')
-
- $.support.transition && this.$element.hasClass('fade') ?
- this.$element
- .one('bsTransitionEnd', $.proxy(this.hideModal, this))
- .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
- this.hideModal()
- }
-
- Modal.prototype.enforceFocus = function () {
- $(document)
- .off('focusin.bs.modal') // guard against infinite focus loop
- .on('focusin.bs.modal', $.proxy(function (e) {
- if (document !== e.target &&
- this.$element[0] !== e.target &&
- !this.$element.has(e.target).length) {
- this.$element.trigger('focus')
- }
- }, this))
- }
-
- Modal.prototype.escape = function () {
- if (this.isShown && this.options.keyboard) {
- this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
- e.which == 27 && this.hide()
- }, this))
- } else if (!this.isShown) {
- this.$element.off('keydown.dismiss.bs.modal')
- }
- }
-
- Modal.prototype.resize = function () {
- if (this.isShown) {
- $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
- } else {
- $(window).off('resize.bs.modal')
- }
- }
-
- Modal.prototype.hideModal = function () {
- var that = this
- this.$element.hide()
- this.backdrop(function () {
- that.$body.removeClass('modal-open')
- that.resetAdjustments()
- that.resetScrollbar()
- that.$element.trigger('hidden.bs.modal')
- })
- }
-
- Modal.prototype.removeBackdrop = function () {
- this.$backdrop && this.$backdrop.remove()
- this.$backdrop = null
- }
-
- Modal.prototype.backdrop = function (callback) {
- var that = this
- var animate = this.$element.hasClass('fade') ? 'fade' : ''
-
- if (this.isShown && this.options.backdrop) {
- var doAnimate = $.support.transition && animate
-
- this.$backdrop = $(document.createElement('div'))
- .addClass('modal-backdrop ' + animate)
- .appendTo(this.$body)
-
- this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
- if (this.ignoreBackdropClick) {
- this.ignoreBackdropClick = false
- return
- }
- if (e.target !== e.currentTarget) return
- this.options.backdrop == 'static'
- ? this.$element[0].focus()
- : this.hide()
- }, this))
-
- if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
-
- this.$backdrop.addClass('in')
-
- if (!callback) return
-
- doAnimate ?
- this.$backdrop
- .one('bsTransitionEnd', callback)
- .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
- callback()
-
- } else if (!this.isShown && this.$backdrop) {
- this.$backdrop.removeClass('in')
-
- var callbackRemove = function () {
- that.removeBackdrop()
- callback && callback()
- }
- $.support.transition && this.$element.hasClass('fade') ?
- this.$backdrop
- .one('bsTransitionEnd', callbackRemove)
- .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
- callbackRemove()
-
- } else if (callback) {
- callback()
- }
- }
-
- // these following methods are used to handle overflowing modals
-
- Modal.prototype.handleUpdate = function () {
- this.adjustDialog()
- }
-
- Modal.prototype.adjustDialog = function () {
- var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
-
- this.$element.css({
- paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
- paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
- })
- }
-
- Modal.prototype.resetAdjustments = function () {
- this.$element.css({
- paddingLeft: '',
- paddingRight: ''
- })
- }
-
- Modal.prototype.checkScrollbar = function () {
- var fullWindowWidth = window.innerWidth
- if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
- var documentElementRect = document.documentElement.getBoundingClientRect()
- fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
- }
- this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
- this.scrollbarWidth = this.measureScrollbar()
- }
-
- Modal.prototype.setScrollbar = function () {
- var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
- this.originalBodyPad = document.body.style.paddingRight || ''
- if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
- }
-
- Modal.prototype.resetScrollbar = function () {
- this.$body.css('padding-right', this.originalBodyPad)
- }
-
- Modal.prototype.measureScrollbar = function () { // thx walsh
- var scrollDiv = document.createElement('div')
- scrollDiv.className = 'modal-scrollbar-measure'
- this.$body.append(scrollDiv)
- var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
- this.$body[0].removeChild(scrollDiv)
- return scrollbarWidth
- }
-
-
- // MODAL PLUGIN DEFINITION
- // =======================
-
- function Plugin(option, _relatedTarget) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.modal')
- var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
-
- if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
- if (typeof option == 'string') data[option](_relatedTarget)
- else if (options.show) data.show(_relatedTarget)
- })
- }
-
- var old = $.fn.modal
-
- $.fn.modal = Plugin
- $.fn.modal.Constructor = Modal
-
-
- // MODAL NO CONFLICT
- // =================
-
- $.fn.modal.noConflict = function () {
- $.fn.modal = old
- return this
- }
-
-
- // MODAL DATA-API
- // ==============
-
- $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
- var $this = $(this)
- var href = $this.attr('href')
- var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
- var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
-
- if ($this.is('a')) e.preventDefault()
-
- $target.one('show.bs.modal', function (showEvent) {
- if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
- $target.one('hidden.bs.modal', function () {
- $this.is(':visible') && $this.trigger('focus')
- })
- })
- Plugin.call($target, option, this)
- })
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: tooltip.js v3.3.6
- * http://getbootstrap.com/javascript/#tooltip
- * Inspired by the original jQuery.tipsy by Jason Frame
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // TOOLTIP PUBLIC CLASS DEFINITION
- // ===============================
-
- var Tooltip = function (element, options) {
- this.type = null
- this.options = null
- this.enabled = null
- this.timeout = null
- this.hoverState = null
- this.$element = null
- this.inState = null
-
- this.init('tooltip', element, options)
- }
-
- Tooltip.VERSION = '3.3.6'
-
- Tooltip.TRANSITION_DURATION = 150
-
- Tooltip.DEFAULTS = {
- animation: true,
- placement: 'top',
- selector: false,
- template: '
',
- trigger: 'hover focus',
- title: '',
- delay: 0,
- html: false,
- container: false,
- viewport: {
- selector: 'body',
- padding: 0
- }
- }
-
- Tooltip.prototype.init = function (type, element, options) {
- this.enabled = true
- this.type = type
- this.$element = $(element)
- this.options = this.getOptions(options)
- this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
- this.inState = { click: false, hover: false, focus: false }
-
- if (this.$element[0] instanceof document.constructor && !this.options.selector) {
- throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
- }
-
- var triggers = this.options.trigger.split(' ')
-
- for (var i = triggers.length; i--;) {
- var trigger = triggers[i]
-
- if (trigger == 'click') {
- this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
- } else if (trigger != 'manual') {
- var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
- var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
-
- this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
- this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
- }
- }
-
- this.options.selector ?
- (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
- this.fixTitle()
- }
-
- Tooltip.prototype.getDefaults = function () {
- return Tooltip.DEFAULTS
- }
-
- Tooltip.prototype.getOptions = function (options) {
- options = $.extend({}, this.getDefaults(), this.$element.data(), options)
-
- if (options.delay && typeof options.delay == 'number') {
- options.delay = {
- show: options.delay,
- hide: options.delay
- }
- }
-
- return options
- }
-
- Tooltip.prototype.getDelegateOptions = function () {
- var options = {}
- var defaults = this.getDefaults()
-
- this._options && $.each(this._options, function (key, value) {
- if (defaults[key] != value) options[key] = value
- })
-
- return options
- }
-
- Tooltip.prototype.enter = function (obj) {
- var self = obj instanceof this.constructor ?
- obj : $(obj.currentTarget).data('bs.' + this.type)
-
- if (!self) {
- self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
- $(obj.currentTarget).data('bs.' + this.type, self)
- }
-
- if (obj instanceof $.Event) {
- self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
- }
-
- if (self.tip().hasClass('in') || self.hoverState == 'in') {
- self.hoverState = 'in'
- return
- }
-
- clearTimeout(self.timeout)
-
- self.hoverState = 'in'
-
- if (!self.options.delay || !self.options.delay.show) return self.show()
-
- self.timeout = setTimeout(function () {
- if (self.hoverState == 'in') self.show()
- }, self.options.delay.show)
- }
-
- Tooltip.prototype.isInStateTrue = function () {
- for (var key in this.inState) {
- if (this.inState[key]) return true
- }
-
- return false
- }
-
- Tooltip.prototype.leave = function (obj) {
- var self = obj instanceof this.constructor ?
- obj : $(obj.currentTarget).data('bs.' + this.type)
-
- if (!self) {
- self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
- $(obj.currentTarget).data('bs.' + this.type, self)
- }
-
- if (obj instanceof $.Event) {
- self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
- }
-
- if (self.isInStateTrue()) return
-
- clearTimeout(self.timeout)
-
- self.hoverState = 'out'
-
- if (!self.options.delay || !self.options.delay.hide) return self.hide()
-
- self.timeout = setTimeout(function () {
- if (self.hoverState == 'out') self.hide()
- }, self.options.delay.hide)
- }
-
- Tooltip.prototype.show = function () {
- var e = $.Event('show.bs.' + this.type)
-
- if (this.hasContent() && this.enabled) {
- this.$element.trigger(e)
-
- var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
- if (e.isDefaultPrevented() || !inDom) return
- var that = this
-
- var $tip = this.tip()
-
- var tipId = this.getUID(this.type)
-
- this.setContent()
- $tip.attr('id', tipId)
- this.$element.attr('aria-describedby', tipId)
-
- if (this.options.animation) $tip.addClass('fade')
-
- var placement = typeof this.options.placement == 'function' ?
- this.options.placement.call(this, $tip[0], this.$element[0]) :
- this.options.placement
-
- var autoToken = /\s?auto?\s?/i
- var autoPlace = autoToken.test(placement)
- if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
-
- $tip
- .detach()
- .css({ top: 0, left: 0, display: 'block' })
- .addClass(placement)
- .data('bs.' + this.type, this)
-
- this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
- this.$element.trigger('inserted.bs.' + this.type)
-
- var pos = this.getPosition()
- var actualWidth = $tip[0].offsetWidth
- var actualHeight = $tip[0].offsetHeight
-
- if (autoPlace) {
- var orgPlacement = placement
- var viewportDim = this.getPosition(this.$viewport)
-
- placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
- placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
- placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
- placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
- placement
-
- $tip
- .removeClass(orgPlacement)
- .addClass(placement)
- }
-
- var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
-
- this.applyPlacement(calculatedOffset, placement)
-
- var complete = function () {
- var prevHoverState = that.hoverState
- that.$element.trigger('shown.bs.' + that.type)
- that.hoverState = null
-
- if (prevHoverState == 'out') that.leave(that)
- }
-
- $.support.transition && this.$tip.hasClass('fade') ?
- $tip
- .one('bsTransitionEnd', complete)
- .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
- complete()
- }
- }
-
- Tooltip.prototype.applyPlacement = function (offset, placement) {
- var $tip = this.tip()
- var width = $tip[0].offsetWidth
- var height = $tip[0].offsetHeight
-
- // manually read margins because getBoundingClientRect includes difference
- var marginTop = parseInt($tip.css('margin-top'), 10)
- var marginLeft = parseInt($tip.css('margin-left'), 10)
-
- // we must check for NaN for ie 8/9
- if (isNaN(marginTop)) marginTop = 0
- if (isNaN(marginLeft)) marginLeft = 0
-
- offset.top += marginTop
- offset.left += marginLeft
-
- // $.fn.offset doesn't round pixel values
- // so we use setOffset directly with our own function B-0
- $.offset.setOffset($tip[0], $.extend({
- using: function (props) {
- $tip.css({
- top: Math.round(props.top),
- left: Math.round(props.left)
- })
- }
- }, offset), 0)
-
- $tip.addClass('in')
-
- // check to see if placing tip in new offset caused the tip to resize itself
- var actualWidth = $tip[0].offsetWidth
- var actualHeight = $tip[0].offsetHeight
-
- if (placement == 'top' && actualHeight != height) {
- offset.top = offset.top + height - actualHeight
- }
-
- var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
-
- if (delta.left) offset.left += delta.left
- else offset.top += delta.top
-
- var isVertical = /top|bottom/.test(placement)
- var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
- var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
-
- $tip.offset(offset)
- this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
- }
-
- Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
- this.arrow()
- .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
- .css(isVertical ? 'top' : 'left', '')
- }
-
- Tooltip.prototype.setContent = function () {
- var $tip = this.tip()
- var title = this.getTitle()
-
- $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
- $tip.removeClass('fade in top bottom left right')
- }
-
- Tooltip.prototype.hide = function (callback) {
- var that = this
- var $tip = $(this.$tip)
- var e = $.Event('hide.bs.' + this.type)
-
- function complete() {
- if (that.hoverState != 'in') $tip.detach()
- that.$element
- .removeAttr('aria-describedby')
- .trigger('hidden.bs.' + that.type)
- callback && callback()
- }
-
- this.$element.trigger(e)
-
- if (e.isDefaultPrevented()) return
-
- $tip.removeClass('in')
-
- $.support.transition && $tip.hasClass('fade') ?
- $tip
- .one('bsTransitionEnd', complete)
- .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
- complete()
-
- this.hoverState = null
-
- return this
- }
-
- Tooltip.prototype.fixTitle = function () {
- var $e = this.$element
- if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
- $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
- }
- }
-
- Tooltip.prototype.hasContent = function () {
- return this.getTitle()
- }
-
- Tooltip.prototype.getPosition = function ($element) {
- $element = $element || this.$element
-
- var el = $element[0]
- var isBody = el.tagName == 'BODY'
-
- var elRect = el.getBoundingClientRect()
- if (elRect.width == null) {
- // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
- elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
- }
- var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
- var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
- var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
-
- return $.extend({}, elRect, scroll, outerDims, elOffset)
- }
-
- Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
- return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
- placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
- placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
- /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
-
- }
-
- Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
- var delta = { top: 0, left: 0 }
- if (!this.$viewport) return delta
-
- var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
- var viewportDimensions = this.getPosition(this.$viewport)
-
- if (/right|left/.test(placement)) {
- var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
- var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
- if (topEdgeOffset < viewportDimensions.top) { // top overflow
- delta.top = viewportDimensions.top - topEdgeOffset
- } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
- delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
- }
- } else {
- var leftEdgeOffset = pos.left - viewportPadding
- var rightEdgeOffset = pos.left + viewportPadding + actualWidth
- if (leftEdgeOffset < viewportDimensions.left) { // left overflow
- delta.left = viewportDimensions.left - leftEdgeOffset
- } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
- delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
- }
- }
-
- return delta
- }
-
- Tooltip.prototype.getTitle = function () {
- var title
- var $e = this.$element
- var o = this.options
-
- title = $e.attr('data-original-title')
- || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
-
- return title
- }
-
- Tooltip.prototype.getUID = function (prefix) {
- do prefix += ~~(Math.random() * 1000000)
- while (document.getElementById(prefix))
- return prefix
- }
-
- Tooltip.prototype.tip = function () {
- if (!this.$tip) {
- this.$tip = $(this.options.template)
- if (this.$tip.length != 1) {
- throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
- }
- }
- return this.$tip
- }
-
- Tooltip.prototype.arrow = function () {
- return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
- }
-
- Tooltip.prototype.enable = function () {
- this.enabled = true
- }
-
- Tooltip.prototype.disable = function () {
- this.enabled = false
- }
-
- Tooltip.prototype.toggleEnabled = function () {
- this.enabled = !this.enabled
- }
-
- Tooltip.prototype.toggle = function (e) {
- var self = this
- if (e) {
- self = $(e.currentTarget).data('bs.' + this.type)
- if (!self) {
- self = new this.constructor(e.currentTarget, this.getDelegateOptions())
- $(e.currentTarget).data('bs.' + this.type, self)
- }
- }
-
- if (e) {
- self.inState.click = !self.inState.click
- if (self.isInStateTrue()) self.enter(self)
- else self.leave(self)
- } else {
- self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
- }
- }
-
- Tooltip.prototype.destroy = function () {
- var that = this
- clearTimeout(this.timeout)
- this.hide(function () {
- that.$element.off('.' + that.type).removeData('bs.' + that.type)
- if (that.$tip) {
- that.$tip.detach()
- }
- that.$tip = null
- that.$arrow = null
- that.$viewport = null
- })
- }
-
-
- // TOOLTIP PLUGIN DEFINITION
- // =========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.tooltip')
- var options = typeof option == 'object' && option
-
- if (!data && /destroy|hide/.test(option)) return
- if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- var old = $.fn.tooltip
-
- $.fn.tooltip = Plugin
- $.fn.tooltip.Constructor = Tooltip
-
-
- // TOOLTIP NO CONFLICT
- // ===================
-
- $.fn.tooltip.noConflict = function () {
- $.fn.tooltip = old
- return this
- }
-
-}(jQuery);
-
-/* ========================================================================
- * Bootstrap: popover.js v3.3.6
- * http://getbootstrap.com/javascript/#popovers
- * ========================================================================
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // POPOVER PUBLIC CLASS DEFINITION
- // ===============================
-
- var Popover = function (element, options) {
- this.init('popover', element, options)
- }
-
- if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
-
- Popover.VERSION = '3.3.6'
-
- Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
- placement: 'right',
- trigger: 'click',
- content: '',
- template: '