scratch

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 74  →  ?path2? @ 75
/bower_components/yaml.js/src/Dumper.coffee
@@ -0,0 +1,56 @@
 
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 input instanceof Date or Utils.isEmpty(input)
output += prefix + Inline.dump(input, exceptionOnInvalidType, objectEncoder)
else
if input instanceof Array
for value in input
willBeInlined = (inline - 1 <= 0 or typeof(value) isnt 'object' or Utils.isEmpty(value))
 
output +=
prefix +
'-' +
(if willBeInlined then ' ' else "\n") +
@dump(value, inline - 1, (if willBeInlined then 0 else indent + @indentation), exceptionOnInvalidType, objectEncoder) +
(if willBeInlined then "\n" else '')
 
else
for key, value of input
willBeInlined = (inline - 1 <= 0 or typeof(value) isnt 'object' or Utils.isEmpty(value))
 
output +=
prefix +
Inline.dump(key, exceptionOnInvalidType, objectEncoder) + ':' +
(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
/bower_components/yaml.js/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('|').split('\\').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) ->
result = @PATTERN_MAPPING_ESCAPEES.replace value, (str) =>
return @MAPPING_ESCAPEES_TO_ESCAPED[str]
return '"'+result+'"'
 
 
# 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(/'/g, "''")+"'"
 
 
module.exports = Escaper
/bower_components/yaml.js/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
/bower_components/yaml.js/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
/bower_components/yaml.js/src/Inline.coffee
@@ -0,0 +1,487 @@
 
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 String(parseInt(value)))
if Utils.isNumeric(value)
return (if type is 'string' then "'"+value+"'" else String(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 Escaper.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 String(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 String(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 date = Utils.stringToDate(scalar)
return date
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
/bower_components/yaml.js/src/Parser.coffee
@@ -0,0 +1,654 @@
 
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[String(i)] ?= value
else
# Merge objects
for key, value of refValue
data[key] ?= value
 
else
if values.value? and 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
k = String(i)
unless data.hasOwnProperty(k)
data[k] = value
else
# Merge objects
for key, value of parsedItem
unless data.hasOwnProperty(key)
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
unless data.hasOwnProperty(key)
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 Utils.ltrim(@currentLine).charAt(0) is '#'
# Don't add line with comments
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 = Utils.rtrim(newText, ' ') + line + "\n"
else
newText += line + ' '
text = newText
 
if '+' isnt indicator
# 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) ->
if value.indexOf("\r") isnt -1
value = value.split("\r\n").join("\n").split("\r").join("\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, ''
 
# Ensure the block is not indented
lines = value.split("\n")
smallestIndent = -1
for line in lines
continue if Utils.trim(line, ' ').length == 0
indent = line.length - Utils.ltrim(line).length
if smallestIndent is -1 or indent < smallestIndent
smallestIndent = indent
if smallestIndent > 0
for line, i in lines
lines[i] = line[smallestIndent..]
value = lines.join("\n")
 
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
/bower_components/yaml.js/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
 
/bower_components/yaml.js/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(/\'\'/g, '\'')
 
 
# 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
/bower_components/yaml.js/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' or (value instanceof Array and value.length 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 String(data)
 
else
# Sync
data = fs.readFileSync path
if data?
return String(data)
return null
 
 
 
module.exports = Utils
/bower_components/yaml.js/src/Yaml.coffee
@@ -0,0 +1,118 @@
 
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) =>
result = null
if input?
result = @parse input, exceptionOnInvalidType, objectDecoder
callback result
return
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
 
# Not in the browser?
unless window?
@YAML = Yaml
 
module.exports = Yaml