Reworked method wrapping decision logic

Reworked method wrapping decision logic

Method wrapping now has two phases:

1. Collect al methods to be wrapped - and the prototype they belong to.
2. Execute wrapping, starting at the base of the inheritence hierarchy.

Methods are collected for wrapping by walking up the prototype chain from
the leaf class. Methods are wrapped by walking down the prototype chain from
the base class.

Checks were also put in place to skip over dependencies that look like methods
that need wrapping.

    q     = require 'q'
    fs    = require 'fs'
    async = require 'async'
    uuid  = require 'uuid-1345'

    microtime = require 'microtime'

    EventEmitter2 = require('eventemitter2').EventEmitter2
    emitter       = new EventEmitter2 wildcard: true

    available   = { }
    initialized = { }
    listeners   = { }

    code_root = process.env.SEARCH_ROOT || 'dist'

    underscore = (value) -> value.replace /\W+/g, '_'
    strip      = (name)  -> name.toLowerCase().replace /\W+/g, ''

    SEARCH_ROOTS  = { }
    WRAPPED       = { }
    _INITIALIZERS = { }
    HYDRATED      = { }

    HYRDATION_LISTENERS = { }

    INITIALIZERS = (cls, method) ->
      _INITIALIZERS[cls] = [ ] unless _INITIALIZERS[cls]?

      _INITIALIZERS[cls].push fn: method, called: false

    WRAP = (cls, method) ->
      unless WRAPPED[cls]?
        WRAPPED[cls] = [
          'constructor'
          'initialize'
          'details'
        ]

      WRAPPED[cls].indexOf(method) < 0

    class Madul

      details: =>
        name  = @.__proto__.constructor.name
        props = for own key, val of @.__proto__
          if key != 'constructor' &&
             key != 'details'     &&
             key != 'initialize'  && ((
               key[0]            == '_' &&
               @.__proto__[key]? == false
             ) || key[0] != '_')

            if typeof val == 'function'
              value = val.constructor.name
            else if Array.isArray val
              value = for v in val
                if typeof v == 'function'
                  v.constructor.name
                else if typeof v == 'object'
                  v.constructor.name
                else
                  v
              value = value.join ','
            else if typeof val == 'object'
              value = val.constructor.name
            else
              value = val

            "#{key} => #{value}"

        "\n  #{name}\n    #{props.filter((e) -> e?).join '\n    '}"

      @LISTEN: (event, callback) => emitter.on event, callback

      @FIRE: (event, args) => emitter.emit event, args

      @SEARCH_ROOT: (mod, path) =>
        Madul.FIRE '$.Madul.search_root.register', "#{mod}": path

        SEARCH_ROOTS[mod] = path.substring 0, path.lastIndexOf '/'

      listen: (event, callback) ->
        Madul.LISTEN "*.#{@constructor.name}.#{event}", callback

      fire: (event, args) ->
        Madul.FIRE "@.#{@constructor.name}.#{event}", args

      warn: (event, details) ->
        Madul.FIRE "!.#{@constructor.name}.#{event}", details

      _report: (name, method, state, id, args) =>
        Madul.FIRE "@.#{name}.#{method}.#{state}",
          uuid:      id
          args:      args
          timestamp: microtime.now()

      _respond: (proto, method, id, deferred) =>
        (state, data) =>
          process.nextTick =>
            deferred[state] data

            proto._report proto.constructor.name, method, state, id, data

      _prep_invocation: (proto, method, input, def) =>
        id  = uuid.v4fast()
        res = proto._respond proto, method, id, def

        if Array.isArray input
          input.push (out) => res 'resolve', out
          input.push (err) => res 'reject',  err
          input.push (out) => res 'notify',  out
        else if typeof input == 'object'
          input.done   = (out) => res 'resolve', out
          input.fail   = (err) => res 'reject',  err
          input.update = (out) => res 'notify',  out

          input = [ input ]
        else
          msg = "input to #{proto.constructor.name}.#{method} must be an Array of Object"
          @warn 'input.invalid', msg
          throw new Error msg

        proto._report proto.constructor.name, method, 'invoke', id, input

        input

      _do_wrap: (proto, method) =>
        if method != 'fire' && method != 'warn' && method != 'listen'
          Madul.FIRE "$.#{proto.constructor.name}.#{method}.wrap"

          if typeof proto[method] == 'function'
            proto["_#{method}"] = proto[method]

            proto[method] = =>
              def  = q.defer()
              args = if arguments[0]? then Array.prototype.slice.call arguments else [ ]

              proto["_#{method}"].apply @, proto._prep_invocation proto, method, args, def

              def.promise
          else if typeof proto[method] == 'object'

            if Array.isArray proto[method].validate
              args_format = 'ARRAY'
              decs        = for val in proto[method].validate
                @_parse_handle(val).ref

              proto[method].validate = decs
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = for own key, val of proto[method].validate
                { ref } = @_parse_handle val
                proto[method].validate[key] = ref
                ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ @_parse_handle(proto[method].validate).ref ]
            else if typeof proto[method].validate != 'undefined'
              @warn 'meta.invalid', validate: 'must be a String, Object, or Array'
              return
            else
              args_format = 'ARRAY'
              decs        = [ ]

            decs = decs.concat(proto[method].before.map (b, i) =>
              { ref } = @_parse_handle b
              proto[method].before[i] = ref
              ref
            ) if proto[method].before?

            decs = decs.concat(proto[method].after.map (a, i) =>
              { ref } = @_parse_handle a
              proto[method].after[i] = ref
              ref
            ) if proto[method].after?

            Madul.FIRE '$.Madul.decorators.hydrate', decs

            @_do_hydrate proto, decs, =>
              proto["_#{method}"] = proto[method]

              proto[method] = =>
                def = q.defer()
                me  = proto["_#{method}"]

                if args_format == 'ARRAY'
                  args = Array.prototype.slice.call arguments

                  if me.validate?
                    validators = for val, i in me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[i]
                      proto[ref].EXECUTE args[i]
                else if args_format == 'OBJECT'
                  args = arguments[0]

                  if me.validate?
                    validators = for own key, val of me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[key]
                      proto[ref].EXECUTE args[key]
                else
                  @warn 'cannot-continue', 'No arg format specified'

                  return def.reject 'No arg format specified'

                me.before = [ ] unless me.before?
                me.after  = [ ] unless me.after?

                q.all validators
                .then =>
                  q.all me.before.map (b) =>
                    Madul.FIRE '$.Madul.before_filter.execute', "#{b}": args
                    proto[b].before args
                .then =>
                  me.behavior.apply @, @_prep_invocation proto, method, args, def
                .then (result) =>
                  if me.after.length > 0
                    q.all me.after.map (b) =>
                      Madul.FIRE '$.Madul.after_filter.execute', "#{b}": result
                      b.after result
                  else
                    d = q.defer()

                    process.nextTick => d.resolve result

                    d.promise
                .then  (out) => def.resolve out
                .catch (err) => def.reject  err

                def.promise
          else
            @warn 'cannot-wrap', method

          WRAPPED[proto.constructor.name].push method

      _wrap_methods: (proto, callback) =>
        name    = proto.constructor.name
        to_wrap = [ ]

        while proto? && Object.keys(proto).length > 0 && WRAPPED[name]? == false
          to_wrap.push { proto, name, methods: [ ] }

          for own prop, body of proto
            if prop[0]                  != '_'         &&
               typeof proto["_#{prop}"] == 'undefined' &&
               WRAP(name, prop)         == true

              continue if proto.deps? && proto.deps.indexOf(prop.replace(/_/g, '-')) > -1

              if typeof body == 'function' || typeof body?.behavior == 'function'
                to_wrap[to_wrap.length - 1].methods.push prop

          proto = proto.__proto__
          name  = proto.constructor.name

        async.each to_wrap.reverse(), (wrap, completed) =>
          async.each wrap.methods, (method, next) =>
            wrap.proto._do_wrap wrap.proto, method

            INITIALIZERS wrap.name, method if method[0] == '$'

            next()
          , => @_call_initializers_for wrap.proto, wrap.name, completed
        , callback

      _make_available: (name, mod) =>
        Madul.FIRE "$.#{name}.available"

        available[strip name] = mod

      _hydrate_deps: (done) =>
        proto  = @.__proto__
        protos = [ proto ]

        if proto.__proto__?
          while proto.__proto__? && Object.keys(proto.__proto__).length > 0
            protos.push proto = proto.__proto__

        async.each protos.reverse(), (p, next) =>
          name = p.constructor.name

          if p.hasOwnProperty 'deps'
            if HYDRATED[name] == undefined
              HYDRATED[name]            = false
              HYRDATION_LISTENERS[name] = [ next ]

              p._do_hydrate p, p.deps, =>
                HYDRATED[name] = true

                for listener in HYRDATION_LISTENERS[name]
                  listener()
            else if HYDRATED[name] == false
              HYRDATION_LISTENERS[name].push next
            else if HYDRATED[name] == true
              next()
          else
            next()
        , done

      _init_if_madul: (path, callback) =>
        mod      = require path
        proto    = mod
        is_madul = false

        while proto
          is_madul = true if proto.constructor.name == 'Madul'

          proto = proto.__super__

        if is_madul
          new mod()
            .initialize()
            .then callback
        else
          callback mod

      _load: (me, name, path, loaded) =>
        me._init_if_madul path, (mod) =>
          me._make_available name, mod
          loaded mod

      _check: (me, path, dep, ref, finished) =>
        fs.readdir path, (err, files) =>
          if err?
            me.warn 'file-not-found', err

            done type: 'ERROR', info: err
          else
            async.each files, (f, next) =>
              depth = "#{path}/#{f}"

              fs.stat depth, (e, s) =>
                if s.isDirectory() && f[0] != '.'
                  me._check me, depth, dep, ref, next
                else if s.isFile() && f.substring(0, f.length - 3) == dep
                  me._load me, ref, depth, (mod) => me._do_add me, mod, ref, next
                else
                  next()
            , finished

      _do_add: (me, mod, ref, next) =>
        Madul.FIRE "$.#{me.constructor.name}.dependency.register", ref

        me[underscore ref] = mod

        next()

      _add: (me, ref, path, next) =>
        me._init_if_madul path, (mod) =>
          me._make_available ref, mod
          me._do_add me, mod, ref, next

      _parse_handle: (value) =>
        tokens = value.split '='

        if tokens.length == 2
          initer = tokens[1].trim()
          t      = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = SEARCH_ROOTS[r[0].trim()]
            t[0] = r[1]

          if t.length == 2
            name  = t[0].trim()
            alias = t[1].trim()
          else if t.length == 1
            name = alias = t[0].trim()
          else
            return next @warn 'alias.invalid', tokens[1]

          toks = initer.split ':'

          if toks.length == 2
            initer = toks[0].trim()
            pres   = toks[1].split(',').map (p) => p.trim()
          else if toks.length == 1
            initer = toks[0].trim()
          else
            return next @warn 'dependency-initializer.invalid', tokens[1]

        else if tokens.length == 1
          t = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = SEARCH_ROOTS[r[0].trim()]
            t[0] = r[1]

          if t.length == 2
            name  = t[0].trim()
            alias = t[1].trim()
          else if t.length == 1
            name = alias = t[0].trim()
          else
            return next @warn 'alias.invalid', tokens[1]

        else
          return next @warn 'dependency.invalid', d

        { ref: alias || name, alias, name, root, initer, pres }

      _do_hydrate: (proto, deps, hydration_complete) =>
        initers = [ ]

        async.each deps, (d, next) =>
          { ref, alias, name, root, initer, pres } = @_parse_handle d

          if pres?
            insert_at = for p in pres
              index_for = (sibling) => sibling.alias == p.alias

              initers.find index_for

            insert_at.sort()

            insert_at = if insert_at.length == 0 then 0 else insert_at[insert_at.length - 1]

            initers.splice insert_at, 0, alias: alias, execute: initer

          if proto[underscore ref]? == false
            if available[strip ref]? == true
              proto._do_add proto, available[strip ref], ref, next
            else
              try
                proto._add proto, ref, name, next
              catch e
                if root?
                  Madul.FIRE '$.Madul.search_root.load', { name, alias, root }

                  proto._check proto, root, name, ref, next
                else
                  cwd = process.cwd()
                  pkg = "#{cwd}/node_modules/#{name}/package.json"

                  fs.stat pkg, (err, stat) =>
                    if stat?.isFile()
                      fs.readFile pkg, 'utf8', (err, data) =>
                        json = JSON.parse data
                        main = json.main || json._main || 'index.js'
                        path = "#{cwd}/node_modules/#{name}/#{main}"

                        proto._add proto, ref, path, next
                    else
                      proto._check proto, "#{cwd}/#{code_root}", name, ref, next
          else
            next()
        , =>
          async.eachSeries initers, (initer, next) =>
            @[initer.execute]().then next
          , hydration_complete

      _finish_up: (proto, args) =>
        name = proto.constructor.name

        @_call_initializers_for name, =>
          if listeners[name]?
            async.each listeners[name], (listener, next) =>
              listener @
              next()
            , => @_register_initialized name
          else
            @_register_initialized name

      _register_initialized: (name) =>
        @_make_available name, @

        initialized[name] = true

        Madul.FIRE "$.#{name}.initialized"

      _call_initializers_for: (name, callback) =>
        if _INITIALIZERS[name]?
          async.each _INITIALIZERS[name], (initializer, next) =>
            if initializer.called == false
              @[initializer.fn]()
                .then =>
                  initializer.called = true
                  next()
            else
              next()
          , callback
        else
          callback()

      _invoke_parent_initializers: (callback) =>
        proto = @.__proto__

        if proto.__proto__?
          parents = while proto.__proto__? && Object.keys(proto.__proto__).length > 0
            proto = proto.__proto__

          async.each parents, (parent, next) =>
            @_call_initializers_for parent.constructor.name, next
          , callback
        else
          callback()

      initialize: =>
        deferred = q.defer()
        proto    = @.__proto__
        name     = proto.constructor.name

        Madul.FIRE "$.#{name}.request_instance"

        if initialized[name] == undefined
          Madul.FIRE "$.#{name}.initialize"

          initialized[name] = false
          listeners[name]   = [ deferred.resolve ]

          @_wrap_methods()
          @_hydrate_deps => @_invoke_parent_initializers => @_finish_up proto
        else if initialized[name] == false
          listeners[name].push deferred.resolve
        else if initialized[name] == true
          process.nextTick => deferred.resolve available[strip name]

        deferred.promise

    module.exports = Madul

    q     = require 'q'
    fs    = require 'fs'
    async = require 'async'
    uuid  = require 'uuid-1345'

    microtime = require 'microtime'

    EventEmitter2 = require('eventemitter2').EventEmitter2
    emitter       = new EventEmitter2 wildcard: true

    available   = { }
    initialized = { }
    listeners   = { }

    code_root = process.env.SEARCH_ROOT || 'dist'

    underscore = (value) -> value.replace /\W+/g, '_'
    strip      = (name)  -> name.toLowerCase().replace /\W+/g, ''

    SEARCH_ROOTS  = { }
    WRAPPED       = { }
    _INITIALIZERS = { }
    HYDRATED      = { }

    HYRDATION_LISTENERS = { }

    INITIALIZERS = (cls, method) ->
      _INITIALIZERS[cls] = [ ] unless _INITIALIZERS[cls]?

      _INITIALIZERS[cls].push fn: method, called: false

    WRAP = (cls, method) ->
      unless WRAPPED[cls]?
        WRAPPED[cls] = [
          'constructor'
          'initialize'
          'details'
        ]

      WRAPPED[cls].indexOf(method) < 0

    class Madul

      details: =>
        name  = @.__proto__.constructor.name
        props = for own key, val of @.__proto__
          if key != 'constructor' &&
             key != 'details'     &&
             key != 'initialize'  && ((
               key[0]            == '_' &&
               @.__proto__[key]? == false
             ) || key[0] != '_')

            if typeof val == 'function'
              value = val.constructor.name
            else if Array.isArray val
              value = for v in val
                if typeof v == 'function'
                  v.constructor.name
                else if typeof v == 'object'
                  v.constructor.name
                else
                  v
              value = value.join ','
            else if typeof val == 'object'
              value = val.constructor.name
            else
              value = val

            "#{key} => #{value}"

        "\n  #{name}\n    #{props.filter((e) -> e?).join '\n    '}"

      @LISTEN: (event, callback) => emitter.on event, callback

      @FIRE: (event, args) => emitter.emit event, args

      @SEARCH_ROOT: (mod, path) =>
        Madul.FIRE '$.Madul.search_root.register', "#{mod}": path

        SEARCH_ROOTS[mod] = path.substring 0, path.lastIndexOf '/'

      listen: (event, callback) ->
        Madul.LISTEN "*.#{@constructor.name}.#{event}", callback

      fire: (event, args) ->
        Madul.FIRE "@.#{@constructor.name}.#{event}", args

      warn: (event, details) ->
        Madul.FIRE "!.#{@constructor.name}.#{event}", details

      _report: (name, method, state, id, args) =>
        Madul.FIRE "@.#{name}.#{method}.#{state}",
          uuid:      id
          args:      args
          timestamp: microtime.now()

      _respond: (proto, method, id, deferred) =>
        (state, data) =>
          process.nextTick =>
            deferred[state] data

            proto._report proto.constructor.name, method, state, id, data

      _prep_invocation: (proto, method, input, def) =>
        id  = uuid.v4fast()
        res = proto._respond proto, method, id, def

        if Array.isArray input
          input.push (out) => res 'resolve', out
          input.push (err) => res 'reject',  err
          input.push (out) => res 'notify',  out
        else if typeof input == 'object'
          input.done   = (out) => res 'resolve', out
          input.fail   = (err) => res 'reject',  err
          input.update = (out) => res 'notify',  out

          input = [ input ]
        else
          msg = "input to #{proto.constructor.name}.#{method} must be an Array of Object"
          @warn 'input.invalid', msg
          throw new Error msg

        proto._report proto.constructor.name, method, 'invoke', id, input

        input

      _do_wrap: (proto, method) =>
        if method != 'fire' && method != 'warn' && method != 'listen'
          Madul.FIRE "$.#{proto.constructor.name}.#{method}.wrap"

          if typeof proto[method] == 'function'
            proto["_#{method}"] = proto[method]

            proto[method] = =>
              def  = q.defer()
              args = if arguments[0]? then Array.prototype.slice.call arguments else [ ]

              proto["_#{method}"].apply @, proto._prep_invocation proto, method, args, def

              def.promise
          else if typeof proto[method] == 'object'

            if Array.isArray proto[method].validate
              args_format = 'ARRAY'
              decs        = for val in proto[method].validate
                @_parse_handle(val).ref

              proto[method].validate = decs
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = for own key, val of proto[method].validate
                { ref } = @_parse_handle val
                proto[method].validate[key] = ref
                ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ @_parse_handle(proto[method].validate).ref ]
            else if typeof proto[method].validate != 'undefined'
              @warn 'meta.invalid', validate: 'must be a String, Object, or Array'
              return
            else
              args_format = 'ARRAY'
              decs        = [ ]

            decs = decs.concat(proto[method].before.map (b, i) =>
              { ref } = @_parse_handle b
              proto[method].before[i] = ref
              ref
            ) if proto[method].before?

            decs = decs.concat(proto[method].after.map (a, i) =>
              { ref } = @_parse_handle a
              proto[method].after[i] = ref
              ref
            ) if proto[method].after?

            Madul.FIRE '$.Madul.decorators.hydrate', decs

            @_do_hydrate proto, decs, =>
              proto["_#{method}"] = proto[method]

              proto[method] = =>
                def = q.defer()
                me  = proto["_#{method}"]

                if args_format == 'ARRAY'
                  args = Array.prototype.slice.call arguments

                  if me.validate?
                    validators = for val, i in me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[i]
                      proto[ref].EXECUTE args[i]
                else if args_format == 'OBJECT'
                  args = arguments[0]

                  if me.validate?
                    validators = for own key, val of me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[key]
                      proto[ref].EXECUTE args[key]
                else
                  @warn 'cannot-continue', 'No arg format specified'

                  return def.reject 'No arg format specified'

                me.before = [ ] unless me.before?
                me.after  = [ ] unless me.after?

                q.all validators
                .then =>
                  q.all me.before.map (b) =>
                    Madul.FIRE '$.Madul.before_filter.execute', "#{b}": args
                    proto[b].before args
                .then =>
                  me.behavior.apply @, @_prep_invocation proto, method, args, def
                .then (result) =>
                  if me.after.length > 0
                    q.all me.after.map (b) =>
                      Madul.FIRE '$.Madul.after_filter.execute', "#{b}": result
                      b.after result
                  else
                    d = q.defer()

                    process.nextTick => d.resolve result

                    d.promise
                .then  (out) => def.resolve out
                .catch (err) => def.reject  err

                def.promise
          else
            @warn 'cannot-wrap', method

          WRAPPED[proto.constructor.name].push method

      _wrap_methods: =>
        proto = @.__proto__
        name  = proto.constructor.name

        while proto? && Object.keys(proto).length > 0 && WRAPPED[name]? == false
          for prop, body of proto
            if prop[0]                  != '_'         &&
               typeof proto["_#{prop}"] == 'undefined' &&
               WRAP(name, prop)         == true

              if typeof body == 'function' || typeof body.behavior == 'function'
                proto._do_wrap proto, prop

                INITIALIZERS name, prop if prop[0] == '$'

          proto = proto.__proto__

      _make_available: (name, mod) =>
        Madul.FIRE "$.#{name}.available"

        available[strip name] = mod

      _hydrate_deps: (done) =>
        proto  = @.__proto__
        protos = [ proto ]

        if proto.__proto__?
          while proto.__proto__? && Object.keys(proto.__proto__).length > 0
            protos.push proto = proto.__proto__

        async.each protos.reverse(), (p, next) =>
          name = p.constructor.name

          if p.hasOwnProperty 'deps'
            if HYDRATED[name] == undefined
              HYDRATED[name]            = false
              HYRDATION_LISTENERS[name] = [ next ]

              p._do_hydrate p, p.deps, =>
                HYDRATED[name] = true

                for listener in HYRDATION_LISTENERS[name]
                  listener()
            else if HYDRATED[name] == false
              HYRDATION_LISTENERS[name].push next
            else if HYDRATED[name] == true
              next()
          else
            next()
        , done

      _init_if_madul: (path, callback) =>
        mod      = require path
        proto    = mod
        is_madul = false

        while proto
          is_madul = true if proto.constructor.name == 'Madul'

          proto = proto.__super__

        if is_madul
          new mod()
            .initialize()
            .then callback
        else
          callback mod

      _load: (me, name, path, loaded) =>
        me._init_if_madul path, (mod) =>
          me._make_available name, mod
          loaded mod

      _check: (me, path, dep, ref, finished) =>
        fs.readdir path, (err, files) =>
          if err?
            me.warn 'file-not-found', err

            done type: 'ERROR', info: err
          else
            async.each files, (f, next) =>
              depth = "#{path}/#{f}"

              fs.stat depth, (e, s) =>
                if s.isDirectory() && f[0] != '.'
                  me._check me, depth, dep, ref, next
                else if s.isFile() && f.substring(0, f.length - 3) == dep
                  me._load me, ref, depth, (mod) => me._do_add me, mod, ref, next
                else
                  next()
            , finished

      _do_add: (me, mod, ref, next) =>
        Madul.FIRE "$.#{me.constructor.name}.dependency.register", ref

        me[underscore ref] = mod

        next()

      _add: (me, ref, path, next) =>
        me._init_if_madul path, (mod) =>
          me._make_available ref, mod
          me._do_add me, mod, ref, next

      _parse_handle: (value) =>
        tokens = value.split '='

        if tokens.length == 2
          initer = tokens[1].trim()
          t      = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = SEARCH_ROOTS[r[0].trim()]
            t[0] = r[1]

          if t.length == 2
            name  = t[0].trim()
            alias = t[1].trim()
          else if t.length == 1
            name = alias = t[0].trim()
          else
            return next @warn 'alias.invalid', tokens[1]

          toks = initer.split ':'

          if toks.length == 2
            initer = toks[0].trim()
            pres   = toks[1].split(',').map (p) => p.trim()
          else if toks.length == 1
            initer = toks[0].trim()
          else
            return next @warn 'dependency-initializer.invalid', tokens[1]

        else if tokens.length == 1
          t = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = SEARCH_ROOTS[r[0].trim()]
            t[0] = r[1]

          if t.length == 2
            name  = t[0].trim()
            alias = t[1].trim()
          else if t.length == 1
            name = alias = t[0].trim()
          else
            return next @warn 'alias.invalid', tokens[1]

        else
          return next @warn 'dependency.invalid', d

        { ref: alias || name, alias, name, root, initer, pres }

      _do_hydrate: (proto, deps, hydration_complete) =>
        initers = [ ]

        async.each deps, (d, next) =>
          { ref, alias, name, root, initer, pres } = @_parse_handle d

          if pres?
            insert_at = for p in pres
              index_for = (sibling) => sibling.alias == p.alias

              initers.find index_for

            insert_at.sort()

            insert_at = if insert_at.length == 0 then 0 else insert_at[insert_at.length - 1]

            initers.splice insert_at, 0, alias: alias, execute: initer

          if proto[underscore ref]? == false
            if available[strip ref]? == true
              proto._do_add proto, available[strip ref], ref, next
            else
              try
                proto._add proto, ref, name, next
              catch e
                if root?
                  Madul.FIRE '$.Madul.search_root.load', { name, alias, root }

                  proto._check proto, root, name, ref, next
                else
                  cwd = process.cwd()
                  pkg = "#{cwd}/node_modules/#{name}/package.json"

                  fs.stat pkg, (err, stat) =>
                    if stat?.isFile()
                      fs.readFile pkg, 'utf8', (err, data) =>
                        json = JSON.parse data
                        main = json.main || json._main || 'index.js'
                        path = "#{cwd}/node_modules/#{name}/#{main}"

                        proto._add proto, ref, path, next
                    else
                      proto._check proto, "#{cwd}/#{code_root}", name, ref, next
          else
            next()
        , =>
          async.eachSeries initers, (initer, next) =>
            @[initer.execute]().then next
          , hydration_complete

      _finish_up: (proto, args) =>
        name = proto.constructor.name

        @_call_initializers_for name, =>
          if listeners[name]?
            async.each listeners[name], (listener, next) =>
              listener @
              next()
            , => @_register_initialized name
          else
            @_register_initialized name

      _register_initialized: (name) =>
        @_make_available name, @

        initialized[name] = true

        Madul.FIRE "$.#{name}.initialized"

      _call_initializers_for: (name, callback) =>
        if _INITIALIZERS[name]?
          async.each _INITIALIZERS[name], (initializer, next) =>
            if initializer.called == false
              @[initializer.fn]()
                .then =>
                  initializer.called = true
                  next()
            else
              next()
          , callback
        else
          callback()

      _invoke_parent_initializers: (callback) =>
        proto = @.__proto__

        if proto.__proto__?
          parents = while proto.__proto__? && Object.keys(proto.__proto__).length > 0
            proto = proto.__proto__

          async.each parents, (parent, next) =>
            @_call_initializers_for parent.constructor.name, next
          , callback
        else
          callback()

      initialize: =>
        deferred = q.defer()
        proto    = @.__proto__
        name     = proto.constructor.name

        Madul.FIRE "$.#{name}.request_instance"

        if initialized[name] == undefined
          Madul.FIRE "$.#{name}.initialize"

          initialized[name] = false
          listeners[name]   = [ deferred.resolve ]

          @_wrap_methods()
          @_hydrate_deps => @_invoke_parent_initializers => @_finish_up proto
        else if initialized[name] == false
          listeners[name].push deferred.resolve
        else if initialized[name] == true
          process.nextTick => deferred.resolve available[strip name]

        deferred.promise

    module.exports = Madul


Update functions.litcoffee

Update functions.litcoffee

### This file

The logic in this file builds the date object.

If you compare this file to the ```python/functions.py``` file
you'll notice they are very similiar. That's intentional,
this file was ported over and kept such that it would be somewhat
easy to port changes back and forth.

### Terminology

Because it's so confusing here is a list of the different levels to refer to:

- Groups
  -- This is the capture groups. The lowest level. ```([0-9])``` etc.
  "Day", "Month", etc.
- Expressions
  -- This is an expression with multiple capture groups. They're usually named
  after the person that wrote them. "Greg Burns", etc.

  In Python, Expressions functions have nice named arguments, def expr(Day, Month, Year),
  but Javascript doesn't support this.
- Type
  -- This is a collection of expressions with a common goal.
  Months (Jan, 0-12, January, etc.).
- Patterns
  -- This is a collection of types ```<Month>/<Day>/<Year>```

### Warning

A note about the above list. Types and Groups are commonly mixed up.
I think groups SHOULD be the lowest
(because they are the actual capture *groups* in regular expressions)
but a group of expressions also makes sense.

It's so confusing that there are at least a couple places here that I've
also mixed myself up and probably in the documentation for RE|PARSE as well.

---

I use named tuples in python, and ```_replace``` mirrors the functionality of
```date._replace```.. that is that it returns a copy of the date with only
certain things changed and leaves the old well enough alone.

        _replace = (_old, _new) ->
            year:   if _new.year? then _new.year else _old.year
            month:  if _new.month? then _new.month else _old.month
            day:    if _new.day? then _new.day  else _old.day
            hour:   if _new.hour? then _new.hour else _old.hour
            minute: if _new.minute? then _new.minute else _old.minute
            second: if _new.second? then _new.second else _old.second
            am_pm:  if _new.am_pm? then _new.am_pm else _old.am_pm

I represent lengths of dates (i.e. Thursday, 1-2pm) with a timedelta that goes right
after the date hash in the result array.

In Javascript, I'm just going to represent a timedelta with a hash.
I make a pretty dumb assumption that timedelta will only cross hour/minutes/second boundaries.

        timedelta_from_Date = (start_time, end_time) ->
            seconds_difference = 0
            if start_time.hour? and end_time.hour?
              seconds_difference += 60*60*(end_time.hour - start_time.hour)

              if start_time.minute? and end_time.minute?
                seconds_difference += 60*(end_time.minute - start_time.minute)

                if start_time.second? and end_time.second?
                  seconds_difference += end_time.second - start_time.second

            hours = Math.floor(seconds_difference/60/60)
            minutes = Math.floor(seconds_difference/60) - (hours * 60)
            seconds = seconds_difference - (minutes * 60) - (hours * 60 * 60)

            return {
               timedelta: true
               hours: hours
               minutes: minutes
               seconds: seconds
            }

This is just a helper function

        in_array = (arr, _) -> arr.indexOf(_) != -1

```progressive_match``` is useful for matching abbreviations
and full spellings. Functions like this could be useful
to help parse fuzzy matches in the future (i.e. misspellings of months).

        progressive_match = (string, possibilities) ->
            part = ""
            if not string? then return
            for character in string.toLowerCase()
                part += character
                matches = []
                for month, value of possibilities
                    if month.indexOf(part) > -1
                        matches.push(month)
                if matches.length == 1
                    return possibilities[matches[0]]
### Types

        month_to_number = (month_string) ->
          months =
              "january": 1
              "february": 2
              "march": 3
              "april": 4
              "may": 5
              "june": 6
              "july": 7
              "august": 8
              "september": 9
              "october": 10
              "november": 11
              "december": 12
           return progressive_match(month_string, months)

        weekday_to_number = (WeekdayString ) ->
            weekday_list = {
                "monday": 0,
                "tuesday": 1,
                "wednesday": 2,
                "thursday": 3,
                "friday": 4,
                "saturday": 5,
                "sunday": 6,
            }
            return progressive_match(WeekdayString, weekday_list)

I serialize am_pm by converting the hours to milliary/24-hour time format.
I also include ```am_pm: 'pm'``` in the date format to show that that transformation
was done. Making that clear helpful because if you get a time like 1, with no ```am_pm```
designation you might want to assume pm and add 12. This is not done in the libary because
date_machine strives for honesty, not guesswork.

        am_pm = (input) ->
            if not input?
              return
            if input.toLowerCase() == "am" then 0
            else if input.toLowerCase() == "pm" then 12

You can see in this function that I try not to repeat logic and use other
functions. In this case I might have been able to simply put time_expression
in the functions hash/object, but in python it makes a difference due to named arguments.
I'm going to leave it as-is for clarity.

        military_time = (MilHour, MilMinute, MilSecond ) ->
            return time_expression(MilHour, MilMinute, MilSecond, undefined)

Here is the ampm conversion. I omit returns when the expressions are simple,
but later on I want to use them as much as possible to make my intentions clear.

        noon = (hour, AMPM) -> hour == 12 and AMPM == 12
        midnight = (hour, AMPM) -> hour == 12 and AMPM == 0

        time_expression = (Hour, Minute, Second, AMPM, SpecialTimeText ) ->
            if not Hour? and not Minute? and not Second? and not AMPM? and not SpecialTimeText?
                return
            if SpecialTimeText
                if SpecialTimeText.toLowerCase() == "noon"
                    return {hour: 12}
                if SpecialTimeText.toLowerCase() == "midnight"
                    return {hour: 0}
            d = {}
            if Hour
                d.hour = Number(Hour)
            if Minute
                d.minute = Number(Minute)
            if Second
                d.second = Number(Second)
            if AMPM?
                if d.hour
                    if noon(d.hour, AMPM)
                        d.hour = 12
                    else if midnight(d.hour, AMPM)
                        d.hour = 0
                    else
                        d.hour = d.hour + AMPM
                d.am_pm = AMPM
            if [d.hour, d.minute, d.second] == [undefined, undefined, undefined]
                return undefined
            return d

        time_and_time = (Hour, Minute, AMPM1, Hour2, Minute2, AMPM2) ->
            if AMPM2?
                AMPM2 = am_pm(AMPM2)
            if not AMPM1? and not AMPM2?
                return [time_expression(Hour, Minute), time_expression(Hour2, Minute2)]
            else if not AMPM1?
                return [time_expression(Hour, Minute, undefined, AMPM2),
                        time_expression(Hour2, Minute2, undefined, AMPM2)]
            else if not AMPM2?
                return [time_expression(Hour, Minute, undefined, AMPM1),
                        time_expression(Hour2, Minute2, undefined, AMPM1)]

        month_type = (input...) ->
            for value in input
                if value?
                    return Number(value)

        date_number = (Day, Abbr) -> if Day? then Number(Day)

        month_number = (MonthNum) -> Number(MonthNum)

        month_num_type = (input) -> Number(input)

        year = (Year) -> if Year? then Number(Year)

Sometimes the value is [undefined, undefined, <value>],
so I need to search for it and find it.

        get_first_defined = (_) ->
          for item in _
            if item?
              return item

### Patterns

There's a some unwrapping values out of arrays here.
Because of the namedarguments issue functions receive a lot more
arrays then in Python and so they need to be unwrapped.

        weekday_range_with_time = (time1, time2, [weekday1], [weekday2], MonthRange) ->
            output = []

            # Get first undefined value
            # Since only one value in list will be defined (if any)
            time1 = get_first_defined(time1)
            time2 = get_first_defined(time2)

            if time1?
                for date in MonthRange
                    output.push(_replace(date, time1))
                    if time2?
                        output.push(_replace(date, time2))
            return output

        weekday_range_with_extra = ( time, and_time, weekday_start, weekday_end, extra_time, extra_weekday, MonthRange) ->
            output = []
            if time?
                for date in MonthRange
                    if date.weekday?
                        if date.weekday in [weekday_start .. weekday_end]
                            output.push(_replace(date, time))
                            if and_time?
                                output.push(_replace(date, and_time))
                        if date.weekday == extra_weekday
                            output.push(_replace(date, extra_time))
            return output

        weekday_range_with_extra_backwards = (extra_time, extra_weekday, time, weekday_start, weekday_end, MonthRange ) ->
            return weekday_range_with_extra(time[0], time[1], weekday_start, weekday_end, extra_time, extra_weekday, MonthRange )

        reverse_basic_text = (time, day, month, year) ->
            return basic_text(time, undefined, undefined, month, day, year)

        basic_text = (time, first_second, weekday, month, day, year) ->
            if not day?
                day = 1
            if (day instanceof Array) and day.length == 1
              day = day[0]
            if (year instanceof Array) and year.length == 1
              year = year[0]
            if not time?
                return {year: year, month: month, day: day}
            else
                year: year
                month: month
                day: day
                hour: time.hour
                minute: time.minute
                second: time.second
                am_pm: time.am_pm

        slash = (month, day, year, time) ->
            return basic_text(time, undefined, undefined, month, day, year)

        month_range = (month, date_a, date_b) ->
            output = []
            for day in [date_a .. date_b]
                output.push(basic_text(undefined, undefined, undefined, month, day, undefined))
            return output

        multi_time = (time1, BasicText) ->
            output = []
            if time1? and BasicText?
                output.push(_replace(BasicText, time1))
                output.push(BasicText)
                return output

        large_repeat_words = ->
            return undefined

        weekday_range_with_time_range = (time1, weekday_range) ->
            output = []
            if time1? and weekday_range?
                range = timedelta_from_Date(_replace(weekday_range[0], time1), weekday_range[0])
                for weekday in weekday_range
                    output.push(_replace(weekday, {hour:time1.hour, minute:time1.minute, am_pm:time1.am_pm}))
                    output.push(range)
                return output

        time_range = (unstrict_time, strict_time, date, reverse) ->
            endtime = date
            starttime = endtime
            if unstrict_time
                starttime = _replace(starttime, {hour:Number(unstrict_time[0])})
                if date.am_pm
                    starttime = _replace(starttime, {hour: starttime.hour + date.am_pm, am_pm:date.am_pm})
            else
                starttime = _replace(starttime, {hour: strict_time.hour, minute: strict_time.minute})

            time_range = timedelta_from_Date(starttime, endtime)
            if reverse
                time_range = timedelta_from_Date(endtime, starttime)
            return [starttime, time_range]

        alt_time_range = (first_second, weekday, month, day, year, time, unstrict_time, strict_time) ->
            return time_range(unstrict_time, strict_time, basic_text(time, first_second, weekday, month, day, year), reverse)

        until_range = (date1, date2) ->
            if date1 and date2
                return [date1, timedelta_from_Date(date1, date2)]

        through_range = (time, weekday1, weekday2, month, date, beginning) ->
            output = []
            if month and date and beginning and weekday1
                ending =
                    month: month
                    day: date
                for day in [beginning.day .. ending.day]
                    temp =
                        month: month
                        day: date
                    if temp.weekday and in_array([weekday1 .. weekday2], temp.weekday)
                        if time
                            output.push(_replace(temp, time))
                        else
                            output.push(temp)
                return output

### The function list

This hash/object matches all the functions with a
string that represents it in the parse tree.

        functions =
            # Groups
            "MonthString": month_to_number,
            "AMPM": am_pm,
            # Expressions
            "Chase Year": year,
            "Chase Date": date_number,
            "Chase Month": month_number,
            "Steve Valaitis": time_expression,
            "Greg Burns": (hour, am_pm) -> time_expression(hour, null, null, am_pm, null),
            "Greg Burns UnstrictTime:": time_expression,
            "Steve Valaitis2": military_time,
            "Steve Valaitis And Time": time_and_time,
            "Text Parts": time_expression,
            "Michael Ash10": weekday_to_number,
            # Types
            "Month": month_type,
            "MonthNum": month_num_type,
            # Patterns
            "LargeRepeatWords": large_repeat_words,
            "BasicText": basic_text,
            "ReverseBasicText": reverse_basic_text,
            "Slash": slash,
            "MonthRange": month_range,
            "MultiTime": multi_time,
            "WeekdayRangeWithTime": weekday_range_with_time,
            "WeekdayRangeWithExtra": weekday_range_with_extra,
            "WeekdayRangeWithExtraBackwards": weekday_range_with_extra_backwards,
            "WeekdayRangeWithTimeRange": weekday_range_with_time_range,
            "UntilRange": until_range,
            "ThroughRange": through_range,
            "TimeRange": time_range,
            "AltTimeRange": alt_time_range,

This is default expression or pattern. ```any``` means
if value is defined, and there is array with even a single defined value then return true.

            "_default": (_) ->
                if any(_) then _ else undefined

```Type``` there is used to mean collection of expressions.
I know that because only one will match, so you just have to find
it and return it.

            "_default_type": (_...) ->
                if _?
                    for item in _
                         if item?
                             return item

            "_default_group": (_...) -> if _[0]? then _[0]

### This file

The logic in this file builds the date object.

If you compare this file to the ```python/functions.py``` file
you'll notice they are very similiar. That's intentional,
this file was ported over and kept such that it would be somewhat
easy to port changes back and forth.

### Terminology

Because it's so confusing here is a list of the different levels to refer to:

- Groups
  -- This is the capture groups. The lowest level. ```([0-9])``` etc.
  "Day", "Month", etc.
- Expressions
  -- This is an expression with multiple capture groups. They're usually named
  after the person that wrote them. "Greg Burns", etc.

  In Python, Expressions functions have nice named arguments, def expr(Day, Month, Year),
  but Javascript doesn't support this.
- Type
  -- This is a collection of expressions with a common goal.
  Months (Jan, 0-12, January, etc.).
- Patterns
  -- This is a collection of types ```<Month>/<Day>/<Year>```

### Warning

A note about the above list. Types and Groups are commonly mixed up.
I think groups SHOULD be the lowest
(because they are the actual capture *groups* in regular expressions)
but a group of expressions also makes sense.

It's so confusing that there are at least a couple places here that I've
also mixed myself up and probably in the documentation for RE|PARSE as well.

---

I use named tuples in python, and ```_replace``` mirrors the functionality of
```date._replace```.. that is that it returns a copy of the date with only
certain things changed and leaves the old well enough alone.

        _replace = (_old, _new) ->
            year:   if _new.year? then _new.year else _old.year
            month:  if _new.month? then _new.month else _old.month
            day:    if _new.day? then _new.day  else _old.day
            hour:   if _new.hour? then _new.hour else _old.hour
            minute: if _new.minute? then _new.minute else _old.minute
            second: if _new.second? then _new.second else _old.second
            am_pm:  if _new.am_pm? then _new.am_pm else _old.am_pm

I represent lengths of dates (i.e. Thursday, 1-2pm) with a timedelta that goes right
after the date hash in the result array.

In Javascript, I'm just going to represent a timedelta with a hash.
I make a pretty dumb assumption that timedelta will only cross hour/minutes/second boundaries.

        timedelta_from_Date = (start_time, end_time) ->
            seconds_difference = 0
            if start_time.hour? and end_time.hour?
              seconds_difference += 60*60*(end_time.hour - start_time.hour)

              if start_time.minute? and end_time.minute?
                seconds_difference += 60*(end_time.minute - start_time.minute)

                if start_time.second? and end_time.second?
                  seconds_difference += end_time.second - start_time.second

            hours = Math.floor(seconds_difference/60/60)
            minutes = Math.floor(seconds_difference/60) - (hours * 60)
            seconds = seconds_difference - (minutes * 60) - (hours * 60 * 60)

            return {
               timedelta: true
               hours: hours
               minutes: minutes
               seconds: seconds
            }

This is just a helper function

        in_array = (arr, _) -> arr.indexOf(_) != -1

```progressive_match``` is useful for matching abbreviations
and full spellings. Functions like this could be useful
to help parse fuzzy matches in the future (i.e. misspellings of months).

        progressive_match = (string, possibilities) ->
            part = ""
            if not string? then return
            for character in string.toLowerCase()
                part += character
                matches = []
                for month, value of possibilities
                    if month.indexOf(part) > -1
                        matches.push(month)
                if matches.length == 1
                    return possibilities[matches[0]]
### Types

The heading above is the heading in the python source.
I actually don't know if it's referring to collections of expressions
or capture groups.

        month_to_number = (month_string) ->
          months =
              "january": 1
              "february": 2
              "march": 3
              "april": 4
              "may": 5
              "june": 6
              "july": 7
              "august": 8
              "september": 9
              "october": 10
              "november": 11
              "december": 12
           return progressive_match(month_string, months)

        weekday_to_number = (WeekdayString ) ->
            weekday_list = {
                "monday": 0,
                "tuesday": 1,
                "wednesday": 2,
                "thursday": 3,
                "friday": 4,
                "saturday": 5,
                "sunday": 6,
            }
            return progressive_match(WeekdayString, weekday_list)

I serialize am_pm by converting the hours to milliary/24-hour time format.
I also include ```am_pm: 'pm'``` in the date format to show that that transformation
was done. Making that clear helpful because if you get a time like 1, with no ```am_pm```
designation you might want to assume pm and add 12. This is not done in the libary because
date_machine strives for honesty, not guesswork.

        am_pm = (input) ->
            if not input?
              return
            if input.toLowerCase() == "am" then 0
            else if input.toLowerCase() == "pm" then 12

You can see in this function that I try not to repeat logic and use other
functions. In this case I might have been able to simply put time_expression
in the functions hash/object, but in python it makes a difference due to named arguments.
I'm going to leave it as-is for clarity.

        military_time = (MilHour, MilMinute, MilSecond ) ->
            return time_expression(MilHour, MilMinute, MilSecond, undefined)

Here is the ampm conversion. I omit returns when the expressions are simple,
but later on I want to use them as much as possible to make my intentions clear.

        noon = (hour, AMPM) -> hour == 12 and AMPM == 12
        midnight = (hour, AMPM) -> hour == 12 and AMPM == 0

        time_expression = (Hour, Minute, Second, AMPM, SpecialTimeText ) ->
            if not Hour? and not Minute? and not Second? and not AMPM? and not SpecialTimeText?
                return
            if SpecialTimeText
                if SpecialTimeText.toLowerCase() == "noon"
                    return {hour: 12}
                if SpecialTimeText.toLowerCase() == "midnight"
                    return {hour: 0}
            d = {}
            if Hour
                d.hour = Number(Hour)
            if Minute
                d.minute = Number(Minute)
            if Second
                d.second = Number(Second)
            if AMPM?
                if d.hour
                    if noon(d.hour, AMPM)
                        d.hour = 12
                    else if midnight(d.hour, AMPM)
                        d.hour = 0
                    else
                        d.hour = d.hour + AMPM
                d.am_pm = AMPM
            if [d.hour, d.minute, d.second] == [undefined, undefined, undefined]
                return undefined
            return d

        time_and_time = (Hour, Minute, AMPM1, Hour2, Minute2, AMPM2) ->
            if AMPM2?
                AMPM2 = am_pm(AMPM2)
            if not AMPM1? and not AMPM2?
                return [time_expression(Hour, Minute), time_expression(Hour2, Minute2)]
            else if not AMPM1?
                return [time_expression(Hour, Minute, undefined, AMPM2),
                        time_expression(Hour2, Minute2, undefined, AMPM2)]
            else if not AMPM2?
                return [time_expression(Hour, Minute, undefined, AMPM1),
                        time_expression(Hour2, Minute2, undefined, AMPM1)]

        month_type = (input...) ->
            for value in input
                if value?
                    return Number(value)

        date_number = (Day, Abbr) -> if Day? then Number(Day)

        month_number = (MonthNum) -> Number(MonthNum)

        month_num_type = (input) -> Number(input)

        year = (Year) -> if Year? then Number(Year)

Sometimes the value is [undefined, undefined, <value>],
so I need to search for it and find it.

        get_first_defined = (_) ->
          for item in _
            if item?
              return item

### Patterns

There's a some unwrapping values out of arrays here.
Because of the namedarguments issue functions receive a lot more
arrays then in Python and so they need to be unwrapped.

        weekday_range_with_time = (time1, time2, [weekday1], [weekday2], MonthRange) ->
            output = []

            # Get first undefined value
            # Since only one value in list will be defined (if any)
            time1 = get_first_defined(time1)
            time2 = get_first_defined(time2)

            if time1?
                for date in MonthRange
                    output.push(_replace(date, time1))
                    if time2?
                        output.push(_replace(date, time2))
            return output

        weekday_range_with_extra = ( time, and_time, weekday_start, weekday_end, extra_time, extra_weekday, MonthRange) ->
            output = []
            if time?
                for date in MonthRange
                    if date.weekday?
                        if date.weekday in [weekday_start .. weekday_end]
                            output.push(_replace(date, time))
                            if and_time?
                                output.push(_replace(date, and_time))
                        if date.weekday == extra_weekday
                            output.push(_replace(date, extra_time))
            return output

        weekday_range_with_extra_backwards = (extra_time, extra_weekday, time, weekday_start, weekday_end, MonthRange ) ->
            return weekday_range_with_extra(time[0], time[1], weekday_start, weekday_end, extra_time, extra_weekday, MonthRange )

        reverse_basic_text = (time, day, month, year) ->
            return basic_text(time, undefined, undefined, month, day, year)

        basic_text = (time, first_second, weekday, month, day, year) ->
            if not day?
                day = 1
            if (day instanceof Array) and day.length == 1
              day = day[0]
            if (year instanceof Array) and year.length == 1
              year = year[0]
            if not time?
                return {year: year, month: month, day: day}
            else
                year: year
                month: month
                day: day
                hour: time.hour
                minute: time.minute
                second: time.second
                am_pm: time.am_pm

        slash = (month, day, year, time) ->
            return basic_text(time, undefined, undefined, month, day, year)

        month_range = (month, date_a, date_b) ->
            output = []
            for day in [date_a .. date_b]
                output.push(basic_text(undefined, undefined, undefined, month, day, undefined))
            return output

        multi_time = (time1, BasicText) ->
            output = []
            if time1? and BasicText?
                output.push(_replace(BasicText, time1))
                output.push(BasicText)
                return output

        large_repeat_words = ->
            return undefined

        weekday_range_with_time_range = (time1, weekday_range) ->
            output = []
            if time1? and weekday_range?
                range = timedelta_from_Date(_replace(weekday_range[0], time1), weekday_range[0])
                for weekday in weekday_range
                    output.push(_replace(weekday, {hour:time1.hour, minute:time1.minute, am_pm:time1.am_pm}))
                    output.push(range)
                return output

        time_range = (unstrict_time, strict_time, date, reverse) ->
            endtime = date
            starttime = endtime
            if unstrict_time
                starttime = _replace(starttime, {hour:Number(unstrict_time[0])})
                if date.am_pm
                    starttime = _replace(starttime, {hour: starttime.hour + date.am_pm, am_pm:date.am_pm})
            else
                starttime = _replace(starttime, {hour: strict_time.hour, minute: strict_time.minute})

            time_range = timedelta_from_Date(starttime, endtime)
            if reverse
                time_range = timedelta_from_Date(endtime, starttime)
            return [starttime, time_range]

        alt_time_range = (first_second, weekday, month, day, year, time, unstrict_time, strict_time) ->
            return time_range(unstrict_time, strict_time, basic_text(time, first_second, weekday, month, day, year), reverse)

        until_range = (date1, date2) ->
            if date1 and date2
                return [date1, timedelta_from_Date(date1, date2)]

        through_range = (time, weekday1, weekday2, month, date, beginning) ->
            output = []
            if month and date and beginning and weekday1
                ending =
                    month: month
                    day: date
                for day in [beginning.day .. ending.day]
                    temp =
                        month: month
                        day: date
                    if temp.weekday and in_array([weekday1 .. weekday2], temp.weekday)
                        if time
                            output.push(_replace(temp, time))
                        else
                            output.push(temp)
                return output

### The function list

This hash/object matches all the functions with a
string that represents it in the parse tree.

        functions =
            # Groups
            "MonthString": month_to_number,
            "AMPM": am_pm,
            # Expressions
            "Chase Year": year,
            "Chase Date": date_number,
            "Chase Month": month_number,
            "Steve Valaitis": time_expression,
            "Greg Burns": (hour, am_pm) -> time_expression(hour, null, null, am_pm, null),
            "Greg Burns UnstrictTime:": time_expression,
            "Steve Valaitis2": military_time,
            "Steve Valaitis And Time": time_and_time,
            "Text Parts": time_expression,
            "Michael Ash10": weekday_to_number,
            # Types
            "Month": month_type,
            "MonthNum": month_num_type,
            # Patterns
            "LargeRepeatWords": large_repeat_words,
            "BasicText": basic_text,
            "ReverseBasicText": reverse_basic_text,
            "Slash": slash,
            "MonthRange": month_range,
            "MultiTime": multi_time,
            "WeekdayRangeWithTime": weekday_range_with_time,
            "WeekdayRangeWithExtra": weekday_range_with_extra,
            "WeekdayRangeWithExtraBackwards": weekday_range_with_extra_backwards,
            "WeekdayRangeWithTimeRange": weekday_range_with_time_range,
            "UntilRange": until_range,
            "ThroughRange": through_range,
            "TimeRange": time_range,
            "AltTimeRange": alt_time_range,

This is default expression or pattern. ```any``` means
if value is defined, and there is array with even a single defined value then return true.

            "_default": (_) ->
                if any(_) then _ else undefined

```Type``` there is used to mean collection of expressions.
I know that because only one will match, so you just have to find
it and return it.

            "_default_type": (_...) ->
                if _?
                    for item in _
                         if item?
                             return item

            "_default_group": (_...) -> if _[0]? then _[0]