qunited 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # QUnited
1
+ <img src="http://i.imgur.com/NIoQy.png" width="150px" />
2
2
 
3
3
  QUnited is a tool to run headless JavaScript tests with QUnit.
4
4
 
5
- Right now it exists in a proof-of-concept phase and only runs tests with Rhino/Envjs. Give it a try and let me know if you have any feedback.
5
+ Tests are run with PhantomJS if available, otherwise Rhino (Java) is used. Give it a try and let me know if you have any feedback.
6
6
 
7
7
  ## Installation
8
8
 
@@ -40,17 +40,25 @@ Note that you can also use an array to configure the test files but a glob patte
40
40
 
41
41
  ## Dependencies
42
42
 
43
- Right now only Rhino is set up to run tests. This means you'll need to have Java (version 1.1 minimum) in your path to use QUnited.
43
+ - PhantomJS
44
44
 
45
- ## Attribution
45
+ OR
46
46
 
47
- QUnited builds on work done on the following projects:
47
+ - Java (version 1.1 minimum)
48
48
 
49
- [QUnit](https://github.com/jquery/qunit/) QUnit is a nice little JavaScript testing library and is, of course, central to what this project does.
49
+ PhantomJS is preferred since it uses real WebKit and is faster. Running Rhino on Java should be considered a fallback.
50
50
 
51
- [Rhino](http://www.mozilla.org/rhino/) Rhino is a JavaScript interpreter that runs on the JVM.
51
+ ## Credits
52
52
 
53
- [Envjs](http://www.envjs.com/) Envjs is a simulated browser environment written in JavaScript.
53
+ QUnited builds on the following projects:
54
+
55
+ [QUnit](https://github.com/jquery/qunit/) is a nice little JavaScript testing library and is, of course, central to what this project does.
56
+
57
+ [PhantomJS](http://phantomjs.org/) is a headless WebKit with JavaScript API.
58
+
59
+ [Rhino](http://www.mozilla.org/rhino/) is a JavaScript interpreter that runs on the JVM.
60
+
61
+ [Envjs](http://www.envjs.com/) is a simulated browser environment written in JavaScript.
54
62
 
55
63
  ## License
56
64
 
data/bin/qunited CHANGED
@@ -1,23 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'qunited'
3
3
 
4
- if ARGV.empty? || ARGV.include?('-h') || ARGV.include?('--help')
5
- puts <<-HELP_TEXT
6
- Usage: qunited [OPTIONS] [JS_SOURCE_FILES...] -- [JS_TEST_FILES..]
7
-
8
- Runs JavaScript unit tests with QUnit.
9
-
10
- JS_SOURCE_FILES are the JavaScript files that you want to test. They will all be
11
- loaded for running each test.
12
-
13
- JS_TEST_FILES are files that contain the QUnit tests to run.
14
- and (optional) NAME
15
-
16
- Options:
17
- -h, --help Show this message
18
- HELP_TEXT
19
- exit
20
- end
21
-
22
- js_source_files, js_test_files = ARGV.join(' ').split('--').map { |file_list| file_list.split(' ') }
23
- exit QUnited::Runner.run(js_source_files, js_test_files)
4
+ QUnited::Application.new.run
@@ -0,0 +1,108 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+
4
+ module QUnited
5
+ class Application
6
+ def run
7
+ handle_exceptions do
8
+ handle_options
9
+ run_tests
10
+ end
11
+ end
12
+
13
+ def run_tests
14
+ js_source_files, js_test_files = ARGV.join(' ').split('--').map { |file_list| file_list.split(' ') }
15
+ exit QUnited::Runner.new(js_source_files, js_test_files, options).run
16
+ end
17
+
18
+ # Client options generally parsed from the command line
19
+ def options
20
+ @options ||= {}
21
+ end
22
+
23
+ # Parse and handle command line options
24
+ def handle_options
25
+ drivers = ::QUnited::Driver.constants.reject { |d| d == :Base }
26
+ valid_drivers_string = "Valid drivers include: #{drivers.map { |d| d.to_s }.join(', ')}"
27
+
28
+ args_empty = ARGV.empty?
29
+
30
+ # This is a bit of a hack, but OptionParser removes the -- that separates the source
31
+ # and test files and we need to put it back in the right place. Save the distance from
32
+ # the end to do this later.
33
+ double_dash_neg_index = ARGV.find_index('--') && (ARGV.find_index('--') - ARGV.size)
34
+
35
+ optparse = OptionParser.new do |opts|
36
+ opts.banner = <<-HELP_TEXT
37
+ Usage: qunited [OPTIONS] [JS_SOURCE_FILES...] -- [JS_TEST_FILES..]
38
+
39
+ Runs JavaScript unit tests with QUnit.
40
+
41
+ JS_SOURCE_FILES are the JavaScript files that you want to test. They will all be
42
+ loaded for running each test.
43
+
44
+ JS_TEST_FILES are files that contain the QUnit tests to run.
45
+
46
+ Options:
47
+ HELP_TEXT
48
+
49
+ opts.on('-d', '--driver [NAME]', 'Specify the driver to use in running the tests',
50
+ valid_drivers_string) do |name|
51
+ raise UsageError, 'Must specify a driver name with -d or --driver option' unless name
52
+ names_and_drivers = Hash[drivers.map { |d| d.to_s.downcase }.zip(drivers)]
53
+ driver = names_and_drivers[name.downcase]
54
+ raise UsageError, "Invalid driver specified: #{name}\n#{valid_drivers_string}" unless driver
55
+ options[:driver] = driver
56
+ end
57
+ opts.on_tail('-h', '--help', 'Show this message') do
58
+ puts opts
59
+ exit
60
+ end
61
+ opts.on_tail('--version', 'Print the QUnited version') do
62
+ puts ::QUnited::VERSION
63
+ exit
64
+ end
65
+
66
+ if args_empty
67
+ puts opts
68
+ exit 1
69
+ end
70
+ end.parse!
71
+
72
+ # Put the -- back in if we had one initially and it was removed
73
+ if double_dash_neg_index && !ARGV.include?('--')
74
+ ARGV.insert(double_dash_neg_index, '--')
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def handle_exceptions
81
+ begin
82
+ yield
83
+ rescue SystemExit
84
+ exit
85
+ rescue UsageError => ex
86
+ $stderr.puts ex.message
87
+ exit 1
88
+ rescue OptionParser::InvalidOption => ex
89
+ $stderr.puts ex.message
90
+ exit 1
91
+ rescue Exception => ex
92
+ display_error_message ex
93
+ exit 1
94
+ end
95
+ end
96
+
97
+ def display_error_message(ex)
98
+ msg = <<MSG
99
+ QUnited has aborted! If this is unexpected, you may want to open an issue at
100
+ github.com/aaronroyer/qunited to get a possible bug fixed. If you do, please
101
+ include the debug information below.
102
+ MSG
103
+ $stderr.puts msg
104
+ $stderr.puts ex.message
105
+ $stderr.puts ex.backtrace
106
+ end
107
+ end
108
+ end
@@ -36,7 +36,7 @@ module QUnited
36
36
  end
37
37
  end
38
38
 
39
- @results = ::QUnited::Results.from_javascript_produced_yaml(IO.read(results_file))
39
+ @results = ::QUnited::Results.from_javascript_produced_json(IO.read(results_file))
40
40
  end
41
41
 
42
42
  private
@@ -95,7 +95,7 @@ page.open(tests_html_file, function(status) {
95
95
  }, function(){
96
96
  // Results should have been collected with code in qunited.js. Check that file
97
97
  // for more details. Grab the YAML it outputs and write it to the results file.
98
- var results = page.evaluate(function() { return QUnited.collectedTestResultsAsYaml(); });
98
+ var results = page.evaluate(function() { return QUnited.collectedTestResultsAsJson(); });
99
99
  fs.write(results_output_file, results, 'a');
100
100
  phantom.exit(0);
101
101
  });
@@ -11,7 +11,6 @@
11
11
  <ol id="qunit-tests"></ol>
12
12
  </body>
13
13
  <%= script_tag support_file_path('qunit.js') %>
14
- <%= script_tag support_file_path('yaml.js') %>
15
14
  <%= script_tag support_file_path('qunited.js') %>
16
15
 
17
16
  <script type="text/javascript" charset="utf-8">
@@ -44,7 +44,7 @@ module QUnited
44
44
  unless (err = stderr.read).strip.empty? then $stderr.puts(err) end
45
45
  end
46
46
 
47
- @results = ::QUnited::Results.from_javascript_produced_yaml(IO.read(results_file))
47
+ @results = ::QUnited::Results.from_javascript_produced_json(IO.read(results_file))
48
48
  end
49
49
  end
50
50
  end
@@ -8,7 +8,7 @@
8
8
  // test files.
9
9
  //
10
10
  // Example:
11
- // java -jar js.jar -opt -1 runner.js commonlibdir libdir outfile.yaml source.js -- test1.js test2.js
11
+ // java -jar js.jar -opt -1 runner.js commonlibdir libdir outfile.json source.js -- test1.js test2.js
12
12
  // ^ our args start here
13
13
 
14
14
  var QUnited = { sourceFiles: [], testFiles: [] };
@@ -20,7 +20,7 @@ var QUnited = { sourceFiles: [], testFiles: [] };
20
20
 
21
21
  load(libDir + '/env.rhino.js');
22
22
 
23
- ['qunit.js', 'yaml.js'].forEach(function(lib) {
23
+ ['qunit.js', 'qunited.js'].forEach(function(lib) {
24
24
  load(commonLibDir + '/' + lib);
25
25
  });
26
26
 
@@ -39,46 +39,7 @@ var QUnited = { sourceFiles: [], testFiles: [] };
39
39
  QUnit.config.autorun = true;
40
40
  QUnit.config.updateRate = 0;
41
41
 
42
- // Various state we'll need while running the tests
43
- QUnited.modulesMap = {};
44
- QUnited.currentTestFile = null; // Set when loading files, see below
45
- var currentModule, currentTest;
46
-
47
- ///// Listen for QUnit events during tests
48
-
49
- QUnit.testStart(function(data) {
50
- currentTest = {
51
- name: data.name,
52
- assertion_data: [], // Ruby-style, since we'll be reading it with Ruby
53
- start: new Date(),
54
- assertions: 0,
55
- file: QUnited.currentTestFile
56
- };
57
-
58
- var moduleName = data.module || "(no module)",
59
- module = QUnited.modulesMap[moduleName];
60
- if (!module) {
61
- module = {name: moduleName, tests: []};
62
- QUnited.modulesMap[moduleName] = module;
63
- }
64
- module.tests.push(currentTest);
65
- });
66
-
67
- QUnit.testDone(function(data) {
68
- currentTest.duration = ((new Date()).getTime() - currentTest.start.getTime()) / 1000;
69
- currentTest.failed = data.failed;
70
- currentTest.total = data.total;
71
- });
72
-
73
- /*
74
- * Called on every assertion AND whenever we have an expect(num) fail. You cannot tell this
75
- * apart from an assertion (even though you could make a good guess) with certainty so just
76
- * don't worry about it as it will only throw assertions count off on a failing test.
77
- */
78
- QUnit.log(function(data) {
79
- currentTest.assertions++;
80
- currentTest.assertion_data.push(data);
81
- });
42
+ QUnited.startCollectingTestResults();
82
43
 
83
44
  })(Array.prototype.slice.call(arguments, 0));
84
45
 
@@ -143,30 +104,7 @@ QUnited.testFiles.forEach(function(file) {
143
104
  });
144
105
 
145
106
  (function() {
146
- var modules = [];
147
-
148
- var ISODateString = function(d) {
149
- function pad(n) { return n < 10 ? '0' + n : n; }
150
- return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1)+'-' + pad(d.getUTCDate()) + 'T' +
151
- pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + 'Z';
152
- }
153
-
154
- // Make a modules array for outputing results
155
- Object.keys(QUnited.modulesMap).forEach(function(key) {
156
- var mod = QUnited.modulesMap[key],
157
- tests = mod.tests;
158
- modules.push(mod);
159
- tests.forEach(function(test) {
160
- // YAML serializer doesn't seem to do dates; make them strings
161
- test.start = ISODateString(test.start);
162
- // Convert the duration to a string since the YAML serializer makes them all 0s otherwise
163
- test.duration = "" + test.duration;
164
- });
165
- });
166
-
167
-
168
- // Write all the results as YAML
169
107
  var writer = new java.io.PrintWriter(QUnited.outputFile);
170
- writer.write(YAML.encode(modules));
108
+ writer.write(QUnited.collectedTestResultsAsJson());
171
109
  writer.close();
172
110
  })();
@@ -53,24 +53,16 @@ QUnited.startCollectingTestResults = function() {
53
53
  });
54
54
  };
55
55
 
56
- QUnited.collectedTestResultsAsYaml = function() {
57
- var modules = [];
58
-
59
- // Make a modules array for outputing results
60
- Object.keys(QUnited.modulesMap).forEach(function(key) {
61
- var mod = QUnited.modulesMap[key],
62
- tests = mod.tests;
63
- modules.push(mod);
64
- tests.forEach(function(test) {
65
- // YAML serializer doesn't seem to do dates; make them strings
66
- test.start = QUnited.util.dateToString(test.start);
67
- // Convert the duration to a string since the YAML serializer makes them all 0s otherwise
68
- test.duration = "" + test.duration;
69
- });
56
+ /* Results as an Array of modules */
57
+ QUnited.collectedTestResults = function() {
58
+ return Object.keys(QUnited.modulesMap).map(function(key) {
59
+ return QUnited.modulesMap[key]
70
60
  });
61
+ };
71
62
 
72
- // Write all the results as YAML
73
- return YAML.encode(modules);
63
+ /* Module results as a JSON string */
64
+ QUnited.collectedTestResultsAsJson = function() {
65
+ return JSON.stringify(QUnited.collectedTestResults());
74
66
  };
75
67
 
76
68
  })();
@@ -13,9 +13,6 @@ module QUnited
13
13
  # order you will have to use source_files=(files_array).
14
14
  #
15
15
  # If an array of files is set with source_files=(files_array) then this will be ignored.
16
- #
17
- # default (unless source_files array is set):
18
- # 'app/assets/javascripts/**/*.js'
19
16
  attr_accessor :source_files_pattern
20
17
 
21
18
  # Array of JavaScript source files (and any dependencies). These will be loaded in order
@@ -25,14 +22,14 @@ module QUnited
25
22
  # Glob pattern to match QUnit test files.
26
23
  #
27
24
  # If an array of test files is set with test_files=(files) then this will be ignored.
28
- #
29
- # default:
30
- # 'test/javascripts/**/*.js'
31
25
  attr_accessor :test_files_pattern
32
26
 
33
27
  # Array of QUnit test files.
34
28
  attr_accessor :test_files
35
29
 
30
+ # The driver to use to run the QUnit tests.
31
+ attr_accessor :driver
32
+
36
33
  # Use verbose output. If this is true, the task will print the QUnited command to stdout.
37
34
  #
38
35
  # default:
@@ -41,6 +38,7 @@ module QUnited
41
38
 
42
39
  def initialize(*args)
43
40
  @name = args.shift || :qunited
41
+ @verbose = true
44
42
 
45
43
  yield self if block_given?
46
44
 
@@ -69,7 +67,9 @@ module QUnited
69
67
  private
70
68
 
71
69
  def command
72
- "qunited #{source_files_to_include.join(' ')} -- #{test_files_to_run.join(' ')}"
70
+ cmd = 'qunited'
71
+ cmd << " --driver #{driver}" if driver
72
+ cmd << " #{source_files_to_include.join(' ')} -- #{test_files_to_run.join(' ')}"
73
73
  end
74
74
 
75
75
  def source_files_to_include
@@ -81,8 +81,8 @@ module QUnited
81
81
  end
82
82
  end
83
83
 
84
- def self.from_javascript_produced_yaml(yaml)
85
- self.new clean_up_results(YAML.load(yaml))
84
+ def self.from_javascript_produced_json(json)
85
+ self.new clean_up_results(YAML.load(json))
86
86
  end
87
87
 
88
88
  def initialize(modules_results_array)
@@ -179,7 +179,6 @@ module QUnited
179
179
 
180
180
  def self.clean_up_test_results(test_results)
181
181
  test_results[:start] = DateTime.parse(test_results[:start])
182
- test_results[:duration] = Float(test_results[:duration])
183
182
  test_results[:assertion_data].map! { |data| symbolize_keys data }
184
183
  test_results
185
184
  end
@@ -2,22 +2,55 @@ module QUnited
2
2
  class Runner
3
3
 
4
4
  # The drivers in order of which to use first when not otherwise specified
5
- DRIVERS = [:PhantomJs, :Rhino].map { |driver| ::QUnited::Driver.const_get(driver) }.freeze
5
+ DRIVERS_PRIORITY = [:PhantomJs, :Rhino].freeze
6
6
 
7
- def self.run(js_source_files, js_test_files)
8
- driver_class = self.best_available_driver
9
- runner = driver_class.new(js_source_files, js_test_files)
7
+ attr_accessor :js_source_files, :js_test_files, :options
10
8
 
11
- puts "\n# Running JavaScript tests with #{runner.name}:\n\n"
9
+ def initialize(js_source_files, js_test_files, options={})
10
+ @js_source_files, @js_test_files, @options = js_source_files, js_test_files, options
11
+ end
12
+
13
+ def run
14
+ driver_class = resolve_driver_class
15
+ driver = driver_class.new(js_source_files, js_test_files)
16
+
17
+ puts "\n# Running JavaScript tests with #{driver.name}:\n\n"
12
18
 
13
- results = runner.run
19
+ results = driver.run
14
20
  puts results
15
21
  results.to_i
16
22
  end
17
23
 
24
+ def resolve_driver_class
25
+ if options[:driver]
26
+ begin
27
+ driver_class = get_driver(options[:driver])
28
+ rescue NameError
29
+ raise UsageError, "#{options[:driver].to_s} does not exist"
30
+ end
31
+
32
+ if !driver_class
33
+ raise UsageError, "#{driver_class} driver not found"
34
+ elsif !driver_class.available?
35
+ raise UsageError, "#{driver_class} driver specified, but not available"
36
+ end
37
+ driver_class
38
+ end
39
+
40
+ driver_class ||= best_available_driver
41
+ raise(UsageError, 'No driver available') unless driver_class
42
+ driver_class
43
+ end
44
+
45
+ def get_driver(klass)
46
+ if ::QUnited::Driver.constants.reject { |d| d == :Base }.include?(klass)
47
+ ::QUnited::Driver.const_get(klass)
48
+ end
49
+ end
50
+
18
51
  # Get the runner that we will be using to run the JavaScript tests.
19
- def self.best_available_driver
20
- DRIVERS.find { |driver| driver.available? }
52
+ def best_available_driver
53
+ DRIVERS_PRIORITY.map { |driver| get_driver(driver) }.find { |driver| driver.available? }
21
54
  end
22
55
  end
23
56
  end
@@ -1,3 +1,3 @@
1
1
  module QUnited
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/qunited.rb CHANGED
@@ -2,3 +2,9 @@ require 'qunited/version'
2
2
  require 'qunited/results'
3
3
  require 'qunited/driver'
4
4
  require 'qunited/runner'
5
+ require 'qunited/application'
6
+
7
+ module QUnited
8
+ class UsageError < Exception
9
+ end
10
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ class AvailableDriver
4
+ def self.available?; true end
5
+ end
6
+
7
+ class NotAvailableDriver
8
+ def self.available?; false end
9
+ end
10
+
11
+ class TestRunner < MiniTest::Unit::TestCase
12
+ def test_raises_exception_with_nonexistent_driver
13
+ runner = QUnited::Runner.new(['source.js'], ['test.js'], { driver: :doesNotExist })
14
+ assert_raises(QUnited::UsageError) do
15
+ runner.resolve_driver_class
16
+ end
17
+ end
18
+
19
+ def test_specified_driver_can_be_used_if_available
20
+ runner = QUnited::Runner.new(['source.js'], ['test.js'], { driver: :AvailableDriver })
21
+
22
+ def runner.get_driver(klass)
23
+ if klass == :AvailableDriver
24
+ AvailableDriver
25
+ else
26
+ raise 'Only :AvailableDriver is used for this test'
27
+ end
28
+ end
29
+ runner.resolve_driver_class # Nothing raised
30
+ end
31
+
32
+ def test_raises_exception_when_not_available_driver_is_specified
33
+ runner = QUnited::Runner.new(['source.js'], ['test.js'], { driver: :NotAvailableDriver })
34
+
35
+ def runner.get_driver(klass)
36
+ if klass == :NotAvailableDriver
37
+ NotAvailableDriver
38
+ else
39
+ raise 'Only :NotAvailableDriver is used for this test'
40
+ end
41
+ end
42
+
43
+ assert_raises(QUnited::UsageError) do
44
+ runner.resolve_driver_class
45
+ end
46
+ end
47
+
48
+ def test_raises_exception_when_no_driver_specified_and_no_drivers_available
49
+ runner = QUnited::Runner.new(['source.js'], ['test.js'])
50
+
51
+ # Make every driver the NotAvailable driver
52
+ def runner.get_driver(klass)
53
+ NotAvailableDriver
54
+ end
55
+
56
+ assert_raises(QUnited::UsageError) do
57
+ runner.resolve_driver_class
58
+ end
59
+ end
60
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qunited
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-06 00:00:00.000000000 Z
12
+ date: 2012-07-08 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: QUnited runs headless QUnit tests as part of your normal build
15
15
  email:
@@ -26,6 +26,7 @@ files:
26
26
  - Rakefile
27
27
  - bin/qunited
28
28
  - lib/qunited.rb
29
+ - lib/qunited/application.rb
29
30
  - lib/qunited/driver.rb
30
31
  - lib/qunited/driver/base.rb
31
32
  - lib/qunited/driver/phantomjs/phantomjs.rb
@@ -37,7 +38,6 @@ files:
37
38
  - lib/qunited/driver/rhino/support/runner.js
38
39
  - lib/qunited/driver/support/qunit.js
39
40
  - lib/qunited/driver/support/qunited.js
40
- - lib/qunited/driver/support/yaml.js
41
41
  - lib/qunited/rake_task.rb
42
42
  - lib/qunited/results.rb
43
43
  - lib/qunited/runner.rb
@@ -63,6 +63,7 @@ files:
63
63
  - test/unit/test_phantomjs_driver.rb
64
64
  - test/unit/test_results.rb
65
65
  - test/unit/test_rhino_driver.rb
66
+ - test/unit/test_runner.rb
66
67
  homepage: https://github.com/aaronroyer/qunited
67
68
  licenses: []
68
69
  post_install_message:
@@ -108,3 +109,4 @@ test_files:
108
109
  - test/unit/test_phantomjs_driver.rb
109
110
  - test/unit/test_results.rb
110
111
  - test/unit/test_rhino_driver.rb
112
+ - test/unit/test_runner.rb
@@ -1,22 +0,0 @@
1
- /*
2
- Copyright (c) 2010 Jeremy Faivre
3
-
4
- Permission is hereby granted, free of charge, to any person obtaining a copy
5
- of this software and associated documentation files (the "Software"), to deal
6
- in the Software without restriction, including without limitation the rights
7
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- copies of the Software, and to permit persons to whom the Software is furnished
9
- to do so, subject to the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be included in all
12
- copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- THE SOFTWARE.
21
- */
22
- var Yaml=function(){};Yaml.prototype={spec:"1.2",setSpecVersion:function(a){if(a!="1.1"&&a!="1.2"){throw new InvalidArgumentException("Version "+a+" of the YAML specifications is not supported")}this.spec=a},getSpecVersion:function(){return this.spec},loadFile:function(a,b){if(b==undefined){input=this.getFileContents(a);return this.load(input)}this.getFileContents(a,function(c){b(new Yaml().load(c))})},load:function(a){var c=new YamlParser();var b=null;try{b=c.parse(a)}catch(d){if(d.name!=undefined&&d.name.toString=="TypeError"){throw d}throw"Syntax error: "+d.message}return b},dump:function(b,a){if(a==undefined){a=2}yaml=new YamlDumper();return yaml.dump(b,a)},getXHR:function(){if(window.XMLHttpRequest){return new XMLHttpRequest()}if(window.ActiveXObject){var c=["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];for(var a=0;a<4;a++){try{return new ActiveXObject(c[a])}catch(b){}}}return null},getFileContents:function(a,c){var b=this.getXHR();if(c==undefined){b.open("GET",a,false);b.send(null);if(b.status==200||b.status==0){return b.responseText}return null}b.onreadystatechange=function(){if(b.readyState==4){if(b.status==200||b.status==0){c(b.responseText)}else{c(null)}}};b.open("GET",a,true);b.send(null)}};var YAML={encode:function(a){return new Yaml().dump(a)},decode:function(a){return new Yaml().load(a)},load:function(a,b){return new Yaml().loadFile(a,b)}};if(typeof(InvalidArgumentException)=="undefined"){InvalidArgumentException=function(a){this.name="InvalidArgumentException";this.message=a}};var YamlInline=function(){};YamlInline.prototype={i:null,load:function(b){var a=null;b=this.trim(b);if(0==b.length){return""}switch(b.charAt(0)){case"[":a=this.parseSequence(b);break;case"{":a=this.parseMapping(b);break;default:a=this.parseScalar(b)}return a},dump:function(d){var b;var a;var c=new Yaml();if("1.1"==c.getSpecVersion()){b=["true","on","+","yes","y"];a=["false","off","-","no","n"]}else{b=["true"];a=["false"]}if(typeof(d)=="object"&&null!=d){return this.dumpObject(d)}if(undefined==d||null==d){return"null"}if(typeof(d)=="boolean"){return d?"true":"false"}if(/^\d+/.test(d)){return typeof(d)=="string"?"'"+d+"'":parseInt(d)}if(this.isNumeric(d)){return typeof(d)=="string"?"'"+d+"'":parseFloat(d)}if(typeof(d)=="number"){return d==Infinity?".Inf":(d==-Infinity?"-.Inf":(isNaN(d)?".NAN":d))}if((d+"").indexOf("\n")!=-1||(d+"").indexOf("\r")!=-1){return'"'+d.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r")+'"'}if((/[\s\'"\:\{\}\[\],&\*\#\?]/.test(d))||(/^[-?|<>=!%@`]/.test(d))){return"'"+d.split("'").join("''")+"'"}if(""==d){return"''"}if(this.getTimestampRegex().test(d)){return"'"+d+"'"}if(this.inArray(d.toLowerCase(),b)){return"'"+d+"'"}if(this.inArray(d.toLowerCase(),a)){return"'"+d+"'"}if(this.inArray(d.toLowerCase(),["null","~"])){return"'"+d+"'"}return d},dumpObject:function(e){var d=this.getKeys(e);var b=null;var c;var a=d.length;if(e instanceof Array){b=[];for(c=0;c<a;c++){b.push(this.dump(e[d[c]]))}return"["+b.join(", ")+"]"}b=[];for(c=0;c<a;c++){b.push(this.dump(d[c])+": "+this.dump(e[d[c]]))}return"{ "+b.join(", ")+" }"},parseScalar:function(b,g,e,d,f){if(g==undefined){g=null}if(e==undefined){e=['"',"'"]}if(d==undefined){d=0}if(f==undefined){f=true}var a=null;var h=null;var c=null;if(this.inArray(b[d],e)){a=this.parseQuotedScalar(b,d);d=this.i}else{if(!g){a=(b+"").substring(d);d+=a.length;h=a.indexOf(" #");if(h!=-1){a=a.substr(0,h).replace(/\s+$/g,"")}}else{if(c=new RegExp("^(.+?)("+g.join("|")+")").exec((b+"").substring(d))){a=c[1];d+=a.length}else{throw new InvalidArgumentException("Malformed inline YAML string ("+b+").")}}a=f?this.evaluateScalar(a):a}this.i=d;return a},parseQuotedScalar:function(b,d){var c=null;if(!(c=new RegExp("^"+YamlInline.REGEX_QUOTED_STRING).exec((b+"").substring(d)))){throw new InvalidArgumentException("Malformed inline YAML string ("+(b+"").substring(d)+").")}var a=c[0].substr(1,c[0].length-2);if('"'==(b+"").charAt(d)){a=a.split('\\"').join('"').split("\\n").join("\n").split("\\r").join("\r")}else{a=a.split("''").join("'")}d+=c[0].length;this.i=d;return a},parseSequence:function(g,c){if(c==undefined){c=0}var b=[];var a=g.length;c+=1;while(c<a){switch(g.charAt(c)){case"[":b.push(this.parseSequence(g,c));c=this.i;break;case"{":b.push(this.parseMapping(g,c));c=this.i;break;case"]":this.i=c;return b;case",":case" ":break;default:isQuoted=this.inArray(g.charAt(c),['"',"'"]);var d=this.parseScalar(g,[",","]"],['"',"'"],c);c=this.i;if(!isQuoted&&(d+"").indexOf(": ")!=-1){try{d=this.parseMapping("{"+d+"}")}catch(f){if(!(f instanceof InvalidArgumentException)){throw f}}}b.push(d);c--}c++}throw new InvalidArgumentException("Malformed inline YAML string "+g)},parseMapping:function(d,f){if(f==undefined){f=0}var c={};var a=d.length;f+=1;var b=false;var g=false;while(f<a){g=false;switch(d.charAt(f)){case" ":case",":f++;g=true;break;case"}":this.i=f;return c}if(g){continue}var e=this.parseScalar(d,[":"," "],['"',"'"],f,false);f=this.i;b=false;while(f<a){switch(d.charAt(f)){case"[":c[e]=this.parseSequence(d,f);f=this.i;b=true;break;case"{":c[e]=this.parseMapping(d,f);f=this.i;b=true;break;case":":case" ":break;default:c[e]=this.parseScalar(d,[",","}"],['"',"'"],f);f=this.i;b=true;f--}++f;if(b){g=true;break}}if(g){continue}}throw new InvalidArgumentException("Malformed inline YAML string "+d)},evaluateScalar:function(b){b=this.trim(b);var e;var d;var f=new Yaml();if("1.1"==f.getSpecVersion()){e=["true","on","+","yes","y"];d=["false","off","-","no","n"]}else{e=["true"];d=["false"]}var c=null;var a=null;if(("null"==b.toLowerCase())||(""==b)||("~"==b)){return null}if((b+"").indexOf("!str")!=-1){return(""+b).substring(5)}if((b+"").indexOf("! ")!=-1){return parseInt(this.parseScalar((b+"").substring(2)))}if(/^\d+/.test(b)){c=b;a=parseInt(b);return"0"==b.charAt(0)?this.octdec(b):((""+c==""+a)?a:c)}if(this.inArray(b.toLowerCase(),e)){return true}if(this.inArray(b.toLowerCase(),d)){return false}if(this.isNumeric(b)){return"0x"==(b+"").substr(0,2)?hexdec($scalar):floatval($scalar)}if(b.toLowerCase()==".inf"){return Infinity}if(b.toLowerCase()==".nan"){return NaN}if(b.toLowerCase()=="-.inf"){return -Infinity}if(/^(-|\+)?[0-9,]+(\.[0-9]+)?$/.test(b)){return parseFloat(b.split(",").join(""))}if(this.getTimestampRegex().test(b)){return this.strtodate(b)}return""+b},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(a){return(a+"").replace(/^\s+/,"").replace(/\s+$/,"")},isNumeric:function(a){return(a-0)==a&&a.length>0&&a.replace(/\s+/g,"")!=""},inArray:function(c,d){var b;var a=d.length;for(b=0;b<a;b++){if(c==d[b]){return true}}return false},getKeys:function(c){var b=[];for(var a in c){if(c.hasOwnProperty(a)){b.push(a)}}return b},octdec:function(a){return parseInt((a+"").replace(/[^0-7]/gi,""),8)},hexdec:function(a){a=this.trim(a);if((a+"").substr(0,2)=="0x"){a=(a+"").substring(2)}return parseInt((a+"").replace(/[^a-f0-9]/gi,""),16)},strtodate:function(a){var b=new Date();b.setTime(this.strtotime(a,new Date().getTime()));return b},strtotime:function(o,t){var q,p,i,m="",s="";m=o;m=m.replace(/\s{2,}|^\s|\s$/g," ");m=m.replace(/[\t\r\n]/g,"");if(m=="now"){return(new Date()).getTime()/1000}else{if(!isNaN(s=Date.parse(m))){return(s/1000)}else{if(t){t=new Date(t*1000)}else{t=new Date()}}}m=m.toLowerCase();var r={day:{sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6},mon:{jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11}};var v=this.strtotime;var u=function(a){var c=(a[2]&&a[2]=="ago");var d=(d=a[0]=="last"?-1:1)*(c?-1:1);switch(a[0]){case"last":case"next":switch(a[1].substring(0,3)){case"yea":t.setFullYear(t.getFullYear()+d);break;case"mon":t.setMonth(t.getMonth()+d);break;case"wee":t.setDate(t.getDate()+(d*7));break;case"day":t.setDate(t.getDate()+d);break;case"hou":t.setHours(t.getHours()+d);break;case"min":t.setMinutes(t.getMinutes()+d);break;case"sec":t.setSeconds(t.getSeconds()+d);break;default:var e;if(typeof(e=r.day[a[1].substring(0,3)])!="undefined"){var b=e-t.getDay();if(b==0){b=7*d}else{if(b>0){if(a[0]=="last"){b-=7}}else{if(a[0]=="next"){b+=7}}}t.setDate(t.getDate()+b)}}break;default:if(/\d+/.test(a[0])){d*=parseInt(a[0],10);switch(a[1].substring(0,3)){case"yea":t.setFullYear(t.getFullYear()+d);break;case"mon":t.setMonth(t.getMonth()+d);break;case"wee":t.setDate(t.getDate()+(d*7));break;case"day":t.setDate(t.getDate()+d);break;case"hou":t.setHours(t.getHours()+d);break;case"min":t.setMinutes(t.getMinutes()+d);break;case"sec":t.setSeconds(t.getSeconds()+d);break}}else{return false}break}return true};p=m.match(/^(\d{2,4}-\d{2}-\d{2})(?:\s(\d{1,2}:\d{2}(:\d{2})?)?(?:\.(\d+))?)?$/);if(p!=null){if(!p[2]){p[2]="00:00:00"}else{if(!p[3]){p[2]+=":00"}}i=p[1].split(/-/g);for(q in r.mon){if(r.mon[q]==i[1]-1){i[1]=q}}i[0]=parseInt(i[0],10);i[0]=(i[0]>=0&&i[0]<=69)?"20"+(i[0]<10?"0"+i[0]:i[0]+""):(i[0]>=70&&i[0]<=99)?"19"+i[0]:i[0]+"";return parseInt(v(i[2]+" "+i[1]+" "+i[0]+" "+p[2])+(p[4]?p[4]/1000:""),10)}var n="([+-]?\\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)?";p=m.match(new RegExp(n,"gi"));if(p==null){return false}for(q=0;q<p.length;q++){if(!u(p[q].split(" "))){return false}}return(t.getTime()/1000)}};YamlInline.REGEX_QUOTED_STRING="(?:\"(?:[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|'(?:[^']*(?:''[^']*)*)')";var YamlParser=function(a){this.offset=this.isDefined(a)?a:0};YamlParser.prototype={offset:0,lines:[],currentLineNb:-1,currentLine:"",refs:{},parse:function(m){this.currentLineNb=-1;this.currentLine="";this.lines=this.cleanup(m).split("\n");var u=null;while(this.moveToNextLine()){if(this.isCurrentLineEmpty()){continue}if(/^\t+/.test(this.currentLine)){throw new InvalidArgumentException("A YAML file cannot contain tabs as indentation at line "+(this.getRealCurrentLineNb()+1)+" ("+this.currentLine+")")}var j=false;var r=false;var q=false;var b=null;var a=null;var t=null;var d=null;var e=null;var v=null;var h=null;var p=null;var f=null;if(b=/^\-((\s+)(.+?))?\s*$/.exec(this.currentLine)){if(!this.isDefined(u)){u=[]}if(!(u instanceof Array)){throw new InvalidArgumentException("Non array entry at line "+(this.getRealCurrentLineNb()+1)+".")}b={leadspaces:b[2],value:b[3]};if(this.isDefined(b.value)&&(a=/^&([^ ]+) *(.*)/.exec(b.value))){a={ref:a[1],value:a[2]};j=a.ref;b.value=a.value}if(!this.isDefined(b.value)||""==b.value.split(" ").join("")||this.trim(b.value).charAt(0)=="#"){t=this.getRealCurrentLineNb()+1;d=new YamlParser(t);d.refs=this.refs;u.push(d.parse(this.getNextEmbedBlock()));this.refs=d.refs}else{if(this.isDefined(b.leadspaces)&&" "==b.leadspaces&&(a=new RegExp("^("+YamlInline.REGEX_QUOTED_STRING+"|[^ '\"{].*?) *:(\\s+(.+?))?\\s*$").exec(b.value))){a={key:a[1],value:a[3]};t=this.getRealCurrentLineNb();d=new YamlParser(t);d.refs=this.refs;e=b.value;if(!this.isNextLineIndented()){e+="\n"+this.getNextEmbedBlock(this.getCurrentLineIndentation()+2)}u.push(d.parse(e));this.refs=d.refs}else{u.push(this.parseValue(b.value))}}}else{if(b=new RegExp("^("+YamlInline.REGEX_QUOTED_STRING+"|[^ '\"].*?) *:(\\s+(.+?))?\\s*$").exec(this.currentLine)){if(!this.isDefined(u)){u={}}if(u instanceof Array){throw new InvalidArgumentException("Non mapped entry at line "+(this.getRealCurrentLineNb()+1)+".")}b={key:b[1],value:b[3]};v=(new YamlInline()).parseScalar(b.key);if("<<"==v){if(this.isDefined(b.value)&&"*"==(b.value+"").charAt(0)){r=b.value.substring(1)}else{if(this.isDefined(b.value)&&b.value!=""){m=b.value}else{m=this.getNextEmbedBlock()}t=this.getRealCurrentLineNb()+1;d=new YamlParser(t);d.refs=this.refs;h=d.parse(m);this.refs=d.refs;var s=[];if(!this.isObject(h)){throw new InvalidArgumentException("YAML merge keys used with a scalar value instead of an array at line "+(this.getRealCurrentLineNb()+1)+" ("+this.currentLine+")")}else{if(this.isDefined(h[0])){f=this.reverseArray(h);p=f.length;for(var o=0;o<p;o++){var l=f[o];if(!this.isObject(f[o])){throw new InvalidArgumentException("Merge items must be arrays at line "+(this.getRealCurrentLineNb()+1)+" ("+f[o]+").")}s=this.mergeObject(f[o],s)}}else{s=this.mergeObject(s,h)}}q=s}}else{if(this.isDefined(b.value)&&(a=/^&([^ ]+) *(.*)/.exec(b.value))){a={ref:a[1],value:a[2]};j=a.ref;b.value=a.value}}if(q){u=q}else{if(!this.isDefined(b.value)||""==b.value.split(" ").join("")||this.trim(b.value).charAt(0)=="#"){if(this.isNextLineIndented()){u[v]=null}else{t=this.getRealCurrentLineNb()+1;d=new YamlParser(t);d.refs=this.refs;u[v]=d.parse(this.getNextEmbedBlock());this.refs=d.refs}}else{if(r){u=this.refs[r]}else{u[v]=this.parseValue(b.value)}}}}else{if(2==this.lines.length&&this.isEmpty(this.lines[1])){m=(new YamlInline()).load(this.lines[0]);if(this.isObject(m)){first=m[0];if("*"==(first+"").substr(0,1)){u=[];p=m.length;for(var o=0;o<p;o++){u.push(this.refs[m[o].substring(1)])}m=u}}return m}throw new InvalidArgumentException('"'+this.currentLine+'" at line '+(this.getRealCurrentLineNb()+1))}}if(j){if(u instanceof Array){this.refs[j]=u[u.length-1]}else{var g=null;for(var n in u){if(u.hasOwnProperty(n)){g=n}}this.refs[j]=u[n]}}}return this.isEmpty(u)?null:u},getRealCurrentLineNb:function(){return this.currentLineNb+this.offset},getCurrentLineIndentation:function(){return this.currentLine.length-this.currentLine.replace(/^ +/g,"").length},getNextEmbedBlock:function(d){this.moveToNextLine();var b=null;var a=null;if(!this.isDefined(d)){b=this.getCurrentLineIndentation();if(!this.isCurrentLineEmpty()&&0==b){throw new InvalidArgumentException("A Indentation problem at line "+(this.getRealCurrentLineNb()+1)+" ("+this.currentLine+")")}}else{b=d}var e=[this.currentLine.substring(b)];while(this.moveToNextLine()){if(this.isCurrentLineEmpty()){if(this.isCurrentLineBlank()){e.push(this.currentLine.substring(b))}continue}a=this.getCurrentLineIndentation();var c;if(c=/^( *)$/.exec(this.currentLine)){e.push(c[1])}else{if(a>=b){e.push(this.currentLine.substring(b))}else{if(0==a){this.moveToPreviousLine();break}else{throw new InvalidArgumentException("B Indentation problem at line "+(this.getRealCurrentLineNb()+1)+" ("+this.currentLine+")")}}}}return e.join("\n")},moveToNextLine:function(){if(this.currentLineNb>=this.lines.length-1){return false}this.currentLineNb++;this.currentLine=this.lines[this.currentLineNb];return true},moveToPreviousLine:function(){this.currentLineNb--;this.currentLine=this.lines[this.currentLineNb]},parseValue:function(c){if("*"==(c+"").charAt(0)){if(this.trim(c).charAt(0)=="#"){c=(c+"").substr(1,c.indexOf("#")-2)}else{c=(c+"").substring(1)}if(this.refs[c]==undefined){throw new InvalidArgumentException('Reference "'+c+'" does not exist ('+this.currentLine+").")}return this.refs[c]}var b=null;if(b=/^(\||>)(\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?( +#.*)?$/.exec(c)){b={separator:b[1],modifiers:b[2],comments:b[3]};var a=this.isDefined(b.modifiers)?b.modifiers:"";return this.parseFoldedScalar(b.separator,a.replace(/\d+/g,""),Math.abs(parseInt(a)))}else{return(new YamlInline()).load(c)}},parseFoldedScalar:function(c,h,f){if(h==undefined){h=""}if(f==undefined){f=0}c="|"==c?"\n":" ";var j="";var g=null;var b=this.moveToNextLine();while(b&&this.isCurrentLineBlank()){j+="\n";b=this.moveToNextLine()}if(!b){return""}var d=null;if(!(d=new RegExp("^("+(f?this.strRepeat(" ",f):" +")+")(.*)$").exec(this.currentLine))){this.moveToPreviousLine();return""}d={indent:d[1],text:d[2]};var a=d.indent;var e=0;j+=d.text+c;while(this.currentLineNb+1<this.lines.length){this.moveToNextLine();if(d=new RegExp("^( {"+a.length+",})(.+)$").exec(this.currentLine)){d={indent:d[1],text:d[2]};if(" "==c&&e!=d.indent){j=j.substr(0,j.length-1)+"\n"}e=d.indent;g=d.indent.length-a.length;j+=this.strRepeat(" ",g)+d.text+(g!=0?"\n":c)}else{if(d=/^( *)$/.exec(this.currentLine)){j+=d[1].replace(new RegExp("^ {1,"+a.length+"}","g"),"",d[1])+"\n"}else{this.moveToPreviousLine();break}}}if(" "==c){j=j.replace(/ (\n*)$/g,"\n$1")}switch(h){case"":j=j.replace(/\n+$/g,"\n");break;case"+":break;case"-":j=j.replace(/\n+$/g,"");break}return j},isNextLineIndented:function(){var b=this.getCurrentLineIndentation();var c=this.moveToNextLine();while(c&&this.isCurrentLineEmpty()){c=this.moveToNextLine()}if(false==c){return false}var a=false;if(this.getCurrentLineIndentation()<=b){a=true}this.moveToPreviousLine();return a},isCurrentLineEmpty:function(){return this.isCurrentLineBlank()||this.isCurrentLineComment()},isCurrentLineBlank:function(){return""==this.currentLine.split(" ").join("")},isCurrentLineComment:function(){var a=this.currentLine.replace(/^ +/g,"");return a.charAt(0)=="#"},cleanup:function(c){c=c.split("\r\n").join("\n").split("\r").join("\n");if(!/\n$/.test(c)){c+="\n"}var b=0;var a=/^\%YAML[: ][\d\.]+.*\n/;while(a.test(c)){c=c.replace(a,"");b++}this.offset+=b;a=/^(#.*?\n)+/;if(a.test(c)){trimmedValue=c.replace(a,"");this.offset+=this.subStrCount(c,"\n")-this.subStrCount(trimmedValue,"\n");c=trimmedValue}a=/^\-\-\-.*?\n/;if(a.test(c)){trimmedValue=c.replace(a,"");this.offset+=this.subStrCount(c,"\n")-this.subStrCount(trimmedValue,"\n");c=trimmedValue;c=c.replace(/\.\.\.\s*$/g,"")}return c},isObject:function(a){return typeof(a)=="object"&&this.isDefined(a)},isEmpty:function(a){return a==undefined||a==null||a==""||a==0||a=="0"||a==false},isDefined:function(a){return a!=undefined&&a!=null},reverseArray:function(c){var b=[];var a=c.length;for(var d=a-1;d>=0;d--){b.push(c[d])}return b},merge:function(e,d){var f={};for(i in e){if(/^\d+$/.test(i)){f.push(e)}else{f[i]=e[i]}}for(i in d){if(/^\d+$/.test(i)){f.push(d)}else{f[i]=d[i]}}return f},strRepeat:function(d,c){var b;var a="";for(b=0;b<c;b++){a+=d}return d},subStrCount:function(d,b,j,f){var h=0;d=""+d;b=""+b;if(j!=undefined){d=d.substr(j)}if(f!=undefined){d=d.substr(0,f)}var a=d.length;var g=b.length;for(var e=0;e<a;e++){if(b==d.substr(e,g)){h++}}return h},trim:function(a){return(a+"").replace(/^\s+/,"").replace(/\s+$/,"")}};YamlDumper=function(){};YamlDumper.prototype={dump:function(g,f,c){if(f==undefined){f=0}if(c==undefined){c=0}var b="";var e=c?this.strRepeat(" ",c):"";var i;if(f<=0||!this.isObject(g)||this.isEmpty(g)){i=new YamlInline();b+=e+i.dump(g)}else{var d=!this.arrayEquals(this.getKeys(g),this.range(0,g.length-1));var a;for(var h in g){if(g.hasOwnProperty(h)){a=f-1<=0||!this.isObject(g[h])||this.isEmpty(g[h]);if(d){i=new YamlInline()}b+=e+""+(d?i.dump(h)+":":"-")+""+(a?" ":"\n")+""+this.dump(g[h],f-1,(a?0:c+2))+""+(a?"\n":"")}}}return b},strRepeat:function(d,c){var b;var a="";for(b=0;b<c;b++){a+=d}return d},isObject:function(a){return typeof(a)=="object"&&this.isDefined(a)},isEmpty:function(a){return a==undefined||a==null||a==""||a==0||a=="0"||a==false},isDefined:function(a){return a!=undefined&&a!=null},getKeys:function(c){var b=[];for(var a in c){if(c.hasOwnProperty(a)){b.push(a)}}return b},range:function(d,a){if(d>a){return[]}var b=[];for(var c=d;c<=a;c++){b.push(c)}return b},arrayEquals:function(e,d){if(e.length!=d.length){return false}var c=e.length;for(var f=0;f<c;f++){if(e[f]!=d[f]){return false}}return true}};