summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Faivre <jeremy.faivre@gmail.com>2014-07-22 10:19:12 +0200
committerJeremy Faivre <jeremy.faivre@gmail.com>2014-07-22 10:21:17 +0200
commitc6cbcf0326723c5f0013490d1fea489694790775 (patch)
treefa735c3ee627b64bd546165aed093d1f6cfce055
parentc5a6a8601d31508bb3e5880b310b2918834e89c9 (diff)
downloadyamljs-c6cbcf0326723c5f0013490d1fea489694790775.tar.gz
Improve performances (more than 2 times faster), rewrite in coffee-script, fix various bugs.
This is the first pass of rewrite of the YAML library (in progress). The focus was on improving code readability, make it well-documented and fix most of the current issues. It didn't focus on the performances yet, even though they are better than the previous version. The next big step (not included in this first pass in progress) will focus on removing most RegExps because they are time consuming and they make the code working on a "line by line" basis. The code will move to a "character by character" parsing, allowing us to deeply improve performances, and add new features from the 1.2 Yaml spec.
-rw-r--r--.gitignore5
-rw-r--r--Cakefile117
-rwxr-xr-xbin/json2yaml70
-rw-r--r--bin/yaml.min.js21
-rwxr-xr-xbin/yaml2json89
-rwxr-xr-xbuild58
-rw-r--r--cli/json2yaml.js (renamed from src/cli/json2yaml.js)70
-rw-r--r--cli/yaml2json.js (renamed from src/cli/yaml2json.js)89
-rw-r--r--demo/demo.html11
-rw-r--r--dist/yaml.debug.js1821
-rw-r--r--dist/yaml.js1820
-rw-r--r--dist/yaml.legacy.js (renamed from bin/yaml.js)0
-rw-r--r--dist/yaml.min.js1
-rw-r--r--index.js22
-rw-r--r--lib/Dumper.js46
-rw-r--r--lib/Escaper.js54
-rw-r--r--lib/Exception/DumpException.js27
-rw-r--r--lib/Exception/ParseException.js27
-rw-r--r--lib/Inline.js475
-rw-r--r--lib/Parser.js576
-rw-r--r--lib/Pattern.js119
-rw-r--r--lib/Unescaper.js83
-rw-r--r--lib/Utils.js284
-rw-r--r--lib/Yaml.js98
-rw-r--r--package.json49
-rw-r--r--src/Dumper.coffee46
-rw-r--r--src/Escaper.coffee80
-rw-r--r--src/Exception/DumpException.coffee12
-rw-r--r--src/Exception/ParseException.coffee12
-rw-r--r--src/Inline.coffee485
-rw-r--r--src/Parser.coffee633
-rw-r--r--src/Pattern.coffee144
-rw-r--r--src/Unescaper.coffee96
-rw-r--r--src/Utils.coffee342
-rw-r--r--src/Yaml.coffee113
-rw-r--r--src/yaml/Yaml.js231
-rw-r--r--src/yaml/YamlDumper.js131
-rw-r--r--src/yaml/YamlEscaper.js89
-rw-r--r--src/yaml/YamlInline.js558
-rw-r--r--src/yaml/YamlParseException.js140
-rw-r--r--src/yaml/YamlParser.js807
-rw-r--r--src/yaml/YamlUnescaper.js108
-rwxr-xr-xtest/SpecRunner.html24
-rwxr-xr-x[-rw-r--r--]test/lib/jasmine-2.0.0/MIT.LICENSE (renamed from test/libs/jasmine-1.2.0/MIT.LICENSE)0
-rwxr-xr-xtest/lib/jasmine-2.0.0/boot.js181
-rwxr-xr-xtest/lib/jasmine-2.0.0/console.js160
-rwxr-xr-xtest/lib/jasmine-2.0.0/jasmine-html.js359
-rwxr-xr-xtest/lib/jasmine-2.0.0/jasmine.css55
-rwxr-xr-xtest/lib/jasmine-2.0.0/jasmine.js2402
-rwxr-xr-xtest/lib/jasmine-2.0.0/jasmine_favicon.pngbin0 -> 2057 bytes
-rw-r--r--test/libs/jasmine-1.2.0/YamlSpec.js22
-rw-r--r--test/libs/jasmine-1.2.0/YamlTests.js699
-rw-r--r--test/libs/jasmine-1.2.0/jasmine-html.js616
-rw-r--r--test/libs/jasmine-1.2.0/jasmine.css81
-rw-r--r--test/libs/jasmine-1.2.0/jasmine.js2529
-rw-r--r--test/spec/YamlSpec.coffee76
-rw-r--r--test/spec/YamlSpec.js33
-rw-r--r--test/test.html51
58 files changed, 11062 insertions, 6285 deletions
diff --git a/.gitignore b/.gitignore
index 91dfed8..8da5ccb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
.DS_Store
-node_modules \ No newline at end of file
+node_modules
+/doc/
+
+/lib/debug/
diff --git a/Cakefile b/Cakefile
new file mode 100644
index 0000000..0449803
--- /dev/null
+++ b/Cakefile
@@ -0,0 +1,117 @@
+
+{exec, spawn} = require 'child_process'
+fs = require 'fs'
+path = require 'path'
+esc = (arg) -> (''+arg).replace(/(?=[^a-zA-Z0-9_.\/\-\x7F-\xFF\n])/gm, '\\').replace(/\n/g, "'\n'").replace(/^$/, "''")
+
+srcDir = path.normalize __dirname+'/src'
+libDir = path.normalize __dirname+'/lib'
+libDebugDir = path.normalize __dirname+'/lib/debug'
+distDir = path.normalize __dirname+'/dist'
+cliDir = path.normalize __dirname+'/cli'
+binDir = path.normalize __dirname+'/bin'
+specDir = path.normalize __dirname+'/test/spec'
+modulesDir = path.normalize __dirname+'/node_modules'
+
+task 'build', 'build project', ->
+
+ # Compile
+ do compile = ->
+ unless fs.existsSync libDir
+ fs.mkdirSync libDir
+ unless fs.existsSync libDir+'/Exception'
+ fs.mkdirSync libDir+'/Exception'
+ toCompile = 'Yaml Utils Unescaper Pattern Parser Inline Escaper Dumper Exception/ParseException Exception/DumpException'.split ' '
+ do compileOne = ->
+ name = toCompile.shift()
+ outputDir = (if '/' in name then libDir+'/Exception' else libDir)
+ exec 'coffee -b -o '+esc(outputDir)+' -c '+esc(srcDir+'/'+name+'.coffee'), (err, res) ->
+ if err then throw err
+
+ console.log "Compiled #{name}.js"
+ if toCompile.length
+ compileOne()
+ else
+ debugCompile()
+
+ # Debug compile
+ debugCompile = ->
+ unless fs.existsSync libDebugDir
+ fs.mkdirSync libDebugDir
+ unless fs.existsSync libDebugDir+'/Exception'
+ fs.mkdirSync libDebugDir+'/Exception'
+ toCompile = 'Yaml Utils Unescaper Pattern Parser Inline Escaper Dumper Exception/ParseException Exception/DumpException'.split ' '
+ do compileOne = ->
+ name = toCompile.shift()
+ outputDir = (if '/' in name then libDebugDir+'/Exception' else libDebugDir)
+ exec 'coffee -m -b -o '+esc(outputDir)+' -c '+esc(srcDir+'/'+name+'.coffee'), (err, res) ->
+ if err then throw err
+
+ console.log "Compiled #{name}.js (debug)"
+ if toCompile.length
+ compileOne()
+ else
+ browserify()
+
+ # Browserify
+ unless fs.existsSync distDir
+ fs.mkdirSync distDir
+ browserify = ->
+ exec 'browserify -t coffeeify --extension=".coffee" '+esc(srcDir+'/Yaml.coffee')+' > '+esc(distDir+'/yaml.js'), (err, res) ->
+ if err then throw err
+
+ console.log "Browserified yaml.js"
+ exec 'browserify --debug -t coffeeify --extension=".coffee" '+esc(srcDir+'/Yaml.coffee')+' > '+esc(distDir+'/yaml.debug.js'), (err, res) ->
+ if err then throw err
+
+ console.log "Browserified yaml.js (debug)"
+ minify()
+
+ # Minify
+ minify = ->
+ exec 'uglifyjs --mangle sort '+esc(distDir+'/yaml.js')+' > '+esc(distDir+'/yaml.min.js'), (err, res) ->
+ if err then throw err
+
+ console.log "Minified yaml.min.js"
+ compileSpec()
+
+ # Compile spec
+ compileSpec = ->
+ exec 'coffee -b -c '+esc(specDir+'/YamlSpec.coffee'), (err, res) ->
+ if err then throw err
+
+ console.log "Compiled YamlSpec.js"
+ compileCLI()
+
+ # Compile CLI
+ compileCLI = ->
+ unless fs.existsSync binDir
+ fs.mkdirSync binDir
+
+ # yaml2json
+ str = fs.readFileSync cliDir+'/yaml2json.js'
+ str = "#!/usr/bin/env node\n" + str
+ fs.writeFileSync binDir+'/yaml2json', str
+ fs.chmodSync binDir+'/yaml2json', '755'
+ console.log "Bundled yaml2json"
+
+ # json2yaml
+ str = fs.readFileSync cliDir+'/json2yaml.js'
+ str = "#!/usr/bin/env node\n" + str
+ fs.writeFileSync binDir+'/json2yaml', str
+ fs.chmodSync binDir+'/json2yaml', '755'
+ console.log "Bundled json2yaml"
+
+
+task 'test', 'test project', ->
+
+ # Test
+ spawn 'node', [modulesDir+'/jasmine-node/lib/jasmine-node/cli.js', '--verbose', '--coffee', specDir+'/YamlSpec.coffee'], stdio: "inherit"
+
+
+task 'doc', 'generate documentation', ->
+
+ # Generate
+ spawn 'codo', [srcDir], stdio: "inherit"
+
+
diff --git a/bin/json2yaml b/bin/json2yaml
index 4e92bf8..f0a8791 100755
--- a/bin/json2yaml
+++ b/bin/json2yaml
@@ -4,7 +4,7 @@
* yaml2json cli program
*/
-var YAML = require('./yaml.js');
+var YAML = require('../lib/Yaml.js');
var ArgumentParser = require('argparse').ArgumentParser;
var cli = new ArgumentParser({
@@ -56,7 +56,7 @@ cli.addArgument(
);
cli.addArgument(['input'], {
- help: 'JSON file or directory containing JSON files.'
+ help: 'JSON file or directory containing JSON files or - to read JSON from stdin.'
});
try {
@@ -67,6 +67,7 @@ try {
var rootPath = process.cwd();
var parsePath = function(input) {
+ if (input == '-') return '-';
var output;
if (!(input != null)) {
return rootPath;
@@ -86,33 +87,39 @@ try {
// Find files
var findFiles = function(input) {
- var isDirectory = fs.statSync(input).isDirectory();
- var files = [];
+ if (input != '-' && input != null) {
+ var isDirectory = fs.statSync(input).isDirectory();
+ var files = [];
- if (!isDirectory) {
- files.push(input);
- }
- else {
- if (options.recursive) {
- files = files.concat(glob.sync(input+'/**/*.json'));
+ if (!isDirectory) {
+ files.push(input);
}
else {
- files = files.concat(glob.sync(input+'/*.json'));
+ if (options.recursive) {
+ files = files.concat(glob.sync(input+'/**/*.json'));
+ }
+ else {
+ files = files.concat(glob.sync(input+'/*.json'));
+ }
}
+
+ return files;
}
-
- return files;
+ return null;
};
// Convert to JSON
- var convertToYAML = function(input, inline, save, spaces) {
+ var convertToYAML = function(input, inline, save, spaces, str) {
var yaml;
if (inline == null) inline = 2;
if (spaces == null) spaces = 2;
- yaml = YAML.stringify(JSON.parse(fs.readFileSync(input)), inline, spaces);
+ if (str == null) {
+ str = ''+fs.readFileSync(input);
+ }
+ yaml = YAML.dump(JSON.parse(str), inline, spaces);
- if (!save) {
+ if (!save || input == null) {
// Ouput result
process.stdout.write(yaml);
}
@@ -139,18 +146,29 @@ try {
var runCommand = function() {
try {
var files = findFiles(input);
- var len = files.length;
-
- for (var i = 0; i < len; i++) {
- var file = files[i];
- var stat = fs.statSync(file);
- var time = stat.mtime.getTime();
- if (!stat.isDirectory()) {
- if (!mtimes[file] || mtimes[file] < time) {
- mtimes[file] = time;
- convertToYAML(file, options.depth, options.save, options.indentation);
+ if (files != null) {
+ var len = files.length;
+ for (var i = 0; i < len; i++) {
+ var file = files[i];
+ var stat = fs.statSync(file);
+ var time = stat.mtime.getTime();
+ if (!stat.isDirectory()) {
+ if (!mtimes[file] || mtimes[file] < time) {
+ mtimes[file] = time;
+ convertToYAML(file, options.depth, options.save, options.indentation);
+ }
}
}
+ } else {
+ // Read from STDIN
+ var stdin = process.openStdin();
+ var data = "";
+ stdin.on('data', function(chunk) {
+ data += chunk;
+ });
+ stdin.on('end', function() {
+ convertToYAML(null, options.depth, options.save, options.indentation, data);
+ });
}
} catch (e) {
process.stderr.write((e.message ? e.message : e)+"\n");
diff --git a/bin/yaml.min.js b/bin/yaml.min.js
deleted file mode 100644
index c1440ac..0000000
--- a/bin/yaml.min.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-Copyright (c) 2010 Jeremy Faivre
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
diff --git a/bin/yaml2json b/bin/yaml2json
index 3d9075c..550230c 100755
--- a/bin/yaml2json
+++ b/bin/yaml2json
@@ -4,7 +4,7 @@
* yaml2json cli program
*/
-var YAML = require('./yaml.js');
+var YAML = require('../lib/Yaml.js');
var ArgumentParser = require('argparse').ArgumentParser;
var cli = new ArgumentParser({
@@ -55,7 +55,7 @@ cli.addArgument(
);
cli.addArgument(['input'], {
- help: 'YAML file or directory containing YAML files.'
+ help: 'YAML file or directory containing YAML files or - to read YAML from stdin.'
});
try {
@@ -66,6 +66,7 @@ try {
var rootPath = process.cwd();
var parsePath = function(input) {
+ if (input == '-') return '-';
var output;
if (!(input != null)) {
return rootPath;
@@ -85,38 +86,50 @@ try {
// Find files
var findFiles = function(input) {
- var isDirectory = fs.statSync(input).isDirectory();
- var files = [];
+ if (input != '-' && input != null) {
+ var isDirectory = fs.statSync(input).isDirectory();
+ var files = [];
- if (!isDirectory) {
- files.push(input);
- }
- else {
- if (options.recursive) {
- files = files.concat(glob.sync(input+'/**/*.yml'));
- files = files.concat(glob.sync(input+'/**/*.yaml'));
+ if (!isDirectory) {
+ files.push(input);
}
else {
- files = files.concat(glob.sync(input+'/*.yml'));
- files = files.concat(glob.sync(input+'/*.yaml'));
+ if (options.recursive) {
+ files = files.concat(glob.sync(input+'/**/*.yml'));
+ files = files.concat(glob.sync(input+'/**/*.yaml'));
+ }
+ else {
+ files = files.concat(glob.sync(input+'/*.yml'));
+ files = files.concat(glob.sync(input+'/*.yaml'));
+ }
}
+
+ return files;
}
-
- return files;
+ return null;
};
// Convert to JSON
- var convertToJSON = function(input, pretty, save, spaces) {
+ var convertToJSON = function(input, pretty, save, spaces, str) {
var json;
if (spaces == null) spaces = 2;
- if (pretty) {
- json = JSON.stringify(YAML.load(input), null, spaces);
- }
- else {
- json = JSON.stringify(YAML.load(input));
+ if (str != null) {
+ if (pretty) {
+ json = JSON.stringify(YAML.parse(str), null, spaces);
+ }
+ else {
+ json = JSON.stringify(YAML.parse(str));
+ }
+ } else {
+ if (pretty) {
+ json = JSON.stringify(YAML.parseFile(input), null, spaces);
+ }
+ else {
+ json = JSON.stringify(YAML.parseFile(input));
+ }
}
- if (!save) {
+ if (!save || input == null) {
// Ouput result
process.stdout.write(json+"\n");
}
@@ -146,18 +159,30 @@ try {
var runCommand = function() {
try {
var files = findFiles(input);
- var len = files.length;
-
- for (var i = 0; i < len; i++) {
- var file = files[i];
- var stat = fs.statSync(file);
- var time = stat.mtime.getTime();
- if (!stat.isDirectory()) {
- if (!mtimes[file] || mtimes[file] < time) {
- mtimes[file] = time;
- convertToJSON(file, options.pretty, options.save, options.indentation);
+ if (files != null) {
+ var len = files.length;
+
+ for (var i = 0; i < len; i++) {
+ var file = files[i];
+ var stat = fs.statSync(file);
+ var time = stat.mtime.getTime();
+ if (!stat.isDirectory()) {
+ if (!mtimes[file] || mtimes[file] < time) {
+ mtimes[file] = time;
+ convertToJSON(file, options.pretty, options.save, options.indentation);
+ }
}
}
+ } else {
+ // Read from STDIN
+ var stdin = process.openStdin();
+ var data = "";
+ stdin.on('data', function(chunk) {
+ data += chunk;
+ });
+ stdin.on('end', function() {
+ convertToJSON(null, options.pretty, options.save, options.indentation, data);
+ });
}
} catch (e) {
process.stderr.write((e.message ? e.message : e)+"\n");
diff --git a/build b/build
deleted file mode 100755
index f06ecb5..0000000
--- a/build
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/bin/sh
-cd `dirname $0`
-
-# Generate yaml.js
-file="bin/yaml.js"
-
-> $file
-
-echo Compiling $file ...
-
-echo " - LICENSE"
-
-echo "/*" >> $file
-cat LICENSE >> $file
-echo "\n*/" >> $file
-echo "(function(){" >> $file
-
-echo " - YamlParseException.js"
-cat src/yaml/YamlParseException.js >> $file
-echo " - Yaml.js"
-cat src/yaml/Yaml.js >> $file
-echo " - YamlInline.js"
-cat src/yaml/YamlInline.js >> $file
-echo " - YamlParser.js"
-cat src/yaml/YamlParser.js >> $file
-echo " - YamlEscaper.js"
-cat src/yaml/YamlEscaper.js >> $file
-echo " - YamlUnescaper.js"
-cat src/yaml/YamlUnescaper.js >> $file
-echo " - YamlDumper.js"
-cat src/yaml/YamlDumper.js >> $file
-
-echo "})();" >> $file
-
-# Generate yaml.min.js
-file="bin/yaml.min.js"
-
-echo "compressing..."
-echo "/*" > $file
-cat LICENSE >> $file
-echo "\n*/" >> $file
-uglifyjs -nc bin/yaml.js >> $file
-
-echo "yaml.js compiled."
-echo "yaml.min.js compiled."
-
-# Generate yaml2json
-echo "#!/usr/bin/env node" > bin/yaml2json
-cat src/cli/yaml2json.js >> bin/yaml2json
-chmod +x bin/yaml2json
-echo "yaml2json compiled."
-
-# Generate json2yaml
-echo "#!/usr/bin/env node" > bin/json2yaml
-cat src/cli/json2yaml.js >> bin/json2yaml
-chmod +x bin/json2yaml
-echo "json2yaml compiled."
-
diff --git a/src/cli/json2yaml.js b/cli/json2yaml.js
index 38d0b86..4c849b2 100644
--- a/src/cli/json2yaml.js
+++ b/cli/json2yaml.js
@@ -3,7 +3,7 @@
* yaml2json cli program
*/
-var YAML = require('./yaml.js');
+var YAML = require('../lib/Yaml.js');
var ArgumentParser = require('argparse').ArgumentParser;
var cli = new ArgumentParser({
@@ -55,7 +55,7 @@ cli.addArgument(
);
cli.addArgument(['input'], {
- help: 'JSON file or directory containing JSON files.'
+ help: 'JSON file or directory containing JSON files or - to read JSON from stdin.'
});
try {
@@ -66,6 +66,7 @@ try {
var rootPath = process.cwd();
var parsePath = function(input) {
+ if (input == '-') return '-';
var output;
if (!(input != null)) {
return rootPath;
@@ -85,33 +86,39 @@ try {
// Find files
var findFiles = function(input) {
- var isDirectory = fs.statSync(input).isDirectory();
- var files = [];
+ if (input != '-' && input != null) {
+ var isDirectory = fs.statSync(input).isDirectory();
+ var files = [];
- if (!isDirectory) {
- files.push(input);
- }
- else {
- if (options.recursive) {
- files = files.concat(glob.sync(input+'/**/*.json'));
+ if (!isDirectory) {
+ files.push(input);
}
else {
- files = files.concat(glob.sync(input+'/*.json'));
+ if (options.recursive) {
+ files = files.concat(glob.sync(input+'/**/*.json'));
+ }
+ else {
+ files = files.concat(glob.sync(input+'/*.json'));
+ }
}
+
+ return files;
}
-
- return files;
+ return null;
};
// Convert to JSON
- var convertToYAML = function(input, inline, save, spaces) {
+ var convertToYAML = function(input, inline, save, spaces, str) {
var yaml;
if (inline == null) inline = 2;
if (spaces == null) spaces = 2;
- yaml = YAML.stringify(JSON.parse(fs.readFileSync(input)), inline, spaces);
+ if (str == null) {
+ str = ''+fs.readFileSync(input);
+ }
+ yaml = YAML.dump(JSON.parse(str), inline, spaces);
- if (!save) {
+ if (!save || input == null) {
// Ouput result
process.stdout.write(yaml);
}
@@ -138,18 +145,29 @@ try {
var runCommand = function() {
try {
var files = findFiles(input);
- var len = files.length;
-
- for (var i = 0; i < len; i++) {
- var file = files[i];
- var stat = fs.statSync(file);
- var time = stat.mtime.getTime();
- if (!stat.isDirectory()) {
- if (!mtimes[file] || mtimes[file] < time) {
- mtimes[file] = time;
- convertToYAML(file, options.depth, options.save, options.indentation);
+ if (files != null) {
+ var len = files.length;
+ for (var i = 0; i < len; i++) {
+ var file = files[i];
+ var stat = fs.statSync(file);
+ var time = stat.mtime.getTime();
+ if (!stat.isDirectory()) {
+ if (!mtimes[file] || mtimes[file] < time) {
+ mtimes[file] = time;
+ convertToYAML(file, options.depth, options.save, options.indentation);
+ }
}
}
+ } else {
+ // Read from STDIN
+ var stdin = process.openStdin();
+ var data = "";
+ stdin.on('data', function(chunk) {
+ data += chunk;
+ });
+ stdin.on('end', function() {
+ convertToYAML(null, options.depth, options.save, options.indentation, data);
+ });
}
} catch (e) {
process.stderr.write((e.message ? e.message : e)+"\n");
diff --git a/src/cli/yaml2json.js b/cli/yaml2json.js
index 8772c4a..662201c 100644
--- a/src/cli/yaml2json.js
+++ b/cli/yaml2json.js
@@ -3,7 +3,7 @@
* yaml2json cli program
*/
-var YAML = require('./yaml.js');
+var YAML = require('../lib/Yaml.js');
var ArgumentParser = require('argparse').ArgumentParser;
var cli = new ArgumentParser({
@@ -54,7 +54,7 @@ cli.addArgument(
);
cli.addArgument(['input'], {
- help: 'YAML file or directory containing YAML files.'
+ help: 'YAML file or directory containing YAML files or - to read YAML from stdin.'
});
try {
@@ -65,6 +65,7 @@ try {
var rootPath = process.cwd();
var parsePath = function(input) {
+ if (input == '-') return '-';
var output;
if (!(input != null)) {
return rootPath;
@@ -84,38 +85,50 @@ try {
// Find files
var findFiles = function(input) {
- var isDirectory = fs.statSync(input).isDirectory();
- var files = [];
+ if (input != '-' && input != null) {
+ var isDirectory = fs.statSync(input).isDirectory();
+ var files = [];
- if (!isDirectory) {
- files.push(input);
- }
- else {
- if (options.recursive) {
- files = files.concat(glob.sync(input+'/**/*.yml'));
- files = files.concat(glob.sync(input+'/**/*.yaml'));
+ if (!isDirectory) {
+ files.push(input);
}
else {
- files = files.concat(glob.sync(input+'/*.yml'));
- files = files.concat(glob.sync(input+'/*.yaml'));
+ if (options.recursive) {
+ files = files.concat(glob.sync(input+'/**/*.yml'));
+ files = files.concat(glob.sync(input+'/**/*.yaml'));
+ }
+ else {
+ files = files.concat(glob.sync(input+'/*.yml'));
+ files = files.concat(glob.sync(input+'/*.yaml'));
+ }
}
+
+ return files;
}
-
- return files;
+ return null;
};
// Convert to JSON
- var convertToJSON = function(input, pretty, save, spaces) {
+ var convertToJSON = function(input, pretty, save, spaces, str) {
var json;
if (spaces == null) spaces = 2;
- if (pretty) {
- json = JSON.stringify(YAML.load(input), null, spaces);
- }
- else {
- json = JSON.stringify(YAML.load(input));
+ if (str != null) {
+ if (pretty) {
+ json = JSON.stringify(YAML.parse(str), null, spaces);
+ }
+ else {
+ json = JSON.stringify(YAML.parse(str));
+ }
+ } else {
+ if (pretty) {
+ json = JSON.stringify(YAML.parseFile(input), null, spaces);
+ }
+ else {
+ json = JSON.stringify(YAML.parseFile(input));
+ }
}
- if (!save) {
+ if (!save || input == null) {
// Ouput result
process.stdout.write(json+"\n");
}
@@ -145,18 +158,30 @@ try {
var runCommand = function() {
try {
var files = findFiles(input);
- var len = files.length;
-
- for (var i = 0; i < len; i++) {
- var file = files[i];
- var stat = fs.statSync(file);
- var time = stat.mtime.getTime();
- if (!stat.isDirectory()) {
- if (!mtimes[file] || mtimes[file] < time) {
- mtimes[file] = time;
- convertToJSON(file, options.pretty, options.save, options.indentation);
+ if (files != null) {
+ var len = files.length;
+
+ for (var i = 0; i < len; i++) {
+ var file = files[i];
+ var stat = fs.statSync(file);
+ var time = stat.mtime.getTime();
+ if (!stat.isDirectory()) {
+ if (!mtimes[file] || mtimes[file] < time) {
+ mtimes[file] = time;
+ convertToJSON(file, options.pretty, options.save, options.indentation);
+ }
}
}
+ } else {
+ // Read from STDIN
+ var stdin = process.openStdin();
+ var data = "";
+ stdin.on('data', function(chunk) {
+ data += chunk;
+ });
+ stdin.on('end', function() {
+ convertToJSON(null, options.pretty, options.save, options.indentation, data);
+ });
}
} catch (e) {
process.stderr.write((e.message ? e.message : e)+"\n");
diff --git a/demo/demo.html b/demo/demo.html
index 87a4f10..101ed53 100644
--- a/demo/demo.html
+++ b/demo/demo.html
@@ -46,15 +46,17 @@
color: black;
background-color: white;
font-family: "Courier New";
- font-size: 15px;
+ font-size: 12px;
width: 50%;
border: none;
position: absolute;
- top: 5em;
+ top: 0;
left: 50%;
overflow: auto;
z-index: 2;
height: 100%;
+ vertical-align: top;
+ overflow: auto;
}
#tests {
width: 50%;
@@ -67,7 +69,7 @@
</style>
<!-- standalone yaml.js library -->
- <script type="text/javascript" src="../bin/yaml.js"></script>
+ <script type="text/javascript" src="../dist/yaml.debug.js"></script>
<title>yaml.js demo</title>
</head>
@@ -104,8 +106,7 @@ comments: &gt;
Backup contact is Nancy
Billsmer @ 338-4338.
</textarea>
-<input type="button" id="parse" name="parse" value="Parse &raquo;" onclick="try{document.getElementById('result').innerHTML=JSON.stringify(YAML.parse(document.getElementById('yaml').value))}catch(e){alert(e);}" />
-<div id="tests"><span>You could also try to run some <a href="tests.html" title="Jasmine tests">javascript tests</a> based on <a href="http://www.yaml.org/YAML_for_ruby.html">YAML cookbook for Ruby</a>. All tests should pass. Those that don't are commented out; they deal with multiple YAML documents in one stream which is not supported by yaml.js (and Symfony)</span></div>
+<input type="button" id="parse" name="parse" value="Parse &raquo;" onclick="document.getElementById('result').innerHTML='<pre>'+JSON.stringify(YAML.parse(document.getElementById('yaml').value), null, 4)+'</pre>'" />
<div id="result"></div>
</form>
diff --git a/dist/yaml.debug.js b/dist/yaml.debug.js
new file mode 100644
index 0000000..220712e
--- /dev/null
+++ b/dist/yaml.debug.js
@@ -0,0 +1,1821 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+var Dumper, Inline, Utils;
+
+Utils = require('./Utils');
+
+Inline = require('./Inline');
+
+Dumper = (function() {
+ function Dumper() {}
+
+ Dumper.indentation = 4;
+
+ Dumper.prototype.dump = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ var isAHash, key, output, prefix, value, willBeInlined;
+ if (inline == null) {
+ inline = 0;
+ }
+ if (indent == null) {
+ indent = 0;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ output = '';
+ prefix = (indent ? Utils.strRepeat(' ', indent) : '');
+ if (inline <= 0 || typeof input !== 'object' || Utils.isEmpty(input)) {
+ output += prefix + Inline.dump(input, exceptionOnInvalidType, objectEncoder);
+ } else {
+ isAHash = !(input instanceof Array);
+ for (key in input) {
+ value = input[key];
+ willBeInlined = inline - 1 <= 0 || typeof value !== 'object' || Utils.isEmpty(value);
+ output += prefix + (isAHash ? Inline.dump(key, exceptionOnInvalidType, objectEncoder) + ':' : '-') + (willBeInlined ? ' ' : "\n") + this.dump(value, inline - 1, (willBeInlined ? 0 : indent + this.indentation), exceptionOnInvalidType, objectEncoder) + (willBeInlined ? "\n" : '');
+ }
+ }
+ return output;
+ };
+
+ return Dumper;
+
+})();
+
+module.exports = Dumper;
+
+
+
+},{"./Inline":5,"./Utils":9}],2:[function(require,module,exports){
+var Escaper, Pattern;
+
+Pattern = require('./Pattern');
+
+Escaper = (function() {
+ var ch;
+
+ function Escaper() {}
+
+ Escaper.LIST_ESCAPEES = ['\\\\', '\\"', '"', "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", (ch = String.fromCharCode)(0x0085), ch(0x00A0), ch(0x2028), ch(0x2029)];
+
+ Escaper.LIST_ESCAPED = ['\\"', '\\\\', '\\"', "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f", "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17", "\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", "\\x1f", "\\N", "\\_", "\\L", "\\P"];
+
+ Escaper.MAPPING_ESCAPEES_TO_ESCAPED = (function() {
+ var i, mapping, _i, _ref;
+ mapping = {};
+ for (i = _i = 0, _ref = Escaper.LIST_ESCAPEES.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
+ mapping[Escaper.LIST_ESCAPEES[i]] = Escaper.LIST_ESCAPED[i];
+ }
+ return mapping;
+ })();
+
+ Escaper.PATTERN_CHARACTERS_TO_ESCAPE = new Pattern('[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9');
+
+ Escaper.PATTERN_MAPPING_ESCAPEES = new Pattern(Escaper.LIST_ESCAPEES.join('|'));
+
+ Escaper.PATTERN_SINGLE_QUOTING = new Pattern('[\\s\'":{}[\\],&*#?]|^[-?|<>=!%@`]');
+
+ Escaper.requiresDoubleQuoting = function(value) {
+ return this.PATTERN_CHARACTERS_TO_ESCAPE.test(value);
+ };
+
+ Escaper.escapeWithDoubleQuotes = function(value) {
+ return this.PATTERN_MAPPING_ESCAPEES.replace(value, (function(_this) {
+ return function(str) {
+ return _this.MAPPING_ESCAPEES_TO_ESCAPED[str];
+ };
+ })(this));
+ };
+
+ Escaper.requiresSingleQuoting = function(value) {
+ return this.PATTERN_SINGLE_QUOTING.test(value);
+ };
+
+ Escaper.escapeWithSingleQuotes = function(value) {
+ return "'" + value.replace('\'', '\'\'') + "'";
+ };
+
+ return Escaper;
+
+})();
+
+module.exports = Escaper;
+
+
+
+},{"./Pattern":7}],3:[function(require,module,exports){
+var DumpException,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+DumpException = (function(_super) {
+ __extends(DumpException, _super);
+
+ function DumpException(message, parsedLine, snippet) {
+ this.message = message;
+ this.parsedLine = parsedLine;
+ this.snippet = snippet;
+ }
+
+ DumpException.prototype.toString = function() {
+ if ((this.parsedLine != null) && (this.snippet != null)) {
+ return '<DumpException> ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')';
+ } else {
+ return '<DumpException> ' + this.message;
+ }
+ };
+
+ return DumpException;
+
+})(Error);
+
+module.exports = DumpException;
+
+
+
+},{}],4:[function(require,module,exports){
+var ParseException,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ParseException = (function(_super) {
+ __extends(ParseException, _super);
+
+ function ParseException(message, parsedLine, snippet) {
+ this.message = message;
+ this.parsedLine = parsedLine;
+ this.snippet = snippet;
+ }
+
+ ParseException.prototype.toString = function() {
+ if ((this.parsedLine != null) && (this.snippet != null)) {
+ return '<ParseException> ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')';
+ } else {
+ return '<ParseException> ' + this.message;
+ }
+ };
+
+ return ParseException;
+
+})(Error);
+
+module.exports = ParseException;
+
+
+
+},{}],5:[function(require,module,exports){
+var DumpException, Escaper, Inline, ParseException, Pattern, Unescaper, Utils,
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
+
+Pattern = require('./Pattern');
+
+Unescaper = require('./Unescaper');
+
+Escaper = require('./Escaper');
+
+Utils = require('./Utils');
+
+ParseException = require('./Exception/ParseException');
+
+DumpException = require('./Exception/DumpException');
+
+Inline = (function() {
+ function Inline() {}
+
+ Inline.REGEX_QUOTED_STRING = '(?:"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\']*(?:\'\'[^\']*)*)\')';
+
+ Inline.PATTERN_TRAILING_COMMENTS = new Pattern('^\\s*#.*$');
+
+ Inline.PATTERN_QUOTED_SCALAR = new Pattern('^' + Inline.REGEX_QUOTED_STRING);
+
+ Inline.PATTERN_THOUSAND_NUMERIC_SCALAR = new Pattern('^(-|\\+)?[0-9,]+(\\.[0-9]+)?$');
+
+ Inline.PATTERN_SCALAR_BY_DELIMITERS = {};
+
+ Inline.settings = {};
+
+ Inline.configure = function(exceptionOnInvalidType, objectDecoder) {
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = null;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.settings.exceptionOnInvalidType = exceptionOnInvalidType;
+ this.settings.objectDecoder = objectDecoder;
+ };
+
+ Inline.parse = function(value, exceptionOnInvalidType, objectDecoder) {
+ var context, result;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.settings.exceptionOnInvalidType = exceptionOnInvalidType;
+ this.settings.objectDecoder = objectDecoder;
+ if (value == null) {
+ return '';
+ }
+ value = Utils.trim(value);
+ if (0 === value.length) {
+ return '';
+ }
+ context = {
+ exceptionOnInvalidType: exceptionOnInvalidType,
+ objectDecoder: objectDecoder,
+ i: 0
+ };
+ switch (value.charAt(0)) {
+ case '[':
+ result = this.parseSequence(value, context);
+ ++context.i;
+ break;
+ case '{':
+ result = this.parseMapping(value, context);
+ ++context.i;
+ break;
+ default:
+ result = this.parseScalar(value, null, ['"', "'"], context);
+ }
+ if (this.PATTERN_TRAILING_COMMENTS.replace(value.slice(context.i), '') !== '') {
+ throw new ParseException('Unexpected characters near "' + value.slice(context.i) + '".');
+ }
+ return result;
+ };
+
+ Inline.dump = function(value, exceptionOnInvalidType, objectEncoder) {
+ var result, type, _ref;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ if (value == null) {
+ return 'null';
+ }
+ type = typeof value;
+ if (type === 'object') {
+ if (value instanceof Date) {
+ return value.toISOString();
+ } else if (objectEncoder != null) {
+ result = objectEncoder(value);
+ if (typeof result === 'string' || (result != null)) {
+ return result;
+ }
+ }
+ return this.dumpObject(value);
+ }
+ if (type === 'boolean') {
+ return (value ? 'true' : 'false');
+ }
+ if (Utils.isDigits(value)) {
+ return (type === 'string' ? "'" + value + "'" : '' + parseInt(value));
+ }
+ if (Utils.isNumeric(value)) {
+ return (type === 'string' ? "'" + value + "'" : '' + parseFloat(value));
+ }
+ if (type === 'number') {
+ return (value === Infinity ? '.Inf' : (value === -Infinity ? '-.Inf' : (isNaN(value) ? '.NaN' : value)));
+ }
+ if (Escaper.requiresDoubleQuoting(value)) {
+ return Escaper.escapeWithDoubleQuotes(value);
+ }
+ if (Escaper.requiresSingleQuoting(value)) {
+ return yaml.escapeWithSingleQuotes(value);
+ }
+ if ('' === value) {
+ return '""';
+ }
+ if (Utils.PATTERN_DATE.test(value)) {
+ return "'" + value + "'";
+ }
+ if ((_ref = value.toLowerCase()) === 'null' || _ref === '~' || _ref === 'true' || _ref === 'false') {
+ return "'" + value + "'";
+ }
+ return value;
+ };
+
+ Inline.dumpObject = function(value, exceptionOnInvalidType, objectSupport) {
+ var key, output, val, _i, _len;
+ if (objectSupport == null) {
+ objectSupport = null;
+ }
+ if (value instanceof Array) {
+ output = [];
+ for (_i = 0, _len = value.length; _i < _len; _i++) {
+ val = value[_i];
+ output.push(this.dump(val));
+ }
+ return '[' + output.join(', ') + ']';
+ } else {
+ output = [];
+ for (key in value) {
+ val = value[key];
+ output.push(this.dump(key) + ': ' + this.dump(val));
+ }
+ return '{' + output.join(', ') + '}';
+ }
+ };
+
+ Inline.parseScalar = function(scalar, delimiters, stringDelimiters, context, evaluate) {
+ var i, joinedDelimiters, match, output, pattern, strpos, tmp, _ref, _ref1;
+ if (delimiters == null) {
+ delimiters = null;
+ }
+ if (stringDelimiters == null) {
+ stringDelimiters = ['"', "'"];
+ }
+ if (context == null) {
+ context = null;
+ }
+ if (evaluate == null) {
+ evaluate = true;
+ }
+ if (context == null) {
+ context = {
+ exceptionOnInvalidType: this.settings.exceptionOnInvalidType,
+ objectDecoder: this.settings.objectDecoder,
+ i: 0
+ };
+ }
+ i = context.i;
+ if (_ref = scalar.charAt(i), __indexOf.call(stringDelimiters, _ref) >= 0) {
+ output = this.parseQuotedScalar(scalar, context);
+ i = context.i;
+ if (delimiters != null) {
+ tmp = Utils.ltrim(scalar.slice(i), ' ');
+ if (!(_ref1 = tmp.charAt(0), __indexOf.call(delimiters, _ref1) >= 0)) {
+ throw new ParseException('Unexpected characters (' + scalar.slice(i) + ').');
+ }
+ }
+ } else {
+ if (!delimiters) {
+ output = scalar.slice(i);
+ i += output.length;
+ strpos = output.indexOf(' #');
+ if (strpos !== -1) {
+ output = Utils.rtrim(output.slice(0, strpos));
+ }
+ } else {
+ joinedDelimiters = delimiters.join('|');
+ pattern = this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters];
+ if (pattern == null) {
+ pattern = new Pattern('^(.+?)(' + joinedDelimiters + ')');
+ this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters] = pattern;
+ }
+ if (match = pattern.exec(scalar.slice(i))) {
+ output = match[1];
+ i += output.length;
+ } else {
+ throw new ParseException('Malformed inline YAML string (' + scalar + ').');
+ }
+ }
+ if (evaluate) {
+ output = this.evaluateScalar(output, context);
+ }
+ }
+ context.i = i;
+ return output;
+ };
+
+ Inline.parseQuotedScalar = function(scalar, context) {
+ var i, match, output;
+ i = context.i;
+ if (!(match = this.PATTERN_QUOTED_SCALAR.exec(scalar.slice(i)))) {
+ throw new ParseException('Malformed inline YAML string (' + scalar.slice(i) + ').');
+ }
+ output = match[0].substr(1, match[0].length - 2);
+ if ('"' === scalar.charAt(i)) {
+ output = Unescaper.unescapeDoubleQuotedString(output);
+ } else {
+ output = Unescaper.unescapeSingleQuotedString(output);
+ }
+ i += match[0].length;
+ context.i = i;
+ return output;
+ };
+
+ Inline.parseSequence = function(sequence, context) {
+ var e, i, isQuoted, len, output, value, _ref;
+ output = [];
+ len = sequence.length;
+ i = context.i;
+ i += 1;
+ while (i < len) {
+ context.i = i;
+ switch (sequence.charAt(i)) {
+ case '[':
+ output.push(this.parseSequence(sequence, context));
+ i = context.i;
+ break;
+ case '{':
+ output.push(this.parseMapping(sequence, context));
+ i = context.i;
+ break;
+ case ']':
+ return output;
+ case ',':
+ case ' ':
+ case "\n":
+ break;
+ default:
+ isQuoted = ((_ref = sequence.charAt(i)) === '"' || _ref === "'");
+ value = this.parseScalar(sequence, [',', ']'], ['"', "'"], context);
+ i = context.i;
+ if (!isQuoted && typeof value === 'string' && (value.indexOf(': ') !== -1 || value.indexOf(":\n") !== -1)) {
+ try {
+ value = this.parseMapping('{' + value + '}');
+ } catch (_error) {
+ e = _error;
+ }
+ }
+ output.push(value);
+ --i;
+ }
+ ++i;
+ }
+ throw new ParseException('Malformed inline YAML string ' + sequence);
+ };
+
+ Inline.parseMapping = function(mapping, context) {
+ var $value, done, i, key, len, output, shouldContinueWhileLoop, value;
+ output = {};
+ len = mapping.length;
+ i = context.i;
+ i += 1;
+ shouldContinueWhileLoop = false;
+ while (i < len) {
+ context.i = i;
+ switch (mapping.charAt(i)) {
+ case ' ':
+ case ',':
+ case "\n":
+ ++i;
+ context.i = i;
+ shouldContinueWhileLoop = true;
+ break;
+ case '}':
+ return output;
+ }
+ if (shouldContinueWhileLoop) {
+ shouldContinueWhileLoop = false;
+ continue;
+ }
+ key = this.parseScalar(mapping, [':', ' ', "\n"], ['"', "'"], context, false);
+ i = context.i;
+ done = false;
+ while (i < len) {
+ context.i = i;
+ switch (mapping.charAt(i)) {
+ case '[':
+ value = this.parseSequence(mapping, context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ break;
+ case '{':
+ $value = this.parseMapping(mapping, context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ break;
+ case ':':
+ case ' ':
+ case "\n":
+ break;
+ default:
+ value = this.parseScalar(mapping, [',', '}'], ['"', "'"], context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ --i;
+ }
+ ++i;
+ if (done) {
+ break;
+ }
+ }
+ }
+ throw new ParseException('Malformed inline YAML string ' + mapping);
+ };
+
+ Inline.evaluateScalar = function(scalar, context) {
+ var cast, exceptionOnInvalidType, firstChar, firstSpace, firstWord, objectDecoder, raw, scalarLower, subValue, trimmedScalar;
+ scalar = Utils.trim(scalar);
+ scalarLower = scalar.toLowerCase();
+ switch (scalarLower) {
+ case 'null':
+ case '':
+ case '~':
+ return null;
+ case 'true':
+ return true;
+ case 'false':
+ return false;
+ case '.inf':
+ return Infinity;
+ case '.nan':
+ return NaN;
+ case '-.inf':
+ return Infinity;
+ default:
+ firstChar = scalarLower.charAt(0);
+ switch (firstChar) {
+ case '!':
+ firstSpace = scalar.indexOf(' ');
+ if (firstSpace === -1) {
+ firstWord = scalarLower;
+ } else {
+ firstWord = scalarLower.slice(0, firstSpace);
+ }
+ switch (firstWord) {
+ case '!':
+ if (firstSpace !== -1) {
+ return parseInt(this.parseScalar(scalar.slice(2)));
+ }
+ return null;
+ case '!str':
+ return Utils.ltrim(scalar.slice(4));
+ case '!!str':
+ return Utils.ltrim(scalar.slice(5));
+ case '!!int':
+ return parseInt(this.parseScalar(scalar.slice(5)));
+ case '!!bool':
+ return Utils.parseBoolean(this.parseScalar(scalar.slice(6)), false);
+ case '!!float':
+ return parseFloat(this.parseScalar(scalar.slice(7)));
+ case '!!timestamp':
+ return Utils.stringToDate(Utils.ltrim(scalar.slice(11)));
+ default:
+ if (context == null) {
+ context = {
+ exceptionOnInvalidType: this.settings.exceptionOnInvalidType,
+ objectDecoder: this.settings.objectDecoder,
+ i: 0
+ };
+ }
+ objectDecoder = context.objectDecoder, exceptionOnInvalidType = context.exceptionOnInvalidType;
+ if (objectDecoder) {
+ trimmedScalar = Utils.rtrim(scalar);
+ firstSpace = trimmedScalar.indexOf(' ');
+ if (firstSpace === -1) {
+ return objectDecoder(trimmedScalar, null);
+ } else {
+ subValue = Utils.ltrim(trimmedScalar.slice(firstSpace + 1));
+ if (!(subValue.length > 0)) {
+ subValue = null;
+ }
+ return objectDecoder(trimmedScalar.slice(0, firstSpace), subValue);
+ }
+ }
+ if (exceptionOnInvalidType) {
+ throw new ParseException('Custom object support when parsing a YAML file has been disabled.');
+ }
+ return null;
+ }
+ break;
+ case '0':
+ if ('0x' === scalar.slice(0, 2)) {
+ return Utils.hexDec(scalar);
+ } else if (Utils.isDigits(scalar)) {
+ return Utils.octDec(scalar);
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ } else {
+ return scalar;
+ }
+ break;
+ case '+':
+ if (Utils.isDigits(scalar)) {
+ raw = scalar;
+ cast = parseInt(raw);
+ if (raw === '' + cast) {
+ return cast;
+ } else {
+ return raw;
+ }
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ case '-':
+ if (Utils.isDigits(scalar.slice(1))) {
+ if ('0' === scalar.charAt(1)) {
+ return -Utils.octDec(scalar.slice(1));
+ } else {
+ raw = scalar.slice(1);
+ cast = parseInt(raw);
+ if (raw === '' + cast) {
+ return -cast;
+ } else {
+ return -raw;
+ }
+ }
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ default:
+ if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ }
+ }
+ };
+
+ return Inline;
+
+})();
+
+module.exports = Inline;
+
+
+
+},{"./Escaper":2,"./Exception/DumpException":3,"./Exception/ParseException":4,"./Pattern":7,"./Unescaper":8,"./Utils":9}],6:[function(require,module,exports){
+var Inline, ParseException, Parser, Pattern, Utils;
+
+Inline = require('./Inline');
+
+Pattern = require('./Pattern');
+
+Utils = require('./Utils');
+
+ParseException = require('./Exception/ParseException');
+
+Parser = (function() {
+ Parser.prototype.PATTERN_FOLDED_SCALAR_ALL = new Pattern('^(?:(?<type>![^\\|>]*)\\s+)?(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$');
+
+ Parser.prototype.PATTERN_FOLDED_SCALAR_END = new Pattern('(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$');
+
+ Parser.prototype.PATTERN_SEQUENCE_ITEM = new Pattern('^\\-((?<leadspaces>\\s+)(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_ANCHOR_VALUE = new Pattern('^&(?<ref>[^ ]+) *(?<value>.*)');
+
+ Parser.prototype.PATTERN_COMPACT_NOTATION = new Pattern('^(?<key>' + Inline.REGEX_QUOTED_STRING + '|[^ \'"\\{\\[].*?) *\\:(\\s+(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_MAPPING_ITEM = new Pattern('^(?<key>' + Inline.REGEX_QUOTED_STRING + '|[^ \'"\\[\\{].*?) *\\:(\\s+(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_DECIMAL = new Pattern('\\d+');
+
+ Parser.prototype.PATTERN_INDENT_SPACES = new Pattern('^ +');
+
+ Parser.prototype.PATTERN_TRAILING_LINES = new Pattern('(\n*)$');
+
+ Parser.prototype.PATTERN_YAML_HEADER = new Pattern('^\\%YAML[: ][\\d\\.]+.*\n');
+
+ Parser.prototype.PATTERN_LEADING_COMMENTS = new Pattern('^(\\#.*?\n)+');
+
+ Parser.prototype.PATTERN_DOCUMENT_MARKER_START = new Pattern('^\\-\\-\\-.*?\n');
+
+ Parser.prototype.PATTERN_DOCUMENT_MARKER_END = new Pattern('^\\.\\.\\.\\s*$');
+
+ Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION = {};
+
+ Parser.prototype.CONTEXT_NONE = 0;
+
+ Parser.prototype.CONTEXT_SEQUENCE = 1;
+
+ Parser.prototype.CONTEXT_MAPPING = 2;
+
+ function Parser(offset) {
+ this.offset = offset != null ? offset : 0;
+ this.lines = [];
+ this.currentLineNb = -1;
+ this.currentLine = '';
+ this.refs = {};
+ }
+
+ Parser.prototype.parse = function(value, exceptionOnInvalidType, objectDecoder) {
+ var alias, allowOverwrite, block, c, context, data, e, first, i, indent, isRef, key, lastKey, lineCount, matches, mergeNode, parsed, parsedItem, parser, refName, refValue, val, values, _i, _j, _k, _l, _len, _len1, _len2, _len3, _name, _name1, _ref, _ref1, _ref2;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.currentLineNb = -1;
+ this.currentLine = '';
+ this.lines = this.cleanup(value).split("\n");
+ data = null;
+ context = this.CONTEXT_NONE;
+ allowOverwrite = false;
+ while (this.moveToNextLine()) {
+ if (this.isCurrentLineEmpty()) {
+ continue;
+ }
+ if ("\t" === this.currentLine[0]) {
+ throw new ParseException('A YAML file cannot contain tabs as indentation.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ isRef = mergeNode = false;
+ if (values = this.PATTERN_SEQUENCE_ITEM.exec(this.currentLine)) {
+ if (this.CONTEXT_MAPPING === context) {
+ throw new ParseException('You cannot define a sequence item when in a mapping');
+ }
+ context = this.CONTEXT_SEQUENCE;
+ if (data == null) {
+ data = [];
+ }
+ if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) {
+ isRef = matches.ref;
+ values.value = matches.value;
+ }
+ if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf('#') === 0) {
+ if (this.currentLineNb < this.lines.length - 1 && !this.isNextLineUnIndentedCollection()) {
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ data.push(parser.parse(this.getNextEmbedBlock(null, true), exceptionOnInvalidType, objectDecoder));
+ } else {
+ data.push(null);
+ }
+ } else {
+ if (((_ref = values.leadspaces) != null ? _ref.length : void 0) && (matches = this.PATTERN_COMPACT_NOTATION.exec(values.value))) {
+ c = this.getRealCurrentLineNb();
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ block = values.value;
+ indent = this.getCurrentLineIndentation();
+ if (this.isNextLineIndented(false)) {
+ block += "\n" + this.getNextEmbedBlock(indent + values.leadspaces.length + 1, true);
+ }
+ data.push(parser.parse(block, exceptionOnInvalidType, objectDecoder));
+ } else {
+ data.push(this.parseValue(values.value, exceptionOnInvalidType, objectDecoder));
+ }
+ }
+ } else if ((values = this.PATTERN_MAPPING_ITEM.exec(this.currentLine)) && values.key.indexOf(' #') === -1) {
+ if (this.CONTEXT_SEQUENCE === context) {
+ throw new ParseException('You cannot define a mapping item when in a sequence');
+ }
+ context = this.CONTEXT_MAPPING;
+ if (data == null) {
+ data = {};
+ }
+ Inline.configure(exceptionOnInvalidType, objectDecoder);
+ try {
+ key = Inline.parseScalar(values.key);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ if ('<<' === key) {
+ mergeNode = true;
+ allowOverwrite = true;
+ if (((_ref1 = values.value) != null ? _ref1.indexOf('*') : void 0) === 0) {
+ refName = values.value.slice(1);
+ if (this.refs[refName] == null) {
+ throw new ParseException('Reference "' + refName + '" does not exist.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ refValue = this.refs[refName];
+ if (typeof refValue !== 'object') {
+ throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (refValue instanceof Array) {
+ for (i = _i = 0, _len = refValue.length; _i < _len; i = ++_i) {
+ value = refValue[i];
+ if (data[_name = '' + i] == null) {
+ data[_name] = value;
+ }
+ }
+ } else {
+ for (key in refValue) {
+ value = refValue[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ } else {
+ if (values.value !== '') {
+ value = values.value;
+ } else {
+ value = this.getNextEmbedBlock();
+ }
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ parsed = parser.parse(value, exceptionOnInvalidType);
+ if (typeof parsed !== 'object') {
+ throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (parsed instanceof Array) {
+ for (_j = 0, _len1 = parsed.length; _j < _len1; _j++) {
+ parsedItem = parsed[_j];
+ if (typeof parsedItem !== 'object') {
+ throw new ParseException('Merge items must be objects.', this.getRealCurrentLineNb() + 1, parsedItem);
+ }
+ if (parsedItem instanceof Array) {
+ for (i = _k = 0, _len2 = parsedItem.length; _k < _len2; i = ++_k) {
+ value = parsedItem[i];
+ if (data[_name1 = '' + i] == null) {
+ data[_name1] = value;
+ }
+ }
+ } else {
+ for (key in parsedItem) {
+ value = parsedItem[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ }
+ } else {
+ for (key in parsed) {
+ value = parsed[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ }
+ } else if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) {
+ isRef = matches.ref;
+ values.value = matches.value;
+ }
+ if (mergeNode) {
+
+ } else if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf('#') === 0) {
+ if (!(this.isNextLineIndented()) && !(this.isNextLineUnIndentedCollection())) {
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = null;
+ }
+ } else {
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ val = parser.parse(this.getNextEmbedBlock(), exceptionOnInvalidType, objectDecoder);
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = val;
+ }
+ }
+ } else {
+ val = this.parseValue(values.value, exceptionOnInvalidType, objectDecoder);
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = val;
+ }
+ }
+ } else {
+ lineCount = this.lines.length;
+ if (1 === lineCount || (2 === lineCount && Utils.isEmpty(this.lines[1]))) {
+ try {
+ value = Inline.parse(this.lines[0], exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ if (typeof value === 'object') {
+ if (value instanceof Array) {
+ first = value[0];
+ } else {
+ for (key in value) {
+ first = value[key];
+ break;
+ }
+ }
+ if (typeof first === 'string' && first.indexOf('*') === 0) {
+ data = [];
+ for (_l = 0, _len3 = value.length; _l < _len3; _l++) {
+ alias = value[_l];
+ data.push(this.refs[alias.slice(1)]);
+ }
+ value = data;
+ }
+ }
+ return value;
+ } else if ((_ref2 = Utils.ltrim(value).charAt(0)) === '[' || _ref2 === '{') {
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ }
+ throw new ParseException('Unable to parse.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (isRef) {
+ if (data instanceof Array) {
+ this.refs[isRef] = data[data.length - 1];
+ } else {
+ lastKey = null;
+ for (key in data) {
+ lastKey = key;
+ }
+ this.refs[isRef] = data[lastKey];
+ }
+ }
+ }
+ if (Utils.isEmpty(data)) {
+ return null;
+ } else {
+ return data;
+ }
+ };
+
+ Parser.prototype.getRealCurrentLineNb = function() {
+ return this.currentLineNb + this.offset;
+ };
+
+ Parser.prototype.getCurrentLineIndentation = function() {
+ return this.currentLine.length - Utils.ltrim(this.currentLine, ' ').length;
+ };
+
+ Parser.prototype.getNextEmbedBlock = function(indentation, includeUnindentedCollection) {
+ var data, indent, isItUnindentedCollection, newIndent, removeComments, removeCommentsPattern, unindentedEmbedBlock;
+ if (indentation == null) {
+ indentation = null;
+ }
+ if (includeUnindentedCollection == null) {
+ includeUnindentedCollection = false;
+ }
+ this.moveToNextLine();
+ if (indentation == null) {
+ newIndent = this.getCurrentLineIndentation();
+ unindentedEmbedBlock = this.isStringUnIndentedCollectionItem(this.currentLine);
+ if (!(this.isCurrentLineEmpty()) && 0 === newIndent && !unindentedEmbedBlock) {
+ throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ } else {
+ newIndent = indentation;
+ }
+ data = [this.currentLine.slice(newIndent)];
+ if (!includeUnindentedCollection) {
+ isItUnindentedCollection = this.isStringUnIndentedCollectionItem(this.currentLine);
+ }
+ removeCommentsPattern = this.PATTERN_FOLDED_SCALAR_END;
+ removeComments = !removeCommentsPattern.test(this.currentLine);
+ while (this.moveToNextLine()) {
+ indent = this.getCurrentLineIndentation();
+ if (indent === newIndent) {
+ removeComments = !removeCommentsPattern.test(this.currentLine);
+ }
+ if (isItUnindentedCollection && !this.isStringUnIndentedCollectionItem(this.currentLine) && indent === newIndent) {
+ this.moveToPreviousLine();
+ break;
+ }
+ if (this.isCurrentLineBlank()) {
+ data.push(this.currentLine.slice(newIndent));
+ continue;
+ }
+ if (removeComments && this.isCurrentLineComment()) {
+ if (indent === newIndent) {
+ continue;
+ }
+ }
+ if (indent >= newIndent) {
+ data.push(this.currentLine.slice(newIndent));
+ } else if (0 === indent) {
+ this.moveToPreviousLine();
+ break;
+ } else {
+ throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ }
+ return data.join("\n");
+ };
+
+ Parser.prototype.moveToNextLine = function() {
+ if (this.currentLineNb >= this.lines.length - 1) {
+ return false;
+ }
+ this.currentLine = this.lines[++this.currentLineNb];
+ return true;
+ };
+
+ Parser.prototype.moveToPreviousLine = function() {
+ this.currentLine = this.lines[--this.currentLineNb];
+ };
+
+ Parser.prototype.parseValue = function(value, exceptionOnInvalidType, objectDecoder) {
+ var e, foldedIndent, matches, modifiers, pos, val, _ref, _ref1;
+ if (0 === value.indexOf('*')) {
+ pos = value.indexOf('#');
+ if (pos !== -1) {
+ value = value.substr(1, pos - 2);
+ } else {
+ value = value.slice(1);
+ }
+ if (this.refs[value] === void 0) {
+ throw new ParseException('Reference "' + value + '" does not exist.', this.currentLine);
+ }
+ return this.refs[value];
+ }
+ if (matches = this.PATTERN_FOLDED_SCALAR_ALL.exec(value)) {
+ modifiers = (_ref = matches.modifiers) != null ? _ref : '';
+ foldedIndent = Math.abs(parseInt(modifiers));
+ if (isNaN(foldedIndent)) {
+ foldedIndent = 0;
+ }
+ val = this.parseFoldedScalar(matches.separator, this.PATTERN_DECIMAL.replace(modifiers, ''), foldedIndent);
+ if (matches.type != null) {
+ Inline.configure(exceptionOnInvalidType, objectDecoder);
+ return Inline.parseScalar(matches.type + ' ' + val);
+ } else {
+ return val;
+ }
+ }
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ if (((_ref1 = value.charAt(0)) === '[' || _ref1 === '{') && e instanceof ParseException && this.isNextLineIndented()) {
+ value += "\n" + this.getNextEmbedBlock();
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ } else {
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ }
+ };
+
+ Parser.prototype.parseFoldedScalar = function(separator, indicator, indentation) {
+ var isCurrentLineBlank, line, matches, newText, notEOF, pattern, text, _i, _len, _ref;
+ if (indicator == null) {
+ indicator = '';
+ }
+ if (indentation == null) {
+ indentation = 0;
+ }
+ notEOF = this.moveToNextLine();
+ if (!notEOF) {
+ return '';
+ }
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ text = '';
+ while (notEOF && isCurrentLineBlank) {
+ if (notEOF = this.moveToNextLine()) {
+ text += "\n";
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ }
+ }
+ if (0 === indentation) {
+ if (matches = this.PATTERN_INDENT_SPACES.exec(this.currentLine)) {
+ indentation = matches[0].length;
+ }
+ }
+ if (indentation > 0) {
+ pattern = this.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation];
+ if (pattern == null) {
+ pattern = new Pattern('^ {' + indentation + '}(.*)$');
+ Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation] = pattern;
+ }
+ while (notEOF && (isCurrentLineBlank || (matches = pattern.exec(this.currentLine)))) {
+ if (isCurrentLineBlank) {
+ text += this.currentLine.slice(indentation);
+ } else {
+ text += matches[1];
+ }
+ if (notEOF = this.moveToNextLine()) {
+ text += "\n";
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ }
+ }
+ } else if (notEOF) {
+ text += "\n";
+ }
+ if (notEOF) {
+ this.moveToPreviousLine();
+ }
+ if ('>' === separator) {
+ newText = '';
+ _ref = text.split("\n");
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ line = _ref[_i];
+ if (line.length === 0 || line.charAt(0) === ' ') {
+ newText += line + "\n";
+ } else {
+ newText += line + ' ';
+ }
+ }
+ text = newText;
+ }
+ text = Utils.rtrim(text);
+ if ('' === indicator) {
+ text = this.PATTERN_TRAILING_LINES.replace(text, "\n");
+ } else if ('-' === indicator) {
+ text = this.PATTERN_TRAILING_LINES.replace(text, '');
+ }
+ return text;
+ };
+
+ Parser.prototype.isNextLineIndented = function(ignoreComments) {
+ var EOF, currentIndentation, ret;
+ if (ignoreComments == null) {
+ ignoreComments = true;
+ }
+ currentIndentation = this.getCurrentLineIndentation();
+ EOF = !this.moveToNextLine();
+ if (ignoreComments) {
+ while (!EOF && this.isCurrentLineEmpty()) {
+ EOF = !this.moveToNextLine();
+ }
+ } else {
+ while (!EOF && this.isCurrentLineBlank()) {
+ EOF = !this.moveToNextLine();
+ }
+ }
+ if (EOF) {
+ return false;
+ }
+ ret = false;
+ if (this.getCurrentLineIndentation() > currentIndentation) {
+ ret = true;
+ }
+ this.moveToPreviousLine();
+ return ret;
+ };
+
+ Parser.prototype.isCurrentLineEmpty = function() {
+ var trimmedLine;
+ trimmedLine = Utils.trim(this.currentLine, ' ');
+ return trimmedLine.length === 0 || trimmedLine.charAt(0) === '#';
+ };
+
+ Parser.prototype.isCurrentLineBlank = function() {
+ return '' === Utils.trim(this.currentLine, ' ');
+ };
+
+ Parser.prototype.isCurrentLineComment = function() {
+ var ltrimmedLine;
+ ltrimmedLine = Utils.ltrim(this.currentLine, ' ');
+ return ltrimmedLine.charAt(0) === '#';
+ };
+
+ Parser.prototype.cleanup = function(value) {
+ var count, trimmedValue, _ref, _ref1, _ref2;
+ value = value.replace("\r\n", "\n").replace("\r", "\n");
+ count = 0;
+ _ref = this.PATTERN_YAML_HEADER.replaceAll(value, ''), value = _ref[0], count = _ref[1];
+ this.offset += count;
+ _ref1 = this.PATTERN_LEADING_COMMENTS.replaceAll(value, '', 1), trimmedValue = _ref1[0], count = _ref1[1];
+ if (count === 1) {
+ this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n");
+ value = trimmedValue;
+ }
+ _ref2 = this.PATTERN_DOCUMENT_MARKER_START.replaceAll(value, '', 1), trimmedValue = _ref2[0], count = _ref2[1];
+ if (count === 1) {
+ this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n");
+ value = trimmedValue;
+ value = this.PATTERN_DOCUMENT_MARKER_END.replace(value, '');
+ }
+ return value;
+ };
+
+ Parser.prototype.isNextLineUnIndentedCollection = function(currentIndentation) {
+ var notEOF, ret;
+ if (currentIndentation == null) {
+ currentIndentation = null;
+ }
+ if (currentIndentation == null) {
+ currentIndentation = this.getCurrentLineIndentation();
+ }
+ notEOF = this.moveToNextLine();
+ while (notEOF && this.isCurrentLineEmpty()) {
+ notEOF = this.moveToNextLine();
+ }
+ if (false === notEOF) {
+ return false;
+ }
+ ret = false;
+ if (this.getCurrentLineIndentation() === currentIndentation && this.isStringUnIndentedCollectionItem(this.currentLine)) {
+ ret = true;
+ }
+ this.moveToPreviousLine();
+ return ret;
+ };
+
+ Parser.prototype.isStringUnIndentedCollectionItem = function() {
+ return this.currentLine === '-' || this.currentLine.slice(0, 2) === '- ';
+ };
+
+ return Parser;
+
+})();
+
+module.exports = Parser;
+
+
+
+},{"./Exception/ParseException":4,"./Inline":5,"./Pattern":7,"./Utils":9}],7:[function(require,module,exports){
+var Pattern;
+
+Pattern = (function() {
+ Pattern.prototype.regex = null;
+
+ Pattern.prototype.rawRegex = null;
+
+ Pattern.prototype.cleanedRegex = null;
+
+ Pattern.prototype.mapping = null;
+
+ function Pattern(rawRegex, modifiers) {
+ var capturingBracketNumber, char, cleanedRegex, i, len, mapping, name, part, subChar;
+ if (modifiers == null) {
+ modifiers = '';
+ }
+ cleanedRegex = '';
+ len = rawRegex.length;
+ mapping = null;
+ capturingBracketNumber = 0;
+ i = 0;
+ while (i < len) {
+ char = rawRegex.charAt(i);
+ if (char === '\\') {
+ cleanedRegex += rawRegex.slice(i, +(i + 1) + 1 || 9e9);
+ i++;
+ } else if (char === '(') {
+ if (i < len - 2) {
+ part = rawRegex.slice(i, +(i + 2) + 1 || 9e9);
+ if (part === '(?:') {
+ i += 2;
+ cleanedRegex += part;
+ } else if (part === '(?<') {
+ capturingBracketNumber++;
+ i += 2;
+ name = '';
+ while (i + 1 < len) {
+ subChar = rawRegex.charAt(i + 1);
+ if (subChar === '>') {
+ cleanedRegex += '(';
+ i++;
+ if (name.length > 0) {
+ if (mapping == null) {
+ mapping = {};
+ }
+ mapping[name] = capturingBracketNumber;
+ }
+ break;
+ } else {
+ name += subChar;
+ }
+ i++;
+ }
+ } else {
+ cleanedRegex += char;
+ capturingBracketNumber++;
+ }
+ } else {
+ cleanedRegex += char;
+ }
+ } else {
+ cleanedRegex += char;
+ }
+ i++;
+ }
+ this.rawRegex = rawRegex;
+ this.cleanedRegex = cleanedRegex;
+ this.regex = new RegExp(this.cleanedRegex, 'g' + modifiers.replace('g', ''));
+ this.mapping = mapping;
+ }
+
+ Pattern.prototype.exec = function(str) {
+ var index, matches, name, _ref;
+ this.regex.lastIndex = 0;
+ matches = this.regex.exec(str);
+ if (matches == null) {
+ return null;
+ }
+ if (this.mapping != null) {
+ _ref = this.mapping;
+ for (name in _ref) {
+ index = _ref[name];
+ matches[name] = matches[index];
+ }
+ }
+ return matches;
+ };
+
+ Pattern.prototype.test = function(str) {
+ this.regex.lastIndex = 0;
+ return this.regex.test(str);
+ };
+
+ Pattern.prototype.replace = function(str, replacement) {
+ this.regex.lastIndex = 0;
+ return str.replace(this.regex, replacement);
+ };
+
+ Pattern.prototype.replaceAll = function(str, replacement, limit) {
+ var count;
+ if (limit == null) {
+ limit = 0;
+ }
+ this.regex.lastIndex = 0;
+ count = 0;
+ while (this.regex.test(str) && (limit === 0 || count < limit)) {
+ this.regex.lastIndex = 0;
+ str = str.replace(this.regex, '');
+ count++;
+ }
+ return [str, count];
+ };
+
+ return Pattern;
+
+})();
+
+module.exports = Pattern;
+
+
+
+},{}],8:[function(require,module,exports){
+var Pattern, Unescaper, Utils;
+
+Utils = require('./Utils');
+
+Pattern = require('./Pattern');
+
+Unescaper = (function() {
+ function Unescaper() {}
+
+ Unescaper.PATTERN_ESCAPED_CHARACTER = new Pattern('\\\\([0abt\tnvfre "\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})');
+
+ Unescaper.unescapeSingleQuotedString = function(value) {
+ return value.replace('\'\'', '\'');
+ };
+
+ Unescaper.unescapeDoubleQuotedString = function(value) {
+ if (this._unescapeCallback == null) {
+ this._unescapeCallback = (function(_this) {
+ return function(str) {
+ return _this.unescapeCharacter(str);
+ };
+ })(this);
+ }
+ return this.PATTERN_ESCAPED_CHARACTER.replace(value, this._unescapeCallback);
+ };
+
+ Unescaper.unescapeCharacter = function(value) {
+ var ch;
+ ch = String.fromCharCode;
+ switch (value.charAt(1)) {
+ case '0':
+ return ch(0);
+ case 'a':
+ return ch(7);
+ case 'b':
+ return ch(8);
+ case 't':
+ return "\t";
+ case "\t":
+ return "\t";
+ case 'n':
+ return "\n";
+ case 'v':
+ return ch(11);
+ case 'f':
+ return ch(12);
+ case 'r':
+ return ch(13);
+ case 'e':
+ return ch(27);
+ case ' ':
+ return ' ';
+ case '"':
+ return '"';
+ case '/':
+ return '/';
+ case '\\':
+ return '\\';
+ case 'N':
+ return ch(0x0085);
+ case '_':
+ return ch(0x00A0);
+ case 'L':
+ return ch(0x2028);
+ case 'P':
+ return ch(0x2029);
+ case 'x':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 2)));
+ case 'u':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 4)));
+ case 'U':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 8)));
+ default:
+ return '';
+ }
+ };
+
+ return Unescaper;
+
+})();
+
+module.exports = Unescaper;
+
+
+
+},{"./Pattern":7,"./Utils":9}],9:[function(require,module,exports){
+var Pattern, Utils;
+
+Pattern = require('./Pattern');
+
+Utils = (function() {
+ function Utils() {}
+
+ Utils.REGEX_LEFT_TRIM_BY_CHAR = {};
+
+ Utils.REGEX_RIGHT_TRIM_BY_CHAR = {};
+
+ Utils.REGEX_SPACES = /\s+/g;
+
+ Utils.REGEX_DIGITS = /^\d+$/;
+
+ Utils.REGEX_OCTAL = /[^0-7]/gi;
+
+ Utils.REGEX_HEXADECIMAL = /[^a-f0-9]/gi;
+
+ Utils.PATTERN_DATE = new Pattern('^' + '(?<year>[0-9][0-9][0-9][0-9])' + '-(?<month>[0-9][0-9]?)' + '-(?<day>[0-9][0-9]?)' + '(?:(?:[Tt]|[ \t]+)' + '(?<hour>[0-9][0-9]?)' + ':(?<minute>[0-9][0-9])' + ':(?<second>[0-9][0-9])' + '(?:\.(?<fraction>[0-9]*))?' + '(?:[ \t]*(?<tz>Z|(?<tz_sign>[-+])(?<tz_hour>[0-9][0-9]?)' + '(?::(?<tz_minute>[0-9][0-9]))?))?)?' + '$', 'i');
+
+ Utils.LOCAL_TIMEZONE_OFFSET = new Date().getTimezoneOffset() * 60 * 1000;
+
+ Utils.trim = function(str, char) {
+ var regexLeft, regexRight;
+ if (char == null) {
+ char = '\\s';
+ }
+ return str.trim();
+ regexLeft = this.REGEX_LEFT_TRIM_BY_CHAR[char];
+ if (regexLeft == null) {
+ this.REGEX_LEFT_TRIM_BY_CHAR[char] = regexLeft = new RegExp('^' + char + '' + char + '*');
+ }
+ regexLeft.lastIndex = 0;
+ regexRight = this.REGEX_RIGHT_TRIM_BY_CHAR[char];
+ if (regexRight == null) {
+ this.REGEX_RIGHT_TRIM_BY_CHAR[char] = regexRight = new RegExp(char + '' + char + '*$');
+ }
+ regexRight.lastIndex = 0;
+ return str.replace(regexLeft, '').replace(regexRight, '');
+ };
+
+ Utils.ltrim = function(str, char) {
+ var regexLeft;
+ if (char == null) {
+ char = '\\s';
+ }
+ regexLeft = this.REGEX_LEFT_TRIM_BY_CHAR[char];
+ if (regexLeft == null) {
+ this.REGEX_LEFT_TRIM_BY_CHAR[char] = regexLeft = new RegExp('^' + char + '' + char + '*');
+ }
+ regexLeft.lastIndex = 0;
+ return str.replace(regexLeft, '');
+ };
+
+ Utils.rtrim = function(str, char) {
+ var regexRight;
+ if (char == null) {
+ char = '\\s';
+ }
+ regexRight = this.REGEX_RIGHT_TRIM_BY_CHAR[char];
+ if (regexRight == null) {
+ this.REGEX_RIGHT_TRIM_BY_CHAR[char] = regexRight = new RegExp(char + '' + char + '*$');
+ }
+ regexRight.lastIndex = 0;
+ return str.replace(regexRight, '');
+ };
+
+ Utils.isEmpty = function(value) {
+ return !value || value === '' || value === '0';
+ };
+
+ Utils.subStrCount = function(string, subString, start, length) {
+ var c, i, len, sublen, _i;
+ c = 0;
+ string = '' + string;
+ subString = '' + subString;
+ if (start != null) {
+ string = string.slice(start);
+ }
+ if (length != null) {
+ string = string.slice(0, length);
+ }
+ len = string.length;
+ sublen = subString.length;
+ for (i = _i = 0; 0 <= len ? _i < len : _i > len; i = 0 <= len ? ++_i : --_i) {
+ if (subString === string.slice(i, sublen)) {
+ c++;
+ i += sublen - 1;
+ }
+ }
+ return c;
+ };
+
+ Utils.isDigits = function(input) {
+ this.REGEX_DIGITS.lastIndex = 0;
+ return this.REGEX_DIGITS.test(input);
+ };
+
+ Utils.octDec = function(input) {
+ this.REGEX_OCTAL.lastIndex = 0;
+ return parseInt((input + '').replace(this.REGEX_OCTAL, ''), 8);
+ };
+
+ Utils.hexDec = function(input) {
+ this.REGEX_HEXADECIMAL.lastIndex = 0;
+ input = this.trim(input);
+ if ((input + '').slice(0, 2) === '0x') {
+ input = (input + '').slice(2);
+ }
+ return parseInt((input + '').replace(this.REGEX_HEXADECIMAL, ''), 16);
+ };
+
+ Utils.utf8chr = function(c) {
+ var ch;
+ ch = String.fromCharCode;
+ if (0x80 > (c %= 0x200000)) {
+ return ch(c);
+ }
+ if (0x800 > c) {
+ return ch(0xC0 | c >> 6) + ch(0x80 | c & 0x3F);
+ }
+ if (0x10000 > c) {
+ return ch(0xE0 | c >> 12) + ch(0x80 | c >> 6 & 0x3F) + ch(0x80 | c & 0x3F);
+ }
+ return ch(0xF0 | c >> 18) + ch(0x80 | c >> 12 & 0x3F) + ch(0x80 | c >> 6 & 0x3F) + ch(0x80 | c & 0x3F);
+ };
+
+ Utils.parseBoolean = function(input, strict) {
+ var lowerInput;
+ if (strict == null) {
+ strict = true;
+ }
+ if (typeof input === 'string') {
+ lowerInput = input.toLowerCase();
+ if (!strict) {
+ if (lowerInput === 'no') {
+ return false;
+ }
+ }
+ if (lowerInput === '0') {
+ return false;
+ }
+ if (lowerInput === 'false') {
+ return false;
+ }
+ if (lowerInput === '') {
+ return false;
+ }
+ return true;
+ }
+ return !!input;
+ };
+
+ Utils.isNumeric = function(input) {
+ this.REGEX_SPACES.lastIndex = 0;
+ return typeof input === 'number' || typeof input === 'string' && !isNaN(input) && input.replace(this.REGEX_SPACES, '') !== '';
+ };
+
+ Utils.stringToDate = function(str) {
+ var date, day, fraction, hour, info, minute, month, second, tz_hour, tz_minute, tz_offset, year;
+ if (!(str != null ? str.length : void 0)) {
+ return null;
+ }
+ info = this.PATTERN_DATE.exec(str);
+ if (!info) {
+ return null;
+ }
+ year = parseInt(info.year, 10);
+ month = parseInt(info.month, 10) - 1;
+ day = parseInt(info.day, 10);
+ if (info.hour == null) {
+ date = new Date(Date.UTC(year, month, day));
+ return date;
+ }
+ hour = parseInt(info.hour, 10);
+ minute = parseInt(info.minute, 10);
+ second = parseInt(info.second, 10);
+ if (info.fraction != null) {
+ fraction = info.fraction.slice(0, 3);
+ while (fraction.length < 3) {
+ fraction += '0';
+ }
+ fraction = parseInt(fraction, 10);
+ } else {
+ fraction = 0;
+ }
+ if (info.tz != null) {
+ tz_hour = parseInt(info.tz_hour, 10);
+ if (info.tz_minute != null) {
+ tz_minute = parseInt(info.tz_minute, 10);
+ } else {
+ tz_minute = 0;
+ }
+ tz_offset = (tz_hour * 60 + tz_minute) * 60000;
+ if ('-' === info.tz_sign) {
+ tz_offset *= -1;
+ }
+ }
+ date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
+ if (tz_offset) {
+ date.setTime(date.getTime() + tz_offset);
+ }
+ return date;
+ };
+
+ Utils.strRepeat = function(str, number) {
+ var i, res;
+ res = '';
+ i = 0;
+ while (i < number) {
+ res += str;
+ i++;
+ }
+ return res;
+ };
+
+ Utils.getStringFromFile = function(path, callback) {
+ var data, fs, name, req, xhr, _i, _len, _ref;
+ if (callback == null) {
+ callback = null;
+ }
+ xhr = null;
+ if (typeof window !== "undefined" && window !== null) {
+ if (window.XMLHttpRequest) {
+ xhr = new XMLHttpRequest();
+ } else if (window.ActiveXObject) {
+ _ref = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ name = _ref[_i];
+ try {
+ xhr = new ActiveXObject(name);
+ } catch (_error) {}
+ }
+ }
+ }
+ if (xhr != null) {
+ if (callback != null) {
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200 || xhr.status === 0) {
+ return callback(xhr.responseText);
+ } else {
+ return callback(null);
+ }
+ }
+ };
+ xhr.open('GET', path, true);
+ return xhr.send(null);
+ } else {
+ xhr.open('GET', path, false);
+ xhr.send(null);
+ if (xhr.status === 200 || xhr.status === 0) {
+ return xhr.responseText;
+ }
+ return null;
+ }
+ } else {
+ req = require;
+ fs = req('fs');
+ if (callback != null) {
+ return fs.readFile(path, function(err, data) {
+ if (err) {
+ return callback(null);
+ } else {
+ return callback(data);
+ }
+ });
+ } else {
+ data = fs.readFileSync(path);
+ if (data != null) {
+ return '' + data;
+ }
+ return null;
+ }
+ }
+ };
+
+ return Utils;
+
+})();
+
+module.exports = Utils;
+
+
+
+},{"./Pattern":7}],10:[function(require,module,exports){
+var Dumper, Parser, Utils, Yaml;
+
+Parser = require('./Parser');
+
+Dumper = require('./Dumper');
+
+Utils = require('./Utils');
+
+Yaml = (function() {
+ function Yaml() {}
+
+ Yaml.parse = function(input, exceptionOnInvalidType, objectDecoder) {
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ return new Parser().parse(input, exceptionOnInvalidType, objectDecoder);
+ };
+
+ Yaml.parseFile = function(path, callback, exceptionOnInvalidType, objectDecoder) {
+ var input;
+ if (callback == null) {
+ callback = null;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ if (callback != null) {
+ return Utils.getStringFromFile(path, (function(_this) {
+ return function(input) {
+ if (input != null) {
+ return _this.parse(input, exceptionOnInvalidType, objectDecoder);
+ }
+ return null;
+ };
+ })(this));
+ } else {
+ input = Utils.getStringFromFile(path);
+ if (input != null) {
+ return this.parse(input, exceptionOnInvalidType, objectDecoder);
+ }
+ return null;
+ }
+ };
+
+ Yaml.dump = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ var yaml;
+ if (inline == null) {
+ inline = 2;
+ }
+ if (indent == null) {
+ indent = 4;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ yaml = new Dumper();
+ yaml.indentation = indent;
+ return yaml.dump(input, inline, 0, exceptionOnInvalidType, objectEncoder);
+ };
+
+ Yaml.register = function() {
+ var require_handler;
+ require_handler = function(module, filename) {
+ return module.exports = YAML.parseFile(filename);
+ };
+ if ((typeof require !== "undefined" && require !== null ? require.extensions : void 0) != null) {
+ require.extensions['.yml'] = require_handler;
+ return require.extensions['.yaml'] = require_handler;
+ }
+ };
+
+ Yaml.prototype.stringify = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ return this.dump(input, inline, indent, exceptionOnInvalidType, objectEncoder);
+ };
+
+ Yaml.prototype.load = function(path, callback, exceptionOnInvalidType, objectDecoder) {
+ return this.parseFile(path, callback, exceptionOnInvalidType, objectDecoder);
+ };
+
+ return Yaml;
+
+})();
+
+if (typeof window !== "undefined" && window !== null) {
+ window.YAML = Yaml;
+}
+
+module.exports = Yaml;
+
+
+
+},{"./Dumper":1,"./Parser":6,"./Utils":9}]},{},[10])
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1wYWNrL19wcmVsdWRlLmpzIiwiL1VzZXJzL2plcmVteWZhL0RvY3VtZW50cy9Qcm9qZXRzL3lhbWxqcy0yL3NyYy9EdW1wZXIuY29mZmVlIiwiL1VzZXJzL2plcmVteWZhL0RvY3VtZW50cy9Qcm9qZXRzL3lhbWxqcy0yL3NyYy9Fc2NhcGVyLmNvZmZlZSIsIi9Vc2Vycy9qZXJlbXlmYS9Eb2N1bWVudHMvUHJvamV0cy95YW1sanMtMi9zcmMvRXhjZXB0aW9uL0R1bXBFeGNlcHRpb24uY29mZmVlIiwiL1VzZXJzL2plcmVteWZhL0RvY3VtZW50cy9Qcm9qZXRzL3lhbWxqcy0yL3NyYy9FeGNlcHRpb24vUGFyc2VFeGNlcHRpb24uY29mZmVlIiwiL1VzZXJzL2plcmVteWZhL0RvY3VtZW50cy9Qcm9qZXRzL3lhbWxqcy0yL3NyYy9JbmxpbmUuY29mZmVlIiwiL1VzZXJzL2plcmVteWZhL0RvY3VtZW50cy9Qcm9qZXRzL3lhbWxqcy0yL3NyYy9QYXJzZXIuY29mZmVlIiwiL1VzZXJzL2plcmVteWZhL0RvY3VtZW50cy9Qcm9qZXRzL3lhbWxqcy0yL3NyYy9QYXR0ZXJuLmNvZmZlZSIsIi9Vc2Vycy9qZXJlbXlmYS9Eb2N1bWVudHMvUHJvamV0cy95YW1sanMtMi9zcmMvVW5lc2NhcGVyLmNvZmZlZSIsIi9Vc2Vycy9qZXJlbXlmYS9Eb2N1bWVudHMvUHJvamV0cy95YW1sanMtMi9zcmMvVXRpbHMuY29mZmVlIiwiL1VzZXJzL2plcmVteWZhL0RvY3VtZW50cy9Qcm9qZXRzL3lhbWxqcy0yL3NyYy9ZYW1sLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0NBLElBQUEscUJBQUE7O0FBQUEsS0FBQSxHQUFVLE9BQUEsQ0FBUSxTQUFSLENBQVYsQ0FBQTs7QUFBQSxNQUNBLEdBQVUsT0FBQSxD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QUFXLENBQUEsTUFBQSxDQUFuQixHQUE2QixlQUE3QixDQUFBO2FBQ0EsT0FBTyxDQUFDLFVBQVcsQ0FBQSxPQUFBLENBQW5CLEdBQThCLGdCQUZsQztLQVBPO0VBQUEsQ0ExRFgsQ0FBQTs7QUFBQSxpQkF3RUEsU0FBQSxHQUFXLFNBQUMsS0FBRCxFQUFRLE1BQVIsRUFBZ0IsTUFBaEIsRUFBd0Isc0JBQXhCLEVBQWdELGFBQWhELEdBQUE7QUFDUCxXQUFPLElBQUMsQ0FBQSxJQUFELENBQU0sS0FBTixFQUFhLE1BQWIsRUFBcUIsTUFBckIsRUFBNkIsc0JBQTdCLEVBQXFELGFBQXJELENBQVAsQ0FETztFQUFBLENBeEVYLENBQUE7O0FBQUEsaUJBOEVBLElBQUEsR0FBTSxTQUFDLElBQUQsRUFBTyxRQUFQLEVBQWlCLHNCQUFqQixFQUF5QyxhQUF6QyxHQUFBO0FBQ0YsV0FBTyxJQUFDLENBQUEsU0FBRCxDQUFXLElBQVgsRUFBaUIsUUFBakIsRUFBMkIsc0JBQTNCLEVBQW1ELGFBQW5ELENBQVAsQ0FERTtFQUFBLENBOUVOLENBQUE7O2NBQUE7O0lBekJKLENBQUE7OztFQTRHQSxNQUFNLENBQUUsSUFBUixHQUFlO0NBNUdmOztBQUFBLE1BOEdNLENBQUMsT0FBUCxHQUFpQixJQTlHakIsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKX12YXIgZj1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwoZi5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxmLGYuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiXG5VdGlscyAgID0gcmVxdWlyZSAnLi9VdGlscydcbklubGluZSAgPSByZXF1aXJlICcuL0lubGluZSdcblxuIyBEdW1wZXIgZHVtcHMgSmF2YVNjcmlwdCB2YXJpYWJsZXMgdG8gWUFNTCBzdHJpbmdzLlxuI1xuY2xhc3MgRHVtcGVyXG5cbiAgICAjIFRoZSBhbW91bnQgb2Ygc3BhY2VzIHRvIHVzZSBmb3IgaW5kZW50YXRpb24gb2YgbmVzdGVkIG5vZGVzLlxuICAgIEBpbmRlbnRhdGlvbjogICA0XG5cblxuICAgICMgRHVtcHMgYSBKYXZhU2NyaXB0IHZhbHVlIHRvIFlBTUwuXG4gICAgI1xuICAgICMgQHBhcmFtIFtPYmplY3RdICAgaW5wdXQgICAgICAgICAgICAgICAgICAgVGhlIEphdmFTY3JpcHQgdmFsdWVcbiAgICAjIEBwYXJhbSBbSW50ZWdlcl0gIGlubGluZSAgICAgICAgICAgICAgICAgIFRoZSBsZXZlbCB3aGVyZSB5b3Ugc3dpdGNoIHRvIGlubGluZSBZQU1MXG4gICAgIyBAcGFyYW0gW0ludGVnZXJdICBpbmRlbnQgICAgICAgICAgICAgICAgICBUaGUgbGV2ZWwgb2YgaW5kZW50YXRpb24gKHVzZWQgaW50ZXJuYWxseSlcbiAgICAjIEBwYXJhbSBbQm9vbGVhbl0gIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUgIHRydWUgaWYgYW4gZXhjZXB0aW9uIG11c3QgYmUgdGhyb3duIG9uIGludmFsaWQgdHlwZXMgKGEgSmF2YVNjcmlwdCByZXNvdXJjZSBvciBvYmplY3QpLCBmYWxzZSBvdGhlcndpc2VcbiAgICAjIEBwYXJhbSBbRnVuY3Rpb25dIG9iamVjdEVuY29kZXIgICAgICAgICAgIEEgZnVuY3Rpb24gdG8gc2VyaWFsaXplIGN1c3RvbSBvYmplY3RzLCBudWxsIG90aGVyd2lzZVxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gIFRoZSBZQU1MIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBKYXZhU2NyaXB0IHZhbHVlXG4gICAgI1xuICAgIGR1bXA6IChpbnB1dCwgaW5saW5lID0gMCwgaW5kZW50ID0gMCwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSA9IGZhbHNlLCBvYmplY3RFbmNvZGVyID0gbnVsbCkgLT5cbiAgICAgICAgb3V0cHV0ID0gJydcbiAgICAgICAgcHJlZml4ID0gKGlmIGluZGVudCB0aGVuIFV0aWxzLnN0clJlcGVhdCgnICcsIGluZGVudCkgZWxzZSAnJylcblxuICAgICAgICBpZiBpbmxpbmUgPD0gMCBvciB0eXBlb2YoaW5wdXQpIGlzbnQgJ29iamVjdCcgb3IgVXRpbHMuaXNFbXB0eShpbnB1dClcbiAgICAgICAgICAgIG91dHB1dCArPSBwcmVmaXggKyBJbmxpbmUuZHVtcChpbnB1dCwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RW5jb2RlcilcbiAgICAgICAgXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGlzQUhhc2ggPSBub3QoaW5wdXQgaW5zdGFuY2VvZiBBcnJheSlcblxuICAgICAgICAgICAgZm9yIGtleSwgdmFsdWUgb2YgaW5wdXRcbiAgICAgICAgICAgICAgICB3aWxsQmVJbmxpbmVkID0gKGlubGluZSAtIDEgPD0gMCBvciB0eXBlb2YodmFsdWUpIGlzbnQgJ29iamVjdCcgb3IgVXRpbHMuaXNFbXB0eSh2YWx1ZSkpXG5cbiAgICAgICAgICAgICAgICBvdXRwdXQgKz1cbiAgICAgICAgICAgICAgICAgICAgcHJlZml4ICtcbiAgICAgICAgICAgICAgICAgICAgKGlmIGlzQUhhc2ggdGhlbiBJbmxpbmUuZHVtcChrZXksIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdEVuY29kZXIpICsgJzonIGVsc2UgJy0nKSArXG4gICAgICAgICAgICAgICAgICAgIChpZiB3aWxsQmVJbmxpbmVkIHRoZW4gJyAnIGVsc2UgXCJcXG5cIikgK1xuICAgICAgICAgICAgICAgICAgICBAZHVtcCh2YWx1ZSwgaW5saW5lIC0gMSwgKGlmIHdpbGxCZUlubGluZWQgdGhlbiAwIGVsc2UgaW5kZW50ICsgQGluZGVudGF0aW9uKSwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RW5jb2RlcikgK1xuICAgICAgICAgICAgICAgICAgICAoaWYgd2lsbEJlSW5saW5lZCB0aGVuIFwiXFxuXCIgZWxzZSAnJylcblxuICAgICAgICByZXR1cm4gb3V0cHV0XG5cblxubW9kdWxlLmV4cG9ydHMgPSBEdW1wZXJcbiIsIlxuUGF0dGVybiA9IHJlcXVpcmUgJy4vUGF0dGVybidcblxuIyBFc2NhcGVyIGVuY2Fwc3VsYXRlcyBlc2NhcGluZyBydWxlcyBmb3Igc2luZ2xlXG4jIGFuZCBkb3VibGUtcXVvdGVkIFlBTUwgc3RyaW5ncy5cbmNsYXNzIEVzY2FwZXJcblxuICAgICMgTWFwcGluZyBhcnJheXMgZm9yIGVzY2FwaW5nIGEgZG91YmxlIHF1b3RlZCBzdHJpbmcuIFRoZSBiYWNrc2xhc2ggaXNcbiAgICAjIGZpcnN0IHRvIGVuc3VyZSBwcm9wZXIgZXNjYXBpbmcuXG4gICAgQExJU1RfRVNDQVBFRVM6ICAgICAgICAgICAgICAgICBbJ1xcXFxcXFxcJywgJ1xcXFxcIicsICdcIicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXHgwMFwiLCAgXCJcXHgwMVwiLCAgXCJcXHgwMlwiLCAgXCJcXHgwM1wiLCAgXCJcXHgwNFwiLCAgXCJcXHgwNVwiLCAgXCJcXHgwNlwiLCAgXCJcXHgwN1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFx4MDhcIiwgIFwiXFx4MDlcIiwgIFwiXFx4MGFcIiwgIFwiXFx4MGJcIiwgIFwiXFx4MGNcIiwgIFwiXFx4MGRcIiwgIFwiXFx4MGVcIiwgIFwiXFx4MGZcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxceDEwXCIsICBcIlxceDExXCIsICBcIlxceDEyXCIsICBcIlxceDEzXCIsICBcIlxceDE0XCIsICBcIlxceDE1XCIsICBcIlxceDE2XCIsICBcIlxceDE3XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXHgxOFwiLCAgXCJcXHgxOVwiLCAgXCJcXHgxYVwiLCAgXCJcXHgxYlwiLCAgXCJcXHgxY1wiLCAgXCJcXHgxZFwiLCAgXCJcXHgxZVwiLCAgXCJcXHgxZlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjaCA9IFN0cmluZy5mcm9tQ2hhckNvZGUpKDB4MDA4NSksIGNoKDB4MDBBMCksIGNoKDB4MjAyOCksIGNoKDB4MjAyOSldXG4gICAgQExJU1RfRVNDQVBFRDogICAgICAgICAgICAgICAgICBbJ1xcXFxcIicsICdcXFxcXFxcXCcsICdcXFxcXCInLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFxcXDBcIiwgICBcIlxcXFx4MDFcIiwgXCJcXFxceDAyXCIsIFwiXFxcXHgwM1wiLCBcIlxcXFx4MDRcIiwgXCJcXFxceDA1XCIsIFwiXFxcXHgwNlwiLCBcIlxcXFxhXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXFxcYlwiLCAgIFwiXFxcXHRcIiwgICBcIlxcXFxuXCIsICAgXCJcXFxcdlwiLCAgIFwiXFxcXGZcIiwgICBcIlxcXFxyXCIsICAgXCJcXFxceDBlXCIsIFwiXFxcXHgwZlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFxcXHgxMFwiLCBcIlxcXFx4MTFcIiwgXCJcXFxceDEyXCIsIFwiXFxcXHgxM1wiLCBcIlxcXFx4MTRcIiwgXCJcXFxceDE1XCIsIFwiXFxcXHgxNlwiLCBcIlxcXFx4MTdcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxcXFx4MThcIiwgXCJcXFxceDE5XCIsIFwiXFxcXHgxYVwiLCBcIlxcXFxlXCIsICAgXCJcXFxceDFjXCIsIFwiXFxcXHgxZFwiLCBcIlxcXFx4MWVcIiwgXCJcXFxceDFmXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXFxcTlwiLCBcIlxcXFxfXCIsIFwiXFxcXExcIiwgXCJcXFxcUFwiXVxuXG4gICAgQE1BUFBJTkdfRVNDQVBFRVNfVE9fRVNDQVBFRDogICBkbyA9PlxuICAgICAgICBtYXBwaW5nID0ge31cbiAgICAgICAgZm9yIGkgaW4gWzAuLi5ATElTVF9FU0NBUEVFUy5sZW5ndGhdXG4gICAgICAgICAgICBtYXBwaW5nW0BMSVNUX0VTQ0FQRUVTW2ldXSA9IEBMSVNUX0VTQ0FQRURbaV1cbiAgICAgICAgcmV0dXJuIG1hcHBpbmcgXG5cbiAgICAjIENoYXJhY3RlcnMgdGhhdCB3b3VsZCBjYXVzZSBhIGR1bXBlZCBzdHJpbmcgdG8gcmVxdWlyZSBkb3VibGUgcXVvdGluZy5cbiAgICBAUEFUVEVSTl9DSEFSQUNURVJTX1RPX0VTQ0FQRTogIG5ldyBQYXR0ZXJuICdbXFxcXHgwMC1cXFxceDFmXXxcXHhjMlxceDg1fFxceGMyXFx4YTB8XFx4ZTJcXHg4MFxceGE4fFxceGUyXFx4ODBcXHhhOSdcblxuICAgICMgT3RoZXIgcHJlY29tcGlsZWQgcGF0dGVybnNcbiAgICBAUEFUVEVSTl9NQVBQSU5HX0VTQ0FQRUVTOiAgICAgIG5ldyBQYXR0ZXJuIEBMSVNUX0VTQ0FQRUVTLmpvaW4oJ3wnKVxuICAgIEBQQVRURVJOX1NJTkdMRV9RVU9USU5HOiAgICAgICAgbmV3IFBhdHRlcm4gJ1tcXFxcc1xcJ1wiOnt9W1xcXFxdLCYqIz9dfF5bLT98PD49ISVAYF0nXG5cblxuXG4gICAgIyBEZXRlcm1pbmVzIGlmIGEgSmF2YVNjcmlwdCB2YWx1ZSB3b3VsZCByZXF1aXJlIGRvdWJsZSBxdW90aW5nIGluIFlBTUwuXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddICAgdmFsdWUgICBBIEphdmFTY3JpcHQgdmFsdWUgdmFsdWVcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtCb29sZWFuXSB0cnVlICAgIGlmIHRoZSB2YWx1ZSB3b3VsZCByZXF1aXJlIGRvdWJsZSBxdW90ZXMuXG4gICAgI1xuICAgIEByZXF1aXJlc0RvdWJsZVF1b3Rpbmc6ICh2YWx1ZSkgLT5cbiAgICAgICAgcmV0dXJuIEBQQVRURVJOX0NIQVJBQ1RFUlNfVE9fRVNDQVBFLnRlc3QgdmFsdWVcblxuXG4gICAgIyBFc2NhcGVzIGFuZCBzdXJyb3VuZHMgYSBKYXZhU2NyaXB0IHZhbHVlIHdpdGggZG91YmxlIHF1b3Rlcy5cbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gICB2YWx1ZSAgIEEgSmF2YVNjcmlwdCB2YWx1ZVxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gIFRoZSBxdW90ZWQsIGVzY2FwZWQgc3RyaW5nXG4gICAgI1xuICAgIEBlc2NhcGVXaXRoRG91YmxlUXVvdGVzOiAodmFsdWUpIC0+XG4gICAgICAgIHJldHVybiBAUEFUVEVSTl9NQVBQSU5HX0VTQ0FQRUVTLnJlcGxhY2UgdmFsdWUsIChzdHIpID0+XG4gICAgICAgICAgICByZXR1cm4gQE1BUFBJTkdfRVNDQVBFRVNfVE9fRVNDQVBFRFtzdHJdXG5cblxuICAgICMgRGV0ZXJtaW5lcyBpZiBhIEphdmFTY3JpcHQgdmFsdWUgd291bGQgcmVxdWlyZSBzaW5nbGUgcXVvdGluZyBpbiBZQU1MLlxuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSAgIHZhbHVlICAgQSBKYXZhU2NyaXB0IHZhbHVlXG4gICAgI1xuICAgICMgQHJldHVybiBbQm9vbGVhbl0gdHJ1ZSBpZiB0aGUgdmFsdWUgd291bGQgcmVxdWlyZSBzaW5nbGUgcXVvdGVzLlxuICAgICNcbiAgICBAcmVxdWlyZXNTaW5nbGVRdW90aW5nOiAodmFsdWUpIC0+XG4gICAgICAgIHJldHVybiBAUEFUVEVSTl9TSU5HTEVfUVVPVElORy50ZXN0IHZhbHVlXG5cblxuICAgICMgRXNjYXBlcyBhbmQgc3Vycm91bmRzIGEgSmF2YVNjcmlwdCB2YWx1ZSB3aXRoIHNpbmdsZSBxdW90ZXMuXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddICAgdmFsdWUgICBBIEphdmFTY3JpcHQgdmFsdWVcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtTdHJpbmddICBUaGUgcXVvdGVkLCBlc2NhcGVkIHN0cmluZ1xuICAgICNcbiAgICBAZXNjYXBlV2l0aFNpbmdsZVF1b3RlczogKHZhbHVlKSAtPlxuICAgICAgICByZXR1cm4gXCInXCIrdmFsdWUucmVwbGFjZSgnXFwnJywgJ1xcJ1xcJycpK1wiJ1wiXG5cblxubW9kdWxlLmV4cG9ydHMgPSBFc2NhcGVyXG5cbiIsIlxuY2xhc3MgRHVtcEV4Y2VwdGlvbiBleHRlbmRzIEVycm9yXG5cbiAgICBjb25zdHJ1Y3RvcjogKEBtZXNzYWdlLCBAcGFyc2VkTGluZSwgQHNuaXBwZXQpIC0+XG5cbiAgICB0b1N0cmluZzogLT5cbiAgICAgICAgaWYgQHBhcnNlZExpbmU/IGFuZCBAc25pcHBldD9cbiAgICAgICAgICAgIHJldHVybiAnPER1bXBFeGNlcHRpb24+ICcgKyBAbWVzc2FnZSArICcgKGxpbmUgJyArIEBwYXJzZWRMaW5lICsgJzogXFwnJyArIEBzbmlwcGV0ICsgJ1xcJyknXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHJldHVybiAnPER1bXBFeGNlcHRpb24+ICcgKyBAbWVzc2FnZVxuXG5tb2R1bGUuZXhwb3J0cyA9IER1bXBFeGNlcHRpb25cbiIsIlxuY2xhc3MgUGFyc2VFeGNlcHRpb24gZXh0ZW5kcyBFcnJvclxuXG4gICAgY29uc3RydWN0b3I6IChAbWVzc2FnZSwgQHBhcnNlZExpbmUsIEBzbmlwcGV0KSAtPlxuXG4gICAgdG9TdHJpbmc6IC0+XG4gICAgICAgIGlmIEBwYXJzZWRMaW5lPyBhbmQgQHNuaXBwZXQ/XG4gICAgICAgICAgICByZXR1cm4gJzxQYXJzZUV4Y2VwdGlvbj4gJyArIEBtZXNzYWdlICsgJyAobGluZSAnICsgQHBhcnNlZExpbmUgKyAnOiBcXCcnICsgQHNuaXBwZXQgKyAnXFwnKSdcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmV0dXJuICc8UGFyc2VFeGNlcHRpb24+ICcgKyBAbWVzc2FnZVxuXG5tb2R1bGUuZXhwb3J0cyA9IFBhcnNlRXhjZXB0aW9uXG4iLCJcblBhdHRlcm4gICAgICAgICA9IHJlcXVpcmUgJy4vUGF0dGVybidcblVuZXNjYXBlciAgICAgICA9IHJlcXVpcmUgJy4vVW5lc2NhcGVyJ1xuRXNjYXBlciAgICAgICAgID0gcmVxdWlyZSAnLi9Fc2NhcGVyJ1xuVXRpbHMgICAgICAgICAgID0gcmVxdWlyZSAnLi9VdGlscydcblBhcnNlRXhjZXB0aW9uICA9IHJlcXVpcmUgJy4vRXhjZXB0aW9uL1BhcnNlRXhjZXB0aW9uJ1xuRHVtcEV4Y2VwdGlvbiAgID0gcmVxdWlyZSAnLi9FeGNlcHRpb24vRHVtcEV4Y2VwdGlvbidcblxuIyBJbmxpbmUgWUFNTCBwYXJzaW5nIGFuZCBkdW1waW5nXG5jbGFzcyBJbmxpbmVcblxuICAgICMgUXVvdGVkIHN0cmluZyByZWd1bGFyIGV4cHJlc3Npb25cbiAgICBAUkVHRVhfUVVPVEVEX1NUUklORzogICAgICAgICAgICAgICAnKD86XCIoPzpbXlwiXFxcXFxcXFxdKig/OlxcXFxcXFxcLlteXCJcXFxcXFxcXF0qKSopXCJ8XFwnKD86W15cXCddKig/OlxcJ1xcJ1teXFwnXSopKilcXCcpJ1xuXG4gICAgIyBQcmUtY29tcGlsZWQgcGF0dGVybnNcbiAgICAjXG4gICAgQFBBVFRFUk5fVFJBSUxJTkdfQ09NTUVOVFM6ICAgICAgICAgbmV3IFBhdHRlcm4gJ15cXFxccyojLiokJ1xuICAgIEBQQVRURVJOX1FVT1RFRF9TQ0FMQVI6ICAgICAgICAgICAgIG5ldyBQYXR0ZXJuICdeJytAUkVHRVhfUVVPVEVEX1NUUklOR1xuICAgIEBQQVRURVJOX1RIT1VTQU5EX05VTUVSSUNfU0NBTEFSOiAgIG5ldyBQYXR0ZXJuICdeKC18XFxcXCspP1swLTksXSsoXFxcXC5bMC05XSspPyQnXG4gICAgQFBBVFRFUk5fU0NBTEFSX0JZX0RFTElNSVRFUlM6ICAgICAge31cblxuICAgICMgU2V0dGluZ3NcbiAgICBAc2V0dGluZ3M6IHt9XG5cblxuICAgICMgQ29uZmlndXJlIFlBTUwgaW5saW5lLlxuICAgICNcbiAgICAjIEBwYXJhbSBbQm9vbGVhbl0gIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUgIHRydWUgaWYgYW4gZXhjZXB0aW9uIG11c3QgYmUgdGhyb3duIG9uIGludmFsaWQgdHlwZXMgKGEgSmF2YVNjcmlwdCByZXNvdXJjZSBvciBvYmplY3QpLCBmYWxzZSBvdGhlcndpc2VcbiAgICAjIEBwYXJhbSBbRnVuY3Rpb25dIG9iamVjdERlY29kZXIgICAgICAgICAgIEEgZnVuY3Rpb24gdG8gZGVzZXJpYWxpemUgY3VzdG9tIG9iamVjdHMsIG51bGwgb3RoZXJ3aXNlXG4gICAgI1xuICAgIEBjb25maWd1cmU6IChleGNlcHRpb25PbkludmFsaWRUeXBlID0gbnVsbCwgb2JqZWN0RGVjb2RlciA9IG51bGwpIC0+XG4gICAgICAgICMgVXBkYXRlIHNldHRpbmdzXG4gICAgICAgIEBzZXR0aW5ncy5leGNlcHRpb25PbkludmFsaWRUeXBlID0gZXhjZXB0aW9uT25JbnZhbGlkVHlwZVxuICAgICAgICBAc2V0dGluZ3Mub2JqZWN0RGVjb2RlciA9IG9iamVjdERlY29kZXJcbiAgICAgICAgcmV0dXJuXG5cblxuICAgICMgQ29udmVydHMgYSBZQU1MIHN0cmluZyB0byBhIEphdmFTY3JpcHQgb2JqZWN0LlxuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSAgIHZhbHVlICAgICAgICAgICAgICAgICAgIEEgWUFNTCBzdHJpbmdcbiAgICAjIEBwYXJhbSBbQm9vbGVhbl0gIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUgIHRydWUgaWYgYW4gZXhjZXB0aW9uIG11c3QgYmUgdGhyb3duIG9uIGludmFsaWQgdHlwZXMgKGEgSmF2YVNjcmlwdCByZXNvdXJjZSBvciBvYmplY3QpLCBmYWxzZSBvdGhlcndpc2VcbiAgICAjIEBwYXJhbSBbRnVuY3Rpb25dIG9iamVjdERlY29kZXIgICAgICAgICAgIEEgZnVuY3Rpb24gdG8gZGVzZXJpYWxpemUgY3VzdG9tIG9iamVjdHMsIG51bGwgb3RoZXJ3aXNlXG4gICAgI1xuICAgICMgQHJldHVybiBbT2JqZWN0XSAgQSBKYXZhU2NyaXB0IG9iamVjdCByZXByZXNlbnRpbmcgdGhlIFlBTUwgc3RyaW5nXG4gICAgI1xuICAgICMgQHRocm93IFtQYXJzZUV4Y2VwdGlvbl1cbiAgICAjXG4gICAgQHBhcnNlOiAodmFsdWUsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUgPSBmYWxzZSwgb2JqZWN0RGVjb2RlciA9IG51bGwpIC0+XG4gICAgICAgICMgVXBkYXRlIHNldHRpbmdzIGZyb20gbGFzdCBjYWxsIG9mIElubGluZS5wYXJzZSgpXG4gICAgICAgIEBzZXR0aW5ncy5leGNlcHRpb25PbkludmFsaWRUeXBlID0gZXhjZXB0aW9uT25JbnZhbGlkVHlwZVxuICAgICAgICBAc2V0dGluZ3Mub2JqZWN0RGVjb2RlciA9IG9iamVjdERlY29kZXJcblxuICAgICAgICBpZiBub3QgdmFsdWU/XG4gICAgICAgICAgICByZXR1cm4gJydcblxuICAgICAgICB2YWx1ZSA9IFV0aWxzLnRyaW0gdmFsdWVcblxuICAgICAgICBpZiAwIGlzIHZhbHVlLmxlbmd0aFxuICAgICAgICAgICAgcmV0dXJuICcnXG5cbiAgICAgICAgIyBLZWVwIGEgY29udGV4dCBvYmplY3QgdG8gcGFzcyB0aHJvdWdoIHN0YXRpYyBtZXRob2RzXG4gICAgICAgIGNvbnRleHQgPSB7ZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RGVjb2RlciwgaTogMH1cblxuICAgICAgICBzd2l0Y2ggdmFsdWUuY2hhckF0KDApXG4gICAgICAgICAgICB3aGVuICdbJ1xuICAgICAgICAgICAgICAgIHJlc3VsdCA9IEBwYXJzZVNlcXVlbmNlIHZhbHVlLCBjb250ZXh0XG4gICAgICAgICAgICAgICAgKytjb250ZXh0LmlcbiAgICAgICAgICAgIHdoZW4gJ3snXG4gICAgICAgICAgICAgICAgcmVzdWx0ID0gQHBhcnNlTWFwcGluZyB2YWx1ZSwgY29udGV4dFxuICAgICAgICAgICAgICAgICsrY29udGV4dC5pXG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgcmVzdWx0ID0gQHBhcnNlU2NhbGFyIHZhbHVlLCBudWxsLCBbJ1wiJywgXCInXCJdLCBjb250ZXh0XG5cbiAgICAgICAgIyBTb21lIGNvbW1lbnRzIGFyZSBhbGxvd2VkIGF0IHRoZSBlbmRcbiAgICAgICAgaWYgQFBBVFRFUk5fVFJBSUxJTkdfQ09NTUVOVFMucmVwbGFjZSh2YWx1ZVtjb250ZXh0LmkuLl0sICcnKSBpc250ICcnXG4gICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2VFeGNlcHRpb24gJ1VuZXhwZWN0ZWQgY2hhcmFjdGVycyBuZWFyIFwiJyt2YWx1ZVtjb250ZXh0LmkuLl0rJ1wiLidcblxuICAgICAgICByZXR1cm4gcmVzdWx0XG5cblxuICAgICMgRHVtcHMgYSBnaXZlbiBKYXZhU2NyaXB0IHZhcmlhYmxlIHRvIGEgWUFNTCBzdHJpbmcuXG4gICAgI1xuICAgICMgQHBhcmFtIFtPYmplY3RdICAgdmFsdWUgICAgICAgICAgICAgICAgICAgVGhlIEphdmFTY3JpcHQgdmFyaWFibGUgdG8gY29udmVydFxuICAgICMgQHBhcmFtIFtCb29sZWFuXSAgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSAgdHJ1ZSBpZiBhbiBleGNlcHRpb24gbXVzdCBiZSB0aHJvd24gb24gaW52YWxpZCB0eXBlcyAoYSBKYXZhU2NyaXB0IHJlc291cmNlIG9yIG9iamVjdCksIGZhbHNlIG90aGVyd2lzZVxuICAgICMgQHBhcmFtIFtGdW5jdGlvbl0gb2JqZWN0RW5jb2RlciAgICAgICAgICAgQSBmdW5jdGlvbiB0byBzZXJpYWxpemUgY3VzdG9tIG9iamVjdHMsIG51bGwgb3RoZXJ3aXNlXG4gICAgI1xuICAgICMgQHJldHVybiBbU3RyaW5nXSAgVGhlIFlBTUwgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgSmF2YVNjcmlwdCBvYmplY3RcbiAgICAjXG4gICAgIyBAdGhyb3cgW0R1bXBFeGNlcHRpb25dXG4gICAgI1xuICAgIEBkdW1wOiAodmFsdWUsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUgPSBmYWxzZSwgb2JqZWN0RW5jb2RlciA9IG51bGwpIC0+XG4gICAgICAgIGlmIG5vdCB2YWx1ZT9cbiAgICAgICAgICAgIHJldHVybiAnbnVsbCdcbiAgICAgICAgdHlwZSA9IHR5cGVvZiB2YWx1ZVxuICAgICAgICBpZiB0eXBlIGlzICdvYmplY3QnXG4gICAgICAgICAgICBpZiB2YWx1ZSBpbnN0YW5jZW9mIERhdGVcbiAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWUudG9JU09TdHJpbmcoKVxuICAgICAgICAgICAgZWxzZSBpZiBvYmplY3RFbmNvZGVyP1xuICAgICAgICAgICAgICAgIHJlc3VsdCA9IG9iamVjdEVuY29kZXIgdmFsdWVcbiAgICAgICAgICAgICAgICBpZiB0eXBlb2YgcmVzdWx0IGlzICdzdHJpbmcnIG9yIHJlc3VsdD9cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdFxuICAgICAgICAgICAgcmV0dXJuIEBkdW1wT2JqZWN0IHZhbHVlXG4gICAgICAgIGlmIHR5cGUgaXMgJ2Jvb2xlYW4nXG4gICAgICAgICAgICByZXR1cm4gKGlmIHZhbHVlIHRoZW4gJ3RydWUnIGVsc2UgJ2ZhbHNlJylcbiAgICAgICAgaWYgVXRpbHMuaXNEaWdpdHModmFsdWUpXG4gICAgICAgICAgICByZXR1cm4gKGlmIHR5cGUgaXMgJ3N0cmluZycgdGhlbiBcIidcIit2YWx1ZStcIidcIiBlbHNlICcnK3BhcnNlSW50KHZhbHVlKSlcbiAgICAgICAgaWYgVXRpbHMuaXNOdW1lcmljKHZhbHVlKVxuICAgICAgICAgICAgcmV0dXJuIChpZiB0eXBlIGlzICdzdHJpbmcnIHRoZW4gXCInXCIrdmFsdWUrXCInXCIgZWxzZSAnJytwYXJzZUZsb2F0KHZhbHVlKSlcbiAgICAgICAgaWYgdHlwZSBpcyAnbnVtYmVyJ1xuICAgICAgICAgICAgcmV0dXJuIChpZiB2YWx1ZSBpcyBJbmZpbml0eSB0aGVuICcuSW5mJyBlbHNlIChpZiB2YWx1ZSBpcyAtSW5maW5pdHkgdGhlbiAnLS5JbmYnIGVsc2UgKGlmIGlzTmFOKHZhbHVlKSB0aGVuICcuTmFOJyBlbHNlIHZhbHVlKSkpXG4gICAgICAgIGlmIEVzY2FwZXIucmVxdWlyZXNEb3VibGVRdW90aW5nIHZhbHVlXG4gICAgICAgICAgICByZXR1cm4gRXNjYXBlci5lc2NhcGVXaXRoRG91YmxlUXVvdGVzIHZhbHVlXG4gICAgICAgIGlmIEVzY2FwZXIucmVxdWlyZXNTaW5nbGVRdW90aW5nIHZhbHVlXG4gICAgICAgICAgICByZXR1cm4geWFtbC5lc2NhcGVXaXRoU2luZ2xlUXVvdGVzIHZhbHVlXG4gICAgICAgIGlmICcnIGlzIHZhbHVlXG4gICAgICAgICAgICByZXR1cm4gJ1wiXCInXG4gICAgICAgIGlmIFV0aWxzLlBBVFRFUk5fREFURS50ZXN0IHZhbHVlXG4gICAgICAgICAgICByZXR1cm4gXCInXCIrdmFsdWUrXCInXCI7XG4gICAgICAgIGlmIHZhbHVlLnRvTG93ZXJDYXNlKCkgaW4gWydudWxsJywnficsJ3RydWUnLCdmYWxzZSddXG4gICAgICAgICAgICByZXR1cm4gXCInXCIrdmFsdWUrXCInXCJcbiAgICAgICAgIyBEZWZhdWx0XG4gICAgICAgIHJldHVybiB2YWx1ZTtcblxuXG4gICAgIyBEdW1wcyBhIEphdmFTY3JpcHQgb2JqZWN0IHRvIGEgWUFNTCBzdHJpbmcuXG4gICAgI1xuICAgICMgQHBhcmFtIFtPYmplY3RdICAgdmFsdWUgICAgICAgICAgICAgICAgICAgVGhlIEphdmFTY3JpcHQgb2JqZWN0IHRvIGR1bXBcbiAgICAjIEBwYXJhbSBbQm9vbGVhbl0gIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUgIHRydWUgaWYgYW4gZXhjZXB0aW9uIG11c3QgYmUgdGhyb3duIG9uIGludmFsaWQgdHlwZXMgKGEgSmF2YVNjcmlwdCByZXNvdXJjZSBvciBvYmplY3QpLCBmYWxzZSBvdGhlcndpc2VcbiAgICAjIEBwYXJhbSBbRnVuY3Rpb25dIG9iamVjdEVuY29kZXIgICAgICAgICAgIEEgZnVuY3Rpb24gZG8gc2VyaWFsaXplIGN1c3RvbSBvYmplY3RzLCBudWxsIG90aGVyd2lzZVxuICAgICNcbiAgICAjIEByZXR1cm4gc3RyaW5nIFRoZSBZQU1MIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIEphdmFTY3JpcHQgb2JqZWN0XG4gICAgI1xuICAgIEBkdW1wT2JqZWN0OiAodmFsdWUsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdFN1cHBvcnQgPSBudWxsKSAtPlxuICAgICAgICAjIEFycmF5XG4gICAgICAgIGlmIHZhbHVlIGluc3RhbmNlb2YgQXJyYXlcbiAgICAgICAgICAgIG91dHB1dCA9IFtdXG4gICAgICAgICAgICBmb3IgdmFsIGluIHZhbHVlXG4gICAgICAgICAgICAgICAgb3V0cHV0LnB1c2ggQGR1bXAgdmFsXG4gICAgICAgICAgICByZXR1cm4gJ1snK291dHB1dC5qb2luKCcsICcpKyddJ1xuXG4gICAgICAgICMgTWFwcGluZ1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBvdXRwdXQgPSBbXVxuICAgICAgICAgICAgZm9yIGtleSwgdmFsIG9mIHZhbHVlXG4gICAgICAgICAgICAgICAgb3V0cHV0LnB1c2ggQGR1bXAoa2V5KSsnOiAnK0BkdW1wKHZhbClcbiAgICAgICAgICAgIHJldHVybiAneycrb3V0cHV0LmpvaW4oJywgJykrJ30nXG5cblxuICAgICMgUGFyc2VzIGEgc2NhbGFyIHRvIGEgWUFNTCBzdHJpbmcuXG4gICAgI1xuICAgICMgQHBhcmFtIFtPYmplY3RdICAgc2NhbGFyXG4gICAgIyBAcGFyYW0gW0FycmF5XSAgICBkZWxpbWl0ZXJzXG4gICAgIyBAcGFyYW0gW0FycmF5XSAgICBzdHJpbmdEZWxpbWl0ZXJzXG4gICAgIyBAcGFyYW0gW09iamVjdF0gICBjb250ZXh0XG4gICAgIyBAcGFyYW0gW0Jvb2xlYW5dICBldmFsdWF0ZVxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gIEEgWUFNTCBzdHJpbmdcbiAgICAjXG4gICAgIyBAdGhyb3cgW1BhcnNlRXhjZXB0aW9uXSBXaGVuIG1hbGZvcm1lZCBpbmxpbmUgWUFNTCBzdHJpbmcgaXMgcGFyc2VkXG4gICAgI1xuICAgIEBwYXJzZVNjYWxhcjogKHNjYWxhciwgZGVsaW1pdGVycyA9IG51bGwsIHN0cmluZ0RlbGltaXRlcnMgPSBbJ1wiJywgXCInXCJdLCBjb250ZXh0ID0gbnVsbCwgZXZhbHVhdGUgPSB0cnVlKSAtPlxuICAgICAgICB1bmxlc3MgY29udGV4dD9cbiAgICAgICAgICAgIGNvbnRleHQgPSBleGNlcHRpb25PbkludmFsaWRUeXBlOiBAc2V0dGluZ3MuZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RGVjb2RlcjogQHNldHRpbmdzLm9iamVjdERlY29kZXIsIGk6IDBcbiAgICAgICAge2l9ID0gY29udGV4dFxuXG4gICAgICAgIGlmIHNjYWxhci5jaGFyQXQoaSkgaW4gc3RyaW5nRGVsaW1pdGVyc1xuICAgICAgICAgICAgIyBRdW90ZWQgc2NhbGFyXG4gICAgICAgICAgICBvdXRwdXQgPSBAcGFyc2VRdW90ZWRTY2FsYXIgc2NhbGFyLCBjb250ZXh0XG4gICAgICAgICAgICB7aX0gPSBjb250ZXh0XG5cbiAgICAgICAgICAgIGlmIGRlbGltaXRlcnM/XG4gICAgICAgICAgICAgICAgdG1wID0gVXRpbHMubHRyaW0gc2NhbGFyW2kuLl0sICcgJ1xuICAgICAgICAgICAgICAgIGlmIG5vdCh0bXAuY2hhckF0KDApIGluIGRlbGltaXRlcnMpXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZUV4Y2VwdGlvbiAnVW5leHBlY3RlZCBjaGFyYWN0ZXJzICgnK3NjYWxhcltpLi5dKycpLidcblxuICAgICAgICBlbHNlXG4gICAgICAgICAgICAjIFwibm9ybWFsXCIgc3RyaW5nXG4gICAgICAgICAgICBpZiBub3QgZGVsaW1pdGVyc1xuICAgICAgICAgICAgICAgIG91dHB1dCA9IHNjYWxhcltpLi5dXG4gICAgICAgICAgICAgICAgaSArPSBvdXRwdXQubGVuZ3RoXG5cbiAgICAgICAgICAgICAgICAjIFJlbW92ZSBjb21tZW50c1xuICAgICAgICAgICAgICAgIHN0cnBvcyA9IG91dHB1dC5pbmRleE9mICcgIydcbiAgICAgICAgICAgICAgICBpZiBzdHJwb3MgaXNudCAtMVxuICAgICAgICAgICAgICAgICAgICBvdXRwdXQgPSBVdGlscy5ydHJpbSBvdXRwdXRbMC4uLnN0cnBvc11cblxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIGpvaW5lZERlbGltaXRlcnMgPSBkZWxpbWl0ZXJzLmpvaW4oJ3wnKVxuICAgICAgICAgICAgICAgIHBhdHRlcm4gPSBAUEFUVEVSTl9TQ0FMQVJfQllfREVMSU1JVEVSU1tqb2luZWREZWxpbWl0ZXJzXVxuICAgICAgICAgICAgICAgIHVubGVzcyBwYXR0ZXJuP1xuICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gbmV3IFBhdHRlcm4gJ14oLis/KSgnK2pvaW5lZERlbGltaXRlcnMrJyknXG4gICAgICAgICAgICAgICAgICAgIEBQQVRURVJOX1NDQUxBUl9CWV9ERUxJTUlURVJTW2pvaW5lZERlbGltaXRlcnNdID0gcGF0dGVyblxuICAgICAgICAgICAgICAgIGlmIG1hdGNoID0gcGF0dGVybi5leGVjIHNjYWxhcltpLi5dXG4gICAgICAgICAgICAgICAgICAgIG91dHB1dCA9IG1hdGNoWzFdXG4gICAgICAgICAgICAgICAgICAgIGkgKz0gb3V0cHV0Lmxlbmd0aFxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlRXhjZXB0aW9uICdNYWxmb3JtZWQgaW5saW5lIFlBTUwgc3RyaW5nICgnK3NjYWxhcisnKS4nXG5cblxuICAgICAgICAgICAgaWYgZXZhbHVhdGVcbiAgICAgICAgICAgICAgICBvdXRwdXQgPSBAZXZhbHVhdGVTY2FsYXIgb3V0cHV0LCBjb250ZXh0XG5cbiAgICAgICAgY29udGV4dC5pID0gaVxuICAgICAgICByZXR1cm4gb3V0cHV0XG5cblxuICAgICMgUGFyc2VzIGEgcXVvdGVkIHNjYWxhciB0byBZQU1MLlxuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSAgIHNjYWxhclxuICAgICMgQHBhcmFtIFtPYmplY3RdICAgY29udGV4dFxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gIEEgWUFNTCBzdHJpbmdcbiAgICAjXG4gICAgIyBAdGhyb3cgW1BhcnNlRXhjZXB0aW9uXSBXaGVuIG1hbGZvcm1lZCBpbmxpbmUgWUFNTCBzdHJpbmcgaXMgcGFyc2VkXG4gICAgI1xuICAgIEBwYXJzZVF1b3RlZFNjYWxhcjogKHNjYWxhciwgY29udGV4dCkgLT5cbiAgICAgICAge2l9ID0gY29udGV4dFxuXG4gICAgICAgIHVubGVzcyBtYXRjaCA9IEBQQVRURVJOX1FVT1RFRF9TQ0FMQVIuZXhlYyBzY2FsYXJbaS4uXVxuICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlRXhjZXB0aW9uICdNYWxmb3JtZWQgaW5saW5lIFlBTUwgc3RyaW5nICgnK3NjYWxhcltpLi5dKycpLidcblxuICAgICAgICBvdXRwdXQgPSBtYXRjaFswXS5zdWJzdHIoMSwgbWF0Y2hbMF0ubGVuZ3RoIC0gMilcblxuICAgICAgICBpZiAnXCInIGlzIHNjYWxhci5jaGFyQXQoaSlcbiAgICAgICAgICAgIG91dHB1dCA9IFVuZXNjYXBlci51bmVzY2FwZURvdWJsZVF1b3RlZFN0cmluZyBvdXRwdXRcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgb3V0cHV0ID0gVW5lc2NhcGVyLnVuZXNjYXBlU2luZ2xlUXVvdGVkU3RyaW5nIG91dHB1dFxuXG4gICAgICAgIGkgKz0gbWF0Y2hbMF0ubGVuZ3RoXG5cbiAgICAgICAgY29udGV4dC5pID0gaVxuICAgICAgICByZXR1cm4gb3V0cHV0XG5cblxuICAgICMgUGFyc2VzIGEgc2VxdWVuY2UgdG8gYSBZQU1MIHN0cmluZy5cbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gICBzZXF1ZW5jZVxuICAgICMgQHBhcmFtIFtPYmplY3RdICAgY29udGV4dFxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gIEEgWUFNTCBzdHJpbmdcbiAgICAjXG4gICAgIyBAdGhyb3cgW1BhcnNlRXhjZXB0aW9uXSBXaGVuIG1hbGZvcm1lZCBpbmxpbmUgWUFNTCBzdHJpbmcgaXMgcGFyc2VkXG4gICAgI1xuICAgIEBwYXJzZVNlcXVlbmNlOiAoc2VxdWVuY2UsIGNvbnRleHQpIC0+XG4gICAgICAgIG91dHB1dCA9IFtdXG4gICAgICAgIGxlbiA9IHNlcXVlbmNlLmxlbmd0aFxuICAgICAgICB7aX0gPSBjb250ZXh0XG4gICAgICAgIGkgKz0gMVxuXG4gICAgICAgICMgW2ZvbywgYmFyLCAuLi5dXG4gICAgICAgIHdoaWxlIGkgPCBsZW5cbiAgICAgICAgICAgIGNvbnRleHQuaSA9IGlcbiAgICAgICAgICAgIHN3aXRjaCBzZXF1ZW5jZS5jaGFyQXQoaSlcbiAgICAgICAgICAgICAgICB3aGVuICdbJ1xuICAgICAgICAgICAgICAgICAgICAjIE5lc3RlZCBzZXF1ZW5jZVxuICAgICAgICAgICAgICAgICAgICBvdXRwdXQucHVzaCBAcGFyc2VTZXF1ZW5jZSBzZXF1ZW5jZSwgY29udGV4dFxuICAgICAgICAgICAgICAgICAgICB7aX0gPSBjb250ZXh0XG4gICAgICAgICAgICAgICAgd2hlbiAneydcbiAgICAgICAgICAgICAgICAgICAgIyBOZXN0ZWQgbWFwcGluZ1xuICAgICAgICAgICAgICAgICAgICBvdXRwdXQucHVzaCBAcGFyc2VNYXBwaW5nIHNlcXVlbmNlLCBjb250ZXh0XG4gICAgICAgICAgICAgICAgICAgIHtpfSA9IGNvbnRleHRcbiAgICAgICAgICAgICAgICB3aGVuICddJ1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb3V0cHV0XG4gICAgICAgICAgICAgICAgd2hlbiAnLCcsICcgJywgXCJcXG5cIlxuICAgICAgICAgICAgICAgICAgICAjIERvIG5vdGhpbmdcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIGlzUXVvdGVkID0gKHNlcXVlbmNlLmNoYXJBdChpKSBpbiBbJ1wiJywgXCInXCJdKVxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IEBwYXJzZVNjYWxhciBzZXF1ZW5jZSwgWycsJywgJ10nXSwgWydcIicsIFwiJ1wiXSwgY29udGV4dFxuICAgICAgICAgICAgICAgICAgICB7aX0gPSBjb250ZXh0XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgbm90KGlzUXVvdGVkKSBhbmQgdHlwZW9mKHZhbHVlKSBpcyAnc3RyaW5nJyBhbmQgKHZhbHVlLmluZGV4T2YoJzogJykgaXNudCAtMSBvciB2YWx1ZS5pbmRleE9mKFwiOlxcblwiKSBpc250IC0xKVxuICAgICAgICAgICAgICAgICAgICAgICAgIyBFbWJlZGRlZCBtYXBwaW5nP1xuICAgICAgICAgICAgICAgICAgICAgICAgdHJ5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBAcGFyc2VNYXBwaW5nICd7Jyt2YWx1ZSsnfSdcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhdGNoIGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE5vLCBpdCdzIG5vdFxuXG5cbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0LnB1c2ggdmFsdWVcblxuICAgICAgICAgICAgICAgICAgICAtLWlcblxuICAgICAgICAgICAgKytpXG5cbiAgICAgICAgdGhyb3cgbmV3IFBhcnNlRXhjZXB0aW9uICdNYWxmb3JtZWQgaW5saW5lIFlBTUwgc3RyaW5nICcrc2VxdWVuY2VcblxuXG4gICAgIyBQYXJzZXMgYSBtYXBwaW5nIHRvIGEgWUFNTCBzdHJpbmcuXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddICAgbWFwcGluZ1xuICAgICMgQHBhcmFtIFtPYmplY3RdICAgY29udGV4dFxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gIEEgWUFNTCBzdHJpbmdcbiAgICAjXG4gICAgIyBAdGhyb3cgW1BhcnNlRXhjZXB0aW9uXSBXaGVuIG1hbGZvcm1lZCBpbmxpbmUgWUFNTCBzdHJpbmcgaXMgcGFyc2VkXG4gICAgI1xuICAgIEBwYXJzZU1hcHBpbmc6IChtYXBwaW5nLCBjb250ZXh0KSAtPlxuICAgICAgICBvdXRwdXQgPSB7fVxuICAgICAgICBsZW4gPSBtYXBwaW5nLmxlbmd0aFxuICAgICAgICB7aX0gPSBjb250ZXh0XG4gICAgICAgIGkgKz0gMVxuXG4gICAgICAgICMge2ZvbzogYmFyLCBiYXI6Zm9vLCAuLi59XG4gICAgICAgIHNob3VsZENvbnRpbnVlV2hpbGVMb29wID0gZmFsc2VcbiAgICAgICAgd2hpbGUgaSA8IGxlblxuICAgICAgICAgICAgY29udGV4dC5pID0gaVxuICAgICAgICAgICAgc3dpdGNoIG1hcHBpbmcuY2hhckF0KGkpXG4gICAgICAgICAgICAgICAgd2hlbiAnICcsICcsJywgXCJcXG5cIlxuICAgICAgICAgICAgICAgICAgICArK2lcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5pID0gaVxuICAgICAgICAgICAgICAgICAgICBzaG91bGRDb250aW51ZVdoaWxlTG9vcCA9IHRydWVcbiAgICAgICAgICAgICAgICB3aGVuICd9J1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb3V0cHV0XG5cbiAgICAgICAgICAgIGlmIHNob3VsZENvbnRpbnVlV2hpbGVMb29wXG4gICAgICAgICAgICAgICAgc2hvdWxkQ29udGludWVXaGlsZUxvb3AgPSBmYWxzZVxuICAgICAgICAgICAgICAgIGNvbnRpbnVlXG5cbiAgICAgICAgICAgICMgS2V5XG4gICAgICAgICAgICBrZXkgPSBAcGFyc2VTY2FsYXIgbWFwcGluZywgWyc6JywgJyAnLCBcIlxcblwiXSwgWydcIicsIFwiJ1wiXSwgY29udGV4dCwgZmFsc2VcbiAgICAgICAgICAgIHtpfSA9IGNvbnRleHRcblxuICAgICAgICAgICAgIyBWYWx1ZVxuICAgICAgICAgICAgZG9uZSA9IGZhbHNlXG5cbiAgICAgICAgICAgIHdoaWxlIGkgPCBsZW5cbiAgICAgICAgICAgICAgICBjb250ZXh0LmkgPSBpXG4gICAgICAgICAgICAgICAgc3dpdGNoIG1hcHBpbmcuY2hhckF0KGkpXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gJ1snXG4gICAgICAgICAgICAgICAgICAgICAgICAjIE5lc3RlZCBzZXF1ZW5jZVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBAcGFyc2VTZXF1ZW5jZSBtYXBwaW5nLCBjb250ZXh0XG4gICAgICAgICAgICAgICAgICAgICAgICB7aX0gPSBjb250ZXh0XG4gICAgICAgICAgICAgICAgICAgICAgICAjIFNwZWM6IEtleXMgTVVTVCBiZSB1bmlxdWU7IGZpcnN0IG9uZSB3aW5zLlxuICAgICAgICAgICAgICAgICAgICAgICAgIyBQYXJzZXIgY2Fubm90IGFib3J0IHRoaXMgbWFwcGluZyBlYXJsaWVyLCBzaW5jZSBsaW5lc1xuICAgICAgICAgICAgICAgICAgICAgICAgIyBhcmUgcHJvY2Vzc2VkIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIG91dHB1dFtrZXldID09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dFtrZXldID0gdmFsdWVcbiAgICAgICAgICAgICAgICAgICAgICAgIGRvbmUgPSB0cnVlXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gJ3snXG4gICAgICAgICAgICAgICAgICAgICAgICAjIE5lc3RlZCBtYXBwaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAkdmFsdWUgPSBAcGFyc2VNYXBwaW5nIG1hcHBpbmcsIGNvbnRleHRcbiAgICAgICAgICAgICAgICAgICAgICAgIHtpfSA9IGNvbnRleHRcbiAgICAgICAgICAgICAgICAgICAgICAgICMgU3BlYzogS2V5cyBNVVNUIGJlIHVuaXF1ZTsgZmlyc3Qgb25lIHdpbnMuXG4gICAgICAgICAgICAgICAgICAgICAgICAjIFBhcnNlciBjYW5ub3QgYWJvcnQgdGhpcyBtYXBwaW5nIGVhcmxpZXIsIHNpbmNlIGxpbmVzXG4gICAgICAgICAgICAgICAgICAgICAgICAjIGFyZSBwcm9jZXNzZWQgc2VxdWVudGlhbGx5LlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgb3V0cHV0W2tleV0gPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0W2tleV0gPSB2YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgZG9uZSA9IHRydWVcbiAgICAgICAgICAgICAgICAgICAgd2hlbiAnOicsICcgJywgXCJcXG5cIlxuICAgICAgICAgICAgICAgICAgICAgICAgIyBEbyBub3RoaW5nXG4gICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gQHBhcnNlU2NhbGFyIG1hcHBpbmcsIFsnLCcsICd9J10sIFsnXCInLCBcIidcIl0sIGNvbnRleHRcbiAgICAgICAgICAgICAgICAgICAgICAgIHtpfSA9IGNvbnRleHRcbiAgICAgICAgICAgICAgICAgICAgICAgICMgU3BlYzogS2V5cyBNVVNUIGJlIHVuaXF1ZTsgZmlyc3Qgb25lIHdpbnMuXG4gICAgICAgICAgICAgICAgICAgICAgICAjIFBhcnNlciBjYW5ub3QgYWJvcnQgdGhpcyBtYXBwaW5nIGVhcmxpZXIsIHNpbmNlIGxpbmVzXG4gICAgICAgICAgICAgICAgICAgICAgICAjIGFyZSBwcm9jZXNzZWQgc2VxdWVudGlhbGx5LlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgb3V0cHV0W2tleV0gPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0W2tleV0gPSB2YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgZG9uZSA9IHRydWVcbiAgICAgICAgICAgICAgICAgICAgICAgIC0taVxuXG4gICAgICAgICAgICAgICAgKytpXG5cbiAgICAgICAgICAgICAgICBpZiBkb25lXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrXG5cbiAgICAgICAgdGhyb3cgbmV3IFBhcnNlRXhjZXB0aW9uICdNYWxmb3JtZWQgaW5saW5lIFlBTUwgc3RyaW5nICcrbWFwcGluZ1xuXG5cbiAgICAjIEV2YWx1YXRlcyBzY2FsYXJzIGFuZCByZXBsYWNlcyBtYWdpYyB2YWx1ZXMuXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddICAgc2NhbGFyXG4gICAgI1xuICAgICMgQHJldHVybiBbU3RyaW5nXSAgQSBZQU1MIHN0cmluZ1xuICAgICNcbiAgICBAZXZhbHVhdGVTY2FsYXI6IChzY2FsYXIsIGNvbnRleHQpIC0+XG4gICAgICAgIHNjYWxhciA9IFV0aWxzLnRyaW0oc2NhbGFyKVxuICAgICAgICBzY2FsYXJMb3dlciA9IHNjYWxhci50b0xvd2VyQ2FzZSgpXG5cbiAgICAgICAgc3dpdGNoIHNjYWxhckxvd2VyXG4gICAgICAgICAgICB3aGVuICdudWxsJywgJycsICd+J1xuICAgICAgICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgICAgICB3aGVuICd0cnVlJ1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlXG4gICAgICAgICAgICB3aGVuICdmYWxzZSdcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2VcbiAgICAgICAgICAgIHdoZW4gJy5pbmYnXG4gICAgICAgICAgICAgICAgcmV0dXJuIEluZmluaXR5XG4gICAgICAgICAgICB3aGVuICcubmFuJ1xuICAgICAgICAgICAgICAgIHJldHVybiBOYU5cbiAgICAgICAgICAgIHdoZW4gJy0uaW5mJ1xuICAgICAgICAgICAgICAgIHJldHVybiBJbmZpbml0eVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIGZpcnN0Q2hhciA9IHNjYWxhckxvd2VyLmNoYXJBdCgwKVxuICAgICAgICAgICAgICAgIHN3aXRjaCBmaXJzdENoYXJcbiAgICAgICAgICAgICAgICAgICAgd2hlbiAnISdcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0U3BhY2UgPSBzY2FsYXIuaW5kZXhPZignICcpXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiBmaXJzdFNwYWNlIGlzIC0xXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlyc3RXb3JkID0gc2NhbGFyTG93ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXJzdFdvcmQgPSBzY2FsYXJMb3dlclswLi4uZmlyc3RTcGFjZV1cbiAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaCBmaXJzdFdvcmRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGVuICchJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBmaXJzdFNwYWNlIGlzbnQgLTFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBwYXJzZUludCBAcGFyc2VTY2FsYXIoc2NhbGFyWzIuLl0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hlbiAnIXN0cidcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFV0aWxzLmx0cmltIHNjYWxhcls0Li5dXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hlbiAnISFzdHInXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBVdGlscy5sdHJpbSBzY2FsYXJbNS4uXVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoZW4gJyEhaW50J1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcGFyc2VJbnQoQHBhcnNlU2NhbGFyKHNjYWxhcls1Li5dKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGVuICchIWJvb2wnXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBVdGlscy5wYXJzZUJvb2xlYW4oQHBhcnNlU2NhbGFyKHNjYWxhcls2Li5dKSwgZmFsc2UpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hlbiAnISFmbG9hdCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQoQHBhcnNlU2NhbGFyKHNjYWxhcls3Li5dKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGVuICchIXRpbWVzdGFtcCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFV0aWxzLnN0cmluZ1RvRGF0ZShVdGlscy5sdHJpbShzY2FsYXJbMTEuLl0pKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5sZXNzIGNvbnRleHQ/XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0ID0gZXhjZXB0aW9uT25JbnZhbGlkVHlwZTogQHNldHRpbmdzLmV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdERlY29kZXI6IEBzZXR0aW5ncy5vYmplY3REZWNvZGVyLCBpOiAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtvYmplY3REZWNvZGVyLCBleGNlcHRpb25PbkludmFsaWRUeXBlfSA9IGNvbnRleHRcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBvYmplY3REZWNvZGVyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIElmIG9iamVjdERlY29kZXIgZnVuY3Rpb24gaXMgZ2l2ZW4sIHdlIGNhbiBkbyBjdXN0b20gZGVjb2Rpbmcgb2YgY3VzdG9tIHR5cGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmltbWVkU2NhbGFyID0gVXRpbHMucnRyaW0gc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXJzdFNwYWNlID0gdHJpbW1lZFNjYWxhci5pbmRleE9mKCcgJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGZpcnN0U3BhY2UgaXMgLTFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb2JqZWN0RGVjb2RlciB0cmltbWVkU2NhbGFyLCBudWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViVmFsdWUgPSBVdGlscy5sdHJpbSB0cmltbWVkU2NhbGFyW2ZpcnN0U3BhY2UrMS4uXVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVubGVzcyBzdWJWYWx1ZS5sZW5ndGggPiAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YlZhbHVlID0gbnVsbFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBvYmplY3REZWNvZGVyIHRyaW1tZWRTY2FsYXJbMC4uLmZpcnN0U3BhY2VdLCBzdWJWYWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBleGNlcHRpb25PbkludmFsaWRUeXBlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2VFeGNlcHRpb24gJ0N1c3RvbSBvYmplY3Qgc3VwcG9ydCB3aGVuIHBhcnNpbmcgYSBZQU1MIGZpbGUgaGFzIGJlZW4gZGlzYWJsZWQuJ1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gJzAnXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAnMHgnIGlzIHNjYWxhclswLi4uMl1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gVXRpbHMuaGV4RGVjIHNjYWxhclxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiBVdGlscy5pc0RpZ2l0cyBzY2FsYXJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gVXRpbHMub2N0RGVjIHNjYWxhclxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiBVdGlscy5pc051bWVyaWMgc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQgc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNjYWxhclxuICAgICAgICAgICAgICAgICAgICB3aGVuICcrJ1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgVXRpbHMuaXNEaWdpdHMgc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF3ID0gc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzdCA9IHBhcnNlSW50KHJhdylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiByYXcgaXMgJycrY2FzdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2FzdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJhd1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiBVdGlscy5pc051bWVyaWMgc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQgc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAjZWxzZSBpZiBAUEFUVEVSTl9USE9VU0FORF9OVU1FUklDX1NDQUxBUi50ZXN0IHNjYWxhclxuICAgICAgICAgICAgICAgICAgICAgICAgIyAgICByZXR1cm4gcGFyc2VGbG9hdChzY2FsYXIucmVwbGFjZSgnLCcsICcnKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBzY2FsYXJcbiAgICAgICAgICAgICAgICAgICAgd2hlbiAnLSdcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIFV0aWxzLmlzRGlnaXRzKHNjYWxhclsxLi5dKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICcwJyBpcyBzY2FsYXIuY2hhckF0KDEpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAtVXRpbHMub2N0RGVjKHNjYWxhclsxLi5dKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF3ID0gc2NhbGFyWzEuLl1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzdCA9IHBhcnNlSW50KHJhdylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgcmF3IGlzICcnK2Nhc3RcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAtY2FzdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gLXJhd1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiBVdGlscy5pc051bWVyaWMgc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQgc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAjZWxzZSBpZiBAUEFUVEVSTl9USE9VU0FORF9OVU1FUklDX1NDQUxBUi50ZXN0IHNjYWxhclxuICAgICAgICAgICAgICAgICAgICAgICAgIyAgICByZXR1cm4gcGFyc2VGbG9hdChzY2FsYXIucmVwbGFjZSgnLCcsICcnKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBzY2FsYXJcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgVXRpbHMuaXNOdW1lcmljKHNjYWxhcilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcGFyc2VGbG9hdCBzY2FsYXJcbiAgICAgICAgICAgICAgICAgICAgICAgICNlbHNlIGlmIEBQQVRURVJOX1RIT1VTQU5EX05VTUVSSUNfU0NBTEFSLnRlc3Qgc2NhbGFyXG4gICAgICAgICAgICAgICAgICAgICAgICAjICAgIHJldHVybiBwYXJzZUZsb2F0KHNjYWxhci5yZXBsYWNlKCcsJywgJycpKVxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNjYWxhclxuXG5tb2R1bGUuZXhwb3J0cyA9IElubGluZVxuIiwiXG5JbmxpbmUgICAgICAgICAgPSByZXF1aXJlICcuL0lubGluZSdcblBhdHRlcm4gICAgICAgICA9IHJlcXVpcmUgJy4vUGF0dGVybidcblV0aWxzICAgICAgICAgICA9IHJlcXVpcmUgJy4vVXRpbHMnXG5QYXJzZUV4Y2VwdGlvbiAgPSByZXF1aXJlICcuL0V4Y2VwdGlvbi9QYXJzZUV4Y2VwdGlvbidcblxuIyBQYXJzZXIgcGFyc2VzIFlBTUwgc3RyaW5ncyB0byBjb252ZXJ0IHRoZW0gdG8gSmF2YVNjcmlwdCBvYmplY3RzLlxuI1xuY2xhc3MgUGFyc2VyXG5cbiAgICAjIFByZS1jb21waWxlZCBwYXR0ZXJuc1xuICAgICNcbiAgICBQQVRURVJOX0ZPTERFRF9TQ0FMQVJfQUxMOiAgICAgICAgICAgICAgbmV3IFBhdHRlcm4gJ14oPzooPzx0eXBlPiFbXlxcXFx8Pl0qKVxcXFxzKyk/KD88c2VwYXJhdG9yPlxcXFx8fD4pKD88bW9kaWZpZXJzPlxcXFwrfFxcXFwtfFxcXFxkK3xcXFxcK1xcXFxkK3xcXFxcLVxcXFxkK3xcXFxcZCtcXFxcK3xcXFxcZCtcXFxcLSk/KD88Y29tbWVudHM+ICsjLiopPyQnXG4gICAgUEFUVEVSTl9GT0xERURfU0NBTEFSX0VORDogICAgICAgICAgICAgIG5ldyBQYXR0ZXJuICcoPzxzZXBhcmF0b3I+XFxcXHx8PikoPzxtb2RpZmllcnM+XFxcXCt8XFxcXC18XFxcXGQrfFxcXFwrXFxcXGQrfFxcXFwtXFxcXGQrfFxcXFxkK1xcXFwrfFxcXFxkK1xcXFwtKT8oPzxjb21tZW50cz4gKyMuKik/JCdcbiAgICBQQVRURVJOX1NFUVVFTkNFX0lURU06ICAgICAgICAgICAgICAgICAgbmV3IFBhdHRlcm4gJ15cXFxcLSgoPzxsZWFkc3BhY2VzPlxcXFxzKykoPzx2YWx1ZT4uKz8pKT9cXFxccyokJ1xuICAgIFBBVFRFUk5fQU5DSE9SX1ZBTFVFOiAgICAgICAgICAgICAgICAgICBuZXcgUGF0dGVybiAnXiYoPzxyZWY+W14gXSspICooPzx2YWx1ZT4uKiknXG4gICAgUEFUVEVSTl9DT01QQUNUX05PVEFUSU9OOiAgICAgICAgICAgICAgIG5ldyBQYXR0ZXJuICdeKD88a2V5PicrSW5saW5lLlJFR0VYX1FVT1RFRF9TVFJJTkcrJ3xbXiBcXCdcIlxcXFx7XFxcXFtdLio/KSAqXFxcXDooXFxcXHMrKD88dmFsdWU+Lis/KSk/XFxcXHMqJCdcbiAgICBQQVRURVJOX01BUFBJTkdfSVRFTTogICAgICAgICAgICAgICAgICAgbmV3IFBhdHRlcm4gJ14oPzxrZXk+JytJbmxpbmUuUkVHRVhfUVVPVEVEX1NUUklORysnfFteIFxcJ1wiXFxcXFtcXFxce10uKj8pICpcXFxcOihcXFxccysoPzx2YWx1ZT4uKz8pKT9cXFxccyokJ1xuICAgIFBBVFRFUk5fREVDSU1BTDogICAgICAgICAgICAgICAgICAgICAgICBuZXcgUGF0dGVybiAnXFxcXGQrJ1xuICAgIFBBVFRFUk5fSU5ERU5UX1NQQUNFUzogICAgICAgICAgICAgICAgICBuZXcgUGF0dGVybiAnXiArJ1xuICAgIFBBVFRFUk5fVFJBSUxJTkdfTElORVM6ICAgICAgICAgICAgICAgICBuZXcgUGF0dGVybiAnKFxcbiopJCdcbiAgICBQQVRURVJOX1lBTUxfSEVBREVSOiAgICAgICAgICAgICAgICAgICAgbmV3IFBhdHRlcm4gJ15cXFxcJVlBTUxbOiBdW1xcXFxkXFxcXC5dKy4qXFxuJ1xuICAgIFBBVFRFUk5fTEVBRElOR19DT01NRU5UUzogICAgICAgICAgICAgICBuZXcgUGF0dGVybiAnXihcXFxcIy4qP1xcbikrJ1xuICAgIFBBVFRFUk5fRE9DVU1FTlRfTUFSS0VSX1NUQVJUOiAgICAgICAgICBuZXcgUGF0dGVybiAnXlxcXFwtXFxcXC1cXFxcLS4qP1xcbidcbiAgICBQQVRURVJOX0RPQ1VNRU5UX01BUktFUl9FTkQ6ICAgICAgICAgICAgbmV3IFBhdHRlcm4gJ15cXFxcLlxcXFwuXFxcXC5cXFxccyokJ1xuICAgIFBBVFRFUk5fRk9MREVEX1NDQUxBUl9CWV9JTkRFTlRBVElPTjogICB7fVxuXG4gICAgIyBDb250ZXh0IHR5cGVzXG4gICAgI1xuICAgIENPTlRFWFRfTk9ORTogICAgICAgMFxuICAgIENPTlRFWFRfU0VRVUVOQ0U6ICAgMVxuICAgIENPTlRFWFRfTUFQUElORzogICAgMlxuXG5cbiAgICAjIENvbnN0cnVjdG9yXG4gICAgI1xuICAgICMgQHBhcmFtIFtJbnRlZ2VyXSAgb2Zmc2V0ICBUaGUgb2Zmc2V0IG9mIFlBTUwgZG9jdW1lbnQgKHVzZWQgZm9yIGxpbmUgbnVtYmVycyBpbiBlcnJvciBtZXNzYWdlcylcbiAgICAjXG4gICAgY29uc3RydWN0b3I6IChAb2Zmc2V0ID0gMCkgLT5cbiAgICAgICAgQGxpbmVzICAgICAgICAgID0gW11cbiAgICAgICAgQGN1cnJlbnRMaW5lTmIgID0gLTFcbiAgICAgICAgQGN1cnJlbnRMaW5lICAgID0gJydcbiAgICAgICAgQHJlZnMgICAgICAgICAgID0ge31cblxuXG4gICAgIyBQYXJzZXMgYSBZQU1MIHN0cmluZyB0byBhIEphdmFTY3JpcHQgdmFsdWUuXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddICAgdmFsdWUgICAgICAgICAgICAgICAgICAgQSBZQU1MIHN0cmluZ1xuICAgICMgQHBhcmFtIFtCb29sZWFuXSAgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSAgdHJ1ZSBpZiBhbiBleGNlcHRpb24gbXVzdCBiZSB0aHJvd24gb24gaW52YWxpZCB0eXBlcyAoYSBKYXZhU2NyaXB0IHJlc291cmNlIG9yIG9iamVjdCksIGZhbHNlIG90aGVyd2lzZVxuICAgICMgQHBhcmFtIFtGdW5jdGlvbl0gb2JqZWN0RGVjb2RlciAgICAgICAgICAgQSBmdW5jdGlvbiB0byBkZXNlcmlhbGl6ZSBjdXN0b20gb2JqZWN0cywgbnVsbCBvdGhlcndpc2VcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtPYmplY3RdICBBIEphdmFTY3JpcHQgdmFsdWVcbiAgICAjXG4gICAgIyBAdGhyb3cgW1BhcnNlRXhjZXB0aW9uXSBJZiB0aGUgWUFNTCBpcyBub3QgdmFsaWRcbiAgICAjXG4gICAgcGFyc2U6ICh2YWx1ZSwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSA9IGZhbHNlLCBvYmplY3REZWNvZGVyID0gbnVsbCkgLT5cbiAgICAgICAgQGN1cnJlbnRMaW5lTmIgPSAtMVxuICAgICAgICBAY3VycmVudExpbmUgPSAnJ1xuICAgICAgICBAbGluZXMgPSBAY2xlYW51cCh2YWx1ZSkuc3BsaXQgXCJcXG5cIlxuXG4gICAgICAgIGRhdGEgPSBudWxsXG4gICAgICAgIGNvbnRleHQgPSBAQ09OVEVYVF9OT05FXG4gICAgICAgIGFsbG93T3ZlcndyaXRlID0gZmFsc2VcbiAgICAgICAgd2hpbGUgQG1vdmVUb05leHRMaW5lKClcbiAgICAgICAgICAgIGlmIEBpc0N1cnJlbnRMaW5lRW1wdHkoKVxuICAgICAgICAgICAgICAgIGNvbnRpbnVlXG5cbiAgICAgICAgICAgICMgVGFiP1xuICAgICAgICAgICAgaWYgXCJcXHRcIiBpcyBAY3VycmVudExpbmVbMF1cbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2VFeGNlcHRpb24gJ0EgWUFNTCBmaWxlIGNhbm5vdCBjb250YWluIHRhYnMgYXMgaW5kZW50YXRpb24uJywgQGdldFJlYWxDdXJyZW50TGluZU5iKCkgKyAxLCBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgaXNSZWYgPSBtZXJnZU5vZGUgPSBmYWxzZVxuICAgICAgICAgICAgaWYgdmFsdWVzID0gQFBBVFRFUk5fU0VRVUVOQ0VfSVRFTS5leGVjIEBjdXJyZW50TGluZVxuICAgICAgICAgICAgICAgIGlmIEBDT05URVhUX01BUFBJTkcgaXMgY29udGV4dFxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2VFeGNlcHRpb24gJ1lvdSBjYW5ub3QgZGVmaW5lIGEgc2VxdWVuY2UgaXRlbSB3aGVuIGluIGEgbWFwcGluZydcbiAgICAgICAgICAgICAgICBjb250ZXh0ID0gQENPTlRFWFRfU0VRVUVOQ0VcbiAgICAgICAgICAgICAgICBkYXRhID89IFtdXG5cbiAgICAgICAgICAgICAgICBpZiB2YWx1ZXMudmFsdWU/IGFuZCBtYXRjaGVzID0gQFBBVFRFUk5fQU5DSE9SX1ZBTFVFLmV4ZWMgdmFsdWVzLnZhbHVlXG4gICAgICAgICAgICAgICAgICAgIGlzUmVmID0gbWF0Y2hlcy5yZWZcbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzLnZhbHVlID0gbWF0Y2hlcy52YWx1ZVxuXG4gICAgICAgICAgICAgICAgIyBBcnJheVxuICAgICAgICAgICAgICAgIGlmIG5vdCh2YWx1ZXMudmFsdWU/KSBvciAnJyBpcyBVdGlscy50cmltKHZhbHVlcy52YWx1ZSwgJyAnKSBvciBVdGlscy5sdHJpbSh2YWx1ZXMudmFsdWUsICcgJykuaW5kZXhPZignIycpIGlzIDBcbiAgICAgICAgICAgICAgICAgICAgaWYgQGN1cnJlbnRMaW5lTmIgPCBAbGluZXMubGVuZ3RoIC0gMSBhbmQgbm90IEBpc05leHRMaW5lVW5JbmRlbnRlZENvbGxlY3Rpb24oKVxuICAgICAgICAgICAgICAgICAgICAgICAgYyA9IEBnZXRSZWFsQ3VycmVudExpbmVOYigpICsgMVxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyc2VyID0gbmV3IFBhcnNlciBjXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJzZXIucmVmcyA9IEByZWZzXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnB1c2ggcGFyc2VyLnBhcnNlKEBnZXROZXh0RW1iZWRCbG9jayhudWxsLCB0cnVlKSwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RGVjb2RlcilcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5wdXNoIG51bGxcblxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgaWYgdmFsdWVzLmxlYWRzcGFjZXM/Lmxlbmd0aCBhbmQgbWF0Y2hlcyA9IEBQQVRURVJOX0NPTVBBQ1RfTk9UQVRJT04uZXhlYyB2YWx1ZXMudmFsdWVcblxuICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGlzIGlzIGEgY29tcGFjdCBub3RhdGlvbiBlbGVtZW50LCBhZGQgdG8gbmV4dCBibG9jayBhbmQgcGFyc2VcbiAgICAgICAgICAgICAgICAgICAgICAgIGMgPSBAZ2V0UmVhbEN1cnJlbnRMaW5lTmIoKVxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyc2VyID0gbmV3IFBhcnNlciBjXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJzZXIucmVmcyA9IEByZWZzXG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGJsb2NrID0gdmFsdWVzLnZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICBpbmRlbnQgPSBAZ2V0Q3VycmVudExpbmVJbmRlbnRhdGlvbigpXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiBAaXNOZXh0TGluZUluZGVudGVkKGZhbHNlKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsb2NrICs9IFwiXFxuXCIrQGdldE5leHRFbWJlZEJsb2NrKGluZGVudCArIHZhbHVlcy5sZWFkc3BhY2VzLmxlbmd0aCArIDEsIHRydWUpXG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEucHVzaCBwYXJzZXIucGFyc2UgYmxvY2ssIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdERlY29kZXJcblxuICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnB1c2ggQHBhcnNlVmFsdWUgdmFsdWVzLnZhbHVlLCBleGNlcHRpb25PbkludmFsaWRUeXBlLCBvYmplY3REZWNvZGVyXG5cbiAgICAgICAgICAgIGVsc2UgaWYgKHZhbHVlcyA9IEBQQVRURVJOX01BUFBJTkdfSVRFTS5leGVjIEBjdXJyZW50TGluZSkgYW5kIHZhbHVlcy5rZXkuaW5kZXhPZignICMnKSBpcyAtMVxuICAgICAgICAgICAgICAgIGlmIEBDT05URVhUX1NFUVVFTkNFIGlzIGNvbnRleHRcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlRXhjZXB0aW9uICdZb3UgY2Fubm90IGRlZmluZSBhIG1hcHBpbmcgaXRlbSB3aGVuIGluIGEgc2VxdWVuY2UnXG4gICAgICAgICAgICAgICAgY29udGV4dCA9IEBDT05URVhUX01BUFBJTkdcbiAgICAgICAgICAgICAgICBkYXRhID89IHt9XG5cbiAgICAgICAgICAgICAgICAjIEZvcmNlIGNvcnJlY3Qgc2V0dGluZ3NcbiAgICAgICAgICAgICAgICBJbmxpbmUuY29uZmlndXJlIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdERlY29kZXJcbiAgICAgICAgICAgICAgICB0cnlcbiAgICAgICAgICAgICAgICAgICAga2V5ID0gSW5saW5lLnBhcnNlU2NhbGFyIHZhbHVlcy5rZXlcbiAgICAgICAgICAgICAgICBjYXRjaCBlXG4gICAgICAgICAgICAgICAgICAgIGUucGFyc2VkTGluZSA9IEBnZXRSZWFsQ3VycmVudExpbmVOYigpICsgMVxuICAgICAgICAgICAgICAgICAgICBlLnNuaXBwZXQgPSBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlXG5cbiAgICAgICAgICAgICAgICBpZiAnPDwnIGlzIGtleVxuICAgICAgICAgICAgICAgICAgICBtZXJnZU5vZGUgPSB0cnVlXG4gICAgICAgICAgICAgICAgICAgIGFsbG93T3ZlcndyaXRlID0gdHJ1ZVxuICAgICAgICAgICAgICAgICAgICBpZiB2YWx1ZXMudmFsdWU/LmluZGV4T2YoJyonKSBpcyAwXG4gICAgICAgICAgICAgICAgICAgICAgICByZWZOYW1lID0gdmFsdWVzLnZhbHVlWzEuLl1cbiAgICAgICAgICAgICAgICAgICAgICAgIHVubGVzcyBAcmVmc1tyZWZOYW1lXT9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2VFeGNlcHRpb24gJ1JlZmVyZW5jZSBcIicrcmVmTmFtZSsnXCIgZG9lcyBub3QgZXhpc3QuJywgQGdldFJlYWxDdXJyZW50TGluZU5iKCkgKyAxLCBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgICAgICAgICAgICAgcmVmVmFsdWUgPSBAcmVmc1tyZWZOYW1lXVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiB0eXBlb2YgcmVmVmFsdWUgaXNudCAnb2JqZWN0J1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZUV4Y2VwdGlvbiAnWUFNTCBtZXJnZSBrZXlzIHVzZWQgd2l0aCBhIHNjYWxhciB2YWx1ZSBpbnN0ZWFkIG9mIGFuIG9iamVjdC4nLCBAZ2V0UmVhbEN1cnJlbnRMaW5lTmIoKSArIDEsIEBjdXJyZW50TGluZVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiByZWZWYWx1ZSBpbnN0YW5jZW9mIEFycmF5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBNZXJnZSBhcnJheSB3aXRoIG9iamVjdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciB2YWx1ZSwgaSBpbiByZWZWYWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhWycnK2ldID89IHZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBNZXJnZSBvYmplY3RzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGtleSwgdmFsdWUgb2YgcmVmVmFsdWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVtrZXldID89IHZhbHVlXG5cbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgdmFsdWVzLnZhbHVlIGlzbnQgJydcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlcy52YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gQGdldE5leHRFbWJlZEJsb2NrKClcbiAgICAgICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgYyA9IEBnZXRSZWFsQ3VycmVudExpbmVOYigpICsgMVxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyc2VyID0gbmV3IFBhcnNlciBjXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJzZXIucmVmcyA9IEByZWZzXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJzZWQgPSBwYXJzZXIucGFyc2UgdmFsdWUsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGVcblxuICAgICAgICAgICAgICAgICAgICAgICAgdW5sZXNzIHR5cGVvZiBwYXJzZWQgaXMgJ29iamVjdCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2VFeGNlcHRpb24gJ1lBTUwgbWVyZ2Uga2V5cyB1c2VkIHdpdGggYSBzY2FsYXIgdmFsdWUgaW5zdGVhZCBvZiBhbiBvYmplY3QuJywgQGdldFJlYWxDdXJyZW50TGluZU5iKCkgKyAxLCBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgcGFyc2VkIGluc3RhbmNlb2YgQXJyYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIElmIHRoZSB2YWx1ZSBhc3NvY2lhdGVkIHdpdGggdGhlIG1lcmdlIGtleSBpcyBhIHNlcXVlbmNlLCB0aGVuIHRoaXMgc2VxdWVuY2UgaXMgZXhwZWN0ZWQgdG8gY29udGFpbiBtYXBwaW5nIG5vZGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhbmQgZWFjaCBvZiB0aGVzZSBub2RlcyBpcyBtZXJnZWQgaW4gdHVybiBhY2NvcmRpbmcgdG8gaXRzIG9yZGVyIGluIHRoZSBzZXF1ZW5jZS4gS2V5cyBpbiBtYXBwaW5nIG5vZGVzIGVhcmxpZXJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBzZXF1ZW5jZSBvdmVycmlkZSBrZXlzIHNwZWNpZmllZCBpbiBsYXRlciBtYXBwaW5nIG5vZGVzLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBwYXJzZWRJdGVtIGluIHBhcnNlZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmxlc3MgdHlwZW9mIHBhcnNlZEl0ZW0gaXMgJ29iamVjdCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZUV4Y2VwdGlvbiAnTWVyZ2UgaXRlbXMgbXVzdCBiZSBvYmplY3RzLicsIEBnZXRSZWFsQ3VycmVudExpbmVOYigpICsgMSwgcGFyc2VkSXRlbVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIHBhcnNlZEl0ZW0gaW5zdGFuY2VvZiBBcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBNZXJnZSBhcnJheSB3aXRoIG9iamVjdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIHZhbHVlLCBpIGluIHBhcnNlZEl0ZW1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhWycnK2ldID89IHZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTWVyZ2Ugb2JqZWN0c1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGtleSwgdmFsdWUgb2YgcGFyc2VkSXRlbVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFba2V5XSA/PSB2YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgSWYgdGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGUga2V5IGlzIGEgc2luZ2xlIG1hcHBpbmcgbm9kZSwgZWFjaCBvZiBpdHMga2V5L3ZhbHVlIHBhaXJzIGlzIGluc2VydGVkIGludG8gdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjdXJyZW50IG1hcHBpbmcsIHVubGVzcyB0aGUga2V5IGFscmVhZHkgZXhpc3RzIGluIGl0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBrZXksIHZhbHVlIG9mIHBhcnNlZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhW2tleV0gPz0gdmFsdWVcblxuICAgICAgICAgICAgICAgIGVsc2UgaWYgdmFsdWVzLnZhbHVlPyBhbmQgbWF0Y2hlcyA9IEBQQVRURVJOX0FOQ0hPUl9WQUxVRS5leGVjIHZhbHVlcy52YWx1ZVxuICAgICAgICAgICAgICAgICAgICBpc1JlZiA9IG1hdGNoZXMucmVmXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlcy52YWx1ZSA9IG1hdGNoZXMudmFsdWVcbiAgICAgICAgICAgICAgICBcblxuICAgICAgICAgICAgICAgIGlmIG1lcmdlTm9kZVxuICAgICAgICAgICAgICAgICAgICAjIE1lcmdlIGtleXNcbiAgICAgICAgICAgICAgICBlbHNlIGlmIG5vdCh2YWx1ZXMudmFsdWU/KSBvciAnJyBpcyBVdGlscy50cmltKHZhbHVlcy52YWx1ZSwgJyAnKSBvciBVdGlscy5sdHJpbSh2YWx1ZXMudmFsdWUsICcgJykuaW5kZXhPZignIycpIGlzIDBcbiAgICAgICAgICAgICAgICAgICAgIyBIYXNoXG4gICAgICAgICAgICAgICAgICAgICMgaWYgbmV4dCBsaW5lIGlzIGxlc3MgaW5kZW50ZWQgb3IgZXF1YWwsIHRoZW4gaXQgbWVhbnMgdGhhdCB0aGUgY3VycmVudCB2YWx1ZSBpcyBudWxsXG4gICAgICAgICAgICAgICAgICAgIGlmIG5vdChAaXNOZXh0TGluZUluZGVudGVkKCkpIGFuZCBub3QoQGlzTmV4dExpbmVVbkluZGVudGVkQ29sbGVjdGlvbigpKVxuICAgICAgICAgICAgICAgICAgICAgICAgIyBTcGVjOiBLZXlzIE1VU1QgYmUgdW5pcXVlOyBmaXJzdCBvbmUgd2lucy5cbiAgICAgICAgICAgICAgICAgICAgICAgICMgQnV0IG92ZXJ3cml0aW5nIGlzIGFsbG93ZWQgd2hlbiBhIG1lcmdlIG5vZGUgaXMgdXNlZCBpbiBjdXJyZW50IGJsb2NrLlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgYWxsb3dPdmVyd3JpdGUgb3IgZGF0YVtrZXldIGlzIHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFba2V5XSA9IG51bGxcblxuICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICBjID0gQGdldFJlYWxDdXJyZW50TGluZU5iKCkgKyAxXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJzZXIgPSBuZXcgUGFyc2VyIGNcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnNlci5yZWZzID0gQHJlZnNcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbCA9IHBhcnNlci5wYXJzZSBAZ2V0TmV4dEVtYmVkQmxvY2soKSwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RGVjb2RlclxuXG4gICAgICAgICAgICAgICAgICAgICAgICAjIFNwZWM6IEtleXMgTVVTVCBiZSB1bmlxdWU7IGZpcnN0IG9uZSB3aW5zLlxuICAgICAgICAgICAgICAgICAgICAgICAgIyBCdXQgb3ZlcndyaXRpbmcgaXMgYWxsb3dlZCB3aGVuIGEgbWVyZ2Ugbm9kZSBpcyB1c2VkIGluIGN1cnJlbnQgYmxvY2suXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiBhbGxvd092ZXJ3cml0ZSBvciBkYXRhW2tleV0gaXMgdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVtrZXldID0gdmFsXG4gICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgdmFsID0gQHBhcnNlVmFsdWUgdmFsdWVzLnZhbHVlLCBleGNlcHRpb25PbkludmFsaWRUeXBlLCBvYmplY3REZWNvZGVyXG5cbiAgICAgICAgICAgICAgICAgICAgIyBTcGVjOiBLZXlzIE1VU1QgYmUgdW5pcXVlOyBmaXJzdCBvbmUgd2lucy5cbiAgICAgICAgICAgICAgICAgICAgIyBCdXQgb3ZlcndyaXRpbmcgaXMgYWxsb3dlZCB3aGVuIGEgbWVyZ2Ugbm9kZSBpcyB1c2VkIGluIGN1cnJlbnQgYmxvY2suXG4gICAgICAgICAgICAgICAgICAgIGlmIGFsbG93T3ZlcndyaXRlIG9yIGRhdGFba2V5XSBpcyB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFba2V5XSA9IHZhbFxuXG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgIyAxLWxpbmVyIG9wdGlvbmFsbHkgZm9sbG93ZWQgYnkgbmV3bGluZVxuICAgICAgICAgICAgICAgIGxpbmVDb3VudCA9IEBsaW5lcy5sZW5ndGhcbiAgICAgICAgICAgICAgICBpZiAxIGlzIGxpbmVDb3VudCBvciAoMiBpcyBsaW5lQ291bnQgYW5kIFV0aWxzLmlzRW1wdHkoQGxpbmVzWzFdKSlcbiAgICAgICAgICAgICAgICAgICAgdHJ5XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IElubGluZS5wYXJzZSBAbGluZXNbMF0sIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdERlY29kZXJcbiAgICAgICAgICAgICAgICAgICAgY2F0Y2ggZVxuICAgICAgICAgICAgICAgICAgICAgICAgZS5wYXJzZWRMaW5lID0gQGdldFJlYWxDdXJyZW50TGluZU5iKCkgKyAxXG4gICAgICAgICAgICAgICAgICAgICAgICBlLnNuaXBwZXQgPSBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZVxuXG4gICAgICAgICAgICAgICAgICAgIGlmIHR5cGVvZiB2YWx1ZSBpcyAnb2JqZWN0J1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgdmFsdWUgaW5zdGFuY2VvZiBBcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0ID0gdmFsdWVbMF1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3Iga2V5IG9mIHZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0ID0gdmFsdWVba2V5XVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiB0eXBlb2YgZmlyc3QgaXMgJ3N0cmluZycgYW5kIGZpcnN0LmluZGV4T2YoJyonKSBpcyAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IFtdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGFsaWFzIGluIHZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEucHVzaCBAcmVmc1thbGlhc1sxLi5dXVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gZGF0YVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZVxuXG4gICAgICAgICAgICAgICAgZWxzZSBpZiBVdGlscy5sdHJpbSh2YWx1ZSkuY2hhckF0KDApIGluIFsnWycsICd7J11cbiAgICAgICAgICAgICAgICAgICAgdHJ5XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gSW5saW5lLnBhcnNlIHZhbHVlLCBleGNlcHRpb25PbkludmFsaWRUeXBlLCBvYmplY3REZWNvZGVyXG4gICAgICAgICAgICAgICAgICAgIGNhdGNoIGVcbiAgICAgICAgICAgICAgICAgICAgICAgIGUucGFyc2VkTGluZSA9IEBnZXRSZWFsQ3VycmVudExpbmVOYigpICsgMVxuICAgICAgICAgICAgICAgICAgICAgICAgZS5zbmlwcGV0ID0gQGN1cnJlbnRMaW5lXG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGVcblxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZUV4Y2VwdGlvbiAnVW5hYmxlIHRvIHBhcnNlLicsIEBnZXRSZWFsQ3VycmVudExpbmVOYigpICsgMSwgQGN1cnJlbnRMaW5lXG5cbiAgICAgICAgICAgIGlmIGlzUmVmXG4gICAgICAgICAgICAgICAgaWYgZGF0YSBpbnN0YW5jZW9mIEFycmF5XG4gICAgICAgICAgICAgICAgICAgIEByZWZzW2lzUmVmXSA9IGRhdGFbZGF0YS5sZW5ndGgtMV1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIGxhc3RLZXkgPSBudWxsXG4gICAgICAgICAgICAgICAgICAgIGZvciBrZXkgb2YgZGF0YVxuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdEtleSA9IGtleVxuICAgICAgICAgICAgICAgICAgICBAcmVmc1tpc1JlZl0gPSBkYXRhW2xhc3RLZXldXG5cblxuICAgICAgICBpZiBVdGlscy5pc0VtcHR5KGRhdGEpXG4gICAgICAgICAgICByZXR1cm4gbnVsbFxuICAgICAgICBlbHNlXG4gICAgICAgICAgICByZXR1cm4gZGF0YVxuXG5cbiAgICBcbiAgICAjIFJldHVybnMgdGhlIGN1cnJlbnQgbGluZSBudW1iZXIgKHRha2VzIHRoZSBvZmZzZXQgaW50byBhY2NvdW50KS5cbiAgICAjXG4gICAgIyBAcmV0dXJuIFtJbnRlZ2VyXSAgICAgVGhlIGN1cnJlbnQgbGluZSBudW1iZXJcbiAgICAjXG4gICAgZ2V0UmVhbEN1cnJlbnRMaW5lTmI6IC0+XG4gICAgICAgIHJldHVybiBAY3VycmVudExpbmVOYiArIEBvZmZzZXRcbiAgICBcblxuICAgICMgUmV0dXJucyB0aGUgY3VycmVudCBsaW5lIGluZGVudGF0aW9uLlxuICAgICNcbiAgICAjIEByZXR1cm4gW0ludGVnZXJdICAgICBUaGUgY3VycmVudCBsaW5lIGluZGVudGF0aW9uXG4gICAgI1xuICAgIGdldEN1cnJlbnRMaW5lSW5kZW50YXRpb246IC0+XG4gICAgICAgIHJldHVybiBAY3VycmVudExpbmUubGVuZ3RoIC0gVXRpbHMubHRyaW0oQGN1cnJlbnRMaW5lLCAnICcpLmxlbmd0aFxuXG5cbiAgICAjIFJldHVybnMgdGhlIG5leHQgZW1iZWQgYmxvY2sgb2YgWUFNTC5cbiAgICAjXG4gICAgIyBAcGFyYW0gW0ludGVnZXJdICAgICAgICAgIGluZGVudGF0aW9uIFRoZSBpbmRlbnQgbGV2ZWwgYXQgd2hpY2ggdGhlIGJsb2NrIGlzIHRvIGJlIHJlYWQsIG9yIG51bGwgZm9yIGRlZmF1bHRcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtTdHJpbmddICAgICAgICAgIEEgWUFNTCBzdHJpbmdcbiAgICAjXG4gICAgIyBAdGhyb3cgW1BhcnNlRXhjZXB0aW9uXSAgIFdoZW4gaW5kZW50YXRpb24gcHJvYmxlbSBhcmUgZGV0ZWN0ZWRcbiAgICAjXG4gICAgZ2V0TmV4dEVtYmVkQmxvY2s6IChpbmRlbnRhdGlvbiA9IG51bGwsIGluY2x1ZGVVbmluZGVudGVkQ29sbGVjdGlvbiA9IGZhbHNlKSAtPlxuICAgICAgICBAbW92ZVRvTmV4dExpbmUoKVxuXG4gICAgICAgIGlmIG5vdCBpbmRlbnRhdGlvbj9cbiAgICAgICAgICAgIG5ld0luZGVudCA9IEBnZXRDdXJyZW50TGluZUluZGVudGF0aW9uKClcblxuICAgICAgICAgICAgdW5pbmRlbnRlZEVtYmVkQmxvY2sgPSBAaXNTdHJpbmdVbkluZGVudGVkQ29sbGVjdGlvbkl0ZW0gQGN1cnJlbnRMaW5lXG5cbiAgICAgICAgICAgIGlmIG5vdChAaXNDdXJyZW50TGluZUVtcHR5KCkpIGFuZCAwIGlzIG5ld0luZGVudCBhbmQgbm90KHVuaW5kZW50ZWRFbWJlZEJsb2NrKVxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZUV4Y2VwdGlvbiAnSW5kZW50YXRpb24gcHJvYmxlbS4nLCBAZ2V0UmVhbEN1cnJlbnRMaW5lTmIoKSArIDEsIEBjdXJyZW50TGluZVxuICAgICAgICAgICAgXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIG5ld0luZGVudCA9IGluZGVudGF0aW9uXG5cblxuICAgICAgICBkYXRhID0gW0BjdXJyZW50TGluZVtuZXdJbmRlbnQuLl1dXG5cbiAgICAgICAgdW5sZXNzIGluY2x1ZGVVbmluZGVudGVkQ29sbGVjdGlvblxuICAgICAgICAgICAgaXNJdFVuaW5kZW50ZWRDb2xsZWN0aW9uID0gQGlzU3RyaW5nVW5JbmRlbnRlZENvbGxlY3Rpb25JdGVtIEBjdXJyZW50TGluZVxuXG4gICAgICAgICMgQ29tbWVudHMgbXVzdCBub3QgYmUgcmVtb3ZlZCBpbnNpZGUgYSBzdHJpbmcgYmxvY2sgKGllLiBhZnRlciBhIGxpbmUgZW5kaW5nIHdpdGggXCJ8XCIpXG4gICAgICAgICMgVGhleSBtdXN0IG5vdCBiZSByZW1vdmVkIGluc2lkZSBhIHN1Yi1lbWJlZGRlZCBibG9jayBhcyB3ZWxsXG4gICAgICAgIHJlbW92ZUNvbW1lbnRzUGF0dGVybiA9IEBQQVRURVJOX0ZPTERFRF9TQ0FMQVJfRU5EXG4gICAgICAgIHJlbW92ZUNvbW1lbnRzID0gbm90IHJlbW92ZUNvbW1lbnRzUGF0dGVybi50ZXN0IEBjdXJyZW50TGluZVxuXG4gICAgICAgIHdoaWxlIEBtb3ZlVG9OZXh0TGluZSgpXG4gICAgICAgICAgICBpbmRlbnQgPSBAZ2V0Q3VycmVudExpbmVJbmRlbnRhdGlvbigpXG5cbiAgICAgICAgICAgIGlmIGluZGVudCBpcyBuZXdJbmRlbnRcbiAgICAgICAgICAgICAgICByZW1vdmVDb21tZW50cyA9IG5vdCByZW1vdmVDb21tZW50c1BhdHRlcm4udGVzdCBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgaWYgaXNJdFVuaW5kZW50ZWRDb2xsZWN0aW9uIGFuZCBub3QgQGlzU3RyaW5nVW5JbmRlbnRlZENvbGxlY3Rpb25JdGVtKEBjdXJyZW50TGluZSkgYW5kIGluZGVudCBpcyBuZXdJbmRlbnRcbiAgICAgICAgICAgICAgICBAbW92ZVRvUHJldmlvdXNMaW5lKClcbiAgICAgICAgICAgICAgICBicmVha1xuXG4gICAgICAgICAgICBpZiBAaXNDdXJyZW50TGluZUJsYW5rKClcbiAgICAgICAgICAgICAgICBkYXRhLnB1c2ggQGN1cnJlbnRMaW5lW25ld0luZGVudC4uXVxuICAgICAgICAgICAgICAgIGNvbnRpbnVlXG5cbiAgICAgICAgICAgIGlmIHJlbW92ZUNvbW1lbnRzIGFuZCBAaXNDdXJyZW50TGluZUNvbW1lbnQoKVxuICAgICAgICAgICAgICAgIGlmIGluZGVudCBpcyBuZXdJbmRlbnRcbiAgICAgICAgICAgICAgICAgICAgY29udGludWVcblxuICAgICAgICAgICAgaWYgaW5kZW50ID49IG5ld0luZGVudFxuICAgICAgICAgICAgICAgIGRhdGEucHVzaCBAY3VycmVudExpbmVbbmV3SW5kZW50Li5dXG4gICAgICAgICAgICBlbHNlIGlmIDAgaXMgaW5kZW50XG4gICAgICAgICAgICAgICAgQG1vdmVUb1ByZXZpb3VzTGluZSgpXG4gICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2VFeGNlcHRpb24gJ0luZGVudGF0aW9uIHByb2JsZW0uJywgQGdldFJlYWxDdXJyZW50TGluZU5iKCkgKyAxLCBAY3VycmVudExpbmVcbiAgICAgICAgXG5cbiAgICAgICAgcmV0dXJuIGRhdGEuam9pbiBcIlxcblwiXG4gICAgXG5cbiAgICAjIE1vdmVzIHRoZSBwYXJzZXIgdG8gdGhlIG5leHQgbGluZS5cbiAgICAjXG4gICAgIyBAcmV0dXJuIFtCb29sZWFuXVxuICAgICNcbiAgICBtb3ZlVG9OZXh0TGluZTogLT5cbiAgICAgICAgaWYgQGN1cnJlbnRMaW5lTmIgPj0gQGxpbmVzLmxlbmd0aCAtIDFcbiAgICAgICAgICAgIHJldHVybiBmYWxzZVxuXG4gICAgICAgIEBjdXJyZW50TGluZSA9IEBsaW5lc1srK0BjdXJyZW50TGluZU5iXTtcblxuICAgICAgICByZXR1cm4gdHJ1ZVxuXG5cbiAgICAjIE1vdmVzIHRoZSBwYXJzZXIgdG8gdGhlIHByZXZpb3VzIGxpbmUuXG4gICAgI1xuICAgIG1vdmVUb1ByZXZpb3VzTGluZTogLT5cbiAgICAgICAgQGN1cnJlbnRMaW5lID0gQGxpbmVzWy0tQGN1cnJlbnRMaW5lTmJdXG4gICAgICAgIHJldHVyblxuXG5cbiAgICAjIFBhcnNlcyBhIFlBTUwgdmFsdWUuXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddICAgdmFsdWUgICAgICAgICAgICAgICAgICAgQSBZQU1MIHZhbHVlXG4gICAgIyBAcGFyYW0gW0Jvb2xlYW5dICBleGNlcHRpb25PbkludmFsaWRUeXBlICB0cnVlIGlmIGFuIGV4Y2VwdGlvbiBtdXN0IGJlIHRocm93biBvbiBpbnZhbGlkIHR5cGVzIGZhbHNlIG90aGVyd2lzZVxuICAgICMgQHBhcmFtIFtGdW5jdGlvbl0gb2JqZWN0RGVjb2RlciAgICAgICAgICAgQSBmdW5jdGlvbiB0byBkZXNlcmlhbGl6ZSBjdXN0b20gb2JqZWN0cywgbnVsbCBvdGhlcndpc2VcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtPYmplY3RdIEEgSmF2YVNjcmlwdCB2YWx1ZVxuICAgICNcbiAgICAjIEB0aHJvdyBbUGFyc2VFeGNlcHRpb25dIFdoZW4gcmVmZXJlbmNlIGRvZXMgbm90IGV4aXN0XG4gICAgI1xuICAgIHBhcnNlVmFsdWU6ICh2YWx1ZSwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RGVjb2RlcikgLT5cbiAgICAgICAgaWYgMCBpcyB2YWx1ZS5pbmRleE9mKCcqJylcbiAgICAgICAgICAgIHBvcyA9IHZhbHVlLmluZGV4T2YgJyMnXG4gICAgICAgICAgICBpZiBwb3MgaXNudCAtMVxuICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuc3Vic3RyKDEsIHBvcy0yKVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWVbMS4uXVxuXG4gICAgICAgICAgICBpZiBAcmVmc1t2YWx1ZV0gaXMgdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlRXhjZXB0aW9uICdSZWZlcmVuY2UgXCInK3ZhbHVlKydcIiBkb2VzIG5vdCBleGlzdC4nLCBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgcmV0dXJuIEByZWZzW3ZhbHVlXVxuXG5cbiAgICAgICAgaWYgbWF0Y2hlcyA9IEBQQVRURVJOX0ZPTERFRF9TQ0FMQVJfQUxMLmV4ZWMgdmFsdWVcbiAgICAgICAgICAgIG1vZGlmaWVycyA9IG1hdGNoZXMubW9kaWZpZXJzID8gJydcblxuICAgICAgICAgICAgZm9sZGVkSW5kZW50ID0gTWF0aC5hYnMocGFyc2VJbnQobW9kaWZpZXJzKSlcbiAgICAgICAgICAgIGlmIGlzTmFOKGZvbGRlZEluZGVudCkgdGhlbiBmb2xkZWRJbmRlbnQgPSAwXG4gICAgICAgICAgICB2YWwgPSBAcGFyc2VGb2xkZWRTY2FsYXIgbWF0Y2hlcy5zZXBhcmF0b3IsIEBQQVRURVJOX0RFQ0lNQUwucmVwbGFjZShtb2RpZmllcnMsICcnKSwgZm9sZGVkSW5kZW50XG4gICAgICAgICAgICBpZiBtYXRjaGVzLnR5cGU/XG4gICAgICAgICAgICAgICAgIyBGb3JjZSBjb3JyZWN0IHNldHRpbmdzXG4gICAgICAgICAgICAgICAgSW5saW5lLmNvbmZpZ3VyZSBleGNlcHRpb25PbkludmFsaWRUeXBlLCBvYmplY3REZWNvZGVyXG4gICAgICAgICAgICAgICAgcmV0dXJuIElubGluZS5wYXJzZVNjYWxhciBtYXRjaGVzLnR5cGUrJyAnK3ZhbFxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHJldHVybiB2YWxcblxuICAgICAgICB0cnlcbiAgICAgICAgICAgIHJldHVybiBJbmxpbmUucGFyc2UgdmFsdWUsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdERlY29kZXJcbiAgICAgICAgY2F0Y2ggZVxuICAgICAgICAgICAgIyBUcnkgdG8gcGFyc2UgbXVsdGlsaW5lIGNvbXBhY3Qgc2VxdWVuY2Ugb3IgbWFwcGluZ1xuICAgICAgICAgICAgaWYgdmFsdWUuY2hhckF0KDApIGluIFsnWycsICd7J10gYW5kIGUgaW5zdGFuY2VvZiBQYXJzZUV4Y2VwdGlvbiBhbmQgQGlzTmV4dExpbmVJbmRlbnRlZCgpXG4gICAgICAgICAgICAgICAgdmFsdWUgKz0gXCJcXG5cIiArIEBnZXROZXh0RW1iZWRCbG9jaygpXG4gICAgICAgICAgICAgICAgdHJ5XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBJbmxpbmUucGFyc2UgdmFsdWUsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdERlY29kZXJcbiAgICAgICAgICAgICAgICBjYXRjaCBlXG4gICAgICAgICAgICAgICAgICAgIGUucGFyc2VkTGluZSA9IEBnZXRSZWFsQ3VycmVudExpbmVOYigpICsgMVxuICAgICAgICAgICAgICAgICAgICBlLnNuaXBwZXQgPSBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlXG5cbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBlLnBhcnNlZExpbmUgPSBAZ2V0UmVhbEN1cnJlbnRMaW5lTmIoKSArIDFcbiAgICAgICAgICAgICAgICBlLnNuaXBwZXQgPSBAY3VycmVudExpbmVcblxuICAgICAgICAgICAgICAgIHRocm93IGVcblxuICAgICAgICByZXR1cm5cblxuXG4gICAgIyBQYXJzZXMgYSBmb2xkZWQgc2NhbGFyLlxuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSAgICAgICBzZXBhcmF0b3IgICBUaGUgc2VwYXJhdG9yIHRoYXQgd2FzIHVzZWQgdG8gYmVnaW4gdGhpcyBmb2xkZWQgc2NhbGFyICh8IG9yID4pXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gICAgICAgaW5kaWNhdG9yICAgVGhlIGluZGljYXRvciB0aGF0IHdhcyB1c2VkIHRvIGJlZ2luIHRoaXMgZm9sZGVkIHNjYWxhciAoKyBvciAtKVxuICAgICMgQHBhcmFtIFtJbnRlZ2VyXSAgICAgIGluZGVudGF0aW9uIFRoZSBpbmRlbnRhdGlvbiB0aGF0IHdhcyB1c2VkIHRvIGJlZ2luIHRoaXMgZm9sZGVkIHNjYWxhclxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gICAgICBUaGUgdGV4dCB2YWx1ZVxuICAgICNcbiAgICBwYXJzZUZvbGRlZFNjYWxhcjogKHNlcGFyYXRvciwgaW5kaWNhdG9yID0gJycsIGluZGVudGF0aW9uID0gMCkgLT5cbiAgICAgICAgbm90RU9GID0gQG1vdmVUb05leHRMaW5lKClcbiAgICAgICAgaWYgbm90IG5vdEVPRlxuICAgICAgICAgICAgcmV0dXJuICcnXG5cbiAgICAgICAgaXNDdXJyZW50TGluZUJsYW5rID0gQGlzQ3VycmVudExpbmVCbGFuaygpXG4gICAgICAgIHRleHQgPSAnJ1xuXG4gICAgICAgICMgTGVhZGluZyBibGFuayBsaW5lcyBhcmUgY29uc3VtZWQgYmVmb3JlIGRldGVybWluaW5nIGluZGVudGF0aW9uXG4gICAgICAgIHdoaWxlIG5vdEVPRiBhbmQgaXNDdXJyZW50TGluZUJsYW5rXG4gICAgICAgICAgICAjIG5ld2xpbmUgb25seSBpZiBub3QgRU9GXG4gICAgICAgICAgICBpZiBub3RFT0YgPSBAbW92ZVRvTmV4dExpbmUoKVxuICAgICAgICAgICAgICAgIHRleHQgKz0gXCJcXG5cIlxuICAgICAgICAgICAgICAgIGlzQ3VycmVudExpbmVCbGFuayA9IEBpc0N1cnJlbnRMaW5lQmxhbmsoKVxuXG5cbiAgICAgICAgIyBEZXRlcm1pbmUgaW5kZW50YXRpb24gaWYgbm90IHNwZWNpZmllZFxuICAgICAgICBpZiAwIGlzIGluZGVudGF0aW9uXG4gICAgICAgICAgICBpZiBtYXRjaGVzID0gQFBBVFRFUk5fSU5ERU5UX1NQQUNFUy5leGVjIEBjdXJyZW50TGluZVxuICAgICAgICAgICAgICAgIGluZGVudGF0aW9uID0gbWF0Y2hlc1swXS5sZW5ndGhcblxuXG4gICAgICAgIGlmIGluZGVudGF0aW9uID4gMFxuICAgICAgICAgICAgcGF0dGVybiA9IEBQQVRURVJOX0ZPTERFRF9TQ0FMQVJfQllfSU5ERU5UQVRJT05baW5kZW50YXRpb25dXG4gICAgICAgICAgICB1bmxlc3MgcGF0dGVybj9cbiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gbmV3IFBhdHRlcm4gJ14geycraW5kZW50YXRpb24rJ30oLiopJCdcbiAgICAgICAgICAgICAgICBQYXJzZXI6OlBBVFRFUk5fRk9MREVEX1NDQUxBUl9CWV9JTkRFTlRBVElPTltpbmRlbnRhdGlvbl0gPSBwYXR0ZXJuXG5cbiAgICAgICAgICAgIHdoaWxlIG5vdEVPRiBhbmQgKGlzQ3VycmVudExpbmVCbGFuayBvciBtYXRjaGVzID0gcGF0dGVybi5leGVjIEBjdXJyZW50TGluZSlcbiAgICAgICAgICAgICAgICBpZiBpc0N1cnJlbnRMaW5lQmxhbmtcbiAgICAgICAgICAgICAgICAgICAgdGV4dCArPSBAY3VycmVudExpbmVbaW5kZW50YXRpb24uLl1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHRleHQgKz0gbWF0Y2hlc1sxXVxuXG4gICAgICAgICAgICAgICAgIyBuZXdsaW5lIG9ubHkgaWYgbm90IEVPRlxuICAgICAgICAgICAgICAgIGlmIG5vdEVPRiA9IEBtb3ZlVG9OZXh0TGluZSgpXG4gICAgICAgICAgICAgICAgICAgIHRleHQgKz0gXCJcXG5cIlxuICAgICAgICAgICAgICAgICAgICBpc0N1cnJlbnRMaW5lQmxhbmsgPSBAaXNDdXJyZW50TGluZUJsYW5rKClcblxuICAgICAgICBlbHNlIGlmIG5vdEVPRlxuICAgICAgICAgICAgdGV4dCArPSBcIlxcblwiXG5cblxuICAgICAgICBpZiBub3RFT0ZcbiAgICAgICAgICAgIEBtb3ZlVG9QcmV2aW91c0xpbmUoKVxuXG5cbiAgICAgICAgIyBSZW1vdmUgbGluZSBicmVha3Mgb2YgZWFjaCBsaW5lcyBleGNlcHQgdGhlIGVtcHR5IGFuZCBtb3JlIGluZGVudGVkIG9uZXNcbiAgICAgICAgaWYgJz4nIGlzIHNlcGFyYXRvclxuICAgICAgICAgICAgbmV3VGV4dCA9ICcnXG4gICAgICAgICAgICBmb3IgbGluZSBpbiB0ZXh0LnNwbGl0IFwiXFxuXCJcbiAgICAgICAgICAgICAgICBpZiBsaW5lLmxlbmd0aCBpcyAwIG9yIGxpbmUuY2hhckF0KDApIGlzICcgJ1xuICAgICAgICAgICAgICAgICAgICBuZXdUZXh0ICs9IGxpbmUgKyBcIlxcblwiXG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICBuZXdUZXh0ICs9IGxpbmUgKyAnICdcbiAgICAgICAgICAgIHRleHQgPSBuZXdUZXh0XG5cbiAgICAgICAgIyBSZW1vdmUgYW55IGV4dHJhIHNwYWNlIG9yIG5ldyBsaW5lIGFzIHdlIGFyZSBhZGRpbmcgdGhlbSBhZnRlclxuICAgICAgICB0ZXh0ID0gVXRpbHMucnRyaW0odGV4dClcblxuICAgICAgICAjIERlYWwgd2l0aCB0cmFpbGluZyBuZXdsaW5lcyBhcyBpbmRpY2F0ZWRcbiAgICAgICAgaWYgJycgaXMgaW5kaWNhdG9yXG4gICAgICAgICAgICB0ZXh0ID0gQFBBVFRFUk5fVFJBSUxJTkdfTElORVMucmVwbGFjZSB0ZXh0LCBcIlxcblwiXG4gICAgICAgIGVsc2UgaWYgJy0nIGlzIGluZGljYXRvclxuICAgICAgICAgICAgdGV4dCA9IEBQQVRURVJOX1RSQUlMSU5HX0xJTkVTLnJlcGxhY2UgdGV4dCwgJydcblxuICAgICAgICByZXR1cm4gdGV4dFxuXG5cbiAgICAjIFJldHVybnMgdHJ1ZSBpZiB0aGUgbmV4dCBsaW5lIGlzIGluZGVudGVkLlxuICAgICNcbiAgICAjIEByZXR1cm4gW0Jvb2xlYW5dICAgICBSZXR1cm5zIHRydWUgaWYgdGhlIG5leHQgbGluZSBpcyBpbmRlbnRlZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAgI1xuICAgIGlzTmV4dExpbmVJbmRlbnRlZDogKGlnbm9yZUNvbW1lbnRzID0gdHJ1ZSkgLT5cbiAgICAgICAgY3VycmVudEluZGVudGF0aW9uID0gQGdldEN1cnJlbnRMaW5lSW5kZW50YXRpb24oKVxuICAgICAgICBFT0YgPSBub3QgQG1vdmVUb05leHRMaW5lKClcblxuICAgICAgICBpZiBpZ25vcmVDb21tZW50c1xuICAgICAgICAgICAgd2hpbGUgbm90KEVPRikgYW5kIEBpc0N1cnJlbnRMaW5lRW1wdHkoKVxuICAgICAgICAgICAgICAgIEVPRiA9IG5vdCBAbW92ZVRvTmV4dExpbmUoKVxuICAgICAgICBlbHNlXG4gICAgICAgICAgICB3aGlsZSBub3QoRU9GKSBhbmQgQGlzQ3VycmVudExpbmVCbGFuaygpXG4gICAgICAgICAgICAgICAgRU9GID0gbm90IEBtb3ZlVG9OZXh0TGluZSgpXG5cbiAgICAgICAgaWYgRU9GXG4gICAgICAgICAgICByZXR1cm4gZmFsc2VcblxuICAgICAgICByZXQgPSBmYWxzZVxuICAgICAgICBpZiBAZ2V0Q3VycmVudExpbmVJbmRlbnRhdGlvbigpID4gY3VycmVudEluZGVudGF0aW9uXG4gICAgICAgICAgICByZXQgPSB0cnVlXG5cbiAgICAgICAgQG1vdmVUb1ByZXZpb3VzTGluZSgpXG5cbiAgICAgICAgcmV0dXJuIHJldFxuXG5cbiAgICAjIFJldHVybnMgdHJ1ZSBpZiB0aGUgY3VycmVudCBsaW5lIGlzIGJsYW5rIG9yIGlmIGl0IGlzIGEgY29tbWVudCBsaW5lLlxuICAgICNcbiAgICAjIEByZXR1cm4gW0Jvb2xlYW5dICAgICBSZXR1cm5zIHRydWUgaWYgdGhlIGN1cnJlbnQgbGluZSBpcyBlbXB0eSBvciBpZiBpdCBpcyBhIGNvbW1lbnQgbGluZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAgI1xuICAgIGlzQ3VycmVudExpbmVFbXB0eTogLT5cbiAgICAgICAgdHJpbW1lZExpbmUgPSBVdGlscy50cmltKEBjdXJyZW50TGluZSwgJyAnKVxuICAgICAgICByZXR1cm4gdHJpbW1lZExpbmUubGVuZ3RoIGlzIDAgb3IgdHJpbW1lZExpbmUuY2hhckF0KDApIGlzICcjJ1xuXG5cbiAgICAjIFJldHVybnMgdHJ1ZSBpZiB0aGUgY3VycmVudCBsaW5lIGlzIGJsYW5rLlxuICAgICNcbiAgICAjIEByZXR1cm4gW0Jvb2xlYW5dICAgICBSZXR1cm5zIHRydWUgaWYgdGhlIGN1cnJlbnQgbGluZSBpcyBibGFuaywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAgI1xuICAgIGlzQ3VycmVudExpbmVCbGFuazogLT5cbiAgICAgICAgcmV0dXJuICcnIGlzIFV0aWxzLnRyaW0oQGN1cnJlbnRMaW5lLCAnICcpXG5cblxuICAgICMgUmV0dXJucyB0cnVlIGlmIHRoZSBjdXJyZW50IGxpbmUgaXMgYSBjb21tZW50IGxpbmUuXG4gICAgI1xuICAgICMgQHJldHVybiBbQm9vbGVhbl0gICAgIFJldHVybnMgdHJ1ZSBpZiB0aGUgY3VycmVudCBsaW5lIGlzIGEgY29tbWVudCBsaW5lLCBmYWxzZSBvdGhlcndpc2VcbiAgICAjXG4gICAgaXNDdXJyZW50TGluZUNvbW1lbnQ6IC0+XG4gICAgICAgICMgQ2hlY2tpbmcgZXhwbGljaXRseSB0aGUgZmlyc3QgY2hhciBvZiB0aGUgdHJpbSBpcyBmYXN0ZXIgdGhhbiBsb29wcyBvciBzdHJwb3NcbiAgICAgICAgbHRyaW1tZWRMaW5lID0gVXRpbHMubHRyaW0oQGN1cnJlbnRMaW5lLCAnICcpXG5cbiAgICAgICAgcmV0dXJuIGx0cmltbWVkTGluZS5jaGFyQXQoMCkgaXMgJyMnXG5cblxuICAgICMgQ2xlYW51cHMgYSBZQU1MIHN0cmluZyB0byBiZSBwYXJzZWQuXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddICAgdmFsdWUgVGhlIGlucHV0IFlBTUwgc3RyaW5nXG4gICAgI1xuICAgICMgQHJldHVybiBbU3RyaW5nXSAgQSBjbGVhbmVkIHVwIFlBTUwgc3RyaW5nXG4gICAgI1xuICAgIGNsZWFudXA6ICh2YWx1ZSkgLT5cbiAgICAgICAgdmFsdWUgPSB2YWx1ZS5yZXBsYWNlKFwiXFxyXFxuXCIsIFwiXFxuXCIpLnJlcGxhY2UoXCJcXHJcIiwgXCJcXG5cIilcblxuICAgICAgICAjIFN0cmlwIFlBTUwgaGVhZGVyXG4gICAgICAgIGNvdW50ID0gMFxuICAgICAgICBbdmFsdWUsIGNvdW50XSA9IEBQQVRURVJOX1lBTUxfSEVBREVSLnJlcGxhY2VBbGwgdmFsdWUsICcnXG4gICAgICAgIEBvZmZzZXQgKz0gY291bnRcblxuICAgICAgICAjIFJlbW92ZSBsZWFkaW5nIGNvbW1lbnRzXG4gICAgICAgIFt0cmltbWVkVmFsdWUsIGNvdW50XSA9IEBQQVRURVJOX0xFQURJTkdfQ09NTUVOVFMucmVwbGFjZUFsbCB2YWx1ZSwgJycsIDFcbiAgICAgICAgaWYgY291bnQgaXMgMVxuICAgICAgICAgICAgIyBJdGVtcyBoYXZlIGJlZW4gcmVtb3ZlZCwgdXBkYXRlIHRoZSBvZmZzZXRcbiAgICAgICAgICAgIEBvZmZzZXQgKz0gVXRpbHMuc3ViU3RyQ291bnQodmFsdWUsIFwiXFxuXCIpIC0gVXRpbHMuc3ViU3RyQ291bnQodHJpbW1lZFZhbHVlLCBcIlxcblwiKVxuICAgICAgICAgICAgdmFsdWUgPSB0cmltbWVkVmFsdWVcblxuICAgICAgICAjIFJlbW92ZSBzdGFydCBvZiB0aGUgZG9jdW1lbnQgbWFya2VyICgtLS0pXG4gICAgICAgIFt0cmltbWVkVmFsdWUsIGNvdW50XSA9IEBQQVRURVJOX0RPQ1VNRU5UX01BUktFUl9TVEFSVC5yZXBsYWNlQWxsIHZhbHVlLCAnJywgMVxuICAgICAgICBpZiBjb3VudCBpcyAxXG4gICAgICAgICAgICAjIEl0ZW1zIGhhdmUgYmVlbiByZW1vdmVkLCB1cGRhdGUgdGhlIG9mZnNldFxuICAgICAgICAgICAgQG9mZnNldCArPSBVdGlscy5zdWJTdHJDb3VudCh2YWx1ZSwgXCJcXG5cIikgLSBVdGlscy5zdWJTdHJDb3VudCh0cmltbWVkVmFsdWUsIFwiXFxuXCIpXG4gICAgICAgICAgICB2YWx1ZSA9IHRyaW1tZWRWYWx1ZVxuXG4gICAgICAgICAgICAjIFJlbW92ZSBlbmQgb2YgdGhlIGRvY3VtZW50IG1hcmtlciAoLi4uKVxuICAgICAgICAgICAgdmFsdWUgPSBAUEFUVEVSTl9ET0NVTUVOVF9NQVJLRVJfRU5ELnJlcGxhY2UgdmFsdWUsICcnXG4gICAgICAgIFxuICAgICAgICByZXR1cm4gdmFsdWVcblxuXG4gICAgIyBSZXR1cm5zIHRydWUgaWYgdGhlIG5leHQgbGluZSBzdGFydHMgdW5pbmRlbnRlZCBjb2xsZWN0aW9uXG4gICAgI1xuICAgICMgQHJldHVybiBbQm9vbGVhbl0gICAgIFJldHVybnMgdHJ1ZSBpZiB0aGUgbmV4dCBsaW5lIHN0YXJ0cyB1bmluZGVudGVkIGNvbGxlY3Rpb24sIGZhbHNlIG90aGVyd2lzZVxuICAgICNcbiAgICBpc05leHRMaW5lVW5JbmRlbnRlZENvbGxlY3Rpb246IChjdXJyZW50SW5kZW50YXRpb24gPSBudWxsKSAtPlxuICAgICAgICBjdXJyZW50SW5kZW50YXRpb24gPz0gQGdldEN1cnJlbnRMaW5lSW5kZW50YXRpb24oKVxuICAgICAgICBub3RFT0YgPSBAbW92ZVRvTmV4dExpbmUoKVxuXG4gICAgICAgIHdoaWxlIG5vdEVPRiBhbmQgQGlzQ3VycmVudExpbmVFbXB0eSgpXG4gICAgICAgICAgICBub3RFT0YgPSBAbW92ZVRvTmV4dExpbmUoKVxuXG4gICAgICAgIGlmIGZhbHNlIGlzIG5vdEVPRlxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlXG5cbiAgICAgICAgcmV0ID0gZmFsc2VcbiAgICAgICAgaWYgQGdldEN1cnJlbnRMaW5lSW5kZW50YXRpb24oKSBpcyBjdXJyZW50SW5kZW50YXRpb24gYW5kIEBpc1N0cmluZ1VuSW5kZW50ZWRDb2xsZWN0aW9uSXRlbShAY3VycmVudExpbmUpXG4gICAgICAgICAgICByZXQgPSB0cnVlXG5cbiAgICAgICAgQG1vdmVUb1ByZXZpb3VzTGluZSgpXG5cbiAgICAgICAgcmV0dXJuIHJldFxuXG5cbiAgICAjIFJldHVybnMgdHJ1ZSBpZiB0aGUgc3RyaW5nIGlzIHVuLWluZGVudGVkIGNvbGxlY3Rpb24gaXRlbVxuICAgICNcbiAgICAjIEByZXR1cm4gW0Jvb2xlYW5dICAgICBSZXR1cm5zIHRydWUgaWYgdGhlIHN0cmluZyBpcyB1bi1pbmRlbnRlZCBjb2xsZWN0aW9uIGl0ZW0sIGZhbHNlIG90aGVyd2lzZVxuICAgICNcbiAgICBpc1N0cmluZ1VuSW5kZW50ZWRDb2xsZWN0aW9uSXRlbTogLT5cbiAgICAgICAgcmV0dXJuIEBjdXJyZW50TGluZSBpcyAnLScgb3IgQGN1cnJlbnRMaW5lWzAuLi4yXSBpcyAnLSAnXG5cblxubW9kdWxlLmV4cG9ydHMgPSBQYXJzZXJcbiIsIlxuIyBQYXR0ZXJuIGlzIGEgemVyby1jb25mbGljdCB3cmFwcGVyIGV4dGVuZGluZyBSZWdFeHAgZmVhdHVyZXNcbiMgaW4gb3JkZXIgdG8gbWFrZSBZQU1MIHBhcnNpbmcgcmVnZXggbW9yZSBleHByZXNzaXZlLlxuI1xuY2xhc3MgUGF0dGVyblxuXG4gICAgIyBAcHJvcGVydHkgW1JlZ0V4cF0gVGhlIFJlZ0V4cCBpbnN0YW5jZVxuICAgIHJlZ2V4OiAgICAgICAgICBudWxsXG5cbiAgICAjIEBwcm9wZXJ0eSBbU3RyaW5nXSBUaGUgcmF3IHJlZ2V4IHN0cmluZ1xuICAgIHJhd1JlZ2V4OiAgICAgICBudWxsXG5cbiAgICAjIEBwcm9wZXJ0eSBbU3RyaW5nXSBUaGUgY2xlYW5lZCByZWdleCBzdHJpbmcgKHVzZWQgdG8gY3JlYXRlIHRoZSBSZWdFeHAgaW5zdGFuY2UpXG4gICAgY2xlYW5lZFJlZ2V4OiAgIG51bGxcblxuICAgICMgQHByb3BlcnR5IFtPYmplY3RdIFRoZSBkaWN0aW9uYXJ5IG1hcHBpbmcgbmFtZXMgdG8gY2FwdHVyaW5nIGJyYWNrZXQgbnVtYmVyc1xuICAgIG1hcHBpbmc6ICAgICAgICBudWxsXG5cbiAgICAjIENvbnN0cnVjdG9yXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddIHJhd1JlZ2V4IFRoZSByYXcgcmVnZXggc3RyaW5nIGRlZmluaW5nIHRoZSBwYXR0ZXJuXG4gICAgI1xuICAgIGNvbnN0cnVjdG9yOiAocmF3UmVnZXgsIG1vZGlmaWVycyA9ICcnKSAtPlxuICAgICAgICBjbGVhbmVkUmVnZXggPSAnJ1xuICAgICAgICBsZW4gPSByYXdSZWdleC5sZW5ndGhcbiAgICAgICAgbWFwcGluZyA9IG51bGxcblxuICAgICAgICAjIENsZWFudXAgcmF3IHJlZ2V4IGFuZCBjb21wdXRlIG1hcHBpbmdcbiAgICAgICAgY2FwdHVyaW5nQnJhY2tldE51bWJlciA9IDBcbiAgICAgICAgaSA9IDBcbiAgICAgICAgd2hpbGUgaSA8IGxlblxuICAgICAgICAgICAgY2hhciA9IHJhd1JlZ2V4LmNoYXJBdChpKVxuICAgICAgICAgICAgaWYgY2hhciBpcyAnXFxcXCdcbiAgICAgICAgICAgICAgICAjIElnbm9yZSBuZXh0IGNoYXJhY3RlclxuICAgICAgICAgICAgICAgIGNsZWFuZWRSZWdleCArPSByYXdSZWdleFtpLi5pKzFdXG4gICAgICAgICAgICAgICAgaSsrXG4gICAgICAgICAgICBlbHNlIGlmIGNoYXIgaXMgJygnXG4gICAgICAgICAgICAgICAgIyBJbmNyZWFzZSBicmFja2V0IG51bWJlciwgb25seSBpZiBpdCBpcyBjYXB0dXJpbmdcbiAgICAgICAgICAgICAgICBpZiBpIDwgbGVuIC0gMlxuICAgICAgICAgICAgICAgICAgICBwYXJ0ID0gcmF3UmVnZXhbaS4uaSsyXVxuICAgICAgICAgICAgICAgICAgICBpZiBwYXJ0IGlzICcoPzonXG4gICAgICAgICAgICAgICAgICAgICAgICAjIE5vbi1jYXB0dXJpbmcgYnJhY2tldFxuICAgICAgICAgICAgICAgICAgICAgICAgaSArPSAyXG4gICAgICAgICAgICAgICAgICAgICAgICBjbGVhbmVkUmVnZXggKz0gcGFydFxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIHBhcnQgaXMgJyg/PCdcbiAgICAgICAgICAgICAgICAgICAgICAgICMgQ2FwdHVyaW5nIGJyYWNrZXQgd2l0aCBwb3NzaWJseSBhIG5hbWVcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhcHR1cmluZ0JyYWNrZXROdW1iZXIrK1xuICAgICAgICAgICAgICAgICAgICAgICAgaSArPSAyXG4gICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gJydcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIGkgKyAxIDwgbGVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViQ2hhciA9IHJhd1JlZ2V4LmNoYXJBdChpICsgMSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBzdWJDaGFyIGlzICc+J1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhbmVkUmVnZXggKz0gJygnXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkrK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBuYW1lLmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQXNzb2NpYXRlIGEgbmFtZSB3aXRoIGEgY2FwdHVyaW5nIGJyYWNrZXQgbnVtYmVyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID89IHt9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nW25hbWVdID0gY2FwdHVyaW5nQnJhY2tldE51bWJlclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSArPSBzdWJDaGFyXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpKytcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5lZFJlZ2V4ICs9IGNoYXJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhcHR1cmluZ0JyYWNrZXROdW1iZXIrK1xuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgY2xlYW5lZFJlZ2V4ICs9IGNoYXJcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBjbGVhbmVkUmVnZXggKz0gY2hhclxuXG4gICAgICAgICAgICBpKytcblxuICAgICAgICBAcmF3UmVnZXggPSByYXdSZWdleFxuICAgICAgICBAY2xlYW5lZFJlZ2V4ID0gY2xlYW5lZFJlZ2V4XG4gICAgICAgIEByZWdleCA9IG5ldyBSZWdFeHAgQGNsZWFuZWRSZWdleCwgJ2cnK21vZGlmaWVycy5yZXBsYWNlKCdnJywgJycpXG4gICAgICAgIEBtYXBwaW5nID0gbWFwcGluZ1xuXG5cbiAgICAjIEV4ZWN1dGVzIHRoZSBwYXR0ZXJuJ3MgcmVnZXggYW5kIHJldHVybnMgdGhlIG1hdGNoaW5nIHZhbHVlc1xuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSBzdHIgVGhlIHN0cmluZyB0byB1c2UgdG8gZXhlY3V0ZSB0aGUgcGF0dGVyblxuICAgICNcbiAgICAjIEByZXR1cm4gW0FycmF5XSBUaGUgbWF0Y2hpbmcgdmFsdWVzIGV4dHJhY3RlZCBmcm9tIGNhcHR1cmluZyBicmFja2V0cyBvciBudWxsIGlmIG5vdGhpbmcgbWF0Y2hlZFxuICAgICNcbiAgICBleGVjOiAoc3RyKSAtPlxuICAgICAgICBAcmVnZXgubGFzdEluZGV4ID0gMFxuICAgICAgICBtYXRjaGVzID0gQHJlZ2V4LmV4ZWMgc3RyXG5cbiAgICAgICAgaWYgbm90IG1hdGNoZXM/XG4gICAgICAgICAgICByZXR1cm4gbnVsbFxuXG4gICAgICAgIGlmIEBtYXBwaW5nP1xuICAgICAgICAgICAgZm9yIG5hbWUsIGluZGV4IG9mIEBtYXBwaW5nXG4gICAgICAgICAgICAgICAgbWF0Y2hlc1tuYW1lXSA9IG1hdGNoZXNbaW5kZXhdXG5cbiAgICAgICAgcmV0dXJuIG1hdGNoZXNcblxuXG4gICAgIyBUZXN0cyB0aGUgcGF0dGVybidzIHJlZ2V4XG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddIHN0ciBUaGUgc3RyaW5nIHRvIHVzZSB0byB0ZXN0IHRoZSBwYXR0ZXJuXG4gICAgI1xuICAgICMgQHJldHVybiBbQm9vbGVhbl0gdHJ1ZSBpZiB0aGUgc3RyaW5nIG1hdGNoZWRcbiAgICAjXG4gICAgdGVzdDogKHN0cikgLT5cbiAgICAgICAgQHJlZ2V4Lmxhc3RJbmRleCA9IDBcbiAgICAgICAgcmV0dXJuIEByZWdleC50ZXN0IHN0clxuXG5cbiAgICAjIFJlcGxhY2VzIG9jY3VyZW5jZXMgbWF0Y2hpbmcgd2l0aCB0aGUgcGF0dGVybidzIHJlZ2V4IHdpdGggcmVwbGFjZW1lbnRcbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gc3RyIFRoZSBzb3VyY2Ugc3RyaW5nIHRvIHBlcmZvcm0gcmVwbGFjZW1lbnRzXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gcmVwbGFjZW1lbnQgVGhlIHN0cmluZyB0byB1c2UgaW4gcGxhY2Ugb2YgZWFjaCByZXBsYWNlZCBvY2N1cmVuY2UuXG4gICAgI1xuICAgICMgQHJldHVybiBbU3RyaW5nXSBUaGUgcmVwbGFjZWQgc3RyaW5nXG4gICAgI1xuICAgIHJlcGxhY2U6IChzdHIsIHJlcGxhY2VtZW50KSAtPlxuICAgICAgICBAcmVnZXgubGFzdEluZGV4ID0gMFxuICAgICAgICByZXR1cm4gc3RyLnJlcGxhY2UgQHJlZ2V4LCByZXBsYWNlbWVudFxuXG5cbiAgICAjIFJlcGxhY2VzIG9jY3VyZW5jZXMgbWF0Y2hpbmcgd2l0aCB0aGUgcGF0dGVybidzIHJlZ2V4IHdpdGggcmVwbGFjZW1lbnQgYW5kXG4gICAgIyBnZXQgYm90aCB0aGUgcmVwbGFjZWQgc3RyaW5nIGFuZCB0aGUgbnVtYmVyIG9mIHJlcGxhY2VkIG9jY3VyZW5jZXMgaW4gdGhlIHN0cmluZy5cbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gc3RyIFRoZSBzb3VyY2Ugc3RyaW5nIHRvIHBlcmZvcm0gcmVwbGFjZW1lbnRzXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gcmVwbGFjZW1lbnQgVGhlIHN0cmluZyB0byB1c2UgaW4gcGxhY2Ugb2YgZWFjaCByZXBsYWNlZCBvY2N1cmVuY2UuXG4gICAgIyBAcGFyYW0gW0ludGVnZXJdIGxpbWl0IFRoZSBtYXhpbXVtIG51bWJlciBvZiBvY2N1cmVuY2VzIHRvIHJlcGxhY2UgKDAgbWVhbnMgaW5maW5pdGUgbnVtYmVyIG9mIG9jY3VyZW5jZXMpXG4gICAgI1xuICAgICMgQHJldHVybiBbQXJyYXldIEEgZGVzdHJ1Y3R1cmFibGUgYXJyYXkgY29udGFpbmluZyB0aGUgcmVwbGFjZWQgc3RyaW5nIGFuZCB0aGUgbnVtYmVyIG9mIHJlcGxhY2VkIG9jY3VyZW5jZXMuIEZvciBpbnN0YW5jZTogW1wibXkgcmVwbGFjZWQgc3RyaW5nXCIsIDJdXG4gICAgI1xuICAgIHJlcGxhY2VBbGw6IChzdHIsIHJlcGxhY2VtZW50LCBsaW1pdCA9IDApIC0+XG4gICAgICAgIEByZWdleC5sYXN0SW5kZXggPSAwXG4gICAgICAgIGNvdW50ID0gMFxuICAgICAgICB3aGlsZSBAcmVnZXgudGVzdChzdHIpIGFuZCAobGltaXQgaXMgMCBvciBjb3VudCA8IGxpbWl0KVxuICAgICAgICAgICAgQHJlZ2V4Lmxhc3RJbmRleCA9IDBcbiAgICAgICAgICAgIHN0ciA9IHN0ci5yZXBsYWNlIEByZWdleCwgJydcbiAgICAgICAgICAgIGNvdW50KytcbiAgICAgICAgXG4gICAgICAgIHJldHVybiBbc3RyLCBjb3VudF1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IFBhdHRlcm5cblxuIiwiXG5VdGlscyAgID0gcmVxdWlyZSAnLi9VdGlscydcblBhdHRlcm4gPSByZXF1aXJlICcuL1BhdHRlcm4nXG5cbiMgVW5lc2NhcGVyIGVuY2Fwc3VsYXRlcyB1bmVzY2FwaW5nIHJ1bGVzIGZvciBzaW5nbGUgYW5kIGRvdWJsZS1xdW90ZWQgWUFNTCBzdHJpbmdzLlxuI1xuY2xhc3MgVW5lc2NhcGVyXG5cbiAgICAjIFJlZ2V4IGZyYWdtZW50IHRoYXQgbWF0Y2hlcyBhbiBlc2NhcGVkIGNoYXJhY3RlciBpblxuICAgICMgYSBkb3VibGUgcXVvdGVkIHN0cmluZy5cbiAgICBAUEFUVEVSTl9FU0NBUEVEX0NIQVJBQ1RFUjogICAgIG5ldyBQYXR0ZXJuICdcXFxcXFxcXChbMGFidFxcdG52ZnJlIFwiXFxcXC9cXFxcXFxcXE5fTFBdfHhbMC05YS1mQS1GXXsyfXx1WzAtOWEtZkEtRl17NH18VVswLTlhLWZBLUZdezh9KSc7XG5cblxuICAgICMgVW5lc2NhcGVzIGEgc2luZ2xlIHF1b3RlZCBzdHJpbmcuXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddICAgICAgIHZhbHVlIEEgc2luZ2xlIHF1b3RlZCBzdHJpbmcuXG4gICAgI1xuICAgICMgQHJldHVybiBbU3RyaW5nXSAgICAgIFRoZSB1bmVzY2FwZWQgc3RyaW5nLlxuICAgICNcbiAgICBAdW5lc2NhcGVTaW5nbGVRdW90ZWRTdHJpbmc6ICh2YWx1ZSkgLT5cbiAgICAgICAgcmV0dXJuIHZhbHVlLnJlcGxhY2UoJ1xcJ1xcJycsICdcXCcnKVxuXG5cbiAgICAjIFVuZXNjYXBlcyBhIGRvdWJsZSBxdW90ZWQgc3RyaW5nLlxuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSAgICAgICB2YWx1ZSBBIGRvdWJsZSBxdW90ZWQgc3RyaW5nLlxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gICAgICBUaGUgdW5lc2NhcGVkIHN0cmluZy5cbiAgICAjXG4gICAgQHVuZXNjYXBlRG91YmxlUXVvdGVkU3RyaW5nOiAodmFsdWUpIC0+XG4gICAgICAgIEBfdW5lc2NhcGVDYWxsYmFjayA/PSAoc3RyKSA9PlxuICAgICAgICAgICAgcmV0dXJuIEB1bmVzY2FwZUNoYXJhY3RlcihzdHIpXG5cbiAgICAgICAgIyBFdmFsdWF0ZSB0aGUgc3RyaW5nXG4gICAgICAgIHJldHVybiBAUEFUVEVSTl9FU0NBUEVEX0NIQVJBQ1RFUi5yZXBsYWNlIHZhbHVlLCBAX3VuZXNjYXBlQ2FsbGJhY2tcblxuXG4gICAgIyBVbmVzY2FwZXMgYSBjaGFyYWN0ZXIgdGhhdCB3YXMgZm91bmQgaW4gYSBkb3VibGUtcXVvdGVkIHN0cmluZ1xuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSAgICAgICB2YWx1ZSBBbiBlc2NhcGVkIGNoYXJhY3RlclxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gICAgICBUaGUgdW5lc2NhcGVkIGNoYXJhY3RlclxuICAgICNcbiAgICBAdW5lc2NhcGVDaGFyYWN0ZXI6ICh2YWx1ZSkgLT5cbiAgICAgICAgY2ggPSBTdHJpbmcuZnJvbUNoYXJDb2RlXG4gICAgICAgIHN3aXRjaCB2YWx1ZS5jaGFyQXQoMSlcbiAgICAgICAgICAgIHdoZW4gJzAnXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNoKDApXG4gICAgICAgICAgICB3aGVuICdhJ1xuICAgICAgICAgICAgICAgIHJldHVybiBjaCg3KVxuICAgICAgICAgICAgd2hlbiAnYidcbiAgICAgICAgICAgICAgICByZXR1cm4gY2goOClcbiAgICAgICAgICAgIHdoZW4gJ3QnXG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiXFx0XCJcbiAgICAgICAgICAgIHdoZW4gXCJcXHRcIlxuICAgICAgICAgICAgICAgIHJldHVybiBcIlxcdFwiXG4gICAgICAgICAgICB3aGVuICduJ1xuICAgICAgICAgICAgICAgIHJldHVybiBcIlxcblwiXG4gICAgICAgICAgICB3aGVuICd2J1xuICAgICAgICAgICAgICAgIHJldHVybiBjaCgxMSlcbiAgICAgICAgICAgIHdoZW4gJ2YnXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNoKDEyKVxuICAgICAgICAgICAgd2hlbiAncidcbiAgICAgICAgICAgICAgICByZXR1cm4gY2goMTMpXG4gICAgICAgICAgICB3aGVuICdlJ1xuICAgICAgICAgICAgICAgIHJldHVybiBjaCgyNylcbiAgICAgICAgICAgIHdoZW4gJyAnXG4gICAgICAgICAgICAgICAgcmV0dXJuICcgJ1xuICAgICAgICAgICAgd2hlbiAnXCInXG4gICAgICAgICAgICAgICAgcmV0dXJuICdcIidcbiAgICAgICAgICAgIHdoZW4gJy8nXG4gICAgICAgICAgICAgICAgcmV0dXJuICcvJ1xuICAgICAgICAgICAgd2hlbiAnXFxcXCdcbiAgICAgICAgICAgICAgICByZXR1cm4gJ1xcXFwnXG4gICAgICAgICAgICB3aGVuICdOJ1xuICAgICAgICAgICAgICAgICMgVSswMDg1IE5FWFQgTElORVxuICAgICAgICAgICAgICAgIHJldHVybiBjaCgweDAwODUpXG4gICAgICAgICAgICB3aGVuICdfJ1xuICAgICAgICAgICAgICAgICMgVSswMEEwIE5PLUJSRUFLIFNQQUNFXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNoKDB4MDBBMClcbiAgICAgICAgICAgIHdoZW4gJ0wnXG4gICAgICAgICAgICAgICAgIyBVKzIwMjggTElORSBTRVBBUkFUT1JcbiAgICAgICAgICAgICAgICByZXR1cm4gY2goMHgyMDI4KVxuICAgICAgICAgICAgd2hlbiAnUCdcbiAgICAgICAgICAgICAgICAjIFUrMjAyOSBQQVJBR1JBUEggU0VQQVJBVE9SXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNoKDB4MjAyOSlcbiAgICAgICAgICAgIHdoZW4gJ3gnXG4gICAgICAgICAgICAgICAgcmV0dXJuIFV0aWxzLnV0ZjhjaHIoVXRpbHMuaGV4RGVjKHZhbHVlLnN1YnN0cigyLCAyKSkpXG4gICAgICAgICAgICB3aGVuICd1J1xuICAgICAgICAgICAgICAgIHJldHVybiBVdGlscy51dGY4Y2hyKFV0aWxzLmhleERlYyh2YWx1ZS5zdWJzdHIoMiwgNCkpKVxuICAgICAgICAgICAgd2hlbiAnVSdcbiAgICAgICAgICAgICAgICByZXR1cm4gVXRpbHMudXRmOGNocihVdGlscy5oZXhEZWModmFsdWUuc3Vic3RyKDIsIDgpKSlcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICByZXR1cm4gJydcblxubW9kdWxlLmV4cG9ydHMgPSBVbmVzY2FwZXJcbiIsIlxuUGF0dGVybiA9IHJlcXVpcmUgJy4vUGF0dGVybidcblxuIyBBIGJ1bmNoIG9mIHV0aWxpdHkgbWV0aG9kc1xuI1xuY2xhc3MgVXRpbHNcblxuICAgIEBSRUdFWF9MRUZUX1RSSU1fQllfQ0hBUjogICB7fVxuICAgIEBSRUdFWF9SSUdIVF9UUklNX0JZX0NIQVI6ICB7fVxuICAgIEBSRUdFWF9TUEFDRVM6ICAgICAgICAgICAgICAvXFxzKy9nXG4gICAgQFJFR0VYX0RJR0lUUzogICAgICAgICAgICAgIC9eXFxkKyQvXG4gICAgQFJFR0VYX09DVEFMOiAgICAgICAgICAgICAgIC9bXjAtN10vZ2lcbiAgICBAUkVHRVhfSEVYQURFQ0lNQUw6ICAgICAgICAgL1teYS1mMC05XS9naVxuXG4gICAgIyBQcmVjb21waWxlZCBkYXRlIHBhdHRlcm5cbiAgICBAUEFUVEVSTl9EQVRFOiAgICAgICAgICAgICAgbmV3IFBhdHRlcm4gJ14nK1xuICAgICAgICAgICAgJyg/PHllYXI+WzAtOV1bMC05XVswLTldWzAtOV0pJytcbiAgICAgICAgICAgICctKD88bW9udGg+WzAtOV1bMC05XT8pJytcbiAgICAgICAgICAgICctKD88ZGF5PlswLTldWzAtOV0/KScrXG4gICAgICAgICAgICAnKD86KD86W1R0XXxbIFxcdF0rKScrXG4gICAgICAgICAgICAnKD88aG91cj5bMC05XVswLTldPyknK1xuICAgICAgICAgICAgJzooPzxtaW51dGU+WzAtOV1bMC05XSknK1xuICAgICAgICAgICAgJzooPzxzZWNvbmQ+WzAtOV1bMC05XSknK1xuICAgICAgICAgICAgJyg/OlxcLig/PGZyYWN0aW9uPlswLTldKikpPycrXG4gICAgICAgICAgICAnKD86WyBcXHRdKig/PHR6Plp8KD88dHpfc2lnbj5bLStdKSg/PHR6X2hvdXI+WzAtOV1bMC05XT8pJytcbiAgICAgICAgICAgICcoPzo6KD88dHpfbWludXRlPlswLTldWzAtOV0pKT8pKT8pPycrXG4gICAgICAgICAgICAnJCcsICdpJ1xuXG4gICAgIyBMb2NhbCB0aW1lem9uZSBvZmZzZXQgaW4gbXNcbiAgICBATE9DQUxfVElNRVpPTkVfT0ZGU0VUOiAgICAgbmV3IERhdGUoKS5nZXRUaW1lem9uZU9mZnNldCgpICogNjAgKiAxMDAwXG5cbiAgICAjIFRyaW1zIHRoZSBnaXZlbiBzdHJpbmcgb24gYm90aCBzaWRlc1xuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSBzdHIgVGhlIHN0cmluZyB0byB0cmltXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gY2hhciBUaGUgY2hhcmFjdGVyIHRvIHVzZSBmb3IgdHJpbW1pbmcgKGRlZmF1bHQ6ICdcXFxccycpXG4gICAgI1xuICAgICMgQHJldHVybiBbU3RyaW5nXSBBIHRyaW1tZWQgc3RyaW5nXG4gICAgI1xuICAgIEB0cmltOiAoc3RyLCBjaGFyID0gJ1xcXFxzJykgLT5cbiAgICAgICAgcmV0dXJuIHN0ci50cmltKClcbiAgICAgICAgcmVnZXhMZWZ0ID0gQFJFR0VYX0xFRlRfVFJJTV9CWV9DSEFSW2NoYXJdXG4gICAgICAgIHVubGVzcyByZWdleExlZnQ/XG4gICAgICAgICAgICBAUkVHRVhfTEVGVF9UUklNX0JZX0NIQVJbY2hhcl0gPSByZWdleExlZnQgPSBuZXcgUmVnRXhwICdeJytjaGFyKycnK2NoYXIrJyonXG4gICAgICAgIHJlZ2V4TGVmdC5sYXN0SW5kZXggPSAwXG4gICAgICAgIHJlZ2V4UmlnaHQgPSBAUkVHRVhfUklHSFRfVFJJTV9CWV9DSEFSW2NoYXJdXG4gICAgICAgIHVubGVzcyByZWdleFJpZ2h0P1xuICAgICAgICAgICAgQFJFR0VYX1JJR0hUX1RSSU1fQllfQ0hBUltjaGFyXSA9IHJlZ2V4UmlnaHQgPSBuZXcgUmVnRXhwIGNoYXIrJycrY2hhcisnKiQnXG4gICAgICAgIHJlZ2V4UmlnaHQubGFzdEluZGV4ID0gMFxuICAgICAgICByZXR1cm4gc3RyLnJlcGxhY2UocmVnZXhMZWZ0LCAnJykucmVwbGFjZShyZWdleFJpZ2h0LCAnJylcblxuXG4gICAgIyBUcmltcyB0aGUgZ2l2ZW4gc3RyaW5nIG9uIHRoZSBsZWZ0IHNpZGVcbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gc3RyIFRoZSBzdHJpbmcgdG8gdHJpbVxuICAgICMgQHBhcmFtIFtTdHJpbmddIGNoYXIgVGhlIGNoYXJhY3RlciB0byB1c2UgZm9yIHRyaW1taW5nIChkZWZhdWx0OiAnXFxcXHMnKVxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gQSB0cmltbWVkIHN0cmluZ1xuICAgICNcbiAgICBAbHRyaW06IChzdHIsIGNoYXIgPSAnXFxcXHMnKSAtPlxuICAgICAgICByZWdleExlZnQgPSBAUkVHRVhfTEVGVF9UUklNX0JZX0NIQVJbY2hhcl1cbiAgICAgICAgdW5sZXNzIHJlZ2V4TGVmdD9cbiAgICAgICAgICAgIEBSRUdFWF9MRUZUX1RSSU1fQllfQ0hBUltjaGFyXSA9IHJlZ2V4TGVmdCA9IG5ldyBSZWdFeHAgJ14nK2NoYXIrJycrY2hhcisnKidcbiAgICAgICAgcmVnZXhMZWZ0Lmxhc3RJbmRleCA9IDBcbiAgICAgICAgcmV0dXJuIHN0ci5yZXBsYWNlKHJlZ2V4TGVmdCwgJycpXG5cblxuICAgICMgVHJpbXMgdGhlIGdpdmVuIHN0cmluZyBvbiB0aGUgcmlnaHQgc2lkZVxuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSBzdHIgVGhlIHN0cmluZyB0byB0cmltXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gY2hhciBUaGUgY2hhcmFjdGVyIHRvIHVzZSBmb3IgdHJpbW1pbmcgKGRlZmF1bHQ6ICdcXFxccycpXG4gICAgI1xuICAgICMgQHJldHVybiBbU3RyaW5nXSBBIHRyaW1tZWQgc3RyaW5nXG4gICAgI1xuICAgIEBydHJpbTogKHN0ciwgY2hhciA9ICdcXFxccycpIC0+XG4gICAgICAgIHJlZ2V4UmlnaHQgPSBAUkVHRVhfUklHSFRfVFJJTV9CWV9DSEFSW2NoYXJdXG4gICAgICAgIHVubGVzcyByZWdleFJpZ2h0P1xuICAgICAgICAgICAgQFJFR0VYX1JJR0hUX1RSSU1fQllfQ0hBUltjaGFyXSA9IHJlZ2V4UmlnaHQgPSBuZXcgUmVnRXhwIGNoYXIrJycrY2hhcisnKiQnXG4gICAgICAgIHJlZ2V4UmlnaHQubGFzdEluZGV4ID0gMFxuICAgICAgICByZXR1cm4gc3RyLnJlcGxhY2UocmVnZXhSaWdodCwgJycpXG5cblxuICAgICMgQ2hlY2tzIGlmIHRoZSBnaXZlbiB2YWx1ZSBpcyBlbXB0eSAobnVsbCwgdW5kZWZpbmVkLCBlbXB0eSBzdHJpbmcsIHN0cmluZyAnMCcpXG4gICAgI1xuICAgICMgQHBhcmFtIFtPYmplY3RdIHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVja1xuICAgICNcbiAgICAjIEByZXR1cm4gW0Jvb2xlYW5dIHRydWUgaWYgdGhlIHZhbHVlIGlzIGVtcHR5XG4gICAgI1xuICAgIEBpc0VtcHR5OiAodmFsdWUpIC0+XG4gICAgICAgIHJldHVybiBub3QodmFsdWUpIG9yIHZhbHVlIGlzICcnIG9yIHZhbHVlIGlzICcwJ1xuXG5cbiAgICAjIENvdW50cyB0aGUgbnVtYmVyIG9mIG9jY3VyZW5jZXMgb2Ygc3ViU3RyaW5nIGluc2lkZSBzdHJpbmdcbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gc3RyaW5nIFRoZSBzdHJpbmcgd2hlcmUgdG8gY291bnQgb2NjdXJlbmNlc1xuICAgICMgQHBhcmFtIFtTdHJpbmddIHN1YlN0cmluZyBUaGUgc3ViU3RyaW5nIHRvIGNvdW50XG4gICAgIyBAcGFyYW0gW0ludGVnZXJdIHN0YXJ0IFRoZSBzdGFydCBpbmRleFxuICAgICMgQHBhcmFtIFtJbnRlZ2VyXSBsZW5ndGggVGhlIHN0cmluZyBsZW5ndGggdW50aWwgd2hlcmUgdG8gY291bnRcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtJbnRlZ2VyXSBUaGUgbnVtYmVyIG9mIG9jY3VyZW5jZXNcbiAgICAjXG4gICAgQHN1YlN0ckNvdW50OiAoc3RyaW5nLCBzdWJTdHJpbmcsIHN0YXJ0LCBsZW5ndGgpIC0+XG4gICAgICAgIGMgPSAwXG4gICAgICAgIFxuICAgICAgICBzdHJpbmcgPSAnJyArIHN0cmluZ1xuICAgICAgICBzdWJTdHJpbmcgPSAnJyArIHN1YlN0cmluZ1xuICAgICAgICBcbiAgICAgICAgaWYgc3RhcnQ/XG4gICAgICAgICAgICBzdHJpbmcgPSBzdHJpbmdbc3RhcnQuLl1cbiAgICAgICAgaWYgbGVuZ3RoP1xuICAgICAgICAgICAgc3RyaW5nID0gc3RyaW5nWzAuLi5sZW5ndGhdXG4gICAgICAgIFxuICAgICAgICBsZW4gPSBzdHJpbmcubGVuZ3RoXG4gICAgICAgIHN1YmxlbiA9IHN1YlN0cmluZy5sZW5ndGhcbiAgICAgICAgZm9yIGkgaW4gWzAuLi5sZW5dXG4gICAgICAgICAgICBpZiBzdWJTdHJpbmcgaXMgc3RyaW5nW2kuLi5zdWJsZW5dXG4gICAgICAgICAgICAgICAgYysrXG4gICAgICAgICAgICAgICAgaSArPSBzdWJsZW4gLSAxXG4gICAgICAgIFxuICAgICAgICByZXR1cm4gY1xuXG5cbiAgICAjIFJldHVybnMgdHJ1ZSBpZiBpbnB1dCBpcyBvbmx5IGNvbXBvc2VkIG9mIGRpZ2l0c1xuICAgICNcbiAgICAjIEBwYXJhbSBbT2JqZWN0XSBpbnB1dCBUaGUgdmFsdWUgdG8gdGVzdFxuICAgICNcbiAgICAjIEByZXR1cm4gW0Jvb2xlYW5dIHRydWUgaWYgaW5wdXQgaXMgb25seSBjb21wb3NlZCBvZiBkaWdpdHNcbiAgICAjXG4gICAgQGlzRGlnaXRzOiAoaW5wdXQpIC0+XG4gICAgICAgIEBSRUdFWF9ESUdJVFMubGFzdEluZGV4ID0gMFxuICAgICAgICByZXR1cm4gQFJFR0VYX0RJR0lUUy50ZXN0IGlucHV0XG5cblxuICAgICMgRGVjb2RlIG9jdGFsIHZhbHVlXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddIGlucHV0IFRoZSB2YWx1ZSB0byBkZWNvZGVcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtJbnRlZ2VyXSBUaGUgZGVjb2RlZCB2YWx1ZVxuICAgICNcbiAgICBAb2N0RGVjOiAoaW5wdXQpIC0+XG4gICAgICAgIEBSRUdFWF9PQ1RBTC5sYXN0SW5kZXggPSAwXG4gICAgICAgIHJldHVybiBwYXJzZUludCgoaW5wdXQrJycpLnJlcGxhY2UoQFJFR0VYX09DVEFMLCAnJyksIDgpXG5cblxuICAgICMgRGVjb2RlIGhleGFkZWNpbWFsIHZhbHVlXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddIGlucHV0IFRoZSB2YWx1ZSB0byBkZWNvZGVcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtJbnRlZ2VyXSBUaGUgZGVjb2RlZCB2YWx1ZVxuICAgICNcbiAgICBAaGV4RGVjOiAoaW5wdXQpIC0+XG4gICAgICAgIEBSRUdFWF9IRVhBREVDSU1BTC5sYXN0SW5kZXggPSAwXG4gICAgICAgIGlucHV0ID0gQHRyaW0oaW5wdXQpXG4gICAgICAgIGlmIChpbnB1dCsnJylbMC4uLjJdIGlzICcweCcgdGhlbiBpbnB1dCA9IChpbnB1dCsnJylbMi4uXVxuICAgICAgICByZXR1cm4gcGFyc2VJbnQoKGlucHV0KycnKS5yZXBsYWNlKEBSRUdFWF9IRVhBREVDSU1BTCwgJycpLCAxNilcblxuXG4gICAgIyBHZXQgdGhlIFVURi04IGNoYXJhY3RlciBmb3IgdGhlIGdpdmVuIGNvZGUgcG9pbnQuXG4gICAgI1xuICAgICMgQHBhcmFtIFtJbnRlZ2VyXSBjIFRoZSB1bmljb2RlIGNvZGUgcG9pbnRcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtTdHJpbmddIFRoZSBjb3JyZXNwb25kaW5nIFVURi04IGNoYXJhY3RlclxuICAgICNcbiAgICBAdXRmOGNocjogKGMpIC0+XG4gICAgICAgIGNoID0gU3RyaW5nLmZyb21DaGFyQ29kZVxuICAgICAgICBpZiAweDgwID4gKGMgJT0gMHgyMDAwMDApXG4gICAgICAgICAgICByZXR1cm4gY2goYylcbiAgICAgICAgaWYgMHg4MDAgPiBjXG4gICAgICAgICAgICByZXR1cm4gY2goMHhDMCB8IGM+PjYpICsgY2goMHg4MCB8IGMgJiAweDNGKVxuICAgICAgICBpZiAweDEwMDAwID4gY1xuICAgICAgICAgICAgcmV0dXJuIGNoKDB4RTAgfCBjPj4xMikgKyBjaCgweDgwIHwgYz4+NiAmIDB4M0YpICsgY2goMHg4MCB8IGMgJiAweDNGKVxuXG4gICAgICAgIHJldHVybiBjaCgweEYwIHwgYz4+MTgpICsgY2goMHg4MCB8IGM+PjEyICYgMHgzRikgKyBjaCgweDgwIHwgYz4+NiAmIDB4M0YpICsgY2goMHg4MCB8IGMgJiAweDNGKVxuXG5cbiAgICAjIFJldHVybnMgdGhlIGJvb2xlYW4gdmFsdWUgZXF1aXZhbGVudCB0byB0aGUgZ2l2ZW4gaW5wdXRcbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ3xPYmplY3RdICAgIGlucHV0ICAgICAgIFRoZSBpbnB1dCB2YWx1ZVxuICAgICMgQHBhcmFtIFtCb29sZWFuXSAgICAgICAgICBzdHJpY3QgICAgICBJZiBzZXQgdG8gZmFsc2UsIGFjY2VwdCAneWVzJyBhbmQgJ25vJyBhcyBib29sZWFuIHZhbHVlc1xuICAgICNcbiAgICAjIEByZXR1cm4gW0Jvb2xlYW5dICAgICAgICAgdGhlIGJvb2xlYW4gdmFsdWVcbiAgICAjXG4gICAgQHBhcnNlQm9vbGVhbjogKGlucHV0LCBzdHJpY3QgPSB0cnVlKSAtPlxuICAgICAgICBpZiB0eXBlb2YoaW5wdXQpIGlzICdzdHJpbmcnXG4gICAgICAgICAgICBsb3dlcklucHV0ID0gaW5wdXQudG9Mb3dlckNhc2UoKVxuICAgICAgICAgICAgaWYgbm90IHN0cmljdFxuICAgICAgICAgICAgICAgIGlmIGxvd2VySW5wdXQgaXMgJ25vJyB0aGVuIHJldHVybiBmYWxzZVxuICAgICAgICAgICAgaWYgbG93ZXJJbnB1dCBpcyAnMCcgdGhlbiByZXR1cm4gZmFsc2VcbiAgICAgICAgICAgIGlmIGxvd2VySW5wdXQgaXMgJ2ZhbHNlJyB0aGVuIHJldHVybiBmYWxzZVxuICAgICAgICAgICAgaWYgbG93ZXJJbnB1dCBpcyAnJyB0aGVuIHJldHVybiBmYWxzZVxuICAgICAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgICAgcmV0dXJuICEhaW5wdXRcblxuXG5cbiAgICAjIFJldHVybnMgdHJ1ZSBpZiBpbnB1dCBpcyBudW1lcmljXG4gICAgI1xuICAgICMgQHBhcmFtIFtPYmplY3RdIGlucHV0IFRoZSB2YWx1ZSB0byB0ZXN0XG4gICAgI1xuICAgICMgQHJldHVybiBbQm9vbGVhbl0gdHJ1ZSBpZiBpbnB1dCBpcyBudW1lcmljXG4gICAgI1xuICAgIEBpc051bWVyaWM6IChpbnB1dCkgLT5cbiAgICAgICAgQFJFR0VYX1NQQUNFUy5sYXN0SW5kZXggPSAwXG4gICAgICAgIHJldHVybiB0eXBlb2YoaW5wdXQpIGlzICdudW1iZXInIG9yIHR5cGVvZihpbnB1dCkgaXMgJ3N0cmluZycgYW5kICFpc05hTihpbnB1dCkgYW5kIGlucHV0LnJlcGxhY2UoQFJFR0VYX1NQQUNFUywgJycpIGlzbnQgJydcblxuXG4gICAgIyBSZXR1cm5zIGEgcGFyc2VkIGRhdGUgZnJvbSB0aGUgZ2l2ZW4gc3RyaW5nXG4gICAgI1xuICAgICMgQHBhcmFtIFtTdHJpbmddIHN0ciBUaGUgZGF0ZSBzdHJpbmcgdG8gcGFyc2VcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtEYXRlXSBUaGUgcGFyc2VkIGRhdGUgb3IgbnVsbCBpZiBwYXJzaW5nIGZhaWxlZFxuICAgICNcbiAgICBAc3RyaW5nVG9EYXRlOiAoc3RyKSAtPlxuICAgICAgICB1bmxlc3Mgc3RyPy5sZW5ndGhcbiAgICAgICAgICAgIHJldHVybiBudWxsXG5cbiAgICAgICAgIyBQZXJmb3JtIHJlZ3VsYXIgZXhwcmVzc2lvbiBwYXR0ZXJuXG4gICAgICAgIGluZm8gPSBAUEFUVEVSTl9EQVRFLmV4ZWMgc3RyXG4gICAgICAgIHVubGVzcyBpbmZvXG4gICAgICAgICAgICByZXR1cm4gbnVsbFxuXG4gICAgICAgICMgRXh0cmFjdCB5ZWFyLCBtb250aCwgZGF5XG4gICAgICAgIHllYXIgPSBwYXJzZUludCBpbmZvLnllYXIsIDEwXG4gICAgICAgIG1vbnRoID0gcGFyc2VJbnQoaW5mby5tb250aCwgMTApIC0gMSAjIEluIGphdmFzY3JpcHQsIGphbnVhcnkgaXMgMCwgZmVicnVhcnkgMSwgZXRjLi4uXG4gICAgICAgIGRheSA9IHBhcnNlSW50IGluZm8uZGF5LCAxMFxuXG4gICAgICAgICMgSWYgbm8gaG91ciBpcyBnaXZlbiwgcmV0dXJuIGEgZGF0ZSB3aXRoIGRheSBwcmVjaXNpb25cbiAgICAgICAgdW5sZXNzIGluZm8uaG91cj9cbiAgICAgICAgICAgIGRhdGUgPSBuZXcgRGF0ZSBEYXRlLlVUQyh5ZWFyLCBtb250aCwgZGF5KVxuICAgICAgICAgICAgcmV0dXJuIGRhdGVcblxuICAgICAgICAjIEV4dHJhY3QgaG91ciwgbWludXRlLCBzZWNvbmRcbiAgICAgICAgaG91ciA9IHBhcnNlSW50IGluZm8uaG91ciwgMTBcbiAgICAgICAgbWludXRlID0gcGFyc2VJbnQgaW5mby5taW51dGUsIDEwXG4gICAgICAgIHNlY29uZCA9IHBhcnNlSW50IGluZm8uc2Vjb25kLCAxMFxuXG4gICAgICAgICMgRXh0cmFjdCBmcmFjdGlvbiwgaWYgZ2l2ZW5cbiAgICAgICAgaWYgaW5mby5mcmFjdGlvbj9cbiAgICAgICAgICAgIGZyYWN0aW9uID0gaW5mby5mcmFjdGlvblswLi4uM11cbiAgICAgICAgICAgIHdoaWxlIGZyYWN0aW9uLmxlbmd0aCA8IDNcbiAgICAgICAgICAgICAgICBmcmFjdGlvbiArPSAnMCdcbiAgICAgICAgICAgIGZyYWN0aW9uID0gcGFyc2VJbnQgZnJhY3Rpb24sIDEwXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGZyYWN0aW9uID0gMFxuXG4gICAgICAgICMgQ29tcHV0ZSB0aW1lem9uZSBvZmZzZXQgaWYgZ2l2ZW5cbiAgICAgICAgaWYgaW5mby50ej9cbiAgICAgICAgICAgIHR6X2hvdXIgPSBwYXJzZUludCBpbmZvLnR6X2hvdXIsIDEwXG4gICAgICAgICAgICBpZiBpbmZvLnR6X21pbnV0ZT9cbiAgICAgICAgICAgICAgICB0el9taW51dGUgPSBwYXJzZUludCBpbmZvLnR6X21pbnV0ZSwgMTBcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICB0el9taW51dGUgPSAwXG5cbiAgICAgICAgICAgICMgQ29tcHV0ZSB0aW1lem9uZSBkZWx0YSBpbiBtc1xuICAgICAgICAgICAgdHpfb2Zmc2V0ID0gKHR6X2hvdXIgKiA2MCArIHR6X21pbnV0ZSkgKiA2MDAwMFxuICAgICAgICAgICAgaWYgJy0nIGlzIGluZm8udHpfc2lnblxuICAgICAgICAgICAgICAgIHR6X29mZnNldCAqPSAtMVxuXG4gICAgICAgICMgQ29tcHV0ZSBkYXRlXG4gICAgICAgIGRhdGUgPSBuZXcgRGF0ZSBEYXRlLlVUQyh5ZWFyLCBtb250aCwgZGF5LCBob3VyLCBtaW51dGUsIHNlY29uZCwgZnJhY3Rpb24pXG4gICAgICAgIGlmIHR6X29mZnNldFxuICAgICAgICAgICAgZGF0ZS5zZXRUaW1lIGRhdGUuZ2V0VGltZSgpICsgdHpfb2Zmc2V0XG5cbiAgICAgICAgcmV0dXJuIGRhdGVcblxuXG4gICAgIyBSZXBlYXRzIHRoZSBnaXZlbiBzdHJpbmcgYSBudW1iZXIgb2YgdGltZXNcbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gICBzdHIgICAgIFRoZSBzdHJpbmcgdG8gcmVwZWF0XG4gICAgIyBAcGFyYW0gW0ludGVnZXJdICBudW1iZXIgIFRoZSBudW1iZXIgb2YgdGltZXMgdG8gcmVwZWF0IHRoZSBzdHJpbmdcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtTdHJpbmddICBUaGUgcmVwZWF0ZWQgc3RyaW5nXG4gICAgI1xuICAgIEBzdHJSZXBlYXQ6IChzdHIsIG51bWJlcikgLT5cbiAgICAgICAgcmVzID0gJydcbiAgICAgICAgaSA9IDBcbiAgICAgICAgd2hpbGUgaSA8IG51bWJlclxuICAgICAgICAgICAgcmVzICs9IHN0clxuICAgICAgICAgICAgaSsrXG4gICAgICAgIHJldHVybiByZXNcblxuXG4gICAgIyBSZWFkcyB0aGUgZGF0YSBmcm9tIHRoZSBnaXZlbiBmaWxlIHBhdGggYW5kIHJldHVybnMgdGhlIHJlc3VsdCBhcyBzdHJpbmdcbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gICBwYXRoICAgICAgICBUaGUgcGF0aCB0byB0aGUgZmlsZVxuICAgICMgQHBhcmFtIFtGdW5jdGlvbl0gY2FsbGJhY2sgICAgQSBjYWxsYmFjayB0byByZWFkIGZpbGUgYXN5bmNocm9ub3VzbHkgKG9wdGlvbmFsKVxuICAgICNcbiAgICAjIEByZXR1cm4gW1N0cmluZ10gIFRoZSByZXN1bHRpbmcgZGF0YSBhcyBzdHJpbmdcbiAgICAjXG4gICAgQGdldFN0cmluZ0Zyb21GaWxlOiAocGF0aCwgY2FsbGJhY2sgPSBudWxsKSAtPlxuICAgICAgICB4aHIgPSBudWxsXG4gICAgICAgIGlmIHdpbmRvdz9cbiAgICAgICAgICAgIGlmIHdpbmRvdy5YTUxIdHRwUmVxdWVzdFxuICAgICAgICAgICAgICAgIHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpXG4gICAgICAgICAgICBlbHNlIGlmIHdpbmRvdy5BY3RpdmVYT2JqZWN0XG4gICAgICAgICAgICAgICAgZm9yIG5hbWUgaW4gW1wiTXN4bWwyLlhNTEhUVFAuNi4wXCIsIFwiTXN4bWwyLlhNTEhUVFAuMy4wXCIsIFwiTXN4bWwyLlhNTEhUVFBcIiwgXCJNaWNyb3NvZnQuWE1MSFRUUFwiXVxuICAgICAgICAgICAgICAgICAgICB0cnlcbiAgICAgICAgICAgICAgICAgICAgICAgIHhociA9IG5ldyBBY3RpdmVYT2JqZWN0KG5hbWUpXG5cbiAgICAgICAgaWYgeGhyP1xuICAgICAgICAgICAgIyBCcm93c2VyXG4gICAgICAgICAgICBpZiBjYWxsYmFjaz9cbiAgICAgICAgICAgICAgICAjIEFzeW5jXG4gICAgICAgICAgICAgICAgeGhyLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IC0+XG4gICAgICAgICAgICAgICAgICAgIGlmIHhoci5yZWFkeVN0YXRlIGlzIDRcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIHhoci5zdGF0dXMgaXMgMjAwIG9yIHhoci5zdGF0dXMgaXMgMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKHhoci5yZXNwb25zZVRleHQpXG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbClcbiAgICAgICAgICAgICAgICB4aHIub3BlbiAnR0VUJywgcGF0aCwgdHJ1ZVxuICAgICAgICAgICAgICAgIHhoci5zZW5kIG51bGxcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICMgU3luY1xuICAgICAgICAgICAgICAgIHhoci5vcGVuICdHRVQnLCBwYXRoLCBmYWxzZVxuICAgICAgICAgICAgICAgIHhoci5zZW5kIG51bGxcblxuICAgICAgICAgICAgICAgIGlmIHhoci5zdGF0dXMgaXMgMjAwIG9yIHhoci5zdGF0dXMgPT0gMFxuICAgICAgICAgICAgICAgICAgICByZXR1cm4geGhyLnJlc3BvbnNlVGV4dFxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgIyBOb2RlLmpzLWxpa2VcbiAgICAgICAgICAgIHJlcSA9IHJlcXVpcmVcbiAgICAgICAgICAgIGZzID0gcmVxKCdmcycpICMgUHJldmVudCBicm93c2VyaWZ5IGZyb20gdHJ5aW5nIHRvIGxvYWQgJ2ZzJyBtb2R1bGVcbiAgICAgICAgICAgIGlmIGNhbGxiYWNrP1xuICAgICAgICAgICAgICAgICMgQXN5bmNcbiAgICAgICAgICAgICAgICBmcy5yZWFkRmlsZSBwYXRoLCAoZXJyLCBkYXRhKSAtPlxuICAgICAgICAgICAgICAgICAgICBpZiBlcnJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrIG51bGxcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sgZGF0YVxuXG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgIyBTeW5jXG4gICAgICAgICAgICAgICAgZGF0YSA9IGZzLnJlYWRGaWxlU3luYyBwYXRoXG4gICAgICAgICAgICAgICAgaWYgZGF0YT9cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICcnK2RhdGFcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbFxuXG5cblxubW9kdWxlLmV4cG9ydHMgPSBVdGlsc1xuIiwiXG5QYXJzZXIgPSByZXF1aXJlICcuL1BhcnNlcidcbkR1bXBlciA9IHJlcXVpcmUgJy4vRHVtcGVyJ1xuVXRpbHMgID0gcmVxdWlyZSAnLi9VdGlscydcblxuIyBZYW1sIG9mZmVycyBjb252ZW5pZW5jZSBtZXRob2RzIHRvIGxvYWQgYW5kIGR1bXAgWUFNTC5cbiNcbmNsYXNzIFlhbWxcblxuICAgICMgUGFyc2VzIFlBTUwgaW50byBhIEphdmFTY3JpcHQgb2JqZWN0LlxuICAgICNcbiAgICAjIFRoZSBwYXJzZSBtZXRob2QsIHdoZW4gc3VwcGxpZWQgd2l0aCBhIFlBTUwgc3RyaW5nLFxuICAgICMgd2lsbCBkbyBpdHMgYmVzdCB0byBjb252ZXJ0IFlBTUwgaW4gYSBmaWxlIGludG8gYSBKYXZhU2NyaXB0IG9iamVjdC5cbiAgICAjXG4gICAgIyAgVXNhZ2U6XG4gICAgIyAgICAgbXlPYmplY3QgPSBZYW1sLnBhcnNlKCdzb21lOiB5YW1sJyk7XG4gICAgIyAgICAgY29uc29sZS5sb2cobXlPYmplY3QpO1xuICAgICNcbiAgICAjIEBwYXJhbSBbU3RyaW5nXSAgIGlucHV0ICAgICAgICAgICAgICAgICAgIEEgc3RyaW5nIGNvbnRhaW5pbmcgWUFNTFxuICAgICMgQHBhcmFtIFtCb29sZWFuXSAgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSAgdHJ1ZSBpZiBhbiBleGNlcHRpb24gbXVzdCBiZSB0aHJvd24gb24gaW52YWxpZCB0eXBlcywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAgIyBAcGFyYW0gW0Z1bmN0aW9uXSBvYmplY3REZWNvZGVyICAgICAgICAgICBBIGZ1bmN0aW9uIHRvIGRlc2VyaWFsaXplIGN1c3RvbSBvYmplY3RzLCBudWxsIG90aGVyd2lzZVxuICAgICNcbiAgICAjIEByZXR1cm4gW09iamVjdF0gIFRoZSBZQU1MIGNvbnZlcnRlZCB0byBhIEphdmFTY3JpcHQgb2JqZWN0XG4gICAgI1xuICAgICMgQHRocm93IFtQYXJzZUV4Y2VwdGlvbl0gSWYgdGhlIFlBTUwgaXMgbm90IHZhbGlkXG4gICAgI1xuICAgIEBwYXJzZTogKGlucHV0LCBleGNlcHRpb25PbkludmFsaWRUeXBlID0gZmFsc2UsIG9iamVjdERlY29kZXIgPSBudWxsKSAtPlxuICAgICAgICByZXR1cm4gbmV3IFBhcnNlcigpLnBhcnNlKGlucHV0LCBleGNlcHRpb25PbkludmFsaWRUeXBlLCBvYmplY3REZWNvZGVyKVxuXG5cbiAgICAjIFBhcnNlcyBZQU1MIGZyb20gZmlsZSBwYXRoIGludG8gYSBKYXZhU2NyaXB0IG9iamVjdC5cbiAgICAjXG4gICAgIyBUaGUgcGFyc2VGaWxlIG1ldGhvZCwgd2hlbiBzdXBwbGllZCB3aXRoIGEgWUFNTCBmaWxlLFxuICAgICMgd2lsbCBkbyBpdHMgYmVzdCB0byBjb252ZXJ0IFlBTUwgaW4gYSBmaWxlIGludG8gYSBKYXZhU2NyaXB0IG9iamVjdC5cbiAgICAjXG4gICAgIyAgVXNhZ2U6XG4gICAgIyAgICAgbXlPYmplY3QgPSBZYW1sLnBhcnNlRmlsZSgnY29uZmlnLnltbCcpO1xuICAgICMgICAgIGNvbnNvbGUubG9nKG15T2JqZWN0KTtcbiAgICAjXG4gICAgIyBAcGFyYW0gW1N0cmluZ10gICBwYXRoICAgICAgICAgICAgICAgICAgICBBIGZpbGUgcGF0aCBwb2ludGluZyB0byBhIHZhbGlkIFlBTUwgZmlsZVxuICAgICMgQHBhcmFtIFtCb29sZWFuXSAgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSAgdHJ1ZSBpZiBhbiBleGNlcHRpb24gbXVzdCBiZSB0aHJvd24gb24gaW52YWxpZCB0eXBlcywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAgIyBAcGFyYW0gW0Z1bmN0aW9uXSBvYmplY3REZWNvZGVyICAgICAgICAgICBBIGZ1bmN0aW9uIHRvIGRlc2VyaWFsaXplIGN1c3RvbSBvYmplY3RzLCBudWxsIG90aGVyd2lzZVxuICAgICNcbiAgICAjIEByZXR1cm4gW09iamVjdF0gIFRoZSBZQU1MIGNvbnZlcnRlZCB0byBhIEphdmFTY3JpcHQgb2JqZWN0IG9yIG51bGwgaWYgdGhlIGZpbGUgZG9lc24ndCBleGlzdC5cbiAgICAjXG4gICAgIyBAdGhyb3cgW1BhcnNlRXhjZXB0aW9uXSBJZiB0aGUgWUFNTCBpcyBub3QgdmFsaWRcbiAgICAjXG4gICAgQHBhcnNlRmlsZTogKHBhdGgsIGNhbGxiYWNrID0gbnVsbCwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSA9IGZhbHNlLCBvYmplY3REZWNvZGVyID0gbnVsbCkgLT5cbiAgICAgICAgaWYgY2FsbGJhY2s/XG4gICAgICAgICAgICAjIEFzeW5jXG4gICAgICAgICAgICBVdGlscy5nZXRTdHJpbmdGcm9tRmlsZSBwYXRoLCAoaW5wdXQpID0+XG4gICAgICAgICAgICAgICAgaWYgaW5wdXQ/XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBAcGFyc2UgaW5wdXQsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdERlY29kZXJcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbFxuICAgICAgICBlbHNlXG4gICAgICAgICAgICAjIFN5bmNcbiAgICAgICAgICAgIGlucHV0ID0gVXRpbHMuZ2V0U3RyaW5nRnJvbUZpbGUgcGF0aFxuICAgICAgICAgICAgaWYgaW5wdXQ/XG4gICAgICAgICAgICAgICAgcmV0dXJuIEBwYXJzZSBpbnB1dCwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RGVjb2RlclxuICAgICAgICAgICAgcmV0dXJuIG51bGxcblxuXG4gICAgIyBEdW1wcyBhIEphdmFTY3JpcHQgb2JqZWN0IHRvIGEgWUFNTCBzdHJpbmcuXG4gICAgI1xuICAgICMgVGhlIGR1bXAgbWV0aG9kLCB3aGVuIHN1cHBsaWVkIHdpdGggYW4gb2JqZWN0LCB3aWxsIGRvIGl0cyBiZXN0XG4gICAgIyB0byBjb252ZXJ0IHRoZSBvYmplY3QgaW50byBmcmllbmRseSBZQU1MLlxuICAgICNcbiAgICAjIEBwYXJhbSBbT2JqZWN0XSAgIGlucHV0ICAgICAgICAgICAgICAgICAgIEphdmFTY3JpcHQgb2JqZWN0XG4gICAgIyBAcGFyYW0gW0ludGVnZXJdICBpbmxpbmUgICAgICAgICAgICAgICAgICBUaGUgbGV2ZWwgd2hlcmUgeW91IHN3aXRjaCB0byBpbmxpbmUgWUFNTFxuICAgICMgQHBhcmFtIFtJbnRlZ2VyXSAgaW5kZW50ICAgICAgICAgICAgICAgICAgVGhlIGFtb3VudCBvZiBzcGFjZXMgdG8gdXNlIGZvciBpbmRlbnRhdGlvbiBvZiBuZXN0ZWQgbm9kZXMuXG4gICAgIyBAcGFyYW0gW0Jvb2xlYW5dICBleGNlcHRpb25PbkludmFsaWRUeXBlICB0cnVlIGlmIGFuIGV4Y2VwdGlvbiBtdXN0IGJlIHRocm93biBvbiBpbnZhbGlkIHR5cGVzIChhIEphdmFTY3JpcHQgcmVzb3VyY2Ugb3Igb2JqZWN0KSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAgIyBAcGFyYW0gW0Z1bmN0aW9uXSBvYmplY3RFbmNvZGVyICAgICAgICAgICBBIGZ1bmN0aW9uIHRvIHNlcmlhbGl6ZSBjdXN0b20gb2JqZWN0cywgbnVsbCBvdGhlcndpc2VcbiAgICAjXG4gICAgIyBAcmV0dXJuIFtTdHJpbmddICBBIFlBTUwgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3JpZ2luYWwgSmF2YVNjcmlwdCBvYmplY3RcbiAgICAjXG4gICAgQGR1bXA6IChpbnB1dCwgaW5saW5lID0gMiwgaW5kZW50ID0gNCwgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSA9IGZhbHNlLCBvYmplY3RFbmNvZGVyID0gbnVsbCkgLT5cbiAgICAgICAgeWFtbCA9IG5ldyBEdW1wZXIoKVxuICAgICAgICB5YW1sLmluZGVudGF0aW9uID0gaW5kZW50XG5cbiAgICAgICAgcmV0dXJuIHlhbWwuZHVtcChpbnB1dCwgaW5saW5lLCAwLCBleGNlcHRpb25PbkludmFsaWRUeXBlLCBvYmplY3RFbmNvZGVyKVxuXG5cbiAgICAjIFJlZ2lzdGVycyAueW1sIGV4dGVuc2lvbiB0byB3b3JrIHdpdGggbm9kZSdzIHJlcXVpcmUoKSBmdW5jdGlvbi5cbiAgICAjXG4gICAgQHJlZ2lzdGVyOiAtPlxuICAgICAgICByZXF1aXJlX2hhbmRsZXIgPSAobW9kdWxlLCBmaWxlbmFtZSkgLT5cbiAgICAgICAgICAgICMgRmlsbCBpbiByZXN1bHRcbiAgICAgICAgICAgIG1vZHVsZS5leHBvcnRzID0gWUFNTC5wYXJzZUZpbGUgZmlsZW5hbWVcblxuICAgICAgICAjIFJlZ2lzdGVyIHJlcXVpcmUgZXh0ZW5zaW9ucyBvbmx5IGlmIHdlJ3JlIG9uIG5vZGUuanNcbiAgICAgICAgIyBoYWNrIGZvciBicm93c2VyaWZ5XG4gICAgICAgIGlmIHJlcXVpcmU/LmV4dGVuc2lvbnM/XG4gICAgICAgICAgICByZXF1aXJlLmV4dGVuc2lvbnNbJy55bWwnXSA9IHJlcXVpcmVfaGFuZGxlclxuICAgICAgICAgICAgcmVxdWlyZS5leHRlbnNpb25zWycueWFtbCddID0gcmVxdWlyZV9oYW5kbGVyXG5cblxuICAgICMgQWxpYXMgb2YgZHVtcCgpIG1ldGhvZCBmb3IgY29tcGF0aWJpbGl0eSByZWFzb25zLlxuICAgICNcbiAgICBzdHJpbmdpZnk6IChpbnB1dCwgaW5saW5lLCBpbmRlbnQsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdEVuY29kZXIpIC0+XG4gICAgICAgIHJldHVybiBAZHVtcCBpbnB1dCwgaW5saW5lLCBpbmRlbnQsIGV4Y2VwdGlvbk9uSW52YWxpZFR5cGUsIG9iamVjdEVuY29kZXJcblxuXG4gICAgIyBBbGlhcyBvZiBwYXJzZUZpbGUoKSBtZXRob2QgZm9yIGNvbXBhdGliaWxpdHkgcmVhc29ucy5cbiAgICAjXG4gICAgbG9hZDogKHBhdGgsIGNhbGxiYWNrLCBleGNlcHRpb25PbkludmFsaWRUeXBlLCBvYmplY3REZWNvZGVyKSAtPlxuICAgICAgICByZXR1cm4gQHBhcnNlRmlsZSBwYXRoLCBjYWxsYmFjaywgZXhjZXB0aW9uT25JbnZhbGlkVHlwZSwgb2JqZWN0RGVjb2RlclxuXG5cbiMgRXhwb3NlIFlBTUwgbmFtZXNwYWNlIHRvIGJyb3dzZXJcbndpbmRvdz8uWUFNTCA9IFlhbWxcblxubW9kdWxlLmV4cG9ydHMgPSBZYW1sXG5cbiJdfQ==
diff --git a/dist/yaml.js b/dist/yaml.js
new file mode 100644
index 0000000..89821e8
--- /dev/null
+++ b/dist/yaml.js
@@ -0,0 +1,1820 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+var Dumper, Inline, Utils;
+
+Utils = require('./Utils');
+
+Inline = require('./Inline');
+
+Dumper = (function() {
+ function Dumper() {}
+
+ Dumper.indentation = 4;
+
+ Dumper.prototype.dump = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ var isAHash, key, output, prefix, value, willBeInlined;
+ if (inline == null) {
+ inline = 0;
+ }
+ if (indent == null) {
+ indent = 0;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ output = '';
+ prefix = (indent ? Utils.strRepeat(' ', indent) : '');
+ if (inline <= 0 || typeof input !== 'object' || Utils.isEmpty(input)) {
+ output += prefix + Inline.dump(input, exceptionOnInvalidType, objectEncoder);
+ } else {
+ isAHash = !(input instanceof Array);
+ for (key in input) {
+ value = input[key];
+ willBeInlined = inline - 1 <= 0 || typeof value !== 'object' || Utils.isEmpty(value);
+ output += prefix + (isAHash ? Inline.dump(key, exceptionOnInvalidType, objectEncoder) + ':' : '-') + (willBeInlined ? ' ' : "\n") + this.dump(value, inline - 1, (willBeInlined ? 0 : indent + this.indentation), exceptionOnInvalidType, objectEncoder) + (willBeInlined ? "\n" : '');
+ }
+ }
+ return output;
+ };
+
+ return Dumper;
+
+})();
+
+module.exports = Dumper;
+
+
+
+},{"./Inline":5,"./Utils":9}],2:[function(require,module,exports){
+var Escaper, Pattern;
+
+Pattern = require('./Pattern');
+
+Escaper = (function() {
+ var ch;
+
+ function Escaper() {}
+
+ Escaper.LIST_ESCAPEES = ['\\\\', '\\"', '"', "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", (ch = String.fromCharCode)(0x0085), ch(0x00A0), ch(0x2028), ch(0x2029)];
+
+ Escaper.LIST_ESCAPED = ['\\"', '\\\\', '\\"', "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f", "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17", "\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", "\\x1f", "\\N", "\\_", "\\L", "\\P"];
+
+ Escaper.MAPPING_ESCAPEES_TO_ESCAPED = (function() {
+ var i, mapping, _i, _ref;
+ mapping = {};
+ for (i = _i = 0, _ref = Escaper.LIST_ESCAPEES.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
+ mapping[Escaper.LIST_ESCAPEES[i]] = Escaper.LIST_ESCAPED[i];
+ }
+ return mapping;
+ })();
+
+ Escaper.PATTERN_CHARACTERS_TO_ESCAPE = new Pattern('[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9');
+
+ Escaper.PATTERN_MAPPING_ESCAPEES = new Pattern(Escaper.LIST_ESCAPEES.join('|'));
+
+ Escaper.PATTERN_SINGLE_QUOTING = new Pattern('[\\s\'":{}[\\],&*#?]|^[-?|<>=!%@`]');
+
+ Escaper.requiresDoubleQuoting = function(value) {
+ return this.PATTERN_CHARACTERS_TO_ESCAPE.test(value);
+ };
+
+ Escaper.escapeWithDoubleQuotes = function(value) {
+ return this.PATTERN_MAPPING_ESCAPEES.replace(value, (function(_this) {
+ return function(str) {
+ return _this.MAPPING_ESCAPEES_TO_ESCAPED[str];
+ };
+ })(this));
+ };
+
+ Escaper.requiresSingleQuoting = function(value) {
+ return this.PATTERN_SINGLE_QUOTING.test(value);
+ };
+
+ Escaper.escapeWithSingleQuotes = function(value) {
+ return "'" + value.replace('\'', '\'\'') + "'";
+ };
+
+ return Escaper;
+
+})();
+
+module.exports = Escaper;
+
+
+
+},{"./Pattern":7}],3:[function(require,module,exports){
+var DumpException,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+DumpException = (function(_super) {
+ __extends(DumpException, _super);
+
+ function DumpException(message, parsedLine, snippet) {
+ this.message = message;
+ this.parsedLine = parsedLine;
+ this.snippet = snippet;
+ }
+
+ DumpException.prototype.toString = function() {
+ if ((this.parsedLine != null) && (this.snippet != null)) {
+ return '<DumpException> ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')';
+ } else {
+ return '<DumpException> ' + this.message;
+ }
+ };
+
+ return DumpException;
+
+})(Error);
+
+module.exports = DumpException;
+
+
+
+},{}],4:[function(require,module,exports){
+var ParseException,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ParseException = (function(_super) {
+ __extends(ParseException, _super);
+
+ function ParseException(message, parsedLine, snippet) {
+ this.message = message;
+ this.parsedLine = parsedLine;
+ this.snippet = snippet;
+ }
+
+ ParseException.prototype.toString = function() {
+ if ((this.parsedLine != null) && (this.snippet != null)) {
+ return '<ParseException> ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')';
+ } else {
+ return '<ParseException> ' + this.message;
+ }
+ };
+
+ return ParseException;
+
+})(Error);
+
+module.exports = ParseException;
+
+
+
+},{}],5:[function(require,module,exports){
+var DumpException, Escaper, Inline, ParseException, Pattern, Unescaper, Utils,
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
+
+Pattern = require('./Pattern');
+
+Unescaper = require('./Unescaper');
+
+Escaper = require('./Escaper');
+
+Utils = require('./Utils');
+
+ParseException = require('./Exception/ParseException');
+
+DumpException = require('./Exception/DumpException');
+
+Inline = (function() {
+ function Inline() {}
+
+ Inline.REGEX_QUOTED_STRING = '(?:"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\']*(?:\'\'[^\']*)*)\')';
+
+ Inline.PATTERN_TRAILING_COMMENTS = new Pattern('^\\s*#.*$');
+
+ Inline.PATTERN_QUOTED_SCALAR = new Pattern('^' + Inline.REGEX_QUOTED_STRING);
+
+ Inline.PATTERN_THOUSAND_NUMERIC_SCALAR = new Pattern('^(-|\\+)?[0-9,]+(\\.[0-9]+)?$');
+
+ Inline.PATTERN_SCALAR_BY_DELIMITERS = {};
+
+ Inline.settings = {};
+
+ Inline.configure = function(exceptionOnInvalidType, objectDecoder) {
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = null;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.settings.exceptionOnInvalidType = exceptionOnInvalidType;
+ this.settings.objectDecoder = objectDecoder;
+ };
+
+ Inline.parse = function(value, exceptionOnInvalidType, objectDecoder) {
+ var context, result;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.settings.exceptionOnInvalidType = exceptionOnInvalidType;
+ this.settings.objectDecoder = objectDecoder;
+ if (value == null) {
+ return '';
+ }
+ value = Utils.trim(value);
+ if (0 === value.length) {
+ return '';
+ }
+ context = {
+ exceptionOnInvalidType: exceptionOnInvalidType,
+ objectDecoder: objectDecoder,
+ i: 0
+ };
+ switch (value.charAt(0)) {
+ case '[':
+ result = this.parseSequence(value, context);
+ ++context.i;
+ break;
+ case '{':
+ result = this.parseMapping(value, context);
+ ++context.i;
+ break;
+ default:
+ result = this.parseScalar(value, null, ['"', "'"], context);
+ }
+ if (this.PATTERN_TRAILING_COMMENTS.replace(value.slice(context.i), '') !== '') {
+ throw new ParseException('Unexpected characters near "' + value.slice(context.i) + '".');
+ }
+ return result;
+ };
+
+ Inline.dump = function(value, exceptionOnInvalidType, objectEncoder) {
+ var result, type, _ref;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ if (value == null) {
+ return 'null';
+ }
+ type = typeof value;
+ if (type === 'object') {
+ if (value instanceof Date) {
+ return value.toISOString();
+ } else if (objectEncoder != null) {
+ result = objectEncoder(value);
+ if (typeof result === 'string' || (result != null)) {
+ return result;
+ }
+ }
+ return this.dumpObject(value);
+ }
+ if (type === 'boolean') {
+ return (value ? 'true' : 'false');
+ }
+ if (Utils.isDigits(value)) {
+ return (type === 'string' ? "'" + value + "'" : '' + parseInt(value));
+ }
+ if (Utils.isNumeric(value)) {
+ return (type === 'string' ? "'" + value + "'" : '' + parseFloat(value));
+ }
+ if (type === 'number') {
+ return (value === Infinity ? '.Inf' : (value === -Infinity ? '-.Inf' : (isNaN(value) ? '.NaN' : value)));
+ }
+ if (Escaper.requiresDoubleQuoting(value)) {
+ return Escaper.escapeWithDoubleQuotes(value);
+ }
+ if (Escaper.requiresSingleQuoting(value)) {
+ return yaml.escapeWithSingleQuotes(value);
+ }
+ if ('' === value) {
+ return '""';
+ }
+ if (Utils.PATTERN_DATE.test(value)) {
+ return "'" + value + "'";
+ }
+ if ((_ref = value.toLowerCase()) === 'null' || _ref === '~' || _ref === 'true' || _ref === 'false') {
+ return "'" + value + "'";
+ }
+ return value;
+ };
+
+ Inline.dumpObject = function(value, exceptionOnInvalidType, objectSupport) {
+ var key, output, val, _i, _len;
+ if (objectSupport == null) {
+ objectSupport = null;
+ }
+ if (value instanceof Array) {
+ output = [];
+ for (_i = 0, _len = value.length; _i < _len; _i++) {
+ val = value[_i];
+ output.push(this.dump(val));
+ }
+ return '[' + output.join(', ') + ']';
+ } else {
+ output = [];
+ for (key in value) {
+ val = value[key];
+ output.push(this.dump(key) + ': ' + this.dump(val));
+ }
+ return '{' + output.join(', ') + '}';
+ }
+ };
+
+ Inline.parseScalar = function(scalar, delimiters, stringDelimiters, context, evaluate) {
+ var i, joinedDelimiters, match, output, pattern, strpos, tmp, _ref, _ref1;
+ if (delimiters == null) {
+ delimiters = null;
+ }
+ if (stringDelimiters == null) {
+ stringDelimiters = ['"', "'"];
+ }
+ if (context == null) {
+ context = null;
+ }
+ if (evaluate == null) {
+ evaluate = true;
+ }
+ if (context == null) {
+ context = {
+ exceptionOnInvalidType: this.settings.exceptionOnInvalidType,
+ objectDecoder: this.settings.objectDecoder,
+ i: 0
+ };
+ }
+ i = context.i;
+ if (_ref = scalar.charAt(i), __indexOf.call(stringDelimiters, _ref) >= 0) {
+ output = this.parseQuotedScalar(scalar, context);
+ i = context.i;
+ if (delimiters != null) {
+ tmp = Utils.ltrim(scalar.slice(i), ' ');
+ if (!(_ref1 = tmp.charAt(0), __indexOf.call(delimiters, _ref1) >= 0)) {
+ throw new ParseException('Unexpected characters (' + scalar.slice(i) + ').');
+ }
+ }
+ } else {
+ if (!delimiters) {
+ output = scalar.slice(i);
+ i += output.length;
+ strpos = output.indexOf(' #');
+ if (strpos !== -1) {
+ output = Utils.rtrim(output.slice(0, strpos));
+ }
+ } else {
+ joinedDelimiters = delimiters.join('|');
+ pattern = this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters];
+ if (pattern == null) {
+ pattern = new Pattern('^(.+?)(' + joinedDelimiters + ')');
+ this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters] = pattern;
+ }
+ if (match = pattern.exec(scalar.slice(i))) {
+ output = match[1];
+ i += output.length;
+ } else {
+ throw new ParseException('Malformed inline YAML string (' + scalar + ').');
+ }
+ }
+ if (evaluate) {
+ output = this.evaluateScalar(output, context);
+ }
+ }
+ context.i = i;
+ return output;
+ };
+
+ Inline.parseQuotedScalar = function(scalar, context) {
+ var i, match, output;
+ i = context.i;
+ if (!(match = this.PATTERN_QUOTED_SCALAR.exec(scalar.slice(i)))) {
+ throw new ParseException('Malformed inline YAML string (' + scalar.slice(i) + ').');
+ }
+ output = match[0].substr(1, match[0].length - 2);
+ if ('"' === scalar.charAt(i)) {
+ output = Unescaper.unescapeDoubleQuotedString(output);
+ } else {
+ output = Unescaper.unescapeSingleQuotedString(output);
+ }
+ i += match[0].length;
+ context.i = i;
+ return output;
+ };
+
+ Inline.parseSequence = function(sequence, context) {
+ var e, i, isQuoted, len, output, value, _ref;
+ output = [];
+ len = sequence.length;
+ i = context.i;
+ i += 1;
+ while (i < len) {
+ context.i = i;
+ switch (sequence.charAt(i)) {
+ case '[':
+ output.push(this.parseSequence(sequence, context));
+ i = context.i;
+ break;
+ case '{':
+ output.push(this.parseMapping(sequence, context));
+ i = context.i;
+ break;
+ case ']':
+ return output;
+ case ',':
+ case ' ':
+ case "\n":
+ break;
+ default:
+ isQuoted = ((_ref = sequence.charAt(i)) === '"' || _ref === "'");
+ value = this.parseScalar(sequence, [',', ']'], ['"', "'"], context);
+ i = context.i;
+ if (!isQuoted && typeof value === 'string' && (value.indexOf(': ') !== -1 || value.indexOf(":\n") !== -1)) {
+ try {
+ value = this.parseMapping('{' + value + '}');
+ } catch (_error) {
+ e = _error;
+ }
+ }
+ output.push(value);
+ --i;
+ }
+ ++i;
+ }
+ throw new ParseException('Malformed inline YAML string ' + sequence);
+ };
+
+ Inline.parseMapping = function(mapping, context) {
+ var $value, done, i, key, len, output, shouldContinueWhileLoop, value;
+ output = {};
+ len = mapping.length;
+ i = context.i;
+ i += 1;
+ shouldContinueWhileLoop = false;
+ while (i < len) {
+ context.i = i;
+ switch (mapping.charAt(i)) {
+ case ' ':
+ case ',':
+ case "\n":
+ ++i;
+ context.i = i;
+ shouldContinueWhileLoop = true;
+ break;
+ case '}':
+ return output;
+ }
+ if (shouldContinueWhileLoop) {
+ shouldContinueWhileLoop = false;
+ continue;
+ }
+ key = this.parseScalar(mapping, [':', ' ', "\n"], ['"', "'"], context, false);
+ i = context.i;
+ done = false;
+ while (i < len) {
+ context.i = i;
+ switch (mapping.charAt(i)) {
+ case '[':
+ value = this.parseSequence(mapping, context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ break;
+ case '{':
+ $value = this.parseMapping(mapping, context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ break;
+ case ':':
+ case ' ':
+ case "\n":
+ break;
+ default:
+ value = this.parseScalar(mapping, [',', '}'], ['"', "'"], context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ --i;
+ }
+ ++i;
+ if (done) {
+ break;
+ }
+ }
+ }
+ throw new ParseException('Malformed inline YAML string ' + mapping);
+ };
+
+ Inline.evaluateScalar = function(scalar, context) {
+ var cast, exceptionOnInvalidType, firstChar, firstSpace, firstWord, objectDecoder, raw, scalarLower, subValue, trimmedScalar;
+ scalar = Utils.trim(scalar);
+ scalarLower = scalar.toLowerCase();
+ switch (scalarLower) {
+ case 'null':
+ case '':
+ case '~':
+ return null;
+ case 'true':
+ return true;
+ case 'false':
+ return false;
+ case '.inf':
+ return Infinity;
+ case '.nan':
+ return NaN;
+ case '-.inf':
+ return Infinity;
+ default:
+ firstChar = scalarLower.charAt(0);
+ switch (firstChar) {
+ case '!':
+ firstSpace = scalar.indexOf(' ');
+ if (firstSpace === -1) {
+ firstWord = scalarLower;
+ } else {
+ firstWord = scalarLower.slice(0, firstSpace);
+ }
+ switch (firstWord) {
+ case '!':
+ if (firstSpace !== -1) {
+ return parseInt(this.parseScalar(scalar.slice(2)));
+ }
+ return null;
+ case '!str':
+ return Utils.ltrim(scalar.slice(4));
+ case '!!str':
+ return Utils.ltrim(scalar.slice(5));
+ case '!!int':
+ return parseInt(this.parseScalar(scalar.slice(5)));
+ case '!!bool':
+ return Utils.parseBoolean(this.parseScalar(scalar.slice(6)), false);
+ case '!!float':
+ return parseFloat(this.parseScalar(scalar.slice(7)));
+ case '!!timestamp':
+ return Utils.stringToDate(Utils.ltrim(scalar.slice(11)));
+ default:
+ if (context == null) {
+ context = {
+ exceptionOnInvalidType: this.settings.exceptionOnInvalidType,
+ objectDecoder: this.settings.objectDecoder,
+ i: 0
+ };
+ }
+ objectDecoder = context.objectDecoder, exceptionOnInvalidType = context.exceptionOnInvalidType;
+ if (objectDecoder) {
+ trimmedScalar = Utils.rtrim(scalar);
+ firstSpace = trimmedScalar.indexOf(' ');
+ if (firstSpace === -1) {
+ return objectDecoder(trimmedScalar, null);
+ } else {
+ subValue = Utils.ltrim(trimmedScalar.slice(firstSpace + 1));
+ if (!(subValue.length > 0)) {
+ subValue = null;
+ }
+ return objectDecoder(trimmedScalar.slice(0, firstSpace), subValue);
+ }
+ }
+ if (exceptionOnInvalidType) {
+ throw new ParseException('Custom object support when parsing a YAML file has been disabled.');
+ }
+ return null;
+ }
+ break;
+ case '0':
+ if ('0x' === scalar.slice(0, 2)) {
+ return Utils.hexDec(scalar);
+ } else if (Utils.isDigits(scalar)) {
+ return Utils.octDec(scalar);
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ } else {
+ return scalar;
+ }
+ break;
+ case '+':
+ if (Utils.isDigits(scalar)) {
+ raw = scalar;
+ cast = parseInt(raw);
+ if (raw === '' + cast) {
+ return cast;
+ } else {
+ return raw;
+ }
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ case '-':
+ if (Utils.isDigits(scalar.slice(1))) {
+ if ('0' === scalar.charAt(1)) {
+ return -Utils.octDec(scalar.slice(1));
+ } else {
+ raw = scalar.slice(1);
+ cast = parseInt(raw);
+ if (raw === '' + cast) {
+ return -cast;
+ } else {
+ return -raw;
+ }
+ }
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ default:
+ if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ }
+ }
+ };
+
+ return Inline;
+
+})();
+
+module.exports = Inline;
+
+
+
+},{"./Escaper":2,"./Exception/DumpException":3,"./Exception/ParseException":4,"./Pattern":7,"./Unescaper":8,"./Utils":9}],6:[function(require,module,exports){
+var Inline, ParseException, Parser, Pattern, Utils;
+
+Inline = require('./Inline');
+
+Pattern = require('./Pattern');
+
+Utils = require('./Utils');
+
+ParseException = require('./Exception/ParseException');
+
+Parser = (function() {
+ Parser.prototype.PATTERN_FOLDED_SCALAR_ALL = new Pattern('^(?:(?<type>![^\\|>]*)\\s+)?(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$');
+
+ Parser.prototype.PATTERN_FOLDED_SCALAR_END = new Pattern('(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$');
+
+ Parser.prototype.PATTERN_SEQUENCE_ITEM = new Pattern('^\\-((?<leadspaces>\\s+)(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_ANCHOR_VALUE = new Pattern('^&(?<ref>[^ ]+) *(?<value>.*)');
+
+ Parser.prototype.PATTERN_COMPACT_NOTATION = new Pattern('^(?<key>' + Inline.REGEX_QUOTED_STRING + '|[^ \'"\\{\\[].*?) *\\:(\\s+(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_MAPPING_ITEM = new Pattern('^(?<key>' + Inline.REGEX_QUOTED_STRING + '|[^ \'"\\[\\{].*?) *\\:(\\s+(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_DECIMAL = new Pattern('\\d+');
+
+ Parser.prototype.PATTERN_INDENT_SPACES = new Pattern('^ +');
+
+ Parser.prototype.PATTERN_TRAILING_LINES = new Pattern('(\n*)$');
+
+ Parser.prototype.PATTERN_YAML_HEADER = new Pattern('^\\%YAML[: ][\\d\\.]+.*\n');
+
+ Parser.prototype.PATTERN_LEADING_COMMENTS = new Pattern('^(\\#.*?\n)+');
+
+ Parser.prototype.PATTERN_DOCUMENT_MARKER_START = new Pattern('^\\-\\-\\-.*?\n');
+
+ Parser.prototype.PATTERN_DOCUMENT_MARKER_END = new Pattern('^\\.\\.\\.\\s*$');
+
+ Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION = {};
+
+ Parser.prototype.CONTEXT_NONE = 0;
+
+ Parser.prototype.CONTEXT_SEQUENCE = 1;
+
+ Parser.prototype.CONTEXT_MAPPING = 2;
+
+ function Parser(offset) {
+ this.offset = offset != null ? offset : 0;
+ this.lines = [];
+ this.currentLineNb = -1;
+ this.currentLine = '';
+ this.refs = {};
+ }
+
+ Parser.prototype.parse = function(value, exceptionOnInvalidType, objectDecoder) {
+ var alias, allowOverwrite, block, c, context, data, e, first, i, indent, isRef, key, lastKey, lineCount, matches, mergeNode, parsed, parsedItem, parser, refName, refValue, val, values, _i, _j, _k, _l, _len, _len1, _len2, _len3, _name, _name1, _ref, _ref1, _ref2;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.currentLineNb = -1;
+ this.currentLine = '';
+ this.lines = this.cleanup(value).split("\n");
+ data = null;
+ context = this.CONTEXT_NONE;
+ allowOverwrite = false;
+ while (this.moveToNextLine()) {
+ if (this.isCurrentLineEmpty()) {
+ continue;
+ }
+ if ("\t" === this.currentLine[0]) {
+ throw new ParseException('A YAML file cannot contain tabs as indentation.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ isRef = mergeNode = false;
+ if (values = this.PATTERN_SEQUENCE_ITEM.exec(this.currentLine)) {
+ if (this.CONTEXT_MAPPING === context) {
+ throw new ParseException('You cannot define a sequence item when in a mapping');
+ }
+ context = this.CONTEXT_SEQUENCE;
+ if (data == null) {
+ data = [];
+ }
+ if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) {
+ isRef = matches.ref;
+ values.value = matches.value;
+ }
+ if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf('#') === 0) {
+ if (this.currentLineNb < this.lines.length - 1 && !this.isNextLineUnIndentedCollection()) {
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ data.push(parser.parse(this.getNextEmbedBlock(null, true), exceptionOnInvalidType, objectDecoder));
+ } else {
+ data.push(null);
+ }
+ } else {
+ if (((_ref = values.leadspaces) != null ? _ref.length : void 0) && (matches = this.PATTERN_COMPACT_NOTATION.exec(values.value))) {
+ c = this.getRealCurrentLineNb();
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ block = values.value;
+ indent = this.getCurrentLineIndentation();
+ if (this.isNextLineIndented(false)) {
+ block += "\n" + this.getNextEmbedBlock(indent + values.leadspaces.length + 1, true);
+ }
+ data.push(parser.parse(block, exceptionOnInvalidType, objectDecoder));
+ } else {
+ data.push(this.parseValue(values.value, exceptionOnInvalidType, objectDecoder));
+ }
+ }
+ } else if ((values = this.PATTERN_MAPPING_ITEM.exec(this.currentLine)) && values.key.indexOf(' #') === -1) {
+ if (this.CONTEXT_SEQUENCE === context) {
+ throw new ParseException('You cannot define a mapping item when in a sequence');
+ }
+ context = this.CONTEXT_MAPPING;
+ if (data == null) {
+ data = {};
+ }
+ Inline.configure(exceptionOnInvalidType, objectDecoder);
+ try {
+ key = Inline.parseScalar(values.key);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ if ('<<' === key) {
+ mergeNode = true;
+ allowOverwrite = true;
+ if (((_ref1 = values.value) != null ? _ref1.indexOf('*') : void 0) === 0) {
+ refName = values.value.slice(1);
+ if (this.refs[refName] == null) {
+ throw new ParseException('Reference "' + refName + '" does not exist.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ refValue = this.refs[refName];
+ if (typeof refValue !== 'object') {
+ throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (refValue instanceof Array) {
+ for (i = _i = 0, _len = refValue.length; _i < _len; i = ++_i) {
+ value = refValue[i];
+ if (data[_name = '' + i] == null) {
+ data[_name] = value;
+ }
+ }
+ } else {
+ for (key in refValue) {
+ value = refValue[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ } else {
+ if (values.value !== '') {
+ value = values.value;
+ } else {
+ value = this.getNextEmbedBlock();
+ }
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ parsed = parser.parse(value, exceptionOnInvalidType);
+ if (typeof parsed !== 'object') {
+ throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (parsed instanceof Array) {
+ for (_j = 0, _len1 = parsed.length; _j < _len1; _j++) {
+ parsedItem = parsed[_j];
+ if (typeof parsedItem !== 'object') {
+ throw new ParseException('Merge items must be objects.', this.getRealCurrentLineNb() + 1, parsedItem);
+ }
+ if (parsedItem instanceof Array) {
+ for (i = _k = 0, _len2 = parsedItem.length; _k < _len2; i = ++_k) {
+ value = parsedItem[i];
+ if (data[_name1 = '' + i] == null) {
+ data[_name1] = value;
+ }
+ }
+ } else {
+ for (key in parsedItem) {
+ value = parsedItem[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ }
+ } else {
+ for (key in parsed) {
+ value = parsed[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ }
+ } else if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) {
+ isRef = matches.ref;
+ values.value = matches.value;
+ }
+ if (mergeNode) {
+
+ } else if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf('#') === 0) {
+ if (!(this.isNextLineIndented()) && !(this.isNextLineUnIndentedCollection())) {
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = null;
+ }
+ } else {
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ val = parser.parse(this.getNextEmbedBlock(), exceptionOnInvalidType, objectDecoder);
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = val;
+ }
+ }
+ } else {
+ val = this.parseValue(values.value, exceptionOnInvalidType, objectDecoder);
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = val;
+ }
+ }
+ } else {
+ lineCount = this.lines.length;
+ if (1 === lineCount || (2 === lineCount && Utils.isEmpty(this.lines[1]))) {
+ try {
+ value = Inline.parse(this.lines[0], exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ if (typeof value === 'object') {
+ if (value instanceof Array) {
+ first = value[0];
+ } else {
+ for (key in value) {
+ first = value[key];
+ break;
+ }
+ }
+ if (typeof first === 'string' && first.indexOf('*') === 0) {
+ data = [];
+ for (_l = 0, _len3 = value.length; _l < _len3; _l++) {
+ alias = value[_l];
+ data.push(this.refs[alias.slice(1)]);
+ }
+ value = data;
+ }
+ }
+ return value;
+ } else if ((_ref2 = Utils.ltrim(value).charAt(0)) === '[' || _ref2 === '{') {
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ }
+ throw new ParseException('Unable to parse.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (isRef) {
+ if (data instanceof Array) {
+ this.refs[isRef] = data[data.length - 1];
+ } else {
+ lastKey = null;
+ for (key in data) {
+ lastKey = key;
+ }
+ this.refs[isRef] = data[lastKey];
+ }
+ }
+ }
+ if (Utils.isEmpty(data)) {
+ return null;
+ } else {
+ return data;
+ }
+ };
+
+ Parser.prototype.getRealCurrentLineNb = function() {
+ return this.currentLineNb + this.offset;
+ };
+
+ Parser.prototype.getCurrentLineIndentation = function() {
+ return this.currentLine.length - Utils.ltrim(this.currentLine, ' ').length;
+ };
+
+ Parser.prototype.getNextEmbedBlock = function(indentation, includeUnindentedCollection) {
+ var data, indent, isItUnindentedCollection, newIndent, removeComments, removeCommentsPattern, unindentedEmbedBlock;
+ if (indentation == null) {
+ indentation = null;
+ }
+ if (includeUnindentedCollection == null) {
+ includeUnindentedCollection = false;
+ }
+ this.moveToNextLine();
+ if (indentation == null) {
+ newIndent = this.getCurrentLineIndentation();
+ unindentedEmbedBlock = this.isStringUnIndentedCollectionItem(this.currentLine);
+ if (!(this.isCurrentLineEmpty()) && 0 === newIndent && !unindentedEmbedBlock) {
+ throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ } else {
+ newIndent = indentation;
+ }
+ data = [this.currentLine.slice(newIndent)];
+ if (!includeUnindentedCollection) {
+ isItUnindentedCollection = this.isStringUnIndentedCollectionItem(this.currentLine);
+ }
+ removeCommentsPattern = this.PATTERN_FOLDED_SCALAR_END;
+ removeComments = !removeCommentsPattern.test(this.currentLine);
+ while (this.moveToNextLine()) {
+ indent = this.getCurrentLineIndentation();
+ if (indent === newIndent) {
+ removeComments = !removeCommentsPattern.test(this.currentLine);
+ }
+ if (isItUnindentedCollection && !this.isStringUnIndentedCollectionItem(this.currentLine) && indent === newIndent) {
+ this.moveToPreviousLine();
+ break;
+ }
+ if (this.isCurrentLineBlank()) {
+ data.push(this.currentLine.slice(newIndent));
+ continue;
+ }
+ if (removeComments && this.isCurrentLineComment()) {
+ if (indent === newIndent) {
+ continue;
+ }
+ }
+ if (indent >= newIndent) {
+ data.push(this.currentLine.slice(newIndent));
+ } else if (0 === indent) {
+ this.moveToPreviousLine();
+ break;
+ } else {
+ throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ }
+ return data.join("\n");
+ };
+
+ Parser.prototype.moveToNextLine = function() {
+ if (this.currentLineNb >= this.lines.length - 1) {
+ return false;
+ }
+ this.currentLine = this.lines[++this.currentLineNb];
+ return true;
+ };
+
+ Parser.prototype.moveToPreviousLine = function() {
+ this.currentLine = this.lines[--this.currentLineNb];
+ };
+
+ Parser.prototype.parseValue = function(value, exceptionOnInvalidType, objectDecoder) {
+ var e, foldedIndent, matches, modifiers, pos, val, _ref, _ref1;
+ if (0 === value.indexOf('*')) {
+ pos = value.indexOf('#');
+ if (pos !== -1) {
+ value = value.substr(1, pos - 2);
+ } else {
+ value = value.slice(1);
+ }
+ if (this.refs[value] === void 0) {
+ throw new ParseException('Reference "' + value + '" does not exist.', this.currentLine);
+ }
+ return this.refs[value];
+ }
+ if (matches = this.PATTERN_FOLDED_SCALAR_ALL.exec(value)) {
+ modifiers = (_ref = matches.modifiers) != null ? _ref : '';
+ foldedIndent = Math.abs(parseInt(modifiers));
+ if (isNaN(foldedIndent)) {
+ foldedIndent = 0;
+ }
+ val = this.parseFoldedScalar(matches.separator, this.PATTERN_DECIMAL.replace(modifiers, ''), foldedIndent);
+ if (matches.type != null) {
+ Inline.configure(exceptionOnInvalidType, objectDecoder);
+ return Inline.parseScalar(matches.type + ' ' + val);
+ } else {
+ return val;
+ }
+ }
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ if (((_ref1 = value.charAt(0)) === '[' || _ref1 === '{') && e instanceof ParseException && this.isNextLineIndented()) {
+ value += "\n" + this.getNextEmbedBlock();
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ } else {
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ }
+ };
+
+ Parser.prototype.parseFoldedScalar = function(separator, indicator, indentation) {
+ var isCurrentLineBlank, line, matches, newText, notEOF, pattern, text, _i, _len, _ref;
+ if (indicator == null) {
+ indicator = '';
+ }
+ if (indentation == null) {
+ indentation = 0;
+ }
+ notEOF = this.moveToNextLine();
+ if (!notEOF) {
+ return '';
+ }
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ text = '';
+ while (notEOF && isCurrentLineBlank) {
+ if (notEOF = this.moveToNextLine()) {
+ text += "\n";
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ }
+ }
+ if (0 === indentation) {
+ if (matches = this.PATTERN_INDENT_SPACES.exec(this.currentLine)) {
+ indentation = matches[0].length;
+ }
+ }
+ if (indentation > 0) {
+ pattern = this.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation];
+ if (pattern == null) {
+ pattern = new Pattern('^ {' + indentation + '}(.*)$');
+ Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation] = pattern;
+ }
+ while (notEOF && (isCurrentLineBlank || (matches = pattern.exec(this.currentLine)))) {
+ if (isCurrentLineBlank) {
+ text += this.currentLine.slice(indentation);
+ } else {
+ text += matches[1];
+ }
+ if (notEOF = this.moveToNextLine()) {
+ text += "\n";
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ }
+ }
+ } else if (notEOF) {
+ text += "\n";
+ }
+ if (notEOF) {
+ this.moveToPreviousLine();
+ }
+ if ('>' === separator) {
+ newText = '';
+ _ref = text.split("\n");
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ line = _ref[_i];
+ if (line.length === 0 || line.charAt(0) === ' ') {
+ newText += line + "\n";
+ } else {
+ newText += line + ' ';
+ }
+ }
+ text = newText;
+ }
+ text = Utils.rtrim(text);
+ if ('' === indicator) {
+ text = this.PATTERN_TRAILING_LINES.replace(text, "\n");
+ } else if ('-' === indicator) {
+ text = this.PATTERN_TRAILING_LINES.replace(text, '');
+ }
+ return text;
+ };
+
+ Parser.prototype.isNextLineIndented = function(ignoreComments) {
+ var EOF, currentIndentation, ret;
+ if (ignoreComments == null) {
+ ignoreComments = true;
+ }
+ currentIndentation = this.getCurrentLineIndentation();
+ EOF = !this.moveToNextLine();
+ if (ignoreComments) {
+ while (!EOF && this.isCurrentLineEmpty()) {
+ EOF = !this.moveToNextLine();
+ }
+ } else {
+ while (!EOF && this.isCurrentLineBlank()) {
+ EOF = !this.moveToNextLine();
+ }
+ }
+ if (EOF) {
+ return false;
+ }
+ ret = false;
+ if (this.getCurrentLineIndentation() > currentIndentation) {
+ ret = true;
+ }
+ this.moveToPreviousLine();
+ return ret;
+ };
+
+ Parser.prototype.isCurrentLineEmpty = function() {
+ var trimmedLine;
+ trimmedLine = Utils.trim(this.currentLine, ' ');
+ return trimmedLine.length === 0 || trimmedLine.charAt(0) === '#';
+ };
+
+ Parser.prototype.isCurrentLineBlank = function() {
+ return '' === Utils.trim(this.currentLine, ' ');
+ };
+
+ Parser.prototype.isCurrentLineComment = function() {
+ var ltrimmedLine;
+ ltrimmedLine = Utils.ltrim(this.currentLine, ' ');
+ return ltrimmedLine.charAt(0) === '#';
+ };
+
+ Parser.prototype.cleanup = function(value) {
+ var count, trimmedValue, _ref, _ref1, _ref2;
+ value = value.replace("\r\n", "\n").replace("\r", "\n");
+ count = 0;
+ _ref = this.PATTERN_YAML_HEADER.replaceAll(value, ''), value = _ref[0], count = _ref[1];
+ this.offset += count;
+ _ref1 = this.PATTERN_LEADING_COMMENTS.replaceAll(value, '', 1), trimmedValue = _ref1[0], count = _ref1[1];
+ if (count === 1) {
+ this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n");
+ value = trimmedValue;
+ }
+ _ref2 = this.PATTERN_DOCUMENT_MARKER_START.replaceAll(value, '', 1), trimmedValue = _ref2[0], count = _ref2[1];
+ if (count === 1) {
+ this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n");
+ value = trimmedValue;
+ value = this.PATTERN_DOCUMENT_MARKER_END.replace(value, '');
+ }
+ return value;
+ };
+
+ Parser.prototype.isNextLineUnIndentedCollection = function(currentIndentation) {
+ var notEOF, ret;
+ if (currentIndentation == null) {
+ currentIndentation = null;
+ }
+ if (currentIndentation == null) {
+ currentIndentation = this.getCurrentLineIndentation();
+ }
+ notEOF = this.moveToNextLine();
+ while (notEOF && this.isCurrentLineEmpty()) {
+ notEOF = this.moveToNextLine();
+ }
+ if (false === notEOF) {
+ return false;
+ }
+ ret = false;
+ if (this.getCurrentLineIndentation() === currentIndentation && this.isStringUnIndentedCollectionItem(this.currentLine)) {
+ ret = true;
+ }
+ this.moveToPreviousLine();
+ return ret;
+ };
+
+ Parser.prototype.isStringUnIndentedCollectionItem = function() {
+ return this.currentLine === '-' || this.currentLine.slice(0, 2) === '- ';
+ };
+
+ return Parser;
+
+})();
+
+module.exports = Parser;
+
+
+
+},{"./Exception/ParseException":4,"./Inline":5,"./Pattern":7,"./Utils":9}],7:[function(require,module,exports){
+var Pattern;
+
+Pattern = (function() {
+ Pattern.prototype.regex = null;
+
+ Pattern.prototype.rawRegex = null;
+
+ Pattern.prototype.cleanedRegex = null;
+
+ Pattern.prototype.mapping = null;
+
+ function Pattern(rawRegex, modifiers) {
+ var capturingBracketNumber, char, cleanedRegex, i, len, mapping, name, part, subChar;
+ if (modifiers == null) {
+ modifiers = '';
+ }
+ cleanedRegex = '';
+ len = rawRegex.length;
+ mapping = null;
+ capturingBracketNumber = 0;
+ i = 0;
+ while (i < len) {
+ char = rawRegex.charAt(i);
+ if (char === '\\') {
+ cleanedRegex += rawRegex.slice(i, +(i + 1) + 1 || 9e9);
+ i++;
+ } else if (char === '(') {
+ if (i < len - 2) {
+ part = rawRegex.slice(i, +(i + 2) + 1 || 9e9);
+ if (part === '(?:') {
+ i += 2;
+ cleanedRegex += part;
+ } else if (part === '(?<') {
+ capturingBracketNumber++;
+ i += 2;
+ name = '';
+ while (i + 1 < len) {
+ subChar = rawRegex.charAt(i + 1);
+ if (subChar === '>') {
+ cleanedRegex += '(';
+ i++;
+ if (name.length > 0) {
+ if (mapping == null) {
+ mapping = {};
+ }
+ mapping[name] = capturingBracketNumber;
+ }
+ break;
+ } else {
+ name += subChar;
+ }
+ i++;
+ }
+ } else {
+ cleanedRegex += char;
+ capturingBracketNumber++;
+ }
+ } else {
+ cleanedRegex += char;
+ }
+ } else {
+ cleanedRegex += char;
+ }
+ i++;
+ }
+ this.rawRegex = rawRegex;
+ this.cleanedRegex = cleanedRegex;
+ this.regex = new RegExp(this.cleanedRegex, 'g' + modifiers.replace('g', ''));
+ this.mapping = mapping;
+ }
+
+ Pattern.prototype.exec = function(str) {
+ var index, matches, name, _ref;
+ this.regex.lastIndex = 0;
+ matches = this.regex.exec(str);
+ if (matches == null) {
+ return null;
+ }
+ if (this.mapping != null) {
+ _ref = this.mapping;
+ for (name in _ref) {
+ index = _ref[name];
+ matches[name] = matches[index];
+ }
+ }
+ return matches;
+ };
+
+ Pattern.prototype.test = function(str) {
+ this.regex.lastIndex = 0;
+ return this.regex.test(str);
+ };
+
+ Pattern.prototype.replace = function(str, replacement) {
+ this.regex.lastIndex = 0;
+ return str.replace(this.regex, replacement);
+ };
+
+ Pattern.prototype.replaceAll = function(str, replacement, limit) {
+ var count;
+ if (limit == null) {
+ limit = 0;
+ }
+ this.regex.lastIndex = 0;
+ count = 0;
+ while (this.regex.test(str) && (limit === 0 || count < limit)) {
+ this.regex.lastIndex = 0;
+ str = str.replace(this.regex, '');
+ count++;
+ }
+ return [str, count];
+ };
+
+ return Pattern;
+
+})();
+
+module.exports = Pattern;
+
+
+
+},{}],8:[function(require,module,exports){
+var Pattern, Unescaper, Utils;
+
+Utils = require('./Utils');
+
+Pattern = require('./Pattern');
+
+Unescaper = (function() {
+ function Unescaper() {}
+
+ Unescaper.PATTERN_ESCAPED_CHARACTER = new Pattern('\\\\([0abt\tnvfre "\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})');
+
+ Unescaper.unescapeSingleQuotedString = function(value) {
+ return value.replace('\'\'', '\'');
+ };
+
+ Unescaper.unescapeDoubleQuotedString = function(value) {
+ if (this._unescapeCallback == null) {
+ this._unescapeCallback = (function(_this) {
+ return function(str) {
+ return _this.unescapeCharacter(str);
+ };
+ })(this);
+ }
+ return this.PATTERN_ESCAPED_CHARACTER.replace(value, this._unescapeCallback);
+ };
+
+ Unescaper.unescapeCharacter = function(value) {
+ var ch;
+ ch = String.fromCharCode;
+ switch (value.charAt(1)) {
+ case '0':
+ return ch(0);
+ case 'a':
+ return ch(7);
+ case 'b':
+ return ch(8);
+ case 't':
+ return "\t";
+ case "\t":
+ return "\t";
+ case 'n':
+ return "\n";
+ case 'v':
+ return ch(11);
+ case 'f':
+ return ch(12);
+ case 'r':
+ return ch(13);
+ case 'e':
+ return ch(27);
+ case ' ':
+ return ' ';
+ case '"':
+ return '"';
+ case '/':
+ return '/';
+ case '\\':
+ return '\\';
+ case 'N':
+ return ch(0x0085);
+ case '_':
+ return ch(0x00A0);
+ case 'L':
+ return ch(0x2028);
+ case 'P':
+ return ch(0x2029);
+ case 'x':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 2)));
+ case 'u':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 4)));
+ case 'U':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 8)));
+ default:
+ return '';
+ }
+ };
+
+ return Unescaper;
+
+})();
+
+module.exports = Unescaper;
+
+
+
+},{"./Pattern":7,"./Utils":9}],9:[function(require,module,exports){
+var Pattern, Utils;
+
+Pattern = require('./Pattern');
+
+Utils = (function() {
+ function Utils() {}
+
+ Utils.REGEX_LEFT_TRIM_BY_CHAR = {};
+
+ Utils.REGEX_RIGHT_TRIM_BY_CHAR = {};
+
+ Utils.REGEX_SPACES = /\s+/g;
+
+ Utils.REGEX_DIGITS = /^\d+$/;
+
+ Utils.REGEX_OCTAL = /[^0-7]/gi;
+
+ Utils.REGEX_HEXADECIMAL = /[^a-f0-9]/gi;
+
+ Utils.PATTERN_DATE = new Pattern('^' + '(?<year>[0-9][0-9][0-9][0-9])' + '-(?<month>[0-9][0-9]?)' + '-(?<day>[0-9][0-9]?)' + '(?:(?:[Tt]|[ \t]+)' + '(?<hour>[0-9][0-9]?)' + ':(?<minute>[0-9][0-9])' + ':(?<second>[0-9][0-9])' + '(?:\.(?<fraction>[0-9]*))?' + '(?:[ \t]*(?<tz>Z|(?<tz_sign>[-+])(?<tz_hour>[0-9][0-9]?)' + '(?::(?<tz_minute>[0-9][0-9]))?))?)?' + '$', 'i');
+
+ Utils.LOCAL_TIMEZONE_OFFSET = new Date().getTimezoneOffset() * 60 * 1000;
+
+ Utils.trim = function(str, char) {
+ var regexLeft, regexRight;
+ if (char == null) {
+ char = '\\s';
+ }
+ return str.trim();
+ regexLeft = this.REGEX_LEFT_TRIM_BY_CHAR[char];
+ if (regexLeft == null) {
+ this.REGEX_LEFT_TRIM_BY_CHAR[char] = regexLeft = new RegExp('^' + char + '' + char + '*');
+ }
+ regexLeft.lastIndex = 0;
+ regexRight = this.REGEX_RIGHT_TRIM_BY_CHAR[char];
+ if (regexRight == null) {
+ this.REGEX_RIGHT_TRIM_BY_CHAR[char] = regexRight = new RegExp(char + '' + char + '*$');
+ }
+ regexRight.lastIndex = 0;
+ return str.replace(regexLeft, '').replace(regexRight, '');
+ };
+
+ Utils.ltrim = function(str, char) {
+ var regexLeft;
+ if (char == null) {
+ char = '\\s';
+ }
+ regexLeft = this.REGEX_LEFT_TRIM_BY_CHAR[char];
+ if (regexLeft == null) {
+ this.REGEX_LEFT_TRIM_BY_CHAR[char] = regexLeft = new RegExp('^' + char + '' + char + '*');
+ }
+ regexLeft.lastIndex = 0;
+ return str.replace(regexLeft, '');
+ };
+
+ Utils.rtrim = function(str, char) {
+ var regexRight;
+ if (char == null) {
+ char = '\\s';
+ }
+ regexRight = this.REGEX_RIGHT_TRIM_BY_CHAR[char];
+ if (regexRight == null) {
+ this.REGEX_RIGHT_TRIM_BY_CHAR[char] = regexRight = new RegExp(char + '' + char + '*$');
+ }
+ regexRight.lastIndex = 0;
+ return str.replace(regexRight, '');
+ };
+
+ Utils.isEmpty = function(value) {
+ return !value || value === '' || value === '0';
+ };
+
+ Utils.subStrCount = function(string, subString, start, length) {
+ var c, i, len, sublen, _i;
+ c = 0;
+ string = '' + string;
+ subString = '' + subString;
+ if (start != null) {
+ string = string.slice(start);
+ }
+ if (length != null) {
+ string = string.slice(0, length);
+ }
+ len = string.length;
+ sublen = subString.length;
+ for (i = _i = 0; 0 <= len ? _i < len : _i > len; i = 0 <= len ? ++_i : --_i) {
+ if (subString === string.slice(i, sublen)) {
+ c++;
+ i += sublen - 1;
+ }
+ }
+ return c;
+ };
+
+ Utils.isDigits = function(input) {
+ this.REGEX_DIGITS.lastIndex = 0;
+ return this.REGEX_DIGITS.test(input);
+ };
+
+ Utils.octDec = function(input) {
+ this.REGEX_OCTAL.lastIndex = 0;
+ return parseInt((input + '').replace(this.REGEX_OCTAL, ''), 8);
+ };
+
+ Utils.hexDec = function(input) {
+ this.REGEX_HEXADECIMAL.lastIndex = 0;
+ input = this.trim(input);
+ if ((input + '').slice(0, 2) === '0x') {
+ input = (input + '').slice(2);
+ }
+ return parseInt((input + '').replace(this.REGEX_HEXADECIMAL, ''), 16);
+ };
+
+ Utils.utf8chr = function(c) {
+ var ch;
+ ch = String.fromCharCode;
+ if (0x80 > (c %= 0x200000)) {
+ return ch(c);
+ }
+ if (0x800 > c) {
+ return ch(0xC0 | c >> 6) + ch(0x80 | c & 0x3F);
+ }
+ if (0x10000 > c) {
+ return ch(0xE0 | c >> 12) + ch(0x80 | c >> 6 & 0x3F) + ch(0x80 | c & 0x3F);
+ }
+ return ch(0xF0 | c >> 18) + ch(0x80 | c >> 12 & 0x3F) + ch(0x80 | c >> 6 & 0x3F) + ch(0x80 | c & 0x3F);
+ };
+
+ Utils.parseBoolean = function(input, strict) {
+ var lowerInput;
+ if (strict == null) {
+ strict = true;
+ }
+ if (typeof input === 'string') {
+ lowerInput = input.toLowerCase();
+ if (!strict) {
+ if (lowerInput === 'no') {
+ return false;
+ }
+ }
+ if (lowerInput === '0') {
+ return false;
+ }
+ if (lowerInput === 'false') {
+ return false;
+ }
+ if (lowerInput === '') {
+ return false;
+ }
+ return true;
+ }
+ return !!input;
+ };
+
+ Utils.isNumeric = function(input) {
+ this.REGEX_SPACES.lastIndex = 0;
+ return typeof input === 'number' || typeof input === 'string' && !isNaN(input) && input.replace(this.REGEX_SPACES, '') !== '';
+ };
+
+ Utils.stringToDate = function(str) {
+ var date, day, fraction, hour, info, minute, month, second, tz_hour, tz_minute, tz_offset, year;
+ if (!(str != null ? str.length : void 0)) {
+ return null;
+ }
+ info = this.PATTERN_DATE.exec(str);
+ if (!info) {
+ return null;
+ }
+ year = parseInt(info.year, 10);
+ month = parseInt(info.month, 10) - 1;
+ day = parseInt(info.day, 10);
+ if (info.hour == null) {
+ date = new Date(Date.UTC(year, month, day));
+ return date;
+ }
+ hour = parseInt(info.hour, 10);
+ minute = parseInt(info.minute, 10);
+ second = parseInt(info.second, 10);
+ if (info.fraction != null) {
+ fraction = info.fraction.slice(0, 3);
+ while (fraction.length < 3) {
+ fraction += '0';
+ }
+ fraction = parseInt(fraction, 10);
+ } else {
+ fraction = 0;
+ }
+ if (info.tz != null) {
+ tz_hour = parseInt(info.tz_hour, 10);
+ if (info.tz_minute != null) {
+ tz_minute = parseInt(info.tz_minute, 10);
+ } else {
+ tz_minute = 0;
+ }
+ tz_offset = (tz_hour * 60 + tz_minute) * 60000;
+ if ('-' === info.tz_sign) {
+ tz_offset *= -1;
+ }
+ }
+ date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
+ if (tz_offset) {
+ date.setTime(date.getTime() + tz_offset);
+ }
+ return date;
+ };
+
+ Utils.strRepeat = function(str, number) {
+ var i, res;
+ res = '';
+ i = 0;
+ while (i < number) {
+ res += str;
+ i++;
+ }
+ return res;
+ };
+
+ Utils.getStringFromFile = function(path, callback) {
+ var data, fs, name, req, xhr, _i, _len, _ref;
+ if (callback == null) {
+ callback = null;
+ }
+ xhr = null;
+ if (typeof window !== "undefined" && window !== null) {
+ if (window.XMLHttpRequest) {
+ xhr = new XMLHttpRequest();
+ } else if (window.ActiveXObject) {
+ _ref = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ name = _ref[_i];
+ try {
+ xhr = new ActiveXObject(name);
+ } catch (_error) {}
+ }
+ }
+ }
+ if (xhr != null) {
+ if (callback != null) {
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200 || xhr.status === 0) {
+ return callback(xhr.responseText);
+ } else {
+ return callback(null);
+ }
+ }
+ };
+ xhr.open('GET', path, true);
+ return xhr.send(null);
+ } else {
+ xhr.open('GET', path, false);
+ xhr.send(null);
+ if (xhr.status === 200 || xhr.status === 0) {
+ return xhr.responseText;
+ }
+ return null;
+ }
+ } else {
+ req = require;
+ fs = req('fs');
+ if (callback != null) {
+ return fs.readFile(path, function(err, data) {
+ if (err) {
+ return callback(null);
+ } else {
+ return callback(data);
+ }
+ });
+ } else {
+ data = fs.readFileSync(path);
+ if (data != null) {
+ return '' + data;
+ }
+ return null;
+ }
+ }
+ };
+
+ return Utils;
+
+})();
+
+module.exports = Utils;
+
+
+
+},{"./Pattern":7}],10:[function(require,module,exports){
+var Dumper, Parser, Utils, Yaml;
+
+Parser = require('./Parser');
+
+Dumper = require('./Dumper');
+
+Utils = require('./Utils');
+
+Yaml = (function() {
+ function Yaml() {}
+
+ Yaml.parse = function(input, exceptionOnInvalidType, objectDecoder) {
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ return new Parser().parse(input, exceptionOnInvalidType, objectDecoder);
+ };
+
+ Yaml.parseFile = function(path, callback, exceptionOnInvalidType, objectDecoder) {
+ var input;
+ if (callback == null) {
+ callback = null;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ if (callback != null) {
+ return Utils.getStringFromFile(path, (function(_this) {
+ return function(input) {
+ if (input != null) {
+ return _this.parse(input, exceptionOnInvalidType, objectDecoder);
+ }
+ return null;
+ };
+ })(this));
+ } else {
+ input = Utils.getStringFromFile(path);
+ if (input != null) {
+ return this.parse(input, exceptionOnInvalidType, objectDecoder);
+ }
+ return null;
+ }
+ };
+
+ Yaml.dump = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ var yaml;
+ if (inline == null) {
+ inline = 2;
+ }
+ if (indent == null) {
+ indent = 4;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ yaml = new Dumper();
+ yaml.indentation = indent;
+ return yaml.dump(input, inline, 0, exceptionOnInvalidType, objectEncoder);
+ };
+
+ Yaml.register = function() {
+ var require_handler;
+ require_handler = function(module, filename) {
+ return module.exports = YAML.parseFile(filename);
+ };
+ if ((typeof require !== "undefined" && require !== null ? require.extensions : void 0) != null) {
+ require.extensions['.yml'] = require_handler;
+ return require.extensions['.yaml'] = require_handler;
+ }
+ };
+
+ Yaml.prototype.stringify = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ return this.dump(input, inline, indent, exceptionOnInvalidType, objectEncoder);
+ };
+
+ Yaml.prototype.load = function(path, callback, exceptionOnInvalidType, objectDecoder) {
+ return this.parseFile(path, callback, exceptionOnInvalidType, objectDecoder);
+ };
+
+ return Yaml;
+
+})();
+
+if (typeof window !== "undefined" && window !== null) {
+ window.YAML = Yaml;
+}
+
+module.exports = Yaml;
+
+
+
+},{"./Dumper":1,"./Parser":6,"./Utils":9}]},{},[10]) \ No newline at end of file
diff --git a/bin/yaml.js b/dist/yaml.legacy.js
index 88c1a28..88c1a28 100644
--- a/bin/yaml.js
+++ b/dist/yaml.legacy.js
diff --git a/dist/yaml.min.js b/dist/yaml.min.js
new file mode 100644
index 0000000..3f89111
--- /dev/null
+++ b/dist/yaml.min.js
@@ -0,0 +1 @@
+(function e(e,t,n){function i(r,a){if(!t[r]){if(!e[r]){var u=typeof require=="function"&&require;if(!a&&u)return u(r,!0);if(s)return s(r,!0);throw new Error("Cannot find module '"+r+"'")}var l=t[r]={exports:{}};e[r][0].call(l.exports,function(t){var n=e[r][1][t];return i(n?n:t)},l,l.exports,e,e,t,n)}return t[r].exports}var s=typeof require=="function"&&require;for(var r=0;r<n.length;r++)i(n[r]);return i})({1:[function(n,r,s){var i,t,e;e=n("./Utils");t=n("./Inline");i=function(){function n(){}n.indentation=4;n.prototype.dump=function(n,l,i,r,s){var h,c,o,f,a,u;if(l==null){l=0}if(i==null){i=0}if(r==null){r=false}if(s==null){s=null}o="";f=i?e.strRepeat(" ",i):"";if(l<=0||typeof n!=="object"||e.isEmpty(n)){o+=f+t.dump(n,r,s)}else{h=!(n instanceof Array);for(c in n){a=n[c];u=l-1<=0||typeof a!=="object"||e.isEmpty(a);o+=f+(h?t.dump(c,r,s)+":":"-")+(u?" ":"\n")+this.dump(a,l-1,u?0:i+this.indentation,r,s)+(u?"\n":"")}}return o};return n}();r.exports=i},{"./Inline":5,"./Utils":9}],2:[function(n,i,r){var t,e;e=n("./Pattern");t=function(){var n;function t(){}t.LIST_ESCAPEES=["\\\\",'\\"','"',"\x00","","","","","","","","\b"," ","\n"," ","\f","\r","","","","","","","","","","","","","","","","","","",(n=String.fromCharCode)(133),n(160),n(8232),n(8233)];t.LIST_ESCAPED=['\\"',"\\\\",'\\"',"\\0","\\x01","\\x02","\\x03","\\x04","\\x05","\\x06","\\a","\\b","\\t","\\n","\\v","\\f","\\r","\\x0e","\\x0f","\\x10","\\x11","\\x12","\\x13","\\x14","\\x15","\\x16","\\x17","\\x18","\\x19","\\x1a","\\e","\\x1c","\\x1d","\\x1e","\\x1f","\\N","\\_","\\L","\\P"];t.MAPPING_ESCAPEES_TO_ESCAPED=function(){var i,r,e,n;r={};for(i=e=0,n=t.LIST_ESCAPEES.length;0<=n?e<n:e>n;i=0<=n?++e:--e){r[t.LIST_ESCAPEES[i]]=t.LIST_ESCAPED[i]}return r}();t.PATTERN_CHARACTERS_TO_ESCAPE=new e("[\\x00-\\x1f]|…| |
|
");t.PATTERN_MAPPING_ESCAPEES=new e(t.LIST_ESCAPEES.join("|"));t.PATTERN_SINGLE_QUOTING=new e("[\\s'\":{}[\\],&*#?]|^[-?|<>=!%@`]");t.requiresDoubleQuoting=function(e){return this.PATTERN_CHARACTERS_TO_ESCAPE.test(e)};t.escapeWithDoubleQuotes=function(e){return this.PATTERN_MAPPING_ESCAPEES.replace(e,function(e){return function(t){return e.MAPPING_ESCAPEES_TO_ESCAPED[t]}}(this))};t.requiresSingleQuoting=function(e){return this.PATTERN_SINGLE_QUOTING.test(e)};t.escapeWithSingleQuotes=function(e){return"'"+e.replace("'","''")+"'"};return t}();i.exports=t},{"./Pattern":7}],3:[function(r,t,s){var e,n={}.hasOwnProperty,i=function(e,t){for(var i in t){if(n.call(t,i))e[i]=t[i]}function r(){this.constructor=e}r.prototype=t.prototype;e.prototype=new r;e.__super__=t.prototype;return e};e=function(t){i(e,t);function e(e,t,n){this.message=e;this.parsedLine=t;this.snippet=n}e.prototype.toString=function(){if(this.parsedLine!=null&&this.snippet!=null){return"<DumpException> "+this.message+" (line "+this.parsedLine+": '"+this.snippet+"')"}else{return"<DumpException> "+this.message}};return e}(Error);t.exports=e},{}],4:[function(r,t,s){var e,n={}.hasOwnProperty,i=function(e,t){for(var i in t){if(n.call(t,i))e[i]=t[i]}function r(){this.constructor=e}r.prototype=t.prototype;e.prototype=new r;e.__super__=t.prototype;return e};e=function(t){i(e,t);function e(e,t,n){this.message=e;this.parsedLine=t;this.snippet=n}e.prototype.toString=function(){if(this.parsedLine!=null&&this.snippet!=null){return"<ParseException> "+this.message+" (line "+this.parsedLine+": '"+this.snippet+"')"}else{return"<ParseException> "+this.message}};return e}(Error);t.exports=e},{}],5:[function(n,a,f){var o,r,u,t,i,s,e,l=[].indexOf||function(t){for(var e=0,n=this.length;e<n;e++){if(e in this&&this[e]===t)return e}return-1};i=n("./Pattern");s=n("./Unescaper");r=n("./Escaper");e=n("./Utils");t=n("./Exception/ParseException");o=n("./Exception/DumpException");u=function(){function n(){}n.REGEX_QUOTED_STRING="(?:\"(?:[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|'(?:[^']*(?:''[^']*)*)')";n.PATTERN_TRAILING_COMMENTS=new i("^\\s*#.*$");n.PATTERN_QUOTED_SCALAR=new i("^"+n.REGEX_QUOTED_STRING);n.PATTERN_THOUSAND_NUMERIC_SCALAR=new i("^(-|\\+)?[0-9,]+(\\.[0-9]+)?$");n.PATTERN_SCALAR_BY_DELIMITERS={};n.settings={};n.configure=function(e,t){if(e==null){e=null}if(t==null){t=null}this.settings.exceptionOnInvalidType=e;this.settings.objectDecoder=t};n.parse=function(n,r,s){var i,l;if(r==null){r=false}if(s==null){s=null}this.settings.exceptionOnInvalidType=r;this.settings.objectDecoder=s;if(n==null){return""}n=e.trim(n);if(0===n.length){return""}i={exceptionOnInvalidType:r,objectDecoder:s,i:0};switch(n.charAt(0)){case"[":l=this.parseSequence(n,i);++i.i;break;case"{":l=this.parseMapping(n,i);++i.i;break;default:l=this.parseScalar(n,null,['"',"'"],i)}if(this.PATTERN_TRAILING_COMMENTS.replace(n.slice(i.i),"")!==""){throw new t('Unexpected characters near "'+n.slice(i.i)+'".')}return l};n.dump=function(t,u,i){var s,n,l;if(u==null){u=false}if(i==null){i=null}if(t==null){return"null"}n=typeof t;if(n==="object"){if(t instanceof Date){return t.toISOString()}else if(i!=null){s=i(t);if(typeof s==="string"||s!=null){return s}}return this.dumpObject(t)}if(n==="boolean"){return t?"true":"false"}if(e.isDigits(t)){return n==="string"?"'"+t+"'":""+parseInt(t)}if(e.isNumeric(t)){return n==="string"?"'"+t+"'":""+parseFloat(t)}if(n==="number"){return t===Infinity?".Inf":t===-Infinity?"-.Inf":isNaN(t)?".NaN":t}if(r.requiresDoubleQuoting(t)){return r.escapeWithDoubleQuotes(t)}if(r.requiresSingleQuoting(t)){return yaml.escapeWithSingleQuotes(t)}if(""===t){return'""'}if(e.PATTERN_DATE.test(t)){return"'"+t+"'"}if((l=t.toLowerCase())==="null"||l==="~"||l==="true"||l==="false"){return"'"+t+"'"}return t};n.dumpObject=function(t,u,s){var r,e,n,i,l;if(s==null){s=null}if(t instanceof Array){e=[];for(i=0,l=t.length;i<l;i++){n=t[i];e.push(this.dump(n))}return"["+e.join(", ")+"]"}else{e=[];for(r in t){n=t[r];e.push(this.dump(r)+": "+this.dump(n))}return"{"+e.join(", ")+"}"}};n.parseScalar=function(u,a,c,s,h){var r,f,_,n,o,p,T,A,E;if(a==null){a=null}if(c==null){c=['"',"'"]}if(s==null){s=null}if(h==null){h=true}if(s==null){s={exceptionOnInvalidType:this.settings.exceptionOnInvalidType,objectDecoder:this.settings.objectDecoder,i:0}}r=s.i;if(A=u.charAt(r),l.call(c,A)>=0){n=this.parseQuotedScalar(u,s);r=s.i;if(a!=null){T=e.ltrim(u.slice(r)," ");if(!(E=T.charAt(0),l.call(a,E)>=0)){throw new t("Unexpected characters ("+u.slice(r)+").")}}}else{if(!a){n=u.slice(r);r+=n.length;p=n.indexOf(" #");if(p!==-1){n=e.rtrim(n.slice(0,p))}}else{f=a.join("|");o=this.PATTERN_SCALAR_BY_DELIMITERS[f];if(o==null){o=new i("^(.+?)("+f+")");this.PATTERN_SCALAR_BY_DELIMITERS[f]=o}if(_=o.exec(u.slice(r))){n=_[1];r+=n.length}else{throw new t("Malformed inline YAML string ("+u+").")}}if(h){n=this.evaluateScalar(n,s)}}s.i=r;return n};n.parseQuotedScalar=function(r,l){var e,i,n;e=l.i;if(!(i=this.PATTERN_QUOTED_SCALAR.exec(r.slice(e)))){throw new t("Malformed inline YAML string ("+r.slice(e)+").")}n=i[0].substr(1,i[0].length-2);if('"'===r.charAt(e)){n=s.unescapeDoubleQuotedString(n)}else{n=s.unescapeSingleQuotedString(n)}e+=i[0].length;l.i=e;return n};n.parseSequence=function(i,n){var o,e,l,u,s,r,a;s=[];u=i.length;e=n.i;e+=1;while(e<u){n.i=e;switch(i.charAt(e)){case"[":s.push(this.parseSequence(i,n));e=n.i;break;case"{":s.push(this.parseMapping(i,n));e=n.i;break;case"]":return s;case",":case" ":case"\n":break;default:l=(a=i.charAt(e))==='"'||a==="'";r=this.parseScalar(i,[",","]"],['"',"'"],n);e=n.i;if(!l&&typeof r==="string"&&(r.indexOf(": ")!==-1||r.indexOf(":\n")!==-1)){try{r=this.parseMapping("{"+r+"}")}catch(f){o=f}}s.push(r);--e}++e}throw new t("Malformed inline YAML string "+i)};n.parseMapping=function(i,n){var f,l,e,s,o,r,a,u;r={};o=i.length;e=n.i;e+=1;a=false;while(e<o){n.i=e;switch(i.charAt(e)){case" ":case",":case"\n":++e;n.i=e;a=true;break;case"}":return r}if(a){a=false;continue}s=this.parseScalar(i,[":"," ","\n"],['"',"'"],n,false);e=n.i;l=false;while(e<o){n.i=e;switch(i.charAt(e)){case"[":u=this.parseSequence(i,n);e=n.i;if(r[s]===void 0){r[s]=u}l=true;break;case"{":f=this.parseMapping(i,n);e=n.i;if(r[s]===void 0){r[s]=u}l=true;break;case":":case" ":case"\n":break;default:u=this.parseScalar(i,[",","}"],['"',"'"],n);e=n.i;if(r[s]===void 0){r[s]=u}l=true;--e}++e;if(l){break}}}throw new t("Malformed inline YAML string "+i)};n.evaluateScalar=function(n,a){var s,p,h,r,c,o,i,u,f,l;n=e.trim(n);u=n.toLowerCase();switch(u){case"null":case"":case"~":return null;case"true":return true;case"false":return false;case".inf":return Infinity;case".nan":return NaN;case"-.inf":return Infinity;default:h=u.charAt(0);switch(h){case"!":r=n.indexOf(" ");if(r===-1){c=u}else{c=u.slice(0,r)}switch(c){case"!":if(r!==-1){return parseInt(this.parseScalar(n.slice(2)))}return null;case"!str":return e.ltrim(n.slice(4));case"!!str":return e.ltrim(n.slice(5));case"!!int":return parseInt(this.parseScalar(n.slice(5)));case"!!bool":return e.parseBoolean(this.parseScalar(n.slice(6)),false);case"!!float":return parseFloat(this.parseScalar(n.slice(7)));case"!!timestamp":return e.stringToDate(e.ltrim(n.slice(11)));default:if(a==null){a={exceptionOnInvalidType:this.settings.exceptionOnInvalidType,objectDecoder:this.settings.objectDecoder,i:0}}o=a.objectDecoder,p=a.exceptionOnInvalidType;if(o){l=e.rtrim(n);r=l.indexOf(" ");if(r===-1){return o(l,null)}else{f=e.ltrim(l.slice(r+1));if(!(f.length>0)){f=null}return o(l.slice(0,r),f)}}if(p){throw new t("Custom object support when parsing a YAML file has been disabled.")}return null}break;case"0":if("0x"===n.slice(0,2)){return e.hexDec(n)}else if(e.isDigits(n)){return e.octDec(n)}else if(e.isNumeric(n)){return parseFloat(n)}else{return n}break;case"+":if(e.isDigits(n)){i=n;s=parseInt(i);if(i===""+s){return s}else{return i}}else if(e.isNumeric(n)){return parseFloat(n)}return n;case"-":if(e.isDigits(n.slice(1))){if("0"===n.charAt(1)){return-e.octDec(n.slice(1))}else{i=n.slice(1);s=parseInt(i);if(i===""+s){return-s}else{return-i}}}else if(e.isNumeric(n)){return parseFloat(n)}return n;default:if(e.isNumeric(n)){return parseFloat(n)}return n}}};return n}();a.exports=u},{"./Escaper":2,"./Exception/DumpException":3,"./Exception/ParseException":4,"./Pattern":7,"./Unescaper":8,"./Utils":9}],6:[function(r,l,u){var i,n,s,t,e;i=r("./Inline");t=r("./Pattern");e=r("./Utils");n=r("./Exception/ParseException");s=function(){r.prototype.PATTERN_FOLDED_SCALAR_ALL=new t("^(?:(?<type>![^\\|>]*)\\s+)?(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$");r.prototype.PATTERN_FOLDED_SCALAR_END=new t("(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$");r.prototype.PATTERN_SEQUENCE_ITEM=new t("^\\-((?<leadspaces>\\s+)(?<value>.+?))?\\s*$");r.prototype.PATTERN_ANCHOR_VALUE=new t("^&(?<ref>[^ ]+) *(?<value>.*)");r.prototype.PATTERN_COMPACT_NOTATION=new t("^(?<key>"+i.REGEX_QUOTED_STRING+"|[^ '\"\\{\\[].*?) *\\:(\\s+(?<value>.+?))?\\s*$");r.prototype.PATTERN_MAPPING_ITEM=new t("^(?<key>"+i.REGEX_QUOTED_STRING+"|[^ '\"\\[\\{].*?) *\\:(\\s+(?<value>.+?))?\\s*$");r.prototype.PATTERN_DECIMAL=new t("\\d+");r.prototype.PATTERN_INDENT_SPACES=new t("^ +");r.prototype.PATTERN_TRAILING_LINES=new t("(\n*)$");r.prototype.PATTERN_YAML_HEADER=new t("^\\%YAML[: ][\\d\\.]+.*\n");r.prototype.PATTERN_LEADING_COMMENTS=new t("^(\\#.*?\n)+");r.prototype.PATTERN_DOCUMENT_MARKER_START=new t("^\\-\\-\\-.*?\n");r.prototype.PATTERN_DOCUMENT_MARKER_END=new t("^\\.\\.\\.\\s*$");r.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION={};r.prototype.CONTEXT_NONE=0;r.prototype.CONTEXT_SEQUENCE=1;r.prototype.CONTEXT_MAPPING=2;function r(e){this.offset=e!=null?e:0;this.lines=[];this.currentLineNb=-1;this.currentLine="";this.refs={}}r.prototype.parse=function(s,f,c){var B,d,v,h,N,t,o,g,E,M,L,u,w,P,T,S,A,p,a,R,_,x,l,y,I,b,C,X,O,G,U,D,k,F,H,Y;if(f==null){f=false}if(c==null){c=null}this.currentLineNb=-1;this.currentLine="";this.lines=this.cleanup(s).split("\n");t=null;N=this.CONTEXT_NONE;d=false;while(this.moveToNextLine()){if(this.isCurrentLineEmpty()){continue}if(" "===this.currentLine[0]){throw new n("A YAML file cannot contain tabs as indentation.",this.getRealCurrentLineNb()+1,this.currentLine)}L=S=false;if(l=this.PATTERN_SEQUENCE_ITEM.exec(this.currentLine)){if(this.CONTEXT_MAPPING===N){throw new n("You cannot define a sequence item when in a mapping")}N=this.CONTEXT_SEQUENCE;if(t==null){t=[]}if(l.value!=null&&(T=this.PATTERN_ANCHOR_VALUE.exec(l.value))){L=T.ref;l.value=T.value}if(!(l.value!=null)||""===e.trim(l.value," ")||e.ltrim(l.value," ").indexOf("#")===0){if(this.currentLineNb<this.lines.length-1&&!this.isNextLineUnIndentedCollection()){h=this.getRealCurrentLineNb()+1;a=new r(h);a.refs=this.refs;t.push(a.parse(this.getNextEmbedBlock(null,true),f,c))}else{t.push(null)}}else{if(((F=l.leadspaces)!=null?F.length:void 0)&&(T=this.PATTERN_COMPACT_NOTATION.exec(l.value))){h=this.getRealCurrentLineNb();a=new r(h);a.refs=this.refs;v=l.value;M=this.getCurrentLineIndentation();if(this.isNextLineIndented(false)){v+="\n"+this.getNextEmbedBlock(M+l.leadspaces.length+1,true)}t.push(a.parse(v,f,c))}else{t.push(this.parseValue(l.value,f,c))}}}else if((l=this.PATTERN_MAPPING_ITEM.exec(this.currentLine))&&l.key.indexOf(" #")===-1){if(this.CONTEXT_SEQUENCE===N){throw new n("You cannot define a mapping item when in a sequence")}N=this.CONTEXT_MAPPING;if(t==null){t={}}i.configure(f,c);try{u=i.parseScalar(l.key)}catch(m){o=m;o.parsedLine=this.getRealCurrentLineNb()+1;o.snippet=this.currentLine;throw o}if("<<"===u){S=true;d=true;if(((H=l.value)!=null?H.indexOf("*"):void 0)===0){R=l.value.slice(1);if(this.refs[R]==null){throw new n('Reference "'+R+'" does not exist.',this.getRealCurrentLineNb()+1,this.currentLine)}_=this.refs[R];if(typeof _!=="object"){throw new n("YAML merge keys used with a scalar value instead of an object.",this.getRealCurrentLineNb()+1,this.currentLine)}if(_ instanceof Array){for(E=y=0,X=_.length;y<X;E=++y){s=_[E];if(t[D=""+E]==null){t[D]=s}}}else{for(u in _){s=_[u];if(t[u]==null){t[u]=s}}}}else{if(l.value!==""){s=l.value}else{s=this.getNextEmbedBlock()}h=this.getRealCurrentLineNb()+1;a=new r(h);a.refs=this.refs;A=a.parse(s,f);if(typeof A!=="object"){throw new n("YAML merge keys used with a scalar value instead of an object.",this.getRealCurrentLineNb()+1,this.currentLine)}if(A instanceof Array){for(I=0,O=A.length;I<O;I++){p=A[I];if(typeof p!=="object"){throw new n("Merge items must be objects.",this.getRealCurrentLineNb()+1,p)}if(p instanceof Array){for(E=b=0,G=p.length;b<G;E=++b){s=p[E];if(t[k=""+E]==null){t[k]=s}}}else{for(u in p){s=p[u];if(t[u]==null){t[u]=s}}}}}else{for(u in A){s=A[u];if(t[u]==null){t[u]=s}}}}}else if(l.value!=null&&(T=this.PATTERN_ANCHOR_VALUE.exec(l.value))){L=T.ref;l.value=T.value}if(S){}else if(!(l.value!=null)||""===e.trim(l.value," ")||e.ltrim(l.value," ").indexOf("#")===0){if(!this.isNextLineIndented()&&!this.isNextLineUnIndentedCollection()){if(d||t[u]===void 0){t[u]=null}}else{h=this.getRealCurrentLineNb()+1;a=new r(h);a.refs=this.refs;x=a.parse(this.getNextEmbedBlock(),f,c);if(d||t[u]===void 0){t[u]=x}}}else{x=this.parseValue(l.value,f,c);if(d||t[u]===void 0){t[u]=x}}}else{P=this.lines.length;if(1===P||2===P&&e.isEmpty(this.lines[1])){try{s=i.parse(this.lines[0],f,c)}catch(m){o=m;o.parsedLine=this.getRealCurrentLineNb()+1;o.snippet=this.currentLine;throw o}if(typeof s==="object"){if(s instanceof Array){g=s[0]}else{for(u in s){g=s[u];break}}if(typeof g==="string"&&g.indexOf("*")===0){t=[];for(C=0,U=s.length;C<U;C++){B=s[C];t.push(this.refs[B.slice(1)])}s=t}}return s}else if((Y=e.ltrim(s).charAt(0))==="["||Y==="{"){try{return i.parse(s,f,c)}catch(m){o=m;o.parsedLine=this.getRealCurrentLineNb()+1;o.snippet=this.currentLine;throw o}}throw new n("Unable to parse.",this.getRealCurrentLineNb()+1,this.currentLine)}if(L){if(t instanceof Array){this.refs[L]=t[t.length-1]}else{w=null;for(u in t){w=u}this.refs[L]=t[w]}}}if(e.isEmpty(t)){return null}else{return t}};r.prototype.getRealCurrentLineNb=function(){return this.currentLineNb+this.offset};r.prototype.getCurrentLineIndentation=function(){return this.currentLine.length-e.ltrim(this.currentLine," ").length};r.prototype.getNextEmbedBlock=function(i,s){var r,t,a,e,l,u,o;if(i==null){i=null}if(s==null){s=false}this.moveToNextLine();if(i==null){e=this.getCurrentLineIndentation();o=this.isStringUnIndentedCollectionItem(this.currentLine);if(!this.isCurrentLineEmpty()&&0===e&&!o){throw new n("Indentation problem.",this.getRealCurrentLineNb()+1,this.currentLine)}}else{e=i}r=[this.currentLine.slice(e)];if(!s){a=this.isStringUnIndentedCollectionItem(this.currentLine)}u=this.PATTERN_FOLDED_SCALAR_END;l=!u.test(this.currentLine);while(this.moveToNextLine()){t=this.getCurrentLineIndentation();if(t===e){l=!u.test(this.currentLine)}if(a&&!this.isStringUnIndentedCollectionItem(this.currentLine)&&t===e){this.moveToPreviousLine();break}if(this.isCurrentLineBlank()){r.push(this.currentLine.slice(e));continue}if(l&&this.isCurrentLineComment()){if(t===e){continue}}if(t>=e){r.push(this.currentLine.slice(e))}else if(0===t){this.moveToPreviousLine();break}else{throw new n("Indentation problem.",this.getRealCurrentLineNb()+1,this.currentLine)}}return r.join("\n")};r.prototype.moveToNextLine=function(){if(this.currentLineNb>=this.lines.length-1){return false}this.currentLine=this.lines[++this.currentLineNb];return true};r.prototype.moveToPreviousLine=function(){this.currentLine=this.lines[--this.currentLineNb]};r.prototype.parseValue=function(e,a,l){var t,s,r,u,o,f,c,h;if(0===e.indexOf("*")){o=e.indexOf("#");if(o!==-1){e=e.substr(1,o-2)}else{e=e.slice(1)}if(this.refs[e]===void 0){throw new n('Reference "'+e+'" does not exist.',this.currentLine)}return this.refs[e]}if(r=this.PATTERN_FOLDED_SCALAR_ALL.exec(e)){u=(c=r.modifiers)!=null?c:"";s=Math.abs(parseInt(u));if(isNaN(s)){s=0}f=this.parseFoldedScalar(r.separator,this.PATTERN_DECIMAL.replace(u,""),s);if(r.type!=null){i.configure(a,l);return i.parseScalar(r.type+" "+f)}else{return f}}try{return i.parse(e,a,l)}catch(p){t=p;if(((h=e.charAt(0))==="["||h==="{")&&t instanceof n&&this.isNextLineIndented()){e+="\n"+this.getNextEmbedBlock();try{return i.parse(e,a,l)}catch(p){t=p;t.parsedLine=this.getRealCurrentLineNb()+1;t.snippet=this.currentLine;throw t}}else{t.parsedLine=this.getRealCurrentLineNb()+1;t.snippet=this.currentLine;throw t}}};r.prototype.parseFoldedScalar=function(T,c,i){var l,u,f,o,s,a,n,h,E,p;if(c==null){c=""}if(i==null){i=0}s=this.moveToNextLine();if(!s){return""}l=this.isCurrentLineBlank();n="";while(s&&l){if(s=this.moveToNextLine()){n+="\n";l=this.isCurrentLineBlank()}}if(0===i){if(f=this.PATTERN_INDENT_SPACES.exec(this.currentLine)){i=f[0].length}}if(i>0){a=this.PATTERN_FOLDED_SCALAR_BY_INDENTATION[i];if(a==null){a=new t("^ {"+i+"}(.*)$");r.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION[i]=a}while(s&&(l||(f=a.exec(this.currentLine)))){if(l){n+=this.currentLine.slice(i)}else{n+=f[1]}if(s=this.moveToNextLine()){n+="\n";l=this.isCurrentLineBlank()}}}else if(s){n+="\n"}if(s){this.moveToPreviousLine()}if(">"===T){o="";p=n.split("\n");for(h=0,E=p.length;h<E;h++){u=p[h];if(u.length===0||u.charAt(0)===" "){o+=u+"\n"}else{o+=u+" "}}n=o}n=e.rtrim(n);if(""===c){n=this.PATTERN_TRAILING_LINES.replace(n,"\n")}else if("-"===c){n=this.PATTERN_TRAILING_LINES.replace(n,"")}return n};r.prototype.isNextLineIndented=function(t){var e,i,n;if(t==null){t=true}i=this.getCurrentLineIndentation();e=!this.moveToNextLine();if(t){while(!e&&this.isCurrentLineEmpty()){e=!this.moveToNextLine()}}else{while(!e&&this.isCurrentLineBlank()){e=!this.moveToNextLine()}}if(e){return false}n=false;if(this.getCurrentLineIndentation()>i){n=true}this.moveToPreviousLine();return n};r.prototype.isCurrentLineEmpty=function(){var t;t=e.trim(this.currentLine," ");return t.length===0||t.charAt(0)==="#"};r.prototype.isCurrentLineBlank=function(){return""===e.trim(this.currentLine," ")};r.prototype.isCurrentLineComment=function(){var t;t=e.ltrim(this.currentLine," ");return t.charAt(0)==="#"};r.prototype.cleanup=function(t){var n,i,r,s,l;t=t.replace("\r\n","\n").replace("\r","\n");n=0;r=this.PATTERN_YAML_HEADER.replaceAll(t,""),t=r[0],n=r[1];this.offset+=n;s=this.PATTERN_LEADING_COMMENTS.replaceAll(t,"",1),i=s[0],n=s[1];if(n===1){this.offset+=e.subStrCount(t,"\n")-e.subStrCount(i,"\n");t=i}l=this.PATTERN_DOCUMENT_MARKER_START.replaceAll(t,"",1),i=l[0],n=l[1];if(n===1){this.offset+=e.subStrCount(t,"\n")-e.subStrCount(i,"\n");t=i;t=this.PATTERN_DOCUMENT_MARKER_END.replace(t,"")}return t};r.prototype.isNextLineUnIndentedCollection=function(e){var t,n;if(e==null){e=null}if(e==null){e=this.getCurrentLineIndentation()}t=this.moveToNextLine();while(t&&this.isCurrentLineEmpty()){t=this.moveToNextLine()}if(false===t){return false}n=false;if(this.getCurrentLineIndentation()===e&&this.isStringUnIndentedCollectionItem(this.currentLine)){n=true}this.moveToPreviousLine();return n};r.prototype.isStringUnIndentedCollectionItem=function(){return this.currentLine==="-"||this.currentLine.slice(0,2)==="- "};return r}();l.exports=s},{"./Exception/ParseException":4,"./Inline":5,"./Pattern":7,"./Utils":9}],7:[function(n,t,i){var e;e=function(){e.prototype.regex=null;e.prototype.rawRegex=null;e.prototype.cleanedRegex=null;e.prototype.mapping=null;function e(n,o){var s,i,t,e,l,r,u,a,f;if(o==null){o=""}t="";l=n.length;r=null;s=0;e=0;while(e<l){i=n.charAt(e);if(i==="\\"){t+=n.slice(e,+(e+1)+1||9e9);e++}else if(i==="("){if(e<l-2){a=n.slice(e,+(e+2)+1||9e9);if(a==="(?:"){e+=2;t+=a}else if(a==="(?<"){s++;e+=2;u="";while(e+1<l){f=n.charAt(e+1);if(f===">"){t+="(";e++;if(u.length>0){if(r==null){r={}}r[u]=s}break}else{u+=f}e++}}else{t+=i;s++}}else{t+=i}}else{t+=i}e++}this.rawRegex=n;this.cleanedRegex=t;this.regex=new RegExp(this.cleanedRegex,"g"+o.replace("g",""));this.mapping=r}e.prototype.exec=function(r){var i,e,t,n;this.regex.lastIndex=0;e=this.regex.exec(r);if(e==null){return null}if(this.mapping!=null){n=this.mapping;for(t in n){i=n[t];e[t]=e[i]}}return e};e.prototype.test=function(e){this.regex.lastIndex=0;return this.regex.test(e)};e.prototype.replace=function(e,t){this.regex.lastIndex=0;return e.replace(this.regex,t)};e.prototype.replaceAll=function(e,i,t){var n;if(t==null){t=0}this.regex.lastIndex=0;n=0;while(this.regex.test(e)&&(t===0||n<t)){this.regex.lastIndex=0;e=e.replace(this.regex,"");n++}return[e,n]};return e}();t.exports=e},{}],8:[function(t,r,s){var n,i,e;e=t("./Utils");n=t("./Pattern");i=function(){function t(){}t.PATTERN_ESCAPED_CHARACTER=new n('\\\\([0abt nvfre "\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})');t.unescapeSingleQuotedString=function(e){return e.replace("''","'")};t.unescapeDoubleQuotedString=function(e){if(this._unescapeCallback==null){this._unescapeCallback=function(e){return function(t){return e.unescapeCharacter(t)}}(this)}return this.PATTERN_ESCAPED_CHARACTER.replace(e,this._unescapeCallback)};t.unescapeCharacter=function(n){var t;t=String.fromCharCode;switch(n.charAt(1)){case"0":return t(0);case"a":return t(7);case"b":return t(8);case"t":return" ";case" ":return" ";case"n":return"\n";case"v":return t(11);case"f":return t(12);case"r":return t(13);case"e":return t(27);case" ":return" ";case'"':return'"';case"/":return"/";case"\\":return"\\";case"N":return t(133);case"_":return t(160);case"L":return t(8232);case"P":return t(8233);case"x":return e.utf8chr(e.hexDec(n.substr(2,2)));case"u":return e.utf8chr(e.hexDec(n.substr(2,4)));case"U":return e.utf8chr(e.hexDec(n.substr(2,8)));default:return""}};return t}();r.exports=i},{"./Pattern":7,"./Utils":9}],9:[function(e,i,r){var t,n;t=e("./Pattern");n=function(){function n(){}n.REGEX_LEFT_TRIM_BY_CHAR={};n.REGEX_RIGHT_TRIM_BY_CHAR={};n.REGEX_SPACES=/\s+/g;n.REGEX_DIGITS=/^\d+$/;n.REGEX_OCTAL=/[^0-7]/gi;n.REGEX_HEXADECIMAL=/[^a-f0-9]/gi;n.PATTERN_DATE=new t("^"+"(?<year>[0-9][0-9][0-9][0-9])"+"-(?<month>[0-9][0-9]?)"+"-(?<day>[0-9][0-9]?)"+"(?:(?:[Tt]|[ ]+)"+"(?<hour>[0-9][0-9]?)"+":(?<minute>[0-9][0-9])"+":(?<second>[0-9][0-9])"+"(?:.(?<fraction>[0-9]*))?"+"(?:[ ]*(?<tz>Z|(?<tz_sign>[-+])(?<tz_hour>[0-9][0-9]?)"+"(?::(?<tz_minute>[0-9][0-9]))?))?)?"+"$","i");n.LOCAL_TIMEZONE_OFFSET=(new Date).getTimezoneOffset()*60*1e3;n.trim=function(i,e){var t,n;if(e==null){e="\\s"}return i.trim();t=this.REGEX_LEFT_TRIM_BY_CHAR[e];if(t==null){this.REGEX_LEFT_TRIM_BY_CHAR[e]=t=new RegExp("^"+e+""+e+"*")}t.lastIndex=0;n=this.REGEX_RIGHT_TRIM_BY_CHAR[e];if(n==null){this.REGEX_RIGHT_TRIM_BY_CHAR[e]=n=new RegExp(e+""+e+"*$")}n.lastIndex=0;return i.replace(t,"").replace(n,"")};n.ltrim=function(n,e){var t;if(e==null){e="\\s"}t=this.REGEX_LEFT_TRIM_BY_CHAR[e];if(t==null){this.REGEX_LEFT_TRIM_BY_CHAR[e]=t=new RegExp("^"+e+""+e+"*")}t.lastIndex=0;return n.replace(t,"")};n.rtrim=function(n,e){var t;if(e==null){e="\\s"}t=this.REGEX_RIGHT_TRIM_BY_CHAR[e];if(t==null){this.REGEX_RIGHT_TRIM_BY_CHAR[e]=t=new RegExp(e+""+e+"*$")}t.lastIndex=0;return n.replace(t,"")};n.isEmpty=function(e){return!e||e===""||e==="0"};n.subStrCount=function(e,i,u,a){var s,r,t,l,n;s=0;e=""+e;i=""+i;if(u!=null){e=e.slice(u)}if(a!=null){e=e.slice(0,a)}t=e.length;l=i.length;for(r=n=0;0<=t?n<t:n>t;r=0<=t?++n:--n){if(i===e.slice(r,l)){s++;r+=l-1}}return s};n.isDigits=function(e){this.REGEX_DIGITS.lastIndex=0;return this.REGEX_DIGITS.test(e)};n.octDec=function(e){this.REGEX_OCTAL.lastIndex=0;return parseInt((e+"").replace(this.REGEX_OCTAL,""),8)};n.hexDec=function(e){this.REGEX_HEXADECIMAL.lastIndex=0;e=this.trim(e);if((e+"").slice(0,2)==="0x"){e=(e+"").slice(2)}return parseInt((e+"").replace(this.REGEX_HEXADECIMAL,""),16)};n.utf8chr=function(e){var t;t=String.fromCharCode;if(128>(e%=2097152)){return t(e)}if(2048>e){return t(192|e>>6)+t(128|e&63)}if(65536>e){return t(224|e>>12)+t(128|e>>6&63)+t(128|e&63)}return t(240|e>>18)+t(128|e>>12&63)+t(128|e>>6&63)+t(128|e&63)};n.parseBoolean=function(t,n){var e;if(n==null){n=true}if(typeof t==="string"){e=t.toLowerCase();if(!n){if(e==="no"){return false}}if(e==="0"){return false}if(e==="false"){return false}if(e===""){return false}return true}return!!t};n.isNumeric=function(e){this.REGEX_SPACES.lastIndex=0;return typeof e==="number"||typeof e==="string"&&!isNaN(e)&&e.replace(this.REGEX_SPACES,"")!==""};n.stringToDate=function(r){var n,l,t,c,e,h,u,f,o,a,i,s;if(!(r!=null?r.length:void 0)){return null}e=this.PATTERN_DATE.exec(r);if(!e){return null}s=parseInt(e.year,10);u=parseInt(e.month,10)-1;l=parseInt(e.day,10);if(e.hour==null){n=new Date(Date.UTC(s,u,l));return n}c=parseInt(e.hour,10);h=parseInt(e.minute,10);f=parseInt(e.second,10);if(e.fraction!=null){t=e.fraction.slice(0,3);while(t.length<3){t+="0"}t=parseInt(t,10)}else{t=0}if(e.tz!=null){o=parseInt(e.tz_hour,10);if(e.tz_minute!=null){a=parseInt(e.tz_minute,10)}else{a=0}i=(o*60+a)*6e4;if("-"===e.tz_sign){i*=-1}}n=new Date(Date.UTC(s,u,l,c,h,f,t));if(i){n.setTime(n.getTime()+i)}return n};n.strRepeat=function(n,i){var e,t;t="";e=0;while(e<i){t+=n;e++}return t};n.getStringFromFile=function(i,n){var s,l,f,a,t,r,o,u;if(n==null){n=null}t=null;if(typeof window!=="undefined"&&window!==null){if(window.XMLHttpRequest){t=new XMLHttpRequest}else if(window.ActiveXObject){u=["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];for(r=0,o=u.length;r<o;r++){f=u[r];try{t=new ActiveXObject(f)}catch(c){}}}}if(t!=null){if(n!=null){t.onreadystatechange=function(){if(t.readyState===4){if(t.status===200||t.status===0){return n(t.responseText)}else{return n(null)}}};t.open("GET",i,true);return t.send(null)}else{t.open("GET",i,false);t.send(null);if(t.status===200||t.status===0){return t.responseText}return null}}else{a=e;l=a("fs");if(n!=null){return l.readFile(i,function(e,t){if(e){return n(null)}else{return n(t)}})}else{s=l.readFileSync(i);if(s!=null){return""+s}return null}}};return n}();i.exports=n},{"./Pattern":7}],10:[function(e,s,l){var i,r,t,n;r=e("./Parser");i=e("./Dumper");t=e("./Utils");n=function(){function n(){}n.parse=function(n,e,t){if(e==null){e=false}if(t==null){t=null}return(new r).parse(n,e,t)};n.parseFile=function(s,i,e,n){var r;if(i==null){i=null}if(e==null){e=false}if(n==null){n=null}if(i!=null){return t.getStringFromFile(s,function(t){return function(i){if(i!=null){return t.parse(i,e,n)}return null}}(this))}else{r=t.getStringFromFile(s);if(r!=null){return this.parse(r,e,n)}return null}};n.dump=function(l,e,t,n,r){var s;if(e==null){e=2}if(t==null){t=4}if(n==null){n=false}if(r==null){r=null}s=new i;s.indentation=t;return s.dump(l,e,0,n,r)};n.register=function(){var t;t=function(e,t){return e.exports=YAML.parseFile(t)};if((typeof e!=="undefined"&&e!==null?e.extensions:void 0)!=null){e.extensions[".yml"]=t;return e.extensions[".yaml"]=t}};n.prototype.stringify=function(e,t,n,i,r){return this.dump(e,t,n,i,r)};n.prototype.load=function(e,t,n,i){return this.parseFile(e,t,n,i)};return n}();if(typeof window!=="undefined"&&window!==null){window.YAML=n}s.exports=n},{"./Dumper":1,"./Parser":6,"./Utils":9}]},{},[10]); \ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..99fc4f5
--- /dev/null
+++ b/index.js
@@ -0,0 +1,22 @@
+
+var Yaml = require('./lib/Yaml');
+
+// Compatibility layer with previous version of yaml.js
+// That was exposing the YAML library as global object in the browser
+if (typeof(window) != 'undefined') {
+ window.YAML = {
+ parse: function(input, exceptionOnInvalidType, objectDecoder) {
+ return Yaml.parse(input, exceptionOnInvalidType, objectDecoder);
+ },
+
+ stringify: function(array, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ return Yaml.dump(array, inline, indent, exceptionOnInvalidType, objectEncoder);
+ }
+ };
+}
+
+module.exports = {
+ Yaml: require('./lib/Yaml'),
+ Parser: require('./lib/Parser'),
+ Dumper: require('./lib/Dumper')
+};
diff --git a/lib/Dumper.js b/lib/Dumper.js
new file mode 100644
index 0000000..8d32a56
--- /dev/null
+++ b/lib/Dumper.js
@@ -0,0 +1,46 @@
+// Generated by CoffeeScript 1.7.1
+var Dumper, Inline, Utils;
+
+Utils = require('./Utils');
+
+Inline = require('./Inline');
+
+Dumper = (function() {
+ function Dumper() {}
+
+ Dumper.indentation = 4;
+
+ Dumper.prototype.dump = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ var isAHash, key, output, prefix, value, willBeInlined;
+ if (inline == null) {
+ inline = 0;
+ }
+ if (indent == null) {
+ indent = 0;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ output = '';
+ prefix = (indent ? Utils.strRepeat(' ', indent) : '');
+ if (inline <= 0 || typeof input !== 'object' || Utils.isEmpty(input)) {
+ output += prefix + Inline.dump(input, exceptionOnInvalidType, objectEncoder);
+ } else {
+ isAHash = !(input instanceof Array);
+ for (key in input) {
+ value = input[key];
+ willBeInlined = inline - 1 <= 0 || typeof value !== 'object' || Utils.isEmpty(value);
+ output += prefix + (isAHash ? Inline.dump(key, exceptionOnInvalidType, objectEncoder) + ':' : '-') + (willBeInlined ? ' ' : "\n") + this.dump(value, inline - 1, (willBeInlined ? 0 : indent + this.indentation), exceptionOnInvalidType, objectEncoder) + (willBeInlined ? "\n" : '');
+ }
+ }
+ return output;
+ };
+
+ return Dumper;
+
+})();
+
+module.exports = Dumper;
diff --git a/lib/Escaper.js b/lib/Escaper.js
new file mode 100644
index 0000000..7551f88
--- /dev/null
+++ b/lib/Escaper.js
@@ -0,0 +1,54 @@
+// Generated by CoffeeScript 1.7.1
+var Escaper, Pattern;
+
+Pattern = require('./Pattern');
+
+Escaper = (function() {
+ var ch;
+
+ function Escaper() {}
+
+ Escaper.LIST_ESCAPEES = ['\\\\', '\\"', '"', "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", (ch = String.fromCharCode)(0x0085), ch(0x00A0), ch(0x2028), ch(0x2029)];
+
+ Escaper.LIST_ESCAPED = ['\\"', '\\\\', '\\"', "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f", "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17", "\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", "\\x1f", "\\N", "\\_", "\\L", "\\P"];
+
+ Escaper.MAPPING_ESCAPEES_TO_ESCAPED = (function() {
+ var i, mapping, _i, _ref;
+ mapping = {};
+ for (i = _i = 0, _ref = Escaper.LIST_ESCAPEES.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
+ mapping[Escaper.LIST_ESCAPEES[i]] = Escaper.LIST_ESCAPED[i];
+ }
+ return mapping;
+ })();
+
+ Escaper.PATTERN_CHARACTERS_TO_ESCAPE = new Pattern('[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9');
+
+ Escaper.PATTERN_MAPPING_ESCAPEES = new Pattern(Escaper.LIST_ESCAPEES.join('|'));
+
+ Escaper.PATTERN_SINGLE_QUOTING = new Pattern('[\\s\'":{}[\\],&*#?]|^[-?|<>=!%@`]');
+
+ Escaper.requiresDoubleQuoting = function(value) {
+ return this.PATTERN_CHARACTERS_TO_ESCAPE.test(value);
+ };
+
+ Escaper.escapeWithDoubleQuotes = function(value) {
+ return this.PATTERN_MAPPING_ESCAPEES.replace(value, (function(_this) {
+ return function(str) {
+ return _this.MAPPING_ESCAPEES_TO_ESCAPED[str];
+ };
+ })(this));
+ };
+
+ Escaper.requiresSingleQuoting = function(value) {
+ return this.PATTERN_SINGLE_QUOTING.test(value);
+ };
+
+ Escaper.escapeWithSingleQuotes = function(value) {
+ return "'" + value.replace('\'', '\'\'') + "'";
+ };
+
+ return Escaper;
+
+})();
+
+module.exports = Escaper;
diff --git a/lib/Exception/DumpException.js b/lib/Exception/DumpException.js
new file mode 100644
index 0000000..e75aa99
--- /dev/null
+++ b/lib/Exception/DumpException.js
@@ -0,0 +1,27 @@
+// Generated by CoffeeScript 1.7.1
+var DumpException,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+DumpException = (function(_super) {
+ __extends(DumpException, _super);
+
+ function DumpException(message, parsedLine, snippet) {
+ this.message = message;
+ this.parsedLine = parsedLine;
+ this.snippet = snippet;
+ }
+
+ DumpException.prototype.toString = function() {
+ if ((this.parsedLine != null) && (this.snippet != null)) {
+ return '<DumpException> ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')';
+ } else {
+ return '<DumpException> ' + this.message;
+ }
+ };
+
+ return DumpException;
+
+})(Error);
+
+module.exports = DumpException;
diff --git a/lib/Exception/ParseException.js b/lib/Exception/ParseException.js
new file mode 100644
index 0000000..2fa9186
--- /dev/null
+++ b/lib/Exception/ParseException.js
@@ -0,0 +1,27 @@
+// Generated by CoffeeScript 1.7.1
+var ParseException,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ParseException = (function(_super) {
+ __extends(ParseException, _super);
+
+ function ParseException(message, parsedLine, snippet) {
+ this.message = message;
+ this.parsedLine = parsedLine;
+ this.snippet = snippet;
+ }
+
+ ParseException.prototype.toString = function() {
+ if ((this.parsedLine != null) && (this.snippet != null)) {
+ return '<ParseException> ' + this.message + ' (line ' + this.parsedLine + ': \'' + this.snippet + '\')';
+ } else {
+ return '<ParseException> ' + this.message;
+ }
+ };
+
+ return ParseException;
+
+})(Error);
+
+module.exports = ParseException;
diff --git a/lib/Inline.js b/lib/Inline.js
new file mode 100644
index 0000000..a901d1e
--- /dev/null
+++ b/lib/Inline.js
@@ -0,0 +1,475 @@
+// Generated by CoffeeScript 1.7.1
+var DumpException, Escaper, Inline, ParseException, Pattern, Unescaper, Utils,
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
+
+Pattern = require('./Pattern');
+
+Unescaper = require('./Unescaper');
+
+Escaper = require('./Escaper');
+
+Utils = require('./Utils');
+
+ParseException = require('./Exception/ParseException');
+
+DumpException = require('./Exception/DumpException');
+
+Inline = (function() {
+ function Inline() {}
+
+ Inline.REGEX_QUOTED_STRING = '(?:"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\']*(?:\'\'[^\']*)*)\')';
+
+ Inline.PATTERN_TRAILING_COMMENTS = new Pattern('^\\s*#.*$');
+
+ Inline.PATTERN_QUOTED_SCALAR = new Pattern('^' + Inline.REGEX_QUOTED_STRING);
+
+ Inline.PATTERN_THOUSAND_NUMERIC_SCALAR = new Pattern('^(-|\\+)?[0-9,]+(\\.[0-9]+)?$');
+
+ Inline.PATTERN_SCALAR_BY_DELIMITERS = {};
+
+ Inline.settings = {};
+
+ Inline.configure = function(exceptionOnInvalidType, objectDecoder) {
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = null;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.settings.exceptionOnInvalidType = exceptionOnInvalidType;
+ this.settings.objectDecoder = objectDecoder;
+ };
+
+ Inline.parse = function(value, exceptionOnInvalidType, objectDecoder) {
+ var context, result;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.settings.exceptionOnInvalidType = exceptionOnInvalidType;
+ this.settings.objectDecoder = objectDecoder;
+ if (value == null) {
+ return '';
+ }
+ value = Utils.trim(value);
+ if (0 === value.length) {
+ return '';
+ }
+ context = {
+ exceptionOnInvalidType: exceptionOnInvalidType,
+ objectDecoder: objectDecoder,
+ i: 0
+ };
+ switch (value.charAt(0)) {
+ case '[':
+ result = this.parseSequence(value, context);
+ ++context.i;
+ break;
+ case '{':
+ result = this.parseMapping(value, context);
+ ++context.i;
+ break;
+ default:
+ result = this.parseScalar(value, null, ['"', "'"], context);
+ }
+ if (this.PATTERN_TRAILING_COMMENTS.replace(value.slice(context.i), '') !== '') {
+ throw new ParseException('Unexpected characters near "' + value.slice(context.i) + '".');
+ }
+ return result;
+ };
+
+ Inline.dump = function(value, exceptionOnInvalidType, objectEncoder) {
+ var result, type, _ref;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ if (value == null) {
+ return 'null';
+ }
+ type = typeof value;
+ if (type === 'object') {
+ if (value instanceof Date) {
+ return value.toISOString();
+ } else if (objectEncoder != null) {
+ result = objectEncoder(value);
+ if (typeof result === 'string' || (result != null)) {
+ return result;
+ }
+ }
+ return this.dumpObject(value);
+ }
+ if (type === 'boolean') {
+ return (value ? 'true' : 'false');
+ }
+ if (Utils.isDigits(value)) {
+ return (type === 'string' ? "'" + value + "'" : '' + parseInt(value));
+ }
+ if (Utils.isNumeric(value)) {
+ return (type === 'string' ? "'" + value + "'" : '' + parseFloat(value));
+ }
+ if (type === 'number') {
+ return (value === Infinity ? '.Inf' : (value === -Infinity ? '-.Inf' : (isNaN(value) ? '.NaN' : value)));
+ }
+ if (Escaper.requiresDoubleQuoting(value)) {
+ return Escaper.escapeWithDoubleQuotes(value);
+ }
+ if (Escaper.requiresSingleQuoting(value)) {
+ return yaml.escapeWithSingleQuotes(value);
+ }
+ if ('' === value) {
+ return '""';
+ }
+ if (Utils.PATTERN_DATE.test(value)) {
+ return "'" + value + "'";
+ }
+ if ((_ref = value.toLowerCase()) === 'null' || _ref === '~' || _ref === 'true' || _ref === 'false') {
+ return "'" + value + "'";
+ }
+ return value;
+ };
+
+ Inline.dumpObject = function(value, exceptionOnInvalidType, objectSupport) {
+ var key, output, val, _i, _len;
+ if (objectSupport == null) {
+ objectSupport = null;
+ }
+ if (value instanceof Array) {
+ output = [];
+ for (_i = 0, _len = value.length; _i < _len; _i++) {
+ val = value[_i];
+ output.push(this.dump(val));
+ }
+ return '[' + output.join(', ') + ']';
+ } else {
+ output = [];
+ for (key in value) {
+ val = value[key];
+ output.push(this.dump(key) + ': ' + this.dump(val));
+ }
+ return '{' + output.join(', ') + '}';
+ }
+ };
+
+ Inline.parseScalar = function(scalar, delimiters, stringDelimiters, context, evaluate) {
+ var i, joinedDelimiters, match, output, pattern, strpos, tmp, _ref, _ref1;
+ if (delimiters == null) {
+ delimiters = null;
+ }
+ if (stringDelimiters == null) {
+ stringDelimiters = ['"', "'"];
+ }
+ if (context == null) {
+ context = null;
+ }
+ if (evaluate == null) {
+ evaluate = true;
+ }
+ if (context == null) {
+ context = {
+ exceptionOnInvalidType: this.settings.exceptionOnInvalidType,
+ objectDecoder: this.settings.objectDecoder,
+ i: 0
+ };
+ }
+ i = context.i;
+ if (_ref = scalar.charAt(i), __indexOf.call(stringDelimiters, _ref) >= 0) {
+ output = this.parseQuotedScalar(scalar, context);
+ i = context.i;
+ if (delimiters != null) {
+ tmp = Utils.ltrim(scalar.slice(i), ' ');
+ if (!(_ref1 = tmp.charAt(0), __indexOf.call(delimiters, _ref1) >= 0)) {
+ throw new ParseException('Unexpected characters (' + scalar.slice(i) + ').');
+ }
+ }
+ } else {
+ if (!delimiters) {
+ output = scalar.slice(i);
+ i += output.length;
+ strpos = output.indexOf(' #');
+ if (strpos !== -1) {
+ output = Utils.rtrim(output.slice(0, strpos));
+ }
+ } else {
+ joinedDelimiters = delimiters.join('|');
+ pattern = this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters];
+ if (pattern == null) {
+ pattern = new Pattern('^(.+?)(' + joinedDelimiters + ')');
+ this.PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters] = pattern;
+ }
+ if (match = pattern.exec(scalar.slice(i))) {
+ output = match[1];
+ i += output.length;
+ } else {
+ throw new ParseException('Malformed inline YAML string (' + scalar + ').');
+ }
+ }
+ if (evaluate) {
+ output = this.evaluateScalar(output, context);
+ }
+ }
+ context.i = i;
+ return output;
+ };
+
+ Inline.parseQuotedScalar = function(scalar, context) {
+ var i, match, output;
+ i = context.i;
+ if (!(match = this.PATTERN_QUOTED_SCALAR.exec(scalar.slice(i)))) {
+ throw new ParseException('Malformed inline YAML string (' + scalar.slice(i) + ').');
+ }
+ output = match[0].substr(1, match[0].length - 2);
+ if ('"' === scalar.charAt(i)) {
+ output = Unescaper.unescapeDoubleQuotedString(output);
+ } else {
+ output = Unescaper.unescapeSingleQuotedString(output);
+ }
+ i += match[0].length;
+ context.i = i;
+ return output;
+ };
+
+ Inline.parseSequence = function(sequence, context) {
+ var e, i, isQuoted, len, output, value, _ref;
+ output = [];
+ len = sequence.length;
+ i = context.i;
+ i += 1;
+ while (i < len) {
+ context.i = i;
+ switch (sequence.charAt(i)) {
+ case '[':
+ output.push(this.parseSequence(sequence, context));
+ i = context.i;
+ break;
+ case '{':
+ output.push(this.parseMapping(sequence, context));
+ i = context.i;
+ break;
+ case ']':
+ return output;
+ case ',':
+ case ' ':
+ case "\n":
+ break;
+ default:
+ isQuoted = ((_ref = sequence.charAt(i)) === '"' || _ref === "'");
+ value = this.parseScalar(sequence, [',', ']'], ['"', "'"], context);
+ i = context.i;
+ if (!isQuoted && typeof value === 'string' && (value.indexOf(': ') !== -1 || value.indexOf(":\n") !== -1)) {
+ try {
+ value = this.parseMapping('{' + value + '}');
+ } catch (_error) {
+ e = _error;
+ }
+ }
+ output.push(value);
+ --i;
+ }
+ ++i;
+ }
+ throw new ParseException('Malformed inline YAML string ' + sequence);
+ };
+
+ Inline.parseMapping = function(mapping, context) {
+ var $value, done, i, key, len, output, shouldContinueWhileLoop, value;
+ output = {};
+ len = mapping.length;
+ i = context.i;
+ i += 1;
+ shouldContinueWhileLoop = false;
+ while (i < len) {
+ context.i = i;
+ switch (mapping.charAt(i)) {
+ case ' ':
+ case ',':
+ case "\n":
+ ++i;
+ context.i = i;
+ shouldContinueWhileLoop = true;
+ break;
+ case '}':
+ return output;
+ }
+ if (shouldContinueWhileLoop) {
+ shouldContinueWhileLoop = false;
+ continue;
+ }
+ key = this.parseScalar(mapping, [':', ' ', "\n"], ['"', "'"], context, false);
+ i = context.i;
+ done = false;
+ while (i < len) {
+ context.i = i;
+ switch (mapping.charAt(i)) {
+ case '[':
+ value = this.parseSequence(mapping, context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ break;
+ case '{':
+ $value = this.parseMapping(mapping, context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ break;
+ case ':':
+ case ' ':
+ case "\n":
+ break;
+ default:
+ value = this.parseScalar(mapping, [',', '}'], ['"', "'"], context);
+ i = context.i;
+ if (output[key] === void 0) {
+ output[key] = value;
+ }
+ done = true;
+ --i;
+ }
+ ++i;
+ if (done) {
+ break;
+ }
+ }
+ }
+ throw new ParseException('Malformed inline YAML string ' + mapping);
+ };
+
+ Inline.evaluateScalar = function(scalar, context) {
+ var cast, exceptionOnInvalidType, firstChar, firstSpace, firstWord, objectDecoder, raw, scalarLower, subValue, trimmedScalar;
+ scalar = Utils.trim(scalar);
+ scalarLower = scalar.toLowerCase();
+ switch (scalarLower) {
+ case 'null':
+ case '':
+ case '~':
+ return null;
+ case 'true':
+ return true;
+ case 'false':
+ return false;
+ case '.inf':
+ return Infinity;
+ case '.nan':
+ return NaN;
+ case '-.inf':
+ return Infinity;
+ default:
+ firstChar = scalarLower.charAt(0);
+ switch (firstChar) {
+ case '!':
+ firstSpace = scalar.indexOf(' ');
+ if (firstSpace === -1) {
+ firstWord = scalarLower;
+ } else {
+ firstWord = scalarLower.slice(0, firstSpace);
+ }
+ switch (firstWord) {
+ case '!':
+ if (firstSpace !== -1) {
+ return parseInt(this.parseScalar(scalar.slice(2)));
+ }
+ return null;
+ case '!str':
+ return Utils.ltrim(scalar.slice(4));
+ case '!!str':
+ return Utils.ltrim(scalar.slice(5));
+ case '!!int':
+ return parseInt(this.parseScalar(scalar.slice(5)));
+ case '!!bool':
+ return Utils.parseBoolean(this.parseScalar(scalar.slice(6)), false);
+ case '!!float':
+ return parseFloat(this.parseScalar(scalar.slice(7)));
+ case '!!timestamp':
+ return Utils.stringToDate(Utils.ltrim(scalar.slice(11)));
+ default:
+ if (context == null) {
+ context = {
+ exceptionOnInvalidType: this.settings.exceptionOnInvalidType,
+ objectDecoder: this.settings.objectDecoder,
+ i: 0
+ };
+ }
+ objectDecoder = context.objectDecoder, exceptionOnInvalidType = context.exceptionOnInvalidType;
+ if (objectDecoder) {
+ trimmedScalar = Utils.rtrim(scalar);
+ firstSpace = trimmedScalar.indexOf(' ');
+ if (firstSpace === -1) {
+ return objectDecoder(trimmedScalar, null);
+ } else {
+ subValue = Utils.ltrim(trimmedScalar.slice(firstSpace + 1));
+ if (!(subValue.length > 0)) {
+ subValue = null;
+ }
+ return objectDecoder(trimmedScalar.slice(0, firstSpace), subValue);
+ }
+ }
+ if (exceptionOnInvalidType) {
+ throw new ParseException('Custom object support when parsing a YAML file has been disabled.');
+ }
+ return null;
+ }
+ break;
+ case '0':
+ if ('0x' === scalar.slice(0, 2)) {
+ return Utils.hexDec(scalar);
+ } else if (Utils.isDigits(scalar)) {
+ return Utils.octDec(scalar);
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ } else {
+ return scalar;
+ }
+ break;
+ case '+':
+ if (Utils.isDigits(scalar)) {
+ raw = scalar;
+ cast = parseInt(raw);
+ if (raw === '' + cast) {
+ return cast;
+ } else {
+ return raw;
+ }
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ case '-':
+ if (Utils.isDigits(scalar.slice(1))) {
+ if ('0' === scalar.charAt(1)) {
+ return -Utils.octDec(scalar.slice(1));
+ } else {
+ raw = scalar.slice(1);
+ cast = parseInt(raw);
+ if (raw === '' + cast) {
+ return -cast;
+ } else {
+ return -raw;
+ }
+ }
+ } else if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ default:
+ if (Utils.isNumeric(scalar)) {
+ return parseFloat(scalar);
+ }
+ return scalar;
+ }
+ }
+ };
+
+ return Inline;
+
+})();
+
+module.exports = Inline;
diff --git a/lib/Parser.js b/lib/Parser.js
new file mode 100644
index 0000000..ef94ec7
--- /dev/null
+++ b/lib/Parser.js
@@ -0,0 +1,576 @@
+// Generated by CoffeeScript 1.7.1
+var Inline, ParseException, Parser, Pattern, Utils;
+
+Inline = require('./Inline');
+
+Pattern = require('./Pattern');
+
+Utils = require('./Utils');
+
+ParseException = require('./Exception/ParseException');
+
+Parser = (function() {
+ Parser.prototype.PATTERN_FOLDED_SCALAR_ALL = new Pattern('^(?:(?<type>![^\\|>]*)\\s+)?(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$');
+
+ Parser.prototype.PATTERN_FOLDED_SCALAR_END = new Pattern('(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$');
+
+ Parser.prototype.PATTERN_SEQUENCE_ITEM = new Pattern('^\\-((?<leadspaces>\\s+)(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_ANCHOR_VALUE = new Pattern('^&(?<ref>[^ ]+) *(?<value>.*)');
+
+ Parser.prototype.PATTERN_COMPACT_NOTATION = new Pattern('^(?<key>' + Inline.REGEX_QUOTED_STRING + '|[^ \'"\\{\\[].*?) *\\:(\\s+(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_MAPPING_ITEM = new Pattern('^(?<key>' + Inline.REGEX_QUOTED_STRING + '|[^ \'"\\[\\{].*?) *\\:(\\s+(?<value>.+?))?\\s*$');
+
+ Parser.prototype.PATTERN_DECIMAL = new Pattern('\\d+');
+
+ Parser.prototype.PATTERN_INDENT_SPACES = new Pattern('^ +');
+
+ Parser.prototype.PATTERN_TRAILING_LINES = new Pattern('(\n*)$');
+
+ Parser.prototype.PATTERN_YAML_HEADER = new Pattern('^\\%YAML[: ][\\d\\.]+.*\n');
+
+ Parser.prototype.PATTERN_LEADING_COMMENTS = new Pattern('^(\\#.*?\n)+');
+
+ Parser.prototype.PATTERN_DOCUMENT_MARKER_START = new Pattern('^\\-\\-\\-.*?\n');
+
+ Parser.prototype.PATTERN_DOCUMENT_MARKER_END = new Pattern('^\\.\\.\\.\\s*$');
+
+ Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION = {};
+
+ Parser.prototype.CONTEXT_NONE = 0;
+
+ Parser.prototype.CONTEXT_SEQUENCE = 1;
+
+ Parser.prototype.CONTEXT_MAPPING = 2;
+
+ function Parser(offset) {
+ this.offset = offset != null ? offset : 0;
+ this.lines = [];
+ this.currentLineNb = -1;
+ this.currentLine = '';
+ this.refs = {};
+ }
+
+ Parser.prototype.parse = function(value, exceptionOnInvalidType, objectDecoder) {
+ var alias, allowOverwrite, block, c, context, data, e, first, i, indent, isRef, key, lastKey, lineCount, matches, mergeNode, parsed, parsedItem, parser, refName, refValue, val, values, _i, _j, _k, _l, _len, _len1, _len2, _len3, _name, _name1, _ref, _ref1, _ref2;
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ this.currentLineNb = -1;
+ this.currentLine = '';
+ this.lines = this.cleanup(value).split("\n");
+ data = null;
+ context = this.CONTEXT_NONE;
+ allowOverwrite = false;
+ while (this.moveToNextLine()) {
+ if (this.isCurrentLineEmpty()) {
+ continue;
+ }
+ if ("\t" === this.currentLine[0]) {
+ throw new ParseException('A YAML file cannot contain tabs as indentation.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ isRef = mergeNode = false;
+ if (values = this.PATTERN_SEQUENCE_ITEM.exec(this.currentLine)) {
+ if (this.CONTEXT_MAPPING === context) {
+ throw new ParseException('You cannot define a sequence item when in a mapping');
+ }
+ context = this.CONTEXT_SEQUENCE;
+ if (data == null) {
+ data = [];
+ }
+ if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) {
+ isRef = matches.ref;
+ values.value = matches.value;
+ }
+ if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf('#') === 0) {
+ if (this.currentLineNb < this.lines.length - 1 && !this.isNextLineUnIndentedCollection()) {
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ data.push(parser.parse(this.getNextEmbedBlock(null, true), exceptionOnInvalidType, objectDecoder));
+ } else {
+ data.push(null);
+ }
+ } else {
+ if (((_ref = values.leadspaces) != null ? _ref.length : void 0) && (matches = this.PATTERN_COMPACT_NOTATION.exec(values.value))) {
+ c = this.getRealCurrentLineNb();
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ block = values.value;
+ indent = this.getCurrentLineIndentation();
+ if (this.isNextLineIndented(false)) {
+ block += "\n" + this.getNextEmbedBlock(indent + values.leadspaces.length + 1, true);
+ }
+ data.push(parser.parse(block, exceptionOnInvalidType, objectDecoder));
+ } else {
+ data.push(this.parseValue(values.value, exceptionOnInvalidType, objectDecoder));
+ }
+ }
+ } else if ((values = this.PATTERN_MAPPING_ITEM.exec(this.currentLine)) && values.key.indexOf(' #') === -1) {
+ if (this.CONTEXT_SEQUENCE === context) {
+ throw new ParseException('You cannot define a mapping item when in a sequence');
+ }
+ context = this.CONTEXT_MAPPING;
+ if (data == null) {
+ data = {};
+ }
+ Inline.configure(exceptionOnInvalidType, objectDecoder);
+ try {
+ key = Inline.parseScalar(values.key);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ if ('<<' === key) {
+ mergeNode = true;
+ allowOverwrite = true;
+ if (((_ref1 = values.value) != null ? _ref1.indexOf('*') : void 0) === 0) {
+ refName = values.value.slice(1);
+ if (this.refs[refName] == null) {
+ throw new ParseException('Reference "' + refName + '" does not exist.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ refValue = this.refs[refName];
+ if (typeof refValue !== 'object') {
+ throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (refValue instanceof Array) {
+ for (i = _i = 0, _len = refValue.length; _i < _len; i = ++_i) {
+ value = refValue[i];
+ if (data[_name = '' + i] == null) {
+ data[_name] = value;
+ }
+ }
+ } else {
+ for (key in refValue) {
+ value = refValue[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ } else {
+ if (values.value !== '') {
+ value = values.value;
+ } else {
+ value = this.getNextEmbedBlock();
+ }
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ parsed = parser.parse(value, exceptionOnInvalidType);
+ if (typeof parsed !== 'object') {
+ throw new ParseException('YAML merge keys used with a scalar value instead of an object.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (parsed instanceof Array) {
+ for (_j = 0, _len1 = parsed.length; _j < _len1; _j++) {
+ parsedItem = parsed[_j];
+ if (typeof parsedItem !== 'object') {
+ throw new ParseException('Merge items must be objects.', this.getRealCurrentLineNb() + 1, parsedItem);
+ }
+ if (parsedItem instanceof Array) {
+ for (i = _k = 0, _len2 = parsedItem.length; _k < _len2; i = ++_k) {
+ value = parsedItem[i];
+ if (data[_name1 = '' + i] == null) {
+ data[_name1] = value;
+ }
+ }
+ } else {
+ for (key in parsedItem) {
+ value = parsedItem[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ }
+ } else {
+ for (key in parsed) {
+ value = parsed[key];
+ if (data[key] == null) {
+ data[key] = value;
+ }
+ }
+ }
+ }
+ } else if ((values.value != null) && (matches = this.PATTERN_ANCHOR_VALUE.exec(values.value))) {
+ isRef = matches.ref;
+ values.value = matches.value;
+ }
+ if (mergeNode) {
+
+ } else if (!(values.value != null) || '' === Utils.trim(values.value, ' ') || Utils.ltrim(values.value, ' ').indexOf('#') === 0) {
+ if (!(this.isNextLineIndented()) && !(this.isNextLineUnIndentedCollection())) {
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = null;
+ }
+ } else {
+ c = this.getRealCurrentLineNb() + 1;
+ parser = new Parser(c);
+ parser.refs = this.refs;
+ val = parser.parse(this.getNextEmbedBlock(), exceptionOnInvalidType, objectDecoder);
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = val;
+ }
+ }
+ } else {
+ val = this.parseValue(values.value, exceptionOnInvalidType, objectDecoder);
+ if (allowOverwrite || data[key] === void 0) {
+ data[key] = val;
+ }
+ }
+ } else {
+ lineCount = this.lines.length;
+ if (1 === lineCount || (2 === lineCount && Utils.isEmpty(this.lines[1]))) {
+ try {
+ value = Inline.parse(this.lines[0], exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ if (typeof value === 'object') {
+ if (value instanceof Array) {
+ first = value[0];
+ } else {
+ for (key in value) {
+ first = value[key];
+ break;
+ }
+ }
+ if (typeof first === 'string' && first.indexOf('*') === 0) {
+ data = [];
+ for (_l = 0, _len3 = value.length; _l < _len3; _l++) {
+ alias = value[_l];
+ data.push(this.refs[alias.slice(1)]);
+ }
+ value = data;
+ }
+ }
+ return value;
+ } else if ((_ref2 = Utils.ltrim(value).charAt(0)) === '[' || _ref2 === '{') {
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ }
+ throw new ParseException('Unable to parse.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ if (isRef) {
+ if (data instanceof Array) {
+ this.refs[isRef] = data[data.length - 1];
+ } else {
+ lastKey = null;
+ for (key in data) {
+ lastKey = key;
+ }
+ this.refs[isRef] = data[lastKey];
+ }
+ }
+ }
+ if (Utils.isEmpty(data)) {
+ return null;
+ } else {
+ return data;
+ }
+ };
+
+ Parser.prototype.getRealCurrentLineNb = function() {
+ return this.currentLineNb + this.offset;
+ };
+
+ Parser.prototype.getCurrentLineIndentation = function() {
+ return this.currentLine.length - Utils.ltrim(this.currentLine, ' ').length;
+ };
+
+ Parser.prototype.getNextEmbedBlock = function(indentation, includeUnindentedCollection) {
+ var data, indent, isItUnindentedCollection, newIndent, removeComments, removeCommentsPattern, unindentedEmbedBlock;
+ if (indentation == null) {
+ indentation = null;
+ }
+ if (includeUnindentedCollection == null) {
+ includeUnindentedCollection = false;
+ }
+ this.moveToNextLine();
+ if (indentation == null) {
+ newIndent = this.getCurrentLineIndentation();
+ unindentedEmbedBlock = this.isStringUnIndentedCollectionItem(this.currentLine);
+ if (!(this.isCurrentLineEmpty()) && 0 === newIndent && !unindentedEmbedBlock) {
+ throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ } else {
+ newIndent = indentation;
+ }
+ data = [this.currentLine.slice(newIndent)];
+ if (!includeUnindentedCollection) {
+ isItUnindentedCollection = this.isStringUnIndentedCollectionItem(this.currentLine);
+ }
+ removeCommentsPattern = this.PATTERN_FOLDED_SCALAR_END;
+ removeComments = !removeCommentsPattern.test(this.currentLine);
+ while (this.moveToNextLine()) {
+ indent = this.getCurrentLineIndentation();
+ if (indent === newIndent) {
+ removeComments = !removeCommentsPattern.test(this.currentLine);
+ }
+ if (isItUnindentedCollection && !this.isStringUnIndentedCollectionItem(this.currentLine) && indent === newIndent) {
+ this.moveToPreviousLine();
+ break;
+ }
+ if (this.isCurrentLineBlank()) {
+ data.push(this.currentLine.slice(newIndent));
+ continue;
+ }
+ if (removeComments && this.isCurrentLineComment()) {
+ if (indent === newIndent) {
+ continue;
+ }
+ }
+ if (indent >= newIndent) {
+ data.push(this.currentLine.slice(newIndent));
+ } else if (0 === indent) {
+ this.moveToPreviousLine();
+ break;
+ } else {
+ throw new ParseException('Indentation problem.', this.getRealCurrentLineNb() + 1, this.currentLine);
+ }
+ }
+ return data.join("\n");
+ };
+
+ Parser.prototype.moveToNextLine = function() {
+ if (this.currentLineNb >= this.lines.length - 1) {
+ return false;
+ }
+ this.currentLine = this.lines[++this.currentLineNb];
+ return true;
+ };
+
+ Parser.prototype.moveToPreviousLine = function() {
+ this.currentLine = this.lines[--this.currentLineNb];
+ };
+
+ Parser.prototype.parseValue = function(value, exceptionOnInvalidType, objectDecoder) {
+ var e, foldedIndent, matches, modifiers, pos, val, _ref, _ref1;
+ if (0 === value.indexOf('*')) {
+ pos = value.indexOf('#');
+ if (pos !== -1) {
+ value = value.substr(1, pos - 2);
+ } else {
+ value = value.slice(1);
+ }
+ if (this.refs[value] === void 0) {
+ throw new ParseException('Reference "' + value + '" does not exist.', this.currentLine);
+ }
+ return this.refs[value];
+ }
+ if (matches = this.PATTERN_FOLDED_SCALAR_ALL.exec(value)) {
+ modifiers = (_ref = matches.modifiers) != null ? _ref : '';
+ foldedIndent = Math.abs(parseInt(modifiers));
+ if (isNaN(foldedIndent)) {
+ foldedIndent = 0;
+ }
+ val = this.parseFoldedScalar(matches.separator, this.PATTERN_DECIMAL.replace(modifiers, ''), foldedIndent);
+ if (matches.type != null) {
+ Inline.configure(exceptionOnInvalidType, objectDecoder);
+ return Inline.parseScalar(matches.type + ' ' + val);
+ } else {
+ return val;
+ }
+ }
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ if (((_ref1 = value.charAt(0)) === '[' || _ref1 === '{') && e instanceof ParseException && this.isNextLineIndented()) {
+ value += "\n" + this.getNextEmbedBlock();
+ try {
+ return Inline.parse(value, exceptionOnInvalidType, objectDecoder);
+ } catch (_error) {
+ e = _error;
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ } else {
+ e.parsedLine = this.getRealCurrentLineNb() + 1;
+ e.snippet = this.currentLine;
+ throw e;
+ }
+ }
+ };
+
+ Parser.prototype.parseFoldedScalar = function(separator, indicator, indentation) {
+ var isCurrentLineBlank, line, matches, newText, notEOF, pattern, text, _i, _len, _ref;
+ if (indicator == null) {
+ indicator = '';
+ }
+ if (indentation == null) {
+ indentation = 0;
+ }
+ notEOF = this.moveToNextLine();
+ if (!notEOF) {
+ return '';
+ }
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ text = '';
+ while (notEOF && isCurrentLineBlank) {
+ if (notEOF = this.moveToNextLine()) {
+ text += "\n";
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ }
+ }
+ if (0 === indentation) {
+ if (matches = this.PATTERN_INDENT_SPACES.exec(this.currentLine)) {
+ indentation = matches[0].length;
+ }
+ }
+ if (indentation > 0) {
+ pattern = this.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation];
+ if (pattern == null) {
+ pattern = new Pattern('^ {' + indentation + '}(.*)$');
+ Parser.prototype.PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation] = pattern;
+ }
+ while (notEOF && (isCurrentLineBlank || (matches = pattern.exec(this.currentLine)))) {
+ if (isCurrentLineBlank) {
+ text += this.currentLine.slice(indentation);
+ } else {
+ text += matches[1];
+ }
+ if (notEOF = this.moveToNextLine()) {
+ text += "\n";
+ isCurrentLineBlank = this.isCurrentLineBlank();
+ }
+ }
+ } else if (notEOF) {
+ text += "\n";
+ }
+ if (notEOF) {
+ this.moveToPreviousLine();
+ }
+ if ('>' === separator) {
+ newText = '';
+ _ref = text.split("\n");
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ line = _ref[_i];
+ if (line.length === 0 || line.charAt(0) === ' ') {
+ newText += line + "\n";
+ } else {
+ newText += line + ' ';
+ }
+ }
+ text = newText;
+ }
+ text = Utils.rtrim(text);
+ if ('' === indicator) {
+ text = this.PATTERN_TRAILING_LINES.replace(text, "\n");
+ } else if ('-' === indicator) {
+ text = this.PATTERN_TRAILING_LINES.replace(text, '');
+ }
+ return text;
+ };
+
+ Parser.prototype.isNextLineIndented = function(ignoreComments) {
+ var EOF, currentIndentation, ret;
+ if (ignoreComments == null) {
+ ignoreComments = true;
+ }
+ currentIndentation = this.getCurrentLineIndentation();
+ EOF = !this.moveToNextLine();
+ if (ignoreComments) {
+ while (!EOF && this.isCurrentLineEmpty()) {
+ EOF = !this.moveToNextLine();
+ }
+ } else {
+ while (!EOF && this.isCurrentLineBlank()) {
+ EOF = !this.moveToNextLine();
+ }
+ }
+ if (EOF) {
+ return false;
+ }
+ ret = false;
+ if (this.getCurrentLineIndentation() > currentIndentation) {
+ ret = true;
+ }
+ this.moveToPreviousLine();
+ return ret;
+ };
+
+ Parser.prototype.isCurrentLineEmpty = function() {
+ var trimmedLine;
+ trimmedLine = Utils.trim(this.currentLine, ' ');
+ return trimmedLine.length === 0 || trimmedLine.charAt(0) === '#';
+ };
+
+ Parser.prototype.isCurrentLineBlank = function() {
+ return '' === Utils.trim(this.currentLine, ' ');
+ };
+
+ Parser.prototype.isCurrentLineComment = function() {
+ var ltrimmedLine;
+ ltrimmedLine = Utils.ltrim(this.currentLine, ' ');
+ return ltrimmedLine.charAt(0) === '#';
+ };
+
+ Parser.prototype.cleanup = function(value) {
+ var count, trimmedValue, _ref, _ref1, _ref2;
+ value = value.replace("\r\n", "\n").replace("\r", "\n");
+ count = 0;
+ _ref = this.PATTERN_YAML_HEADER.replaceAll(value, ''), value = _ref[0], count = _ref[1];
+ this.offset += count;
+ _ref1 = this.PATTERN_LEADING_COMMENTS.replaceAll(value, '', 1), trimmedValue = _ref1[0], count = _ref1[1];
+ if (count === 1) {
+ this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n");
+ value = trimmedValue;
+ }
+ _ref2 = this.PATTERN_DOCUMENT_MARKER_START.replaceAll(value, '', 1), trimmedValue = _ref2[0], count = _ref2[1];
+ if (count === 1) {
+ this.offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n");
+ value = trimmedValue;
+ value = this.PATTERN_DOCUMENT_MARKER_END.replace(value, '');
+ }
+ return value;
+ };
+
+ Parser.prototype.isNextLineUnIndentedCollection = function(currentIndentation) {
+ var notEOF, ret;
+ if (currentIndentation == null) {
+ currentIndentation = null;
+ }
+ if (currentIndentation == null) {
+ currentIndentation = this.getCurrentLineIndentation();
+ }
+ notEOF = this.moveToNextLine();
+ while (notEOF && this.isCurrentLineEmpty()) {
+ notEOF = this.moveToNextLine();
+ }
+ if (false === notEOF) {
+ return false;
+ }
+ ret = false;
+ if (this.getCurrentLineIndentation() === currentIndentation && this.isStringUnIndentedCollectionItem(this.currentLine)) {
+ ret = true;
+ }
+ this.moveToPreviousLine();
+ return ret;
+ };
+
+ Parser.prototype.isStringUnIndentedCollectionItem = function() {
+ return this.currentLine === '-' || this.currentLine.slice(0, 2) === '- ';
+ };
+
+ return Parser;
+
+})();
+
+module.exports = Parser;
diff --git a/lib/Pattern.js b/lib/Pattern.js
new file mode 100644
index 0000000..1ef2f3d
--- /dev/null
+++ b/lib/Pattern.js
@@ -0,0 +1,119 @@
+// Generated by CoffeeScript 1.7.1
+var Pattern;
+
+Pattern = (function() {
+ Pattern.prototype.regex = null;
+
+ Pattern.prototype.rawRegex = null;
+
+ Pattern.prototype.cleanedRegex = null;
+
+ Pattern.prototype.mapping = null;
+
+ function Pattern(rawRegex, modifiers) {
+ var capturingBracketNumber, char, cleanedRegex, i, len, mapping, name, part, subChar;
+ if (modifiers == null) {
+ modifiers = '';
+ }
+ cleanedRegex = '';
+ len = rawRegex.length;
+ mapping = null;
+ capturingBracketNumber = 0;
+ i = 0;
+ while (i < len) {
+ char = rawRegex.charAt(i);
+ if (char === '\\') {
+ cleanedRegex += rawRegex.slice(i, +(i + 1) + 1 || 9e9);
+ i++;
+ } else if (char === '(') {
+ if (i < len - 2) {
+ part = rawRegex.slice(i, +(i + 2) + 1 || 9e9);
+ if (part === '(?:') {
+ i += 2;
+ cleanedRegex += part;
+ } else if (part === '(?<') {
+ capturingBracketNumber++;
+ i += 2;
+ name = '';
+ while (i + 1 < len) {
+ subChar = rawRegex.charAt(i + 1);
+ if (subChar === '>') {
+ cleanedRegex += '(';
+ i++;
+ if (name.length > 0) {
+ if (mapping == null) {
+ mapping = {};
+ }
+ mapping[name] = capturingBracketNumber;
+ }
+ break;
+ } else {
+ name += subChar;
+ }
+ i++;
+ }
+ } else {
+ cleanedRegex += char;
+ capturingBracketNumber++;
+ }
+ } else {
+ cleanedRegex += char;
+ }
+ } else {
+ cleanedRegex += char;
+ }
+ i++;
+ }
+ this.rawRegex = rawRegex;
+ this.cleanedRegex = cleanedRegex;
+ this.regex = new RegExp(this.cleanedRegex, 'g' + modifiers.replace('g', ''));
+ this.mapping = mapping;
+ }
+
+ Pattern.prototype.exec = function(str) {
+ var index, matches, name, _ref;
+ this.regex.lastIndex = 0;
+ matches = this.regex.exec(str);
+ if (matches == null) {
+ return null;
+ }
+ if (this.mapping != null) {
+ _ref = this.mapping;
+ for (name in _ref) {
+ index = _ref[name];
+ matches[name] = matches[index];
+ }
+ }
+ return matches;
+ };
+
+ Pattern.prototype.test = function(str) {
+ this.regex.lastIndex = 0;
+ return this.regex.test(str);
+ };
+
+ Pattern.prototype.replace = function(str, replacement) {
+ this.regex.lastIndex = 0;
+ return str.replace(this.regex, replacement);
+ };
+
+ Pattern.prototype.replaceAll = function(str, replacement, limit) {
+ var count;
+ if (limit == null) {
+ limit = 0;
+ }
+ this.regex.lastIndex = 0;
+ count = 0;
+ while (this.regex.test(str) && (limit === 0 || count < limit)) {
+ this.regex.lastIndex = 0;
+ str = str.replace(this.regex, '');
+ count++;
+ }
+ return [str, count];
+ };
+
+ return Pattern;
+
+})();
+
+module.exports = Pattern;
diff --git a/lib/Unescaper.js b/lib/Unescaper.js
new file mode 100644
index 0000000..20c700c
--- /dev/null
+++ b/lib/Unescaper.js
@@ -0,0 +1,83 @@
+// Generated by CoffeeScript 1.7.1
+var Pattern, Unescaper, Utils;
+
+Utils = require('./Utils');
+
+Pattern = require('./Pattern');
+
+Unescaper = (function() {
+ function Unescaper() {}
+
+ Unescaper.PATTERN_ESCAPED_CHARACTER = new Pattern('\\\\([0abt\tnvfre "\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})');
+
+ Unescaper.unescapeSingleQuotedString = function(value) {
+ return value.replace('\'\'', '\'');
+ };
+
+ Unescaper.unescapeDoubleQuotedString = function(value) {
+ if (this._unescapeCallback == null) {
+ this._unescapeCallback = (function(_this) {
+ return function(str) {
+ return _this.unescapeCharacter(str);
+ };
+ })(this);
+ }
+ return this.PATTERN_ESCAPED_CHARACTER.replace(value, this._unescapeCallback);
+ };
+
+ Unescaper.unescapeCharacter = function(value) {
+ var ch;
+ ch = String.fromCharCode;
+ switch (value.charAt(1)) {
+ case '0':
+ return ch(0);
+ case 'a':
+ return ch(7);
+ case 'b':
+ return ch(8);
+ case 't':
+ return "\t";
+ case "\t":
+ return "\t";
+ case 'n':
+ return "\n";
+ case 'v':
+ return ch(11);
+ case 'f':
+ return ch(12);
+ case 'r':
+ return ch(13);
+ case 'e':
+ return ch(27);
+ case ' ':
+ return ' ';
+ case '"':
+ return '"';
+ case '/':
+ return '/';
+ case '\\':
+ return '\\';
+ case 'N':
+ return ch(0x0085);
+ case '_':
+ return ch(0x00A0);
+ case 'L':
+ return ch(0x2028);
+ case 'P':
+ return ch(0x2029);
+ case 'x':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 2)));
+ case 'u':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 4)));
+ case 'U':
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 8)));
+ default:
+ return '';
+ }
+ };
+
+ return Unescaper;
+
+})();
+
+module.exports = Unescaper;
diff --git a/lib/Utils.js b/lib/Utils.js
new file mode 100644
index 0000000..8d81f06
--- /dev/null
+++ b/lib/Utils.js
@@ -0,0 +1,284 @@
+// Generated by CoffeeScript 1.7.1
+var Pattern, Utils;
+
+Pattern = require('./Pattern');
+
+Utils = (function() {
+ function Utils() {}
+
+ Utils.REGEX_LEFT_TRIM_BY_CHAR = {};
+
+ Utils.REGEX_RIGHT_TRIM_BY_CHAR = {};
+
+ Utils.REGEX_SPACES = /\s+/g;
+
+ Utils.REGEX_DIGITS = /^\d+$/;
+
+ Utils.REGEX_OCTAL = /[^0-7]/gi;
+
+ Utils.REGEX_HEXADECIMAL = /[^a-f0-9]/gi;
+
+ Utils.PATTERN_DATE = new Pattern('^' + '(?<year>[0-9][0-9][0-9][0-9])' + '-(?<month>[0-9][0-9]?)' + '-(?<day>[0-9][0-9]?)' + '(?:(?:[Tt]|[ \t]+)' + '(?<hour>[0-9][0-9]?)' + ':(?<minute>[0-9][0-9])' + ':(?<second>[0-9][0-9])' + '(?:\.(?<fraction>[0-9]*))?' + '(?:[ \t]*(?<tz>Z|(?<tz_sign>[-+])(?<tz_hour>[0-9][0-9]?)' + '(?::(?<tz_minute>[0-9][0-9]))?))?)?' + '$', 'i');
+
+ Utils.LOCAL_TIMEZONE_OFFSET = new Date().getTimezoneOffset() * 60 * 1000;
+
+ Utils.trim = function(str, char) {
+ var regexLeft, regexRight;
+ if (char == null) {
+ char = '\\s';
+ }
+ return str.trim();
+ regexLeft = this.REGEX_LEFT_TRIM_BY_CHAR[char];
+ if (regexLeft == null) {
+ this.REGEX_LEFT_TRIM_BY_CHAR[char] = regexLeft = new RegExp('^' + char + '' + char + '*');
+ }
+ regexLeft.lastIndex = 0;
+ regexRight = this.REGEX_RIGHT_TRIM_BY_CHAR[char];
+ if (regexRight == null) {
+ this.REGEX_RIGHT_TRIM_BY_CHAR[char] = regexRight = new RegExp(char + '' + char + '*$');
+ }
+ regexRight.lastIndex = 0;
+ return str.replace(regexLeft, '').replace(regexRight, '');
+ };
+
+ Utils.ltrim = function(str, char) {
+ var regexLeft;
+ if (char == null) {
+ char = '\\s';
+ }
+ regexLeft = this.REGEX_LEFT_TRIM_BY_CHAR[char];
+ if (regexLeft == null) {
+ this.REGEX_LEFT_TRIM_BY_CHAR[char] = regexLeft = new RegExp('^' + char + '' + char + '*');
+ }
+ regexLeft.lastIndex = 0;
+ return str.replace(regexLeft, '');
+ };
+
+ Utils.rtrim = function(str, char) {
+ var regexRight;
+ if (char == null) {
+ char = '\\s';
+ }
+ regexRight = this.REGEX_RIGHT_TRIM_BY_CHAR[char];
+ if (regexRight == null) {
+ this.REGEX_RIGHT_TRIM_BY_CHAR[char] = regexRight = new RegExp(char + '' + char + '*$');
+ }
+ regexRight.lastIndex = 0;
+ return str.replace(regexRight, '');
+ };
+
+ Utils.isEmpty = function(value) {
+ return !value || value === '' || value === '0';
+ };
+
+ Utils.subStrCount = function(string, subString, start, length) {
+ var c, i, len, sublen, _i;
+ c = 0;
+ string = '' + string;
+ subString = '' + subString;
+ if (start != null) {
+ string = string.slice(start);
+ }
+ if (length != null) {
+ string = string.slice(0, length);
+ }
+ len = string.length;
+ sublen = subString.length;
+ for (i = _i = 0; 0 <= len ? _i < len : _i > len; i = 0 <= len ? ++_i : --_i) {
+ if (subString === string.slice(i, sublen)) {
+ c++;
+ i += sublen - 1;
+ }
+ }
+ return c;
+ };
+
+ Utils.isDigits = function(input) {
+ this.REGEX_DIGITS.lastIndex = 0;
+ return this.REGEX_DIGITS.test(input);
+ };
+
+ Utils.octDec = function(input) {
+ this.REGEX_OCTAL.lastIndex = 0;
+ return parseInt((input + '').replace(this.REGEX_OCTAL, ''), 8);
+ };
+
+ Utils.hexDec = function(input) {
+ this.REGEX_HEXADECIMAL.lastIndex = 0;
+ input = this.trim(input);
+ if ((input + '').slice(0, 2) === '0x') {
+ input = (input + '').slice(2);
+ }
+ return parseInt((input + '').replace(this.REGEX_HEXADECIMAL, ''), 16);
+ };
+
+ Utils.utf8chr = function(c) {
+ var ch;
+ ch = String.fromCharCode;
+ if (0x80 > (c %= 0x200000)) {
+ return ch(c);
+ }
+ if (0x800 > c) {
+ return ch(0xC0 | c >> 6) + ch(0x80 | c & 0x3F);
+ }
+ if (0x10000 > c) {
+ return ch(0xE0 | c >> 12) + ch(0x80 | c >> 6 & 0x3F) + ch(0x80 | c & 0x3F);
+ }
+ return ch(0xF0 | c >> 18) + ch(0x80 | c >> 12 & 0x3F) + ch(0x80 | c >> 6 & 0x3F) + ch(0x80 | c & 0x3F);
+ };
+
+ Utils.parseBoolean = function(input, strict) {
+ var lowerInput;
+ if (strict == null) {
+ strict = true;
+ }
+ if (typeof input === 'string') {
+ lowerInput = input.toLowerCase();
+ if (!strict) {
+ if (lowerInput === 'no') {
+ return false;
+ }
+ }
+ if (lowerInput === '0') {
+ return false;
+ }
+ if (lowerInput === 'false') {
+ return false;
+ }
+ if (lowerInput === '') {
+ return false;
+ }
+ return true;
+ }
+ return !!input;
+ };
+
+ Utils.isNumeric = function(input) {
+ this.REGEX_SPACES.lastIndex = 0;
+ return typeof input === 'number' || typeof input === 'string' && !isNaN(input) && input.replace(this.REGEX_SPACES, '') !== '';
+ };
+
+ Utils.stringToDate = function(str) {
+ var date, day, fraction, hour, info, minute, month, second, tz_hour, tz_minute, tz_offset, year;
+ if (!(str != null ? str.length : void 0)) {
+ return null;
+ }
+ info = this.PATTERN_DATE.exec(str);
+ if (!info) {
+ return null;
+ }
+ year = parseInt(info.year, 10);
+ month = parseInt(info.month, 10) - 1;
+ day = parseInt(info.day, 10);
+ if (info.hour == null) {
+ date = new Date(Date.UTC(year, month, day));
+ return date;
+ }
+ hour = parseInt(info.hour, 10);
+ minute = parseInt(info.minute, 10);
+ second = parseInt(info.second, 10);
+ if (info.fraction != null) {
+ fraction = info.fraction.slice(0, 3);
+ while (fraction.length < 3) {
+ fraction += '0';
+ }
+ fraction = parseInt(fraction, 10);
+ } else {
+ fraction = 0;
+ }
+ if (info.tz != null) {
+ tz_hour = parseInt(info.tz_hour, 10);
+ if (info.tz_minute != null) {
+ tz_minute = parseInt(info.tz_minute, 10);
+ } else {
+ tz_minute = 0;
+ }
+ tz_offset = (tz_hour * 60 + tz_minute) * 60000;
+ if ('-' === info.tz_sign) {
+ tz_offset *= -1;
+ }
+ }
+ date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
+ if (tz_offset) {
+ date.setTime(date.getTime() + tz_offset);
+ }
+ return date;
+ };
+
+ Utils.strRepeat = function(str, number) {
+ var i, res;
+ res = '';
+ i = 0;
+ while (i < number) {
+ res += str;
+ i++;
+ }
+ return res;
+ };
+
+ Utils.getStringFromFile = function(path, callback) {
+ var data, fs, name, req, xhr, _i, _len, _ref;
+ if (callback == null) {
+ callback = null;
+ }
+ xhr = null;
+ if (typeof window !== "undefined" && window !== null) {
+ if (window.XMLHttpRequest) {
+ xhr = new XMLHttpRequest();
+ } else if (window.ActiveXObject) {
+ _ref = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ name = _ref[_i];
+ try {
+ xhr = new ActiveXObject(name);
+ } catch (_error) {}
+ }
+ }
+ }
+ if (xhr != null) {
+ if (callback != null) {
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200 || xhr.status === 0) {
+ return callback(xhr.responseText);
+ } else {
+ return callback(null);
+ }
+ }
+ };
+ xhr.open('GET', path, true);
+ return xhr.send(null);
+ } else {
+ xhr.open('GET', path, false);
+ xhr.send(null);
+ if (xhr.status === 200 || xhr.status === 0) {
+ return xhr.responseText;
+ }
+ return null;
+ }
+ } else {
+ req = require;
+ fs = req('fs');
+ if (callback != null) {
+ return fs.readFile(path, function(err, data) {
+ if (err) {
+ return callback(null);
+ } else {
+ return callback(data);
+ }
+ });
+ } else {
+ data = fs.readFileSync(path);
+ if (data != null) {
+ return '' + data;
+ }
+ return null;
+ }
+ }
+ };
+
+ return Utils;
+
+})();
+
+module.exports = Utils;
diff --git a/lib/Yaml.js b/lib/Yaml.js
new file mode 100644
index 0000000..8ab695f
--- /dev/null
+++ b/lib/Yaml.js
@@ -0,0 +1,98 @@
+// Generated by CoffeeScript 1.7.1
+var Dumper, Parser, Utils, Yaml;
+
+Parser = require('./Parser');
+
+Dumper = require('./Dumper');
+
+Utils = require('./Utils');
+
+Yaml = (function() {
+ function Yaml() {}
+
+ Yaml.parse = function(input, exceptionOnInvalidType, objectDecoder) {
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ return new Parser().parse(input, exceptionOnInvalidType, objectDecoder);
+ };
+
+ Yaml.parseFile = function(path, callback, exceptionOnInvalidType, objectDecoder) {
+ var input;
+ if (callback == null) {
+ callback = null;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectDecoder == null) {
+ objectDecoder = null;
+ }
+ if (callback != null) {
+ return Utils.getStringFromFile(path, (function(_this) {
+ return function(input) {
+ if (input != null) {
+ return _this.parse(input, exceptionOnInvalidType, objectDecoder);
+ }
+ return null;
+ };
+ })(this));
+ } else {
+ input = Utils.getStringFromFile(path);
+ if (input != null) {
+ return this.parse(input, exceptionOnInvalidType, objectDecoder);
+ }
+ return null;
+ }
+ };
+
+ Yaml.dump = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ var yaml;
+ if (inline == null) {
+ inline = 2;
+ }
+ if (indent == null) {
+ indent = 4;
+ }
+ if (exceptionOnInvalidType == null) {
+ exceptionOnInvalidType = false;
+ }
+ if (objectEncoder == null) {
+ objectEncoder = null;
+ }
+ yaml = new Dumper();
+ yaml.indentation = indent;
+ return yaml.dump(input, inline, 0, exceptionOnInvalidType, objectEncoder);
+ };
+
+ Yaml.register = function() {
+ var require_handler;
+ require_handler = function(module, filename) {
+ return module.exports = YAML.parseFile(filename);
+ };
+ if ((typeof require !== "undefined" && require !== null ? require.extensions : void 0) != null) {
+ require.extensions['.yml'] = require_handler;
+ return require.extensions['.yaml'] = require_handler;
+ }
+ };
+
+ Yaml.prototype.stringify = function(input, inline, indent, exceptionOnInvalidType, objectEncoder) {
+ return this.dump(input, inline, indent, exceptionOnInvalidType, objectEncoder);
+ };
+
+ Yaml.prototype.load = function(path, callback, exceptionOnInvalidType, objectDecoder) {
+ return this.parseFile(path, callback, exceptionOnInvalidType, objectDecoder);
+ };
+
+ return Yaml;
+
+})();
+
+if (typeof window !== "undefined" && window !== null) {
+ window.YAML = Yaml;
+}
+
+module.exports = Yaml;
diff --git a/package.json b/package.json
index bf45337..013fa9f 100644
--- a/package.json
+++ b/package.json
@@ -1,24 +1,29 @@
{
- "name": "yamljs",
- "version": "0.1.5",
- "description": "Standalone JavaScript YAML 1.2 Parser & Encoder. Works under node.js and all major browsers. Also brings command line YAML/JSON conversion tools.",
- "keywords": [
- "yaml", "json", "yaml2json", "json2yaml"
- ],
- "author": "Jeremy Faivre <contact@jeremyfa.com>",
- "main": "./bin/yaml.js",
- "dependencies": {
- "argparse": "~0.1.4",
- "glob": "~3.1.11"
- },
- "bin": {
- "yaml2json": "./bin/yaml2json",
- "json2yaml": "./bin/json2yaml"
- },
- "devDependencies": {
- },
- "repository": {
- "type": "git",
- "url": "git://github.com/jeremyfa/yaml.js.git"
- }
+ "name": "yamljs",
+ "version": "0.1.5",
+ "description": "Standalone JavaScript YAML 1.2 Parser & Encoder. Works under node.js and all major browsers. Also brings command line YAML/JSON conversion tools.",
+ "keywords": [
+ "yaml",
+ "json",
+ "yaml2json",
+ "json2yaml"
+ ],
+ "author": "Jeremy Faivre <contact@jeremyfa.com>",
+ "main": "./bin/yaml.js",
+ "dependencies": {
+ "argparse": "^0.1.15",
+ "glob": "^3.1.21",
+ "coffeeify": "^0.7.0",
+ "benchmark": "^1.0.0",
+ "jasmine-node": "^1.14.5"
+ },
+ "bin": {
+ "yaml2json": "./bin/yaml2json",
+ "json2yaml": "./bin/json2yaml"
+ },
+ "devDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/jeremyfa/yaml.js.git"
+ }
}
diff --git a/src/Dumper.coffee b/src/Dumper.coffee
new file mode 100644
index 0000000..e259658
--- /dev/null
+++ b/src/Dumper.coffee
@@ -0,0 +1,46 @@
+
+Utils = require './Utils'
+Inline = require './Inline'
+
+# Dumper dumps JavaScript variables to YAML strings.
+#
+class Dumper
+
+ # The amount of spaces to use for indentation of nested nodes.
+ @indentation: 4
+
+
+ # Dumps a JavaScript value to YAML.
+ #
+ # @param [Object] input The JavaScript value
+ # @param [Integer] inline The level where you switch to inline YAML
+ # @param [Integer] indent The level of indentation (used internally)
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types (a JavaScript resource or object), false otherwise
+ # @param [Function] objectEncoder A function to serialize custom objects, null otherwise
+ #
+ # @return [String] The YAML representation of the JavaScript value
+ #
+ dump: (input, inline = 0, indent = 0, exceptionOnInvalidType = false, objectEncoder = null) ->
+ output = ''
+ prefix = (if indent then Utils.strRepeat(' ', indent) else '')
+
+ if inline <= 0 or typeof(input) isnt 'object' or Utils.isEmpty(input)
+ output += prefix + Inline.dump(input, exceptionOnInvalidType, objectEncoder)
+
+ else
+ isAHash = not(input instanceof Array)
+
+ for key, value of input
+ willBeInlined = (inline - 1 <= 0 or typeof(value) isnt 'object' or Utils.isEmpty(value))
+
+ output +=
+ prefix +
+ (if isAHash then Inline.dump(key, exceptionOnInvalidType, objectEncoder) + ':' else '-') +
+ (if willBeInlined then ' ' else "\n") +
+ @dump(value, inline - 1, (if willBeInlined then 0 else indent + @indentation), exceptionOnInvalidType, objectEncoder) +
+ (if willBeInlined then "\n" else '')
+
+ return output
+
+
+module.exports = Dumper
diff --git a/src/Escaper.coffee b/src/Escaper.coffee
new file mode 100644
index 0000000..f499398
--- /dev/null
+++ b/src/Escaper.coffee
@@ -0,0 +1,80 @@
+
+Pattern = require './Pattern'
+
+# Escaper encapsulates escaping rules for single
+# and double-quoted YAML strings.
+class Escaper
+
+ # Mapping arrays for escaping a double quoted string. The backslash is
+ # first to ensure proper escaping.
+ @LIST_ESCAPEES: ['\\\\', '\\"', '"',
+ "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
+ "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
+ "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
+ "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
+ (ch = String.fromCharCode)(0x0085), ch(0x00A0), ch(0x2028), ch(0x2029)]
+ @LIST_ESCAPED: ['\\"', '\\\\', '\\"',
+ "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a",
+ "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f",
+ "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17",
+ "\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", "\\x1f",
+ "\\N", "\\_", "\\L", "\\P"]
+
+ @MAPPING_ESCAPEES_TO_ESCAPED: do =>
+ mapping = {}
+ for i in [0...@LIST_ESCAPEES.length]
+ mapping[@LIST_ESCAPEES[i]] = @LIST_ESCAPED[i]
+ return mapping
+
+ # Characters that would cause a dumped string to require double quoting.
+ @PATTERN_CHARACTERS_TO_ESCAPE: new Pattern '[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9'
+
+ # Other precompiled patterns
+ @PATTERN_MAPPING_ESCAPEES: new Pattern @LIST_ESCAPEES.join('|')
+ @PATTERN_SINGLE_QUOTING: new Pattern '[\\s\'":{}[\\],&*#?]|^[-?|<>=!%@`]'
+
+
+
+ # Determines if a JavaScript value would require double quoting in YAML.
+ #
+ # @param [String] value A JavaScript value value
+ #
+ # @return [Boolean] true if the value would require double quotes.
+ #
+ @requiresDoubleQuoting: (value) ->
+ return @PATTERN_CHARACTERS_TO_ESCAPE.test value
+
+
+ # Escapes and surrounds a JavaScript value with double quotes.
+ #
+ # @param [String] value A JavaScript value
+ #
+ # @return [String] The quoted, escaped string
+ #
+ @escapeWithDoubleQuotes: (value) ->
+ return @PATTERN_MAPPING_ESCAPEES.replace value, (str) =>
+ return @MAPPING_ESCAPEES_TO_ESCAPED[str]
+
+
+ # Determines if a JavaScript value would require single quoting in YAML.
+ #
+ # @param [String] value A JavaScript value
+ #
+ # @return [Boolean] true if the value would require single quotes.
+ #
+ @requiresSingleQuoting: (value) ->
+ return @PATTERN_SINGLE_QUOTING.test value
+
+
+ # Escapes and surrounds a JavaScript value with single quotes.
+ #
+ # @param [String] value A JavaScript value
+ #
+ # @return [String] The quoted, escaped string
+ #
+ @escapeWithSingleQuotes: (value) ->
+ return "'"+value.replace('\'', '\'\'')+"'"
+
+
+module.exports = Escaper
+
diff --git a/src/Exception/DumpException.coffee b/src/Exception/DumpException.coffee
new file mode 100644
index 0000000..9cc6c27
--- /dev/null
+++ b/src/Exception/DumpException.coffee
@@ -0,0 +1,12 @@
+
+class DumpException extends Error
+
+ constructor: (@message, @parsedLine, @snippet) ->
+
+ toString: ->
+ if @parsedLine? and @snippet?
+ return '<DumpException> ' + @message + ' (line ' + @parsedLine + ': \'' + @snippet + '\')'
+ else
+ return '<DumpException> ' + @message
+
+module.exports = DumpException
diff --git a/src/Exception/ParseException.coffee b/src/Exception/ParseException.coffee
new file mode 100644
index 0000000..a6a0785
--- /dev/null
+++ b/src/Exception/ParseException.coffee
@@ -0,0 +1,12 @@
+
+class ParseException extends Error
+
+ constructor: (@message, @parsedLine, @snippet) ->
+
+ toString: ->
+ if @parsedLine? and @snippet?
+ return '<ParseException> ' + @message + ' (line ' + @parsedLine + ': \'' + @snippet + '\')'
+ else
+ return '<ParseException> ' + @message
+
+module.exports = ParseException
diff --git a/src/Inline.coffee b/src/Inline.coffee
new file mode 100644
index 0000000..4d5fe8b
--- /dev/null
+++ b/src/Inline.coffee
@@ -0,0 +1,485 @@
+
+Pattern = require './Pattern'
+Unescaper = require './Unescaper'
+Escaper = require './Escaper'
+Utils = require './Utils'
+ParseException = require './Exception/ParseException'
+DumpException = require './Exception/DumpException'
+
+# Inline YAML parsing and dumping
+class Inline
+
+ # Quoted string regular expression
+ @REGEX_QUOTED_STRING: '(?:"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\']*(?:\'\'[^\']*)*)\')'
+
+ # Pre-compiled patterns
+ #
+ @PATTERN_TRAILING_COMMENTS: new Pattern '^\\s*#.*$'
+ @PATTERN_QUOTED_SCALAR: new Pattern '^'+@REGEX_QUOTED_STRING
+ @PATTERN_THOUSAND_NUMERIC_SCALAR: new Pattern '^(-|\\+)?[0-9,]+(\\.[0-9]+)?$'
+ @PATTERN_SCALAR_BY_DELIMITERS: {}
+
+ # Settings
+ @settings: {}
+
+
+ # Configure YAML inline.
+ #
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types (a JavaScript resource or object), false otherwise
+ # @param [Function] objectDecoder A function to deserialize custom objects, null otherwise
+ #
+ @configure: (exceptionOnInvalidType = null, objectDecoder = null) ->
+ # Update settings
+ @settings.exceptionOnInvalidType = exceptionOnInvalidType
+ @settings.objectDecoder = objectDecoder
+ return
+
+
+ # Converts a YAML string to a JavaScript object.
+ #
+ # @param [String] value A YAML string
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types (a JavaScript resource or object), false otherwise
+ # @param [Function] objectDecoder A function to deserialize custom objects, null otherwise
+ #
+ # @return [Object] A JavaScript object representing the YAML string
+ #
+ # @throw [ParseException]
+ #
+ @parse: (value, exceptionOnInvalidType = false, objectDecoder = null) ->
+ # Update settings from last call of Inline.parse()
+ @settings.exceptionOnInvalidType = exceptionOnInvalidType
+ @settings.objectDecoder = objectDecoder
+
+ if not value?
+ return ''
+
+ value = Utils.trim value
+
+ if 0 is value.length
+ return ''
+
+ # Keep a context object to pass through static methods
+ context = {exceptionOnInvalidType, objectDecoder, i: 0}
+
+ switch value.charAt(0)
+ when '['
+ result = @parseSequence value, context
+ ++context.i
+ when '{'
+ result = @parseMapping value, context
+ ++context.i
+ else
+ result = @parseScalar value, null, ['"', "'"], context
+
+ # Some comments are allowed at the end
+ if @PATTERN_TRAILING_COMMENTS.replace(value[context.i..], '') isnt ''
+ throw new ParseException 'Unexpected characters near "'+value[context.i..]+'".'
+
+ return result
+
+
+ # Dumps a given JavaScript variable to a YAML string.
+ #
+ # @param [Object] value The JavaScript variable to convert
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types (a JavaScript resource or object), false otherwise
+ # @param [Function] objectEncoder A function to serialize custom objects, null otherwise
+ #
+ # @return [String] The YAML string representing the JavaScript object
+ #
+ # @throw [DumpException]
+ #
+ @dump: (value, exceptionOnInvalidType = false, objectEncoder = null) ->
+ if not value?
+ return 'null'
+ type = typeof value
+ if type is 'object'
+ if value instanceof Date
+ return value.toISOString()
+ else if objectEncoder?
+ result = objectEncoder value
+ if typeof result is 'string' or result?
+ return result
+ return @dumpObject value
+ if type is 'boolean'
+ return (if value then 'true' else 'false')
+ if Utils.isDigits(value)
+ return (if type is 'string' then "'"+value+"'" else ''+parseInt(value))
+ if Utils.isNumeric(value)
+ return (if type is 'string' then "'"+value+"'" else ''+parseFloat(value))
+ if type is 'number'
+ return (if value is Infinity then '.Inf' else (if value is -Infinity then '-.Inf' else (if isNaN(value) then '.NaN' else value)))
+ if Escaper.requiresDoubleQuoting value
+ return Escaper.escapeWithDoubleQuotes value
+ if Escaper.requiresSingleQuoting value
+ return yaml.escapeWithSingleQuotes value
+ if '' is value
+ return '""'
+ if Utils.PATTERN_DATE.test value
+ return "'"+value+"'";
+ if value.toLowerCase() in ['null','~','true','false']
+ return "'"+value+"'"
+ # Default
+ return value;
+
+
+ # Dumps a JavaScript object to a YAML string.
+ #
+ # @param [Object] value The JavaScript object to dump
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types (a JavaScript resource or object), false otherwise
+ # @param [Function] objectEncoder A function do serialize custom objects, null otherwise
+ #
+ # @return string The YAML string representing the JavaScript object
+ #
+ @dumpObject: (value, exceptionOnInvalidType, objectSupport = null) ->
+ # Array
+ if value instanceof Array
+ output = []
+ for val in value
+ output.push @dump val
+ return '['+output.join(', ')+']'
+
+ # Mapping
+ else
+ output = []
+ for key, val of value
+ output.push @dump(key)+': '+@dump(val)
+ return '{'+output.join(', ')+'}'
+
+
+ # Parses a scalar to a YAML string.
+ #
+ # @param [Object] scalar
+ # @param [Array] delimiters
+ # @param [Array] stringDelimiters
+ # @param [Object] context
+ # @param [Boolean] evaluate
+ #
+ # @return [String] A YAML string
+ #
+ # @throw [ParseException] When malformed inline YAML string is parsed
+ #
+ @parseScalar: (scalar, delimiters = null, stringDelimiters = ['"', "'"], context = null, evaluate = true) ->
+ unless context?
+ context = exceptionOnInvalidType: @settings.exceptionOnInvalidType, objectDecoder: @settings.objectDecoder, i: 0
+ {i} = context
+
+ if scalar.charAt(i) in stringDelimiters
+ # Quoted scalar
+ output = @parseQuotedScalar scalar, context
+ {i} = context
+
+ if delimiters?
+ tmp = Utils.ltrim scalar[i..], ' '
+ if not(tmp.charAt(0) in delimiters)
+ throw new ParseException 'Unexpected characters ('+scalar[i..]+').'
+
+ else
+ # "normal" string
+ if not delimiters
+ output = scalar[i..]
+ i += output.length
+
+ # Remove comments
+ strpos = output.indexOf ' #'
+ if strpos isnt -1
+ output = Utils.rtrim output[0...strpos]
+
+ else
+ joinedDelimiters = delimiters.join('|')
+ pattern = @PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters]
+ unless pattern?
+ pattern = new Pattern '^(.+?)('+joinedDelimiters+')'
+ @PATTERN_SCALAR_BY_DELIMITERS[joinedDelimiters] = pattern
+ if match = pattern.exec scalar[i..]
+ output = match[1]
+ i += output.length
+ else
+ throw new ParseException 'Malformed inline YAML string ('+scalar+').'
+
+
+ if evaluate
+ output = @evaluateScalar output, context
+
+ context.i = i
+ return output
+
+
+ # Parses a quoted scalar to YAML.
+ #
+ # @param [String] scalar
+ # @param [Object] context
+ #
+ # @return [String] A YAML string
+ #
+ # @throw [ParseException] When malformed inline YAML string is parsed
+ #
+ @parseQuotedScalar: (scalar, context) ->
+ {i} = context
+
+ unless match = @PATTERN_QUOTED_SCALAR.exec scalar[i..]
+ throw new ParseException 'Malformed inline YAML string ('+scalar[i..]+').'
+
+ output = match[0].substr(1, match[0].length - 2)
+
+ if '"' is scalar.charAt(i)
+ output = Unescaper.unescapeDoubleQuotedString output
+ else
+ output = Unescaper.unescapeSingleQuotedString output
+
+ i += match[0].length
+
+ context.i = i
+ return output
+
+
+ # Parses a sequence to a YAML string.
+ #
+ # @param [String] sequence
+ # @param [Object] context
+ #
+ # @return [String] A YAML string
+ #
+ # @throw [ParseException] When malformed inline YAML string is parsed
+ #
+ @parseSequence: (sequence, context) ->
+ output = []
+ len = sequence.length
+ {i} = context
+ i += 1
+
+ # [foo, bar, ...]
+ while i < len
+ context.i = i
+ switch sequence.charAt(i)
+ when '['
+ # Nested sequence
+ output.push @parseSequence sequence, context
+ {i} = context
+ when '{'
+ # Nested mapping
+ output.push @parseMapping sequence, context
+ {i} = context
+ when ']'
+ return output
+ when ',', ' ', "\n"
+ # Do nothing
+ else
+ isQuoted = (sequence.charAt(i) in ['"', "'"])
+ value = @parseScalar sequence, [',', ']'], ['"', "'"], context
+ {i} = context
+
+ if not(isQuoted) and typeof(value) is 'string' and (value.indexOf(': ') isnt -1 or value.indexOf(":\n") isnt -1)
+ # Embedded mapping?
+ try
+ value = @parseMapping '{'+value+'}'
+ catch e
+ # No, it's not
+
+
+ output.push value
+
+ --i
+
+ ++i
+
+ throw new ParseException 'Malformed inline YAML string '+sequence
+
+
+ # Parses a mapping to a YAML string.
+ #
+ # @param [String] mapping
+ # @param [Object] context
+ #
+ # @return [String] A YAML string
+ #
+ # @throw [ParseException] When malformed inline YAML string is parsed
+ #
+ @parseMapping: (mapping, context) ->
+ output = {}
+ len = mapping.length
+ {i} = context
+ i += 1
+
+ # {foo: bar, bar:foo, ...}
+ shouldContinueWhileLoop = false
+ while i < len
+ context.i = i
+ switch mapping.charAt(i)
+ when ' ', ',', "\n"
+ ++i
+ context.i = i
+ shouldContinueWhileLoop = true
+ when '}'
+ return output
+
+ if shouldContinueWhileLoop
+ shouldContinueWhileLoop = false
+ continue
+
+ # Key
+ key = @parseScalar mapping, [':', ' ', "\n"], ['"', "'"], context, false
+ {i} = context
+
+ # Value
+ done = false
+
+ while i < len
+ context.i = i
+ switch mapping.charAt(i)
+ when '['
+ # Nested sequence
+ value = @parseSequence mapping, context
+ {i} = context
+ # Spec: Keys MUST be unique; first one wins.
+ # Parser cannot abort this mapping earlier, since lines
+ # are processed sequentially.
+ if output[key] == undefined
+ output[key] = value
+ done = true
+ when '{'
+ # Nested mapping
+ $value = @parseMapping mapping, context
+ {i} = context
+ # Spec: Keys MUST be unique; first one wins.
+ # Parser cannot abort this mapping earlier, since lines
+ # are processed sequentially.
+ if output[key] == undefined
+ output[key] = value
+ done = true
+ when ':', ' ', "\n"
+ # Do nothing
+ else
+ value = @parseScalar mapping, [',', '}'], ['"', "'"], context
+ {i} = context
+ # Spec: Keys MUST be unique; first one wins.
+ # Parser cannot abort this mapping earlier, since lines
+ # are processed sequentially.
+ if output[key] == undefined
+ output[key] = value
+ done = true
+ --i
+
+ ++i
+
+ if done
+ break
+
+ throw new ParseException 'Malformed inline YAML string '+mapping
+
+
+ # Evaluates scalars and replaces magic values.
+ #
+ # @param [String] scalar
+ #
+ # @return [String] A YAML string
+ #
+ @evaluateScalar: (scalar, context) ->
+ scalar = Utils.trim(scalar)
+ scalarLower = scalar.toLowerCase()
+
+ switch scalarLower
+ when 'null', '', '~'
+ return null
+ when 'true'
+ return true
+ when 'false'
+ return false
+ when '.inf'
+ return Infinity
+ when '.nan'
+ return NaN
+ when '-.inf'
+ return Infinity
+ else
+ firstChar = scalarLower.charAt(0)
+ switch firstChar
+ when '!'
+ firstSpace = scalar.indexOf(' ')
+ if firstSpace is -1
+ firstWord = scalarLower
+ else
+ firstWord = scalarLower[0...firstSpace]
+ switch firstWord
+ when '!'
+ if firstSpace isnt -1
+ return parseInt @parseScalar(scalar[2..])
+ return null
+ when '!str'
+ return Utils.ltrim scalar[4..]
+ when '!!str'
+ return Utils.ltrim scalar[5..]
+ when '!!int'
+ return parseInt(@parseScalar(scalar[5..]))
+ when '!!bool'
+ return Utils.parseBoolean(@parseScalar(scalar[6..]), false)
+ when '!!float'
+ return parseFloat(@parseScalar(scalar[7..]))
+ when '!!timestamp'
+ return Utils.stringToDate(Utils.ltrim(scalar[11..]))
+ else
+ unless context?
+ context = exceptionOnInvalidType: @settings.exceptionOnInvalidType, objectDecoder: @settings.objectDecoder, i: 0
+ {objectDecoder, exceptionOnInvalidType} = context
+
+ if objectDecoder
+ # If objectDecoder function is given, we can do custom decoding of custom types
+ trimmedScalar = Utils.rtrim scalar
+ firstSpace = trimmedScalar.indexOf(' ')
+ if firstSpace is -1
+ return objectDecoder trimmedScalar, null
+ else
+ subValue = Utils.ltrim trimmedScalar[firstSpace+1..]
+ unless subValue.length > 0
+ subValue = null
+ return objectDecoder trimmedScalar[0...firstSpace], subValue
+
+ if exceptionOnInvalidType
+ throw new ParseException 'Custom object support when parsing a YAML file has been disabled.'
+
+ return null
+ when '0'
+ if '0x' is scalar[0...2]
+ return Utils.hexDec scalar
+ else if Utils.isDigits scalar
+ return Utils.octDec scalar
+ else if Utils.isNumeric scalar
+ return parseFloat scalar
+ else
+ return scalar
+ when '+'
+ if Utils.isDigits scalar
+ raw = scalar
+ cast = parseInt(raw)
+ if raw is ''+cast
+ return cast
+ else
+ return raw
+ else if Utils.isNumeric scalar
+ return parseFloat scalar
+ #else if @PATTERN_THOUSAND_NUMERIC_SCALAR.test scalar
+ # return parseFloat(scalar.replace(',', ''))
+ return scalar
+ when '-'
+ if Utils.isDigits(scalar[1..])
+ if '0' is scalar.charAt(1)
+ return -Utils.octDec(scalar[1..])
+ else
+ raw = scalar[1..]
+ cast = parseInt(raw)
+ if raw is ''+cast
+ return -cast
+ else
+ return -raw
+ else if Utils.isNumeric scalar
+ return parseFloat scalar
+ #else if @PATTERN_THOUSAND_NUMERIC_SCALAR.test scalar
+ # return parseFloat(scalar.replace(',', ''))
+ return scalar
+ else
+ if Utils.isNumeric(scalar)
+ return parseFloat scalar
+ #else if @PATTERN_THOUSAND_NUMERIC_SCALAR.test scalar
+ # return parseFloat(scalar.replace(',', ''))
+ return scalar
+
+module.exports = Inline
diff --git a/src/Parser.coffee b/src/Parser.coffee
new file mode 100644
index 0000000..98dfa41
--- /dev/null
+++ b/src/Parser.coffee
@@ -0,0 +1,633 @@
+
+Inline = require './Inline'
+Pattern = require './Pattern'
+Utils = require './Utils'
+ParseException = require './Exception/ParseException'
+
+# Parser parses YAML strings to convert them to JavaScript objects.
+#
+class Parser
+
+ # Pre-compiled patterns
+ #
+ PATTERN_FOLDED_SCALAR_ALL: new Pattern '^(?:(?<type>![^\\|>]*)\\s+)?(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$'
+ PATTERN_FOLDED_SCALAR_END: new Pattern '(?<separator>\\||>)(?<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?<comments> +#.*)?$'
+ PATTERN_SEQUENCE_ITEM: new Pattern '^\\-((?<leadspaces>\\s+)(?<value>.+?))?\\s*$'
+ PATTERN_ANCHOR_VALUE: new Pattern '^&(?<ref>[^ ]+) *(?<value>.*)'
+ PATTERN_COMPACT_NOTATION: new Pattern '^(?<key>'+Inline.REGEX_QUOTED_STRING+'|[^ \'"\\{\\[].*?) *\\:(\\s+(?<value>.+?))?\\s*$'
+ PATTERN_MAPPING_ITEM: new Pattern '^(?<key>'+Inline.REGEX_QUOTED_STRING+'|[^ \'"\\[\\{].*?) *\\:(\\s+(?<value>.+?))?\\s*$'
+ PATTERN_DECIMAL: new Pattern '\\d+'
+ PATTERN_INDENT_SPACES: new Pattern '^ +'
+ PATTERN_TRAILING_LINES: new Pattern '(\n*)$'
+ PATTERN_YAML_HEADER: new Pattern '^\\%YAML[: ][\\d\\.]+.*\n'
+ PATTERN_LEADING_COMMENTS: new Pattern '^(\\#.*?\n)+'
+ PATTERN_DOCUMENT_MARKER_START: new Pattern '^\\-\\-\\-.*?\n'
+ PATTERN_DOCUMENT_MARKER_END: new Pattern '^\\.\\.\\.\\s*$'
+ PATTERN_FOLDED_SCALAR_BY_INDENTATION: {}
+
+ # Context types
+ #
+ CONTEXT_NONE: 0
+ CONTEXT_SEQUENCE: 1
+ CONTEXT_MAPPING: 2
+
+
+ # Constructor
+ #
+ # @param [Integer] offset The offset of YAML document (used for line numbers in error messages)
+ #
+ constructor: (@offset = 0) ->
+ @lines = []
+ @currentLineNb = -1
+ @currentLine = ''
+ @refs = {}
+
+
+ # Parses a YAML string to a JavaScript value.
+ #
+ # @param [String] value A YAML string
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types (a JavaScript resource or object), false otherwise
+ # @param [Function] objectDecoder A function to deserialize custom objects, null otherwise
+ #
+ # @return [Object] A JavaScript value
+ #
+ # @throw [ParseException] If the YAML is not valid
+ #
+ parse: (value, exceptionOnInvalidType = false, objectDecoder = null) ->
+ @currentLineNb = -1
+ @currentLine = ''
+ @lines = @cleanup(value).split "\n"
+
+ data = null
+ context = @CONTEXT_NONE
+ allowOverwrite = false
+ while @moveToNextLine()
+ if @isCurrentLineEmpty()
+ continue
+
+ # Tab?
+ if "\t" is @currentLine[0]
+ throw new ParseException 'A YAML file cannot contain tabs as indentation.', @getRealCurrentLineNb() + 1, @currentLine
+
+ isRef = mergeNode = false
+ if values = @PATTERN_SEQUENCE_ITEM.exec @currentLine
+ if @CONTEXT_MAPPING is context
+ throw new ParseException 'You cannot define a sequence item when in a mapping'
+ context = @CONTEXT_SEQUENCE
+ data ?= []
+
+ if values.value? and matches = @PATTERN_ANCHOR_VALUE.exec values.value
+ isRef = matches.ref
+ values.value = matches.value
+
+ # Array
+ if not(values.value?) or '' is Utils.trim(values.value, ' ') or Utils.ltrim(values.value, ' ').indexOf('#') is 0
+ if @currentLineNb < @lines.length - 1 and not @isNextLineUnIndentedCollection()
+ c = @getRealCurrentLineNb() + 1
+ parser = new Parser c
+ parser.refs = @refs
+ data.push parser.parse(@getNextEmbedBlock(null, true), exceptionOnInvalidType, objectDecoder)
+ else
+ data.push null
+
+ else
+ if values.leadspaces?.length and matches = @PATTERN_COMPACT_NOTATION.exec values.value
+
+ # This is a compact notation element, add to next block and parse
+ c = @getRealCurrentLineNb()
+ parser = new Parser c
+ parser.refs = @refs
+
+ block = values.value
+ indent = @getCurrentLineIndentation()
+ if @isNextLineIndented(false)
+ block += "\n"+@getNextEmbedBlock(indent + values.leadspaces.length + 1, true)
+
+ data.push parser.parse block, exceptionOnInvalidType, objectDecoder
+
+ else
+ data.push @parseValue values.value, exceptionOnInvalidType, objectDecoder
+
+ else if (values = @PATTERN_MAPPING_ITEM.exec @currentLine) and values.key.indexOf(' #') is -1
+ if @CONTEXT_SEQUENCE is context
+ throw new ParseException 'You cannot define a mapping item when in a sequence'
+ context = @CONTEXT_MAPPING
+ data ?= {}
+
+ # Force correct settings
+ Inline.configure exceptionOnInvalidType, objectDecoder
+ try
+ key = Inline.parseScalar values.key
+ catch e
+ e.parsedLine = @getRealCurrentLineNb() + 1
+ e.snippet = @currentLine
+
+ throw e
+
+ if '<<' is key
+ mergeNode = true
+ allowOverwrite = true
+ if values.value?.indexOf('*') is 0
+ refName = values.value[1..]
+ unless @refs[refName]?
+ throw new ParseException 'Reference "'+refName+'" does not exist.', @getRealCurrentLineNb() + 1, @currentLine
+
+ refValue = @refs[refName]
+
+ if typeof refValue isnt 'object'
+ throw new ParseException 'YAML merge keys used with a scalar value instead of an object.', @getRealCurrentLineNb() + 1, @currentLine
+
+ if refValue instanceof Array
+ # Merge array with object
+ for value, i in refValue
+ data[''+i] ?= value
+ else
+ # Merge objects
+ for key, value of refValue
+ data[key] ?= value
+
+ else
+ if values.value isnt ''
+ value = values.value
+ else
+ value = @getNextEmbedBlock()
+
+ c = @getRealCurrentLineNb() + 1
+ parser = new Parser c
+ parser.refs = @refs
+ parsed = parser.parse value, exceptionOnInvalidType
+
+ unless typeof parsed is 'object'
+ throw new ParseException 'YAML merge keys used with a scalar value instead of an object.', @getRealCurrentLineNb() + 1, @currentLine
+
+ if parsed instanceof Array
+ # If the value associated with the merge key is a sequence, then this sequence is expected to contain mapping nodes
+ # and each of these nodes is merged in turn according to its order in the sequence. Keys in mapping nodes earlier
+ # in the sequence override keys specified in later mapping nodes.
+ for parsedItem in parsed
+ unless typeof parsedItem is 'object'
+ throw new ParseException 'Merge items must be objects.', @getRealCurrentLineNb() + 1, parsedItem
+
+ if parsedItem instanceof Array
+ # Merge array with object
+ for value, i in parsedItem
+ data[''+i] ?= value
+ else
+ # Merge objects
+ for key, value of parsedItem
+ data[key] ?= value
+
+ else
+ # If the value associated with the key is a single mapping node, each of its key/value pairs is inserted into the
+ # current mapping, unless the key already exists in it.
+ for key, value of parsed
+ data[key] ?= value
+
+ else if values.value? and matches = @PATTERN_ANCHOR_VALUE.exec values.value
+ isRef = matches.ref
+ values.value = matches.value
+
+
+ if mergeNode
+ # Merge keys
+ else if not(values.value?) or '' is Utils.trim(values.value, ' ') or Utils.ltrim(values.value, ' ').indexOf('#') is 0
+ # Hash
+ # if next line is less indented or equal, then it means that the current value is null
+ if not(@isNextLineIndented()) and not(@isNextLineUnIndentedCollection())
+ # Spec: Keys MUST be unique; first one wins.
+ # But overwriting is allowed when a merge node is used in current block.
+ if allowOverwrite or data[key] is undefined
+ data[key] = null
+
+ else
+ c = @getRealCurrentLineNb() + 1
+ parser = new Parser c
+ parser.refs = @refs
+ val = parser.parse @getNextEmbedBlock(), exceptionOnInvalidType, objectDecoder
+
+ # Spec: Keys MUST be unique; first one wins.
+ # But overwriting is allowed when a merge node is used in current block.
+ if allowOverwrite or data[key] is undefined
+ data[key] = val
+
+ else
+ val = @parseValue values.value, exceptionOnInvalidType, objectDecoder
+
+ # Spec: Keys MUST be unique; first one wins.
+ # But overwriting is allowed when a merge node is used in current block.
+ if allowOverwrite or data[key] is undefined
+ data[key] = val
+
+ else
+ # 1-liner optionally followed by newline
+ lineCount = @lines.length
+ if 1 is lineCount or (2 is lineCount and Utils.isEmpty(@lines[1]))
+ try
+ value = Inline.parse @lines[0], exceptionOnInvalidType, objectDecoder
+ catch e
+ e.parsedLine = @getRealCurrentLineNb() + 1
+ e.snippet = @currentLine
+
+ throw e
+
+ if typeof value is 'object'
+ if value instanceof Array
+ first = value[0]
+ else
+ for key of value
+ first = value[key]
+ break
+
+ if typeof first is 'string' and first.indexOf('*') is 0
+ data = []
+ for alias in value
+ data.push @refs[alias[1..]]
+ value = data
+
+ return value
+
+ else if Utils.ltrim(value).charAt(0) in ['[', '{']
+ try
+ return Inline.parse value, exceptionOnInvalidType, objectDecoder
+ catch e
+ e.parsedLine = @getRealCurrentLineNb() + 1
+ e.snippet = @currentLine
+
+ throw e
+
+ throw new ParseException 'Unable to parse.', @getRealCurrentLineNb() + 1, @currentLine
+
+ if isRef
+ if data instanceof Array
+ @refs[isRef] = data[data.length-1]
+ else
+ lastKey = null
+ for key of data
+ lastKey = key
+ @refs[isRef] = data[lastKey]
+
+
+ if Utils.isEmpty(data)
+ return null
+ else
+ return data
+
+
+
+ # Returns the current line number (takes the offset into account).
+ #
+ # @return [Integer] The current line number
+ #
+ getRealCurrentLineNb: ->
+ return @currentLineNb + @offset
+
+
+ # Returns the current line indentation.
+ #
+ # @return [Integer] The current line indentation
+ #
+ getCurrentLineIndentation: ->
+ return @currentLine.length - Utils.ltrim(@currentLine, ' ').length
+
+
+ # Returns the next embed block of YAML.
+ #
+ # @param [Integer] indentation The indent level at which the block is to be read, or null for default
+ #
+ # @return [String] A YAML string
+ #
+ # @throw [ParseException] When indentation problem are detected
+ #
+ getNextEmbedBlock: (indentation = null, includeUnindentedCollection = false) ->
+ @moveToNextLine()
+
+ if not indentation?
+ newIndent = @getCurrentLineIndentation()
+
+ unindentedEmbedBlock = @isStringUnIndentedCollectionItem @currentLine
+
+ if not(@isCurrentLineEmpty()) and 0 is newIndent and not(unindentedEmbedBlock)
+ throw new ParseException 'Indentation problem.', @getRealCurrentLineNb() + 1, @currentLine
+
+ else
+ newIndent = indentation
+
+
+ data = [@currentLine[newIndent..]]
+
+ unless includeUnindentedCollection
+ isItUnindentedCollection = @isStringUnIndentedCollectionItem @currentLine
+
+ # Comments must not be removed inside a string block (ie. after a line ending with "|")
+ # They must not be removed inside a sub-embedded block as well
+ removeCommentsPattern = @PATTERN_FOLDED_SCALAR_END
+ removeComments = not removeCommentsPattern.test @currentLine
+
+ while @moveToNextLine()
+ indent = @getCurrentLineIndentation()
+
+ if indent is newIndent
+ removeComments = not removeCommentsPattern.test @currentLine
+
+ if isItUnindentedCollection and not @isStringUnIndentedCollectionItem(@currentLine) and indent is newIndent
+ @moveToPreviousLine()
+ break
+
+ if @isCurrentLineBlank()
+ data.push @currentLine[newIndent..]
+ continue
+
+ if removeComments and @isCurrentLineComment()
+ if indent is newIndent
+ continue
+
+ if indent >= newIndent
+ data.push @currentLine[newIndent..]
+ else if 0 is indent
+ @moveToPreviousLine()
+ break
+ else
+ throw new ParseException 'Indentation problem.', @getRealCurrentLineNb() + 1, @currentLine
+
+
+ return data.join "\n"
+
+
+ # Moves the parser to the next line.
+ #
+ # @return [Boolean]
+ #
+ moveToNextLine: ->
+ if @currentLineNb >= @lines.length - 1
+ return false
+
+ @currentLine = @lines[++@currentLineNb];
+
+ return true
+
+
+ # Moves the parser to the previous line.
+ #
+ moveToPreviousLine: ->
+ @currentLine = @lines[--@currentLineNb]
+ return
+
+
+ # Parses a YAML value.
+ #
+ # @param [String] value A YAML value
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types false otherwise
+ # @param [Function] objectDecoder A function to deserialize custom objects, null otherwise
+ #
+ # @return [Object] A JavaScript value
+ #
+ # @throw [ParseException] When reference does not exist
+ #
+ parseValue: (value, exceptionOnInvalidType, objectDecoder) ->
+ if 0 is value.indexOf('*')
+ pos = value.indexOf '#'
+ if pos isnt -1
+ value = value.substr(1, pos-2)
+ else
+ value = value[1..]
+
+ if @refs[value] is undefined
+ throw new ParseException 'Reference "'+value+'" does not exist.', @currentLine
+
+ return @refs[value]
+
+
+ if matches = @PATTERN_FOLDED_SCALAR_ALL.exec value
+ modifiers = matches.modifiers ? ''
+
+ foldedIndent = Math.abs(parseInt(modifiers))
+ if isNaN(foldedIndent) then foldedIndent = 0
+ val = @parseFoldedScalar matches.separator, @PATTERN_DECIMAL.replace(modifiers, ''), foldedIndent
+ if matches.type?
+ # Force correct settings
+ Inline.configure exceptionOnInvalidType, objectDecoder
+ return Inline.parseScalar matches.type+' '+val
+ else
+ return val
+
+ try
+ return Inline.parse value, exceptionOnInvalidType, objectDecoder
+ catch e
+ # Try to parse multiline compact sequence or mapping
+ if value.charAt(0) in ['[', '{'] and e instanceof ParseException and @isNextLineIndented()
+ value += "\n" + @getNextEmbedBlock()
+ try
+ return Inline.parse value, exceptionOnInvalidType, objectDecoder
+ catch e
+ e.parsedLine = @getRealCurrentLineNb() + 1
+ e.snippet = @currentLine
+
+ throw e
+
+ else
+ e.parsedLine = @getRealCurrentLineNb() + 1
+ e.snippet = @currentLine
+
+ throw e
+
+ return
+
+
+ # Parses a folded scalar.
+ #
+ # @param [String] separator The separator that was used to begin this folded scalar (| or >)
+ # @param [String] indicator The indicator that was used to begin this folded scalar (+ or -)
+ # @param [Integer] indentation The indentation that was used to begin this folded scalar
+ #
+ # @return [String] The text value
+ #
+ parseFoldedScalar: (separator, indicator = '', indentation = 0) ->
+ notEOF = @moveToNextLine()
+ if not notEOF
+ return ''
+
+ isCurrentLineBlank = @isCurrentLineBlank()
+ text = ''
+
+ # Leading blank lines are consumed before determining indentation
+ while notEOF and isCurrentLineBlank
+ # newline only if not EOF
+ if notEOF = @moveToNextLine()
+ text += "\n"
+ isCurrentLineBlank = @isCurrentLineBlank()
+
+
+ # Determine indentation if not specified
+ if 0 is indentation
+ if matches = @PATTERN_INDENT_SPACES.exec @currentLine
+ indentation = matches[0].length
+
+
+ if indentation > 0
+ pattern = @PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation]
+ unless pattern?
+ pattern = new Pattern '^ {'+indentation+'}(.*)$'
+ Parser::PATTERN_FOLDED_SCALAR_BY_INDENTATION[indentation] = pattern
+
+ while notEOF and (isCurrentLineBlank or matches = pattern.exec @currentLine)
+ if isCurrentLineBlank
+ text += @currentLine[indentation..]
+ else
+ text += matches[1]
+
+ # newline only if not EOF
+ if notEOF = @moveToNextLine()
+ text += "\n"
+ isCurrentLineBlank = @isCurrentLineBlank()
+
+ else if notEOF
+ text += "\n"
+
+
+ if notEOF
+ @moveToPreviousLine()
+
+
+ # Remove line breaks of each lines except the empty and more indented ones
+ if '>' is separator
+ newText = ''
+ for line in text.split "\n"
+ if line.length is 0 or line.charAt(0) is ' '
+ newText += line + "\n"
+ else
+ newText += line + ' '
+ text = newText
+
+ # Remove any extra space or new line as we are adding them after
+ text = Utils.rtrim(text)
+
+ # Deal with trailing newlines as indicated
+ if '' is indicator
+ text = @PATTERN_TRAILING_LINES.replace text, "\n"
+ else if '-' is indicator
+ text = @PATTERN_TRAILING_LINES.replace text, ''
+
+ return text
+
+
+ # Returns true if the next line is indented.
+ #
+ # @return [Boolean] Returns true if the next line is indented, false otherwise
+ #
+ isNextLineIndented: (ignoreComments = true) ->
+ currentIndentation = @getCurrentLineIndentation()
+ EOF = not @moveToNextLine()
+
+ if ignoreComments
+ while not(EOF) and @isCurrentLineEmpty()
+ EOF = not @moveToNextLine()
+ else
+ while not(EOF) and @isCurrentLineBlank()
+ EOF = not @moveToNextLine()
+
+ if EOF
+ return false
+
+ ret = false
+ if @getCurrentLineIndentation() > currentIndentation
+ ret = true
+
+ @moveToPreviousLine()
+
+ return ret
+
+
+ # Returns true if the current line is blank or if it is a comment line.
+ #
+ # @return [Boolean] Returns true if the current line is empty or if it is a comment line, false otherwise
+ #
+ isCurrentLineEmpty: ->
+ trimmedLine = Utils.trim(@currentLine, ' ')
+ return trimmedLine.length is 0 or trimmedLine.charAt(0) is '#'
+
+
+ # Returns true if the current line is blank.
+ #
+ # @return [Boolean] Returns true if the current line is blank, false otherwise
+ #
+ isCurrentLineBlank: ->
+ return '' is Utils.trim(@currentLine, ' ')
+
+
+ # Returns true if the current line is a comment line.
+ #
+ # @return [Boolean] Returns true if the current line is a comment line, false otherwise
+ #
+ isCurrentLineComment: ->
+ # Checking explicitly the first char of the trim is faster than loops or strpos
+ ltrimmedLine = Utils.ltrim(@currentLine, ' ')
+
+ return ltrimmedLine.charAt(0) is '#'
+
+
+ # Cleanups a YAML string to be parsed.
+ #
+ # @param [String] value The input YAML string
+ #
+ # @return [String] A cleaned up YAML string
+ #
+ cleanup: (value) ->
+ value = value.replace("\r\n", "\n").replace("\r", "\n")
+
+ # Strip YAML header
+ count = 0
+ [value, count] = @PATTERN_YAML_HEADER.replaceAll value, ''
+ @offset += count
+
+ # Remove leading comments
+ [trimmedValue, count] = @PATTERN_LEADING_COMMENTS.replaceAll value, '', 1
+ if count is 1
+ # Items have been removed, update the offset
+ @offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n")
+ value = trimmedValue
+
+ # Remove start of the document marker (---)
+ [trimmedValue, count] = @PATTERN_DOCUMENT_MARKER_START.replaceAll value, '', 1
+ if count is 1
+ # Items have been removed, update the offset
+ @offset += Utils.subStrCount(value, "\n") - Utils.subStrCount(trimmedValue, "\n")
+ value = trimmedValue
+
+ # Remove end of the document marker (...)
+ value = @PATTERN_DOCUMENT_MARKER_END.replace value, ''
+
+ return value
+
+
+ # Returns true if the next line starts unindented collection
+ #
+ # @return [Boolean] Returns true if the next line starts unindented collection, false otherwise
+ #
+ isNextLineUnIndentedCollection: (currentIndentation = null) ->
+ currentIndentation ?= @getCurrentLineIndentation()
+ notEOF = @moveToNextLine()
+
+ while notEOF and @isCurrentLineEmpty()
+ notEOF = @moveToNextLine()
+
+ if false is notEOF
+ return false
+
+ ret = false
+ if @getCurrentLineIndentation() is currentIndentation and @isStringUnIndentedCollectionItem(@currentLine)
+ ret = true
+
+ @moveToPreviousLine()
+
+ return ret
+
+
+ # Returns true if the string is un-indented collection item
+ #
+ # @return [Boolean] Returns true if the string is un-indented collection item, false otherwise
+ #
+ isStringUnIndentedCollectionItem: ->
+ return @currentLine is '-' or @currentLine[0...2] is '- '
+
+
+module.exports = Parser
diff --git a/src/Pattern.coffee b/src/Pattern.coffee
new file mode 100644
index 0000000..ada37b2
--- /dev/null
+++ b/src/Pattern.coffee
@@ -0,0 +1,144 @@
+
+# Pattern is a zero-conflict wrapper extending RegExp features
+# in order to make YAML parsing regex more expressive.
+#
+class Pattern
+
+ # @property [RegExp] The RegExp instance
+ regex: null
+
+ # @property [String] The raw regex string
+ rawRegex: null
+
+ # @property [String] The cleaned regex string (used to create the RegExp instance)
+ cleanedRegex: null
+
+ # @property [Object] The dictionary mapping names to capturing bracket numbers
+ mapping: null
+
+ # Constructor
+ #
+ # @param [String] rawRegex The raw regex string defining the pattern
+ #
+ constructor: (rawRegex, modifiers = '') ->
+ cleanedRegex = ''
+ len = rawRegex.length
+ mapping = null
+
+ # Cleanup raw regex and compute mapping
+ capturingBracketNumber = 0
+ i = 0
+ while i < len
+ char = rawRegex.charAt(i)
+ if char is '\\'
+ # Ignore next character
+ cleanedRegex += rawRegex[i..i+1]
+ i++
+ else if char is '('
+ # Increase bracket number, only if it is capturing
+ if i < len - 2
+ part = rawRegex[i..i+2]
+ if part is '(?:'
+ # Non-capturing bracket
+ i += 2
+ cleanedRegex += part
+ else if part is '(?<'
+ # Capturing bracket with possibly a name
+ capturingBracketNumber++
+ i += 2
+ name = ''
+ while i + 1 < len
+ subChar = rawRegex.charAt(i + 1)
+ if subChar is '>'
+ cleanedRegex += '('
+ i++
+ if name.length > 0
+ # Associate a name with a capturing bracket number
+ mapping ?= {}
+ mapping[name] = capturingBracketNumber
+ break
+ else
+ name += subChar
+
+ i++
+ else
+ cleanedRegex += char
+ capturingBracketNumber++
+ else
+ cleanedRegex += char
+ else
+ cleanedRegex += char
+
+ i++
+
+ @rawRegex = rawRegex
+ @cleanedRegex = cleanedRegex
+ @regex = new RegExp @cleanedRegex, 'g'+modifiers.replace('g', '')
+ @mapping = mapping
+
+
+ # Executes the pattern's regex and returns the matching values
+ #
+ # @param [String] str The string to use to execute the pattern
+ #
+ # @return [Array] The matching values extracted from capturing brackets or null if nothing matched
+ #
+ exec: (str) ->
+ @regex.lastIndex = 0
+ matches = @regex.exec str
+
+ if not matches?
+ return null
+
+ if @mapping?
+ for name, index of @mapping
+ matches[name] = matches[index]
+
+ return matches
+
+
+ # Tests the pattern's regex
+ #
+ # @param [String] str The string to use to test the pattern
+ #
+ # @return [Boolean] true if the string matched
+ #
+ test: (str) ->
+ @regex.lastIndex = 0
+ return @regex.test str
+
+
+ # Replaces occurences matching with the pattern's regex with replacement
+ #
+ # @param [String] str The source string to perform replacements
+ # @param [String] replacement The string to use in place of each replaced occurence.
+ #
+ # @return [String] The replaced string
+ #
+ replace: (str, replacement) ->
+ @regex.lastIndex = 0
+ return str.replace @regex, replacement
+
+
+ # Replaces occurences matching with the pattern's regex with replacement and
+ # get both the replaced string and the number of replaced occurences in the string.
+ #
+ # @param [String] str The source string to perform replacements
+ # @param [String] replacement The string to use in place of each replaced occurence.
+ # @param [Integer] limit The maximum number of occurences to replace (0 means infinite number of occurences)
+ #
+ # @return [Array] A destructurable array containing the replaced string and the number of replaced occurences. For instance: ["my replaced string", 2]
+ #
+ replaceAll: (str, replacement, limit = 0) ->
+ @regex.lastIndex = 0
+ count = 0
+ while @regex.test(str) and (limit is 0 or count < limit)
+ @regex.lastIndex = 0
+ str = str.replace @regex, ''
+ count++
+
+ return [str, count]
+
+
+module.exports = Pattern
+
diff --git a/src/Unescaper.coffee b/src/Unescaper.coffee
new file mode 100644
index 0000000..c1fe5ae
--- /dev/null
+++ b/src/Unescaper.coffee
@@ -0,0 +1,96 @@
+
+Utils = require './Utils'
+Pattern = require './Pattern'
+
+# Unescaper encapsulates unescaping rules for single and double-quoted YAML strings.
+#
+class Unescaper
+
+ # Regex fragment that matches an escaped character in
+ # a double quoted string.
+ @PATTERN_ESCAPED_CHARACTER: new Pattern '\\\\([0abt\tnvfre "\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})';
+
+
+ # Unescapes a single quoted string.
+ #
+ # @param [String] value A single quoted string.
+ #
+ # @return [String] The unescaped string.
+ #
+ @unescapeSingleQuotedString: (value) ->
+ return value.replace('\'\'', '\'')
+
+
+ # Unescapes a double quoted string.
+ #
+ # @param [String] value A double quoted string.
+ #
+ # @return [String] The unescaped string.
+ #
+ @unescapeDoubleQuotedString: (value) ->
+ @_unescapeCallback ?= (str) =>
+ return @unescapeCharacter(str)
+
+ # Evaluate the string
+ return @PATTERN_ESCAPED_CHARACTER.replace value, @_unescapeCallback
+
+
+ # Unescapes a character that was found in a double-quoted string
+ #
+ # @param [String] value An escaped character
+ #
+ # @return [String] The unescaped character
+ #
+ @unescapeCharacter: (value) ->
+ ch = String.fromCharCode
+ switch value.charAt(1)
+ when '0'
+ return ch(0)
+ when 'a'
+ return ch(7)
+ when 'b'
+ return ch(8)
+ when 't'
+ return "\t"
+ when "\t"
+ return "\t"
+ when 'n'
+ return "\n"
+ when 'v'
+ return ch(11)
+ when 'f'
+ return ch(12)
+ when 'r'
+ return ch(13)
+ when 'e'
+ return ch(27)
+ when ' '
+ return ' '
+ when '"'
+ return '"'
+ when '/'
+ return '/'
+ when '\\'
+ return '\\'
+ when 'N'
+ # U+0085 NEXT LINE
+ return ch(0x0085)
+ when '_'
+ # U+00A0 NO-BREAK SPACE
+ return ch(0x00A0)
+ when 'L'
+ # U+2028 LINE SEPARATOR
+ return ch(0x2028)
+ when 'P'
+ # U+2029 PARAGRAPH SEPARATOR
+ return ch(0x2029)
+ when 'x'
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 2)))
+ when 'u'
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 4)))
+ when 'U'
+ return Utils.utf8chr(Utils.hexDec(value.substr(2, 8)))
+ else
+ return ''
+
+module.exports = Unescaper
diff --git a/src/Utils.coffee b/src/Utils.coffee
new file mode 100644
index 0000000..0a8f336
--- /dev/null
+++ b/src/Utils.coffee
@@ -0,0 +1,342 @@
+
+Pattern = require './Pattern'
+
+# A bunch of utility methods
+#
+class Utils
+
+ @REGEX_LEFT_TRIM_BY_CHAR: {}
+ @REGEX_RIGHT_TRIM_BY_CHAR: {}
+ @REGEX_SPACES: /\s+/g
+ @REGEX_DIGITS: /^\d+$/
+ @REGEX_OCTAL: /[^0-7]/gi
+ @REGEX_HEXADECIMAL: /[^a-f0-9]/gi
+
+ # Precompiled date pattern
+ @PATTERN_DATE: new Pattern '^'+
+ '(?<year>[0-9][0-9][0-9][0-9])'+
+ '-(?<month>[0-9][0-9]?)'+
+ '-(?<day>[0-9][0-9]?)'+
+ '(?:(?:[Tt]|[ \t]+)'+
+ '(?<hour>[0-9][0-9]?)'+
+ ':(?<minute>[0-9][0-9])'+
+ ':(?<second>[0-9][0-9])'+
+ '(?:\.(?<fraction>[0-9]*))?'+
+ '(?:[ \t]*(?<tz>Z|(?<tz_sign>[-+])(?<tz_hour>[0-9][0-9]?)'+
+ '(?::(?<tz_minute>[0-9][0-9]))?))?)?'+
+ '$', 'i'
+
+ # Local timezone offset in ms
+ @LOCAL_TIMEZONE_OFFSET: new Date().getTimezoneOffset() * 60 * 1000
+
+ # Trims the given string on both sides
+ #
+ # @param [String] str The string to trim
+ # @param [String] char The character to use for trimming (default: '\\s')
+ #
+ # @return [String] A trimmed string
+ #
+ @trim: (str, char = '\\s') ->
+ return str.trim()
+ regexLeft = @REGEX_LEFT_TRIM_BY_CHAR[char]
+ unless regexLeft?
+ @REGEX_LEFT_TRIM_BY_CHAR[char] = regexLeft = new RegExp '^'+char+''+char+'*'
+ regexLeft.lastIndex = 0
+ regexRight = @REGEX_RIGHT_TRIM_BY_CHAR[char]
+ unless regexRight?
+ @REGEX_RIGHT_TRIM_BY_CHAR[char] = regexRight = new RegExp char+''+char+'*$'
+ regexRight.lastIndex = 0
+ return str.replace(regexLeft, '').replace(regexRight, '')
+
+
+ # Trims the given string on the left side
+ #
+ # @param [String] str The string to trim
+ # @param [String] char The character to use for trimming (default: '\\s')
+ #
+ # @return [String] A trimmed string
+ #
+ @ltrim: (str, char = '\\s') ->
+ regexLeft = @REGEX_LEFT_TRIM_BY_CHAR[char]
+ unless regexLeft?
+ @REGEX_LEFT_TRIM_BY_CHAR[char] = regexLeft = new RegExp '^'+char+''+char+'*'
+ regexLeft.lastIndex = 0
+ return str.replace(regexLeft, '')
+
+
+ # Trims the given string on the right side
+ #
+ # @param [String] str The string to trim
+ # @param [String] char The character to use for trimming (default: '\\s')
+ #
+ # @return [String] A trimmed string
+ #
+ @rtrim: (str, char = '\\s') ->
+ regexRight = @REGEX_RIGHT_TRIM_BY_CHAR[char]
+ unless regexRight?
+ @REGEX_RIGHT_TRIM_BY_CHAR[char] = regexRight = new RegExp char+''+char+'*$'
+ regexRight.lastIndex = 0
+ return str.replace(regexRight, '')
+
+
+ # Checks if the given value is empty (null, undefined, empty string, string '0')
+ #
+ # @param [Object] value The value to check
+ #
+ # @return [Boolean] true if the value is empty
+ #
+ @isEmpty: (value) ->
+ return not(value) or value is '' or value is '0'
+
+
+ # Counts the number of occurences of subString inside string
+ #
+ # @param [String] string The string where to count occurences
+ # @param [String] subString The subString to count
+ # @param [Integer] start The start index
+ # @param [Integer] length The string length until where to count
+ #
+ # @return [Integer] The number of occurences
+ #
+ @subStrCount: (string, subString, start, length) ->
+ c = 0
+
+ string = '' + string
+ subString = '' + subString
+
+ if start?
+ string = string[start..]
+ if length?
+ string = string[0...length]
+
+ len = string.length
+ sublen = subString.length
+ for i in [0...len]
+ if subString is string[i...sublen]
+ c++
+ i += sublen - 1
+
+ return c
+
+
+ # Returns true if input is only composed of digits
+ #
+ # @param [Object] input The value to test
+ #
+ # @return [Boolean] true if input is only composed of digits
+ #
+ @isDigits: (input) ->
+ @REGEX_DIGITS.lastIndex = 0
+ return @REGEX_DIGITS.test input
+
+
+ # Decode octal value
+ #
+ # @param [String] input The value to decode
+ #
+ # @return [Integer] The decoded value
+ #
+ @octDec: (input) ->
+ @REGEX_OCTAL.lastIndex = 0
+ return parseInt((input+'').replace(@REGEX_OCTAL, ''), 8)
+
+
+ # Decode hexadecimal value
+ #
+ # @param [String] input The value to decode
+ #
+ # @return [Integer] The decoded value
+ #
+ @hexDec: (input) ->
+ @REGEX_HEXADECIMAL.lastIndex = 0
+ input = @trim(input)
+ if (input+'')[0...2] is '0x' then input = (input+'')[2..]
+ return parseInt((input+'').replace(@REGEX_HEXADECIMAL, ''), 16)
+
+
+ # Get the UTF-8 character for the given code point.
+ #
+ # @param [Integer] c The unicode code point
+ #
+ # @return [String] The corresponding UTF-8 character
+ #
+ @utf8chr: (c) ->
+ ch = String.fromCharCode
+ if 0x80 > (c %= 0x200000)
+ return ch(c)
+ if 0x800 > c
+ return ch(0xC0 | c>>6) + ch(0x80 | c & 0x3F)
+ if 0x10000 > c
+ return ch(0xE0 | c>>12) + ch(0x80 | c>>6 & 0x3F) + ch(0x80 | c & 0x3F)
+
+ return ch(0xF0 | c>>18) + ch(0x80 | c>>12 & 0x3F) + ch(0x80 | c>>6 & 0x3F) + ch(0x80 | c & 0x3F)
+
+
+ # Returns the boolean value equivalent to the given input
+ #
+ # @param [String|Object] input The input value
+ # @param [Boolean] strict If set to false, accept 'yes' and 'no' as boolean values
+ #
+ # @return [Boolean] the boolean value
+ #
+ @parseBoolean: (input, strict = true) ->
+ if typeof(input) is 'string'
+ lowerInput = input.toLowerCase()
+ if not strict
+ if lowerInput is 'no' then return false
+ if lowerInput is '0' then return false
+ if lowerInput is 'false' then return false
+ if lowerInput is '' then return false
+ return true
+ return !!input
+
+
+
+ # Returns true if input is numeric
+ #
+ # @param [Object] input The value to test
+ #
+ # @return [Boolean] true if input is numeric
+ #
+ @isNumeric: (input) ->
+ @REGEX_SPACES.lastIndex = 0
+ return typeof(input) is 'number' or typeof(input) is 'string' and !isNaN(input) and input.replace(@REGEX_SPACES, '') isnt ''
+
+
+ # Returns a parsed date from the given string
+ #
+ # @param [String] str The date string to parse
+ #
+ # @return [Date] The parsed date or null if parsing failed
+ #
+ @stringToDate: (str) ->
+ unless str?.length
+ return null
+
+ # Perform regular expression pattern
+ info = @PATTERN_DATE.exec str
+ unless info
+ return null
+
+ # Extract year, month, day
+ year = parseInt info.year, 10
+ month = parseInt(info.month, 10) - 1 # In javascript, january is 0, february 1, etc...
+ day = parseInt info.day, 10
+
+ # If no hour is given, return a date with day precision
+ unless info.hour?
+ date = new Date Date.UTC(year, month, day)
+ return date
+
+ # Extract hour, minute, second
+ hour = parseInt info.hour, 10
+ minute = parseInt info.minute, 10
+ second = parseInt info.second, 10
+
+ # Extract fraction, if given
+ if info.fraction?
+ fraction = info.fraction[0...3]
+ while fraction.length < 3
+ fraction += '0'
+ fraction = parseInt fraction, 10
+ else
+ fraction = 0
+
+ # Compute timezone offset if given
+ if info.tz?
+ tz_hour = parseInt info.tz_hour, 10
+ if info.tz_minute?
+ tz_minute = parseInt info.tz_minute, 10
+ else
+ tz_minute = 0
+
+ # Compute timezone delta in ms
+ tz_offset = (tz_hour * 60 + tz_minute) * 60000
+ if '-' is info.tz_sign
+ tz_offset *= -1
+
+ # Compute date
+ date = new Date Date.UTC(year, month, day, hour, minute, second, fraction)
+ if tz_offset
+ date.setTime date.getTime() + tz_offset
+
+ return date
+
+
+ # Repeats the given string a number of times
+ #
+ # @param [String] str The string to repeat
+ # @param [Integer] number The number of times to repeat the string
+ #
+ # @return [String] The repeated string
+ #
+ @strRepeat: (str, number) ->
+ res = ''
+ i = 0
+ while i < number
+ res += str
+ i++
+ return res
+
+
+ # Reads the data from the given file path and returns the result as string
+ #
+ # @param [String] path The path to the file
+ # @param [Function] callback A callback to read file asynchronously (optional)
+ #
+ # @return [String] The resulting data as string
+ #
+ @getStringFromFile: (path, callback = null) ->
+ xhr = null
+ if window?
+ if window.XMLHttpRequest
+ xhr = new XMLHttpRequest()
+ else if window.ActiveXObject
+ for name in ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]
+ try
+ xhr = new ActiveXObject(name)
+
+ if xhr?
+ # Browser
+ if callback?
+ # Async
+ xhr.onreadystatechange = ->
+ if xhr.readyState is 4
+ if xhr.status is 200 or xhr.status is 0
+ callback(xhr.responseText)
+ else
+ callback(null)
+ xhr.open 'GET', path, true
+ xhr.send null
+
+ else
+ # Sync
+ xhr.open 'GET', path, false
+ xhr.send null
+
+ if xhr.status is 200 or xhr.status == 0
+ return xhr.responseText
+
+ return null
+ else
+ # Node.js-like
+ req = require
+ fs = req('fs') # Prevent browserify from trying to load 'fs' module
+ if callback?
+ # Async
+ fs.readFile path, (err, data) ->
+ if err
+ callback null
+ else
+ callback data
+
+ else
+ # Sync
+ data = fs.readFileSync path
+ if data?
+ return ''+data
+ return null
+
+
+
+module.exports = Utils
diff --git a/src/Yaml.coffee b/src/Yaml.coffee
new file mode 100644
index 0000000..fd16cd2
--- /dev/null
+++ b/src/Yaml.coffee
@@ -0,0 +1,113 @@
+
+Parser = require './Parser'
+Dumper = require './Dumper'
+Utils = require './Utils'
+
+# Yaml offers convenience methods to load and dump YAML.
+#
+class Yaml
+
+ # Parses YAML into a JavaScript object.
+ #
+ # The parse method, when supplied with a YAML string,
+ # will do its best to convert YAML in a file into a JavaScript object.
+ #
+ # Usage:
+ # myObject = Yaml.parse('some: yaml');
+ # console.log(myObject);
+ #
+ # @param [String] input A string containing YAML
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types, false otherwise
+ # @param [Function] objectDecoder A function to deserialize custom objects, null otherwise
+ #
+ # @return [Object] The YAML converted to a JavaScript object
+ #
+ # @throw [ParseException] If the YAML is not valid
+ #
+ @parse: (input, exceptionOnInvalidType = false, objectDecoder = null) ->
+ return new Parser().parse(input, exceptionOnInvalidType, objectDecoder)
+
+
+ # Parses YAML from file path into a JavaScript object.
+ #
+ # The parseFile method, when supplied with a YAML file,
+ # will do its best to convert YAML in a file into a JavaScript object.
+ #
+ # Usage:
+ # myObject = Yaml.parseFile('config.yml');
+ # console.log(myObject);
+ #
+ # @param [String] path A file path pointing to a valid YAML file
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types, false otherwise
+ # @param [Function] objectDecoder A function to deserialize custom objects, null otherwise
+ #
+ # @return [Object] The YAML converted to a JavaScript object or null if the file doesn't exist.
+ #
+ # @throw [ParseException] If the YAML is not valid
+ #
+ @parseFile: (path, callback = null, exceptionOnInvalidType = false, objectDecoder = null) ->
+ if callback?
+ # Async
+ Utils.getStringFromFile path, (input) =>
+ if input?
+ return @parse input, exceptionOnInvalidType, objectDecoder
+ return null
+ else
+ # Sync
+ input = Utils.getStringFromFile path
+ if input?
+ return @parse input, exceptionOnInvalidType, objectDecoder
+ return null
+
+
+ # Dumps a JavaScript object to a YAML string.
+ #
+ # The dump method, when supplied with an object, will do its best
+ # to convert the object into friendly YAML.
+ #
+ # @param [Object] input JavaScript object
+ # @param [Integer] inline The level where you switch to inline YAML
+ # @param [Integer] indent The amount of spaces to use for indentation of nested nodes.
+ # @param [Boolean] exceptionOnInvalidType true if an exception must be thrown on invalid types (a JavaScript resource or object), false otherwise
+ # @param [Function] objectEncoder A function to serialize custom objects, null otherwise
+ #
+ # @return [String] A YAML string representing the original JavaScript object
+ #
+ @dump: (input, inline = 2, indent = 4, exceptionOnInvalidType = false, objectEncoder = null) ->
+ yaml = new Dumper()
+ yaml.indentation = indent
+
+ return yaml.dump(input, inline, 0, exceptionOnInvalidType, objectEncoder)
+
+
+ # Registers .yml extension to work with node's require() function.
+ #
+ @register: ->
+ require_handler = (module, filename) ->
+ # Fill in result
+ module.exports = YAML.parseFile filename
+
+ # Register require extensions only if we're on node.js
+ # hack for browserify
+ if require?.extensions?
+ require.extensions['.yml'] = require_handler
+ require.extensions['.yaml'] = require_handler
+
+
+ # Alias of dump() method for compatibility reasons.
+ #
+ stringify: (input, inline, indent, exceptionOnInvalidType, objectEncoder) ->
+ return @dump input, inline, indent, exceptionOnInvalidType, objectEncoder
+
+
+ # Alias of parseFile() method for compatibility reasons.
+ #
+ load: (path, callback, exceptionOnInvalidType, objectDecoder) ->
+ return @parseFile path, callback, exceptionOnInvalidType, objectDecoder
+
+
+# Expose YAML namespace to browser
+window?.YAML = Yaml
+
+module.exports = Yaml
+
diff --git a/src/yaml/Yaml.js b/src/yaml/Yaml.js
deleted file mode 100644
index 8a7af0f..0000000
--- a/src/yaml/Yaml.js
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * Yaml offers convenience methods to parse and dump YAML.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-
-var YamlRunningUnderNode = false;
-var Yaml = function(){};
-Yaml.prototype =
-{
-
- /**
- * Parses YAML into a JS representation.
- *
- * The parse method, when supplied with a YAML stream (file),
- * will do its best to convert YAML in a file into a JS representation.
- *
- * Usage:
- * <code>
- * obj = yaml.parseFile('config.yml');
- * </code>
- *
- * @param string input Path of YAML file
- *
- * @return array The YAML converted to a JS representation
- *
- * @throws YamlParseException If the YAML is not valid
- */
- parseFile: function(file /* String */, callback /* Function */)
- {
- if ( callback == null )
- {
- var input = this.getFileContents(file);
- var ret = null;
- try
- {
- ret = this.parse(input);
- }
- catch ( e )
- {
- if ( e instanceof YamlParseException ) {
- e.setParsedFile(file);
- }
- throw e;
- }
- return ret;
- }
-
- this.getFileContents(file, function(data)
- {
- callback(new Yaml().parse(data));
- });
- },
-
- /**
- * Parses YAML into a JS representation.
- *
- * The parse method, when supplied with a YAML stream (string),
- * will do its best to convert YAML into a JS representation.
- *
- * Usage:
- * <code>
- * obj = yaml.parse(...);
- * </code>
- *
- * @param string input string containing YAML
- *
- * @return array The YAML converted to a JS representation
- *
- * @throws YamlParseException If the YAML is not valid
- */
- parse: function(input /* String */)
- {
- var yaml = new YamlParser();
-
- return yaml.parse(input);
- },
-
- /**
- * Dumps a JS representation to a YAML string.
- *
- * The dump method, when supplied with an array, will do its best
- * to convert the array into friendly YAML.
- *
- * @param array array JS representation
- * @param integer inline The level where you switch to inline YAML
- *
- * @return string A YAML string representing the original JS representation
- *
- * @api
- */
- dump: function(array, inline, spaces)
- {
- if ( inline == null ) inline = 2;
-
- var yaml = new YamlDumper();
- if (spaces) {
- yaml.numSpacesForIndentation = spaces;
- }
-
- return yaml.dump(array, inline);
- },
-
- getXHR: function()
- {
- if ( window.XMLHttpRequest )
- return new XMLHttpRequest();
-
- if ( window.ActiveXObject )
- {
- var names = [
- "Msxml2.XMLHTTP.6.0",
- "Msxml2.XMLHTTP.3.0",
- "Msxml2.XMLHTTP",
- "Microsoft.XMLHTTP"
- ];
-
- for ( var i = 0; i < 4; i++ )
- {
- try{ return new ActiveXObject(names[i]); }
- catch(e){}
- }
- }
- return null;
- },
-
- getFileContents: function(file, callback)
- {
- if ( YamlRunningUnderNode )
- {
- var fs = require('fs');
- if ( callback == null )
- {
- var data = fs.readFileSync(file);
- if (data == null) return null;
- return ''+data;
- }
- else
- {
- fs.readFile(file, function(err, data)
- {
- if (err)
- callback(null);
- else
- callback(data);
- });
- }
- }
- else
- {
- var request = this.getXHR();
-
- // Sync
- if ( callback == null )
- {
- request.open('GET', file, false);
- request.send(null);
-
- if ( request.status == 200 || request.status == 0 )
- return request.responseText;
-
- return null;
- }
-
- // Async
- request.onreadystatechange = function()
- {
- if ( request.readyState == 4 )
- if ( request.status == 200 || request.status == 0 )
- callback(request.responseText);
- else
- callback(null);
- };
- request.open('GET', file, true);
- request.send(null);
- }
- }
-};
-
-var YAML =
-{
- /*
- * @param integer inline The level where you switch to inline YAML
- */
-
- stringify: function(input, inline, spaces)
- {
- return new Yaml().dump(input, inline, spaces);
- },
-
- parse: function(input)
- {
- return new Yaml().parse(input);
- },
-
- load: function(file, callback)
- {
- return new Yaml().parseFile(file, callback);
- }
-};
-
-// Handle node.js case
-if (typeof exports !== 'undefined') {
- if (typeof module !== 'undefined' && module.exports) {
- exports = module.exports = YAML;
- YamlRunningUnderNode = true;
-
- // Add require handler
- (function () {
- var require_handler = function (module, filename) {
- // fill in result
- module.exports = YAML.load(filename);
- };
-
- // register require extensions only if we're on node.js
- // hack for browserify
- if ( undefined !== require.extensions ) {
- require.extensions['.yml'] = require_handler;
- require.extensions['.yaml'] = require_handler;
- }
- }());
- }
-}
-
-// Handle browser case
-if ( typeof(window) != "undefined" )
-{
- window.YAML = YAML;
-}
diff --git a/src/yaml/YamlDumper.js b/src/yaml/YamlDumper.js
deleted file mode 100644
index b1881f3..0000000
--- a/src/yaml/YamlDumper.js
+++ /dev/null
@@ -1,131 +0,0 @@
-
-/**
- * YamlDumper dumps JS variables to YAML strings.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
-var YamlDumper = function(){};
-YamlDumper.prototype =
-{
- /**
- * Dumps a JS value to YAML.
- *
- * @param mixed input The JS value
- * @param integer inline The level where you switch to inline YAML
- * @param integer indent The level o indentation indentation (used internally)
- *
- * @return string The YAML representation of the JS value
- */
- dump: function(input, inline, indent)
- {
- if ( inline == null ) inline = 0;
- if ( indent == null ) indent = 0;
- var output = '';
- var prefix = indent ? this.strRepeat(' ', indent) : '';
- var yaml;
- if (!this.numSpacesForIndentation) this.numSpacesForIndentation = 2;
-
- if ( inline <= 0 || !this.isObject(input) || this.isEmpty(input) )
- {
- yaml = new YamlInline();
- output += prefix + yaml.dump(input);
- }
- else
- {
- var isAHash = !this.arrayEquals(this.getKeys(input), this.range(0,input.length - 1));
- var willBeInlined;
-
- for ( var key in input )
- {
- if ( input.hasOwnProperty(key) )
- {
- willBeInlined = inline - 1 <= 0 || !this.isObject(input[key]) || this.isEmpty(input[key]);
-
- if ( isAHash ) yaml = new YamlInline();
-
- output +=
- prefix + '' +
- (isAHash ? yaml.dump(key)+':' : '-') + '' +
- (willBeInlined ? ' ' : "\n") + '' +
- this.dump(input[key], inline - 1, (willBeInlined ? 0 : indent + this.numSpacesForIndentation)) + '' +
- (willBeInlined ? "\n" : '');
- }
- }
- }
-
- return output;
- },
-
- strRepeat: function(str /* String */, count /* Integer */)
- {
- var i;
- var result = '';
- for ( i = 0; i < count; i++ ) result += str;
- return result;
- },
-
- isObject: function(input)
- {
- return this.isDefined(input) && typeof(input) == 'object';
- },
-
- isEmpty: function(input)
- {
- var ret = input == undefined || input == null || input == '' || input == 0 || input == "0" || input == false;
- if ( !ret && typeof(input) == "object" && !(input instanceof Array)){
- var propCount = 0;
- for ( var key in input )
- if ( input.hasOwnProperty(key) ) propCount++;
- ret = !propCount;
- }
- return ret;
- },
-
- isDefined: function(input)
- {
- return input != undefined && input != null;
- },
-
- getKeys: function(tab)
- {
- var ret = [];
-
- for ( var name in tab )
- {
- if ( tab.hasOwnProperty(name) )
- {
- ret.push(name);
- }
- }
-
- return ret;
- },
-
- range: function(start, end)
- {
- if ( start > end ) return [];
-
- var ret = [];
-
- for ( var i = start; i <= end; i++ )
- {
- ret.push(i);
- }
-
- return ret;
- },
-
- arrayEquals: function(a,b)
- {
- if ( a.length != b.length ) return false;
-
- var len = a.length;
-
- for ( var i = 0; i < len; i++ )
- {
- if ( a[i] != b[i] ) return false;
- }
-
- return true;
- }
-};
diff --git a/src/yaml/YamlEscaper.js b/src/yaml/YamlEscaper.js
deleted file mode 100644
index 8714c51..0000000
--- a/src/yaml/YamlEscaper.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * YamlEscaper encapsulates escaping rules for single and double-quoted
- * YAML strings.
- *
- * @author Matthew Lewinski <matthew@lewinski.org>
- */
-YamlEscaper = function(){};
-YamlEscaper.prototype =
-{
- /**
- * Determines if a JS value would require double quoting in YAML.
- *
- * @param string value A JS value
- *
- * @return Boolean True if the value would require double quotes.
- */
- requiresDoubleQuoting: function(value)
- {
- return new RegExp(YamlEscaper.REGEX_CHARACTER_TO_ESCAPE).test(value);
- },
-
- /**
- * Escapes and surrounds a JS value with double quotes.
- *
- * @param string value A JS value
- *
- * @return string The quoted, escaped string
- */
- escapeWithDoubleQuotes: function(value)
- {
- value = value + '';
- var len = YamlEscaper.escapees.length;
- var maxlen = YamlEscaper.escaped.length;
- var esc = YamlEscaper.escaped;
- for (var i = 0; i < len; ++i)
- if ( i >= maxlen ) esc.push('');
-
- var ret = '';
- ret = value.replace(new RegExp(YamlEscaper.escapees.join('|'),'g'), function(str){
- for(var i = 0; i < len; ++i){
- if( str == YamlEscaper.escapees[i] )
- return esc[i];
- }
- });
- return '"' + ret + '"';
- },
-
- /**
- * Determines if a JS value would require single quoting in YAML.
- *
- * @param string value A JS value
- *
- * @return Boolean True if the value would require single quotes.
- */
- requiresSingleQuoting: function(value)
- {
- return /[\s'":{}[\],&*#?]|^[-?|<>=!%@`]/.test(value);
- },
-
- /**
- * Escapes and surrounds a JS value with single quotes.
- *
- * @param string value A JS value
- *
- * @return string The quoted, escaped string
- */
- escapeWithSingleQuotes : function(value)
- {
- return "'" + value.replace(/'/g, "''") + "'";
- }
-};
-
-// Characters that would cause a dumped string to require double quoting.
-YamlEscaper.REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";
-
-// Mapping arrays for escaping a double quoted string. The backslash is
-// first to ensure proper escaping.
-YamlEscaper.escapees = ['\\\\', '\\"', '"',
- "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
- "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
- "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
- "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
- "\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9"];
-YamlEscaper.escaped = ['\\"', '\\\\', '\\"',
- "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a",
- "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f",
- "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17",
- "\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", "\\x1f",
- "\\N", "\\_", "\\L", "\\P"];
diff --git a/src/yaml/YamlInline.js b/src/yaml/YamlInline.js
deleted file mode 100644
index 0548512..0000000
--- a/src/yaml/YamlInline.js
+++ /dev/null
@@ -1,558 +0,0 @@
-
-/**
- * YamlInline implements a YAML parser/dumper for the YAML inline syntax.
- */
-var YamlInline = function(){};
-YamlInline.prototype =
-{
- i: null,
-
- /**
- * Convert a YAML string to a JS object.
- *
- * @param string value A YAML string
- *
- * @return object A JS object representing the YAML string
- */
- parse: function(value)
- {
- var result = null;
- value = this.trim(value);
-
- if ( 0 == value.length )
- {
- return '';
- }
-
- switch ( value.charAt(0) )
- {
- case '[':
- result = this.parseSequence(value);
- break;
- case '{':
- result = this.parseMapping(value);
- break;
- default:
- result = this.parseScalar(value);
- }
-
- // some comment can end the scalar
- if ( value.substr(this.i+1).replace(/^\s*#.*$/, '') != '' ) {
- console.log("oups "+value.substr(this.i+1));
- throw new YamlParseException('Unexpected characters near "'+value.substr(this.i)+'".');
- }
-
- return result;
- },
-
- /**
- * Dumps a given JS variable to a YAML string.
- *
- * @param mixed value The JS variable to convert
- *
- * @return string The YAML string representing the JS object
- */
- dump: function(value)
- {
- if ( undefined == value || null == value )
- return 'null';
- if ( value instanceof Date)
- return value.toISOString();
- if ( typeof(value) == 'object')
- return this.dumpObject(value);
- if ( typeof(value) == 'boolean' )
- return value ? 'true' : 'false';
- if ( /^\d+$/.test(value) )
- return typeof(value) == 'string' ? "'"+value+"'" : parseInt(value);
- if ( this.isNumeric(value) )
- return typeof(value) == 'string' ? "'"+value+"'" : parseFloat(value);
- if ( typeof(value) == 'number' )
- return value == Infinity ? '.Inf' : ( value == -Infinity ? '-.Inf' : ( isNaN(value) ? '.NAN' : value ) );
- var yaml = new YamlEscaper();
- if ( yaml.requiresDoubleQuoting(value) )
- return yaml.escapeWithDoubleQuotes(value);
- if ( yaml.requiresSingleQuoting(value) )
- return yaml.escapeWithSingleQuotes(value);
- if ( '' == value )
- return '""';
- if ( this.getTimestampRegex().test(value) )
- return "'"+value+"'";
- if ( this.inArray(value.toLowerCase(), ['null','~','true','false']) )
- return "'"+value+"'";
- // default
- return value;
- },
-
- /**
- * Dumps a JS object to a YAML string.
- *
- * @param object value The JS array to dump
- *
- * @return string The YAML string representing the JS object
- */
- dumpObject: function(value)
- {
- var keys = this.getKeys(value);
- var output = null;
- var i;
- var len = keys.length;
-
- // array
- if ( value instanceof Array )
- /*( 1 == len && '0' == keys[0] )
- ||
- ( len > 1 && this.reduceArray(keys, function(v,w){return Math.floor(v+w);}, 0) == len * (len - 1) / 2) )*/
- {
- output = [];
- for ( i = 0; i < len; i++ )
- {
- output.push(this.dump(value[keys[i]]));
- }
-
- return '['+output.join(', ')+']';
- }
-
- // mapping
- output = [];
- for ( i = 0; i < len; i++ )
- {
- output.push(this.dump(keys[i])+': '+this.dump(value[keys[i]]));
- }
-
- return '{ '+output.join(', ')+' }';
- },
-
- /**
- * Parses a scalar to a YAML string.
- *
- * @param scalar scalar
- * @param string delimiters
- * @param object stringDelimiters
- * @param integer i
- * @param boolean evaluate
- *
- * @return string A YAML string
- *
- * @throws YamlParseException When malformed inline YAML string is parsed
- */
- parseScalar: function(scalar, delimiters, stringDelimiters, i, evaluate)
- {
- if ( delimiters == undefined ) delimiters = null;
- if ( stringDelimiters == undefined ) stringDelimiters = ['"', "'"];
- if ( i == undefined ) i = 0;
- if ( evaluate == undefined ) evaluate = true;
-
- var output = null;
- var pos = null;
- var matches = null;
-
- if ( this.inArray(scalar[i], stringDelimiters) )
- {
- // quoted scalar
- output = this.parseQuotedScalar(scalar, i);
- i = this.i;
- if (null !== delimiters) {
- var tmp = scalar.substr(i).replace(/^\s+/, '');
- if (!this.inArray(tmp.charAt(0), delimiters)) {
- throw new YamlParseException('Unexpected characters ('+scalar.substr(i)+').');
- }
- }
- }
- else
- {
- // "normal" string
- if ( !delimiters )
- {
- output = (scalar+'').substring(i);
-
- i += output.length;
-
- // remove comments
- pos = output.indexOf(' #');
- if ( pos != -1 )
- {
- output = output.substr(0, pos).replace(/\s+$/g,'');
- }
- }
- else if ( matches = new RegExp('^(.+?)('+delimiters.join('|')+')').exec((scalar+'').substring(i)) )
- {
- output = matches[1];
- i += output.length;
- }
- else
- {
- throw new YamlParseException('Malformed inline YAML string ('+scalar+').');
- }
- output = evaluate ? this.evaluateScalar(output) : output;
- }
-
- this.i = i;
-
- return output;
- },
-
- /**
- * Parses a quoted scalar to YAML.
- *
- * @param string scalar
- * @param integer i
- *
- * @return string A YAML string
- *
- * @throws YamlParseException When malformed inline YAML string is parsed
- */
- parseQuotedScalar: function(scalar, i)
- {
- var matches = null;
- //var item = /^(.*?)['"]\s*(?:[,:]|[}\]]\s*,)/.exec((scalar+'').substring(i))[1];
-
- if ( !(matches = new RegExp('^'+YamlInline.REGEX_QUOTED_STRING).exec((scalar+'').substring(i))) )
- {
- throw new YamlParseException('Malformed inline YAML string ('+(scalar+'').substring(i)+').');
- }
-
- var output = matches[0].substr(1, matches[0].length - 2);
-
- var unescaper = new YamlUnescaper();
-
- if ( '"' == (scalar+'').charAt(i) )
- {
- output = unescaper.unescapeDoubleQuotedString(output);
- }
- else
- {
- output = unescaper.unescapeSingleQuotedString(output);
- }
-
- i += matches[0].length;
-
- this.i = i;
- return output;
- },
-
- /**
- * Parses a sequence to a YAML string.
- *
- * @param string sequence
- * @param integer i
- *
- * @return string A YAML string
- *
- * @throws YamlParseException When malformed inline YAML string is parsed
- */
- parseSequence: function(sequence, i)
- {
- if ( i == undefined ) i = 0;
-
- var output = [];
- var len = sequence.length;
- i += 1;
-
- // [foo, bar, ...]
- while ( i < len )
- {
- switch ( sequence.charAt(i) )
- {
- case '[':
- // nested sequence
- output.push(this.parseSequence(sequence, i));
- i = this.i;
- break;
- case '{':
- // nested mapping
- output.push(this.parseMapping(sequence, i));
- i = this.i;
- break;
- case ']':
- this.i = i;
- return output;
- case ',':
- case ' ':
- break;
- default:
- var isQuoted = this.inArray(sequence.charAt(i), ['"', "'"]);
- var value = this.parseScalar(sequence, [',', ']'], ['"', "'"], i);
- i = this.i;
-
- if ( !isQuoted && (value+'').indexOf(': ') != -1 )
- {
- // embedded mapping?
- try
- {
- value = this.parseMapping('{'+value+'}');
- }
- catch ( e )
- {
- if ( !(e instanceof YamlParseException ) ) throw e;
- // no, it's not
- }
- }
-
- output.push(value);
-
- i--;
- }
-
- i++;
- }
-
- throw new YamlParseException('Malformed inline YAML string "'+sequence+'"');
- },
-
- /**
- * Parses a mapping to a YAML string.
- *
- * @param string mapping
- * @param integer i
- *
- * @return string A YAML string
- *
- * @throws YamlParseException When malformed inline YAML string is parsed
- */
- parseMapping: function(mapping, i)
- {
- if ( i == undefined ) i = 0;
- var output = {};
- var len = mapping.length;
- i += 1;
- var done = false;
- var doContinue = false;
-
- // {foo: bar, bar:foo, ...}
- while ( i < len )
- {
- doContinue = false;
-
- switch ( mapping.charAt(i) )
- {
- case ' ':
- case ',':
- i++;
- doContinue = true;
- break;
- case '}':
- this.i = i;
- return output;
- }
-
- if ( doContinue ) continue;
-
- // key
- var key = this.parseScalar(mapping, [':', ' '], ['"', "'"], i, false);
- i = this.i;
-
- // value
- done = false;
- while ( i < len )
- {
- switch ( mapping.charAt(i) )
- {
- case '[':
- // nested sequence
- output[key] = this.parseSequence(mapping, i);
- i = this.i;
- done = true;
- break;
- case '{':
- // nested mapping
- output[key] = this.parseMapping(mapping, i);
- i = this.i;
- done = true;
- break;
- case ':':
- case ' ':
- break;
- default:
- output[key] = this.parseScalar(mapping, [',', '}'], ['"', "'"], i);
- i = this.i;
- done = true;
- i--;
- }
-
- ++i;
-
- if ( done )
- {
- doContinue = true;
- break;
- }
- }
-
- if ( doContinue ) continue;
- }
-
- throw new YamlParseException('Malformed inline YAML string "'+mapping+'"');
- },
-
- /**
- * Evaluates scalars and replaces magic values.
- *
- * @param string scalar
- *
- * @return string A YAML string
- */
- evaluateScalar: function(scalar)
- {
- scalar = this.trim(scalar);
-
- var raw = null;
- var cast = null;
-
- if ( ( 'null' == scalar.toLowerCase() ) ||
- ( '' == scalar ) ||
- ( '~' == scalar ) )
- return null;
- if ( (scalar+'').indexOf('!str ') == 0 )
- return (''+scalar).substring(5);
- if ( (scalar+'').indexOf('! ') == 0 )
- return parseInt(this.parseScalar((scalar+'').substr(2)));
- if ( /^\d+$/.test(scalar) )
- {
- raw = scalar;
- cast = parseInt(scalar);
- return '0' == scalar.charAt(0) ? this.octdec(scalar) : (( ''+raw == ''+cast ) ? cast : raw);
- }
- if ( 'true' == (scalar+'').toLowerCase() )
- return true;
- if ( 'false' == (scalar+'').toLowerCase() )
- return false;
- if ( this.isNumeric(scalar) )
- return '0x' == (scalar+'').substr(0, 2) ? this.hexdec(scalar) : parseFloat(scalar);
- if ( scalar.toLowerCase() == '.inf' )
- return Infinity;
- if ( scalar.toLowerCase() == '.nan' )
- return NaN;
- if ( scalar.toLowerCase() == '-.inf' )
- return -Infinity;
- if ( /^(-|\+)?[0-9,]+(\.[0-9]+)?$/.test(scalar) )
- return parseFloat(scalar.split(',').join(''));
- if ( this.getTimestampRegex().test(scalar) )
- return new Date(this.strtotime(scalar));
- //else
- return ''+scalar;
- },
-
- /**
- * Gets a regex that matches an unix timestamp
- *
- * @return string The regular expression
- */
- getTimestampRegex: function()
- {
- return new RegExp('^'+
- '([0-9][0-9][0-9][0-9])'+
- '-([0-9][0-9]?)'+
- '-([0-9][0-9]?)'+
- '(?:(?:[Tt]|[ \t]+)'+
- '([0-9][0-9]?)'+
- ':([0-9][0-9])'+
- ':([0-9][0-9])'+
- '(?:\.([0-9]*))?'+
- '(?:[ \t]*(Z|([-+])([0-9][0-9]?)'+
- '(?::([0-9][0-9]))?))?)?'+
- '$','gi');
- },
-
- trim: function(str /* String */)
- {
- return (str+'').replace(/^\s+/,'').replace(/\s+$/,'');
- },
-
- isNumeric: function(input)
- {
- return (input - 0) == input && input.length > 0 && input.replace(/\s+/g,'') != '';
- },
-
- inArray: function(key, tab)
- {
- var i;
- var len = tab.length;
- for ( i = 0; i < len; i++ )
- {
- if ( key == tab[i] ) return true;
- }
- return false;
- },
-
- getKeys: function(tab)
- {
- var ret = [];
-
- for ( var name in tab )
- {
- if ( tab.hasOwnProperty(name) )
- {
- ret.push(name);
- }
- }
-
- return ret;
- },
-
- /*reduceArray: function(tab, fun)
- {
- var len = tab.length;
- if (typeof fun != "function")
- throw new YamlParseException("fun is not a function");
-
- // no value to return if no initial value and an empty array
- if (len == 0 && arguments.length == 1)
- throw new YamlParseException("empty array");
-
- var i = 0;
- if (arguments.length >= 2)
- {
- var rv = arguments[1];
- }
- else
- {
- do
- {
- if (i in tab)
- {
- rv = tab[i++];
- break;
- }
-
- // if array contains no values, no initial value to return
- if (++i >= len)
- throw new YamlParseException("no initial value to return");
- }
- while (true);
- }
-
- for (; i < len; i++)
- {
- if (i in tab)
- rv = fun.call(null, rv, tab[i], i, tab);
- }
-
- return rv;
- },*/
-
- octdec: function(input)
- {
- return parseInt((input+'').replace(/[^0-7]/gi, ''), 8);
- },
-
- hexdec: function(input)
- {
- input = this.trim(input);
- if ( (input+'').substr(0, 2) == '0x' ) input = (input+'').substring(2);
- return parseInt((input+'').replace(/[^a-f0-9]/gi, ''), 16);
- },
-
- /**
- * @see http://phpjs.org/functions/strtotime
- * @note we need timestamp with msecs so /1000 removed
- * @note original contained binary | 0 (wtf?!) everywhere, which messes everything up
- */
- strtotime: function (h,b){var f,c,g,k,d="";h=(h+"").replace(/\s{2,}|^\s|\s$/g," ").replace(/[\t\r\n]/g,"");if(h==="now"){return b===null||isNaN(b)?new Date().getTime()||0:b||0}else{if(!isNaN(d=Date.parse(h))){return d||0}else{if(b){b=new Date(b)}else{b=new Date()}}}h=h.toLowerCase();var e={day:{sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6},mon:["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]};var a=function(i){var o=(i[2]&&i[2]==="ago");var n=(n=i[0]==="last"?-1:1)*(o?-1:1);switch(i[0]){case"last":case"next":switch(i[1].substring(0,3)){case"yea":b.setFullYear(b.getFullYear()+n);break;case"wee":b.setDate(b.getDate()+(n*7));break;case"day":b.setDate(b.getDate()+n);break;case"hou":b.setHours(b.getHours()+n);break;case"min":b.setMinutes(b.getMinutes()+n);break;case"sec":b.setSeconds(b.getSeconds()+n);break;case"mon":if(i[1]==="month"){b.setMonth(b.getMonth()+n);break}default:var l=e.day[i[1].substring(0,3)];if(typeof l!=="undefined"){var p=l-b.getDay();if(p===0){p=7*n}else{if(p>0){if(i[0]==="last"){p-=7}}else{if(i[0]==="next"){p+=7}}}b.setDate(b.getDate()+p);b.setHours(0,0,0,0)}}break;default:if(/\d+/.test(i[0])){n*=parseInt(i[0],10);switch(i[1].substring(0,3)){case"yea":b.setFullYear(b.getFullYear()+n);break;case"mon":b.setMonth(b.getMonth()+n);break;case"wee":b.setDate(b.getDate()+(n*7));break;case"day":b.setDate(b.getDate()+n);break;case"hou":b.setHours(b.getHours()+n);break;case"min":b.setMinutes(b.getMinutes()+n);break;case"sec":b.setSeconds(b.getSeconds()+n);break}}else{return false}break}return true};g=h.match(/^(\d{2,4}-\d{2}-\d{2})(?:\s(\d{1,2}:\d{2}(:\d{2})?)?(?:\.(\d+))?)?$/);if(g!==null){if(!g[2]){g[2]="00:00:00"}else{if(!g[3]){g[2]+=":00"}}k=g[1].split(/-/g);k[1]=e.mon[k[1]-1]||k[1];k[0]=+k[0];k[0]=(k[0]>=0&&k[0]<=69)?"20"+(k[0]<10?"0"+k[0]:k[0]+""):(k[0]>=70&&k[0]<=99)?"19"+k[0]:k[0]+"";return parseInt(this.strtotime(k[2]+" "+k[1]+" "+k[0]+" "+g[2])+(g[4]?g[4]:""),10)}var j="([+-]?\\d+\\s(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday)|(last|next)\\s(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday))(\\sago)?";g=h.match(new RegExp(j,"gi"));if(g===null){return false}for(f=0,c=g.length;f<c;f++){if(!a(g[f].split(" "))){return false}}return b.getTime()||0}
-
-};
-
-/*
- * @note uses only non-capturing sub-patterns (unlike PHP original)
- */
-YamlInline.REGEX_QUOTED_STRING = '(?:"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\']*(?:\'\'[^\']*)*)\')';
-
diff --git a/src/yaml/YamlParseException.js b/src/yaml/YamlParseException.js
deleted file mode 100644
index b926941..0000000
--- a/src/yaml/YamlParseException.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/**
- * Exception class thrown when an error occurs during parsing.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @api
- */
-
-/**
- * Constructor.
- *
- * @param string message The error message
- * @param integer parsedLine The line where the error occurred
- * @param integer snippet The snippet of code near the problem
- * @param string parsedFile The file name where the error occurred
- */
-
-var YamlParseException = function(message, parsedLine, snippet, parsedFile){
-
- this.rawMessage = message;
- this.parsedLine = (parsedLine !== undefined) ? parsedLine : -1;
- this.snippet = (snippet !== undefined) ? snippet : null;
- this.parsedFile = (parsedFile !== undefined) ? parsedFile : null;
-
- this.updateRepr();
-
- this.message = message;
-
-};
-YamlParseException.prototype =
-{
-
- name: 'YamlParseException',
- message: null,
-
- parsedFile: null,
- parsedLine: -1,
- snippet: null,
- rawMessage: null,
-
- isDefined: function(input)
- {
- return input != undefined && input != null;
- },
-
- /**
- * Gets the snippet of code near the error.
- *
- * @return string The snippet of code
- */
- getSnippet: function()
- {
- return this.snippet;
- },
-
- /**
- * Sets the snippet of code near the error.
- *
- * @param string snippet The code snippet
- */
- setSnippet: function(snippet)
- {
- this.snippet = snippet;
-
- this.updateRepr();
- },
-
- /**
- * Gets the filename where the error occurred.
- *
- * This method returns null if a string is parsed.
- *
- * @return string The filename
- */
- getParsedFile: function()
- {
- return this.parsedFile;
- },
-
- /**
- * Sets the filename where the error occurred.
- *
- * @param string parsedFile The filename
- */
- setParsedFile: function(parsedFile)
- {
- this.parsedFile = parsedFile;
-
- this.updateRepr();
- },
-
- /**
- * Gets the line where the error occurred.
- *
- * @return integer The file line
- */
- getParsedLine: function()
- {
- return this.parsedLine;
- },
-
- /**
- * Sets the line where the error occurred.
- *
- * @param integer parsedLine The file line
- */
- setParsedLine: function(parsedLine)
- {
- this.parsedLine = parsedLine;
-
- this.updateRepr();
- },
-
- updateRepr: function()
- {
- this.message = this.rawMessage;
-
- var dot = false;
- if ('.' === this.message.charAt(this.message.length - 1)) {
- this.message = this.message.substring(0, this.message.length - 1);
- dot = true;
- }
-
- if (null !== this.parsedFile) {
- this.message += ' in ' + JSON.stringify(this.parsedFile);
- }
-
- if (this.parsedLine >= 0) {
- this.message += ' at line ' + this.parsedLine;
- }
-
- if (this.snippet) {
- this.message += ' (near "' + this.snippet + '")';
- }
-
- if (dot) {
- this.message += '.';
- }
- }
-}
diff --git a/src/yaml/YamlParser.js b/src/yaml/YamlParser.js
deleted file mode 100644
index 2e091d4..0000000
--- a/src/yaml/YamlParser.js
+++ /dev/null
@@ -1,807 +0,0 @@
-
-/**
- * YamlParser parses YAML strings to convert them to JS objects
- * (port of Yaml Symfony Component)
- */
-var YamlParser = function(offset /* Integer */)
-{
- this.offset = (offset !== undefined) ? offset : 0;
-};
-YamlParser.prototype =
-{
- offset: 0,
- lines: [],
- currentLineNb: -1,
- currentLine: '',
- refs: {},
-
- /**
- * Parses a YAML string to a JS value.
- *
- * @param String value A YAML string
- *
- * @return mixed A JS value
- */
- parse: function(value /* String */)
- {
- this.currentLineNb = -1;
- this.currentLine = '';
- this.lines = this.cleanup(value).split("\n");
-
- var data = null;
- var context = null;
-
- while ( this.moveToNextLine() )
- {
- if ( this.isCurrentLineEmpty() )
- {
- continue;
- }
-
- // tab?
- if ( this.currentLine.charAt(0) == '\t' )
- {
- throw new YamlParseException('A YAML file cannot contain tabs as indentation.', this.getRealCurrentLineNb() + 1, this.currentLine);
- }
-
- var isRef = false;
- var isInPlace = false;
- var isProcessed = false;
- var values = null;
- var matches = null;
- var c = null;
- var parser = null;
- var block = null;
- var key = null;
- var parsed = null;
- var len = null;
- var reverse = null;
-
- if ( values = /^\-((\s+)(.+?))?\s*$/.exec(this.currentLine) )
- {
-
- if (context && 'mapping' == context) {
- throw new YamlParseException('You cannot define a sequence item when in a mapping', this.getRealCurrentLineNb() + 1, this.currentLine);
- }
- context = 'sequence';
-
- if ( !this.isDefined(data) ) data = [];
- //if ( !(data instanceof Array) ) throw new YamlParseException("Non array entry", this.getRealCurrentLineNb() + 1, this.currentLine);
-
- values = {leadspaces: values[2], value: values[3]};
-
- if ( this.isDefined(values.value) && ( matches = /^&([^ ]+) *(.*)/.exec(values.value) ) )
- {
- matches = {ref: matches[1], value: matches[2]};
- isRef = matches.ref;
- values.value = matches.value;
- }
-
- // array
- if ( !this.isDefined(values.value) || '' == this.trim(values.value) || values.value.replace(/^ +/,'').charAt(0) == '#' )
- {
- c = this.getRealCurrentLineNb() + 1;
- parser = new YamlParser(c);
- parser.refs = this.refs;
- data.push(parser.parse(this.getNextEmbedBlock()));
- this.refs = parser.refs;
- }
- else
- {
- if ( this.isDefined(values.leadspaces) &&
- ' ' == values.leadspaces &&
- ( matches = new RegExp('^('+YamlInline.REGEX_QUOTED_STRING+'|[^ \'"\{\[].*?) *\:(\\s+(.+?))?\\s*$').exec(values.value) )
- ) {
- matches = {key: matches[1], value: matches[3]};
- // this is a compact notation element, add to next block and parse
- c = this.getRealCurrentLineNb();
- parser = new YamlParser(c);
- parser.refs = this.refs;
- block = values.value;
-
- if ( !this.isNextLineIndented() )
- {
- block += "\n"+this.getNextEmbedBlock(this.getCurrentLineIndentation() + 2);
- }
-
- data.push(parser.parse(block));
- this.refs = parser.refs;
- }
- else
- {
- data.push(this.parseValue(values.value));
- }
- }
- }
- else if ( values = new RegExp('^('+YamlInline.REGEX_QUOTED_STRING+'|[^ \'"\[\{].*?) *\:(\\s+(.+?))?\\s*$').exec(this.currentLine) )
- {
- if ( !this.isDefined(data) ) data = {};
- if (context && 'sequence' == context) {
- throw new YamlParseException('You cannot define a mapping item when in a sequence', this.getRealCurrentLineNb() + 1, this.currentLine);
- }
- context = 'mapping';
- //if ( data instanceof Array ) throw new YamlParseException("Non mapped entry", this.getRealCurrentLineNb() + 1, this.currentLine);
-
- values = {key: values[1], value: values[3]};
-
- try {
- key = new YamlInline().parseScalar(values.key);
- } catch (e) {
- if ( e instanceof YamlParseException ) {
- e.setParsedLine(this.getRealCurrentLineNb() + 1);
- e.setSnippet(this.currentLine);
- }
- throw e;
- }
-
-
- if ( '<<' == key )
- {
- if ( this.isDefined(values.value) && '*' == (values.value+'').charAt(0) )
- {
- isInPlace = values.value.substr(1);
- if ( this.refs[isInPlace] == undefined )
- {
- throw new YamlParseException('Reference "'+value+'" does not exist', this.getRealCurrentLineNb() + 1, this.currentLine);
- }
- }
- else
- {
- if ( this.isDefined(values.value) && values.value != '' )
- {
- value = values.value;
- }
- else
- {
- value = this.getNextEmbedBlock();
- }
-
- c = this.getRealCurrentLineNb() + 1;
- parser = new YamlParser(c);
- parser.refs = this.refs;
- parsed = parser.parse(value);
- this.refs = parser.refs;
-
- var merged = [];
- if ( !this.isObject(parsed) )
- {
- throw new YamlParseException("YAML merge keys used with a scalar value instead of an array", this.getRealCurrentLineNb() + 1, this.currentLine);
- }
- else if ( this.isDefined(parsed[0]) )
- {
- // Numeric array, merge individual elements
- reverse = this.reverseArray(parsed);
- len = reverse.length;
- for ( var i = 0; i < len; i++ )
- {
- var parsedItem = reverse[i];
- if ( !this.isObject(reverse[i]) )
- {
- throw new YamlParseException("Merge items must be arrays", this.getRealCurrentLineNb() + 1, this.currentLine);
- }
- merged = this.mergeObject(reverse[i], merged);
- }
- }
- else
- {
- // Associative array, merge
- merged = this.mergeObject(merged, parsed);
- }
-
- isProcessed = merged;
- }
- }
- else if ( this.isDefined(values.value) && (matches = /^&([^ ]+) *(.*)/.exec(values.value) ) )
- {
- matches = {ref: matches[1], value: matches[2]};
- isRef = matches.ref;
- values.value = matches.value;
- }
-
- if ( isProcessed )
- {
- // Merge keys
- data = isProcessed;
- }
- // hash
- else if ( !this.isDefined(values.value) || '' == this.trim(values.value) || this.trim(values.value).charAt(0) == '#' )
- {
- // if next line is less indented or equal, then it means that the current value is null
- if ( this.isNextLineIndented() && !this.isNextLineUnIndentedCollection() )
- {
- data[key] = null;
- }
- else
- {
- c = this.getRealCurrentLineNb() + 1;
- parser = new YamlParser(c);
- parser.refs = this.refs;
- data[key] = parser.parse(this.getNextEmbedBlock());
- this.refs = parser.refs;
- }
- }
- else
- {
- if ( isInPlace )
- {
- data = this.refs[isInPlace];
- }
- else
- {
- data[key] = this.parseValue(values.value);
- }
- }
- }
- else
- {
- // 1-liner followed by newline
- if ( 2 == this.lines.length && this.isEmpty(this.lines[1]) )
- {
- try {
- value = new YamlInline().parse(this.lines[0]);
- } catch (e) {
- if ( e instanceof YamlParseException ) {
- e.setParsedLine(this.getRealCurrentLineNb() + 1);
- e.setSnippet(this.currentLine);
- }
- throw e;
- }
-
- if ( this.isObject(value) )
- {
- var first = value[0];
- if ( typeof(value) == 'string' && '*' == first.charAt(0) )
- {
- data = [];
- len = value.length;
- for ( var i = 0; i < len; i++ )
- {
- data.push(this.refs[value[i].substr(1)]);
- }
- value = data;
- }
- }
-
- return value;
- }
-
- throw new YamlParseException('Unable to parse.', this.getRealCurrentLineNb() + 1, this.currentLine);
- }
-
- if ( isRef )
- {
- if ( data instanceof Array )
- this.refs[isRef] = data[data.length-1];
- else
- {
- var lastKey = null;
- for ( var k in data )
- {
- if ( data.hasOwnProperty(k) ) lastKey = k;
- }
- this.refs[isRef] = data[k];
- }
- }
- }
-
- return this.isEmpty(data) ? null : data;
- },
-
- /**
- * Returns the current line number (takes the offset into account).
- *
- * @return integer The current line number
- */
- getRealCurrentLineNb: function()
- {
- return this.currentLineNb + this.offset;
- },
-
- /**
- * Returns the current line indentation.
- *
- * @return integer The current line indentation
- */
- getCurrentLineIndentation: function()
- {
- return this.currentLine.length - this.currentLine.replace(/^ +/g, '').length;
- },
-
- /**
- * Returns the next embed block of YAML.
- *
- * @param integer indentation The indent level at which the block is to be read, or null for default
- *
- * @return string A YAML string
- *
- * @throws YamlParseException When indentation problem are detected
- */
- getNextEmbedBlock: function(indentation)
- {
- this.moveToNextLine();
- var newIndent = null;
- var indent = null;
-
- if ( !this.isDefined(indentation) )
- {
- newIndent = this.getCurrentLineIndentation();
-
- var unindentedEmbedBlock = this.isStringUnIndentedCollectionItem(this.currentLine);
-
- if ( !this.isCurrentLineEmpty() && 0 == newIndent && !unindentedEmbedBlock )
- {
- throw new YamlParseException('Indentation problem A', this.getRealCurrentLineNb() + 1, this.currentLine);
- }
- }
- else
- {
- newIndent = indentation;
- }
-
- var data = [this.currentLine.substr(newIndent)];
-
- var isUnindentedCollection = this.isStringUnIndentedCollectionItem(this.currentLine);
-
- var continuationIndent = -1;
- if (isUnindentedCollection === true) {
- continuationIndent = 1 + /^\-((\s+)(.+?))?\s*$/.exec(this.currentLine)[2].length;
- }
-
- while ( this.moveToNextLine() )
- {
-
- if (isUnindentedCollection && !this.isStringUnIndentedCollectionItem(this.currentLine) && this.getCurrentLineIndentation() != continuationIndent) {
- this.moveToPreviousLine();
- break;
- }
-
- if ( this.isCurrentLineEmpty() )
- {
- if ( this.isCurrentLineBlank() )
- {
- data.push(this.currentLine.substr(newIndent));
- }
-
- continue;
- }
-
- indent = this.getCurrentLineIndentation();
- var matches;
- if ( matches = /^( *)$/.exec(this.currentLine) )
- {
- // empty line
- data.push(matches[1]);
- }
- else if ( indent >= newIndent )
- {
- data.push(this.currentLine.substr(newIndent));
- }
- else if ( 0 == indent )
- {
- this.moveToPreviousLine();
-
- break;
- }
- else
- {
- throw new YamlParseException('Indentation problem B', this.getRealCurrentLineNb() + 1, this.currentLine);
- }
- }
-
- return data.join("\n");
- },
-
- /**
- * Moves the parser to the next line.
- *
- * @return Boolean
- */
- moveToNextLine: function()
- {
- if ( this.currentLineNb >= this.lines.length - 1 )
- {
- return false;
- }
-
- this.currentLineNb++;
- this.currentLine = this.lines[this.currentLineNb];
-
- return true;
- },
-
- /**
- * Moves the parser to the previous line.
- */
- moveToPreviousLine: function()
- {
- this.currentLineNb--;
- this.currentLine = this.lines[this.currentLineNb];
- },
-
- /**
- * Parses a YAML value.
- *
- * @param string value A YAML value
- *
- * @return mixed A JS value
- *
- * @throws YamlParseException When reference does not exist
- */
- parseValue: function(value)
- {
- if ( '*' == (value+'').charAt(0) )
- {
- if ( this.trim(value).charAt(0) == '#' )
- {
- value = (value+'').substr(1, value.indexOf('#') - 2);
- }
- else
- {
- value = (value+'').substr(1);
- }
-
- if ( this.refs[value] == undefined )
- {
- throw new YamlParseException('Reference "'+value+'" does not exist', this.getRealCurrentLineNb() + 1, this.currentLine);
- }
- return this.refs[value];
- }
-
- var matches = null;
- if ( matches = /^(\||>)(\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?( +#.*)?$/.exec(value) )
- {
- matches = {separator: matches[1], modifiers: matches[2], comments: matches[3]};
- var modifiers = this.isDefined(matches.modifiers) ? matches.modifiers : '';
-
- return this.parseFoldedScalar(matches.separator, modifiers.replace(/\d+/g, ''), Math.abs(parseInt(modifiers)));
- }
- try {
- return new YamlInline().parse(value);
- } catch (e) {
- if ( e instanceof YamlParseException ) {
- e.setParsedLine(this.getRealCurrentLineNb() + 1);
- e.setSnippet(this.currentLine);
- }
- throw e;
- }
- },
-
- /**
- * Parses a folded scalar.
- *
- * @param string separator The separator that was used to begin this folded scalar (| or >)
- * @param string indicator The indicator that was used to begin this folded scalar (+ or -)
- * @param integer indentation The indentation that was used to begin this folded scalar
- *
- * @return string The text value
- */
- parseFoldedScalar: function(separator, indicator, indentation)
- {
- if ( indicator == undefined ) indicator = '';
- if ( indentation == undefined ) indentation = 0;
-
- separator = '|' == separator ? "\n" : ' ';
- var text = '';
- var diff = null;
-
- var notEOF = this.moveToNextLine();
-
- while ( notEOF && this.isCurrentLineBlank() )
- {
- text += "\n";
-
- notEOF = this.moveToNextLine();
- }
-
- if ( !notEOF )
- {
- return '';
- }
-
- var matches = null;
- if ( !(matches = new RegExp('^('+(indentation ? this.strRepeat(' ', indentation) : ' +')+')(.*)$').exec(this.currentLine)) )
- {
- this.moveToPreviousLine();
-
- return '';
- }
-
- matches = {indent: matches[1], text: matches[2]};
-
- var textIndent = matches.indent;
- var previousIndent = 0;
-
- text += matches.text + separator;
- while ( this.currentLineNb + 1 < this.lines.length )
- {
- this.moveToNextLine();
-
- if ( matches = new RegExp('^( {'+textIndent.length+',})(.+)$').exec(this.currentLine) )
- {
- matches = {indent: matches[1], text: matches[2]};
-
- if ( ' ' == separator && previousIndent != matches.indent )
- {
- text = text.substr(0, text.length - 1)+"\n";
- }
-
- previousIndent = matches.indent;
-
- diff = matches.indent.length - textIndent.length;
- text += this.strRepeat(' ', diff) + matches.text + (diff != 0 ? "\n" : separator);
- }
- else if ( matches = /^( *)$/.exec(this.currentLine) )
- {
- text += matches[1].replace(new RegExp('^ {1,'+textIndent.length+'}','g'), '')+"\n";
- }
- else
- {
- this.moveToPreviousLine();
-
- break;
- }
- }
-
- if ( ' ' == separator )
- {
- // replace last separator by a newline
- text = text.replace(/ (\n*)$/g, "\n$1");
- }
-
- switch ( indicator )
- {
- case '':
- text = text.replace(/\n+$/g, "\n");
- break;
- case '+':
- break;
- case '-':
- text = text.replace(/\n+$/g, '');
- break;
- }
-
- return text;
- },
-
- /**
- * Returns true if the next line is indented.
- *
- * @return Boolean Returns true if the next line is indented, false otherwise
- */
- isNextLineIndented: function()
- {
- var currentIndentation = this.getCurrentLineIndentation();
- var notEOF = this.moveToNextLine();
-
- while ( notEOF && this.isCurrentLineEmpty() )
- {
- notEOF = this.moveToNextLine();
- }
-
- if ( false == notEOF )
- {
- return false;
- }
-
- var ret = false;
- if ( this.getCurrentLineIndentation() <= currentIndentation )
- {
- ret = true;
- }
-
- this.moveToPreviousLine();
-
- return ret;
- },
-
- /**
- * Returns true if the current line is blank or if it is a comment line.
- *
- * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
- */
- isCurrentLineEmpty: function()
- {
- return this.isCurrentLineBlank() || this.isCurrentLineComment();
- },
-
- /**
- * Returns true if the current line is blank.
- *
- * @return Boolean Returns true if the current line is blank, false otherwise
- */
- isCurrentLineBlank: function()
- {
- return '' == this.trim(this.currentLine);
- },
-
- /**
- * Returns true if the current line is a comment line.
- *
- * @return Boolean Returns true if the current line is a comment line, false otherwise
- */
- isCurrentLineComment: function()
- {
- //checking explicitly the first char of the trim is faster than loops or strpos
- var ltrimmedLine = this.currentLine.replace(/^ +/g, '');
- return ltrimmedLine.charAt(0) == '#';
- },
-
- /**
- * Cleanups a YAML string to be parsed.
- *
- * @param string value The input YAML string
- *
- * @return string A cleaned up YAML string
- */
- cleanup: function(value)
- {
- value = value.split("\r\n").join("\n").split("\r").join("\n");
-
- if ( !/\n$/.test(value) )
- {
- value += "\n";
- }
-
- // strip YAML header
- var count = 0;
- var regex = /^\%YAML[: ][\d\.]+.*\n/;
- while ( regex.test(value) )
- {
- value = value.replace(regex, '');
- count++;
- }
- this.offset += count;
-
- // remove leading comments
- regex = /^(#.*?\n)+/;
- if ( regex.test(value) )
- {
- var trimmedValue = value.replace(regex, '');
-
- // items have been removed, update the offset
- this.offset += this.subStrCount(value, "\n") - this.subStrCount(trimmedValue, "\n");
- value = trimmedValue;
- }
-
- // remove start of the document marker (---)
- regex = /^\-\-\-.*?\n/;
- if ( regex.test(value) )
- {
- trimmedValue = value.replace(regex, '');
-
- // items have been removed, update the offset
- this.offset += this.subStrCount(value, "\n") - this.subStrCount(trimmedValue, "\n");
- value = trimmedValue;
-
- // remove end of the document marker (...)
- value = value.replace(/\.\.\.\s*$/g, '');
- }
-
- return value;
- },
-
- /**
- * Returns true if the next line starts unindented collection
- *
- * @return Boolean Returns true if the next line starts unindented collection, false otherwise
- */
- isNextLineUnIndentedCollection: function()
- {
- var currentIndentation = this.getCurrentLineIndentation();
- var notEOF = this.moveToNextLine();
-
- while (notEOF && this.isCurrentLineEmpty()) {
- notEOF = this.moveToNextLine();
- }
-
- if (false === notEOF) {
- return false;
- }
-
- var ret = false;
- if (
- this.getCurrentLineIndentation() == currentIndentation
- &&
- this.isStringUnIndentedCollectionItem(this.currentLine)
- ) {
- ret = true;
- }
-
- this.moveToPreviousLine();
-
- return ret;
- },
-
- /**
- * Returns true if the string is unindented collection item
- *
- * @return Boolean Returns true if the string is unindented collection item, false otherwise
- */
- isStringUnIndentedCollectionItem: function(string)
- {
- return (0 === this.currentLine.indexOf('- '));
- },
-
- isObject: function(input)
- {
- return typeof(input) == 'object' && this.isDefined(input);
- },
-
- isEmpty: function(input)
- {
- return input == undefined || input == null || input == '' || input == 0 || input == "0" || input == false;
- },
-
- isDefined: function(input)
- {
- return input != undefined && input != null;
- },
-
- reverseArray: function(input /* Array */)
- {
- var result = [];
- var len = input.length;
- for ( var i = len-1; i >= 0; i-- )
- {
- result.push(input[i]);
- }
-
- return result;
- },
-
- merge: function(a /* Object */, b /* Object */)
- {
- var c = {};
- var i;
-
- for ( i in a )
- {
- if ( a.hasOwnProperty(i) )
- if ( /^\d+$/.test(i) ) c.push(a);
- else c[i] = a[i];
- }
- for ( i in b )
- {
- if ( b.hasOwnProperty(i) )
- if ( /^\d+$/.test(i) ) c.push(b);
- else c[i] = b[i];
- }
-
- return c;
- },
-
- strRepeat: function(str /* String */, count /* Integer */)
- {
- var i;
- var result = '';
- for ( i = 0; i < count; i++ ) result += str;
- return result;
- },
-
- subStrCount: function(string, subString, start, length)
- {
- var c = 0;
-
- string = '' + string;
- subString = '' + subString;
-
- if ( start != undefined ) string = string.substr(start);
- if ( length != undefined ) string = string.substr(0, length);
-
- var len = string.length;
- var sublen = subString.length;
- for ( var i = 0; i < len; i++ )
- {
- if ( subString == string.substr(i, sublen) )
- c++;
- i += sublen - 1;
- }
-
- return c;
- },
-
- trim: function(str /* String */)
- {
- return (str+'').replace(/^ +/,'').replace(/ +$/,'');
- }
-};
diff --git a/src/yaml/YamlUnescaper.js b/src/yaml/YamlUnescaper.js
deleted file mode 100644
index ea4a2c6..0000000
--- a/src/yaml/YamlUnescaper.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * YamlUnescaper encapsulates unescaping rules for single and double-quoted
- * YAML strings.
- *
- * @author Matthew Lewinski <matthew@lewinski.org>
- */
-var YamlUnescaper = function(){};
-YamlUnescaper.prototype =
-{
- /**
- * Unescapes a single quoted string.
- *
- * @param string value A single quoted string.
- *
- * @return string The unescaped string.
- */
- unescapeSingleQuotedString: function(value)
- {
- return value.replace(/''/g, "'");
- },
-
- /**
- * Unescapes a double quoted string.
- *
- * @param string value A double quoted string.
- *
- * @return string The unescaped string.
- */
- unescapeDoubleQuotedString: function(value)
- {
- var callback = function(m) {
- return new YamlUnescaper().unescapeCharacter(m);
- };
-
- // evaluate the string
- return value.replace(new RegExp(YamlUnescaper.REGEX_ESCAPED_CHARACTER, 'g'), callback);
- },
-
- /**
- * Unescapes a character that was found in a double-quoted string
- *
- * @param string value An escaped character
- *
- * @return string The unescaped character
- */
- unescapeCharacter: function(value)
- {
- switch (value.charAt(1)) {
- case '0':
- return String.fromCharCode(0);
- case 'a':
- return String.fromCharCode(7);
- case 'b':
- return String.fromCharCode(8);
- case 't':
- return "\t";
- case "\t":
- return "\t";
- case 'n':
- return "\n";
- case 'v':
- return String.fromCharCode(11);
- case 'f':
- return String.fromCharCode(12);
- case 'r':
- return String.fromCharCode(13);
- case 'e':
- return "\x1b";
- case ' ':
- return ' ';
- case '"':
- return '"';
- case '/':
- return '/';
- case '\\':
- return '\\';
- case 'N':
- // U+0085 NEXT LINE
- return "\x00\x85";
- case '_':
- // U+00A0 NO-BREAK SPACE
- return "\x00\xA0";
- case 'L':
- // U+2028 LINE SEPARATOR
- return "\x20\x28";
- case 'P':
- // U+2029 PARAGRAPH SEPARATOR
- return "\x20\x29";
- case 'x':
- return this.pack('n', new YamlInline().hexdec(value.substr(2, 2)));
- case 'u':
- return this.pack('n', new YamlInline().hexdec(value.substr(2, 4)));
- case 'U':
- return this.pack('N', new YamlInline().hexdec(value.substr(2, 8)));
- }
- },
-
- /**
- * @see http://phpjs.org/functions/pack
- * @warning only modes used above copied
- */
- pack: function(B){var g=0,o=1,m="",l="",z=0,p=[],E,s,C,I,h,c;var d,b,x,H,u,e,A,q,D,t,w,a,G,F,y,v,f;while(g<B.length){E=B.charAt(g);s="";g++;while((g<B.length)&&(B.charAt(g).match(/[\d\*]/)!==null)){s+=B.charAt(g);g++}if(s===""){s="1"}switch(E){case"n":if(s==="*"){s=arguments.length-o}if(s>(arguments.length-o)){throw new Error("Warning: pack() Type "+E+": too few arguments")}for(z=0;z<s;z++){m+=String.fromCharCode(arguments[o]>>8&255);m+=String.fromCharCode(arguments[o]&255);o++}break;case"N":if(s==="*"){s=arguments.length-o}if(s>(arguments.length-o)){throw new Error("Warning: pack() Type "+E+": too few arguments")}for(z=0;z<s;z++){m+=String.fromCharCode(arguments[o]>>24&255);m+=String.fromCharCode(arguments[o]>>16&255);m+=String.fromCharCode(arguments[o]>>8&255);m+=String.fromCharCode(arguments[o]&255);o++}break;default:throw new Error("Warning: pack() Type "+E+": unknown format code")}}if(o<arguments.length){throw new Error("Warning: pack(): "+(arguments.length-o)+" arguments unused")}return m}
-}
-
-// Regex fragment that matches an escaped character in a double quoted
-// string.
-// why escape quotes, ffs!
-YamlUnescaper.REGEX_ESCAPED_CHARACTER = '\\\\([0abt\tnvfre "\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})';
diff --git a/test/SpecRunner.html b/test/SpecRunner.html
new file mode 100755
index 0000000..840545d
--- /dev/null
+++ b/test/SpecRunner.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Jasmine Spec Runner v2.0.0</title>
+
+ <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.0.0/jasmine_favicon.png">
+ <link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.0/jasmine.css">
+
+ <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine.js"></script>
+ <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine-html.js"></script>
+ <script type="text/javascript" src="lib/jasmine-2.0.0/boot.js"></script>
+
+ <!-- include source files here... -->
+ <script type="text/javascript" src="../dist/yaml.debug.js"></script>
+
+ <!-- include spec files here... -->
+ <script type="text/javascript" src="spec/YamlSpec.js"></script>
+
+</head>
+
+<body>
+</body>
+</html>
diff --git a/test/libs/jasmine-1.2.0/MIT.LICENSE b/test/lib/jasmine-2.0.0/MIT.LICENSE
index 7c435ba..7c435ba 100644..100755
--- a/test/libs/jasmine-1.2.0/MIT.LICENSE
+++ b/test/lib/jasmine-2.0.0/MIT.LICENSE
diff --git a/test/lib/jasmine-2.0.0/boot.js b/test/lib/jasmine-2.0.0/boot.js
new file mode 100755
index 0000000..ec8baa0
--- /dev/null
+++ b/test/lib/jasmine-2.0.0/boot.js
@@ -0,0 +1,181 @@
+/**
+ Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
+
+ If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
+
+ The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
+
+ [jasmine-gem]: http://github.com/pivotal/jasmine-gem
+ */
+
+(function() {
+
+ /**
+ * ## Require &amp; Instantiate
+ *
+ * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
+ */
+ window.jasmine = jasmineRequire.core(jasmineRequire);
+
+ /**
+ * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
+ */
+ jasmineRequire.html(jasmine);
+
+ /**
+ * Create the Jasmine environment. This is used to run all specs in a project.
+ */
+ var env = jasmine.getEnv();
+
+ /**
+ * ## The Global Interface
+ *
+ * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
+ */
+ var jasmineInterface = {
+ describe: function(description, specDefinitions) {
+ return env.describe(description, specDefinitions);
+ },
+
+ xdescribe: function(description, specDefinitions) {
+ return env.xdescribe(description, specDefinitions);
+ },
+
+ it: function(desc, func) {
+ return env.it(desc, func);
+ },
+
+ xit: function(desc, func) {
+ return env.xit(desc, func);
+ },
+
+ beforeEach: function(beforeEachFunction) {
+ return env.beforeEach(beforeEachFunction);
+ },
+
+ afterEach: function(afterEachFunction) {
+ return env.afterEach(afterEachFunction);
+ },
+
+ expect: function(actual) {
+ return env.expect(actual);
+ },
+
+ pending: function() {
+ return env.pending();
+ },
+
+ spyOn: function(obj, methodName) {
+ return env.spyOn(obj, methodName);
+ },
+
+ jsApiReporter: new jasmine.JsApiReporter({
+ timer: new jasmine.Timer()
+ })
+ };
+
+ /**
+ * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
+ */
+ if (typeof window == "undefined" && typeof exports == "object") {
+ extend(exports, jasmineInterface);
+ } else {
+ extend(window, jasmineInterface);
+ }
+
+ /**
+ * Expose the interface for adding custom equality testers.
+ */
+ jasmine.addCustomEqualityTester = function(tester) {
+ env.addCustomEqualityTester(tester);
+ };
+
+ /**
+ * Expose the interface for adding custom expectation matchers
+ */
+ jasmine.addMatchers = function(matchers) {
+ return env.addMatchers(matchers);
+ };
+
+ /**
+ * Expose the mock interface for the JavaScript timeout functions
+ */
+ jasmine.clock = function() {
+ return env.clock;
+ };
+
+ /**
+ * ## Runner Parameters
+ *
+ * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
+ */
+
+ var queryString = new jasmine.QueryString({
+ getWindowLocation: function() { return window.location; }
+ });
+
+ var catchingExceptions = queryString.getParam("catch");
+ env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
+
+ /**
+ * ## Reporters
+ * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
+ */
+ var htmlReporter = new jasmine.HtmlReporter({
+ env: env,
+ onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
+ getContainer: function() { return document.body; },
+ createElement: function() { return document.createElement.apply(document, arguments); },
+ createTextNode: function() { return document.createTextNode.apply(document, arguments); },
+ timer: new jasmine.Timer()
+ });
+
+ /**
+ * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
+ */
+ env.addReporter(jasmineInterface.jsApiReporter);
+ env.addReporter(htmlReporter);
+
+ /**
+ * Filter which specs will be run by matching the start of the full name against the `spec` query param.
+ */
+ var specFilter = new jasmine.HtmlSpecFilter({
+ filterString: function() { return queryString.getParam("spec"); }
+ });
+
+ env.specFilter = function(spec) {
+ return specFilter.matches(spec.getFullName());
+ };
+
+ /**
+ * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
+ */
+ window.setTimeout = window.setTimeout;
+ window.setInterval = window.setInterval;
+ window.clearTimeout = window.clearTimeout;
+ window.clearInterval = window.clearInterval;
+
+ /**
+ * ## Execution
+ *
+ * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
+ */
+ var currentWindowOnload = window.onload;
+
+ window.onload = function() {
+ if (currentWindowOnload) {
+ currentWindowOnload();
+ }
+ htmlReporter.initialize();
+ env.execute();
+ };
+
+ /**
+ * Helper function for readability above.
+ */
+ function extend(destination, source) {
+ for (var property in source) destination[property] = source[property];
+ return destination;
+ }
+
+}());
diff --git a/test/lib/jasmine-2.0.0/console.js b/test/lib/jasmine-2.0.0/console.js
new file mode 100755
index 0000000..33c1698
--- /dev/null
+++ b/test/lib/jasmine-2.0.0/console.js
@@ -0,0 +1,160 @@
+/*
+Copyright (c) 2008-2013 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+function getJasmineRequireObj() {
+ if (typeof module !== "undefined" && module.exports) {
+ return exports;
+ } else {
+ window.jasmineRequire = window.jasmineRequire || {};
+ return window.jasmineRequire;
+ }
+}
+
+getJasmineRequireObj().console = function(jRequire, j$) {
+ j$.ConsoleReporter = jRequire.ConsoleReporter();
+};
+
+getJasmineRequireObj().ConsoleReporter = function() {
+
+ var noopTimer = {
+ start: function(){},
+ elapsed: function(){ return 0; }
+ };
+
+ function ConsoleReporter(options) {
+ var print = options.print,
+ showColors = options.showColors || false,
+ onComplete = options.onComplete || function() {},
+ timer = options.timer || noopTimer,
+ specCount,
+ failureCount,
+ failedSpecs = [],
+ pendingCount,
+ ansi = {
+ green: '\x1B[32m',
+ red: '\x1B[31m',
+ yellow: '\x1B[33m',
+ none: '\x1B[0m'
+ };
+
+ this.jasmineStarted = function() {
+ specCount = 0;
+ failureCount = 0;
+ pendingCount = 0;
+ print("Started");
+ printNewline();
+ timer.start();
+ };
+
+ this.jasmineDone = function() {
+ printNewline();
+ for (var i = 0; i < failedSpecs.length; i++) {
+ specFailureDetails(failedSpecs[i]);
+ }
+
+ printNewline();
+ var specCounts = specCount + " " + plural("spec", specCount) + ", " +
+ failureCount + " " + plural("failure", failureCount);
+
+ if (pendingCount) {
+ specCounts += ", " + pendingCount + " pending " + plural("spec", pendingCount);
+ }
+
+ print(specCounts);
+
+ printNewline();
+ var seconds = timer.elapsed() / 1000;
+ print("Finished in " + seconds + " " + plural("second", seconds));
+
+ printNewline();
+
+ onComplete(failureCount === 0);
+ };
+
+ this.specDone = function(result) {
+ specCount++;
+
+ if (result.status == "pending") {
+ pendingCount++;
+ print(colored("yellow", "*"));
+ return;
+ }
+
+ if (result.status == "passed") {
+ print(colored("green", '.'));
+ return;
+ }
+
+ if (result.status == "failed") {
+ failureCount++;
+ failedSpecs.push(result);
+ print(colored("red", 'F'));
+ }
+ };
+
+ return this;
+
+ function printNewline() {
+ print("\n");
+ }
+
+ function colored(color, str) {
+ return showColors ? (ansi[color] + str + ansi.none) : str;
+ }
+
+ function plural(str, count) {
+ return count == 1 ? str : str + "s";
+ }
+
+ function repeat(thing, times) {
+ var arr = [];
+ for (var i = 0; i < times; i++) {
+ arr.push(thing);
+ }
+ return arr;
+ }
+
+ function indent(str, spaces) {
+ var lines = (str || '').split("\n");
+ var newArr = [];
+ for (var i = 0; i < lines.length; i++) {
+ newArr.push(repeat(" ", spaces).join("") + lines[i]);
+ }
+ return newArr.join("\n");
+ }
+
+ function specFailureDetails(result) {
+ printNewline();
+ print(result.fullName);
+
+ for (var i = 0; i < result.failedExpectations.length; i++) {
+ var failedExpectation = result.failedExpectations[i];
+ printNewline();
+ print(indent(failedExpectation.stack, 2));
+ }
+
+ printNewline();
+ }
+ }
+
+ return ConsoleReporter;
+};
diff --git a/test/lib/jasmine-2.0.0/jasmine-html.js b/test/lib/jasmine-2.0.0/jasmine-html.js
new file mode 100755
index 0000000..985d0d1
--- /dev/null
+++ b/test/lib/jasmine-2.0.0/jasmine-html.js
@@ -0,0 +1,359 @@
+/*
+Copyright (c) 2008-2013 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+jasmineRequire.html = function(j$) {
+ j$.ResultsNode = jasmineRequire.ResultsNode();
+ j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
+ j$.QueryString = jasmineRequire.QueryString();
+ j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
+};
+
+jasmineRequire.HtmlReporter = function(j$) {
+
+ var noopTimer = {
+ start: function() {},
+ elapsed: function() { return 0; }
+ };
+
+ function HtmlReporter(options) {
+ var env = options.env || {},
+ getContainer = options.getContainer,
+ createElement = options.createElement,
+ createTextNode = options.createTextNode,
+ onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
+ timer = options.timer || noopTimer,
+ results = [],
+ specsExecuted = 0,
+ failureCount = 0,
+ pendingSpecCount = 0,
+ htmlReporterMain,
+ symbols;
+
+ this.initialize = function() {
+ htmlReporterMain = createDom("div", {className: "html-reporter"},
+ createDom("div", {className: "banner"},
+ createDom("span", {className: "title"}, "Jasmine"),
+ createDom("span", {className: "version"}, j$.version)
+ ),
+ createDom("ul", {className: "symbol-summary"}),
+ createDom("div", {className: "alert"}),
+ createDom("div", {className: "results"},
+ createDom("div", {className: "failures"})
+ )
+ );
+ getContainer().appendChild(htmlReporterMain);
+
+ symbols = find(".symbol-summary");
+ };
+
+ var totalSpecsDefined;
+ this.jasmineStarted = function(options) {
+ totalSpecsDefined = options.totalSpecsDefined || 0;
+ timer.start();
+ };
+
+ var summary = createDom("div", {className: "summary"});
+
+ var topResults = new j$.ResultsNode({}, "", null),
+ currentParent = topResults;
+
+ this.suiteStarted = function(result) {
+ currentParent.addChild(result, "suite");
+ currentParent = currentParent.last();
+ };
+
+ this.suiteDone = function(result) {
+ if (currentParent == topResults) {
+ return;
+ }
+
+ currentParent = currentParent.parent;
+ };
+
+ this.specStarted = function(result) {
+ currentParent.addChild(result, "spec");
+ };
+
+ var failures = [];
+ this.specDone = function(result) {
+ if (result.status != "disabled") {
+ specsExecuted++;
+ }
+
+ symbols.appendChild(createDom("li", {
+ className: result.status,
+ id: "spec_" + result.id,
+ title: result.fullName
+ }
+ ));
+
+ if (result.status == "failed") {
+ failureCount++;
+
+ var failure =
+ createDom("div", {className: "spec-detail failed"},
+ createDom("div", {className: "description"},
+ createDom("a", {title: result.fullName, href: specHref(result)}, result.fullName)
+ ),
+ createDom("div", {className: "messages"})
+ );
+ var messages = failure.childNodes[1];
+
+ for (var i = 0; i < result.failedExpectations.length; i++) {
+ var expectation = result.failedExpectations[i];
+ messages.appendChild(createDom("div", {className: "result-message"}, expectation.message));
+ messages.appendChild(createDom("div", {className: "stack-trace"}, expectation.stack));
+ }
+
+ failures.push(failure);
+ }
+
+ if (result.status == "pending") {
+ pendingSpecCount++;
+ }
+ };
+
+ this.jasmineDone = function() {
+ var banner = find(".banner");
+ banner.appendChild(createDom("span", {className: "duration"}, "finished in " + timer.elapsed() / 1000 + "s"));
+
+ var alert = find(".alert");
+
+ alert.appendChild(createDom("span", { className: "exceptions" },
+ createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"),
+ createDom("input", {
+ className: "raise",
+ id: "raise-exceptions",
+ type: "checkbox"
+ })
+ ));
+ var checkbox = find("input");
+
+ checkbox.checked = !env.catchingExceptions();
+ checkbox.onclick = onRaiseExceptionsClick;
+
+ if (specsExecuted < totalSpecsDefined) {
+ var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all";
+ alert.appendChild(
+ createDom("span", {className: "bar skipped"},
+ createDom("a", {href: "?", title: "Run all specs"}, skippedMessage)
+ )
+ );
+ }
+ var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount);
+ if (pendingSpecCount) { statusBarMessage += ", " + pluralize("pending spec", pendingSpecCount); }
+
+ var statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed");
+ alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage));
+
+ var results = find(".results");
+ results.appendChild(summary);
+
+ summaryList(topResults, summary);
+
+ function summaryList(resultsTree, domParent) {
+ var specListNode;
+ for (var i = 0; i < resultsTree.children.length; i++) {
+ var resultNode = resultsTree.children[i];
+ if (resultNode.type == "suite") {
+ var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id},
+ createDom("li", {className: "suite-detail"},
+ createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
+ )
+ );
+
+ summaryList(resultNode, suiteListNode);
+ domParent.appendChild(suiteListNode);
+ }
+ if (resultNode.type == "spec") {
+ if (domParent.getAttribute("class") != "specs") {
+ specListNode = createDom("ul", {className: "specs"});
+ domParent.appendChild(specListNode);
+ }
+ specListNode.appendChild(
+ createDom("li", {
+ className: resultNode.result.status,
+ id: "spec-" + resultNode.result.id
+ },
+ createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
+ )
+ );
+ }
+ }
+ }
+
+ if (failures.length) {
+ alert.appendChild(
+ createDom('span', {className: "menu bar spec-list"},
+ createDom("span", {}, "Spec List | "),
+ createDom('a', {className: "failures-menu", href: "#"}, "Failures")));
+ alert.appendChild(
+ createDom('span', {className: "menu bar failure-list"},
+ createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"),
+ createDom("span", {}, " | Failures ")));
+
+ find(".failures-menu").onclick = function() {
+ setMenuModeTo('failure-list');
+ };
+ find(".spec-list-menu").onclick = function() {
+ setMenuModeTo('spec-list');
+ };
+
+ setMenuModeTo('failure-list');
+
+ var failureNode = find(".failures");
+ for (var i = 0; i < failures.length; i++) {
+ failureNode.appendChild(failures[i]);
+ }
+ }
+ };
+
+ return this;
+
+ function find(selector) {
+ return getContainer().querySelector(selector);
+ }
+
+ function createDom(type, attrs, childrenVarArgs) {
+ var el = createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+ }
+
+ function pluralize(singular, count) {
+ var word = (count == 1 ? singular : singular + "s");
+
+ return "" + count + " " + word;
+ }
+
+ function specHref(result) {
+ return "?spec=" + encodeURIComponent(result.fullName);
+ }
+
+ function setMenuModeTo(mode) {
+ htmlReporterMain.setAttribute("class", "html-reporter " + mode);
+ }
+ }
+
+ return HtmlReporter;
+};
+
+jasmineRequire.HtmlSpecFilter = function() {
+ function HtmlSpecFilter(options) {
+ var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+ var filterPattern = new RegExp(filterString);
+
+ this.matches = function(specName) {
+ return filterPattern.test(specName);
+ };
+ }
+
+ return HtmlSpecFilter;
+};
+
+jasmineRequire.ResultsNode = function() {
+ function ResultsNode(result, type, parent) {
+ this.result = result;
+ this.type = type;
+ this.parent = parent;
+
+ this.children = [];
+
+ this.addChild = function(result, type) {
+ this.children.push(new ResultsNode(result, type, this));
+ };
+
+ this.last = function() {
+ return this.children[this.children.length - 1];
+ };
+ }
+
+ return ResultsNode;
+};
+
+jasmineRequire.QueryString = function() {
+ function QueryString(options) {
+
+ this.setParam = function(key, value) {
+ var paramMap = queryStringToParamMap();
+ paramMap[key] = value;
+ options.getWindowLocation().search = toQueryString(paramMap);
+ };
+
+ this.getParam = function(key) {
+ return queryStringToParamMap()[key];
+ };
+
+ return this;
+
+ function toQueryString(paramMap) {
+ var qStrPairs = [];
+ for (var prop in paramMap) {
+ qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop]));
+ }
+ return "?" + qStrPairs.join('&');
+ }
+
+ function queryStringToParamMap() {
+ var paramStr = options.getWindowLocation().search.substring(1),
+ params = [],
+ paramMap = {};
+
+ if (paramStr.length > 0) {
+ params = paramStr.split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ var value = decodeURIComponent(p[1]);
+ if (value === "true" || value === "false") {
+ value = JSON.parse(value);
+ }
+ paramMap[decodeURIComponent(p[0])] = value;
+ }
+ }
+
+ return paramMap;
+ }
+
+ }
+
+ return QueryString;
+};
diff --git a/test/lib/jasmine-2.0.0/jasmine.css b/test/lib/jasmine-2.0.0/jasmine.css
new file mode 100755
index 0000000..f4d35b6
--- /dev/null
+++ b/test/lib/jasmine-2.0.0/jasmine.css
@@ -0,0 +1,55 @@
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+.html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+.html-reporter a { text-decoration: none; }
+.html-reporter a:hover { text-decoration: underline; }
+.html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; }
+.html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; }
+.html-reporter .banner .version { margin-left: 14px; }
+.html-reporter #jasmine_content { position: fixed; right: 100%; }
+.html-reporter .version { color: #aaaaaa; }
+.html-reporter .banner { margin-top: 14px; }
+.html-reporter .duration { color: #aaaaaa; float: right; }
+.html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+.html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; }
+.html-reporter .symbol-summary li.passed { font-size: 14px; }
+.html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; }
+.html-reporter .symbol-summary li.failed { line-height: 9px; }
+.html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+.html-reporter .symbol-summary li.disabled { font-size: 14px; }
+.html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; }
+.html-reporter .symbol-summary li.pending { line-height: 17px; }
+.html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; }
+.html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
+.html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+.html-reporter .bar.failed { background-color: #b03911; }
+.html-reporter .bar.passed { background-color: #a6b779; }
+.html-reporter .bar.skipped { background-color: #bababa; }
+.html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; }
+.html-reporter .bar.menu a { color: #333333; }
+.html-reporter .bar a { color: white; }
+.html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; }
+.html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; }
+.html-reporter .running-alert { background-color: #666666; }
+.html-reporter .results { margin-top: 14px; }
+.html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+.html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+.html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+.html-reporter.showDetails .summary { display: none; }
+.html-reporter.showDetails #details { display: block; }
+.html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+.html-reporter .summary { margin-top: 14px; }
+.html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; }
+.html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; }
+.html-reporter .summary li.passed a { color: #5e7d00; }
+.html-reporter .summary li.failed a { color: #b03911; }
+.html-reporter .summary li.pending a { color: #ba9d37; }
+.html-reporter .description + .suite { margin-top: 0; }
+.html-reporter .suite { margin-top: 14px; }
+.html-reporter .suite a { color: #333333; }
+.html-reporter .failures .spec-detail { margin-bottom: 28px; }
+.html-reporter .failures .spec-detail .description { background-color: #b03911; }
+.html-reporter .failures .spec-detail .description a { color: white; }
+.html-reporter .result-message { padding-top: 14px; color: #333333; white-space: pre; }
+.html-reporter .result-message span.result { display: block; }
+.html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
diff --git a/test/lib/jasmine-2.0.0/jasmine.js b/test/lib/jasmine-2.0.0/jasmine.js
new file mode 100755
index 0000000..24463ec
--- /dev/null
+++ b/test/lib/jasmine-2.0.0/jasmine.js
@@ -0,0 +1,2402 @@
+/*
+Copyright (c) 2008-2013 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+function getJasmineRequireObj() {
+ if (typeof module !== "undefined" && module.exports) {
+ return exports;
+ } else {
+ window.jasmineRequire = window.jasmineRequire || {};
+ return window.jasmineRequire;
+ }
+}
+
+getJasmineRequireObj().core = function(jRequire) {
+ var j$ = {};
+
+ jRequire.base(j$);
+ j$.util = jRequire.util();
+ j$.Any = jRequire.Any();
+ j$.CallTracker = jRequire.CallTracker();
+ j$.Clock = jRequire.Clock();
+ j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
+ j$.Env = jRequire.Env(j$);
+ j$.ExceptionFormatter = jRequire.ExceptionFormatter();
+ j$.Expectation = jRequire.Expectation();
+ j$.buildExpectationResult = jRequire.buildExpectationResult();
+ j$.JsApiReporter = jRequire.JsApiReporter();
+ j$.matchersUtil = jRequire.matchersUtil(j$);
+ j$.ObjectContaining = jRequire.ObjectContaining(j$);
+ j$.pp = jRequire.pp(j$);
+ j$.QueueRunner = jRequire.QueueRunner();
+ j$.ReportDispatcher = jRequire.ReportDispatcher();
+ j$.Spec = jRequire.Spec(j$);
+ j$.SpyStrategy = jRequire.SpyStrategy();
+ j$.Suite = jRequire.Suite();
+ j$.Timer = jRequire.Timer();
+ j$.version = jRequire.version();
+
+ j$.matchers = jRequire.requireMatchers(jRequire, j$);
+
+ return j$;
+};
+
+getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
+ var availableMatchers = [
+ "toBe",
+ "toBeCloseTo",
+ "toBeDefined",
+ "toBeFalsy",
+ "toBeGreaterThan",
+ "toBeLessThan",
+ "toBeNaN",
+ "toBeNull",
+ "toBeTruthy",
+ "toBeUndefined",
+ "toContain",
+ "toEqual",
+ "toHaveBeenCalled",
+ "toHaveBeenCalledWith",
+ "toMatch",
+ "toThrow",
+ "toThrowError"
+ ],
+ matchers = {};
+
+ for (var i = 0; i < availableMatchers.length; i++) {
+ var name = availableMatchers[i];
+ matchers[name] = jRequire[name](j$);
+ }
+
+ return matchers;
+};
+
+getJasmineRequireObj().base = function(j$) {
+ j$.unimplementedMethod_ = function() {
+ throw new Error("unimplemented method");
+ };
+
+ j$.MAX_PRETTY_PRINT_DEPTH = 40;
+ j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+ j$.getGlobal = (function() {
+ var jasmineGlobal = eval.call(null, "this");
+ return function() {
+ return jasmineGlobal;
+ };
+ })();
+
+ j$.getEnv = function(options) {
+ var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
+ //jasmine. singletons in here (setTimeout blah blah).
+ return env;
+ };
+
+ j$.isArray_ = function(value) {
+ return j$.isA_("Array", value);
+ };
+
+ j$.isString_ = function(value) {
+ return j$.isA_("String", value);
+ };
+
+ j$.isNumber_ = function(value) {
+ return j$.isA_("Number", value);
+ };
+
+ j$.isA_ = function(typeName, value) {
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+ };
+
+ j$.isDomNode = function(obj) {
+ return obj.nodeType > 0;
+ };
+
+ j$.any = function(clazz) {
+ return new j$.Any(clazz);
+ };
+
+ j$.objectContaining = function(sample) {
+ return new j$.ObjectContaining(sample);
+ };
+
+ j$.createSpy = function(name, originalFn) {
+
+ var spyStrategy = new j$.SpyStrategy({
+ name: name,
+ fn: originalFn,
+ getSpy: function() { return spy; }
+ }),
+ callTracker = new j$.CallTracker(),
+ spy = function() {
+ callTracker.track({
+ object: this,
+ args: Array.prototype.slice.apply(arguments)
+ });
+ return spyStrategy.exec.apply(this, arguments);
+ };
+
+ for (var prop in originalFn) {
+ if (prop === 'and' || prop === 'calls') {
+ throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon");
+ }
+
+ spy[prop] = originalFn[prop];
+ }
+
+ spy.and = spyStrategy;
+ spy.calls = callTracker;
+
+ return spy;
+ };
+
+ j$.isSpy = function(putativeSpy) {
+ if (!putativeSpy) {
+ return false;
+ }
+ return putativeSpy.and instanceof j$.SpyStrategy &&
+ putativeSpy.calls instanceof j$.CallTracker;
+ };
+
+ j$.createSpyObj = function(baseName, methodNames) {
+ if (!j$.isArray_(methodNames) || methodNames.length === 0) {
+ throw "createSpyObj requires a non-empty array of method names to create spies for";
+ }
+ var obj = {};
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
+ }
+ return obj;
+ };
+};
+
+getJasmineRequireObj().util = function() {
+
+ var util = {};
+
+ util.inherit = function(childClass, parentClass) {
+ var Subclass = function() {
+ };
+ Subclass.prototype = parentClass.prototype;
+ childClass.prototype = new Subclass();
+ };
+
+ util.htmlEscape = function(str) {
+ if (!str) {
+ return str;
+ }
+ return str.replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;');
+ };
+
+ util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) {
+ arrayOfArgs.push(args[i]);
+ }
+ return arrayOfArgs;
+ };
+
+ util.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ return util;
+};
+
+getJasmineRequireObj().Spec = function(j$) {
+ function Spec(attrs) {
+ this.expectationFactory = attrs.expectationFactory;
+ this.resultCallback = attrs.resultCallback || function() {};
+ this.id = attrs.id;
+ this.description = attrs.description || '';
+ this.fn = attrs.fn;
+ this.beforeFns = attrs.beforeFns || function() { return []; };
+ this.afterFns = attrs.afterFns || function() { return []; };
+ this.onStart = attrs.onStart || function() {};
+ this.exceptionFormatter = attrs.exceptionFormatter || function() {};
+ this.getSpecName = attrs.getSpecName || function() { return ''; };
+ this.expectationResultFactory = attrs.expectationResultFactory || function() { };
+ this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
+ this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
+
+ this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout};
+
+ if (!this.fn) {
+ this.pend();
+ }
+
+ this.result = {
+ id: this.id,
+ description: this.description,
+ fullName: this.getFullName(),
+ failedExpectations: []
+ };
+ }
+
+ Spec.prototype.addExpectationResult = function(passed, data) {
+ if (passed) {
+ return;
+ }
+ this.result.failedExpectations.push(this.expectationResultFactory(data));
+ };
+
+ Spec.prototype.expect = function(actual) {
+ return this.expectationFactory(actual, this);
+ };
+
+ Spec.prototype.execute = function(onComplete) {
+ var self = this,
+ timeout;
+
+ this.onStart(this);
+
+ if (this.markedPending || this.disabled) {
+ complete();
+ return;
+ }
+
+ function timeoutable(fn) {
+ return function(done) {
+ timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
+ onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'));
+ done();
+ }, j$.DEFAULT_TIMEOUT_INTERVAL]]);
+
+ var callDone = function() {
+ clearTimeoutable();
+ done();
+ };
+
+ fn.call(this, callDone); //TODO: do we care about more than 1 arg?
+ };
+ }
+
+ function clearTimeoutable() {
+ Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]);
+ timeout = void 0;
+ }
+
+ var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()),
+ allTimeoutableFns = [];
+ for (var i = 0; i < allFns.length; i++) {
+ var fn = allFns[i];
+ allTimeoutableFns.push(fn.length > 0 ? timeoutable(fn) : fn);
+ }
+
+ this.queueRunnerFactory({
+ fns: allTimeoutableFns,
+ onException: onException,
+ onComplete: complete
+ });
+
+ function onException(e) {
+ clearTimeoutable();
+ if (Spec.isPendingSpecException(e)) {
+ self.pend();
+ return;
+ }
+
+ self.addExpectationResult(false, {
+ matcherName: "",
+ passed: false,
+ expected: "",
+ actual: "",
+ error: e
+ });
+ }
+
+ function complete() {
+ self.result.status = self.status();
+ self.resultCallback(self.result);
+
+ if (onComplete) {
+ onComplete();
+ }
+ }
+ };
+
+ Spec.prototype.disable = function() {
+ this.disabled = true;
+ };
+
+ Spec.prototype.pend = function() {
+ this.markedPending = true;
+ };
+
+ Spec.prototype.status = function() {
+ if (this.disabled) {
+ return 'disabled';
+ }
+
+ if (this.markedPending) {
+ return 'pending';
+ }
+
+ if (this.result.failedExpectations.length > 0) {
+ return 'failed';
+ } else {
+ return 'passed';
+ }
+ };
+
+ Spec.prototype.getFullName = function() {
+ return this.getSpecName(this);
+ };
+
+ Spec.pendingSpecExceptionMessage = "=> marked Pending";
+
+ Spec.isPendingSpecException = function(e) {
+ return e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1;
+ };
+
+ return Spec;
+};
+
+if (typeof window == void 0 && typeof exports == "object") {
+ exports.Spec = jasmineRequire.Spec;
+}
+
+getJasmineRequireObj().Env = function(j$) {
+ function Env(options) {
+ options = options || {};
+
+ var self = this;
+ var global = options.global || j$.getGlobal();
+
+ var totalSpecsDefined = 0;
+
+ var catchExceptions = true;
+
+ var realSetTimeout = j$.getGlobal().setTimeout;
+ var realClearTimeout = j$.getGlobal().clearTimeout;
+ this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler());
+
+ var runnableLookupTable = {};
+
+ var spies = [];
+
+ var currentSpec = null;
+ var currentSuite = null;
+
+ var reporter = new j$.ReportDispatcher([
+ "jasmineStarted",
+ "jasmineDone",
+ "suiteStarted",
+ "suiteDone",
+ "specStarted",
+ "specDone"
+ ]);
+
+ this.specFilter = function() {
+ return true;
+ };
+
+ var equalityTesters = [];
+
+ var customEqualityTesters = [];
+ this.addCustomEqualityTester = function(tester) {
+ customEqualityTesters.push(tester);
+ };
+
+ j$.Expectation.addCoreMatchers(j$.matchers);
+
+ var nextSpecId = 0;
+ var getNextSpecId = function() {
+ return 'spec' + nextSpecId++;
+ };
+
+ var nextSuiteId = 0;
+ var getNextSuiteId = function() {
+ return 'suite' + nextSuiteId++;
+ };
+
+ var expectationFactory = function(actual, spec) {
+ return j$.Expectation.Factory({
+ util: j$.matchersUtil,
+ customEqualityTesters: customEqualityTesters,
+ actual: actual,
+ addExpectationResult: addExpectationResult
+ });
+
+ function addExpectationResult(passed, result) {
+ return spec.addExpectationResult(passed, result);
+ }
+ };
+
+ var specStarted = function(spec) {
+ currentSpec = spec;
+ reporter.specStarted(spec.result);
+ };
+
+ var beforeFns = function(suite) {
+ return function() {
+ var befores = [];
+ while(suite) {
+ befores = befores.concat(suite.beforeFns);
+ suite = suite.parentSuite;
+ }
+ return befores.reverse();
+ };
+ };
+
+ var afterFns = function(suite) {
+ return function() {
+ var afters = [];
+ while(suite) {
+ afters = afters.concat(suite.afterFns);
+ suite = suite.parentSuite;
+ }
+ return afters;
+ };
+ };
+
+ var getSpecName = function(spec, suite) {
+ return suite.getFullName() + ' ' + spec.description;
+ };
+
+ // TODO: we may just be able to pass in the fn instead of wrapping here
+ var buildExpectationResult = j$.buildExpectationResult,
+ exceptionFormatter = new j$.ExceptionFormatter(),
+ expectationResultFactory = function(attrs) {
+ attrs.messageFormatter = exceptionFormatter.message;
+ attrs.stackFormatter = exceptionFormatter.stack;
+
+ return buildExpectationResult(attrs);
+ };
+
+ // TODO: fix this naming, and here's where the value comes in
+ this.catchExceptions = function(value) {
+ catchExceptions = !!value;
+ return catchExceptions;
+ };
+
+ this.catchingExceptions = function() {
+ return catchExceptions;
+ };
+
+ var maximumSpecCallbackDepth = 20;
+ var currentSpecCallbackDepth = 0;
+
+ function clearStack(fn) {
+ currentSpecCallbackDepth++;
+ if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) {
+ currentSpecCallbackDepth = 0;
+ realSetTimeout(fn, 0);
+ } else {
+ fn();
+ }
+ }
+
+ var catchException = function(e) {
+ return j$.Spec.isPendingSpecException(e) || catchExceptions;
+ };
+
+ var queueRunnerFactory = function(options) {
+ options.catchException = catchException;
+ options.clearStack = options.clearStack || clearStack;
+
+ new j$.QueueRunner(options).execute();
+ };
+
+ var topSuite = new j$.Suite({
+ env: this,
+ id: getNextSuiteId(),
+ description: 'Jasmine__TopLevel__Suite',
+ queueRunner: queueRunnerFactory,
+ resultCallback: function() {} // TODO - hook this up
+ });
+ runnableLookupTable[topSuite.id] = topSuite;
+ currentSuite = topSuite;
+
+ this.topSuite = function() {
+ return topSuite;
+ };
+
+ this.execute = function(runnablesToRun) {
+ runnablesToRun = runnablesToRun || [topSuite.id];
+
+ var allFns = [];
+ for(var i = 0; i < runnablesToRun.length; i++) {
+ var runnable = runnableLookupTable[runnablesToRun[i]];
+ allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
+ }
+
+ reporter.jasmineStarted({
+ totalSpecsDefined: totalSpecsDefined
+ });
+
+ queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
+ };
+
+ this.addReporter = function(reporterToAdd) {
+ reporter.addReporter(reporterToAdd);
+ };
+
+ this.addMatchers = function(matchersToAdd) {
+ j$.Expectation.addMatchers(matchersToAdd);
+ };
+
+ this.spyOn = function(obj, methodName) {
+ if (j$.util.isUndefined(obj)) {
+ throw new Error("spyOn could not find an object to spy upon for " + methodName + "()");
+ }
+
+ if (j$.util.isUndefined(obj[methodName])) {
+ throw new Error(methodName + '() method does not exist');
+ }
+
+ if (obj[methodName] && j$.isSpy(obj[methodName])) {
+ //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
+ throw new Error(methodName + ' has already been spied upon');
+ }
+
+ var spy = j$.createSpy(methodName, obj[methodName]);
+
+ spies.push({
+ spy: spy,
+ baseObj: obj,
+ methodName: methodName,
+ originalValue: obj[methodName]
+ });
+
+ obj[methodName] = spy;
+
+ return spy;
+ };
+
+ var suiteFactory = function(description) {
+ var suite = new j$.Suite({
+ env: self,
+ id: getNextSuiteId(),
+ description: description,
+ parentSuite: currentSuite,
+ queueRunner: queueRunnerFactory,
+ onStart: suiteStarted,
+ resultCallback: function(attrs) {
+ reporter.suiteDone(attrs);
+ }
+ });
+
+ runnableLookupTable[suite.id] = suite;
+ return suite;
+ };
+
+ this.describe = function(description, specDefinitions) {
+ var suite = suiteFactory(description);
+
+ var parentSuite = currentSuite;
+ parentSuite.addChild(suite);
+ currentSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch (e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ this.it("encountered a declaration exception", function() {
+ throw declarationError;
+ });
+ }
+
+ currentSuite = parentSuite;
+
+ return suite;
+ };
+
+ this.xdescribe = function(description, specDefinitions) {
+ var suite = this.describe(description, specDefinitions);
+ suite.disable();
+ return suite;
+ };
+
+ var specFactory = function(description, fn, suite) {
+ totalSpecsDefined++;
+
+ var spec = new j$.Spec({
+ id: getNextSpecId(),
+ beforeFns: beforeFns(suite),
+ afterFns: afterFns(suite),
+ expectationFactory: expectationFactory,
+ exceptionFormatter: exceptionFormatter,
+ resultCallback: specResultCallback,
+ getSpecName: function(spec) {
+ return getSpecName(spec, suite);
+ },
+ onStart: specStarted,
+ description: description,
+ expectationResultFactory: expectationResultFactory,
+ queueRunnerFactory: queueRunnerFactory,
+ fn: fn,
+ timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
+ });
+
+ runnableLookupTable[spec.id] = spec;
+
+ if (!self.specFilter(spec)) {
+ spec.disable();
+ }
+
+ return spec;
+
+ function removeAllSpies() {
+ for (var i = 0; i < spies.length; i++) {
+ var spyEntry = spies[i];
+ spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
+ }
+ spies = [];
+ }
+
+ function specResultCallback(result) {
+ removeAllSpies();
+ j$.Expectation.resetMatchers();
+ customEqualityTesters = [];
+ currentSpec = null;
+ reporter.specDone(result);
+ }
+ };
+
+ var suiteStarted = function(suite) {
+ reporter.suiteStarted(suite.result);
+ };
+
+ this.it = function(description, fn) {
+ var spec = specFactory(description, fn, currentSuite);
+ currentSuite.addChild(spec);
+ return spec;
+ };
+
+ this.xit = function(description, fn) {
+ var spec = this.it(description, fn);
+ spec.pend();
+ return spec;
+ };
+
+ this.expect = function(actual) {
+ return currentSpec.expect(actual);
+ };
+
+ this.beforeEach = function(beforeEachFunction) {
+ currentSuite.beforeEach(beforeEachFunction);
+ };
+
+ this.afterEach = function(afterEachFunction) {
+ currentSuite.afterEach(afterEachFunction);
+ };
+
+ this.pending = function() {
+ throw j$.Spec.pendingSpecExceptionMessage;
+ };
+ }
+
+ return Env;
+};
+
+getJasmineRequireObj().JsApiReporter = function() {
+
+ var noopTimer = {
+ start: function(){},
+ elapsed: function(){ return 0; }
+ };
+
+ function JsApiReporter(options) {
+ var timer = options.timer || noopTimer,
+ status = "loaded";
+
+ this.started = false;
+ this.finished = false;
+
+ this.jasmineStarted = function() {
+ this.started = true;
+ status = 'started';
+ timer.start();
+ };
+
+ var executionTime;
+
+ this.jasmineDone = function() {
+ this.finished = true;
+ executionTime = timer.elapsed();
+ status = 'done';
+ };
+
+ this.status = function() {
+ return status;
+ };
+
+ var suites = {};
+
+ this.suiteStarted = function(result) {
+ storeSuite(result);
+ };
+
+ this.suiteDone = function(result) {
+ storeSuite(result);
+ };
+
+ function storeSuite(result) {
+ suites[result.id] = result;
+ }
+
+ this.suites = function() {
+ return suites;
+ };
+
+ var specs = [];
+ this.specStarted = function(result) { };
+
+ this.specDone = function(result) {
+ specs.push(result);
+ };
+
+ this.specResults = function(index, length) {
+ return specs.slice(index, index + length);
+ };
+
+ this.specs = function() {
+ return specs;
+ };
+
+ this.executionTime = function() {
+ return executionTime;
+ };
+
+ }
+
+ return JsApiReporter;
+};
+
+getJasmineRequireObj().Any = function() {
+
+ function Any(expectedObject) {
+ this.expectedObject = expectedObject;
+ }
+
+ Any.prototype.jasmineMatches = function(other) {
+ if (this.expectedObject == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedObject == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedObject == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedObject == Object) {
+ return typeof other == 'object';
+ }
+
+ if (this.expectedObject == Boolean) {
+ return typeof other == 'boolean';
+ }
+
+ return other instanceof this.expectedObject;
+ };
+
+ Any.prototype.jasmineToString = function() {
+ return '<jasmine.any(' + this.expectedClass + ')>';
+ };
+
+ return Any;
+};
+
+getJasmineRequireObj().CallTracker = function() {
+
+ function CallTracker() {
+ var calls = [];
+
+ this.track = function(context) {
+ calls.push(context);
+ };
+
+ this.any = function() {
+ return !!calls.length;
+ };
+
+ this.count = function() {
+ return calls.length;
+ };
+
+ this.argsFor = function(index) {
+ var call = calls[index];
+ return call ? call.args : [];
+ };
+
+ this.all = function() {
+ return calls;
+ };
+
+ this.allArgs = function() {
+ var callArgs = [];
+ for(var i = 0; i < calls.length; i++){
+ callArgs.push(calls[i].args);
+ }
+
+ return callArgs;
+ };
+
+ this.first = function() {
+ return calls[0];
+ };
+
+ this.mostRecent = function() {
+ return calls[calls.length - 1];
+ };
+
+ this.reset = function() {
+ calls = [];
+ };
+ }
+
+ return CallTracker;
+};
+
+getJasmineRequireObj().Clock = function() {
+ function Clock(global, delayedFunctionScheduler) {
+ var self = this,
+ realTimingFunctions = {
+ setTimeout: global.setTimeout,
+ clearTimeout: global.clearTimeout,
+ setInterval: global.setInterval,
+ clearInterval: global.clearInterval
+ },
+ fakeTimingFunctions = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setInterval: setInterval,
+ clearInterval: clearInterval
+ },
+ installed = false,
+ timer;
+
+ self.install = function() {
+ replace(global, fakeTimingFunctions);
+ timer = fakeTimingFunctions;
+ installed = true;
+ };
+
+ self.uninstall = function() {
+ delayedFunctionScheduler.reset();
+ replace(global, realTimingFunctions);
+ timer = realTimingFunctions;
+ installed = false;
+ };
+
+ self.setTimeout = function(fn, delay, params) {
+ if (legacyIE()) {
+ if (arguments.length > 2) {
+ throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill");
+ }
+ return timer.setTimeout(fn, delay);
+ }
+ return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
+ };
+
+ self.setInterval = function(fn, delay, params) {
+ if (legacyIE()) {
+ if (arguments.length > 2) {
+ throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill");
+ }
+ return timer.setInterval(fn, delay);
+ }
+ return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
+ };
+
+ self.clearTimeout = function(id) {
+ return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
+ };
+
+ self.clearInterval = function(id) {
+ return Function.prototype.call.apply(timer.clearInterval, [global, id]);
+ };
+
+ self.tick = function(millis) {
+ if (installed) {
+ delayedFunctionScheduler.tick(millis);
+ } else {
+ throw new Error("Mock clock is not installed, use jasmine.clock().install()");
+ }
+ };
+
+ return self;
+
+ function legacyIE() {
+ //if these methods are polyfilled, apply will be present
+ return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply;
+ }
+
+ function replace(dest, source) {
+ for (var prop in source) {
+ dest[prop] = source[prop];
+ }
+ }
+
+ function setTimeout(fn, delay) {
+ return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
+ }
+
+ function clearTimeout(id) {
+ return delayedFunctionScheduler.removeFunctionWithId(id);
+ }
+
+ function setInterval(fn, interval) {
+ return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
+ }
+
+ function clearInterval(id) {
+ return delayedFunctionScheduler.removeFunctionWithId(id);
+ }
+
+ function argSlice(argsObj, n) {
+ return Array.prototype.slice.call(argsObj, 2);
+ }
+ }
+
+ return Clock;
+};
+
+getJasmineRequireObj().DelayedFunctionScheduler = function() {
+ function DelayedFunctionScheduler() {
+ var self = this;
+ var scheduledLookup = [];
+ var scheduledFunctions = {};
+ var currentTime = 0;
+ var delayedFnCount = 0;
+
+ self.tick = function(millis) {
+ millis = millis || 0;
+ var endTime = currentTime + millis;
+
+ runScheduledFunctions(endTime);
+ currentTime = endTime;
+ };
+
+ self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
+ var f;
+ if (typeof(funcToCall) === 'string') {
+ /* jshint evil: true */
+ f = function() { return eval(funcToCall); };
+ /* jshint evil: false */
+ } else {
+ f = funcToCall;
+ }
+
+ millis = millis || 0;
+ timeoutKey = timeoutKey || ++delayedFnCount;
+ runAtMillis = runAtMillis || (currentTime + millis);
+
+ var funcToSchedule = {
+ runAtMillis: runAtMillis,
+ funcToCall: f,
+ recurring: recurring,
+ params: params,
+ timeoutKey: timeoutKey,
+ millis: millis
+ };
+
+ if (runAtMillis in scheduledFunctions) {
+ scheduledFunctions[runAtMillis].push(funcToSchedule);
+ } else {
+ scheduledFunctions[runAtMillis] = [funcToSchedule];
+ scheduledLookup.push(runAtMillis);
+ scheduledLookup.sort(function (a, b) {
+ return a - b;
+ });
+ }
+
+ return timeoutKey;
+ };
+
+ self.removeFunctionWithId = function(timeoutKey) {
+ for (var runAtMillis in scheduledFunctions) {
+ var funcs = scheduledFunctions[runAtMillis];
+ var i = indexOfFirstToPass(funcs, function (func) {
+ return func.timeoutKey === timeoutKey;
+ });
+
+ if (i > -1) {
+ if (funcs.length === 1) {
+ delete scheduledFunctions[runAtMillis];
+ deleteFromLookup(runAtMillis);
+ } else {
+ funcs.splice(i, 1);
+ }
+
+ // intervals get rescheduled when executed, so there's never more
+ // than a single scheduled function with a given timeoutKey
+ break;
+ }
+ }
+ };
+
+ self.reset = function() {
+ currentTime = 0;
+ scheduledLookup = [];
+ scheduledFunctions = {};
+ delayedFnCount = 0;
+ };
+
+ return self;
+
+ function indexOfFirstToPass(array, testFn) {
+ var index = -1;
+
+ for (var i = 0; i < array.length; ++i) {
+ if (testFn(array[i])) {
+ index = i;
+ break;
+ }
+ }
+
+ return index;
+ }
+
+ function deleteFromLookup(key) {
+ var value = Number(key);
+ var i = indexOfFirstToPass(scheduledLookup, function (millis) {
+ return millis === value;
+ });
+
+ if (i > -1) {
+ scheduledLookup.splice(i, 1);
+ }
+ }
+
+ function reschedule(scheduledFn) {
+ self.scheduleFunction(scheduledFn.funcToCall,
+ scheduledFn.millis,
+ scheduledFn.params,
+ true,
+ scheduledFn.timeoutKey,
+ scheduledFn.runAtMillis + scheduledFn.millis);
+ }
+
+ function runScheduledFunctions(endTime) {
+ if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
+ return;
+ }
+
+ do {
+ currentTime = scheduledLookup.shift();
+
+ var funcsToRun = scheduledFunctions[currentTime];
+ delete scheduledFunctions[currentTime];
+
+ for (var i = 0; i < funcsToRun.length; ++i) {
+ var funcToRun = funcsToRun[i];
+ funcToRun.funcToCall.apply(null, funcToRun.params || []);
+
+ if (funcToRun.recurring) {
+ reschedule(funcToRun);
+ }
+ }
+ } while (scheduledLookup.length > 0 &&
+ // checking first if we're out of time prevents setTimeout(0)
+ // scheduled in a funcToRun from forcing an extra iteration
+ currentTime !== endTime &&
+ scheduledLookup[0] <= endTime);
+ }
+ }
+
+ return DelayedFunctionScheduler;
+};
+
+getJasmineRequireObj().ExceptionFormatter = function() {
+ function ExceptionFormatter() {
+ this.message = function(error) {
+ var message = error.name +
+ ': ' +
+ error.message;
+
+ if (error.fileName || error.sourceURL) {
+ message += " in " + (error.fileName || error.sourceURL);
+ }
+
+ if (error.line || error.lineNumber) {
+ message += " (line " + (error.line || error.lineNumber) + ")";
+ }
+
+ return message;
+ };
+
+ this.stack = function(error) {
+ return error ? error.stack : null;
+ };
+ }
+
+ return ExceptionFormatter;
+};
+
+getJasmineRequireObj().Expectation = function() {
+
+ var matchers = {};
+
+ function Expectation(options) {
+ this.util = options.util || { buildFailureMessage: function() {} };
+ this.customEqualityTesters = options.customEqualityTesters || [];
+ this.actual = options.actual;
+ this.addExpectationResult = options.addExpectationResult || function(){};
+ this.isNot = options.isNot;
+
+ for (var matcherName in matchers) {
+ this[matcherName] = matchers[matcherName];
+ }
+ }
+
+ Expectation.prototype.wrapCompare = function(name, matcherFactory) {
+ return function() {
+ var args = Array.prototype.slice.call(arguments, 0),
+ expected = args.slice(0),
+ message = "";
+
+ args.unshift(this.actual);
+
+ var matcher = matcherFactory(this.util, this.customEqualityTesters),
+ matcherCompare = matcher.compare;
+
+ function defaultNegativeCompare() {
+ var result = matcher.compare.apply(null, args);
+ result.pass = !result.pass;
+ return result;
+ }
+
+ if (this.isNot) {
+ matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
+ }
+
+ var result = matcherCompare.apply(null, args);
+
+ if (!result.pass) {
+ if (!result.message) {
+ args.unshift(this.isNot);
+ args.unshift(name);
+ message = this.util.buildFailureMessage.apply(null, args);
+ } else {
+ message = result.message;
+ }
+ }
+
+ if (expected.length == 1) {
+ expected = expected[0];
+ }
+
+ // TODO: how many of these params are needed?
+ this.addExpectationResult(
+ result.pass,
+ {
+ matcherName: name,
+ passed: result.pass,
+ message: message,
+ actual: this.actual,
+ expected: expected // TODO: this may need to be arrayified/sliced
+ }
+ );
+ };
+ };
+
+ Expectation.addCoreMatchers = function(matchers) {
+ var prototype = Expectation.prototype;
+ for (var matcherName in matchers) {
+ var matcher = matchers[matcherName];
+ prototype[matcherName] = prototype.wrapCompare(matcherName, matcher);
+ }
+ };
+
+ Expectation.addMatchers = function(matchersToAdd) {
+ for (var name in matchersToAdd) {
+ var matcher = matchersToAdd[name];
+ matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
+ }
+ };
+
+ Expectation.resetMatchers = function() {
+ for (var name in matchers) {
+ delete matchers[name];
+ }
+ };
+
+ Expectation.Factory = function(options) {
+ options = options || {};
+
+ var expect = new Expectation(options);
+
+ // TODO: this would be nice as its own Object - NegativeExpectation
+ // TODO: copy instead of mutate options
+ options.isNot = true;
+ expect.not = new Expectation(options);
+
+ return expect;
+ };
+
+ return Expectation;
+};
+
+//TODO: expectation result may make more sense as a presentation of an expectation.
+getJasmineRequireObj().buildExpectationResult = function() {
+ function buildExpectationResult(options) {
+ var messageFormatter = options.messageFormatter || function() {},
+ stackFormatter = options.stackFormatter || function() {};
+
+ return {
+ matcherName: options.matcherName,
+ expected: options.expected,
+ actual: options.actual,
+ message: message(),
+ stack: stack(),
+ passed: options.passed
+ };
+
+ function message() {
+ if (options.passed) {
+ return "Passed.";
+ } else if (options.message) {
+ return options.message;
+ } else if (options.error) {
+ return messageFormatter(options.error);
+ }
+ return "";
+ }
+
+ function stack() {
+ if (options.passed) {
+ return "";
+ }
+
+ var error = options.error;
+ if (!error) {
+ try {
+ throw new Error(message());
+ } catch (e) {
+ error = e;
+ }
+ }
+ return stackFormatter(error);
+ }
+ }
+
+ return buildExpectationResult;
+};
+
+getJasmineRequireObj().ObjectContaining = function(j$) {
+
+ function ObjectContaining(sample) {
+ this.sample = sample;
+ }
+
+ ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+ if (typeof(this.sample) !== "object") { throw new Error("You must provide an object to objectContaining, not '"+this.sample+"'."); }
+
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ var hasKey = function(obj, keyName) {
+ return obj !== null && !j$.util.isUndefined(obj[keyName]);
+ };
+
+ for (var property in this.sample) {
+ if (!hasKey(other, property) && hasKey(this.sample, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ else if (!j$.matchersUtil.equals(this.sample[property], other[property])) {
+ mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in actual, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in expected.");
+ }
+ }
+
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+ };
+
+ ObjectContaining.prototype.jasmineToString = function() {
+ return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>";
+ };
+
+ return ObjectContaining;
+};
+
+getJasmineRequireObj().pp = function(j$) {
+
+ function PrettyPrinter() {
+ this.ppNestLevel_ = 0;
+ }
+
+ PrettyPrinter.prototype.format = function(value) {
+ this.ppNestLevel_++;
+ try {
+ if (j$.util.isUndefined(value)) {
+ this.emitScalar('undefined');
+ } else if (value === null) {
+ this.emitScalar('null');
+ } else if (value === j$.getGlobal()) {
+ this.emitScalar('<global>');
+ } else if (value.jasmineToString) {
+ this.emitScalar(value.jasmineToString());
+ } else if (typeof value === 'string') {
+ this.emitString(value);
+ } else if (j$.isSpy(value)) {
+ this.emitScalar("spy on " + value.and.identity());
+ } else if (value instanceof RegExp) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'function') {
+ this.emitScalar('Function');
+ } else if (typeof value.nodeType === 'number') {
+ this.emitScalar('HTMLNode');
+ } else if (value instanceof Date) {
+ this.emitScalar('Date(' + value + ')');
+ } else if (value.__Jasmine_been_here_before__) {
+ this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
+ } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
+ value.__Jasmine_been_here_before__ = true;
+ if (j$.isArray_(value)) {
+ this.emitArray(value);
+ } else {
+ this.emitObject(value);
+ }
+ delete value.__Jasmine_been_here_before__;
+ } else {
+ this.emitScalar(value.toString());
+ }
+ } finally {
+ this.ppNestLevel_--;
+ }
+ };
+
+ PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+ for (var property in obj) {
+ if (!obj.hasOwnProperty(property)) { continue; }
+ if (property == '__Jasmine_been_here_before__') { continue; }
+ fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
+ obj.__lookupGetter__(property) !== null) : false);
+ }
+ };
+
+ PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
+ PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
+ PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
+ PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
+
+ function StringPrettyPrinter() {
+ PrettyPrinter.call(this);
+
+ this.string = '';
+ }
+
+ j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
+
+ StringPrettyPrinter.prototype.emitScalar = function(value) {
+ this.append(value);
+ };
+
+ StringPrettyPrinter.prototype.emitString = function(value) {
+ this.append("'" + value + "'");
+ };
+
+ StringPrettyPrinter.prototype.emitArray = function(array) {
+ if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+ this.append("Array");
+ return;
+ }
+
+ this.append('[ ');
+ for (var i = 0; i < array.length; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(array[i]);
+ }
+ this.append(' ]');
+ };
+
+ StringPrettyPrinter.prototype.emitObject = function(obj) {
+ if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+ this.append("Object");
+ return;
+ }
+
+ var self = this;
+ this.append('{ ');
+ var first = true;
+
+ this.iterateObject(obj, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.append(property);
+ self.append(' : ');
+ if (isGetter) {
+ self.append('<getter>');
+ } else {
+ self.format(obj[property]);
+ }
+ });
+
+ this.append(' }');
+ };
+
+ StringPrettyPrinter.prototype.append = function(value) {
+ this.string += value;
+ };
+
+ return function(value) {
+ var stringPrettyPrinter = new StringPrettyPrinter();
+ stringPrettyPrinter.format(value);
+ return stringPrettyPrinter.string;
+ };
+};
+
+getJasmineRequireObj().QueueRunner = function() {
+
+ function QueueRunner(attrs) {
+ this.fns = attrs.fns || [];
+ this.onComplete = attrs.onComplete || function() {};
+ this.clearStack = attrs.clearStack || function(fn) {fn();};
+ this.onException = attrs.onException || function() {};
+ this.catchException = attrs.catchException || function() { return true; };
+ this.userContext = {};
+ }
+
+ QueueRunner.prototype.execute = function() {
+ this.run(this.fns, 0);
+ };
+
+ QueueRunner.prototype.run = function(fns, recursiveIndex) {
+ var length = fns.length,
+ self = this,
+ iterativeIndex;
+
+ for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
+ var fn = fns[iterativeIndex];
+ if (fn.length > 0) {
+ return attemptAsync(fn);
+ } else {
+ attemptSync(fn);
+ }
+ }
+
+ var runnerDone = iterativeIndex >= length;
+
+ if (runnerDone) {
+ this.clearStack(this.onComplete);
+ }
+
+ function attemptSync(fn) {
+ try {
+ fn.call(self.userContext);
+ } catch (e) {
+ handleException(e);
+ }
+ }
+
+ function attemptAsync(fn) {
+ var next = function () { self.run(fns, iterativeIndex + 1); };
+
+ try {
+ fn.call(self.userContext, next);
+ } catch (e) {
+ handleException(e);
+ next();
+ }
+ }
+
+ function handleException(e) {
+ self.onException(e);
+ if (!self.catchException(e)) {
+ //TODO: set a var when we catch an exception and
+ //use a finally block to close the loop in a nice way..
+ throw e;
+ }
+ }
+ };
+
+ return QueueRunner;
+};
+
+getJasmineRequireObj().ReportDispatcher = function() {
+ function ReportDispatcher(methods) {
+
+ var dispatchedMethods = methods || [];
+
+ for (var i = 0; i < dispatchedMethods.length; i++) {
+ var method = dispatchedMethods[i];
+ this[method] = (function(m) {
+ return function() {
+ dispatch(m, arguments);
+ };
+ }(method));
+ }
+
+ var reporters = [];
+
+ this.addReporter = function(reporter) {
+ reporters.push(reporter);
+ };
+
+ return this;
+
+ function dispatch(method, args) {
+ for (var i = 0; i < reporters.length; i++) {
+ var reporter = reporters[i];
+ if (reporter[method]) {
+ reporter[method].apply(reporter, args);
+ }
+ }
+ }
+ }
+
+ return ReportDispatcher;
+};
+
+
+getJasmineRequireObj().SpyStrategy = function() {
+
+ function SpyStrategy(options) {
+ options = options || {};
+
+ var identity = options.name || "unknown",
+ originalFn = options.fn || function() {},
+ getSpy = options.getSpy || function() {},
+ plan = function() {};
+
+ this.identity = function() {
+ return identity;
+ };
+
+ this.exec = function() {
+ return plan.apply(this, arguments);
+ };
+
+ this.callThrough = function() {
+ plan = originalFn;
+ return getSpy();
+ };
+
+ this.returnValue = function(value) {
+ plan = function() {
+ return value;
+ };
+ return getSpy();
+ };
+
+ this.throwError = function(something) {
+ var error = (something instanceof Error) ? something : new Error(something);
+ plan = function() {
+ throw error;
+ };
+ return getSpy();
+ };
+
+ this.callFake = function(fn) {
+ plan = fn;
+ return getSpy();
+ };
+
+ this.stub = function(fn) {
+ plan = function() {};
+ return getSpy();
+ };
+ }
+
+ return SpyStrategy;
+};
+
+getJasmineRequireObj().Suite = function() {
+ function Suite(attrs) {
+ this.env = attrs.env;
+ this.id = attrs.id;
+ this.parentSuite = attrs.parentSuite;
+ this.description = attrs.description;
+ this.onStart = attrs.onStart || function() {};
+ this.resultCallback = attrs.resultCallback || function() {};
+ this.clearStack = attrs.clearStack || function(fn) {fn();};
+
+ this.beforeFns = [];
+ this.afterFns = [];
+ this.queueRunner = attrs.queueRunner || function() {};
+ this.disabled = false;
+
+ this.children = [];
+
+ this.result = {
+ id: this.id,
+ status: this.disabled ? 'disabled' : '',
+ description: this.description,
+ fullName: this.getFullName()
+ };
+ }
+
+ Suite.prototype.getFullName = function() {
+ var fullName = this.description;
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ if (parentSuite.parentSuite) {
+ fullName = parentSuite.description + ' ' + fullName;
+ }
+ }
+ return fullName;
+ };
+
+ Suite.prototype.disable = function() {
+ this.disabled = true;
+ };
+
+ Suite.prototype.beforeEach = function(fn) {
+ this.beforeFns.unshift(fn);
+ };
+
+ Suite.prototype.afterEach = function(fn) {
+ this.afterFns.unshift(fn);
+ };
+
+ Suite.prototype.addChild = function(child) {
+ this.children.push(child);
+ };
+
+ Suite.prototype.execute = function(onComplete) {
+ var self = this;
+ if (this.disabled) {
+ complete();
+ return;
+ }
+
+ var allFns = [];
+
+ for (var i = 0; i < this.children.length; i++) {
+ allFns.push(wrapChildAsAsync(this.children[i]));
+ }
+
+ this.onStart(this);
+
+ this.queueRunner({
+ fns: allFns,
+ onComplete: complete
+ });
+
+ function complete() {
+ self.resultCallback(self.result);
+
+ if (onComplete) {
+ onComplete();
+ }
+ }
+
+ function wrapChildAsAsync(child) {
+ return function(done) { child.execute(done); };
+ }
+ };
+
+ return Suite;
+};
+
+if (typeof window == void 0 && typeof exports == "object") {
+ exports.Suite = jasmineRequire.Suite;
+}
+
+getJasmineRequireObj().Timer = function() {
+ function Timer(options) {
+ options = options || {};
+
+ var now = options.now || function() { return new Date().getTime(); },
+ startTime;
+
+ this.start = function() {
+ startTime = now();
+ };
+
+ this.elapsed = function() {
+ return now() - startTime;
+ };
+ }
+
+ return Timer;
+};
+
+getJasmineRequireObj().matchersUtil = function(j$) {
+ // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
+
+ return {
+ equals: function(a, b, customTesters) {
+ customTesters = customTesters || [];
+
+ return eq(a, b, [], [], customTesters);
+ },
+
+ contains: function(haystack, needle, customTesters) {
+ customTesters = customTesters || [];
+
+ if (Object.prototype.toString.apply(haystack) === "[object Array]") {
+ for (var i = 0; i < haystack.length; i++) {
+ if (eq(haystack[i], needle, [], [], customTesters)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return haystack.indexOf(needle) >= 0;
+ },
+
+ buildFailureMessage: function() {
+ var args = Array.prototype.slice.call(arguments, 0),
+ matcherName = args[0],
+ isNot = args[1],
+ actual = args[2],
+ expected = args.slice(3),
+ englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+
+ var message = "Expected " +
+ j$.pp(actual) +
+ (isNot ? " not " : " ") +
+ englishyPredicate;
+
+ if (expected.length > 0) {
+ for (var i = 0; i < expected.length; i++) {
+ if (i > 0) {
+ message += ",";
+ }
+ message += " " + j$.pp(expected[i]);
+ }
+ }
+
+ return message + ".";
+ }
+ };
+
+ // Equality function lovingly adapted from isEqual in
+ // [Underscore](http://underscorejs.org)
+ function eq(a, b, aStack, bStack, customTesters) {
+ var result = true;
+
+ for (var i = 0; i < customTesters.length; i++) {
+ var customTesterResult = customTesters[i](a, b);
+ if (!j$.util.isUndefined(customTesterResult)) {
+ return customTesterResult;
+ }
+ }
+
+ if (a instanceof j$.Any) {
+ result = a.jasmineMatches(b);
+ if (result) {
+ return true;
+ }
+ }
+
+ if (b instanceof j$.Any) {
+ result = b.jasmineMatches(a);
+ if (result) {
+ return true;
+ }
+ }
+
+ if (b instanceof j$.ObjectContaining) {
+ result = b.jasmineMatches(a);
+ if (result) {
+ return true;
+ }
+ }
+
+ if (a instanceof Error && b instanceof Error) {
+ return a.message == b.message;
+ }
+
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+ if (a === b) { return a !== 0 || 1 / a == 1 / b; }
+ // A strict comparison is necessary because `null == undefined`.
+ if (a === null || b === null) { return a === b; }
+ var className = Object.prototype.toString.call(a);
+ if (className != Object.prototype.toString.call(b)) { return false; }
+ switch (className) {
+ // Strings, numbers, dates, and booleans are compared by value.
+ case '[object String]':
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+ // equivalent to `new String("5")`.
+ return a == String(b);
+ case '[object Number]':
+ // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+ // other numeric values.
+ return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
+ case '[object Date]':
+ case '[object Boolean]':
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are not equivalent.
+ return +a == +b;
+ // RegExps are compared by their source patterns and flags.
+ case '[object RegExp]':
+ return a.source == b.source &&
+ a.global == b.global &&
+ a.multiline == b.multiline &&
+ a.ignoreCase == b.ignoreCase;
+ }
+ if (typeof a != 'object' || typeof b != 'object') { return false; }
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+ var length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (aStack[length] == a) { return bStack[length] == b; }
+ }
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+ var size = 0;
+ // Recursively compare objects and arrays.
+ if (className == '[object Array]') {
+ // Compare array lengths to determine if a deep comparison is necessary.
+ size = a.length;
+ result = size == b.length;
+ if (result) {
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (size--) {
+ if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; }
+ }
+ }
+ } else {
+ // Objects with different constructors are not equivalent, but `Object`s
+ // from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) &&
+ isFunction(bCtor) && (bCtor instanceof bCtor))) {
+ return false;
+ }
+ // Deep compare objects.
+ for (var key in a) {
+ if (has(a, key)) {
+ // Count the expected number of properties.
+ size++;
+ // Deep compare each member.
+ if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; }
+ }
+ }
+ // Ensure that both objects contain the same number of properties.
+ if (result) {
+ for (key in b) {
+ if (has(b, key) && !(size--)) { break; }
+ }
+ result = !size;
+ }
+ }
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+
+ return result;
+
+ function has(obj, key) {
+ return obj.hasOwnProperty(key);
+ }
+
+ function isFunction(obj) {
+ return typeof obj === 'function';
+ }
+ }
+};
+
+getJasmineRequireObj().toBe = function() {
+ function toBe() {
+ return {
+ compare: function(actual, expected) {
+ return {
+ pass: actual === expected
+ };
+ }
+ };
+ }
+
+ return toBe;
+};
+
+getJasmineRequireObj().toBeCloseTo = function() {
+
+ function toBeCloseTo() {
+ return {
+ compare: function(actual, expected, precision) {
+ if (precision !== 0) {
+ precision = precision || 2;
+ }
+
+ return {
+ pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
+ };
+ }
+ };
+ }
+
+ return toBeCloseTo;
+};
+
+getJasmineRequireObj().toBeDefined = function() {
+ function toBeDefined() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: (void 0 !== actual)
+ };
+ }
+ };
+ }
+
+ return toBeDefined;
+};
+
+getJasmineRequireObj().toBeFalsy = function() {
+ function toBeFalsy() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: !!!actual
+ };
+ }
+ };
+ }
+
+ return toBeFalsy;
+};
+
+getJasmineRequireObj().toBeGreaterThan = function() {
+
+ function toBeGreaterThan() {
+ return {
+ compare: function(actual, expected) {
+ return {
+ pass: actual > expected
+ };
+ }
+ };
+ }
+
+ return toBeGreaterThan;
+};
+
+
+getJasmineRequireObj().toBeLessThan = function() {
+ function toBeLessThan() {
+ return {
+
+ compare: function(actual, expected) {
+ return {
+ pass: actual < expected
+ };
+ }
+ };
+ }
+
+ return toBeLessThan;
+};
+getJasmineRequireObj().toBeNaN = function(j$) {
+
+ function toBeNaN() {
+ return {
+ compare: function(actual) {
+ var result = {
+ pass: (actual !== actual)
+ };
+
+ if (result.pass) {
+ result.message = "Expected actual not to be NaN.";
+ } else {
+ result.message = "Expected " + j$.pp(actual) + " to be NaN.";
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toBeNaN;
+};
+
+getJasmineRequireObj().toBeNull = function() {
+
+ function toBeNull() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: actual === null
+ };
+ }
+ };
+ }
+
+ return toBeNull;
+};
+
+getJasmineRequireObj().toBeTruthy = function() {
+
+ function toBeTruthy() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: !!actual
+ };
+ }
+ };
+ }
+
+ return toBeTruthy;
+};
+
+getJasmineRequireObj().toBeUndefined = function() {
+
+ function toBeUndefined() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: void 0 === actual
+ };
+ }
+ };
+ }
+
+ return toBeUndefined;
+};
+
+getJasmineRequireObj().toContain = function() {
+ function toContain(util, customEqualityTesters) {
+ customEqualityTesters = customEqualityTesters || [];
+
+ return {
+ compare: function(actual, expected) {
+
+ return {
+ pass: util.contains(actual, expected, customEqualityTesters)
+ };
+ }
+ };
+ }
+
+ return toContain;
+};
+
+getJasmineRequireObj().toEqual = function() {
+
+ function toEqual(util, customEqualityTesters) {
+ customEqualityTesters = customEqualityTesters || [];
+
+ return {
+ compare: function(actual, expected) {
+ var result = {
+ pass: false
+ };
+
+ result.pass = util.equals(actual, expected, customEqualityTesters);
+
+ return result;
+ }
+ };
+ }
+
+ return toEqual;
+};
+
+getJasmineRequireObj().toHaveBeenCalled = function(j$) {
+
+ function toHaveBeenCalled() {
+ return {
+ compare: function(actual) {
+ var result = {};
+
+ if (!j$.isSpy(actual)) {
+ throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
+ }
+
+ if (arguments.length > 1) {
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ result.pass = actual.calls.any();
+
+ result.message = result.pass ?
+ "Expected spy " + actual.and.identity() + " not to have been called." :
+ "Expected spy " + actual.and.identity() + " to have been called.";
+
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalled;
+};
+
+getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
+
+ function toHaveBeenCalledWith(util) {
+ return {
+ compare: function() {
+ var args = Array.prototype.slice.call(arguments, 0),
+ actual = args[0],
+ expectedArgs = args.slice(1),
+ result = { pass: false };
+
+ if (!j$.isSpy(actual)) {
+ throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
+ }
+
+ if (!actual.calls.any()) {
+ result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but it was never called.";
+ return result;
+ }
+
+ if (util.contains(actual.calls.allArgs(), expectedArgs)) {
+ result.pass = true;
+ result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";
+ } else {
+ result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but actual calls were " + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + ".";
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalledWith;
+};
+
+getJasmineRequireObj().toMatch = function() {
+
+ function toMatch() {
+ return {
+ compare: function(actual, expected) {
+ var regexp = new RegExp(expected);
+
+ return {
+ pass: regexp.test(actual)
+ };
+ }
+ };
+ }
+
+ return toMatch;
+};
+
+getJasmineRequireObj().toThrow = function(j$) {
+
+ function toThrow(util) {
+ return {
+ compare: function(actual, expected) {
+ var result = { pass: false },
+ threw = false,
+ thrown;
+
+ if (typeof actual != "function") {
+ throw new Error("Actual is not a Function");
+ }
+
+ try {
+ actual();
+ } catch (e) {
+ threw = true;
+ thrown = e;
+ }
+
+ if (!threw) {
+ result.message = "Expected function to throw an exception.";
+ return result;
+ }
+
+ if (arguments.length == 1) {
+ result.pass = true;
+ result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + ".";
+
+ return result;
+ }
+
+ if (util.equals(thrown, expected)) {
+ result.pass = true;
+ result.message = "Expected function not to throw " + j$.pp(expected) + ".";
+ } else {
+ result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " + j$.pp(thrown) + ".";
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toThrow;
+};
+
+getJasmineRequireObj().toThrowError = function(j$) {
+ function toThrowError (util) {
+ return {
+ compare: function(actual) {
+ var threw = false,
+ thrown,
+ errorType,
+ message,
+ regexp,
+ name,
+ constructorName;
+
+ if (typeof actual != "function") {
+ throw new Error("Actual is not a Function");
+ }
+
+ extractExpectedParams.apply(null, arguments);
+
+ try {
+ actual();
+ } catch (e) {
+ threw = true;
+ thrown = e;
+ }
+
+ if (!threw) {
+ return fail("Expected function to throw an Error.");
+ }
+
+ if (!(thrown instanceof Error)) {
+ return fail("Expected function to throw an Error, but it threw " + thrown + ".");
+ }
+
+ if (arguments.length == 1) {
+ return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + ".");
+ }
+
+ if (errorType) {
+ name = fnNameFor(errorType);
+ constructorName = fnNameFor(thrown.constructor);
+ }
+
+ if (errorType && message) {
+ if (thrown.constructor == errorType && util.equals(thrown.message, message)) {
+ return pass("Expected function not to throw " + name + " with message \"" + message + "\".");
+ } else {
+ return fail("Expected function to throw " + name + " with message \"" + message +
+ "\", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
+ }
+ }
+
+ if (errorType && regexp) {
+ if (thrown.constructor == errorType && regexp.test(thrown.message)) {
+ return pass("Expected function not to throw " + name + " with message matching " + regexp + ".");
+ } else {
+ return fail("Expected function to throw " + name + " with message matching " + regexp +
+ ", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
+ }
+ }
+
+ if (errorType) {
+ if (thrown.constructor == errorType) {
+ return pass("Expected function not to throw " + name + ".");
+ } else {
+ return fail("Expected function to throw " + name + ", but it threw " + constructorName + ".");
+ }
+ }
+
+ if (message) {
+ if (thrown.message == message) {
+ return pass("Expected function not to throw an exception with message " + j$.pp(message) + ".");
+ } else {
+ return fail("Expected function to throw an exception with message " + j$.pp(message) +
+ ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
+ }
+ }
+
+ if (regexp) {
+ if (regexp.test(thrown.message)) {
+ return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + ".");
+ } else {
+ return fail("Expected function to throw an exception with a message matching " + j$.pp(regexp) +
+ ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
+ }
+ }
+
+ function fnNameFor(func) {
+ return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
+ }
+
+ function pass(notMessage) {
+ return {
+ pass: true,
+ message: notMessage
+ };
+ }
+
+ function fail(message) {
+ return {
+ pass: false,
+ message: message
+ };
+ }
+
+ function extractExpectedParams() {
+ if (arguments.length == 1) {
+ return;
+ }
+
+ if (arguments.length == 2) {
+ var expected = arguments[1];
+
+ if (expected instanceof RegExp) {
+ regexp = expected;
+ } else if (typeof expected == "string") {
+ message = expected;
+ } else if (checkForAnErrorType(expected)) {
+ errorType = expected;
+ }
+
+ if (!(errorType || message || regexp)) {
+ throw new Error("Expected is not an Error, string, or RegExp.");
+ }
+ } else {
+ if (checkForAnErrorType(arguments[1])) {
+ errorType = arguments[1];
+ } else {
+ throw new Error("Expected error type is not an Error.");
+ }
+
+ if (arguments[2] instanceof RegExp) {
+ regexp = arguments[2];
+ } else if (typeof arguments[2] == "string") {
+ message = arguments[2];
+ } else {
+ throw new Error("Expected error message is not a string or RegExp.");
+ }
+ }
+ }
+
+ function checkForAnErrorType(type) {
+ if (typeof type !== "function") {
+ return false;
+ }
+
+ var Surrogate = function() {};
+ Surrogate.prototype = type.prototype;
+ return (new Surrogate()) instanceof Error;
+ }
+ }
+ };
+ }
+
+ return toThrowError;
+};
+
+getJasmineRequireObj().version = function() {
+ return "2.0.0";
+};
diff --git a/test/lib/jasmine-2.0.0/jasmine_favicon.png b/test/lib/jasmine-2.0.0/jasmine_favicon.png
new file mode 100755
index 0000000..3562e27
--- /dev/null
+++ b/test/lib/jasmine-2.0.0/jasmine_favicon.png
Binary files differ
diff --git a/test/libs/jasmine-1.2.0/YamlSpec.js b/test/libs/jasmine-1.2.0/YamlSpec.js
deleted file mode 100644
index f3b9f79..0000000
--- a/test/libs/jasmine-1.2.0/YamlSpec.js
+++ /dev/null
@@ -1,22 +0,0 @@
-describe("YAML parsing", function() {
- var t;
- for ( var i = 0; i < YAML.parseTests.length; i++){
-
- t = YAML.parseTests[i];
-
- it(t.title, function() {
- expect(YAML.parse(t.input)).toEqual(t.output);
- });
- }
-});
-describe("YAML dumping and parsing", function() {
- var t;
- for ( var i = 0; i < YAML.parseTests.length; i++){
-
- t = YAML.parseTests[i];
-
- it(t.title, function() {
- expect(YAML.parse(YAML.stringify(t.output))).toEqual(t.output);
- });
- }
-}); \ No newline at end of file
diff --git a/test/libs/jasmine-1.2.0/YamlTests.js b/test/libs/jasmine-1.2.0/YamlTests.js
deleted file mode 100644
index 3b8d5d6..0000000
--- a/test/libs/jasmine-1.2.0/YamlTests.js
+++ /dev/null
@@ -1,699 +0,0 @@
-YAML.parseTests=[
- {
- title: "Simple Sequence",
- input:
-'\
-- apple\n\
-- banana\n\
-- carrot\n\
-',
- output: ['apple', 'banana', 'carrot']
- },
- {
- title: "Nested Sequences",
- input:
-'\
--\n\
- - foo\n\
- - bar\n\
- - baz\n\
-',
- output: [['foo', 'bar', 'baz']]
- },
- {
- title: "Mixed Sequences",
- input:
-'\
-- apple\n\
--\n\
- - foo\n\
- - bar\n\
- - x123\n\
-- banana\n\
-- carrot\n\
-',
- output: ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
- },
- {
- title: "Deeply Nested Sequences",
- input:
-'\
--\n\
- -\n\
- - uno\n\
- - dos\n\
-',
- output: [[['uno', 'dos']]]
- },
- {
- title: "Simple Mapping",
- input:
-'\
-foo: whatever\n\
-bar: stuff\n\
-',
- output: { 'foo' : 'whatever', 'bar' : 'stuff' }
- },
- {
- title: "Sequence in a Mapping",
- input:
-'\
-foo: whatever\n\
-bar:\n\
- - uno\n\
- - dos\n\
-',
- output: { 'foo' : 'whatever', 'bar' : [ 'uno', 'dos' ] }
- },
- {
- title: "Unindented Sequence in a Mapping",
- input:
-'\
-foo:\n\
-- uno: 1\n\
- dos: 2\n\
-',
- output: { 'foo' : [ {'uno': 1, 'dos': 2} ] }
- },
- {
- title: "Nested Mappings",
- input:
-'\
-foo: whatever\n\
-bar:\n\
- fruit: apple\n\
- name: steve\n\
- sport: baseball\n\
-',
- output:
- { 'foo' : 'whatever',
- 'bar' : {
- 'fruit' : 'apple',
- 'name' : 'steve',
- 'sport' : 'baseball'
- }
- }
- },
- {
- title: "Mixed Mapping",
- input:
-'\
-foo: whatever\n\
-bar:\n\
- -\n\
- fruit: apple\n\
- name: steve\n\
- sport: baseball\n\
- - more\n\
- -\n\
- python: rocks\n\
- perl: papers\n\
- ruby: scissorses\n\
-',
- output:
- { 'foo' : 'whatever',
- 'bar' : [
- {
- 'fruit' : 'apple',
- 'name' : 'steve',
- 'sport' : 'baseball'
- },
- 'more',
- {
- 'python' : 'rocks',
- 'perl' : 'papers',
- 'ruby' : 'scissorses'
- }
- ]
- }
- },
- {
- title: "Mapping-in-Sequence Shortcut",
- input:
-'\
-- work on YAML.py:\n\
- - work on Store\n\
-',
- output: [ { 'work on YAML.py' : ['work on Store'] } ]
-
- },
- {
- title: "Sequence-in-Mapping Shortcut",
- input:
-"\
-allow:\n\
-- 'localhost'\n\
-- '%.sourceforge.net'\n\
-- '%.freepan.org'\n\
-",
- output: { 'allow' : [ 'localhost', '%.sourceforge.net', '%.freepan.org' ] }
-
- },
- {
- title: "Merge key",
- disabled: true,
- input:
-"\
-mapping:\n\
- name: Joe\n\
- job: Accountant\n\
- <<:\n\
- age: 38\n\
-",
- output:
- { 'mapping' :
- { 'name' : 'Joe',
- 'job' : 'Accountant',
- 'age' : 38
- }
- }
- },
- {
- title: "Simple Inline Array",
- input:
-"\
---- \n\
-seq: [ a, b, c ]\n\
-",
- output: { 'seq' : [ 'a', 'b', 'c' ] }
-
- },
- {
- title: "Simple Inline Hash",
- input:
-"\
----\n\
-hash: { name: Steve, foo: bar }\n\
-",
- output: { 'hash' : { 'name' : 'Steve', 'foo' : 'bar' } }
-
- },
- {
- title: "Multi-line Inline Collections",
- input:
-"\
-languages: [ Ruby,\n\
- Perl,\n\
- Python ]\n\
-websites: { YAML: yaml.org,\n\
- Ruby: ruby-lang.org,\n\
- Python: python.org,\n\
- Perl: use.perl.org }\n\
-",
- output:
- { 'languages' : [ 'Ruby', 'Perl', 'Python' ],
- 'websites' : {
- 'YAML' : 'yaml.org',
- 'Ruby' : 'ruby-lang.org',
- 'Python' : 'python.org',
- 'Perl' : 'use.perl.org'
- }
- }
- },
- {
- title: "Commas in Values",
- input:
-"\
-attendances: [ 45,123, 70,000, 17,222 ]\n\
-",
- output: { 'attendances' : [ 45123, 70000, 17222 ] }
-
- },
- {
- title: "Strings",
- input:
-"\
---- \n\
-String\n\
-",
- output: 'String'
-
- },
- {
- title: "String characters",
- input:
-"\
-- What's Yaml?\n\
-- It's for writing data structures in plain text.\n\
-- And?\n\
-- And what? That's not good enough for you?\n\
-- No, I mean, \"And what about Yaml?\"\n\
-- Oh, oh yeah. Uh.. Yaml for Ruby.\n\
-",
- output:
- [
- "What's Yaml?",
- "It's for writing data structures in plain text.",
- "And?",
- "And what? That's not good enough for you?",
- "No, I mean, \"And what about Yaml?\"",
- "Oh, oh yeah. Uh.. Yaml for Ruby."
- ]
- },
- {
- title: "Indicators in Strings",
- input:
-"\
-the colon followed by space is an indicator: but is a string:right here\n\
-same for the pound sign: here we have it#in a string\n\
-the comma can, honestly, be used in most cases: [ but not in, inline collections ]\n\
-",
- output:
- {
- 'the colon followed by space is an indicator' : 'but is a string:right here',
- 'same for the pound sign' : 'here we have it#in a string',
- 'the comma can, honestly, be used in most cases' : [ 'but not in', 'inline collections' ]
- }
- },
- {
- title: "Forcing Strings",
- input:
-"\
-date string: !str 2001-08-01\n\
-number string: !str 192\n\
-",
- output:
- {
- 'date string' : '2001-08-01',
- 'number string' : '192'
- }
- },
- {
- title: "Single-quoted Strings",
- input:
-"\
-all my favorite symbols: '#:!/%.)'\n\
-a few i hate: '&(*'\n\
-why do i hate them?: 'it''s very hard to explain'\n\
-",
- output:
- {
- 'all my favorite symbols' : '#:!/%.)',
- 'a few i hate' : '&(*',
- 'why do i hate them?' : 'it\'s very hard to explain'
- }
- },
- {
- title: "Double-quoted Strings",
- input:
-'\
-i know where i want my line breaks: "one here\\nand another here\\n"\n\
-',
- output:
- {
- 'i know where i want my line breaks' : "one here\nand another here\n"
- }
- },
- {
- title: "Multi-line Quoted Strings",
- input:
-"\
-i want a long string: \"so i'm going to\n\
- let it go on and on to other lines\n\
- until i end it with a quote.\"\n\
-",
- output:
- { 'i want a long string' : "so i'm going to " +
- "let it go on and on to other lines " +
- "until i end it with a quote."
- }
- },
- {
- title: "Plain scalars",
- input:
-"\
-- My little toe is broken in two places;\n\
-- I'm crazy to have skied this way;\n\
-- I'm not the craziest he's seen, since there was always the German guy\n\
- who skied for 3 hours on a broken shin bone (just below the kneecap);\n\
-- Nevertheless, second place is respectable, and he doesn't\n\
- recommend going for the record;\n\
-- He's going to put my foot in plaster for a month;\n\
-- This would impair my skiing ability somewhat for the\n\
- duration, as can be imagined.\n\
-",
- output:
- [
- "My little toe is broken in two places;",
- "I'm crazy to have skied this way;",
- "I'm not the craziest he's seen, since there was always " +
- "the German guy who skied for 3 hours on a broken shin " +
- "bone (just below the kneecap);",
- "Nevertheless, second place is respectable, and he doesn't " +
- "recommend going for the record;",
- "He's going to put my foot in plaster for a month;",
- "This would impair my skiing ability somewhat for the duration, " +
- "as can be imagined."
- ]
- },
- {
- title: "Null",
- input:
-"\
-name: Mr. Show\n\
-hosted by: Bob and David\n\
-date of next season: ~\n\
-",
- output:
- {
- 'name' : 'Mr. Show',
- 'hosted by' : 'Bob and David',
- 'date of next season' : null
- }
- },
- {
- title: "Boolean",
- input:
-"\
-Is Gus a Liar?: true\n\
-Do I rely on Gus for Sustenance?: false\n\
-",
- output:
- {
- 'Is Gus a Liar?' : true,
- 'Do I rely on Gus for Sustenance?' : false
- }
- },
- {
- title: "Integers",
- input:
-"\
-zero: 0\n\
-simple: 12\n\
-one-thousand: 1,000\n\
-negative one-thousand: -1,000\n\
-",
- output:
- {
- 'zero' : 0,
- 'simple' : 12,
- 'one-thousand' : 1000,
- 'negative one-thousand' : -1000
- }
- },
- {
- title: "Integers as Map Keys",
- input:
-"\
-1: one\n\
-2: two\n\
-3: three\n\
-",
- output:
- {
- 1 : 'one',
- 2 : 'two',
- 3 : 'three'
- }
- },
- {
- title: "Floats",
- input:
-"\
-a simple float: 2.00\n\
-larger float: 1,000.09\n\
-scientific notation: 1.00009e+3\n\
-",
- output:
- {
- 'a simple float' : 2.0,
- 'larger float' : 1000.09,
- 'scientific notation' : 1000.09
- }
- },
- {
- title: "Time",
- input:
-"\
-iso8601: 2001-12-14t21:59:43.10-05:00\n\
-space seperated: 2001-12-14 21:59:43.10 -05:00\n\
-",
- output:
- {
- 'iso8601' : new Date("2001-12-14t21:59:43.10-05:00"),
- 'space seperated' : new Date("2001-12-14 21:59:43.10 -05:00")
- }
- },
- {
- title: "Date",
- input:
-"\
-1976-07-31\n\
-",
- output: new Date("1976-07-31"),
-
- },
- {
- title: "Single ending newline",
- input:
-"\
----\n\
-this: |\n\
- Foo\n\
- Bar\n\
-",
- output: { 'this' : "Foo\nBar\n" }
-
- },
- {
- title: "The '+' indicator",
- input:
-"\
-normal: |\n\
- extra new lines not kept\n\
-\n\
-preserving: |+\n\
- extra new lines are kept\n\
-\n\
-\n\
-dummy: value\n\
-",
- output:
- {
- 'normal' : "extra new lines not kept\n",
- 'preserving' : "extra new lines are kept\n\n\n",
- 'dummy' : 'value'
- }
- },
- {
- title: "Three trailing newlines in literals",
- input:
-'\
-clipped: |\n\
- This has one newline.\n\
-\n\
-\n\
-\n\
-same as "clipped" above: "This has one newline.\n"\n\
-\n\
-stripped: |-\n\
- This has no newline.\n\
-\n\
-\n\
-\n\
-same as "stripped" above: "This has no newline."\n\
-\n\
-kept: |+\n\
- This has four newlines.\n\
-\n\
-\n\
-\n\
-same as "kept" above: "This has four newlines.\n\n\n\n"\n\
-',
- output:
- {
- 'clipped' : "This has one newline.\n",
- 'same as "clipped" above' : "This has one newline.\n",
- 'stripped' : 'This has no newline.',
- 'same as "stripped" above' : 'This has no newline.',
- 'kept' : "This has four newlines.\n\n\n\n",
- 'same as "kept" above' : "This has four newlines.\n\n\n\n"
- }
- },
- {
- title: "Extra trailing newlines with spaces",
- input:
-"\
----\n\
-this: |\n\
- Foo\n\
-\n\
- \n\
-kept: |+\n\
- Foo\n\
- \n\
-",
- output:
- { 'this' : "Foo\n\n \n",
- 'kept' : "Foo\n\n \n" }
- },
- {
- title: "Folded Block in a Sequence",
- input:
-"\
----\n\
-- apple\n\
-- banana\n\
-- >\n\
- can't you see\n\
- the beauty of yaml?\n\
- hmm\n\
-- dog\n\
-",
- output:
- [
- 'apple',
- 'banana',
- "can't you see the beauty of yaml? hmm\n",
- 'dog'
- ]
- },
- {
- title: "Folded Block as a Mapping Value",
- input:
-"\
----\n\
-quote: >\n\
- Mark McGwire's\n\
- year was crippled\n\
- by a knee injury.\n\
-source: espn\n\
-",
- output:
- {
- 'quote' : "Mark McGwire's year was crippled by a knee injury.\n",
- 'source' : 'espn'
- }
- },
- {
- title: "Three trailing newlines in folded blocks",
- input:
-'\
-clipped: >\n\
- This has one newline.\n\
-\n\
-\n\
-\n\
-same as "clipped" above: "This has one newline.\\n"\n\
-\n\
-stripped: >-\n\
- This has no newline.\n\
-\n\
-\n\
-\n\
-same as "stripped" above: "This has no newline."\n\
-\n\
-kept: >+\n\
- This has four newlines.\n\
-\n\
-\n\
-\n\
-same as "kept" above: "This has four newlines.\\n\\n\\n\\n"\n\
-',
- output:
- {
- 'clipped' : "This has one newline.\n",
- 'same as "clipped" above' : "This has one newline.\n",
- 'stripped' : 'This has no newline.',
- 'same as "stripped" above' : 'This has no newline.',
- 'kept' : "This has four newlines.\n\n\n\n",
- 'same as "kept" above' : "This has four newlines.\n\n\n\n"
- }
- },
- {
- title: "Simple Alias Example",
- input:
-"\
-- &showell Steve\n\
-- Clark\n\
-- Brian\n\
-- Oren\n\
-- *showell\n\
-",
- output: [ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve' ]
-
- },
- {
- title: "Alias of a Mapping",
- input:
-"\
-- &hello\n\
- Meat: pork\n\
- Starch: potato\n\
-- banana\n\
-- *hello\n\
-",
- output:
- [
- { 'Meat' : 'pork', 'Starch' : 'potato' },
- 'banana',
- { 'Meat' : 'pork', 'Starch' : 'potato' }
- ]
- },
-/* {
- title: "Trailing Document Separator",
- input:
-"\
-- foo: 1\n\
- bar: 2\n\
----\n\
-more: stuff\n\
-",
- output: [ { 'foo' : 1, 'bar' : 2 } ]
-
- },*/
- {
- title: "Leading Document Separator",
- input:
-"\
----\n\
-- foo: 1\n\
- bar: 2\n\
-# ---\n\
-# more: stuff\n\
-",
- output: [ { 'foo' : 1, 'bar' : 2 } ]
-
- },
- {
- title: "YAML Header",
- input:
-"\
---- %YAML:1.0\n\
-foo: 1\n\
-bar: 2\n\
-",
- output: { 'foo' : 1, 'bar' : 2 }
-
- },
- {
- title: "Red Herring Document Separator",
- input:
-"\
-foo: |\n\
- ---\n\
-",
- output: { 'foo' : "---\n" }
-
- },
- {
- title: "Strings",
- input:
-"\
-foo: |\n\
- ---\n\
- foo: bar\n\
- ---\n\
- yo: baz\n\
-bar: |\n\
- fooness\n\
-",
- output:
- {
- 'foo' : "---\nfoo: bar\n---\nyo: baz\n",
- 'bar' : "fooness\n"
- }
-
- },
-
-];
diff --git a/test/libs/jasmine-1.2.0/jasmine-html.js b/test/libs/jasmine-1.2.0/jasmine-html.js
deleted file mode 100644
index a0b0639..0000000
--- a/test/libs/jasmine-1.2.0/jasmine-html.js
+++ /dev/null
@@ -1,616 +0,0 @@
-jasmine.HtmlReporterHelpers = {};
-
-jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
- var el = document.createElement(type);
-
- for (var i = 2; i < arguments.length; i++) {
- var child = arguments[i];
-
- if (typeof child === 'string') {
- el.appendChild(document.createTextNode(child));
- } else {
- if (child) {
- el.appendChild(child);
- }
- }
- }
-
- for (var attr in attrs) {
- if (attr == "className") {
- el[attr] = attrs[attr];
- } else {
- el.setAttribute(attr, attrs[attr]);
- }
- }
-
- return el;
-};
-
-jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
- var results = child.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.skipped) {
- status = 'skipped';
- }
-
- return status;
-};
-
-jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
- var parentDiv = this.dom.summary;
- var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
- var parent = child[parentSuite];
-
- if (parent) {
- if (typeof this.views.suites[parent.id] == 'undefined') {
- this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
- }
- parentDiv = this.views.suites[parent.id].element;
- }
-
- parentDiv.appendChild(childElement);
-};
-
-
-jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
- for(var fn in jasmine.HtmlReporterHelpers) {
- ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
- }
-};
-
-jasmine.HtmlReporter = function(_doc) {
- var self = this;
- var doc = _doc || window.document;
-
- var reporterView;
-
- var dom = {};
-
- // Jasmine Reporter Public Interface
- self.logRunningSpecs = false;
-
- self.reportRunnerStarting = function(runner) {
- var specs = runner.specs() || [];
-
- if (specs.length == 0) {
- return;
- }
-
- createReporterDom(runner.env.versionString());
- doc.body.appendChild(dom.reporter);
-
- reporterView = new jasmine.HtmlReporter.ReporterView(dom);
- reporterView.addSpecs(specs, self.specFilter);
- };
-
- self.reportRunnerResults = function(runner) {
- reporterView && reporterView.complete();
- };
-
- self.reportSuiteResults = function(suite) {
- reporterView.suiteComplete(suite);
- };
-
- self.reportSpecStarting = function(spec) {
- if (self.logRunningSpecs) {
- self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
- }
- };
-
- self.reportSpecResults = function(spec) {
- reporterView.specComplete(spec);
- };
-
- self.log = function() {
- var console = jasmine.getGlobal().console;
- if (console && console.log) {
- if (console.log.apply) {
- console.log.apply(console, arguments);
- } else {
- console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
- }
- }
- };
-
- self.specFilter = function(spec) {
- if (!focusedSpecName()) {
- return true;
- }
-
- return spec.getFullName().indexOf(focusedSpecName()) === 0;
- };
-
- return self;
-
- function focusedSpecName() {
- var specName;
-
- (function memoizeFocusedSpec() {
- if (specName) {
- return;
- }
-
- var paramMap = [];
- var params = doc.location.search.substring(1).split('&');
-
- for (var i = 0; i < params.length; i++) {
- var p = params[i].split('=');
- paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
- }
-
- specName = paramMap.spec;
- })();
-
- return specName;
- }
-
- function createReporterDom(version) {
- dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
- dom.banner = self.createDom('div', { className: 'banner' },
- self.createDom('span', { className: 'title' }, "Jasmine "),
- self.createDom('span', { className: 'version' }, version)),
-
- dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
- dom.alert = self.createDom('div', {className: 'alert'}),
- dom.results = self.createDom('div', {className: 'results'},
- dom.summary = self.createDom('div', { className: 'summary' }),
- dom.details = self.createDom('div', { id: 'details' }))
- );
- }
-};
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
- this.startedAt = new Date();
- this.runningSpecCount = 0;
- this.completeSpecCount = 0;
- this.passedCount = 0;
- this.failedCount = 0;
- this.skippedCount = 0;
-
- this.createResultsMenu = function() {
- this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
- this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
- ' | ',
- this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
-
- this.summaryMenuItem.onclick = function() {
- dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
- };
-
- this.detailsMenuItem.onclick = function() {
- showDetails();
- };
- };
-
- this.addSpecs = function(specs, specFilter) {
- this.totalSpecCount = specs.length;
-
- this.views = {
- specs: {},
- suites: {}
- };
-
- for (var i = 0; i < specs.length; i++) {
- var spec = specs[i];
- this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
- if (specFilter(spec)) {
- this.runningSpecCount++;
- }
- }
- };
-
- this.specComplete = function(spec) {
- this.completeSpecCount++;
-
- if (isUndefined(this.views.specs[spec.id])) {
- this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
- }
-
- var specView = this.views.specs[spec.id];
-
- switch (specView.status()) {
- case 'passed':
- this.passedCount++;
- break;
-
- case 'failed':
- this.failedCount++;
- break;
-
- case 'skipped':
- this.skippedCount++;
- break;
- }
-
- specView.refresh();
- this.refresh();
- };
-
- this.suiteComplete = function(suite) {
- var suiteView = this.views.suites[suite.id];
- if (isUndefined(suiteView)) {
- return;
- }
- suiteView.refresh();
- };
-
- this.refresh = function() {
-
- if (isUndefined(this.resultsMenu)) {
- this.createResultsMenu();
- }
-
- // currently running UI
- if (isUndefined(this.runningAlert)) {
- this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
- dom.alert.appendChild(this.runningAlert);
- }
- this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
-
- // skipped specs UI
- if (isUndefined(this.skippedAlert)) {
- this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
- }
-
- this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
-
- if (this.skippedCount === 1 && isDefined(dom.alert)) {
- dom.alert.appendChild(this.skippedAlert);
- }
-
- // passing specs UI
- if (isUndefined(this.passedAlert)) {
- this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
- }
- this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
-
- // failing specs UI
- if (isUndefined(this.failedAlert)) {
- this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
- }
- this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
-
- if (this.failedCount === 1 && isDefined(dom.alert)) {
- dom.alert.appendChild(this.failedAlert);
- dom.alert.appendChild(this.resultsMenu);
- }
-
- // summary info
- this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
- this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
- };
-
- this.complete = function() {
- dom.alert.removeChild(this.runningAlert);
-
- this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
-
- if (this.failedCount === 0) {
- dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
- } else {
- showDetails();
- }
-
- dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
- };
-
- return this;
-
- function showDetails() {
- if (dom.reporter.className.search(/showDetails/) === -1) {
- dom.reporter.className += " showDetails";
- }
- }
-
- function isUndefined(obj) {
- return typeof obj === 'undefined';
- }
-
- function isDefined(obj) {
- return !isUndefined(obj);
- }
-
- function specPluralizedFor(count) {
- var str = count + " spec";
- if (count > 1) {
- str += "s"
- }
- return str;
- }
-
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
-
-
-jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
- this.spec = spec;
- this.dom = dom;
- this.views = views;
-
- this.symbol = this.createDom('li', { className: 'pending' });
- this.dom.symbolSummary.appendChild(this.symbol);
-
- this.summary = this.createDom('div', { className: 'specSummary' },
- this.createDom('a', {
- className: 'description',
- href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
- title: this.spec.getFullName()
- }, this.spec.description)
- );
-
- this.detail = this.createDom('div', { className: 'specDetail' },
- this.createDom('a', {
- className: 'description',
- href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
- title: this.spec.getFullName()
- }, this.spec.getFullName())
- );
-};
-
-jasmine.HtmlReporter.SpecView.prototype.status = function() {
- return this.getSpecStatus(this.spec);
-};
-
-jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
- this.symbol.className = this.status();
-
- switch (this.status()) {
- case 'skipped':
- break;
-
- case 'passed':
- this.appendSummaryToSuiteDiv();
- break;
-
- case 'failed':
- this.appendSummaryToSuiteDiv();
- this.appendFailureDetail();
- break;
- }
-};
-
-jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
- this.summary.className += ' ' + this.status();
- this.appendToSummary(this.spec, this.summary);
-};
-
-jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
- this.detail.className += ' ' + this.status();
-
- var resultItems = this.spec.results().getItems();
- var messagesDiv = this.createDom('div', { className: 'messages' });
-
- for (var i = 0; i < resultItems.length; i++) {
- var result = resultItems[i];
-
- if (result.type == 'log') {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
- } else if (result.type == 'expect' && result.passed && !result.passed()) {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
- if (result.trace.stack) {
- messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
- }
- }
- }
-
- if (messagesDiv.childNodes.length > 0) {
- this.detail.appendChild(messagesDiv);
- this.dom.details.appendChild(this.detail);
- }
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
- this.suite = suite;
- this.dom = dom;
- this.views = views;
-
- this.element = this.createDom('div', { className: 'suite' },
- this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
- );
-
- this.appendToSummary(this.suite, this.element);
-};
-
-jasmine.HtmlReporter.SuiteView.prototype.status = function() {
- return this.getSpecStatus(this.suite);
-};
-
-jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
- this.element.className += " " + this.status();
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
-
-/* @deprecated Use jasmine.HtmlReporter instead
- */
-jasmine.TrivialReporter = function(doc) {
- this.document = doc || document;
- this.suiteDivs = {};
- this.logRunningSpecs = false;
-};
-
-jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
- var el = document.createElement(type);
-
- for (var i = 2; i < arguments.length; i++) {
- var child = arguments[i];
-
- if (typeof child === 'string') {
- el.appendChild(document.createTextNode(child));
- } else {
- if (child) { el.appendChild(child); }
- }
- }
-
- for (var attr in attrs) {
- if (attr == "className") {
- el[attr] = attrs[attr];
- } else {
- el.setAttribute(attr, attrs[attr]);
- }
- }
-
- return el;
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
- var showPassed, showSkipped;
-
- this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
- this.createDom('div', { className: 'banner' },
- this.createDom('div', { className: 'logo' },
- this.createDom('span', { className: 'title' }, "Jasmine"),
- this.createDom('span', { className: 'version' }, runner.env.versionString())),
- this.createDom('div', { className: 'options' },
- "Show ",
- showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
- this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
- showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
- this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
- )
- ),
-
- this.runnerDiv = this.createDom('div', { className: 'runner running' },
- this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
- this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
- this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
- );
-
- this.document.body.appendChild(this.outerDiv);
-
- var suites = runner.suites();
- for (var i = 0; i < suites.length; i++) {
- var suite = suites[i];
- var suiteDiv = this.createDom('div', { className: 'suite' },
- this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
- this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
- this.suiteDivs[suite.id] = suiteDiv;
- var parentDiv = this.outerDiv;
- if (suite.parentSuite) {
- parentDiv = this.suiteDivs[suite.parentSuite.id];
- }
- parentDiv.appendChild(suiteDiv);
- }
-
- this.startedAt = new Date();
-
- var self = this;
- showPassed.onclick = function(evt) {
- if (showPassed.checked) {
- self.outerDiv.className += ' show-passed';
- } else {
- self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
- }
- };
-
- showSkipped.onclick = function(evt) {
- if (showSkipped.checked) {
- self.outerDiv.className += ' show-skipped';
- } else {
- self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
- }
- };
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
- var results = runner.results();
- var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
- this.runnerDiv.setAttribute("class", className);
- //do it twice for IE
- this.runnerDiv.setAttribute("className", className);
- var specs = runner.specs();
- var specCount = 0;
- for (var i = 0; i < specs.length; i++) {
- if (this.specFilter(specs[i])) {
- specCount++;
- }
- }
- var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
- message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
- this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
-
- this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
-};
-
-jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
- var results = suite.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.totalCount === 0) { // todo: change this to check results.skipped
- status = 'skipped';
- }
- this.suiteDivs[suite.id].className += " " + status;
-};
-
-jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
- if (this.logRunningSpecs) {
- this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
- }
-};
-
-jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
- var results = spec.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.skipped) {
- status = 'skipped';
- }
- var specDiv = this.createDom('div', { className: 'spec ' + status },
- this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
- this.createDom('a', {
- className: 'description',
- href: '?spec=' + encodeURIComponent(spec.getFullName()),
- title: spec.getFullName()
- }, spec.description));
-
-
- var resultItems = results.getItems();
- var messagesDiv = this.createDom('div', { className: 'messages' });
- for (var i = 0; i < resultItems.length; i++) {
- var result = resultItems[i];
-
- if (result.type == 'log') {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
- } else if (result.type == 'expect' && result.passed && !result.passed()) {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
- if (result.trace.stack) {
- messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
- }
- }
- }
-
- if (messagesDiv.childNodes.length > 0) {
- specDiv.appendChild(messagesDiv);
- }
-
- this.suiteDivs[spec.suite.id].appendChild(specDiv);
-};
-
-jasmine.TrivialReporter.prototype.log = function() {
- var console = jasmine.getGlobal().console;
- if (console && console.log) {
- if (console.log.apply) {
- console.log.apply(console, arguments);
- } else {
- console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
- }
- }
-};
-
-jasmine.TrivialReporter.prototype.getLocation = function() {
- return this.document.location;
-};
-
-jasmine.TrivialReporter.prototype.specFilter = function(spec) {
- var paramMap = {};
- var params = this.getLocation().search.substring(1).split('&');
- for (var i = 0; i < params.length; i++) {
- var p = params[i].split('=');
- paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
- }
-
- if (!paramMap.spec) {
- return true;
- }
- return spec.getFullName().indexOf(paramMap.spec) === 0;
-};
diff --git a/test/libs/jasmine-1.2.0/jasmine.css b/test/libs/jasmine-1.2.0/jasmine.css
deleted file mode 100644
index 826e575..0000000
--- a/test/libs/jasmine-1.2.0/jasmine.css
+++ /dev/null
@@ -1,81 +0,0 @@
-body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
-
-#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
-#HTMLReporter a { text-decoration: none; }
-#HTMLReporter a:hover { text-decoration: underline; }
-#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
-#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
-#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
-#HTMLReporter .version { color: #aaaaaa; }
-#HTMLReporter .banner { margin-top: 14px; }
-#HTMLReporter .duration { color: #aaaaaa; float: right; }
-#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
-#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
-#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
-#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
-#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
-#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
-#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
-#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
-#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
-#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
-#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
-#HTMLReporter .runningAlert { background-color: #666666; }
-#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
-#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
-#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
-#HTMLReporter .passingAlert { background-color: #a6b779; }
-#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
-#HTMLReporter .failingAlert { background-color: #cf867e; }
-#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
-#HTMLReporter .results { margin-top: 14px; }
-#HTMLReporter #details { display: none; }
-#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
-#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
-#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
-#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
-#HTMLReporter.showDetails .summary { display: none; }
-#HTMLReporter.showDetails #details { display: block; }
-#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
-#HTMLReporter .summary { margin-top: 14px; }
-#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
-#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
-#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
-#HTMLReporter .description + .suite { margin-top: 0; }
-#HTMLReporter .suite { margin-top: 14px; }
-#HTMLReporter .suite a { color: #333333; }
-#HTMLReporter #details .specDetail { margin-bottom: 28px; }
-#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
-#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
-#HTMLReporter .resultMessage span.result { display: block; }
-#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
-
-#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
-#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
-#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
-#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
-#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
-#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
-#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
-#TrivialReporter .runner.running { background-color: yellow; }
-#TrivialReporter .options { text-align: right; font-size: .8em; }
-#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
-#TrivialReporter .suite .suite { margin: 5px; }
-#TrivialReporter .suite.passed { background-color: #dfd; }
-#TrivialReporter .suite.failed { background-color: #fdd; }
-#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
-#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
-#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
-#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
-#TrivialReporter .spec.skipped { background-color: #bbb; }
-#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
-#TrivialReporter .passed { background-color: #cfc; display: none; }
-#TrivialReporter .failed { background-color: #fbb; }
-#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
-#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
-#TrivialReporter .resultMessage .mismatch { color: black; }
-#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
-#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
-#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
-#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
-#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
diff --git a/test/libs/jasmine-1.2.0/jasmine.js b/test/libs/jasmine-1.2.0/jasmine.js
deleted file mode 100644
index 03bf89a..0000000
--- a/test/libs/jasmine-1.2.0/jasmine.js
+++ /dev/null
@@ -1,2529 +0,0 @@
-var isCommonJS = typeof window == "undefined";
-
-/**
- * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
- *
- * @namespace
- */
-var jasmine = {};
-if (isCommonJS) exports.jasmine = jasmine;
-/**
- * @private
- */
-jasmine.unimplementedMethod_ = function() {
- throw new Error("unimplemented method");
-};
-
-/**
- * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
- * a plain old variable and may be redefined by somebody else.
- *
- * @private
- */
-jasmine.undefined = jasmine.___undefined___;
-
-/**
- * Show diagnostic messages in the console if set to true
- *
- */
-jasmine.VERBOSE = false;
-
-/**
- * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
- *
- */
-jasmine.DEFAULT_UPDATE_INTERVAL = 250;
-
-/**
- * Default timeout interval in milliseconds for waitsFor() blocks.
- */
-jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
-
-jasmine.getGlobal = function() {
- function getGlobal() {
- return this;
- }
-
- return getGlobal();
-};
-
-/**
- * Allows for bound functions to be compared. Internal use only.
- *
- * @ignore
- * @private
- * @param base {Object} bound 'this' for the function
- * @param name {Function} function to find
- */
-jasmine.bindOriginal_ = function(base, name) {
- var original = base[name];
- if (original.apply) {
- return function() {
- return original.apply(base, arguments);
- };
- } else {
- // IE support
- return jasmine.getGlobal()[name];
- }
-};
-
-jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
-jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
-jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
-jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
-
-jasmine.MessageResult = function(values) {
- this.type = 'log';
- this.values = values;
- this.trace = new Error(); // todo: test better
-};
-
-jasmine.MessageResult.prototype.toString = function() {
- var text = "";
- for (var i = 0; i < this.values.length; i++) {
- if (i > 0) text += " ";
- if (jasmine.isString_(this.values[i])) {
- text += this.values[i];
- } else {
- text += jasmine.pp(this.values[i]);
- }
- }
- return text;
-};
-
-jasmine.ExpectationResult = function(params) {
- this.type = 'expect';
- this.matcherName = params.matcherName;
- this.passed_ = params.passed;
- this.expected = params.expected;
- this.actual = params.actual;
- this.message = this.passed_ ? 'Passed.' : params.message;
-
- var trace = (params.trace || new Error(this.message));
- this.trace = this.passed_ ? '' : trace;
-};
-
-jasmine.ExpectationResult.prototype.toString = function () {
- return this.message;
-};
-
-jasmine.ExpectationResult.prototype.passed = function () {
- return this.passed_;
-};
-
-/**
- * Getter for the Jasmine environment. Ensures one gets created
- */
-jasmine.getEnv = function() {
- var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
- return env;
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isArray_ = function(value) {
- return jasmine.isA_("Array", value);
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isString_ = function(value) {
- return jasmine.isA_("String", value);
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isNumber_ = function(value) {
- return jasmine.isA_("Number", value);
-};
-
-/**
- * @ignore
- * @private
- * @param {String} typeName
- * @param value
- * @returns {Boolean}
- */
-jasmine.isA_ = function(typeName, value) {
- return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
-};
-
-/**
- * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
- *
- * @param value {Object} an object to be outputted
- * @returns {String}
- */
-jasmine.pp = function(value) {
- var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
- stringPrettyPrinter.format(value);
- return stringPrettyPrinter.string;
-};
-
-/**
- * Returns true if the object is a DOM Node.
- *
- * @param {Object} obj object to check
- * @returns {Boolean}
- */
-jasmine.isDomNode = function(obj) {
- return obj.nodeType > 0;
-};
-
-/**
- * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
- *
- * @example
- * // don't care about which function is passed in, as long as it's a function
- * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
- *
- * @param {Class} clazz
- * @returns matchable object of the type clazz
- */
-jasmine.any = function(clazz) {
- return new jasmine.Matchers.Any(clazz);
-};
-
-/**
- * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
- * attributes on the object.
- *
- * @example
- * // don't care about any other attributes than foo.
- * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
- *
- * @param sample {Object} sample
- * @returns matchable object for the sample
- */
-jasmine.objectContaining = function (sample) {
- return new jasmine.Matchers.ObjectContaining(sample);
-};
-
-/**
- * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
- *
- * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
- * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
- *
- * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
- *
- * Spies are torn down at the end of every spec.
- *
- * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
- *
- * @example
- * // a stub
- * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
- *
- * // spy example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- *
- * // actual foo.not will not be called, execution stops
- * spyOn(foo, 'not');
-
- // foo.not spied upon, execution will continue to implementation
- * spyOn(foo, 'not').andCallThrough();
- *
- * // fake example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- *
- * // foo.not(val) will return val
- * spyOn(foo, 'not').andCallFake(function(value) {return value;});
- *
- * // mock example
- * foo.not(7 == 7);
- * expect(foo.not).toHaveBeenCalled();
- * expect(foo.not).toHaveBeenCalledWith(true);
- *
- * @constructor
- * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
- * @param {String} name
- */
-jasmine.Spy = function(name) {
- /**
- * The name of the spy, if provided.
- */
- this.identity = name || 'unknown';
- /**
- * Is this Object a spy?
- */
- this.isSpy = true;
- /**
- * The actual function this spy stubs.
- */
- this.plan = function() {
- };
- /**
- * Tracking of the most recent call to the spy.
- * @example
- * var mySpy = jasmine.createSpy('foo');
- * mySpy(1, 2);
- * mySpy.mostRecentCall.args = [1, 2];
- */
- this.mostRecentCall = {};
-
- /**
- * Holds arguments for each call to the spy, indexed by call count
- * @example
- * var mySpy = jasmine.createSpy('foo');
- * mySpy(1, 2);
- * mySpy(7, 8);
- * mySpy.mostRecentCall.args = [7, 8];
- * mySpy.argsForCall[0] = [1, 2];
- * mySpy.argsForCall[1] = [7, 8];
- */
- this.argsForCall = [];
- this.calls = [];
-};
-
-/**
- * Tells a spy to call through to the actual implemenatation.
- *
- * @example
- * var foo = {
- * bar: function() { // do some stuff }
- * }
- *
- * // defining a spy on an existing property: foo.bar
- * spyOn(foo, 'bar').andCallThrough();
- */
-jasmine.Spy.prototype.andCallThrough = function() {
- this.plan = this.originalValue;
- return this;
-};
-
-/**
- * For setting the return value of a spy.
- *
- * @example
- * // defining a spy from scratch: foo() returns 'baz'
- * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
- *
- * // defining a spy on an existing property: foo.bar() returns 'baz'
- * spyOn(foo, 'bar').andReturn('baz');
- *
- * @param {Object} value
- */
-jasmine.Spy.prototype.andReturn = function(value) {
- this.plan = function() {
- return value;
- };
- return this;
-};
-
-/**
- * For throwing an exception when a spy is called.
- *
- * @example
- * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
- * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
- *
- * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
- * spyOn(foo, 'bar').andThrow('baz');
- *
- * @param {String} exceptionMsg
- */
-jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
- this.plan = function() {
- throw exceptionMsg;
- };
- return this;
-};
-
-/**
- * Calls an alternate implementation when a spy is called.
- *
- * @example
- * var baz = function() {
- * // do some stuff, return something
- * }
- * // defining a spy from scratch: foo() calls the function baz
- * var foo = jasmine.createSpy('spy on foo').andCall(baz);
- *
- * // defining a spy on an existing property: foo.bar() calls an anonymnous function
- * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
- *
- * @param {Function} fakeFunc
- */
-jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
- this.plan = fakeFunc;
- return this;
-};
-
-/**
- * Resets all of a spy's the tracking variables so that it can be used again.
- *
- * @example
- * spyOn(foo, 'bar');
- *
- * foo.bar();
- *
- * expect(foo.bar.callCount).toEqual(1);
- *
- * foo.bar.reset();
- *
- * expect(foo.bar.callCount).toEqual(0);
- */
-jasmine.Spy.prototype.reset = function() {
- this.wasCalled = false;
- this.callCount = 0;
- this.argsForCall = [];
- this.calls = [];
- this.mostRecentCall = {};
-};
-
-jasmine.createSpy = function(name) {
-
- var spyObj = function() {
- spyObj.wasCalled = true;
- spyObj.callCount++;
- var args = jasmine.util.argsToArray(arguments);
- spyObj.mostRecentCall.object = this;
- spyObj.mostRecentCall.args = args;
- spyObj.argsForCall.push(args);
- spyObj.calls.push({object: this, args: args});
- return spyObj.plan.apply(this, arguments);
- };
-
- var spy = new jasmine.Spy(name);
-
- for (var prop in spy) {
- spyObj[prop] = spy[prop];
- }
-
- spyObj.reset();
-
- return spyObj;
-};
-
-/**
- * Determines whether an object is a spy.
- *
- * @param {jasmine.Spy|Object} putativeSpy
- * @returns {Boolean}
- */
-jasmine.isSpy = function(putativeSpy) {
- return putativeSpy && putativeSpy.isSpy;
-};
-
-/**
- * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
- * large in one call.
- *
- * @param {String} baseName name of spy class
- * @param {Array} methodNames array of names of methods to make spies
- */
-jasmine.createSpyObj = function(baseName, methodNames) {
- if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
- throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
- }
- var obj = {};
- for (var i = 0; i < methodNames.length; i++) {
- obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
- }
- return obj;
-};
-
-/**
- * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
- *
- * Be careful not to leave calls to <code>jasmine.log</code> in production code.
- */
-jasmine.log = function() {
- var spec = jasmine.getEnv().currentSpec;
- spec.log.apply(spec, arguments);
-};
-
-/**
- * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
- *
- * @example
- * // spy example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
- *
- * @see jasmine.createSpy
- * @param obj
- * @param methodName
- * @returns a Jasmine spy that can be chained with all spy methods
- */
-var spyOn = function(obj, methodName) {
- return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
-};
-if (isCommonJS) exports.spyOn = spyOn;
-
-/**
- * Creates a Jasmine spec that will be added to the current suite.
- *
- * // TODO: pending tests
- *
- * @example
- * it('should be true', function() {
- * expect(true).toEqual(true);
- * });
- *
- * @param {String} desc description of this specification
- * @param {Function} func defines the preconditions and expectations of the spec
- */
-var it = function(desc, func) {
- return jasmine.getEnv().it(desc, func);
-};
-if (isCommonJS) exports.it = it;
-
-/**
- * Creates a <em>disabled</em> Jasmine spec.
- *
- * A convenience method that allows existing specs to be disabled temporarily during development.
- *
- * @param {String} desc description of this specification
- * @param {Function} func defines the preconditions and expectations of the spec
- */
-var xit = function(desc, func) {
- return jasmine.getEnv().xit(desc, func);
-};
-if (isCommonJS) exports.xit = xit;
-
-/**
- * Starts a chain for a Jasmine expectation.
- *
- * It is passed an Object that is the actual value and should chain to one of the many
- * jasmine.Matchers functions.
- *
- * @param {Object} actual Actual value to test against and expected value
- */
-var expect = function(actual) {
- return jasmine.getEnv().currentSpec.expect(actual);
-};
-if (isCommonJS) exports.expect = expect;
-
-/**
- * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
- *
- * @param {Function} func Function that defines part of a jasmine spec.
- */
-var runs = function(func) {
- jasmine.getEnv().currentSpec.runs(func);
-};
-if (isCommonJS) exports.runs = runs;
-
-/**
- * Waits a fixed time period before moving to the next block.
- *
- * @deprecated Use waitsFor() instead
- * @param {Number} timeout milliseconds to wait
- */
-var waits = function(timeout) {
- jasmine.getEnv().currentSpec.waits(timeout);
-};
-if (isCommonJS) exports.waits = waits;
-
-/**
- * Waits for the latchFunction to return true before proceeding to the next block.
- *
- * @param {Function} latchFunction
- * @param {String} optional_timeoutMessage
- * @param {Number} optional_timeout
- */
-var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
- jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
-};
-if (isCommonJS) exports.waitsFor = waitsFor;
-
-/**
- * A function that is called before each spec in a suite.
- *
- * Used for spec setup, including validating assumptions.
- *
- * @param {Function} beforeEachFunction
- */
-var beforeEach = function(beforeEachFunction) {
- jasmine.getEnv().beforeEach(beforeEachFunction);
-};
-if (isCommonJS) exports.beforeEach = beforeEach;
-
-/**
- * A function that is called after each spec in a suite.
- *
- * Used for restoring any state that is hijacked during spec execution.
- *
- * @param {Function} afterEachFunction
- */
-var afterEach = function(afterEachFunction) {
- jasmine.getEnv().afterEach(afterEachFunction);
-};
-if (isCommonJS) exports.afterEach = afterEach;
-
-/**
- * Defines a suite of specifications.
- *
- * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
- * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
- * of setup in some tests.
- *
- * @example
- * // TODO: a simple suite
- *
- * // TODO: a simple suite with a nested describe block
- *
- * @param {String} description A string, usually the class under test.
- * @param {Function} specDefinitions function that defines several specs.
- */
-var describe = function(description, specDefinitions) {
- return jasmine.getEnv().describe(description, specDefinitions);
-};
-if (isCommonJS) exports.describe = describe;
-
-/**
- * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
- *
- * @param {String} description A string, usually the class under test.
- * @param {Function} specDefinitions function that defines several specs.
- */
-var xdescribe = function(description, specDefinitions) {
- return jasmine.getEnv().xdescribe(description, specDefinitions);
-};
-if (isCommonJS) exports.xdescribe = xdescribe;
-
-
-// Provide the XMLHttpRequest class for IE 5.x-6.x:
-jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
- function tryIt(f) {
- try {
- return f();
- } catch(e) {
- }
- return null;
- }
-
- var xhr = tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP.6.0");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP.3.0");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Microsoft.XMLHTTP");
- });
-
- if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
-
- return xhr;
-} : XMLHttpRequest;
-/**
- * @namespace
- */
-jasmine.util = {};
-
-/**
- * Declare that a child class inherit it's prototype from the parent class.
- *
- * @private
- * @param {Function} childClass
- * @param {Function} parentClass
- */
-jasmine.util.inherit = function(childClass, parentClass) {
- /**
- * @private
- */
- var subclass = function() {
- };
- subclass.prototype = parentClass.prototype;
- childClass.prototype = new subclass();
-};
-
-jasmine.util.formatException = function(e) {
- var lineNumber;
- if (e.line) {
- lineNumber = e.line;
- }
- else if (e.lineNumber) {
- lineNumber = e.lineNumber;
- }
-
- var file;
-
- if (e.sourceURL) {
- file = e.sourceURL;
- }
- else if (e.fileName) {
- file = e.fileName;
- }
-
- var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
-
- if (file && lineNumber) {
- message += ' in ' + file + ' (line ' + lineNumber + ')';
- }
-
- return message;
-};
-
-jasmine.util.htmlEscape = function(str) {
- if (!str) return str;
- return str.replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;');
-};
-
-jasmine.util.argsToArray = function(args) {
- var arrayOfArgs = [];
- for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
- return arrayOfArgs;
-};
-
-jasmine.util.extend = function(destination, source) {
- for (var property in source) destination[property] = source[property];
- return destination;
-};
-
-/**
- * Environment for Jasmine
- *
- * @constructor
- */
-jasmine.Env = function() {
- this.currentSpec = null;
- this.currentSuite = null;
- this.currentRunner_ = new jasmine.Runner(this);
-
- this.reporter = new jasmine.MultiReporter();
-
- this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
- this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
- this.lastUpdate = 0;
- this.specFilter = function() {
- return true;
- };
-
- this.nextSpecId_ = 0;
- this.nextSuiteId_ = 0;
- this.equalityTesters_ = [];
-
- // wrap matchers
- this.matchersClass = function() {
- jasmine.Matchers.apply(this, arguments);
- };
- jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
-
- jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
-};
-
-
-jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
-jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
-jasmine.Env.prototype.setInterval = jasmine.setInterval;
-jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
-
-/**
- * @returns an object containing jasmine version build info, if set.
- */
-jasmine.Env.prototype.version = function () {
- if (jasmine.version_) {
- return jasmine.version_;
- } else {
- throw new Error('Version not set');
- }
-};
-
-/**
- * @returns string containing jasmine version build info, if set.
- */
-jasmine.Env.prototype.versionString = function() {
- if (!jasmine.version_) {
- return "version unknown";
- }
-
- var version = this.version();
- var versionString = version.major + "." + version.minor + "." + version.build;
- if (version.release_candidate) {
- versionString += ".rc" + version.release_candidate;
- }
- versionString += " revision " + version.revision;
- return versionString;
-};
-
-/**
- * @returns a sequential integer starting at 0
- */
-jasmine.Env.prototype.nextSpecId = function () {
- return this.nextSpecId_++;
-};
-
-/**
- * @returns a sequential integer starting at 0
- */
-jasmine.Env.prototype.nextSuiteId = function () {
- return this.nextSuiteId_++;
-};
-
-/**
- * Register a reporter to receive status updates from Jasmine.
- * @param {jasmine.Reporter} reporter An object which will receive status updates.
- */
-jasmine.Env.prototype.addReporter = function(reporter) {
- this.reporter.addReporter(reporter);
-};
-
-jasmine.Env.prototype.execute = function() {
- this.currentRunner_.execute();
-};
-
-jasmine.Env.prototype.describe = function(description, specDefinitions) {
- var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
-
- var parentSuite = this.currentSuite;
- if (parentSuite) {
- parentSuite.add(suite);
- } else {
- this.currentRunner_.add(suite);
- }
-
- this.currentSuite = suite;
-
- var declarationError = null;
- try {
- specDefinitions.call(suite);
- } catch(e) {
- declarationError = e;
- }
-
- if (declarationError) {
- this.it("encountered a declaration exception", function() {
- throw declarationError;
- });
- }
-
- this.currentSuite = parentSuite;
-
- return suite;
-};
-
-jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
- if (this.currentSuite) {
- this.currentSuite.beforeEach(beforeEachFunction);
- } else {
- this.currentRunner_.beforeEach(beforeEachFunction);
- }
-};
-
-jasmine.Env.prototype.currentRunner = function () {
- return this.currentRunner_;
-};
-
-jasmine.Env.prototype.afterEach = function(afterEachFunction) {
- if (this.currentSuite) {
- this.currentSuite.afterEach(afterEachFunction);
- } else {
- this.currentRunner_.afterEach(afterEachFunction);
- }
-
-};
-
-jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
- return {
- execute: function() {
- }
- };
-};
-
-jasmine.Env.prototype.it = function(description, func) {
- var spec = new jasmine.Spec(this, this.currentSuite, description);
- this.currentSuite.add(spec);
- this.currentSpec = spec;
-
- if (func) {
- spec.runs(func);
- }
-
- return spec;
-};
-
-jasmine.Env.prototype.xit = function(desc, func) {
- return {
- id: this.nextSpecId(),
- runs: function() {
- }
- };
-};
-
-jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
- if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
- return true;
- }
-
- a.__Jasmine_been_here_before__ = b;
- b.__Jasmine_been_here_before__ = a;
-
- var hasKey = function(obj, keyName) {
- return obj !== null && obj[keyName] !== jasmine.undefined;
- };
-
- for (var property in b) {
- if (!hasKey(a, property) && hasKey(b, property)) {
- mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
- }
- }
- for (property in a) {
- if (!hasKey(b, property) && hasKey(a, property)) {
- mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
- }
- }
- for (property in b) {
- if (property == '__Jasmine_been_here_before__') continue;
- if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
- mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
- }
- }
-
- if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
- mismatchValues.push("arrays were not the same length");
- }
-
- delete a.__Jasmine_been_here_before__;
- delete b.__Jasmine_been_here_before__;
- return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-};
-
-jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
- mismatchKeys = mismatchKeys || [];
- mismatchValues = mismatchValues || [];
-
- for (var i = 0; i < this.equalityTesters_.length; i++) {
- var equalityTester = this.equalityTesters_[i];
- var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
- if (result !== jasmine.undefined) return result;
- }
-
- if (a === b) return true;
-
- if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
- return (a == jasmine.undefined && b == jasmine.undefined);
- }
-
- if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
- return a === b;
- }
-
- if (a instanceof Date && b instanceof Date) {
- return a.getTime() == b.getTime();
- }
-
- if (a.jasmineMatches) {
- return a.jasmineMatches(b);
- }
-
- if (b.jasmineMatches) {
- return b.jasmineMatches(a);
- }
-
- if (a instanceof jasmine.Matchers.ObjectContaining) {
- return a.matches(b);
- }
-
- if (b instanceof jasmine.Matchers.ObjectContaining) {
- return b.matches(a);
- }
-
- if (jasmine.isString_(a) && jasmine.isString_(b)) {
- return (a == b);
- }
-
- if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
- return (a == b);
- }
-
- if (typeof a === "object" && typeof b === "object") {
- return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
- }
-
- //Straight check
- return (a === b);
-};
-
-jasmine.Env.prototype.contains_ = function(haystack, needle) {
- if (jasmine.isArray_(haystack)) {
- for (var i = 0; i < haystack.length; i++) {
- if (this.equals_(haystack[i], needle)) return true;
- }
- return false;
- }
- return haystack.indexOf(needle) >= 0;
-};
-
-jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
- this.equalityTesters_.push(equalityTester);
-};
-/** No-op base class for Jasmine reporters.
- *
- * @constructor
- */
-jasmine.Reporter = function() {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecResults = function(spec) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.log = function(str) {
-};
-
-/**
- * Blocks are functions with executable code that make up a spec.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {Function} func
- * @param {jasmine.Spec} spec
- */
-jasmine.Block = function(env, func, spec) {
- this.env = env;
- this.func = func;
- this.spec = spec;
-};
-
-jasmine.Block.prototype.execute = function(onComplete) {
- try {
- this.func.apply(this.spec);
- } catch (e) {
- this.spec.fail(e);
- }
- onComplete();
-};
-/** JavaScript API reporter.
- *
- * @constructor
- */
-jasmine.JsApiReporter = function() {
- this.started = false;
- this.finished = false;
- this.suites_ = [];
- this.results_ = {};
-};
-
-jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
- this.started = true;
- var suites = runner.topLevelSuites();
- for (var i = 0; i < suites.length; i++) {
- var suite = suites[i];
- this.suites_.push(this.summarize_(suite));
- }
-};
-
-jasmine.JsApiReporter.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
- var isSuite = suiteOrSpec instanceof jasmine.Suite;
- var summary = {
- id: suiteOrSpec.id,
- name: suiteOrSpec.description,
- type: isSuite ? 'suite' : 'spec',
- children: []
- };
-
- if (isSuite) {
- var children = suiteOrSpec.children();
- for (var i = 0; i < children.length; i++) {
- summary.children.push(this.summarize_(children[i]));
- }
- }
- return summary;
-};
-
-jasmine.JsApiReporter.prototype.results = function() {
- return this.results_;
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
- return this.results_[specId];
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
- this.finished = true;
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
- this.results_[spec.id] = {
- messages: spec.results().getItems(),
- result: spec.results().failedCount > 0 ? "failed" : "passed"
- };
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.log = function(str) {
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
- var results = {};
- for (var i = 0; i < specIds.length; i++) {
- var specId = specIds[i];
- results[specId] = this.summarizeResult_(this.results_[specId]);
- }
- return results;
-};
-
-jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
- var summaryMessages = [];
- var messagesLength = result.messages.length;
- for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
- var resultMessage = result.messages[messageIndex];
- summaryMessages.push({
- text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
- passed: resultMessage.passed ? resultMessage.passed() : true,
- type: resultMessage.type,
- message: resultMessage.message,
- trace: {
- stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
- }
- });
- }
-
- return {
- result : result.result,
- messages : summaryMessages
- };
-};
-
-/**
- * @constructor
- * @param {jasmine.Env} env
- * @param actual
- * @param {jasmine.Spec} spec
- */
-jasmine.Matchers = function(env, actual, spec, opt_isNot) {
- this.env = env;
- this.actual = actual;
- this.spec = spec;
- this.isNot = opt_isNot || false;
- this.reportWasCalled_ = false;
-};
-
-// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
-jasmine.Matchers.pp = function(str) {
- throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
-};
-
-// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
-jasmine.Matchers.prototype.report = function(result, failing_message, details) {
- throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
-};
-
-jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
- for (var methodName in prototype) {
- if (methodName == 'report') continue;
- var orig = prototype[methodName];
- matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
- }
-};
-
-jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
- return function() {
- var matcherArgs = jasmine.util.argsToArray(arguments);
- var result = matcherFunction.apply(this, arguments);
-
- if (this.isNot) {
- result = !result;
- }
-
- if (this.reportWasCalled_) return result;
-
- var message;
- if (!result) {
- if (this.message) {
- message = this.message.apply(this, arguments);
- if (jasmine.isArray_(message)) {
- message = message[this.isNot ? 1 : 0];
- }
- } else {
- var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
- message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
- if (matcherArgs.length > 0) {
- for (var i = 0; i < matcherArgs.length; i++) {
- if (i > 0) message += ",";
- message += " " + jasmine.pp(matcherArgs[i]);
- }
- }
- message += ".";
- }
- }
- var expectationResult = new jasmine.ExpectationResult({
- matcherName: matcherName,
- passed: result,
- expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
- actual: this.actual,
- message: message
- });
- this.spec.addMatcherResult(expectationResult);
- return jasmine.undefined;
- };
-};
-
-
-
-
-/**
- * toBe: compares the actual to the expected using ===
- * @param expected
- */
-jasmine.Matchers.prototype.toBe = function(expected) {
- return this.actual === expected;
-};
-
-/**
- * toNotBe: compares the actual to the expected using !==
- * @param expected
- * @deprecated as of 1.0. Use not.toBe() instead.
- */
-jasmine.Matchers.prototype.toNotBe = function(expected) {
- return this.actual !== expected;
-};
-
-/**
- * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
- *
- * @param expected
- */
-jasmine.Matchers.prototype.toEqual = function(expected) {
- return this.env.equals_(this.actual, expected);
-};
-
-/**
- * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
- * @param expected
- * @deprecated as of 1.0. Use not.toEqual() instead.
- */
-jasmine.Matchers.prototype.toNotEqual = function(expected) {
- return !this.env.equals_(this.actual, expected);
-};
-
-/**
- * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
- * a pattern or a String.
- *
- * @param expected
- */
-jasmine.Matchers.prototype.toMatch = function(expected) {
- return new RegExp(expected).test(this.actual);
-};
-
-/**
- * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
- * @param expected
- * @deprecated as of 1.0. Use not.toMatch() instead.
- */
-jasmine.Matchers.prototype.toNotMatch = function(expected) {
- return !(new RegExp(expected).test(this.actual));
-};
-
-/**
- * Matcher that compares the actual to jasmine.undefined.
- */
-jasmine.Matchers.prototype.toBeDefined = function() {
- return (this.actual !== jasmine.undefined);
-};
-
-/**
- * Matcher that compares the actual to jasmine.undefined.
- */
-jasmine.Matchers.prototype.toBeUndefined = function() {
- return (this.actual === jasmine.undefined);
-};
-
-/**
- * Matcher that compares the actual to null.
- */
-jasmine.Matchers.prototype.toBeNull = function() {
- return (this.actual === null);
-};
-
-/**
- * Matcher that boolean not-nots the actual.
- */
-jasmine.Matchers.prototype.toBeTruthy = function() {
- return !!this.actual;
-};
-
-
-/**
- * Matcher that boolean nots the actual.
- */
-jasmine.Matchers.prototype.toBeFalsy = function() {
- return !this.actual;
-};
-
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was called.
- */
-jasmine.Matchers.prototype.toHaveBeenCalled = function() {
- if (arguments.length > 0) {
- throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
- }
-
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy " + this.actual.identity + " to have been called.",
- "Expected spy " + this.actual.identity + " not to have been called."
- ];
- };
-
- return this.actual.wasCalled;
-};
-
-/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
-jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was not called.
- *
- * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
- */
-jasmine.Matchers.prototype.wasNotCalled = function() {
- if (arguments.length > 0) {
- throw new Error('wasNotCalled does not take arguments');
- }
-
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy " + this.actual.identity + " to not have been called.",
- "Expected spy " + this.actual.identity + " to have been called."
- ];
- };
-
- return !this.actual.wasCalled;
-};
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
- *
- * @example
- *
- */
-jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
- var expectedArgs = jasmine.util.argsToArray(arguments);
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
- this.message = function() {
- if (this.actual.callCount === 0) {
- // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
- return [
- "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
- "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
- ];
- } else {
- return [
- "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
- "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
- ];
- }
- };
-
- return this.env.contains_(this.actual.argsForCall, expectedArgs);
-};
-
-/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
-
-/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasNotCalledWith = function() {
- var expectedArgs = jasmine.util.argsToArray(arguments);
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
- "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
- ];
- };
-
- return !this.env.contains_(this.actual.argsForCall, expectedArgs);
-};
-
-/**
- * Matcher that checks that the expected item is an element in the actual Array.
- *
- * @param {Object} expected
- */
-jasmine.Matchers.prototype.toContain = function(expected) {
- return this.env.contains_(this.actual, expected);
-};
-
-/**
- * Matcher that checks that the expected item is NOT an element in the actual Array.
- *
- * @param {Object} expected
- * @deprecated as of 1.0. Use not.toContain() instead.
- */
-jasmine.Matchers.prototype.toNotContain = function(expected) {
- return !this.env.contains_(this.actual, expected);
-};
-
-jasmine.Matchers.prototype.toBeLessThan = function(expected) {
- return this.actual < expected;
-};
-
-jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
- return this.actual > expected;
-};
-
-/**
- * Matcher that checks that the expected item is equal to the actual item
- * up to a given level of decimal precision (default 2).
- *
- * @param {Number} expected
- * @param {Number} precision
- */
-jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
- if (!(precision === 0)) {
- precision = precision || 2;
- }
- var multiplier = Math.pow(10, precision);
- var actual = Math.round(this.actual * multiplier);
- expected = Math.round(expected * multiplier);
- return expected == actual;
-};
-
-/**
- * Matcher that checks that the expected exception was thrown by the actual.
- *
- * @param {String} expected
- */
-jasmine.Matchers.prototype.toThrow = function(expected) {
- var result = false;
- var exception;
- if (typeof this.actual != 'function') {
- throw new Error('Actual is not a function');
- }
- try {
- this.actual();
- } catch (e) {
- exception = e;
- }
- if (exception) {
- result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
- }
-
- var not = this.isNot ? "not " : "";
-
- this.message = function() {
- if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
- return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
- } else {
- return "Expected function to throw an exception.";
- }
- };
-
- return result;
-};
-
-jasmine.Matchers.Any = function(expectedClass) {
- this.expectedClass = expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
- if (this.expectedClass == String) {
- return typeof other == 'string' || other instanceof String;
- }
-
- if (this.expectedClass == Number) {
- return typeof other == 'number' || other instanceof Number;
- }
-
- if (this.expectedClass == Function) {
- return typeof other == 'function' || other instanceof Function;
- }
-
- if (this.expectedClass == Object) {
- return typeof other == 'object';
- }
-
- return other instanceof this.expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.jasmineToString = function() {
- return '<jasmine.any(' + this.expectedClass + ')>';
-};
-
-jasmine.Matchers.ObjectContaining = function (sample) {
- this.sample = sample;
-};
-
-jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
- mismatchKeys = mismatchKeys || [];
- mismatchValues = mismatchValues || [];
-
- var env = jasmine.getEnv();
-
- var hasKey = function(obj, keyName) {
- return obj != null && obj[keyName] !== jasmine.undefined;
- };
-
- for (var property in this.sample) {
- if (!hasKey(other, property) && hasKey(this.sample, property)) {
- mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
- }
- else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
- mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
- }
- }
-
- return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-};
-
-jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
- return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
-};
-// Mock setTimeout, clearTimeout
-// Contributed by Pivotal Computer Systems, www.pivotalsf.com
-
-jasmine.FakeTimer = function() {
- this.reset();
-
- var self = this;
- self.setTimeout = function(funcToCall, millis) {
- self.timeoutsMade++;
- self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
- return self.timeoutsMade;
- };
-
- self.setInterval = function(funcToCall, millis) {
- self.timeoutsMade++;
- self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
- return self.timeoutsMade;
- };
-
- self.clearTimeout = function(timeoutKey) {
- self.scheduledFunctions[timeoutKey] = jasmine.undefined;
- };
-
- self.clearInterval = function(timeoutKey) {
- self.scheduledFunctions[timeoutKey] = jasmine.undefined;
- };
-
-};
-
-jasmine.FakeTimer.prototype.reset = function() {
- this.timeoutsMade = 0;
- this.scheduledFunctions = {};
- this.nowMillis = 0;
-};
-
-jasmine.FakeTimer.prototype.tick = function(millis) {
- var oldMillis = this.nowMillis;
- var newMillis = oldMillis + millis;
- this.runFunctionsWithinRange(oldMillis, newMillis);
- this.nowMillis = newMillis;
-};
-
-jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
- var scheduledFunc;
- var funcsToRun = [];
- for (var timeoutKey in this.scheduledFunctions) {
- scheduledFunc = this.scheduledFunctions[timeoutKey];
- if (scheduledFunc != jasmine.undefined &&
- scheduledFunc.runAtMillis >= oldMillis &&
- scheduledFunc.runAtMillis <= nowMillis) {
- funcsToRun.push(scheduledFunc);
- this.scheduledFunctions[timeoutKey] = jasmine.undefined;
- }
- }
-
- if (funcsToRun.length > 0) {
- funcsToRun.sort(function(a, b) {
- return a.runAtMillis - b.runAtMillis;
- });
- for (var i = 0; i < funcsToRun.length; ++i) {
- try {
- var funcToRun = funcsToRun[i];
- this.nowMillis = funcToRun.runAtMillis;
- funcToRun.funcToCall();
- if (funcToRun.recurring) {
- this.scheduleFunction(funcToRun.timeoutKey,
- funcToRun.funcToCall,
- funcToRun.millis,
- true);
- }
- } catch(e) {
- }
- }
- this.runFunctionsWithinRange(oldMillis, nowMillis);
- }
-};
-
-jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
- this.scheduledFunctions[timeoutKey] = {
- runAtMillis: this.nowMillis + millis,
- funcToCall: funcToCall,
- recurring: recurring,
- timeoutKey: timeoutKey,
- millis: millis
- };
-};
-
-/**
- * @namespace
- */
-jasmine.Clock = {
- defaultFakeTimer: new jasmine.FakeTimer(),
-
- reset: function() {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.defaultFakeTimer.reset();
- },
-
- tick: function(millis) {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.defaultFakeTimer.tick(millis);
- },
-
- runFunctionsWithinRange: function(oldMillis, nowMillis) {
- jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
- },
-
- scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
- jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
- },
-
- useMock: function() {
- if (!jasmine.Clock.isInstalled()) {
- var spec = jasmine.getEnv().currentSpec;
- spec.after(jasmine.Clock.uninstallMock);
-
- jasmine.Clock.installMock();
- }
- },
-
- installMock: function() {
- jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
- },
-
- uninstallMock: function() {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.installed = jasmine.Clock.real;
- },
-
- real: {
- setTimeout: jasmine.getGlobal().setTimeout,
- clearTimeout: jasmine.getGlobal().clearTimeout,
- setInterval: jasmine.getGlobal().setInterval,
- clearInterval: jasmine.getGlobal().clearInterval
- },
-
- assertInstalled: function() {
- if (!jasmine.Clock.isInstalled()) {
- throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
- }
- },
-
- isInstalled: function() {
- return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
- },
-
- installed: null
-};
-jasmine.Clock.installed = jasmine.Clock.real;
-
-//else for IE support
-jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
- if (jasmine.Clock.installed.setTimeout.apply) {
- return jasmine.Clock.installed.setTimeout.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.setTimeout(funcToCall, millis);
- }
-};
-
-jasmine.getGlobal().setInterval = function(funcToCall, millis) {
- if (jasmine.Clock.installed.setInterval.apply) {
- return jasmine.Clock.installed.setInterval.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.setInterval(funcToCall, millis);
- }
-};
-
-jasmine.getGlobal().clearTimeout = function(timeoutKey) {
- if (jasmine.Clock.installed.clearTimeout.apply) {
- return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.clearTimeout(timeoutKey);
- }
-};
-
-jasmine.getGlobal().clearInterval = function(timeoutKey) {
- if (jasmine.Clock.installed.clearTimeout.apply) {
- return jasmine.Clock.installed.clearInterval.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.clearInterval(timeoutKey);
- }
-};
-
-/**
- * @constructor
- */
-jasmine.MultiReporter = function() {
- this.subReporters_ = [];
-};
-jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
-
-jasmine.MultiReporter.prototype.addReporter = function(reporter) {
- this.subReporters_.push(reporter);
-};
-
-(function() {
- var functionNames = [
- "reportRunnerStarting",
- "reportRunnerResults",
- "reportSuiteResults",
- "reportSpecStarting",
- "reportSpecResults",
- "log"
- ];
- for (var i = 0; i < functionNames.length; i++) {
- var functionName = functionNames[i];
- jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
- return function() {
- for (var j = 0; j < this.subReporters_.length; j++) {
- var subReporter = this.subReporters_[j];
- if (subReporter[functionName]) {
- subReporter[functionName].apply(subReporter, arguments);
- }
- }
- };
- })(functionName);
- }
-})();
-/**
- * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
- *
- * @constructor
- */
-jasmine.NestedResults = function() {
- /**
- * The total count of results
- */
- this.totalCount = 0;
- /**
- * Number of passed results
- */
- this.passedCount = 0;
- /**
- * Number of failed results
- */
- this.failedCount = 0;
- /**
- * Was this suite/spec skipped?
- */
- this.skipped = false;
- /**
- * @ignore
- */
- this.items_ = [];
-};
-
-/**
- * Roll up the result counts.
- *
- * @param result
- */
-jasmine.NestedResults.prototype.rollupCounts = function(result) {
- this.totalCount += result.totalCount;
- this.passedCount += result.passedCount;
- this.failedCount += result.failedCount;
-};
-
-/**
- * Adds a log message.
- * @param values Array of message parts which will be concatenated later.
- */
-jasmine.NestedResults.prototype.log = function(values) {
- this.items_.push(new jasmine.MessageResult(values));
-};
-
-/**
- * Getter for the results: message & results.
- */
-jasmine.NestedResults.prototype.getItems = function() {
- return this.items_;
-};
-
-/**
- * Adds a result, tracking counts (total, passed, & failed)
- * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
- */
-jasmine.NestedResults.prototype.addResult = function(result) {
- if (result.type != 'log') {
- if (result.items_) {
- this.rollupCounts(result);
- } else {
- this.totalCount++;
- if (result.passed()) {
- this.passedCount++;
- } else {
- this.failedCount++;
- }
- }
- }
- this.items_.push(result);
-};
-
-/**
- * @returns {Boolean} True if <b>everything</b> below passed
- */
-jasmine.NestedResults.prototype.passed = function() {
- return this.passedCount === this.totalCount;
-};
-/**
- * Base class for pretty printing for expectation results.
- */
-jasmine.PrettyPrinter = function() {
- this.ppNestLevel_ = 0;
-};
-
-/**
- * Formats a value in a nice, human-readable string.
- *
- * @param value
- */
-jasmine.PrettyPrinter.prototype.format = function(value) {
- if (this.ppNestLevel_ > 40) {
- throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
- }
-
- this.ppNestLevel_++;
- try {
- if (value === jasmine.undefined) {
- this.emitScalar('undefined');
- } else if (value === null) {
- this.emitScalar('null');
- } else if (value === jasmine.getGlobal()) {
- this.emitScalar('<global>');
- } else if (value.jasmineToString) {
- this.emitScalar(value.jasmineToString());
- } else if (typeof value === 'string') {
- this.emitString(value);
- } else if (jasmine.isSpy(value)) {
- this.emitScalar("spy on " + value.identity);
- } else if (value instanceof RegExp) {
- this.emitScalar(value.toString());
- } else if (typeof value === 'function') {
- this.emitScalar('Function');
- } else if (typeof value.nodeType === 'number') {
- this.emitScalar('HTMLNode');
- } else if (value instanceof Date) {
- this.emitScalar('Date(' + value + ')');
- } else if (value.__Jasmine_been_here_before__) {
- this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
- } else if (jasmine.isArray_(value) || typeof value == 'object') {
- value.__Jasmine_been_here_before__ = true;
- if (jasmine.isArray_(value)) {
- this.emitArray(value);
- } else {
- this.emitObject(value);
- }
- delete value.__Jasmine_been_here_before__;
- } else {
- this.emitScalar(value.toString());
- }
- } finally {
- this.ppNestLevel_--;
- }
-};
-
-jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
- for (var property in obj) {
- if (property == '__Jasmine_been_here_before__') continue;
- fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
- obj.__lookupGetter__(property) !== null) : false);
- }
-};
-
-jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
-
-jasmine.StringPrettyPrinter = function() {
- jasmine.PrettyPrinter.call(this);
-
- this.string = '';
-};
-jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
-
-jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
- this.append(value);
-};
-
-jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
- this.append("'" + value + "'");
-};
-
-jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
- this.append('[ ');
- for (var i = 0; i < array.length; i++) {
- if (i > 0) {
- this.append(', ');
- }
- this.format(array[i]);
- }
- this.append(' ]');
-};
-
-jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
- var self = this;
- this.append('{ ');
- var first = true;
-
- this.iterateObject(obj, function(property, isGetter) {
- if (first) {
- first = false;
- } else {
- self.append(', ');
- }
-
- self.append(property);
- self.append(' : ');
- if (isGetter) {
- self.append('<getter>');
- } else {
- self.format(obj[property]);
- }
- });
-
- this.append(' }');
-};
-
-jasmine.StringPrettyPrinter.prototype.append = function(value) {
- this.string += value;
-};
-jasmine.Queue = function(env) {
- this.env = env;
- this.blocks = [];
- this.running = false;
- this.index = 0;
- this.offset = 0;
- this.abort = false;
-};
-
-jasmine.Queue.prototype.addBefore = function(block) {
- this.blocks.unshift(block);
-};
-
-jasmine.Queue.prototype.add = function(block) {
- this.blocks.push(block);
-};
-
-jasmine.Queue.prototype.insertNext = function(block) {
- this.blocks.splice((this.index + this.offset + 1), 0, block);
- this.offset++;
-};
-
-jasmine.Queue.prototype.start = function(onComplete) {
- this.running = true;
- this.onComplete = onComplete;
- this.next_();
-};
-
-jasmine.Queue.prototype.isRunning = function() {
- return this.running;
-};
-
-jasmine.Queue.LOOP_DONT_RECURSE = true;
-
-jasmine.Queue.prototype.next_ = function() {
- var self = this;
- var goAgain = true;
-
- while (goAgain) {
- goAgain = false;
-
- if (self.index < self.blocks.length && !this.abort) {
- var calledSynchronously = true;
- var completedSynchronously = false;
-
- var onComplete = function () {
- if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
- completedSynchronously = true;
- return;
- }
-
- if (self.blocks[self.index].abort) {
- self.abort = true;
- }
-
- self.offset = 0;
- self.index++;
-
- var now = new Date().getTime();
- if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
- self.env.lastUpdate = now;
- self.env.setTimeout(function() {
- self.next_();
- }, 0);
- } else {
- if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
- goAgain = true;
- } else {
- self.next_();
- }
- }
- };
- self.blocks[self.index].execute(onComplete);
-
- calledSynchronously = false;
- if (completedSynchronously) {
- onComplete();
- }
-
- } else {
- self.running = false;
- if (self.onComplete) {
- self.onComplete();
- }
- }
- }
-};
-
-jasmine.Queue.prototype.results = function() {
- var results = new jasmine.NestedResults();
- for (var i = 0; i < this.blocks.length; i++) {
- if (this.blocks[i].results) {
- results.addResult(this.blocks[i].results());
- }
- }
- return results;
-};
-
-
-/**
- * Runner
- *
- * @constructor
- * @param {jasmine.Env} env
- */
-jasmine.Runner = function(env) {
- var self = this;
- self.env = env;
- self.queue = new jasmine.Queue(env);
- self.before_ = [];
- self.after_ = [];
- self.suites_ = [];
-};
-
-jasmine.Runner.prototype.execute = function() {
- var self = this;
- if (self.env.reporter.reportRunnerStarting) {
- self.env.reporter.reportRunnerStarting(this);
- }
- self.queue.start(function () {
- self.finishCallback();
- });
-};
-
-jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
- beforeEachFunction.typeName = 'beforeEach';
- this.before_.splice(0,0,beforeEachFunction);
-};
-
-jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
- afterEachFunction.typeName = 'afterEach';
- this.after_.splice(0,0,afterEachFunction);
-};
-
-
-jasmine.Runner.prototype.finishCallback = function() {
- this.env.reporter.reportRunnerResults(this);
-};
-
-jasmine.Runner.prototype.addSuite = function(suite) {
- this.suites_.push(suite);
-};
-
-jasmine.Runner.prototype.add = function(block) {
- if (block instanceof jasmine.Suite) {
- this.addSuite(block);
- }
- this.queue.add(block);
-};
-
-jasmine.Runner.prototype.specs = function () {
- var suites = this.suites();
- var specs = [];
- for (var i = 0; i < suites.length; i++) {
- specs = specs.concat(suites[i].specs());
- }
- return specs;
-};
-
-jasmine.Runner.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.Runner.prototype.topLevelSuites = function() {
- var topLevelSuites = [];
- for (var i = 0; i < this.suites_.length; i++) {
- if (!this.suites_[i].parentSuite) {
- topLevelSuites.push(this.suites_[i]);
- }
- }
- return topLevelSuites;
-};
-
-jasmine.Runner.prototype.results = function() {
- return this.queue.results();
-};
-/**
- * Internal representation of a Jasmine specification, or test.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {jasmine.Suite} suite
- * @param {String} description
- */
-jasmine.Spec = function(env, suite, description) {
- if (!env) {
- throw new Error('jasmine.Env() required');
- }
- if (!suite) {
- throw new Error('jasmine.Suite() required');
- }
- var spec = this;
- spec.id = env.nextSpecId ? env.nextSpecId() : null;
- spec.env = env;
- spec.suite = suite;
- spec.description = description;
- spec.queue = new jasmine.Queue(env);
-
- spec.afterCallbacks = [];
- spec.spies_ = [];
-
- spec.results_ = new jasmine.NestedResults();
- spec.results_.description = description;
- spec.matchersClass = null;
-};
-
-jasmine.Spec.prototype.getFullName = function() {
- return this.suite.getFullName() + ' ' + this.description + '.';
-};
-
-
-jasmine.Spec.prototype.results = function() {
- return this.results_;
-};
-
-/**
- * All parameters are pretty-printed and concatenated together, then written to the spec's output.
- *
- * Be careful not to leave calls to <code>jasmine.log</code> in production code.
- */
-jasmine.Spec.prototype.log = function() {
- return this.results_.log(arguments);
-};
-
-jasmine.Spec.prototype.runs = function (func) {
- var block = new jasmine.Block(this.env, func, this);
- this.addToQueue(block);
- return this;
-};
-
-jasmine.Spec.prototype.addToQueue = function (block) {
- if (this.queue.isRunning()) {
- this.queue.insertNext(block);
- } else {
- this.queue.add(block);
- }
-};
-
-/**
- * @param {jasmine.ExpectationResult} result
- */
-jasmine.Spec.prototype.addMatcherResult = function(result) {
- this.results_.addResult(result);
-};
-
-jasmine.Spec.prototype.expect = function(actual) {
- var positive = new (this.getMatchersClass_())(this.env, actual, this);
- positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
- return positive;
-};
-
-/**
- * Waits a fixed time period before moving to the next block.
- *
- * @deprecated Use waitsFor() instead
- * @param {Number} timeout milliseconds to wait
- */
-jasmine.Spec.prototype.waits = function(timeout) {
- var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
- this.addToQueue(waitsFunc);
- return this;
-};
-
-/**
- * Waits for the latchFunction to return true before proceeding to the next block.
- *
- * @param {Function} latchFunction
- * @param {String} optional_timeoutMessage
- * @param {Number} optional_timeout
- */
-jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
- var latchFunction_ = null;
- var optional_timeoutMessage_ = null;
- var optional_timeout_ = null;
-
- for (var i = 0; i < arguments.length; i++) {
- var arg = arguments[i];
- switch (typeof arg) {
- case 'function':
- latchFunction_ = arg;
- break;
- case 'string':
- optional_timeoutMessage_ = arg;
- break;
- case 'number':
- optional_timeout_ = arg;
- break;
- }
- }
-
- var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
- this.addToQueue(waitsForFunc);
- return this;
-};
-
-jasmine.Spec.prototype.fail = function (e) {
- var expectationResult = new jasmine.ExpectationResult({
- passed: false,
- message: e ? jasmine.util.formatException(e) : 'Exception',
- trace: { stack: e.stack }
- });
- this.results_.addResult(expectationResult);
-};
-
-jasmine.Spec.prototype.getMatchersClass_ = function() {
- return this.matchersClass || this.env.matchersClass;
-};
-
-jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
- var parent = this.getMatchersClass_();
- var newMatchersClass = function() {
- parent.apply(this, arguments);
- };
- jasmine.util.inherit(newMatchersClass, parent);
- jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
- this.matchersClass = newMatchersClass;
-};
-
-jasmine.Spec.prototype.finishCallback = function() {
- this.env.reporter.reportSpecResults(this);
-};
-
-jasmine.Spec.prototype.finish = function(onComplete) {
- this.removeAllSpies();
- this.finishCallback();
- if (onComplete) {
- onComplete();
- }
-};
-
-jasmine.Spec.prototype.after = function(doAfter) {
- if (this.queue.isRunning()) {
- this.queue.add(new jasmine.Block(this.env, doAfter, this));
- } else {
- this.afterCallbacks.unshift(doAfter);
- }
-};
-
-jasmine.Spec.prototype.execute = function(onComplete) {
- var spec = this;
- if (!spec.env.specFilter(spec)) {
- spec.results_.skipped = true;
- spec.finish(onComplete);
- return;
- }
-
- this.env.reporter.reportSpecStarting(this);
-
- spec.env.currentSpec = spec;
-
- spec.addBeforesAndAftersToQueue();
-
- spec.queue.start(function () {
- spec.finish(onComplete);
- });
-};
-
-jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
- var runner = this.env.currentRunner();
- var i;
-
- for (var suite = this.suite; suite; suite = suite.parentSuite) {
- for (i = 0; i < suite.before_.length; i++) {
- this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
- }
- }
- for (i = 0; i < runner.before_.length; i++) {
- this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
- }
- for (i = 0; i < this.afterCallbacks.length; i++) {
- this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
- }
- for (suite = this.suite; suite; suite = suite.parentSuite) {
- for (i = 0; i < suite.after_.length; i++) {
- this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
- }
- }
- for (i = 0; i < runner.after_.length; i++) {
- this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
- }
-};
-
-jasmine.Spec.prototype.explodes = function() {
- throw 'explodes function should not have been called';
-};
-
-jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
- if (obj == jasmine.undefined) {
- throw "spyOn could not find an object to spy upon for " + methodName + "()";
- }
-
- if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
- throw methodName + '() method does not exist';
- }
-
- if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
- throw new Error(methodName + ' has already been spied upon');
- }
-
- var spyObj = jasmine.createSpy(methodName);
-
- this.spies_.push(spyObj);
- spyObj.baseObj = obj;
- spyObj.methodName = methodName;
- spyObj.originalValue = obj[methodName];
-
- obj[methodName] = spyObj;
-
- return spyObj;
-};
-
-jasmine.Spec.prototype.removeAllSpies = function() {
- for (var i = 0; i < this.spies_.length; i++) {
- var spy = this.spies_[i];
- spy.baseObj[spy.methodName] = spy.originalValue;
- }
- this.spies_ = [];
-};
-
-/**
- * Internal representation of a Jasmine suite.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {String} description
- * @param {Function} specDefinitions
- * @param {jasmine.Suite} parentSuite
- */
-jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
- var self = this;
- self.id = env.nextSuiteId ? env.nextSuiteId() : null;
- self.description = description;
- self.queue = new jasmine.Queue(env);
- self.parentSuite = parentSuite;
- self.env = env;
- self.before_ = [];
- self.after_ = [];
- self.children_ = [];
- self.suites_ = [];
- self.specs_ = [];
-};
-
-jasmine.Suite.prototype.getFullName = function() {
- var fullName = this.description;
- for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
- fullName = parentSuite.description + ' ' + fullName;
- }
- return fullName;
-};
-
-jasmine.Suite.prototype.finish = function(onComplete) {
- this.env.reporter.reportSuiteResults(this);
- this.finished = true;
- if (typeof(onComplete) == 'function') {
- onComplete();
- }
-};
-
-jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
- beforeEachFunction.typeName = 'beforeEach';
- this.before_.unshift(beforeEachFunction);
-};
-
-jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
- afterEachFunction.typeName = 'afterEach';
- this.after_.unshift(afterEachFunction);
-};
-
-jasmine.Suite.prototype.results = function() {
- return this.queue.results();
-};
-
-jasmine.Suite.prototype.add = function(suiteOrSpec) {
- this.children_.push(suiteOrSpec);
- if (suiteOrSpec instanceof jasmine.Suite) {
- this.suites_.push(suiteOrSpec);
- this.env.currentRunner().addSuite(suiteOrSpec);
- } else {
- this.specs_.push(suiteOrSpec);
- }
- this.queue.add(suiteOrSpec);
-};
-
-jasmine.Suite.prototype.specs = function() {
- return this.specs_;
-};
-
-jasmine.Suite.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.Suite.prototype.children = function() {
- return this.children_;
-};
-
-jasmine.Suite.prototype.execute = function(onComplete) {
- var self = this;
- this.queue.start(function () {
- self.finish(onComplete);
- });
-};
-jasmine.WaitsBlock = function(env, timeout, spec) {
- this.timeout = timeout;
- jasmine.Block.call(this, env, null, spec);
-};
-
-jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
-
-jasmine.WaitsBlock.prototype.execute = function (onComplete) {
- if (jasmine.VERBOSE) {
- this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
- }
- this.env.setTimeout(function () {
- onComplete();
- }, this.timeout);
-};
-/**
- * A block which waits for some condition to become true, with timeout.
- *
- * @constructor
- * @extends jasmine.Block
- * @param {jasmine.Env} env The Jasmine environment.
- * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
- * @param {Function} latchFunction A function which returns true when the desired condition has been met.
- * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
- * @param {jasmine.Spec} spec The Jasmine spec.
- */
-jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
- this.timeout = timeout || env.defaultTimeoutInterval;
- this.latchFunction = latchFunction;
- this.message = message;
- this.totalTimeSpentWaitingForLatch = 0;
- jasmine.Block.call(this, env, null, spec);
-};
-jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
-
-jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
-
-jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
- if (jasmine.VERBOSE) {
- this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
- }
- var latchFunctionResult;
- try {
- latchFunctionResult = this.latchFunction.apply(this.spec);
- } catch (e) {
- this.spec.fail(e);
- onComplete();
- return;
- }
-
- if (latchFunctionResult) {
- onComplete();
- } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
- var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
- this.spec.fail({
- name: 'timeout',
- message: message
- });
-
- this.abort = true;
- onComplete();
- } else {
- this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
- var self = this;
- this.env.setTimeout(function() {
- self.execute(onComplete);
- }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
- }
-};
-
-jasmine.version_= {
- "major": 1,
- "minor": 2,
- "build": 0,
- "revision": 1337005947
-};
diff --git a/test/spec/YamlSpec.coffee b/test/spec/YamlSpec.coffee
new file mode 100644
index 0000000..1d69981
--- /dev/null
+++ b/test/spec/YamlSpec.coffee
@@ -0,0 +1,76 @@
+
+unless YAML?
+ YAML = require '../../src/Yaml'
+
+
+describe 'YAML Parser', ->
+
+
+ it 'parses simple sequence', ->
+
+ expect YAML.parse '''
+ - apple
+ - banana
+ - carrot
+ '''
+ .toEqual ['apple', 'banana', 'carrot']
+
+
+ it 'parses nested sequences', ->
+
+ expect YAML.parse '''
+ -
+ - foo
+ - bar
+ - baz
+ '''
+ .toEqual [['foo', 'bar', 'baz']]
+
+
+ it 'parses mixed sequences', ->
+
+ expect YAML.parse '''
+ - apple
+ -
+ - foo
+ - bar
+ - x123
+ - banana
+ - carrot
+ '''
+ .toEqual ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+
+
+ it 'parses deeply nested sequences', ->
+
+ expect YAML.parse '''
+ -
+ -
+ - uno
+ - dos
+ '''
+ .toEqual [[['uno', 'dos']]]
+
+
+ it 'parses simple mapping', ->
+
+ expect YAML.parse '''
+ foo: whatever
+ bar: stuff
+ '''
+ .toEqual foo: 'whatever', bar: 'stuff'
+
+
+ it 'parses sequence in a mapping', ->
+
+ expect YAML.parse '''
+ foo: whatever
+ bar:
+ - uno
+ - dos
+ '''
+ .toEqual foo: 'whatever', bar: ['uno', 'dos']
+
+
+
+
diff --git a/test/spec/YamlSpec.js b/test/spec/YamlSpec.js
new file mode 100644
index 0000000..6e162c4
--- /dev/null
+++ b/test/spec/YamlSpec.js
@@ -0,0 +1,33 @@
+// Generated by CoffeeScript 1.7.1
+var YAML;
+
+if (typeof YAML === "undefined" || YAML === null) {
+ YAML = require('../../src/Yaml');
+}
+
+describe('YAML Parser', function() {
+ it('parses simple sequence', function() {
+ return expect(YAML.parse('- apple\n- banana\n- carrot')).toEqual(['apple', 'banana', 'carrot']);
+ });
+ it('parses nested sequences', function() {
+ return expect(YAML.parse('-\n - foo\n - bar\n - baz')).toEqual([['foo', 'bar', 'baz']]);
+ });
+ it('parses mixed sequences', function() {
+ return expect(YAML.parse('- apple\n-\n - foo\n - bar\n - x123\n- banana\n- carrot')).toEqual(['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']);
+ });
+ it('parses deeply nested sequences', function() {
+ return expect(YAML.parse('-\n -\n - uno\n - dos')).toEqual([[['uno', 'dos']]]);
+ });
+ it('parses simple mapping', function() {
+ return expect(YAML.parse('foo: whatever\nbar: stuff')).toEqual({
+ foo: 'whatever',
+ bar: 'stuff'
+ });
+ });
+ return it('parses sequence in a mapping', function() {
+ return expect(YAML.parse('foo: whatever\nbar:\n - uno\n - dos')).toEqual({
+ foo: 'whatever',
+ bar: ['uno', 'dos']
+ });
+ });
+});
diff --git a/test/test.html b/test/test.html
deleted file mode 100644
index a0381e8..0000000
--- a/test/test.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
- <title>Jasmine YAML tests</title>
-
- <link rel="shortcut icon" type="image/png" href="libs/jasmine-1.2.0/jasmine_favicon.png">
- <link rel="stylesheet" type="text/css" href="libs/jasmine-1.2.0/jasmine.css">
- <script type="text/javascript" src="libs/jasmine-1.2.0/jasmine.js"></script>
- <script type="text/javascript" src="libs/jasmine-1.2.0/jasmine-html.js"></script>
-
- <!-- include source files here... -->
- <script type="text/javascript" src="../bin/yaml.js"></script>
- <script type="text/javascript" src="libs/jasmine-1.2.0/YamlTests.js"></script>
- <!-- include spec files here... -->
- <script type="text/javascript" src="libs/jasmine-1.2.0/YamlSpec.js"></script>
-
- <script type="text/javascript">
- (function() {
- var jasmineEnv = jasmine.getEnv();
- jasmineEnv.updateInterval = 1000;
-
- var htmlReporter = new jasmine.HtmlReporter();
-
- jasmineEnv.addReporter(htmlReporter);
-
- jasmineEnv.specFilter = function(spec) {
- return htmlReporter.specFilter(spec);
- };
-
- var currentWindowOnload = window.onload;
-
- window.onload = function() {
- if (currentWindowOnload) {
- currentWindowOnload();
- }
- execJasmine();
- };
-
- function execJasmine() {
- jasmineEnv.execute();
- }
-
- })();
- </script>
-
-</head>
-
-<body>
-</body>
-</html>