Minor formatting and description fix

Minor formatting and description fix

Methods that extend the native Javascript String class

Here is the list of 'default' String global objects:
[Global_Objects/String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)

Note that there are more String Extension Methods (they exist inside their main dependency: crypto, path, fs)

methods

twin methods: add

@.**append** value

    String::append = (value)->
        @ + if value then value else ''

    String::add = String::append

@.**after** value

    String::after = (value)->
      if ((index = @.indexOf(    value)) == -1 )
        ''
      else
        @.substr(index + value.size())

@.**after_Last** value

    String::after_Last = (value)->
      if ((index = @.lastIndexOf(value)) == -1 )
        ''
      else
        @.substr(index + value.size())

@.**before** value

    String::before = (value)->
      @.substring(0,@.indexOf(value))

@.**before_Last** value

    String::before_Last = (value)->
      @.substring(0,@.lastIndexOf(value))

@.**contains** value

Checks that ```value``` is inside @.

If ```value``` is an Array, then all elements are expected to be found inside @

If ```value``` is an RegExp then checks if it matches @

    String::contains = (value)->
      if value instanceof RegExp
        regex = new RegExp(value)
        return regex.exec(@) isnt null
      if value instanceof Array
        for item in value
          if @.indexOf(item) is -1
            return false
        return true
      @.indexOf(value) > -1

@.**ends_With** value

    String::ends_With = (value)->
      if not value
        false
      else
        @.valueOf().slice(-value.length) is value

@.**is** value

Returns true if ```@``` is equal to ```value```

    String::is = (value)->
      @.valueOf() is value

@.**is_Not** value

Returns true if ```@``` is NOT equal to ```value```

twin methods: isnt

    String::is_Not = (value)->
      @.valueOf() isnt value

    String::isnt = String::is_Not

@.**lines**

returns @ split by '/n'

twin methods: split_Lines

    String::lines = ()->
      @.split(/\r\n|[\n\r\u0085\u2028\u2029]/g)

    String::split_Lines = String::lines

@.**lower**

returns @ in lowercase

    String::lower = ()->
      @.toLowerCase()

@.**not_Contains** value

    String::not_Contains  = (value)->
      @.indexOf(value) == -1

@.**only_Letters**

Returns a string where all chars that are not an letter (uppper or lower case) are replaced
with a - (dash)

The letters capitalization is not modified

    String::only_Letters =
      ()-> @.replace(/[^a-zA-Z]/gi, '-')

@.**only_Numbers**

Returns a string where all chars that are not an number are replaced
with a - (dash)

    String::only_Numbers = ()->
      @.replace(/[^0-9]/gi, '-').lower()

@.**remove** value

Removes all instances of **value**

Note: ```@.replace(value,'')``` doesn't work because it
only removes the first occurance

    String::remove = (value)->

      result = @
      while result.contains(value)
        result = result.replace(value,'')
      result

@.**repeat** value

Repeats @ ```value``` times

Note: the implementation uses a while loop in order to handle ok cases when
value is negative or weird

    String::repeat = (value)->
      result = ''
      if typeof(value) is 'number'
        while value > 0
          result += @
          value--
      return result

@.**size**

    String::size = ()->
      @.length

@.**starts_With** value

    String::starts_With = (value)->
      if not value
        false
      else
        @.valueOf().slice(0,value.length) is value

@.**to_Safe_String**

Returns a string where all chars that are dont match the regex are replaced
with a - (dash)

The current regex allows
- lowercase letters
- uppercase letters
- numbers
- the chars: , - _  (comma, dash and underscore)

The letters capitalization is modified, with the returned string being converted
into lowercase

    String::to_Safe_String = ()->
      @.replace(/[^a-zA-Z0-9.\-_]/gi, '-').lower()

@.**trim**

    String::trim = ()->
      @.replace(/^\s+|\s+$/g, '')

@.**twice**

    String::twice = ()->
      @ + @

@.**upper**

    String::upper = ()->
      @.toUpperCase()

@.**json_Parse**

returns the object representation of the the json string @

Note: if there is a prob parsing the json an empty object will be returned (use **json_Valid** to check for well formed json)

    String::json_Parse = ()->
      try
        JSON.parse(@)
      catch
        {}

@.**json_Valid**

Returns true if @ can be deserialised ok into a json object

    String::json_Valid = ()->
      try
        JSON.parse(@)
        true
      catch
        false

@.**is_Local_Url**

Returns a boolean indicating if the URL is local to Host or not. It helps to prevent Open redirects attacks. Backported from http://www.asp.net/mvc/overview/security/preventing-open-redirection-attacks

    String::is_Local_Url = ()->
      url = @.url_Decode()
      if(url? && url.length >0)
        return  (
                  (url[0] == '/' &&
                  (url.length == 1 ||(url[1] != '/' && url[1] != '\\'))) || # validates "/" or "/foo" but not "//" or "/\"
                  (url.length > 1 && url[0] == '~' && url[1] == '/')        # validates  "~/" or "~/foo"
                );
      else
        return false
---
back to [index](index.html)

Methods that extend the native Javascript String class

Here is the list of 'default' String global objects:
[Global_Objects/String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)

Note that there are more String Extension Methods (they exist inside their main dependency: crypto, path, fs)

methods

twin methods: add

@.**append** value

    String::append = (value)->
        @ + if value then value else ''

    String::add = String::append

@.**after** value

    String::after = (value)->
      if ((index = @.indexOf(    value)) == -1 )
        ''
      else
        @.substr(index + value.size())

@.**after_Last** value

    String::after_Last = (value)->
      if ((index = @.lastIndexOf(value)) == -1 )
        ''
      else
        @.substr(index + value.size())

@.**before** value

    String::before = (value)->
      @.substring(0,@.indexOf(value))

@.**before_Last** value

    String::before_Last = (value)->
      @.substring(0,@.lastIndexOf(value))

@.**contains** value

Checks that ```value``` is inside @.

If ```value``` is an Array, then all elements are expected to be found inside @

If ```value``` is an RegExp then checks if it matches @

    String::contains = (value)->
      if value instanceof RegExp
        regex = new RegExp(value)
        return regex.exec(@) isnt null
      if value instanceof Array
        for item in value
          if @.indexOf(item) is -1
            return false
        return true
      @.indexOf(value) > -1

@.**ends_With** value

    String::ends_With = (value)->
      if not value
        false
      else
        @.valueOf().slice(-value.length) is value

@.**is** value

Returns true if ```@``` is equal to ```value```

    String::is = (value)->
      @.valueOf() is value

@.**is_Not** value

Returns true if ```@``` is NOT equal to ```value```

twin methods: isnt

    String::is_Not = (value)->
      @.valueOf() isnt value

    String::isnt = String::is_Not

@.**lines**

returns @ split by '/n'

twin methods: split_Lines

    String::lines = ()->
      @.split(/\r\n|[\n\r\u0085\u2028\u2029]/g)

    String::split_Lines = String::lines

@.**lower**

returns @ in lowercase

    String::lower = ()->
      @.toLowerCase()

@.**not_Contains** value

    String::not_Contains  = (value)->
      @.indexOf(value) == -1

@.**only_Letters**

Returns a string where all chars that are not an letter (uppper or lower case) are replaced
with a - (dash)

The letters capitalization is not modified

    String::only_Letters =
      ()-> @.replace(/[^a-zA-Z]/gi, '-')

@.**only_Numbers**

Returns a string where all chars that are not an number are replaced
with a - (dash)

    String::only_Numbers = ()->
      @.replace(/[^0-9]/gi, '-').lower()

@.**remove** value

Removes all instances of **value**

Note: ```@.replace(value,'')``` doesn't work because it
only removes the first occurance

    String::remove = (value)->

      result = @
      while result.contains(value)
        result = result.replace(value,'')
      result

@.**repeat** value

Repeats @ ```value``` times

Note: the implementation uses a while loop in order to handle ok cases when
value is negative or weird

    String::repeat = (value)->
      result = ''
      if typeof(value) is 'number'
        while value > 0
          result += @
          value--
      return result

@.**size**

    String::size = ()->
      @.length

@.**starts_With** value

    String::starts_With = (value)->
      if not value
        false
      else
        @.valueOf().slice(0,value.length) is value

@.**to_Safe_String**

Returns a string where all chars that are dont match the regex are replaced
with a - (dash)

The current regex allows
- lowercase letters
- uppercase letters
- numbers
- the chars: , - _  (comma, dash and underscore)

The letters capitalization is modified, with the returned string being converted
into lowercase

    String::to_Safe_String = ()->
      @.replace(/[^a-zA-Z0-9.\-_]/gi, '-').lower()

@.**trim**

    String::trim = ()->
      @.replace(/^\s+|\s+$/g, '')

@.**twice**

    String::twice = ()->
      @ + @

@.**upper**

    String::upper = ()->
      @.toUpperCase()

@.**json_Parse**

returns the object representation of the the json string @

Note: if there is a prob parsing the json an empty object will be returned (use **json_Valid** to check for well formed json)

    String::json_Parse = ()->
      try
        JSON.parse(@)
      catch
        {}

@.**json_Valid**

Returns true if @ can be deserialised ok into a json object

    String::json_Valid = ()->
      try
        JSON.parse(@)
        true
      catch
        false

@.**isLocalUrl**

Returns a boolean indicating if the URL is local to Host or not. It helps to prevent Open redirects attacks. Back ported from http://www.asp.net/mvc/overview/security/preventing-open-redirection-attacks

    String::is_Local_Url = ()->
      url = @.url_Decode()
      if(url? && url.length >0)
        return  (
                  (url[0] == '/' &&
                  (url.length == 1 ||(url[1] != '/' && url[1] != '\\'))) || # validates "/" or "/foo" but not "//" or "/\"
                  (url.length > 1 && url[0] == '~' && url[1] == '/')        # validates  "~/" or "~/foo"
                );
      else
        return false
---
back to [index](index.html)


in. jokes

in. jokes

#! /usr/bin/env coffee

The expander supports multiple asyncronous functions that `appear = syncronous()`.

To achieve that it needed to do some peculiar things.

__Very peculiar!__

Things that [some](https://www.google.co.za/search?q=uptight+people&espv=2&biw=1063&bih=1058&source=lnms&tbm=isch&sa=X&ei=q6CJVYTyIpPB7Ab95YLQBA&ved=0CAYQ_AUoAQ#tbm=isch&q=uptight) may disaprove of.

Like wearing [spandex in public](https://www.google.co.za/search?q=spandex+in+public+nuts&espv=2&biw=1063&bih=1058&tbm=isch&source=lnms&sa=X&ei=5Z-JVez6KeWY7gbl_oCYAg&ved=0CAYQ_AUoAQ#tbm=isch&q=spandex+in+public).

It broke the [expan](https://github.com/nomilous/in./blob/master/lib/expander.js)sion (to be [eval](https://github.com/nomilous/in./blob/master/lib/compiler.js#L57)'d) [into pieces and substituted](https://www.google.co.za/search?q=into+pieces+and+substituted+an+array&es_sm=91&source=lnms&tbm=isch&sa=X&ei=laOJVbKFOqKM7Abs4Y_ACw&ved=0CAkQ_AUoAw&biw=1063&bih=1058#tbm=isch&q=into+pieces+and+substituted) an array ($e[n]) for each function's results.

Then pipelined the fuctions to produce ($e) so that the final eval

`{{ i for an.i in ( an = $e[0] ) }}`

Where `$e[0]` was originally `async(fn1)`

`{{ i for an.i in ( an = async(fn1) ) }}`

The results of the division are loaded into a variable called `spandex`...

Which happens to be in scope at eval.

    require('../')

    $$in (arg) ->

        ### in(arg).as {{1}}###

        console.log arg

#### Return and finish later - few bits still to wire together

#! /usr/bin/env coffee

The expander supports multiple asyncronous functions.

To achieve that it needed to do some peculiar things.

__Very peculiar!__

Things that [some](https://www.google.co.za/search?q=uptight+people&espv=2&biw=1063&bih=1058&source=lnms&tbm=isch&sa=X&ei=q6CJVYTyIpPB7Ab95YLQBA&ved=0CAYQ_AUoAQ#tbm=isch&q=uptight) may disaprove of.

Like wearing [spandex in public](https://www.google.co.za/search?q=spandex+in+public+nuts&espv=2&biw=1063&bih=1058&tbm=isch&source=lnms&sa=X&ei=5Z-JVez6KeWY7gbl_oCYAg&ved=0CAYQ_AUoAQ#tbm=isch&q=spandex+in+public).

It broke the [expan](https://github.com/nomilous/in./blob/master/lib/expander.js)sion (to be [eval](https://github.com/nomilous/in./blob/master/lib/compiler.js#L57)'d) [into pieces and substituted](https://www.google.co.za/search?q=into+pieces+and+substituted+an+array&es_sm=91&source=lnms&tbm=isch&sa=X&ei=laOJVbKFOqKM7Abs4Y_ACw&ved=0CAkQ_AUoAw&biw=1063&bih=1058#tbm=isch&q=into+pieces+and+substituted) an array ($e[n]) for each function's results.

Then pipelined the fuctions to produce ($e) so that the final eval

`{{ i for an.i in ( an = $e[0] ) }}`

Where `$e[0]` was originally `async(fn1)`

`{{ i for an.i in ( an = async(fn1) ) }}`

The results of the division are loaded into a variable called `spandex`...

Which happens to be in scope at eval.

    require('../')

    $$in (arg) ->

        ### in(arg).as {{1}}###

        console.log arg

#### Return and finish later - few bits still to wire together


Added an experimental invert function to the matrix module.

Matrices are arrays of 16 numbers forming a 4x4 matrix.

    temp1 = []
    temp2 = []
    rotationTemp = []
    tempVector = []
    tempVectorFrom = []
    tempVectorTo = []
    fromTemp = []
    toTemp = []
    tempVectorX = []
    tempVectorY = []
    tempVectorZ = []

    makeRotate = (axis1, axis2, axis3, axis4) ->
        temp3 = []
        rotationTemp.push temp3
        (radians, output) ->
            sin = Math.sin radians
            cos = Math.cos radians
            temp3[axis1] = cos
            temp3[axis2] = -sin
            temp3[axis3] = sin
            temp3[axis4] = cos
            module.exports.multiply output, temp3, output
            return

    vector = require "./vector.litcoffee"

    module.exports =

Given a matrix, calling the "identity" property writes the identity matrix to
it.

        identity: (output) ->
            for row in [0...4]
                for column in [0...4]
                    output[row * 4 + column] = if row is column then 1 else 0
            return

Given two matrices, calling the "copy" property copies every component from the
first to the second.

        copy: (input, output) ->
            output[index] = value for value, index in input
            return

Given three matrices, calling the "multiply" property multiplies the first two
together and writes the result to the third.

        multiply: (a, b, output) ->
            module.exports.copy a, temp1
            module.exports.copy b, temp2

            for row in [0...4]
                for column in [0...4]
                    temp = 0
                    for component in [0...4]
                        temp += temp1[component * 4 + column] * temp2[row * 4 + component]
                    output[row * 4 + column] = temp
            return

Given a number of radians and a matrix, calling the "rotateX" property modifies
the matrix to have been rotated by that number of radians about the X axis.

        rotateX: makeRotate 5, 6, 9, 10

Given a number of radians and a matrix, calling the "rotateY" property modifies
the matrix to have been rotated by that number of radians about the Y axis.

        rotateY: makeRotate 0, 2, 8, 10

Given a number of radians and a matrix, calling the "rotateZ" property modifies
the matrix to have been rotated by that number of radians about the Z axis.

        rotateZ: makeRotate 0, 1, 4, 5

Given a vector specifying the scaling factor on each axis and a matrix, calling
the "scale" property scales the matrix by those scaling factors.

        scale: (vector, output) ->
            output[index] *= vector[0] for index in [0...4]
            output[index] *= vector[1] for index in [4...8]
            output[index] *= vector[2] for index in [8...12]
            return

Given a vector specifying a translation and a matrix to translate, calling the
"translate" property applies that translation to that matrix.

        translate: (vector, output) ->
            output[3] += vector[0]
            output[7] += vector[1]
            output[11] += vector[2]
            return

Given a matrix, X, Y, Z and W values (defaulting to 0, 0, 0 and 1 respectively
if not given), calling the "apply" property returns an array of four numbers
representing the transformed vector.

        apply: (matrix, x, y, z, w) ->
            if x is undefined then x = 0
            if y is undefined then y = 0
            if z is undefined then z = 0
            if w is undefined then w = 1

            [
                x * matrix[0] + y * matrix[1] + z * matrix[2] + w * matrix[3]
                x * matrix[4] + y * matrix[5] + z * matrix[6] + w * matrix[7]
                x * matrix[8] + y * matrix[9] + z * matrix[10] + w * matrix[11]
                x * matrix[12] + y * matrix[13] + z * matrix[14] + w * matrix[15]
            ]

Given a matrix, input vector and output vector, calling the "applyToVector"
property writes the input vector transformed by the matrix to the output vector.

        applyToVector: (matrix, input, output) ->
            vector.copy input, tempVector
            output[0] = tempVector[0] * matrix[0] + tempVector[1] * matrix[1] + tempVector[2] * matrix[2] + matrix[3]
            output[1] = tempVector[0] * matrix[4] + tempVector[1] * matrix[5] + tempVector[2] * matrix[6] + matrix[7]
            output[2] = tempVector[0] * matrix[8] + tempVector[1] * matrix[9] + tempVector[2] * matrix[10] + matrix[11]
            return

Given a matrix and output vector, calling the "getTranslation" property writes
the translation applied by the matrix to the output vector.

        getTranslation: (matrix, output) ->
            output[0] = matrix[3]
            output[1] = matrix[7]
            output[2] = matrix[11]

Given a matrix and output vector, calling the "getX" property writes the vector
of the matrix's X axis (a scaled normal) to the output vector.

        getX: (matrix, output) ->
            output[0] = matrix[0]
            output[1] = matrix[4]
            output[2] = matrix[8]

Given a matrix and output vector, calling the "getY" property writes the vector
of the matrix's Y axis (a scaled normal) to the output vector.

        getY: (matrix, output) ->
            output[0] = matrix[1]
            output[1] = matrix[5]
            output[2] = matrix[9]

Given a matrix and output vector, calling the "getZ" property writes the vector
of the matrix's Z axis (a scaled normal) to the output vector.

        getZ: (matrix, output) ->
            output[0] = matrix[2]
            output[1] = matrix[6]
            output[2] = matrix[10]

# setTranslation

- A vector specifying the translation to set.
- A matrix to set the translation of.

Overwrites the translation of the matrix with the content of the given vector.

        setTranslation: (output, matrix) ->
            matrix[3] = output[0]
            matrix[7] = output[1]
            matrix[11] = output[2]

# setX

- A vector specifying the X axis vector to set.
- A matrix to set the X axis vector of.

Overwrites the X axis of the matrix with the content of the given vector.

        setX: (output, matrix) ->
            matrix[0] = output[0]
            matrix[4] = output[1]
            matrix[8] = output[2]

# setY

- A vector specifying the Y axis vector to set.
- A matrix to set the Y axis vector of.

Overwrites the Y axis of the matrix with the content of the given vector.

        setY: (output, matrix) ->
            matrix[1] = output[0]
            matrix[5] = output[1]
            matrix[9] = output[2]

# setZ

- A vector specifying the Z axis vector to set.
- A matrix to set the Z axis vector of.

Overwrites the Z axis of the matrix with the content of the given vector.

        setZ: (output, matrix) ->
            matrix[2] = output[0]
            matrix[6] = output[1]
            matrix[10] = output[2]

# interpolate

- An input matrix to interpolate from.
- An input matrix to interpolate to.
- A number specifying how far along to interpolate; "0" is "from" and "1" is
  "to".
- An output matrix.

Attempts to perform a somewhat crude interpolation between the two matrices
which is not very linear.  Good enough for smoothing over small changes.
Prioritizes the Z and Y axes over the X axis when ensuring orthogonal.

        interpolate: (from, to, alpha, output) ->
            module.exports.copy from, fromTemp
            module.exports.copy to, toTemp
            module.exports.identity output
            module.exports.getTranslation fromTemp, tempVectorFrom
            module.exports.getTranslation toTemp, tempVectorTo
            vector.interpolate tempVectorFrom, tempVectorTo, alpha, tempVector
            module.exports.setTranslation tempVector, output

            module.exports.getX fromTemp, tempVectorFrom
            module.exports.getX toTemp, tempVectorTo
            vector.interpolate tempVectorFrom, tempVectorTo, alpha, tempVector
            vector.normalize tempVector, tempVectorX, true

            module.exports.getY fromTemp, tempVectorFrom
            module.exports.getY toTemp, tempVectorTo
            vector.interpolate tempVectorFrom, tempVectorTo, alpha, tempVectorY

            vector.cross tempVectorX, tempVectorY, tempVectorZ
            vector.normalize tempVectorZ, tempVectorZ
            vector.cross tempVectorZ, tempVectorX, tempVectorY
            vector.normalize tempVectorY, tempVectorY

            module.exports.setX tempVectorX, output
            module.exports.setY tempVectorY, output
            module.exports.setZ tempVectorZ, output
            return

# invert

- An input matrix to invert.
- An output matrix to write to.

Attempts to calculate the inverse of a matrix by negating its translation and
transposing its X, Y and Z axes.  Will not work if any scaling has been applied.

        invert: (input, output) ->
            module.exports.copy input, fromTemp
            module.exports.getX fromTemp, tempVectorX
            module.exports.getY fromTemp, tempVectorY
            module.exports.getZ fromTemp, tempVectorZ
            module.exports.getTranslation fromTemp, tempVector
            output[0] = input[0]
            output[1] = input[4]
            output[2] = input[8]
            output[3] = -vector.dot tempVector, tempVectorX

            output[4] = input[1]
            output[5] = input[5]
            output[6] = input[9]
            output[7] = -vector.dot tempVector, tempVectorY

            output[8] = input[2]
            output[9] = input[6]
            output[10] = input[10]
            output[11] = -vector.dot tempVector, tempVectorZ

            output[12] = 0
            output[13] = 0
            output[14] = 0
            output[15] = 1

            return

    module.exports.identity temp1
    module.exports.identity temp2
    for mat in rotationTemp
        module.exports.identity mat

Matrices are arrays of 16 numbers forming a 4x4 matrix.

    temp1 = []
    temp2 = []
    rotationTemp = []
    tempVector = []
    tempVectorFrom = []
    tempVectorTo = []
    fromTemp = []
    toTemp = []
    tempVectorX = []
    tempVectorY = []
    tempVectorZ = []

    makeRotate = (axis1, axis2, axis3, axis4) ->
        temp3 = []
        rotationTemp.push temp3
        (radians, output) ->
            sin = Math.sin radians
            cos = Math.cos radians
            temp3[axis1] = cos
            temp3[axis2] = -sin
            temp3[axis3] = sin
            temp3[axis4] = cos
            module.exports.multiply output, temp3, output
            return

    vector = require "./vector.litcoffee"

    module.exports =

Given a matrix, calling the "identity" property writes the identity matrix to
it.

        identity: (output) ->
            for row in [0...4]
                for column in [0...4]
                    output[row * 4 + column] = if row is column then 1 else 0
            return

Given two matrices, calling the "copy" property copies every component from the
first to the second.

        copy: (input, output) ->
            output[index] = value for value, index in input
            return

Given three matrices, calling the "multiply" property multiplies the first two
together and writes the result to the third.

        multiply: (a, b, output) ->
            module.exports.copy a, temp1
            module.exports.copy b, temp2

            for row in [0...4]
                for column in [0...4]
                    temp = 0
                    for component in [0...4]
                        temp += temp1[component * 4 + column] * temp2[row * 4 + component]
                    output[row * 4 + column] = temp
            return

Given a number of radians and a matrix, calling the "rotateX" property modifies
the matrix to have been rotated by that number of radians about the X axis.

        rotateX: makeRotate 5, 6, 9, 10

Given a number of radians and a matrix, calling the "rotateY" property modifies
the matrix to have been rotated by that number of radians about the Y axis.

        rotateY: makeRotate 0, 2, 8, 10

Given a number of radians and a matrix, calling the "rotateZ" property modifies
the matrix to have been rotated by that number of radians about the Z axis.

        rotateZ: makeRotate 0, 1, 4, 5

Given a vector specifying the scaling factor on each axis and a matrix, calling
the "scale" property scales the matrix by those scaling factors.

        scale: (vector, output) ->
            output[index] *= vector[0] for index in [0...4]
            output[index] *= vector[1] for index in [4...8]
            output[index] *= vector[2] for index in [8...12]
            return

Given a vector specifying a translation and a matrix to translate, calling the
"translate" property applies that translation to that matrix.

        translate: (vector, output) ->
            output[3] += vector[0]
            output[7] += vector[1]
            output[11] += vector[2]
            return

Given a matrix, X, Y, Z and W values (defaulting to 0, 0, 0 and 1 respectively
if not given), calling the "apply" property returns an array of four numbers
representing the transformed vector.

        apply: (matrix, x, y, z, w) ->
            if x is undefined then x = 0
            if y is undefined then y = 0
            if z is undefined then z = 0
            if w is undefined then w = 1

            [
                x * matrix[0] + y * matrix[1] + z * matrix[2] + w * matrix[3]
                x * matrix[4] + y * matrix[5] + z * matrix[6] + w * matrix[7]
                x * matrix[8] + y * matrix[9] + z * matrix[10] + w * matrix[11]
                x * matrix[12] + y * matrix[13] + z * matrix[14] + w * matrix[15]
            ]

Given a matrix, input vector and output vector, calling the "applyToVector"
property writes the input vector transformed by the matrix to the output vector.

        applyToVector: (matrix, input, output) ->
            vector.copy input, tempVector
            output[0] = tempVector[0] * matrix[0] + tempVector[1] * matrix[1] + tempVector[2] * matrix[2] + matrix[3]
            output[1] = tempVector[0] * matrix[4] + tempVector[1] * matrix[5] + tempVector[2] * matrix[6] + matrix[7]
            output[2] = tempVector[0] * matrix[8] + tempVector[1] * matrix[9] + tempVector[2] * matrix[10] + matrix[11]
            return

Given a matrix and output vector, calling the "getTranslation" property writes
the translation applied by the matrix to the output vector.

        getTranslation: (matrix, output) ->
            output[0] = matrix[3]
            output[1] = matrix[7]
            output[2] = matrix[11]

Given a matrix and output vector, calling the "getX" property writes the vector
of the matrix's X axis (a scaled normal) to the output vector.

        getX: (matrix, output) ->
            output[0] = matrix[0]
            output[1] = matrix[4]
            output[2] = matrix[8]

Given a matrix and output vector, calling the "getY" property writes the vector
of the matrix's Y axis (a scaled normal) to the output vector.

        getY: (matrix, output) ->
            output[0] = matrix[1]
            output[1] = matrix[5]
            output[2] = matrix[9]

Given a matrix and output vector, calling the "getZ" property writes the vector
of the matrix's Z axis (a scaled normal) to the output vector.

        getZ: (matrix, output) ->
            output[0] = matrix[2]
            output[1] = matrix[6]
            output[2] = matrix[10]

# setTranslation

- A vector specifying the translation to set.
- A matrix to set the translation of.

Overwrites the translation of the matrix with the content of the given vector.

        setTranslation: (output, matrix) ->
            matrix[3] = output[0]
            matrix[7] = output[1]
            matrix[11] = output[2]

# setX

- A vector specifying the X axis vector to set.
- A matrix to set the X axis vector of.

Overwrites the X axis of the matrix with the content of the given vector.

        setX: (output, matrix) ->
            matrix[0] = output[0]
            matrix[4] = output[1]
            matrix[8] = output[2]

# setY

- A vector specifying the Y axis vector to set.
- A matrix to set the Y axis vector of.

Overwrites the Y axis of the matrix with the content of the given vector.

        setY: (output, matrix) ->
            matrix[1] = output[0]
            matrix[5] = output[1]
            matrix[9] = output[2]

# setZ

- A vector specifying the Z axis vector to set.
- A matrix to set the Z axis vector of.

Overwrites the Z axis of the matrix with the content of the given vector.

        setZ: (output, matrix) ->
            matrix[2] = output[0]
            matrix[6] = output[1]
            matrix[10] = output[2]

# interpolate

- An input matrix to interpolate from.
- An input matrix to interpolate to.
- A number specifying how far along to interpolate; "0" is "from" and "1" is
  "to".
- An output matrix.

Attempts to perform a somewhat crude interpolation between the two matrices
which is not very linear.  Good enough for smoothing over small changes.
Prioritizes the Z and Y axes over the X axis when ensuring orthogonal.

        interpolate: (from, to, alpha, output) ->
            module.exports.copy from, fromTemp
            module.exports.copy to, toTemp
            module.exports.identity output
            module.exports.getTranslation fromTemp, tempVectorFrom
            module.exports.getTranslation toTemp, tempVectorTo
            vector.interpolate tempVectorFrom, tempVectorTo, alpha, tempVector
            module.exports.setTranslation tempVector, output

            module.exports.getX fromTemp, tempVectorFrom
            module.exports.getX toTemp, tempVectorTo
            vector.interpolate tempVectorFrom, tempVectorTo, alpha, tempVector
            vector.normalize tempVector, tempVectorX, true

            module.exports.getY fromTemp, tempVectorFrom
            module.exports.getY toTemp, tempVectorTo
            vector.interpolate tempVectorFrom, tempVectorTo, alpha, tempVectorY

            vector.cross tempVectorX, tempVectorY, tempVectorZ
            vector.normalize tempVectorZ, tempVectorZ
            vector.cross tempVectorZ, tempVectorX, tempVectorY
            vector.normalize tempVectorY, tempVectorY

            module.exports.setX tempVectorX, output
            module.exports.setY tempVectorY, output
            module.exports.setZ tempVectorZ, output
            return

    module.exports.identity temp1
    module.exports.identity temp2
    for mat in rotationTemp
        module.exports.identity mat


Added a function for "flatten"ing vectors against surface normals.

# vector

Vectors are arrays of 3 numbers; X, Y and Z.
X runs from left to right.
Y runs from bottom to top.
Z runs from back to front.

When given as outputs, vectors can safely be empty arrays.

    misc = require "./misc.litcoffee"

## sum

- A vector.

Returns the sum of the components.

    sum = (vector) ->
        total = 0
        (total += component) for component in vector
        total

    unary = (callback) -> (input, output) ->
        (output[index] = callback value) for value, index in input
        return

## copy

- An input vector.
- An output vector.

Copies every component from the input to the output.

    copy = unary (component) -> component

## copy

- An input vector.
- An output vector.

Writes the negative of every component of the input to the output.

    negate = unary (component) -> -component

    binary = (callback) ->
        vector: (a, b, output) ->
            (output[index] = callback valueA, b[index]) for valueA, index in a
            return

        scalarBy: (a, b, output) ->
            (output[index] = callback a, valueB) for valueB, index in b
            return

        byScalar: (a, b, output) ->
            (output[index] = callback valueA, b) for valueA, index in a
            return

## add.vector

- An input vector.
- An input vector.
- An output vector.

Adds each component in the input vectors and writes the results to the output
vector.

## add.scalarBy

- A number.
- An input vector.
- An output vector.

Adds the number to each component in the vector and and writes the results to
the output vector.

## add.byScalar

- An input vector.
- A number.
- An output vector.

Adds each component in the vector to the number and writes the result to
the output vector.

    add = binary (a, b) -> a + b

## subtract.vector

- An input vector.
- An input vector.
- An output vector.

Subtracts each compenent in the second input vector from the equivalent in the
first input vector and writes the results to the output vector.

## subtract.scalarBy

- A number.
- An input vector.
- An output vector.

Subtracts each component in the vector from the number and writes the results to
the output vector.

## subtract.byScalar

- An input vector.
- A number.
- An output vector.

Subtracts the number from each component in the vector and writes the results to
the output vector.

    subtract = binary (a, b) -> a - b

## multiply.vector

- An input vector.
- An input vector.
- An output vector.

Multiplies each compenent in the second input vector with the equivalent in the
first input vector and writes the results to the output vector.

## multiply.scalarBy

- A number.
- An input vector.
- An output vector.

Multiplies the number by each component in the vector and writes the results to
the output vector.

## multiply.byScalar

- An input vector.
- A number.
- An output vector.

Multiplies each component in the vector by the number and writes the results to
the output vector.

    multiply = binary (a, b) -> a * b

## divide.vector

- An input vector.
- An input vector.
- An output vector.

Divides each compenent in the first input vector by the equivalent in the second
input vector and writes the results to the output vector.

## divide.scalarBy

- A number.
- An input vector.
- An output vector.

Divides the number by each component in the vector and writes the results to the
output vector.

## divide.byScalar

- An input vector.
- A number.
- An output vector.

Divides each component in the vector by the number and writes the results to the
output vector.

    divide = binary (a, b) -> a / b

# dot

- A vector.
- A vector.

Returns the dot product of the two vectors.

    tempA = []
    tempB = []
    dot = (a, b) ->
        multiply.vector a, b, tempA
        sum tempA

# magnitudeSquared

- A vector.

Returns the square of the magnitude/length of the vector.
Faster than "magnitude".

    magnitudeSquared = (v) -> dot v, v

# magnitude

- A vector.

Returns the magnitude/length of the vector.
Slower than "magnitudeSquared".

    magnitude = (v) -> Math.sqrt magnitudeSquared v

# distanceSquared

- A vector.
- A vector.

Returns the square of the distance between the two vectors.
Faster than "distance".

    distanceSquared = (a, b) ->
        subtract.vector a, b, tempB
        magnitudeSquared tempB

# distance

- A vector.
- A vector.

Returns the distance between the two vectors.
Slower than "distanceSquared".

    distance = (a, b) ->
        subtract.vector a, b, tempB
        magnitude tempB

# normalize

- An input vector.
- An output vector.

Writes the normalized/unit length version of the input vector to the output.
Returns the magnitude/length of the original vector.

    normalize = (input, output) ->
        len = magnitude input
        divide.byScalar input, len, output
        len

# cross

- An input vector.
- An input vector.
- An output vector.

Writes the cross product of the two input vectors to the output vector.

    cross = (a, b, output) ->
        copy a, tempA
        copy b, tempB
        output[0] = tempA[1] * tempB[2] - tempB[1] * tempA[2]
        output[1] = tempA[2] * tempB[0] - tempB[2] * tempA[0]
        output[2] = tempA[0] * tempB[1] - tempB[0] * tempA[1]
        return

# interpolate

- An input vector to interpolate from.
- An input vector to interpolate to.
- A number, where "0" is "from" and "1" is "to".
- An output vector.

Writes the linear interpolation between, or linear extrapolation beyond, the
two input vectors to the output.

    interpolate = (from, to, alpha, output) ->
        for fromValue, index in from
            toValue = to[index]
            output[index] = misc.interpolate fromValue, toValue, alpha
        return

# reflect

- An input vector.
- An input normal vector.
- An output vector.

Writes the reflection of the input vector against the surface normal specified
to the output vector.

    reflectTemp = []
    reflect = (input, normal, output) ->
        coefficient = dot input, normal
        multiply.byScalar normal, (coefficient * 2), reflectTemp
        subtract.vector input, reflectTemp, output

# flatten

- An input vector.
- An input normal vector.
- An output vector.

Writes the input vector to the output vector, but "flattened" along the surface
normal.  For instance, a vector pointing up and right with a normal facing right
would output a vector pointing only up.

    flattenTemp = []
    flatten = (input, normal, output) ->
        matched = dot input, normal
        multiply.byScalar normal, matched, flattenTemp
        subtract.vector input, flattenTemp, output

    module.exports = {
            sum, copy, negate
            add, subtract, multiply, divide
            dot, cross
            magnitudeSquared, magnitude
            distanceSquared, distance
            normalize
            interpolate
            reflect, flatten
        }

# vector

Vectors are arrays of 3 numbers; X, Y and Z.
X runs from left to right.
Y runs from bottom to top.
Z runs from back to front.

When given as outputs, vectors can safely be empty arrays.

    misc = require "./misc.litcoffee"

## sum

- A vector.

Returns the sum of the components.

    sum = (vector) ->
        total = 0
        (total += component) for component in vector
        total

    unary = (callback) -> (input, output) ->
        (output[index] = callback value) for value, index in input
        return

## copy

- An input vector.
- An output vector.

Copies every component from the input to the output.

    copy = unary (component) -> component

## copy

- An input vector.
- An output vector.

Writes the negative of every component of the input to the output.

    negate = unary (component) -> -component

    binary = (callback) ->
        vector: (a, b, output) ->
            (output[index] = callback valueA, b[index]) for valueA, index in a
            return

        scalarBy: (a, b, output) ->
            (output[index] = callback a, valueB) for valueB, index in b
            return

        byScalar: (a, b, output) ->
            (output[index] = callback valueA, b) for valueA, index in a
            return

## add.vector

- An input vector.
- An input vector.
- An output vector.

Adds each component in the input vectors and writes the results to the output
vector.

## add.scalarBy

- A number.
- An input vector.
- An output vector.

Adds the number to each component in the vector and and writes the results to
the output vector.

## add.byScalar

- An input vector.
- A number.
- An output vector.

Adds each component in the vector to the number and writes the result to
the output vector.

    add = binary (a, b) -> a + b

## subtract.vector

- An input vector.
- An input vector.
- An output vector.

Subtracts each compenent in the second input vector from the equivalent in the
first input vector and writes the results to the output vector.

## subtract.scalarBy

- A number.
- An input vector.
- An output vector.

Subtracts each component in the vector from the number and writes the results to
the output vector.

## subtract.byScalar

- An input vector.
- A number.
- An output vector.

Subtracts the number from each component in the vector and writes the results to
the output vector.

    subtract = binary (a, b) -> a - b

## multiply.vector

- An input vector.
- An input vector.
- An output vector.

Multiplies each compenent in the second input vector with the equivalent in the
first input vector and writes the results to the output vector.

## multiply.scalarBy

- A number.
- An input vector.
- An output vector.

Multiplies the number by each component in the vector and writes the results to
the output vector.

## multiply.byScalar

- An input vector.
- A number.
- An output vector.

Multiplies each component in the vector by the number and writes the results to
the output vector.

    multiply = binary (a, b) -> a * b

## divide.vector

- An input vector.
- An input vector.
- An output vector.

Divides each compenent in the first input vector by the equivalent in the second
input vector and writes the results to the output vector.

## divide.scalarBy

- A number.
- An input vector.
- An output vector.

Divides the number by each component in the vector and writes the results to the
output vector.

## divide.byScalar

- An input vector.
- A number.
- An output vector.

Divides each component in the vector by the number and writes the results to the
output vector.

    divide = binary (a, b) -> a / b

# dot

- A vector.
- A vector.

Returns the dot product of the two vectors.

    tempA = []
    tempB = []
    dot = (a, b) ->
        multiply.vector a, b, tempA
        sum tempA

# magnitudeSquared

- A vector.

Returns the square of the magnitude/length of the vector.
Faster than "magnitude".

    magnitudeSquared = (v) -> dot v, v

# magnitude

- A vector.

Returns the magnitude/length of the vector.
Slower than "magnitudeSquared".

    magnitude = (v) -> Math.sqrt magnitudeSquared v

# distanceSquared

- A vector.
- A vector.

Returns the square of the distance between the two vectors.
Faster than "distance".

    distanceSquared = (a, b) ->
        subtract.vector a, b, tempB
        magnitudeSquared tempB

# distance

- A vector.
- A vector.

Returns the distance between the two vectors.
Slower than "distanceSquared".

    distance = (a, b) ->
        subtract.vector a, b, tempB
        magnitude tempB

# normalize

- An input vector.
- An output vector.

Writes the normalized/unit length version of the input vector to the output.
Returns the magnitude/length of the original vector.

    normalize = (input, output) ->
        len = magnitude input
        divide.byScalar input, len, output
        len

# cross

- An input vector.
- An input vector.
- An output vector.

Writes the cross product of the two input vectors to the output vector.

    cross = (a, b, output) ->
        copy a, tempA
        copy b, tempB
        output[0] = tempA[1] * tempB[2] - tempB[1] * tempA[2]
        output[1] = tempA[2] * tempB[0] - tempB[2] * tempA[0]
        output[2] = tempA[0] * tempB[1] - tempB[0] * tempA[1]
        return

# interpolate

- An input vector to interpolate from.
- An input vector to interpolate to.
- A number, where "0" is "from" and "1" is "to".
- An output vector.

Writes the linear interpolation between, or linear extrapolation beyond, the
two input vectors to the output.

    interpolate = (from, to, alpha, output) ->
        for fromValue, index in from
            toValue = to[index]
            output[index] = misc.interpolate fromValue, toValue, alpha
        return

# reflect

- An input vector.
- An input normal vector.
- An output vector.

Writes the reflection of the input vector against the surface normal specified
to the output vector.

    reflectTemp = []
    reflect = (input, normal, output) ->
        coefficient = dot input, normal
        multiply.byScalar normal, (coefficient * 2), reflectTemp
        subtract.vector input, reflectTemp, output

    module.exports = {
            sum, copy, negate
            add, subtract, multiply, divide
            dot, cross
            magnitudeSquared, magnitude
            distanceSquared, distance
            normalize
            interpolate
            reflect
        }


FLAGS section

FLAGS section

# CLASS: Event
* Extends: [Base][Base]

Base event class. The design has been influenced by [DOM Events][DOMEvents].

      module.exports = class Event extends require './base'

The Event class does not have any methods that affect the state of the
system somehow (Besides the constructor and state setters). It was primarily
intended to serve as an envelope for the data.

## CONSTRUCTOR

### new Event(args, callback)
### new Event(type, callback)

* Returns: [Event][Event]

Create the event. All the key-value pairs from **args** will be copied
to the event instance. If **callback** is provided in the **args**, it
will override the **callback** provided as the second argument.

Upon instance creation, the event will log it's creation timestamp. This
can be disabled by passing `timestamp:null` to constructor.

Any Event instance at its minimum will have **timestamp** property. This
is the only mandatory property.

      constructor: (args = {}, callback) ->
        if typeof args is 'string' then args = type:args else
          if (arguments.length < 2) and typeof args is 'function'
            callback = args
            args = {}

        this[key] = value for key, value of args

        @callback = callback if callback and not @callback

        if (args.timestamp is true) or not args.hasOwnProperty 'timestamp'
          date = Date.now()
          perf = performance?.now() or 0
          @timestamp = 1000 * date + Math.floor 1000 * (perf - Math.floor perf)

### PARAMETERS
**args**
* Type: [Object][Object] - event data

**args.type**
* Type: [String][String] - event type

**args.callback**
* Type: [Function][Function] - event completion callback
* Optional
* Overrides the **callback** parameter

**args.timestamp**
* Type: [Boolean][Boolean] - set to `false` to disable the timestamp calculation
* Type: [Number][Number] - event timestamp

**type**
* Type: [String][String] - event type

**callback**
* Type: [Function][Function] - event completion callback
* Optional

---

## PROPERTIES

### #type
* Type: [String][String] - event type

### #phase
* Type: [Number][Number] - event phase (1..3)

### #timestamp
* Type: [Number][Number] - event creation timestamp

### #callback
* Type: [Function][Function] - event completion callback

---

## FLAGS

### #started
* Type: [Boolean][Boolean] - event **started** flag

### #stopped
* Type: [Boolean][Boolean] - event **stopped** flag

### #canceled
* Type: [Boolean][Boolean] - event **canceled** flag

### #aborted
* Type: [Boolean][Boolean] - event **aborted** flag

### #done
* Type: [Boolean][Boolean] - event **done** flag

---

## METHODS

### #start()
* Returns [Event][Event]

**started** flag setter

      start: -> (@started = yes) and this

---

### #stop()
* Returns [Event][Event]

**stopped** flag setter

      stop: -> (@stopped = yes) and this

---

### #cancel()
* Returns [Event][Event]

**canceled** flag setter

      cancel: -> (@canceled = yes) and this

---

### #abort()
* Returns [Event][Event]

**aborted** flag setter

      abort: -> (@aborted = yes) and this

---

### finish()
* Returns [Event][Event]

**done** flag setter

      finish: -> (@done = yes) and this

[Base]: ./base
[Event]: ./event
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
[String]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
[Function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
[Boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[Number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number

[DOMEvents]: http://www.w3.org/TR/DOM-Level-2-Events/events.html

# CLASS: Event
* Extends: [Base][Base]

Base event class. The design has been influenced by [DOM Events][DOMEvents].

      module.exports = class Event extends require './base'

The Event class does not have any methods that affect the state of the
system somehow (Besides the constructor and state setters). It was primarily
intended to serve as an envelope for the data.

## CONSTRUCTOR

### new Event(args, callback)
### new Event(type, callback)

* Returns: [Event][Event]

Create the event. All the key-value pairs from **args** will be copied
to the event instance. If **callback** is provided in the **args**, it
will override the **callback** provided as the second argument.

Upon instance creation, the event will log it's creation timestamp. This
can be disabled by passing `timestamp:null` to constructor.

Any Event instance at its minimum will have **timestamp** property. This
is the only mandatory property.

      constructor: (args = {}, callback) ->
        if typeof args is 'string' then args = type:args else
          if (arguments.length < 2) and typeof args is 'function'
            callback = args
            args = {}

        this[key] = value for key, value of args

        @callback = callback if callback and not @callback

        if (args.timestamp is true) or not args.hasOwnProperty 'timestamp'
          date = Date.now()
          perf = performance?.now() or 0
          @timestamp = 1000 * date + Math.floor 1000 * (perf - Math.floor perf)

### PARAMETERS
**args**
* Type: [Object][Object] - event data

**args.type**
* Type: [String][String] - event type

**args.callback**
* Type: [Function][Function] - event completion callback
* Optional
* Overrides the **callback** parameter

**args.timestamp**
* Type: [Boolean][Boolean] - set to `false` to disable the timestamp calculation
* Type: [Number][Number] - event timestamp

**type**
* Type: [String][String] - event type

**callback**
* Type: [Function][Function] - event completion callback
* Optional

---

## PROPERTIES

### #type
* Type: [String][String] - event type

### #timestamp
* Type: [Number][Number] - event creation timestamp

### #callback
* Type: [Function][Function] - event completion callback

### #started
* Type: [Boolean][Boolean] - event **started** flag

### #stopped
* Type: [Boolean][Boolean] - event **stopped** flag

### #canceled
* Type: [Boolean][Boolean] - event **canceled** flag

### #aborted
* Type: [Boolean][Boolean] - event **aborted** flag

### #done
* Type: [Boolean][Boolean] - event **done** flag

---
## METHODS

### #start()
* Returns [Event][Event]

**started** flag setter

      start: -> (@started = yes) and this

---
### #stop()
* Returns [Event][Event]

**stopped** flag setter

      stop: -> (@stopped = yes) and this

---
### #cancel()
* Returns [Event][Event]

**canceled** flag setter

      cancel: -> (@canceled = yes) and this

---
### #abort()
* Returns [Event][Event]

**aborted** flag setter

      abort: -> (@aborted = yes) and this

---
### finish()
* Returns [Event][Event]

**done** flag setter

      finish: -> (@done = yes) and this

[Base]: ./base
[Event]: ./event
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
[String]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
[Function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
[Boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[Number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number

[DOMEvents]: http://www.w3.org/TR/DOM-Level-2-Events/events.html


fix issue with binding on module schema without any data nodes

# Yang - evaluable schema expression

This module provides support for basic set of YANG schema modeling
language by using the built-in *extension* syntax to define additional
schema language constructs. The actual YANG language [RFC
6020](http://tools.ietf.org/html/rfc6020) specifications are loaded
inside the [main module](./main.coffee).

This module is the **primary interface** for consumers of this
library.

## Dependencies

    debug  = require('debug')('yang:schema')
    parser = require 'yang-parser'
    indent = require 'indent-string'

    Expression = require './expression'
    Extension = require './extension'
    XPath = require './xpath'

## Class Yang

    class Yang extends Expression
      @scope:
        extension: '0..n'
        typedef:   '0..n'
        module:    '0..n'
        submodule: '0..n'

## Class-level methods

      @clear: ->
        @module.splice(0,@module.length) if @module?
        @submodule.splice(0,@submodule.length) if @submodule?

### parse (schema)

This class-level routine performs recursive parsing of passed in
statement and sub-statements. It provides syntactic, semantic and
contextual validations on the provided schema and returns the final JS
object tree structure as hierarchical Yang expression instances.

If any validation errors are encountered, it will throw the
appropriate error along with the context information regarding the
error.

      @parse: (schema, opts={}) ->
        return schema if schema instanceof Yang
        opts.compile ?= true
        try
          schema = parser.parse schema if typeof schema is 'string'
        catch e
          e.offset = 50 unless e.offset > 50
          offender = schema.slice e.offset-50, e.offset+50
          offender = offender.replace /\s\s+/g, ' '
          throw @error "invalid YANG syntax detected around: '#{offender}'", offender

        unless schema instanceof Object
          throw @error "must pass in valid YANG schema", schema

        kind = switch
          when !!schema.prf then "#{schema.prf}:#{schema.kw}"
          else schema.kw
        tag = schema.arg unless schema.arg is false

        yang = (new this kind, tag).extends schema.substmts.map (x) => @parse x, compile: (x.kw is 'extension')

        # perform final scoped constraint validation
        for kind, constraint of yang.scope when constraint in [ '1', '1..n' ]
          unless yang.hasOwnProperty kind
            throw yang.error "constraint violation for required '#{kind}' = #{constraint}"
        yang.compile() if opts.compile
        return yang

For comprehensive overview on currently supported YANG statements,
please refer to
[Compliance Report](../test/yang-compliance-coverage.md) for the latest
[RFC 6020](http://tools.ietf.org/html/rfc6020) YANG specification
compliance.

### compose (data [, opts={}])

This call *accepts* any arbitrary JS object and it will attempt to
convert it into a structural `Yang` expression instance. It will
analyze the passed in JS data and perform best match mapping to an
appropriate YANG schema representation to describe the input
data. This method will not be able to determine conditionals or any
meta-data to further constrain the data, but it should provide a good
starting point with the resulting `Yang` expression instance.

      @compose: (data, opts={}) ->
        unless data?
          throw @error "must supply input 'data' to compose"

        # explict compose
        if opts.kind?
          ext = Yang::lookup.call this, 'extension', opts.kind
          unless ext instanceof Expression
            throw @error "unable to find requested '#{opts.kind}' extension"
          return ext.compose? data, opts

        # implicit compose (dynamic discovery)
        for ext in @extension when ext.compose instanceof Function
          debug "checking data if #{ext.tag}"
          res = ext.compose data, opts
          return res if res instanceof Yang

This facility is a powerful construct to dynamically generate `Yang`
schema from ordinary JS objects. For additional usage examples, please
refer to [Dynamic Composition](../TUTORIAL.md#dynamic-composition)
section in the [Getting Started Guide](../TUTORIAL.md).

## Main constructor

The constructor inherits from `Expression` which returns a `bound
function` that invokes [eval](#eval-data-opts) when called.

      @property 'source',
        get: ->
          @state.source ?= @lookup 'extension', @kind
          @state.source or {}
        set: (value) -> @state.source = value

      @property 'datakey',
        get: -> switch
          when @parent instanceof Yang and @parent.kind is 'module'
            "#{@parent.tag}:#{@tag}"
          when @parent instanceof Yang and @parent.kind is 'submodule'
            "#{@parent['belongs-to'].tag}:#{@tag}"
          when @node and @external and not @state.relative
            "#{@origin.root.tag}:#{@tag}"
          else @tag ? @kind

      @property 'external',
        get: -> @origin? and @origin.root isnt @root and @origin.root.kind is 'module'

      @property 'datapath',
        get: ->
          return '' if @kind is 'module'
          label = if @node then @datakey else "#{@kind}(#{@datakey})"
          return switch
            when @parent?.datapath? then [ @parent.datapath, label ].join('/')
            else label

      debug: -> debug "[#{@uri}]", arguments...
      emit: (event, args...) ->
        @emitter.emit arguments...
        @root.emit event, this if event is 'change' and this isnt @root

## Instance-level methods

### compile (obj)

      compile: ->
        unless @source instanceof Expression
          @debug @source
          throw @error "encountered unknown extension '#{@kind}'"
        super arguments...

### bind (obj)

Every instance of `Yang` expression can be *bound* with control logic
which will be used during [eval](#eval-data-opts) to produce schema
infused **adaptive data object**. This routine is *inherited* from
[Class Expression](./expression.coffee).

This facility can be used to associate default behaviors for any
element in the configuration tree, as well as handler logic for
various YANG statements such as *rpc*, *feature*, etc.

This call will return the original `Yang` expression instance with the
new bindings registered within the `Yang` expression hierarchy.

      bind: (data) ->
        if not @data and (@kind is 'module' or @nodes.length > 0) and typeof data is 'object'
          for key, binding of data
            try @locate(key).bind binding
            catch e
              throw e if e.name is 'ExpressionError'
              throw @error "failed to bind to '#{key}' (schema-path not found)", e
        else
          super data
        return this

Please refer to [Schema Binding](../TUTORIAL.md#schema-binding)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

### eval (data, opts={})

Every instance of `Yang` expression can be [eval](#eval-data-opts)
with arbitrary JS data input which will apply the schema against the
provided data and return a schema infused **adaptive** data object.

This is an extremely useful construct which brings out the true power
of YANG for defining and governing arbitrary JS data structures.

Basically, the input `data` will be YANG schema validated and
converted to a schema infused *adaptive data model* that dynamically
defines properties according to the schema expressions.

It currently supports the `opts.adaptive` parameter (default `false`)
which establishes a persistent binding relationship with the governing
`Yang` expression instance. This allows the generated model to
dynamically **adapt** to any changes to the governing `Yang`
expression instance. Refer to below [extends](#extends-schema) section
for additional info on how the schema can be programmatically
modified.

      eval: (data, ctx, opts={}) ->
        if opts.adaptive is true
          # TODO: this will break for 'module' which will return Model?
          @once 'change', arguments.callee.bind(this, data, opts)
        super arguments...

Please refer to [Working with Models](../TUTORIAL.md#working-with-models)
section of the [Getting Started Guide](../TUTORIAL.md) for special
usage examples for `module` schemas.

### override (callback)

Perform schema source extension override to dynamically alter the
handling/behavior of the current schema element.

      override: (callback) ->
        { argument, scope, resolve, transform, construct } = @source
        @source = new Extension @kind, Object.assign {
          argument, scope, resolve, transform, construct
        }, callback(@source)

### validate (data, opts={})

Perform schema correctness validation for the passed in `data`.  This
differs from [eval](#eval-data-opts) in that the final data returned
is not infused as dynamic data model using Property instances. It
should be used to perform a sanity check on the data if it will not
be programmatically modified.

For example, [Property](./property.litcoffee) instance uses `validate`
when dealing with non-configurable data nodes `config false`.

      validate: (data, opts={}) -> @apply data, null, Object.assign opts, force: true, preserve: true

### extends (schema...)

Every instance of `Yang` expression can be `extends` with additional
YANG schema string(s) and it will automatically perform
[parse](#parse-schema) of the provided schema text and update itself
accordingly.

This action also triggers an event emitter which will *retroactively*
adapt any previously [eval](#eval-data-opts) produced adaptive data
model instances to react accordingly to the newly changed underlying
schema expression(s).

      # extends() is inherited from Element

      merge: (elem) ->
        unless elem instanceof Yang
          throw @error "cannot merge invalid element into Yang", elem

        switch elem.kind
          when 'type'     then super elem, append: true
          when 'argument' then super elem, replace: true
          else super arguments...

Please refer to [Schema Extension](../TUTORIAL.md#schema-extension)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

      normalizePath: (ypath) ->
        lastPrefix = null
        prefix2module = (root, prefix) ->
          return unless root.kind is 'module'
          switch
            when root.tag is prefix then prefix
            when root.prefix.tag is prefix then root.tag
            else
              for m in root.import ? [] when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              modules = root.lookup 'module'
              for m in modules when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              return prefix # return as-is...

        normalizeEntry = (x) =>
          return x unless x? and !!x
          match = x.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)(?:\[.+\])?$/
          unless match?
            throw @error "invalid path expression '#{x}' found in #{ypath}"
          [ prefix, target ] = [ match[1], match[2] ]
          return switch
            when not prefix? then target
            when prefix is lastPrefix then target
            else
              lastPrefix = prefix
              mname = prefix2module @root, prefix
              "#{mname}:#{target}"
        ypath = ypath.replace /\s/g, ''
        res = XPath.split(ypath).map(normalizeEntry).join('/')
        res = '/' + res if /^\//.test ypath
        return res

### locate (ypath)

This is an internal helper facility used to locate a given schema node
within the `Yang` schema expression tree hierarchy. It supports a
limited version of XPATH-like expression to locate an explicit
element.

      locate: (ypath) ->
        # TODO: figure out how to eliminate duplicate code-block section
        # shared with Element
        return unless ypath?

        @debug "locate enter for '#{ypath}'"
        if typeof ypath is 'string'
          if (/^\//.test ypath) and this isnt @root
            return @root.locate ypath
          [ key, rest... ] = @normalizePath(ypath).split('/').filter (e) -> !!e
        else
          [ key, rest... ] = ypath
        @debug key
        return this unless key? and key isnt '.'

        if key is '..'
          return @parent?.locate rest

        match = key.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)$/
        [ prefix, target ] = [ match[1], match[2] ]
        if prefix? and this is @root
          search = [target].concat(rest)
          if (@tag is prefix) or (@lookup 'prefix', prefix)
            @debug "locate (local) '/#{prefix}:#{search.join('/')}'"
            return super search
          for m in @import ? [] when m.tag is prefix or m.prefix.tag is prefix
            @debug "locate (external) '/#{prefix}:#{search.join('/')}'"
            return m.module.locate search
          m = @lookup 'module', prefix
          return m?.locate search

        @debug "checking #{target}"
        switch
          when /^{.+}$/.test(target)
            kind = 'grouping'
            tag  = target.replace /^{(.+)}$/, '$1'
          when /^\[.+\]$/.test(target)
            kind = 'feature'
            tag  = target.replace /^\[(.+)\]$/, '$1'
          when /^[^(]+\([^)]*\)$/.test(target)
            target = target.match /^([^(]+)\((.*)\)$/
            [ kind, tag ] = [ target[1], target[2] ]
            tag = undefined unless !!tag
          when /^\<.+\>$/.test(target)
            target = target.replace /^\<(.+)\>$/, '$1'
            [ kind..., tag ]  = target.split ':'
            [ tag, selector ] = tag.split '='
            kind = kind[0] if kind?.length
          else return super [key].concat rest

        @debug "matching #{kind} #{tag}"
        match = @match kind, tag
        return switch
          when rest.length is 0 then match
          when Array.isArray match then match.map((x) -> x.locate rest).filter(Boolean)
          else match?.locate rest

### match (kind, tag)

This is an internal helper facility used by [locate](#locate-ypath) and
[lookup](./element.litcoffee#lookup-kind-tag) to test whether a given
entity exists in the local schema tree.

      # Yang Expression can support 'tag' with prefix to another module
      # (or itself).
      match: (kind, tag) ->
        return super arguments... unless kind? and tag? and typeof tag is 'string'
        res = super arguments...
        return res if res?

        [ prefix..., arg ] = tag.split ':'
        return unless prefix.length

        @debug "[match] with #{kind} #{tag}"

        prefix = prefix[0]
        @debug "[match] check if current module's prefix"
        if @root.tag is prefix or @root.prefix?.tag is prefix
          return @root.match kind, arg

        @debug "[match] checking if submodule's parent"
        ctx = @lookup 'belongs-to'
        if ctx?.prefix.tag is prefix
          return ctx.module?.match kind, arg

        @debug "[match] check if one of current module's imports"
        imports = @root?.import ? []
        for m in imports when m.prefix.tag is prefix
          @debug "[match] checking #{m.tag}"
          return m.module?.match kind, arg

        @debug "[match] check if one of available modules"
        module = @lookup 'module', prefix
        return module.match kind, arg if module?

### toString (opts={})

The current `Yang` expression will covert back to the equivalent YANG
schema text format.

At first glance, this may not seem like a useful facility since YANG
schema text is *generally known* before [parse](#parse-schema) but it
becomes highly relevant when you consider a given `Yang` expression
programatically changing via [extends](#extends-schema).

Currently it supports `space` parameter which can be used to specify
number of spaces to use for indenting YANG statement blocks.  It
defaults to **2** but when set to **0**, the generated output will
omit newlines and other spacing for a more compact YANG output.

      toString: (opts={ space: 2 }) ->
        s = @kind
        if @argument?
          s += ' ' + switch @argument
            when 'value' then switch
              when Array.isArray(@tag) then "'#{@tag.join(' ')}'"
              else "'#{@tag}'"
            when 'text'
              "\n" + (indent '"'+@tag+'"', ' ', opts.space)
            else @tag
        sub =
          @children
            .filter (x) => x.parent is this
            .map (x) -> x.toString opts
            .join "\n"
        if !!sub
          s += " {\n" + (indent sub, ' ', opts.space) + "\n}"
        else
          s += ';'
        return s

### toJSON

The current `Yang` expression will convert into a simple JS object
format.

      # toJSON() is inherited from Element

### valueOf

The current 'Yang' expression will convert into a primitive form for
comparision purposes.

      valueOf: ->
        switch @argument
          when 'value','text' then @tag.valueOf()
          else this

Please refer to [Schema Conversion](../TUTORIAL.md#schema-conversion)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

## Export Yang Class

    module.exports = Yang

# Yang - evaluable schema expression

This module provides support for basic set of YANG schema modeling
language by using the built-in *extension* syntax to define additional
schema language constructs. The actual YANG language [RFC
6020](http://tools.ietf.org/html/rfc6020) specifications are loaded
inside the [main module](./main.coffee).

This module is the **primary interface** for consumers of this
library.

## Dependencies

    debug  = require('debug')('yang:schema')
    parser = require 'yang-parser'
    indent = require 'indent-string'

    Expression = require './expression'
    Extension = require './extension'
    XPath = require './xpath'

## Class Yang

    class Yang extends Expression
      @scope:
        extension: '0..n'
        typedef:   '0..n'
        module:    '0..n'
        submodule: '0..n'

## Class-level methods

      @clear: ->
        @module.splice(0,@module.length) if @module?
        @submodule.splice(0,@submodule.length) if @submodule?

### parse (schema)

This class-level routine performs recursive parsing of passed in
statement and sub-statements. It provides syntactic, semantic and
contextual validations on the provided schema and returns the final JS
object tree structure as hierarchical Yang expression instances.

If any validation errors are encountered, it will throw the
appropriate error along with the context information regarding the
error.

      @parse: (schema, opts={}) ->
        return schema if schema instanceof Yang
        opts.compile ?= true
        try
          schema = parser.parse schema if typeof schema is 'string'
        catch e
          e.offset = 50 unless e.offset > 50
          offender = schema.slice e.offset-50, e.offset+50
          offender = offender.replace /\s\s+/g, ' '
          throw @error "invalid YANG syntax detected around: '#{offender}'", offender

        unless schema instanceof Object
          throw @error "must pass in valid YANG schema", schema

        kind = switch
          when !!schema.prf then "#{schema.prf}:#{schema.kw}"
          else schema.kw
        tag = schema.arg unless schema.arg is false

        yang = (new this kind, tag).extends schema.substmts.map (x) => @parse x, compile: (x.kw is 'extension')

        # perform final scoped constraint validation
        for kind, constraint of yang.scope when constraint in [ '1', '1..n' ]
          unless yang.hasOwnProperty kind
            throw yang.error "constraint violation for required '#{kind}' = #{constraint}"
        yang.compile() if opts.compile
        return yang

For comprehensive overview on currently supported YANG statements,
please refer to
[Compliance Report](../test/yang-compliance-coverage.md) for the latest
[RFC 6020](http://tools.ietf.org/html/rfc6020) YANG specification
compliance.

### compose (data [, opts={}])

This call *accepts* any arbitrary JS object and it will attempt to
convert it into a structural `Yang` expression instance. It will
analyze the passed in JS data and perform best match mapping to an
appropriate YANG schema representation to describe the input
data. This method will not be able to determine conditionals or any
meta-data to further constrain the data, but it should provide a good
starting point with the resulting `Yang` expression instance.

      @compose: (data, opts={}) ->
        unless data?
          throw @error "must supply input 'data' to compose"

        # explict compose
        if opts.kind?
          ext = Yang::lookup.call this, 'extension', opts.kind
          unless ext instanceof Expression
            throw @error "unable to find requested '#{opts.kind}' extension"
          return ext.compose? data, opts

        # implicit compose (dynamic discovery)
        for ext in @extension when ext.compose instanceof Function
          debug "checking data if #{ext.tag}"
          res = ext.compose data, opts
          return res if res instanceof Yang

This facility is a powerful construct to dynamically generate `Yang`
schema from ordinary JS objects. For additional usage examples, please
refer to [Dynamic Composition](../TUTORIAL.md#dynamic-composition)
section in the [Getting Started Guide](../TUTORIAL.md).

## Main constructor

The constructor inherits from `Expression` which returns a `bound
function` that invokes [eval](#eval-data-opts) when called.

      @property 'source',
        get: ->
          @state.source ?= @lookup 'extension', @kind
          @state.source or {}
        set: (value) -> @state.source = value

      @property 'datakey',
        get: -> switch
          when @parent instanceof Yang and @parent.kind is 'module'
            "#{@parent.tag}:#{@tag}"
          when @parent instanceof Yang and @parent.kind is 'submodule'
            "#{@parent['belongs-to'].tag}:#{@tag}"
          when @node and @external and not @state.relative
            "#{@origin.root.tag}:#{@tag}"
          else @tag ? @kind

      @property 'external',
        get: -> @origin? and @origin.root isnt @root and @origin.root.kind is 'module'

      @property 'datapath',
        get: ->
          return '' if @kind is 'module'
          label = if @node then @datakey else "#{@kind}(#{@datakey})"
          return switch
            when @parent?.datapath? then [ @parent.datapath, label ].join('/')
            else label

      debug: -> debug "[#{@uri}]", arguments...
      emit: (event, args...) ->
        @emitter.emit arguments...
        @root.emit event, this if event is 'change' and this isnt @root

## Instance-level methods

### compile (obj)

      compile: ->
        unless @source instanceof Expression
          @debug @source
          throw @error "encountered unknown extension '#{@kind}'"
        super arguments...

### bind (obj)

Every instance of `Yang` expression can be *bound* with control logic
which will be used during [eval](#eval-data-opts) to produce schema
infused **adaptive data object**. This routine is *inherited* from
[Class Expression](./expression.coffee).

This facility can be used to associate default behaviors for any
element in the configuration tree, as well as handler logic for
various YANG statements such as *rpc*, *feature*, etc.

This call will return the original `Yang` expression instance with the
new bindings registered within the `Yang` expression hierarchy.

      bind: (data) ->
        if not @data and @nodes.length > 0 and typeof data is 'object'
          for key, binding of data
            try @locate(key).bind binding
            catch e
              throw e if e.name is 'ExpressionError'
              throw @error "failed to bind to '#{key}' (schema-path not found)", e
        else
          super data
        return this

Please refer to [Schema Binding](../TUTORIAL.md#schema-binding)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

### eval (data, opts={})

Every instance of `Yang` expression can be [eval](#eval-data-opts)
with arbitrary JS data input which will apply the schema against the
provided data and return a schema infused **adaptive** data object.

This is an extremely useful construct which brings out the true power
of YANG for defining and governing arbitrary JS data structures.

Basically, the input `data` will be YANG schema validated and
converted to a schema infused *adaptive data model* that dynamically
defines properties according to the schema expressions.

It currently supports the `opts.adaptive` parameter (default `false`)
which establishes a persistent binding relationship with the governing
`Yang` expression instance. This allows the generated model to
dynamically **adapt** to any changes to the governing `Yang`
expression instance. Refer to below [extends](#extends-schema) section
for additional info on how the schema can be programmatically
modified.

      eval: (data, ctx, opts={}) ->
        if opts.adaptive is true
          # TODO: this will break for 'module' which will return Model?
          @once 'change', arguments.callee.bind(this, data, opts)
        super arguments...

Please refer to [Working with Models](../TUTORIAL.md#working-with-models)
section of the [Getting Started Guide](../TUTORIAL.md) for special
usage examples for `module` schemas.

### override (callback)

Perform schema source extension override to dynamically alter the
handling/behavior of the current schema element.

      override: (callback) ->
        { argument, scope, resolve, transform, construct } = @source
        @source = new Extension @kind, Object.assign {
          argument, scope, resolve, transform, construct
        }, callback(@source)

### validate (data, opts={})

Perform schema correctness validation for the passed in `data`.  This
differs from [eval](#eval-data-opts) in that the final data returned
is not infused as dynamic data model using Property instances. It
should be used to perform a sanity check on the data if it will not
be programmatically modified.

For example, [Property](./property.litcoffee) instance uses `validate`
when dealing with non-configurable data nodes `config false`.

      validate: (data, opts={}) -> @apply data, null, Object.assign opts, force: true, preserve: true

### extends (schema...)

Every instance of `Yang` expression can be `extends` with additional
YANG schema string(s) and it will automatically perform
[parse](#parse-schema) of the provided schema text and update itself
accordingly.

This action also triggers an event emitter which will *retroactively*
adapt any previously [eval](#eval-data-opts) produced adaptive data
model instances to react accordingly to the newly changed underlying
schema expression(s).

      # extends() is inherited from Element

      merge: (elem) ->
        unless elem instanceof Yang
          throw @error "cannot merge invalid element into Yang", elem

        switch elem.kind
          when 'type'     then super elem, append: true
          when 'argument' then super elem, replace: true
          else super arguments...

Please refer to [Schema Extension](../TUTORIAL.md#schema-extension)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

      normalizePath: (ypath) ->
        lastPrefix = null
        prefix2module = (root, prefix) ->
          return unless root.kind is 'module'
          switch
            when root.tag is prefix then prefix
            when root.prefix.tag is prefix then root.tag
            else
              for m in root.import ? [] when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              modules = root.lookup 'module'
              for m in modules when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              return prefix # return as-is...

        normalizeEntry = (x) =>
          return x unless x? and !!x
          match = x.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)(?:\[.+\])?$/
          unless match?
            throw @error "invalid path expression '#{x}' found in #{ypath}"
          [ prefix, target ] = [ match[1], match[2] ]
          return switch
            when not prefix? then target
            when prefix is lastPrefix then target
            else
              lastPrefix = prefix
              mname = prefix2module @root, prefix
              "#{mname}:#{target}"
        ypath = ypath.replace /\s/g, ''
        res = XPath.split(ypath).map(normalizeEntry).join('/')
        res = '/' + res if /^\//.test ypath
        return res

### locate (ypath)

This is an internal helper facility used to locate a given schema node
within the `Yang` schema expression tree hierarchy. It supports a
limited version of XPATH-like expression to locate an explicit
element.

      locate: (ypath) ->
        # TODO: figure out how to eliminate duplicate code-block section
        # shared with Element
        return unless ypath?

        @debug "locate enter for '#{ypath}'"
        if typeof ypath is 'string'
          if (/^\//.test ypath) and this isnt @root
            return @root.locate ypath
          [ key, rest... ] = @normalizePath(ypath).split('/').filter (e) -> !!e
        else
          [ key, rest... ] = ypath
        @debug key
        return this unless key? and key isnt '.'

        if key is '..'
          return @parent?.locate rest

        match = key.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)$/
        [ prefix, target ] = [ match[1], match[2] ]
        if prefix? and this is @root
          search = [target].concat(rest)
          if (@tag is prefix) or (@lookup 'prefix', prefix)
            @debug "locate (local) '/#{prefix}:#{search.join('/')}'"
            return super search
          for m in @import ? [] when m.tag is prefix or m.prefix.tag is prefix
            @debug "locate (external) '/#{prefix}:#{search.join('/')}'"
            return m.module.locate search
          m = @lookup 'module', prefix
          return m?.locate search

        @debug "checking #{target}"
        switch
          when /^{.+}$/.test(target)
            kind = 'grouping'
            tag  = target.replace /^{(.+)}$/, '$1'
          when /^\[.+\]$/.test(target)
            kind = 'feature'
            tag  = target.replace /^\[(.+)\]$/, '$1'
          when /^[^(]+\([^)]*\)$/.test(target)
            target = target.match /^([^(]+)\((.*)\)$/
            [ kind, tag ] = [ target[1], target[2] ]
            tag = undefined unless !!tag
          when /^\<.+\>$/.test(target)
            target = target.replace /^\<(.+)\>$/, '$1'
            [ kind..., tag ]  = target.split ':'
            [ tag, selector ] = tag.split '='
            kind = kind[0] if kind?.length
          else return super [key].concat rest

        @debug "matching #{kind} #{tag}"
        match = @match kind, tag
        return switch
          when rest.length is 0 then match
          when Array.isArray match then match.map((x) -> x.locate rest).filter(Boolean)
          else match?.locate rest

### match (kind, tag)

This is an internal helper facility used by [locate](#locate-ypath) and
[lookup](./element.litcoffee#lookup-kind-tag) to test whether a given
entity exists in the local schema tree.

      # Yang Expression can support 'tag' with prefix to another module
      # (or itself).
      match: (kind, tag) ->
        return super arguments... unless kind? and tag? and typeof tag is 'string'
        res = super arguments...
        return res if res?

        [ prefix..., arg ] = tag.split ':'
        return unless prefix.length

        @debug "[match] with #{kind} #{tag}"

        prefix = prefix[0]
        @debug "[match] check if current module's prefix"
        if @root.tag is prefix or @root.prefix?.tag is prefix
          return @root.match kind, arg

        @debug "[match] checking if submodule's parent"
        ctx = @lookup 'belongs-to'
        if ctx?.prefix.tag is prefix
          return ctx.module?.match kind, arg

        @debug "[match] check if one of current module's imports"
        imports = @root?.import ? []
        for m in imports when m.prefix.tag is prefix
          @debug "[match] checking #{m.tag}"
          return m.module?.match kind, arg

        @debug "[match] check if one of available modules"
        module = @lookup 'module', prefix
        return module.match kind, arg if module?

### toString (opts={})

The current `Yang` expression will covert back to the equivalent YANG
schema text format.

At first glance, this may not seem like a useful facility since YANG
schema text is *generally known* before [parse](#parse-schema) but it
becomes highly relevant when you consider a given `Yang` expression
programatically changing via [extends](#extends-schema).

Currently it supports `space` parameter which can be used to specify
number of spaces to use for indenting YANG statement blocks.  It
defaults to **2** but when set to **0**, the generated output will
omit newlines and other spacing for a more compact YANG output.

      toString: (opts={ space: 2 }) ->
        s = @kind
        if @argument?
          s += ' ' + switch @argument
            when 'value' then switch
              when Array.isArray(@tag) then "'#{@tag.join(' ')}'"
              else "'#{@tag}'"
            when 'text'
              "\n" + (indent '"'+@tag+'"', ' ', opts.space)
            else @tag
        sub =
          @children
            .filter (x) => x.parent is this
            .map (x) -> x.toString opts
            .join "\n"
        if !!sub
          s += " {\n" + (indent sub, ' ', opts.space) + "\n}"
        else
          s += ';'
        return s

### toJSON

The current `Yang` expression will convert into a simple JS object
format.

      # toJSON() is inherited from Element

### valueOf

The current 'Yang' expression will convert into a primitive form for
comparision purposes.

      valueOf: ->
        switch @argument
          when 'value','text' then @tag.valueOf()
          else this

Please refer to [Schema Conversion](../TUTORIAL.md#schema-conversion)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

## Export Yang Class

    module.exports = Yang