Skip over node_modules directories

Skip over node_modules directories

    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   = { }

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

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

    SKIP_WRAP = [
      'constructor'
      'initialize'
      'details'
      'fire'
      'warn'
      'listen'
      'set'
      'runtime_exception'
    ]

    HYRDATION_LISTENERS = { }

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

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

    WRAP = (cls, method) ->
      WRAPPED[cls] = [ ] unless WRAPPED[cls]?

      WRAPPED[cls].indexOf(method) < 0

    determine_local = (token) ->
      project_local = false
      node_local    = false
      name          = token.substring 1, token.length

      if token[0] == '.'
        project_local = true
      else if token[0] == '~'
        node_local = true
      else
        name = token

      [project_local, node_local, name]

    parse_name_and_local = (tokens) ->
      [project_local, node_local, name] = determine_local tokens[0].trim()

      if tokens.length == 2
        alias = underscore tokens[1].trim()
      else if tokens.length == 1
        alias = underscore name
      else
        return Madul.FIRE '!.Madul.dependency_spec.alias.invalid', tokens[1]

      [project_local, node_local, name, alias]

    parse_alias_and_parent = (token) ->
      t = token.split '->'

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

      [parent, t]

    extract_properties = (token) ->
      [parent, t] = parse_alias_and_parent token
      [project_local, node_local, name, alias] = parse_name_and_local t

      [project_local, node_local, name, alias, parent]

    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    '}"

      @DUMMY: (deps, cb) ->
        class __DUMMY__ extends Madul
          deps: deps

        new __DUMMY__()
          .initialize()
          .then cb

      @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 '/'

      @PARSE_SPEC: (value) =>
        tokens = value.split '='

        [project_local, node_local, name, alias, parent] = extract_properties tokens[0]

        if tokens.length == 2
          initializer = tokens[1].trim()
          toks        = initializer.split ':'
          initializer = toks[0].trim()

          if toks.length == 2
            prerequisites = toks[1].split(',').map (p) => p.trim()
          else if toks.length > 2
            return Madul.FIRE '!.Madul.dependency_spec.initializer.invalid', tokens[1]

        else if tokens.length > 2
          return Madul.FIRE '!.Madul.dependency_spec.invalid', d

        { ref: alias || underscore(name), alias, name, parent, initializer, prerequisites, project_local, node_local }

      @BUILD_SPEC: ({ search_root, name, alias, initializer, prerequisites }) =>
        unless name?
          return Madul.FIRE '!.Madul.dependency_spec.name-required', arguments[0]

        if prerequisites? && initializer? == false
          return Madul.FIRE '!.Madul.dependency_spec.prerequisites-require-initializer', arguments[0]

        "#{if search_root?   then "#{search_root}#"            else ''}\
         #{name}\
         #{if alias?         then " -> #{alias}"               else ''}\
         #{if initializer?   then " = #{initializer}"          else ''}\
         #{if prerequisites? then ":#{prerequisites.join ','}" else ''}\
        "

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

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

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

        finisher() if typeof finisher == 'function'

      runtime_exception: (exit = false) =>
        (err) =>
          Madul.FIRE "!.#{@constructor.name}.runtime-exception",
            stack:     err.stack
            message:   err.message
            timestamp: microtime.now()

          process.exit(1) if exit == 'DIE_ON_EXCEPTION'

      set: (prop, val) =>
        proto = @.__proto__
        mod   = available[strip proto.constructor.name.toLowerCase()]

        if mod?
          mod.__proto__[prop] = val

      _report: (method, state, id, args, breaker) =>
        invoke = undefined
        params =
          uuid:      id
          args:      args
          timestamp: microtime.now()

        if state == 'reject'
          if typeof breaker == 'function'
            stop = new Error()
            stop.break = true

            breaker stop

          @warn "#{method}.#{state}", params
        else
          @fire "#{method}.#{state}", params

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

            proto._report method, state, id, data, breaker

      _prep_invocation: (proto, method, input, def) =>
        out = [ ]
        id  = uuid.v4fast()
        res = proto._respond proto, method, id, def
        e   = (brk) =>
          error = (err) => res 'reject', err, brk

          if typeof brk == 'function'
            error
          else
            error brk

        if Array.isArray input
          out = out.concat input
        else if typeof input == 'object'
          out.push input
        else
          msg = "input to #{proto.constructor.name}.#{method} must be an Array of Object"

          proto.warn.call proto, 'input.invalid', msg

          throw new Error msg

        out.push (out) => res 'resolve', out
        out.push e
        out.push (out) => res 'notify',  out

        proto._report method, 'invoke', id, out

        out

      _process_decorators: (proto, type) =>
        if Array.isArray proto[type]
          proto[type].map (b) => Madul.PARSE_SPEC(b).ref
        else if typeof proto[type] == 'string'
          [ Madul.PARSE_SPEC(proto[type]).ref ]
        else
          [ ]

      _do_wrap: (proto, method, wrapped) =>
        if SKIP_WRAP.includes method
          wrapped()
        else
          Madul.FIRE "$.#{proto.constructor.name}.#{method}.wrap"

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

            proto[method] = =>
              def   = q.defer()
              args  = Array.prototype.slice.call arguments
              input = proto._prep_invocation proto, method, args, def

              try
                proto["_#{method}"].apply proto, input
              catch e
                failed = if input[0].fail? then input[0].fail else input[input.length - 2]

                proto.warn.call proto, 'runtime-exception', stack: e.stack, message: e.message

                failed e.message

              def.promise

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

            WRAPPED[proto.constructor.name].push method

            wrapped()
          else if typeof proto[method] == 'object'

            if Array.isArray proto[method].validate
              args_format = 'ARRAY'
              decs        = proto[method].validate

              proto[method].validators = for val, i in decs
                "#{i}": Madul.PARSE_SPEC(val).ref
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = [ ]

              for own key, val of proto[method].validate
                if Array.isArray val
                  for v in val
                    decs.push v
                else if typeof val == 'object'
                  for own k, v of val
                    if Array.isArray v
                      for V in v
                        decs.push V
                    else
                      decs.push v
                else
                  decs.push val

              proto[method].validators = [ ]

              for own key, val of proto[method].validate
                if Array.isArray val
                  proto[method].validators.push "#{key}": for v in val
                    Madul.PARSE_SPEC(v).ref
                else if typeof val == 'object'
                  for own k, v of val
                    if Array.isArray v
                      proto[method].validators.push "#{key}.#{k}": for V in v
                        Madul.PARSE_SPEC(V).ref
                    else
                      proto[method].validators.push "#{key}.#{k}": Madul.PARSE_SPEC(v).ref
                else
                  proto[method].validators.push "#{key}": Madul.PARSE_SPEC(val).ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ proto[method].validate ]

              proto[method].validators = [ { 0: Madul.PARSE_SPEC(proto[method].validate).ref }]
            else if typeof proto[method].validate != 'undefined'
              proto.warn.call proto, 'meta.invalid', validate: 'must be a String, Object, or Array'
              return
            else
              args_format = 'ARRAY'
              decs        = [ ]

            if Array.isArray proto[method].before
              decs = decs.concat proto[method].before
            else if typeof proto[method].before == 'string'
              decs = decs.concat [ proto[method].before ]

            if Array.isArray proto[method].after
              decs = decs.concat proto[method].after
            else if typeof proto[method].after == 'string'
              decs = decs.concat [ Madul.PARSE_SPEC proto[method].after ]

            deduped = decs.filter (e, i, a) => a.indexOf(e) == i

            proto.fire.call proto, 'decorators.hydrate', deduped

            handle_err = (fn, args, next, reject) =>
              (err) =>
                proto.warn.call proto, "#{fn}.validator.failed", args
                reject err

                stop = new Error()
                stop.break = true

                next stop

            @_do_hydrate proto, deduped, (errors) =>
              if errors?
                wrapped errors
              else
                proto["_#{method}"] = proto[method]

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

                  if args_format == 'ARRAY'
                    args = Array.prototype.slice.call arguments
                  else if args_format == 'OBJECT'
                    args = arguments[0]
                  else
                    proto.warn.call proto, 'cannot-continue', 'No arg format specified'

                    return def.reject 'No arg format specified'

                  before = @_process_decorators me, 'before'
                  after  = @_process_decorators me, 'after'

                  q.Promise (resolve, reject) =>
                    async.eachSeries me.validators, (v, next) =>
                      arg       = Object.keys(v)[0]
                      validator = v[arg]
                      input     = arg
                      prop      = args

                      for a in arg.split '.'
                        prop  = prop[a]
                        input = a

                      if Array.isArray validator
                        async.eachSeries validator, (v, nxt) =>
                          proto.fire.call proto, 'validator.execute', "#{v}": prop

                          proto[v].EXECUTE.call proto[v], input, prop
                            .then nxt
                            .catch handle_err v, { "#{input}": prop }, nxt, (err) =>
                              reject err
                              def.reject err
                        , next
                      else
                        proto.fire.call proto, 'validator.execute', "#{validator}": prop

                        proto[validator].EXECUTE.call proto[validator], input, prop
                          .then next
                          .catch handle_err v, { "#{input}": prop }, next, (err) =>
                            reject err
                            def.reject err
                    , resolve
                  .catch (err) => def.reject err
                  .then =>
                    q.Promise (resolve, reject) =>
                      async.eachSeries before, (b, next) =>
                        proto.fire.call proto, 'before_filter.execute', "#{b}": args

                        proto[b].before.call proto[b], args
                          .then next
                          .catch handle_err b, args, next, (err) =>
                            reject err
                            def.reject err
                      , resolve
                  .catch (err) => def.reject err
                  .then =>
                    q.Promise (resolve, reject) =>
                      d     = q.defer()
                      input = proto._prep_invocation proto, method, args, d

                      try
                        me.behavior.apply proto, input
                          .then  (out) => resolve out
                          .catch (err) => reject  err
                      catch e
                        me.warn.call me, 'runtime-exception', stack: e.stack, message: e.message

                        reject e
                  .catch (err) => def.reject err
                  .then (result) =>
                    q.Promise (resolve, reject) =>
                      if after.length > 0
                        async.eachSeries after, (a, next) =>
                          proto.fire.call proto, 'after_filter.execute', "#{a}": args

                          proto[a].after.call proto[a], result
                            .then next
                            .catch handle_err b, args, next, (err) =>
                              reject err
                              def.reject err
                        , => resolve result
                      else
                        process.nextTick => resolve result
                  .then  (out) => def.resolve out
                  .catch (err) => def.reject  err

                  def.promise

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

                WRAPPED[proto.constructor.name].push method

                wrapped()
          else
            proto.warn.call proto, 'cannot-wrap', 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

              if proto.deps?
                filtered = proto.deps.filter (d) => Madul.PARSE_SPEC(d).name == prop.replace /_/g, '-'

                continue if filtered.length > 0

              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, (errors) =>
              if errors?
                stop = new Error()
                stop.break = true

                next stop
              else
                next()
          , (errors) =>
            if errors?
              stop = new Error()
              stop.break = true

              completed stop
            else
              @_call_initializers_for wrap.proto, wrap.name, completed
        , callback

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

        available[strip name] = mod

      _hydrate_deps: (proto, done) =>
        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, (errors) =>
                if errors?
                  stop = new Error()
                  stop.break = true

                  next stop
                else
                  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, done, fail) =>
        mod      = require path
        proto    = mod
        is_madul = false

        while proto
          is_madul = true if proto.name == 'Madul'
          if is_madul                            == false      &&
             proto.constructor.name              != 'Object'   &&
             typeof proto                        == 'function' &&
             typeof proto.__super__?.constructor == 'function'
            proto = proto.__super__.constructor
          else
            proto = undefined

        if is_madul
          new mod()
            .initialize()
            .then  (m)   => done m
            .catch (err) => fail err
        else
          done mod

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

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

            finished 'NOT_FOUND'
          else
            error   = true
            checked = 0

            async.eachOfSeries files, (f, i, next) =>
              depth = "#{path}/#{f}"

              fs.stat depth, (e, s) =>
                if s.isDirectory() && f[0] != '.' && f != 'node_modules'
                  me._check me, depth, dep, ref, => next()
                else if s.isFile() && f.substring(0, f.length - 3) == dep
                  stop  = new Error()
                  stop.break = true

                  me._load me, ref, depth, =>
                    error  = undefined
                    loaded = true

                    me._do_add me, ref, => next stop
                  , (err) => next stop
                else
                  next()
            , => finished error

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

        me[underscore ref] = available[strip ref]

        next() if typeof next == 'function'

      _add: (me, ref, path, next) =>
        me._init_if_madul path, (mod) =>
          me._make_available ref, mod
          me._do_add me, ref, next
        , (err) =>
          stop = new Error()
          stop.break = true

          next stop

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

        async.eachSeries deps, (d, next) =>
          spec = Madul.PARSE_SPEC d

          if spec.prerequisites?
            insert_at = for p in spec.prerequisites
              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: spec.alias, execute: spec.initializer
          else if spec.initializer?
            initers.push alias: spec.alias, execute: spec.initializer

          if typeof proto[underscore spec.ref] == 'undefined'
            if available[strip spec.ref]? == true
              proto._do_add proto, spec.ref, next
            else
              if spec.parent?
                if proto[spec.parent]?
                  proto._check proto, SEARCH_ROOTS[spec.parent], spec.name, spec.ref, (err) =>
                    if err?
                      deep = "#{SEARCH_ROOTS[spec.parent]}/node_modules/#{spec.parent}/dist"

                      proto._check proto, deep, spec.name, spec.ref, (e) =>
                        next()
                    else
                      next()
                else
                  proto.fire.call proto, 'search_root.load', { name: spec.name, alias: spec.alias, parent: spec.parent }

                  @_do_hydrate proto, [ spec.parent ], (errors) =>
                    if errors?
                      stop = new Error()
                      stop.break = true

                      next stop
                    else
                      if SEARCH_ROOTS[spec.parent] == undefined
                        SEARCH_ROOTS[spec.parent] = @_find_code_root spec.parent

                      proto._check proto, SEARCH_ROOTS[spec.parent], spec.name, spec.ref, (err) =>
                        if err?
                          deep = "#{SEARCH_ROOTS[spec.parent]}/node_modules/#{spec.parent}/dist"

                          proto._check proto, deep, spec.name, spec.ref, (e) =>
                            next()
                        else
                          next()
              else if spec.node_local
                key = @_find_require_key proto.constructor.name

                async.eachSeries require.cache[key].paths, (path, nxt) =>
                  @_load_from_package_json proto, path, spec.name, spec.ref, =>
                    nxt()
                  , =>
                    nxt()
                , =>
                  next()
              else if spec.project_local
                proto._check proto, LOCALS[proto.constructor.name], spec.name, spec.ref, (err) =>
                  if err?
                    details = not_found: spec.name
                    stop    = new Error()

                    stop.break = true

                    proto.warn.call proto, 'hydrating', details

                    errors.push(details)

                    next stop
                  else
                    next()
              else
                try
                  proto._add proto, spec.ref, spec.name, next
                catch e
                  path = "#{process.cwd()}/node_modules"

                  @_load_from_package_json proto, path, spec.name, spec.ref, next, =>
                    pth = LOCALS[proto.constructor.name]

                    try
                      proto._check proto, pth, spec.name, spec.ref, (err) =>
                        if err?
                          proto._check proto, "#{process.cwd()}/dist", spec.name, spec.ref, next
                        else
                          next()

          else
            next()
        , (err) =>
          if err?.length > 0
            proto.warn.call proto, 'hydration.halt', errors

            hydration_complete errors
          else
            async.eachSeries initers, (initer, next) =>
              proto[initer.execute].apply(@).then next
            , hydration_complete

      _load_from_package_json: (proto, path, name, ref, success, next) =>
        pkg = "#{path}/#{name}/package.json"
        fs.stat pkg, (err, stat) =>
          if err?
            next()
          else if stat.isFile()
            fs.readFile pkg, 'utf8', (err, data) =>
              json = JSON.parse data
              main = json.main || json._main || 'index.js'
              path = "#{path}/#{name}/#{main}"

              proto._add proto, ref, path, success
          else
            next()

      _finish_up: (proto, args) =>
        name = proto.constructor.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: (proto, name, callback) =>
        if _INITIALIZERS[name]?
          async.each _INITIALIZERS[name], (initializer, next) =>
            if initializer.called == false
              proto[initializer.fn].apply proto
                .then =>
                  initializer.called = true
                  next()
            else
              next()
          , callback
        else
          callback()

      _do_find: (thing, cb) =>
        file  = thing.toLowerCase()
        found = for own key, val of require.cache
          if key.replace(/_/g, '').toLowerCase().includes file
            cb key

        filtered = found.filter (f) => f?

        if filtered.length > 0
          filtered.sort((a, b) => a.length - b.length)[0]
        else
          [ ]

      _find_require_key: (resource) =>
        @_do_find resource, (key) => key

      _find_code_root: (resource) =>
        @_do_find resource, (key) => key.substring(0, key.lastIndexOf '/').split '/'
          .join '/'

      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 ]

          if LOCALS[name] == undefined
            LOCALS[name] = @_find_code_root name

          @_hydrate_deps proto, (errors) =>
            if errors?
              deferred.reject errors
            else
              @_wrap_methods proto, (err) =>
                if err?
                  deferred.reject err
                else
                  @_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   = { }

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

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

    SKIP_WRAP = [
      'constructor'
      'initialize'
      'details'
      'fire'
      'warn'
      'listen'
      'set'
      'runtime_exception'
    ]

    HYRDATION_LISTENERS = { }

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

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

    WRAP = (cls, method) ->
      WRAPPED[cls] = [ ] unless WRAPPED[cls]?

      WRAPPED[cls].indexOf(method) < 0

    determine_local = (token) ->
      project_local = false
      node_local    = false
      name          = token.substring 1, token.length

      if token[0] == '.'
        project_local = true
      else if token[0] == '~'
        node_local = true
      else
        name = token

      [project_local, node_local, name]

    parse_name_and_local = (tokens) ->
      [project_local, node_local, name] = determine_local tokens[0].trim()

      if tokens.length == 2
        alias = underscore tokens[1].trim()
      else if tokens.length == 1
        alias = underscore name
      else
        return Madul.FIRE '!.Madul.dependency_spec.alias.invalid', tokens[1]

      [project_local, node_local, name, alias]

    parse_alias_and_parent = (token) ->
      t = token.split '->'

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

      [parent, t]

    extract_properties = (token) ->
      [parent, t] = parse_alias_and_parent token
      [project_local, node_local, name, alias] = parse_name_and_local t

      [project_local, node_local, name, alias, parent]

    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    '}"

      @DUMMY: (deps, cb) ->
        class __DUMMY__ extends Madul
          deps: deps

        new __DUMMY__()
          .initialize()
          .then cb

      @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 '/'

      @PARSE_SPEC: (value) =>
        tokens = value.split '='

        [project_local, node_local, name, alias, parent] = extract_properties tokens[0]

        if tokens.length == 2
          initializer = tokens[1].trim()
          toks        = initializer.split ':'
          initializer = toks[0].trim()

          if toks.length == 2
            prerequisites = toks[1].split(',').map (p) => p.trim()
          else if toks.length > 2
            return Madul.FIRE '!.Madul.dependency_spec.initializer.invalid', tokens[1]

        else if tokens.length > 2
          return Madul.FIRE '!.Madul.dependency_spec.invalid', d

        { ref: alias || underscore(name), alias, name, parent, initializer, prerequisites, project_local, node_local }

      @BUILD_SPEC: ({ search_root, name, alias, initializer, prerequisites }) =>
        unless name?
          return Madul.FIRE '!.Madul.dependency_spec.name-required', arguments[0]

        if prerequisites? && initializer? == false
          return Madul.FIRE '!.Madul.dependency_spec.prerequisites-require-initializer', arguments[0]

        "#{if search_root?   then "#{search_root}#"            else ''}\
         #{name}\
         #{if alias?         then " -> #{alias}"               else ''}\
         #{if initializer?   then " = #{initializer}"          else ''}\
         #{if prerequisites? then ":#{prerequisites.join ','}" else ''}\
        "

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

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

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

        finisher() if typeof finisher == 'function'

      runtime_exception: (exit = false) =>
        (err) =>
          Madul.FIRE "!.#{@constructor.name}.runtime-exception",
            stack:     err.stack
            message:   err.message
            timestamp: microtime.now()

          process.exit(1) if exit == 'DIE_ON_EXCEPTION'

      set: (prop, val) =>
        proto = @.__proto__
        mod   = available[strip proto.constructor.name.toLowerCase()]

        if mod?
          mod.__proto__[prop] = val

      _report: (method, state, id, args, breaker) =>
        invoke = undefined
        params =
          uuid:      id
          args:      args
          timestamp: microtime.now()

        if state == 'reject'
          if typeof breaker == 'function'
            stop = new Error()
            stop.break = true

            breaker stop

          @warn "#{method}.#{state}", params
        else
          @fire "#{method}.#{state}", params

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

            proto._report method, state, id, data, breaker

      _prep_invocation: (proto, method, input, def) =>
        out = [ ]
        id  = uuid.v4fast()
        res = proto._respond proto, method, id, def
        e   = (brk) =>
          error = (err) => res 'reject', err, brk

          if typeof brk == 'function'
            error
          else
            error brk

        if Array.isArray input
          out = out.concat input
        else if typeof input == 'object'
          out.push input
        else
          msg = "input to #{proto.constructor.name}.#{method} must be an Array of Object"

          proto.warn.call proto, 'input.invalid', msg

          throw new Error msg

        out.push (out) => res 'resolve', out
        out.push e
        out.push (out) => res 'notify',  out

        proto._report method, 'invoke', id, out

        out

      _process_decorators: (proto, type) =>
        if Array.isArray proto[type]
          proto[type].map (b) => Madul.PARSE_SPEC(b).ref
        else if typeof proto[type] == 'string'
          [ Madul.PARSE_SPEC(proto[type]).ref ]
        else
          [ ]

      _do_wrap: (proto, method, wrapped) =>
        if SKIP_WRAP.includes method
          wrapped()
        else
          Madul.FIRE "$.#{proto.constructor.name}.#{method}.wrap"

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

            proto[method] = =>
              def   = q.defer()
              args  = Array.prototype.slice.call arguments
              input = proto._prep_invocation proto, method, args, def

              try
                proto["_#{method}"].apply proto, input
              catch e
                failed = if input[0].fail? then input[0].fail else input[input.length - 2]

                proto.warn.call proto, 'runtime-exception', stack: e.stack, message: e.message

                failed e.message

              def.promise

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

            WRAPPED[proto.constructor.name].push method

            wrapped()
          else if typeof proto[method] == 'object'

            if Array.isArray proto[method].validate
              args_format = 'ARRAY'
              decs        = proto[method].validate

              proto[method].validators = for val, i in decs
                "#{i}": Madul.PARSE_SPEC(val).ref
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = [ ]

              for own key, val of proto[method].validate
                if Array.isArray val
                  for v in val
                    decs.push v
                else if typeof val == 'object'
                  for own k, v of val
                    if Array.isArray v
                      for V in v
                        decs.push V
                    else
                      decs.push v
                else
                  decs.push val

              proto[method].validators = [ ]

              for own key, val of proto[method].validate
                if Array.isArray val
                  proto[method].validators.push "#{key}": for v in val
                    Madul.PARSE_SPEC(v).ref
                else if typeof val == 'object'
                  for own k, v of val
                    if Array.isArray v
                      proto[method].validators.push "#{key}.#{k}": for V in v
                        Madul.PARSE_SPEC(V).ref
                    else
                      proto[method].validators.push "#{key}.#{k}": Madul.PARSE_SPEC(v).ref
                else
                  proto[method].validators.push "#{key}": Madul.PARSE_SPEC(val).ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ proto[method].validate ]

              proto[method].validators = [ { 0: Madul.PARSE_SPEC(proto[method].validate).ref }]
            else if typeof proto[method].validate != 'undefined'
              proto.warn.call proto, 'meta.invalid', validate: 'must be a String, Object, or Array'
              return
            else
              args_format = 'ARRAY'
              decs        = [ ]

            if Array.isArray proto[method].before
              decs = decs.concat proto[method].before
            else if typeof proto[method].before == 'string'
              decs = decs.concat [ proto[method].before ]

            if Array.isArray proto[method].after
              decs = decs.concat proto[method].after
            else if typeof proto[method].after == 'string'
              decs = decs.concat [ Madul.PARSE_SPEC proto[method].after ]

            deduped = decs.filter (e, i, a) => a.indexOf(e) == i

            proto.fire.call proto, 'decorators.hydrate', deduped

            handle_err = (fn, args, next, reject) =>
              (err) =>
                proto.warn.call proto, "#{fn}.validator.failed", args
                reject err

                stop = new Error()
                stop.break = true

                next stop

            @_do_hydrate proto, deduped, (errors) =>
              if errors?
                wrapped errors
              else
                proto["_#{method}"] = proto[method]

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

                  if args_format == 'ARRAY'
                    args = Array.prototype.slice.call arguments
                  else if args_format == 'OBJECT'
                    args = arguments[0]
                  else
                    proto.warn.call proto, 'cannot-continue', 'No arg format specified'

                    return def.reject 'No arg format specified'

                  before = @_process_decorators me, 'before'
                  after  = @_process_decorators me, 'after'

                  q.Promise (resolve, reject) =>
                    async.eachSeries me.validators, (v, next) =>
                      arg       = Object.keys(v)[0]
                      validator = v[arg]
                      input     = arg
                      prop      = args

                      for a in arg.split '.'
                        prop  = prop[a]
                        input = a

                      if Array.isArray validator
                        async.eachSeries validator, (v, nxt) =>
                          proto.fire.call proto, 'validator.execute', "#{v}": prop

                          proto[v].EXECUTE.call proto[v], input, prop
                            .then nxt
                            .catch handle_err v, { "#{input}": prop }, nxt, (err) =>
                              reject err
                              def.reject err
                        , next
                      else
                        proto.fire.call proto, 'validator.execute', "#{validator}": prop

                        proto[validator].EXECUTE.call proto[validator], input, prop
                          .then next
                          .catch handle_err v, { "#{input}": prop }, next, (err) =>
                            reject err
                            def.reject err
                    , resolve
                  .catch (err) => def.reject err
                  .then =>
                    q.Promise (resolve, reject) =>
                      async.eachSeries before, (b, next) =>
                        proto.fire.call proto, 'before_filter.execute', "#{b}": args

                        proto[b].before.call proto[b], args
                          .then next
                          .catch handle_err b, args, next, (err) =>
                            reject err
                            def.reject err
                      , resolve
                  .catch (err) => def.reject err
                  .then =>
                    q.Promise (resolve, reject) =>
                      d     = q.defer()
                      input = proto._prep_invocation proto, method, args, d

                      try
                        me.behavior.apply proto, input
                          .then  (out) => resolve out
                          .catch (err) => reject  err
                      catch e
                        me.warn.call me, 'runtime-exception', stack: e.stack, message: e.message

                        reject e
                  .catch (err) => def.reject err
                  .then (result) =>
                    q.Promise (resolve, reject) =>
                      if after.length > 0
                        async.eachSeries after, (a, next) =>
                          proto.fire.call proto, 'after_filter.execute', "#{a}": args

                          proto[a].after.call proto[a], result
                            .then next
                            .catch handle_err b, args, next, (err) =>
                              reject err
                              def.reject err
                        , => resolve result
                      else
                        process.nextTick => resolve result
                  .then  (out) => def.resolve out
                  .catch (err) => def.reject  err

                  def.promise

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

                WRAPPED[proto.constructor.name].push method

                wrapped()
          else
            proto.warn.call proto, 'cannot-wrap', 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

              if proto.deps?
                filtered = proto.deps.filter (d) => Madul.PARSE_SPEC(d).name == prop.replace /_/g, '-'

                continue if filtered.length > 0

              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, (errors) =>
              if errors?
                stop = new Error()
                stop.break = true

                next stop
              else
                next()
          , (errors) =>
            if errors?
              stop = new Error()
              stop.break = true

              completed stop
            else
              @_call_initializers_for wrap.proto, wrap.name, completed
        , callback

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

        available[strip name] = mod

      _hydrate_deps: (proto, done) =>
        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, (errors) =>
                if errors?
                  stop = new Error()
                  stop.break = true

                  next stop
                else
                  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, done, fail) =>
        mod      = require path
        proto    = mod
        is_madul = false

        while proto
          is_madul = true if proto.name == 'Madul'
          if is_madul                            == false      &&
             proto.constructor.name              != 'Object'   &&
             typeof proto                        == 'function' &&
             typeof proto.__super__?.constructor == 'function'
            proto = proto.__super__.constructor
          else
            proto = undefined

        if is_madul
          new mod()
            .initialize()
            .then  (m)   => done m
            .catch (err) => fail err
        else
          done mod

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

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

            finished 'NOT_FOUND'
          else
            error   = true
            checked = 0

            async.eachOfSeries files, (f, i, 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
                  stop  = new Error()
                  stop.break = true

                  me._load me, ref, depth, =>
                    error  = undefined
                    loaded = true

                    me._do_add me, ref, => next stop
                  , (err) => next stop
                else
                  next()
            , => finished error

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

        me[underscore ref] = available[strip ref]

        next() if typeof next == 'function'

      _add: (me, ref, path, next) =>
        me._init_if_madul path, (mod) =>
          me._make_available ref, mod
          me._do_add me, ref, next
        , (err) =>
          stop = new Error()
          stop.break = true

          next stop

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

        async.eachSeries deps, (d, next) =>
          spec = Madul.PARSE_SPEC d

          if spec.prerequisites?
            insert_at = for p in spec.prerequisites
              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: spec.alias, execute: spec.initializer
          else if spec.initializer?
            initers.push alias: spec.alias, execute: spec.initializer

          if typeof proto[underscore spec.ref] == 'undefined'
            if available[strip spec.ref]? == true
              proto._do_add proto, spec.ref, next
            else
              if spec.parent?
                if proto[spec.parent]?
                  proto._check proto, SEARCH_ROOTS[spec.parent], spec.name, spec.ref, (err) =>
                    if err?
                      deep = "#{SEARCH_ROOTS[spec.parent]}/node_modules/#{spec.parent}/dist"

                      proto._check proto, deep, spec.name, spec.ref, (e) =>
                        next()
                    else
                      next()
                else
                  proto.fire.call proto, 'search_root.load', { name: spec.name, alias: spec.alias, parent: spec.parent }

                  @_do_hydrate proto, [ spec.parent ], (errors) =>
                    if errors?
                      stop = new Error()
                      stop.break = true

                      next stop
                    else
                      if SEARCH_ROOTS[spec.parent] == undefined
                        SEARCH_ROOTS[spec.parent] = @_find_code_root spec.parent

                      proto._check proto, SEARCH_ROOTS[spec.parent], spec.name, spec.ref, (err) =>
                        if err?
                          deep = "#{SEARCH_ROOTS[spec.parent]}/node_modules/#{spec.parent}/dist"

                          proto._check proto, deep, spec.name, spec.ref, (e) =>
                            next()
                        else
                          next()
              else if spec.node_local
                key = @_find_require_key proto.constructor.name

                async.eachSeries require.cache[key].paths, (path, nxt) =>
                  @_load_from_package_json proto, path, spec.name, spec.ref, =>
                    nxt()
                  , =>
                    nxt()
                , =>
                  next()
              else if spec.project_local
                proto._check proto, LOCALS[proto.constructor.name], spec.name, spec.ref, (err) =>
                  if err?
                    details = not_found: spec.name
                    stop    = new Error()

                    stop.break = true

                    proto.warn.call proto, 'hydrating', details

                    errors.push(details)

                    next stop
                  else
                    next()
              else
                try
                  proto._add proto, spec.ref, spec.name, next
                catch e
                  path = "#{process.cwd()}/node_modules"

                  @_load_from_package_json proto, path, spec.name, spec.ref, next, =>
                    pth = LOCALS[proto.constructor.name]

                    try
                      proto._check proto, pth, spec.name, spec.ref, (err) =>
                        if err?
                          proto._check proto, "#{process.cwd()}/dist", spec.name, spec.ref, next
                        else
                          next()

          else
            next()
        , (err) =>
          if err?.length > 0
            proto.warn.call proto, 'hydration.halt', errors

            hydration_complete errors
          else
            async.eachSeries initers, (initer, next) =>
              proto[initer.execute].apply(@).then next
            , hydration_complete

      _load_from_package_json: (proto, path, name, ref, success, next) =>
        pkg = "#{path}/#{name}/package.json"
        fs.stat pkg, (err, stat) =>
          if err?
            next()
          else if stat.isFile()
            fs.readFile pkg, 'utf8', (err, data) =>
              json = JSON.parse data
              main = json.main || json._main || 'index.js'
              path = "#{path}/#{name}/#{main}"

              proto._add proto, ref, path, success
          else
            next()

      _finish_up: (proto, args) =>
        name = proto.constructor.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: (proto, name, callback) =>
        if _INITIALIZERS[name]?
          async.each _INITIALIZERS[name], (initializer, next) =>
            if initializer.called == false
              proto[initializer.fn].apply proto
                .then =>
                  initializer.called = true
                  next()
            else
              next()
          , callback
        else
          callback()

      _do_find: (thing, cb) =>
        file  = thing.toLowerCase()
        found = for own key, val of require.cache
          if key.replace(/_/g, '').toLowerCase().includes file
            cb key

        filtered = found.filter (f) => f?

        if filtered.length > 0
          filtered.sort((a, b) => a.length - b.length)[0]
        else
          [ ]

      _find_require_key: (resource) =>
        @_do_find resource, (key) => key

      _find_code_root: (resource) =>
        @_do_find resource, (key) => key.substring(0, key.lastIndexOf '/').split '/'
          .join '/'

      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 ]

          if LOCALS[name] == undefined
            LOCALS[name] = @_find_code_root name

          @_hydrate_deps proto, (errors) =>
            if errors?
              deferred.reject errors
            else
              @_wrap_methods proto, (err) =>
                if err?
                  deferred.reject err
                else
                  @_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


Production config: fix OccurenceOrderPlugin arg

# Webpack Configuration

[Webpack](https://github.com/webpack/webpack) handles asset compilation (Sass, CoffeeScript, etc).
It also manages loading via JavaScript `require`, Sass `@import`, and CSS `url()`.

First, require the dependencies:

    webpack = require('webpack')
    fs      = require('fs')
    path    = require('path')
    _       = require('lodash')

Define an empty configuration:

    module.exports = {}

Entry bundles, i.e. package source paths. See [docs](http://webpack.github.io/docs/configuration.html#entry).

    entries = module.exports.entry =
      "main"            : "./src/scripts/main.litcoffee"
      "styles"          : "./src/styles/styles.scss"
      "vendor/es5-shim" : "./bower_components/es5-shim/es5-shim.js"
      "vendor/es5-sham" : "./bower_components/es5-shim/es5-sham.js"

Define compiled distribution output directory:

    outputDir = path.join(__dirname, "dist", "assets")

## Loaders

Define how files should be loaded (required) based on the extension.

### Scripts

Process CoffeeScript and JSX.

    jsLoaders = ["jsx"]
    scriptModLoaders = [
      { test: /\.coffee$/   , loaders: jsLoaders.concat(["coffee"]) }
      { test: /\.litcoffee$/, loaders: jsLoaders.concat(["coffee?literate"]) }
      { test: /\.js$/       , loaders: jsLoaders }
    ]

### Styles

Process Sass and use Autoprefixer.

    cssLoaders = ['style', 'css', 'autoprefixer-loader?browsers=last 2 versions']
    styleModLoaders = [
      { test: /\.scss$/, loaders: cssLoaders.concat([
          "sass?precision=10&outputStyle=expanded&sourceMap=true&includePaths[]=" + path.resolve(__dirname, './bower_components')]) }
      { test: /\.css$/ , loaders: cssLoaders }
    ]

### Static assets

Embed data-URLs into CSS and JS for small images and `.woff` fonts:

    staticModLoaders = [
      { test: /\.gif$/  , loader: "url?limit=10000&mimetype=image/gif" }
      { test: /\.jpg$/  , loader: "url?limit=10000&mimetype=image/jpg" }
      { test: /\.png$/  , loader: "url?limit=10000&mimetype=image/png" }
      { test: /\.woff$/ , loader: "url?limit=10000&mimetype=application/font-woff" }
      { test: /\.woff2$/, loader: "url?limit=10000&mimetype=application/font-woff2" }
      { test: /\.ttf$/  , loader: "file?mimetype=application/vnd.ms-fontobject" }
      { test: /\.eot$/  , loader: "file?mimetype=application/x-font-ttf" }
      { test: /\.svg$/  , loader: "file?mimetype=image/svg+xml" }
    ]

### Output CSS to `.css` files

`ExtractTextPlugin` is an experimental plugin to output CSS in `.css` and not as `.js` files with embedded CSS strings.

Require the plugin:

    ExtractTextPlugin = require("extract-text-webpack-plugin")

Set `styleModLoaders` to use the plugin:

    styleModLoaders = styleModLoaders.map (e) ->
      { test: e.test, loader: ExtractTextPlugin.extract(e.loaders.slice(1).join('!')) }

Create an instance of the extractTextPlugin:

    extractTextPlugin = new ExtractTextPlugin("[name].css", allChunks: true)

### Define macro variables

`DefinePlugin` defines variables to be substituted in the assets (a la macro).

Define `__PRODUCTION__: false` variable (set to true on `useProductionSettings()`):

    definePlugin = new webpack.DefinePlugin(
      __PRODUCTION__: JSON.stringify(false)
    )

### Generate a manifest

Generate a manifest mapping logical paths to actual paths:

    generateManifestPlugin = (compiler) ->
      @plugin 'done', (stats) ->
        stats = stats.toJson()

Set target path extension to `.css` for style assets, because we use `ExtractTextPlugin`:

        assetStats = stats.assetsByChunkName
        setCssExt = (p) -> p.replace(/\.js$/, '.css')
        for entryName, entryPath of assetStats when /\.(?:scss|sass|css)$/.test(entries[entryName])
          if _.isArray(entryPath)
            assetStats[entryName] = entryPath.map (p) -> setCssExt(p)
          else
            assetStats[entryName] = setCssExt(entryPath)

Write asset-ref -> asset-hash manifest to outputDir/stats.json

        fs.writeFileSync(path.join(outputDir, "asset-stats.json"), JSON.stringify(stats.assetsByChunkName, null, 2))

### Other options

    _.merge module.exports,

Set compilation target to "web". See [docs](http://webpack.github.io/docs/configuration.html#target).

      target: "web"

Set development options by default:

      cache: true
      debug: true
      # We are watching in Gulp, so tell webpack not to watch
      watch: false
      # watchDelay: 300
      devtool: 'source-map'

Output options:

      output:
        path         : outputDir
        publicPath   : "/assets/"
        filename     : "[name].js"
        chunkFilename: "[name].[id].[chunkhash].js"

Look for required files in bower and node

      resolve:
        modulesDirectories: [
          'src'
          'bower_components'
          'node_modules'
        ]

Define how modules should be loaded based on path extension:

      module:
        loaders: styleModLoaders.concat(scriptModLoaders).concat(staticModLoaders)

Define the plugins:

      plugins: [
        definePlugin
        extractTextPlugin
        generateManifestPlugin
      ]

## Production overrides

Export a method that applies production settings (used in gulpfile):

      mergeProductionConfig: (addHashes = true) ->

Production plugins:

Set `__PRODUCTION__` to true in the `DefinePlugin` instance:

        definePlugin.definitions.__PRODUCTION__ = JSON.stringify(true)

Add content hashes to the output filenames:

        _.merge @,
          output:
            filename: "[name]-[hash].js"

Tell `ExtractTextPlugin` to append hashes:

        extractTextPlugin.filename = '[name]-[hash].css'

Disable development settings:

        _.merge @,
          debug: false
          watch: false
          devtool: null

Turn on production optimizations:

          plugins: @plugins.concat [

Order the modules and chunks by occurrence. This saves space, because often referenced modules and chunks get smaller ids.

            new webpack.optimize.OccurenceOrderPlugin(true)

Minify JavaScript with UglifyJS:

            new webpack.optimize.UglifyJsPlugin()

          ]

[Learn more](https://github.com/webpack/docs/wiki/internal-webpack-plugins#optimize)
about optimization plugins shipped with Webpack.

# Webpack Configuration

[Webpack](https://github.com/webpack/webpack) handles asset compilation (Sass, CoffeeScript, etc).
It also manages loading via JavaScript `require`, Sass `@import`, and CSS `url()`.

First, require the dependencies:

    webpack = require('webpack')
    fs      = require('fs')
    path    = require('path')
    _       = require('lodash')

Define an empty configuration:

    module.exports = {}

Entry bundles, i.e. package source paths. See [docs](http://webpack.github.io/docs/configuration.html#entry).

    entries = module.exports.entry =
      "main"            : "./src/scripts/main.litcoffee"
      "styles"          : "./src/styles/styles.scss"
      "vendor/es5-shim" : "./bower_components/es5-shim/es5-shim.js"
      "vendor/es5-sham" : "./bower_components/es5-shim/es5-sham.js"

Define compiled distribution output directory:

    outputDir = path.join(__dirname, "dist", "assets")

## Loaders

Define how files should be loaded (required) based on the extension.

### Scripts

Process CoffeeScript and JSX.

    jsLoaders = ["jsx"]
    scriptModLoaders = [
      { test: /\.coffee$/   , loaders: jsLoaders.concat(["coffee"]) }
      { test: /\.litcoffee$/, loaders: jsLoaders.concat(["coffee?literate"]) }
      { test: /\.js$/       , loaders: jsLoaders }
    ]

### Styles

Process Sass and use Autoprefixer.

    cssLoaders = ['style', 'css', 'autoprefixer-loader?browsers=last 2 versions']
    styleModLoaders = [
      { test: /\.scss$/, loaders: cssLoaders.concat([
          "sass?precision=10&outputStyle=expanded&sourceMap=true&includePaths[]=" + path.resolve(__dirname, './bower_components')]) }
      { test: /\.css$/ , loaders: cssLoaders }
    ]

### Static assets

Embed data-URLs into CSS and JS for small images and `.woff` fonts:

    staticModLoaders = [
      { test: /\.gif$/  , loader: "url?limit=10000&mimetype=image/gif" }
      { test: /\.jpg$/  , loader: "url?limit=10000&mimetype=image/jpg" }
      { test: /\.png$/  , loader: "url?limit=10000&mimetype=image/png" }
      { test: /\.woff$/ , loader: "url?limit=10000&mimetype=application/font-woff" }
      { test: /\.woff2$/, loader: "url?limit=10000&mimetype=application/font-woff2" }
      { test: /\.ttf$/  , loader: "file?mimetype=application/vnd.ms-fontobject" }
      { test: /\.eot$/  , loader: "file?mimetype=application/x-font-ttf" }
      { test: /\.svg$/  , loader: "file?mimetype=image/svg+xml" }
    ]

### Output CSS to `.css` files

`ExtractTextPlugin` is an experimental plugin to output CSS in `.css` and not as `.js` files with embedded CSS strings.

Require the plugin:

    ExtractTextPlugin = require("extract-text-webpack-plugin")

Set `styleModLoaders` to use the plugin:

    styleModLoaders = styleModLoaders.map (e) ->
      { test: e.test, loader: ExtractTextPlugin.extract(e.loaders.slice(1).join('!')) }

Create an instance of the extractTextPlugin:

    extractTextPlugin = new ExtractTextPlugin("[name].css", allChunks: true)

### Define macro variables

`DefinePlugin` defines variables to be substituted in the assets (a la macro).

Define `__PRODUCTION__: false` variable (set to true on `useProductionSettings()`):

    definePlugin = new webpack.DefinePlugin(
      __PRODUCTION__: JSON.stringify(false)
    )

### Generate a manifest

Generate a manifest mapping logical paths to actual paths:

    generateManifestPlugin = (compiler) ->
      @plugin 'done', (stats) ->
        stats = stats.toJson()

Set target path extension to `.css` for style assets, because we use `ExtractTextPlugin`:

        assetStats = stats.assetsByChunkName
        setCssExt = (p) -> p.replace(/\.js$/, '.css')
        for entryName, entryPath of assetStats when /\.(?:scss|sass|css)$/.test(entries[entryName])
          if _.isArray(entryPath)
            assetStats[entryName] = entryPath.map (p) -> setCssExt(p)
          else
            assetStats[entryName] = setCssExt(entryPath)

Write asset-ref -> asset-hash manifest to outputDir/stats.json

        fs.writeFileSync(path.join(outputDir, "asset-stats.json"), JSON.stringify(stats.assetsByChunkName, null, 2))

### Other options

    _.merge module.exports,

Set compilation target to "web". See [docs](http://webpack.github.io/docs/configuration.html#target).

      target: "web"

Set development options by default:

      cache: true
      debug: true
      # We are watching in Gulp, so tell webpack not to watch
      watch: false
      # watchDelay: 300
      devtool: 'source-map'

Output options:

      output:
        path         : outputDir
        publicPath   : "/assets/"
        filename     : "[name].js"
        chunkFilename: "[name].[id].[chunkhash].js"

Look for required files in bower and node

      resolve:
        modulesDirectories: [
          'src'
          'bower_components'
          'node_modules'
        ]

Define how modules should be loaded based on path extension:

      module:
        loaders: styleModLoaders.concat(scriptModLoaders).concat(staticModLoaders)

Define the plugins:

      plugins: [
        definePlugin
        extractTextPlugin
        generateManifestPlugin
      ]

## Production overrides

Export a method that applies production settings (used in gulpfile):

      mergeProductionConfig: (addHashes = true) ->

Production plugins:

Set `__PRODUCTION__` to true in the `DefinePlugin` instance:

        definePlugin.definitions.__PRODUCTION__ = JSON.stringify(true)

Add content hashes to the output filenames:

        _.merge @,
          output:
            filename: "[name]-[hash].js"

Tell `ExtractTextPlugin` to append hashes:

        extractTextPlugin.filename = '[name]-[hash].css'

Disable development settings:

        _.merge @,
          debug: false
          watch: false
          devtool: null

Turn on production optimizations:

          plugins: @plugins.concat [

Order the modules and chunks by occurrence. This saves space, because often referenced modules and chunks get smaller ids.

            new webpack.optimize.OccurenceOrderPlugin(preferEntry: true)

Minify JavaScript with UglifyJS:

            new webpack.optimize.UglifyJsPlugin()

          ]

[Learn more](https://github.com/webpack/docs/wiki/internal-webpack-plugins#optimize)
about optimization plugins shipped with Webpack.


Reload page on jade template change

Reload page on jade template change

Equestria.tv Gulpfile
=========================

## Config

    autoprefixerConfig =
      browsers: ['> 5%']
      cascade: true

## Dependencies

#### Base Deps

    gulp = require 'gulp'
    concat = require 'gulp-concat'

#### Gulp Utils

    livereload = require 'gulp-livereload'
    plumber = require 'gulp-plumber'
    notify = require 'gulp-notify'

#### Browser Utilities

    autoprefixer = require 'gulp-autoprefixer'

#### Pre-compilers

    sass = require 'gulp-sass'

## Tasks

SCSS Compilation

    gulp.task 'css', () ->
      gulp.src 'resources/stylesheets/eqtv.scss'
        .pipe plumber({errorHandler: notify.onError("Error: <%= error.message %>")})
        .pipe sass()
        .pipe autoprefixer autoprefixerConfig
        .pipe gulp.dest 'www/css'
        .pipe notify 'Application SCSS has been compiled'

Copy fonts

    gulp.task 'copy:fonts', () ->
      gulp.src [
        'bower_components/bootstrap-sass/assets/fonts/**/*'
        'bower_components/font-awesome/fonts/**/*'
      ]
        .pipe gulp.dest('www/fonts')

Copy JS

    gulp.task 'copy:js', () ->
      gulp.src [
        'bower_components/nanoscroller/bin/javascripts/jquery.nanoscroller.js'
      ]
        .pipe gulp.dest('www/js/vendor')

Realtime Compilation

    gulp.task 'watch', ['build'], () ->
      livereload.listen();

      gulp.watch('resources/stylesheets/**/*.scss', ['css'])
      gulp.watch('www/css/eqtv.css').on 'change', livereload.changed
      gulp.watch('templates/**/*.jade').on 'change', livereload.changed

Build everything!

    gulp.task 'build', ['css', 'copy:fonts', 'copy:js']
    # Not much else to do here - everything has already run!

Default Task

    gulp.task 'default', ['build'] # All we do is call build!

Equestria.tv Gulpfile
=========================

## Config

    autoprefixerConfig =
      browsers: ['> 5%']
      cascade: true

## Dependencies

#### Base Deps

    gulp = require 'gulp'
    concat = require 'gulp-concat'

#### Gulp Utils

    livereload = require 'gulp-livereload'
    plumber = require 'gulp-plumber'
    notify = require 'gulp-notify'

#### Browser Utilities

    autoprefixer = require 'gulp-autoprefixer'

#### Pre-compilers

    sass = require 'gulp-sass'

## Tasks

SCSS Compilation

    gulp.task 'css', () ->
      gulp.src 'resources/stylesheets/eqtv.scss'
        .pipe plumber({errorHandler: notify.onError("Error: <%= error.message %>")})
        .pipe sass()
        .pipe autoprefixer autoprefixerConfig
        .pipe gulp.dest 'www/css'
        .pipe notify 'Application SCSS has been compiled'

Copy fonts

    gulp.task 'copy:fonts', () ->
      gulp.src [
        'bower_components/bootstrap-sass/assets/fonts/**/*'
        'bower_components/font-awesome/fonts/**/*'
      ]
        .pipe gulp.dest('www/fonts')

Copy JS

    gulp.task 'copy:js', () ->
      gulp.src [
        'bower_components/nanoscroller/bin/javascripts/jquery.nanoscroller.js'
      ]
        .pipe gulp.dest('www/js/vendor')

Realtime Compilation

    gulp.task 'watch', ['build'], () ->
      livereload.listen();

      gulp.watch('resources/stylesheets/**/*.scss', ['css'])
      gulp.watch('www/css/eqtv.css').on 'change', livereload.changed

Build everything!

    gulp.task 'build', ['css', 'copy:fonts', 'copy:js']
    # Not much else to do here - everything has already run!

Default Task

    gulp.task 'default', ['build'] # All we do is call build!


added helpers - localizer and region finder

# CLASS: Element
* Extends: [Evented][Evented]
* Parent: [Index][Parent]

A visual element.

---

    module.exports = class Element extends require 'ecl/dist/evented'

## CONSTRUCTOR

### new Element()

Creates an Element instance.

      constructor: ->
        super

Register validating listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Localize the **type** variable.

          do (type) =>

Add capturing listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:yes, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Add normal listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:no, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Register extendable listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Add capturing extendable listener

          @addListener type, this["#{type}CaptureListener"], yes

Add normal extendable listener

          @addListener type, this["#{type}Listener"], no

#### PARAMETERS
* **args** - named arguments

---

## PROPERTIES

---

## METHODS
### #localizeEventCoordinates(event) ->
* Returns: [Element][Element]

Helper method, to localize event coordinates.

      localizeEventCoordinates: (event) ->
        if event

If event already has localized **x**, use it instead of absolute **x**

          x = (if event.localX? then event.localX else event.x)
          event.localX = x - (@origin?.x or 0)

If event already has localized **y**, use it instead of absolute **y**

          y = (if event.localY? then event.localY else event.y)
          event.localY = y - (origin?.y or 0)

        return this
---

### #getEventRegions(event)
* Returns: [Object][Object] - named set of matching regions

Helper method, to get element regions that match the event.

      getEventRegions: (event) ->

Proceed only if event coordinates are localized

        if event and (x = event.localX)? and (y = event.localY)?
          result = {}

Walk through the element regions

          for name, $ of @regions

and add the region to the result if event localized coordinates are within
the region rectangle.

            if $[0] <= x <= ($[0] + $[2]) and $[1] <= y <= ($[1] + $[3])
              result[name] = $

        return result

---

## LISTENERS
### #mousemoveCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousemove** listener

      mousemoveCaptureListener: (event) ->

Store the event in the runtime for later

        @___runtime.mousemoveEvent = event
        return this

---

### #mousedownCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousedown** listener

      mousedownCaptureListener: (event) ->

Store the event in the runtime for later

        @___runtime.mousedownEvent = event
        return this

---

### #mouseupCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mouseup** listener

      mouseupCaptureListener: (event) ->

Store the event in the runtime for later

        @___runtime.mouseupEvent = event
        return this

---

### #mousemoveListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousemoveListener: -> this

---

### #mousedownListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousedownListener: -> this

---

### #mouseupListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mouseupListener: -> this

[Element]: ./element

[Parent]: ./index.litcoffee
[Evented]: https://nhzio.github.com/ecl/evented.html

# CLASS: Element
* Extends: [Evented][Evented]
* Parent: [Index][Parent]

A visual element.

---

    module.exports = class Element extends require 'ecl/dist/evented'

## CONSTRUCTOR

### new Element()

Creates an Element instance.

      constructor: ->
        super

Register validating listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Localize the **type** variable.

          do (type) =>

Add capturing listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:yes, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Add normal listener which will cancel and stop the event
if the event type is not enabled.

            @addListener type:type, capture:no, listener: (event) ->
              event.cancel().stop() unless @events?[type]

Register extendable listeners for each **type** from the list.

        for type in ['mousemove', 'mousedown', 'mouseup']

Add capturing extendable listener

          @addListener type, this["#{type}CaptureListener"], yes

Add normal extendable listener

          @addListener type, this["#{type}Listener"], no

#### PARAMETERS
* **args** - named arguments

---

## PROPERTIES

---

## METHODS
### #mousemoveCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousemove** listener

      mousemoveCaptureListener: (event) ->

Store the event in the runtime for later

        @___runtime.mousemoveEvent = event
        return this

---

### #mousedownCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mousedown** listener

      mousedownCaptureListener: (event) ->

Store the event in the runtime for later

        @___runtime.mousedownEvent = event
        return this

---

### #mouseupCaptureListener(event)
* Returns: [Element][Element]

Extendable capturing **mouseup** listener

      mouseupCaptureListener: (event) ->

Store the event in the runtime for later

        @___runtime.mouseupEvent = event
        return this

---

### #mousemoveListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousemoveListener: -> this

---

### #mousedownListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mousedownListener: -> this

---

### #mouseupListener(event)
* Returns: [Element][Element]

Extendable **mousemove** listener

      mouseupListener: -> this

[Element]: ./element

[Parent]: ./index.litcoffee
[Evented]: https://nhzio.github.com/ecl/evented.html


fix infinite loop for unbound and undefined methods

# Method - controller of functions

## Class Method

    debug = require('debug')('yang:method')
    Property = require('./property')

    class Method extends Property
      debug: -> debug @uri, arguments...

      get: (pattern) -> switch
        when pattern? then super arguments...
        when @binding? then @do.bind this
        else @data

### do ()

A convenience wrap to a Property instance that holds a function to
perform a Promise-based execution.

Always returns a Promise.

      do: (input={}, opts={}) ->
        unless (@binding instanceof Function) or (@data instanceof Function)
          return Promise.reject @error "cannot perform action on a property without function"
        @debug "[do] executing method: #{@name}"
        @debug input
        ctx = @parent?.context ? @context
        ctx = ctx.with opts, path: @path
        try
          # calling context is the parent node of the method
          input = @schema.input.apply input, this, force: true

          # first apply schema bound function (if availble), otherwise
          # execute assigned function (if available and not 'missing')
          if @binding?
            @debug "[do] calling bound function with: #{Object.keys(input)}"
            @debug @binding.toString()
            output = @binding? ctx, input
          else
            @debug "[do] calling assigned function: #{@data.name}"
            @debug @value
            @debug @data
            output = @data.call @parent.data, input, ctx

          output = await output
          { output } = @schema.output.eval { output }, this, force: true
          return output
        catch e
          @debug e
          return Promise.reject(e)

      update: (value, opts) ->
        super value, opts unless value instanceof Property

### toJSON

This call always returns undefined for the Method node.

      toJSON: (key) ->
        value = undefined
        value = "#{@name}": value if key is true
        return value

    module.exports = Method

# Method - controller of functions

## Class Method

    debug = require('debug')('yang:method')
    Property = require('./property')

    class Method extends Property
      debug: -> debug @uri, arguments...

      @property 'value',
        get: -> @state.value ? @do.bind this

      get: (pattern) -> switch
        when pattern? then super arguments...
        when @binding? then @do.bind this
        else @data

### do ()

A convenience wrap to a Property instance that holds a function to
perform a Promise-based execution.

Always returns a Promise.

      do: (input={}, opts={}) ->
        unless (@binding instanceof Function) or (@data instanceof Function)
          return Promise.reject @error "cannot perform action on a property without function"
        @debug "[do] executing method: #{@name}"
        @debug input
        ctx = @parent?.context ? @context
        ctx = ctx.with opts, path: @path
        try
          # calling context is the parent node of the method
          input = @schema.input.apply input, this, force: true

          # first apply schema bound function (if availble), otherwise
          # execute assigned function (if available and not 'missing')
          if @binding?
            @debug "[do] calling bound function with: #{Object.keys(input)}"
            @debug @binding.toString()
            output = @binding? ctx, input
          else
            @debug "[do] calling assigned function: #{@data.name}"
            @debug @value
            @debug @data
            output = @data.call @parent.data, input, ctx

          output = await output
          { output } = @schema.output.eval { output }, this, force: true
          return output
        catch e
          @debug e
          return Promise.reject(e)

      update: (value, opts) ->
        super value, opts unless value instanceof Property

### toJSON

This call always returns undefined for the Method node.

      toJSON: (key) ->
        value = undefined
        value = "#{@name}": value if key is true
        return value

    module.exports = Method