<commit_before>
(function(){
  Express = {
    version : '0.0.1',
    routes  : [],

    // --- Response

    response : {
      body : null,
      status : 200,
      headers : {},
      cookie : {}
    },

    // --- Defaults

    defaults : {
      cookie : {
        maxAge : 3600
      },
      route : {
        callback : function() {
          Express.status('Not Found')
          'Not Found'
        }
      }
    },

    hookCallbacks : {
      request : [

        // Headers hash

        function (request, response) {
          Express.request = request
          request.headers = Express.arrayToHash(request.headers)
        },

        // Cookie parsing

        function (request, response) {
          Express.response.cookie = request.cookie = Express.parseCookie(request.headers['Cookie'])
        }
      ],

      response : [
        function() {
          Express.header('Content-Length', (Express.response.body || '').length)
        }
      ]
    },

    /**
     * Invoke hook _name_ with _args_.
     *
     * @param  {string} name
     * @param  {...} args
     * @api public
     */

    hook : function(name, args) {
      if (this.hookCallbacks[name])
        for (i = 0, len = this.hookCallbacks[name].length; i < len; ++i)
          this.hookCallbacks[name][i].apply(this, this.argsArray(arguments, 1))
    },

    /**
     * Start express, binding to _port_.
     *
     * @param {int} port
     * @api public
     */

    start : function(port) {
      this.server.listen(port || 3000, function(request, response){
        Express.hook('request', request, response)
        request.uri.params = Express.parseNestedParams(request.uri.params)
        request.uri.path = Express.normalizePath(request.uri.path)
        Express.response.body = Express.callRouteFor(request)
        Express.prepareCookie()
        Express.hook('response')
        response.sendHeader(Express.response.status, Express.hashToArray(Express.response.headers))
        response.sendBody(Express.response.body || '')
        response.finish()
      })
    },

    server : {

      /**
       * Listen to _port_ with _callback_.
       *
       * @param {int} port
       * @param {function} callback
       * @api private
       */

      listen : function(port, callback) {
        node.http.createServer(callback).listen(port)
        puts('Express listening to http://localhost:' + port)
      }
    },

    prepareCookie : function() {
      p (this.response)
      var cookie = []
      for (var key in this.response.cookie)
        if (this.response.cookie.hasOwnProperty(key))
          cookie.push(key + '=' + this.response.cookie[key])
      if (cookie.length)
        this.header('Set-Cookie', cookie.join('; '))
    },

    /**
     * Return an associative array generated
     * from the key / value pairs in _hash_.
     *
     * @param  {hash} hash
     * @return {array}
     * @api public
     */

    hashToArray : function(hash) {
      var array = []
      for (var key in hash)
        if (hash.hasOwnProperty(key))
          array.push([key, hash[key]])
      return array
    },

    /**
     * Return hash generated from an
     * associative array.
     *
     * @param  {array} array
     * @return {hash}
     * @api public
     */

    arrayToHash : function(array) {
      var hash = {}
      for (i = 0, len = array.length; i < len; ++i)
        hash[array[i][0]] = array[i][1]
      return hash
    },

    /**
     * Set response status to _value_. Where value may be
     * a case-insensitive string such as 'Not Found', 'forbidden',
     * or a numeric HTTP response status code.
     *
     * @param  {int, string} value
     * @return {int}
     * @api public
     */

    status : function(value) {
      if (typeof value == 'number') return this.response.status = value
      for (var code in node.http.STATUS_CODES)
        if (node.http.STATUS_CODES.hasOwnProperty(code))
          if (node.http.STATUS_CODES[code].toLowerCase() == value.toLowerCase())
            return this.response.status = code
    },

    /**
     * Sets _name_ header to _value_. When _value_
     * is not present the value of the header _name_
     * will be returned (if available).
     *
     * @param {string} name
     * @param {string} value
     * @api public
     */

    header : function(name, value) {
      return value ? this.response.headers[name] = value :
               this.response.headers[name]
    },

    /**
     * Return param _key_'s value or _defaultValue_ when
     * the param has not been set.
     *
     * @param  {string} key
     * @param  {mixed} defaultValue
     * @return {mixed}
     * @api public
     */

    param : function(key, defaultValue) {
      return this.request.uri.params[key] || defaultValue
    },

    /**
     * Return cookie _key_. When _value_ is present
     * then a response cookie field will be set.
     *
     * @param  {string} key
     * @param  {string} value
     * @return {string, hash}
     * @api public
     */

    cookie : function(key, value) {
      return value ? this.response.cookie[key] = value :
               this.response.cookie[key]
    },

    /**
     * Parse _params_, splitting { user[info][name] : 'tj' } into
     * { user : { info : { name : 'tj' }}}
     *
     * @param  {hash} params
     * @return {hash}
     * @api public
     */

    parseNestedParams : function(params) {
      for (var key in params)
        if (params.hasOwnProperty(key))
          if (parts = key.split('['))
            if (parts.length > 1)
              for (i = 0, prop = params, len = parts.length; i < len; ++i) {
                if (i == len - 1) {
                  var name = parts[i].replace(']', '')
                  prop[name] = params[key]
                  prop = params, delete params[key]
                }
                else {
                  var name = parts[i].replace(']', '')
                  prop = prop[name] = prop[name] || {}
                }
              }

      return params
    },

    /**
     * Parse _cookie_ string into an object (hash).
     *
     * @param  {string} cookie
     * @return {hash}
     * @api public
     */

    parseCookie : function(cookie) {
      var hash = {}
      if (!cookie) return hash
      var attrs = cookie.split(/\s*;\s*/)
      for (i = 0; i < attrs.length; ++i)
        hash[attrs[i].split('=')[0]] = unescape(attrs[i].split('=')[1])
      return hash
    },

    /**
     * Normalize a path. Strips trailing / leading whitespace
     * and slashes ('/').
     *
     * @param  {string} path
     * @return {string}
     * @api public
     */

    normalizePath : function(path) {
      if (typeof path != 'string') return path
      return path.replace(/^(\s|\/)*|(\s|\/)*$/g, '')
    },

    /**
     * Normalize _path_. When a RegExp it is simply returned,
     * otherwise a string is converted to a regular expression
     * surrounded by ^$. So /user/:id/edit would become:
     *
     * \^/user/(.*?)\/edit\$/
     *
     * Each param key (:id) will be captured and placed in the
     * params array, so param('id') would give the string captured.
     *
     * @param  {string} path
     * @return {regexp}
     * @api public
     */

    pathToRegexp : function(path) {
      Express.regexpKeys = []
      if (path.constructor == RegExp) return path
      path = path.replace(/:(\w+)/g, function(_, key){
        Express.regexpKeys.push(key)
        return '(.*?)'
      })
      return new RegExp('^' + this.escapeRegexp(path, '/ [ ]') + '$', 'i')
    },

    /**
     * Escape RegExp _chars_ in _string_. Where _chars_
     * defaults to regular expression special characters.
     *
     * _chars_ should be a space delimited list of characters,
     * for example '[ ] ( )'.
     *
     * @param  {string} string
     * @param  {string} chars
     * @return {Type}
     * @api public
     */

    escapeRegexp : function(string, chars) {
      var specials = (chars || '/ . * + ? | ( ) [ ] { } \\').split(' ').join('|\\')
      return string.replace(new RegExp('(\\' + specials + ')', 'g'), '\\$1')
    },

    /**
     * Return the contents of a function body.
     *
     * @param  {function} body
     * @return {string}
     * @api public
     */

    contentsOf : function(body) {
      return body.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1]
    },

    /**
     * Eval _string_ in context of Express.
     *
     * @param  {string} string
     * @return {mixed}
     * @api public
     */

    eval : function(string) {
      return eval('with (Express){' + string + '}')
    },

    /**
     * Escape special characters in _html_.
     *
     * @param  {string} html
     * @return {string}
     * @api public
     */

    escape : function(html) {
      return html.
        replace(/&/g, '&').
        replace(/"/g, '"').
        replace(/</g, '<').
        replace(/>/g, '>')
    },

    /**
     * Convert native arguments object into an
     * array with optional _offset_.
     *
     * @param  {arguments} args
     * @param  {int} offset
     * @return {array}
     * @api public
     */

    argsArray : function(args, offset) {
      return Array.prototype.slice.call(args, offset)
    },

    /**
     * Check if _route_ matches the proper _request_ method.
     *
     * @param  {hash} route
     * @param  {hash} request
     * @return {bool}
     * @api private
     */

    routeMethod : function(route, request) {
      return route.method.toUpperCase() == request.method
    },

    /**
     * Check if _route_ matches provides the proper
     * encoding types listed in _request_'s Accept header.
     *
     * @param  {hash} route
     * @param  {hash} request
     * @return {bool}
     * @api private
     */

    routeProvides : function(route, request) {
      if (!route.options.provides) return true
      if (route.options.provides.constructor != Array)
        route.options.provides = [route.options.provides]
      for (i = 0, len = route.options.provides.length; i < len; ++i)
        if (request.headers['Accept'].match(route.options.provides[i]))
          return true
      return false
    },

    /**
     * Attept to match and call a route for
     * the given _request_, returning the data
     * returned by the route callback.
     *
     * @param  {object} request
     * @return {mixed}
     * @api private
     */

    callRouteFor : function(request) {
      var route = this.findRouteFor(request) || this.defaults.route
      if (route.keys)
        for (i = 0, len = route.keys.length; i < len; ++i)
          this.request.uri.params[route.keys[i]] = Express.captures[i+1] || null
      return this.eval(Express.contentsOf(route.callback)).toString()
    },

    /**
     * Attemp to find and return a route matching _request_.
     *
     * @param  {object} request
     * @return {object}
     * @api private
     */

    findRouteFor : function(request) {
      for (i = 0, len = this.routes.length; i < len; ++i)
        if (this.routeMatches(this.routes[i], request))
          return this.routes[i]
    },

    /**
     * Check if _route_ matches _request_
     *
     * @param  {object} route
     * @param  {object} request
     * @return {bool}
     * @api private
     */

    routeMatches : function(route, request) {
      // var conditions = [Express.routeMethod]
      // for (i = 0, len = conditions.length; i < len; ++i)
      //   if (!conditions[i](route, request))
      //     return false
      switch (route.path.constructor) {
        case String: return route.path == request.uri.path
        case RegExp: return !! (Express.captures = request.uri.path.match(route.path))
      }
    },

    /**
     * Return a routing function for _method_.
     *
     * @param  {string} method
     * @return {function}
     * @api private
     */

    routeFunctionFor : function(method) {
      return function(path, options, callback) {
        if (options.constructor == Function) callback = options, options = {}
        path = Express.pathToRegexp(Express.normalizePath(path))
        Express.routes.push({
          keys : Express.regexpKeys,
          path : path,
          method : method,
          options : options,
          callback : callback
        })
      }
    },

    readFile : function(path, callback, errorCallback) {
      var promise = node.fs.cat(path, "utf8")
      errorCallback = errorCallback || function(){
        throw "failed to read file `" + path + "'"
      }
      promise.addCallback(callback)
      promise.addErrback(errorCallback)
    },

    parseView : function(contents, context) {

    },

    display : function(path) {

    }
  }

  get = Express.routeFunctionFor('get')
  post = Express.routeFunctionFor('post')
  del = Express.routeFunctionFor('delete')
  put = Express.routeFunctionFor('put')

})()

get('user/:name/:operation', function(){
 p(request.headers['User-Agent'])
 p(request.headers['Accept'])
 p(request.headers['Accept-Encoding'])
 p(request.headers['Cookie'])
 p(request.cookie)
 param('operation') + 'ing ' + param('name')
})

get('cookies', function(){
  cookie('foo', 'bar')
  cookie('some-thing', 'some value')
  cookie('max-age', '1000')
  p(request.headers)
  p(response.headers)
  'Wahoo!'
})

get('articles', function(){
  display('spec/data/example.html.js')
  'list of articles'
})

get(/articles\/(\d+)/, function(){
  'article id ' + captures[1]
})

get('articles/:name', function(){
  if (param('name') == 'tj')
    'hello tj'
  else
    'article name ' + param('name')
})

Express.start()
<commit_msg>Moving code around<commit_after>
(function(){
  Express = {
    version : '0.0.1',
    routes  : [],

    // --- Response

    response : {
      body : null,
      status : 200,
      headers : {},
      cookie : {}
    },

    // --- Defaults

    defaults : {
      cookie : {
        maxAge : 3600
      },
      route : {
        callback : function() {
          Express.status('Not Found')
          'Not Found'
        }
      }
    },

    hookCallbacks : {
      request : [

        // Cookie parsing

        function (request, response) {
          Express.response.cookie = request.cookie = Express.parseCookie(request.headers['Cookie'])
        }
      ],

      response : [

        // Content length

        function() {
          Express.header('Content-Length', (Express.response.body || '').length)
        }
      ]
    },

    /**
     * Invoke hook _name_ with _args_.
     *
     * @param  {string} name
     * @param  {...} args
     * @api public
     */

    hook : function(name, args) {
      if (this.hookCallbacks[name])
        for (i = 0, len = this.hookCallbacks[name].length; i < len; ++i)
          this.hookCallbacks[name][i].apply(this, this.argsArray(arguments, 1))
    },

    /**
     * Start express, binding to _port_.
     *
     * @param {int} port
     * @api public
     */

    start : function(port) {
      this.server.listen(port || 3000, function(request, response){
        Express.request = request
        request.headers = Express.arrayToHash(request.headers)
        Express.hook('request', request, response)
        request.uri.params = Express.parseNestedParams(request.uri.params)
        request.uri.path = Express.normalizePath(request.uri.path)
        Express.response.body = Express.callRouteFor(request)
        Express.prepareCookie()
        Express.hook('response')
        response.sendHeader(Express.response.status, Express.hashToArray(Express.response.headers))
        response.sendBody(Express.response.body || '')
        response.finish()
      })
    },

    server : {

      /**
       * Listen to _port_ with _callback_.
       *
       * @param {int} port
       * @param {function} callback
       * @api private
       */

      listen : function(port, callback) {
        node.http.createServer(callback).listen(port)
        puts('Express listening to http://localhost:' + port)
      }
    },

    prepareCookie : function() {
      p (this.response)
      var cookie = []
      for (var key in this.response.cookie)
        if (this.response.cookie.hasOwnProperty(key))
          cookie.push(key + '=' + this.response.cookie[key])
      if (cookie.length)
        this.header('Set-Cookie', cookie.join('; '))
    },

    /**
     * Return an associative array generated
     * from the key / value pairs in _hash_.
     *
     * @param  {hash} hash
     * @return {array}
     * @api public
     */

    hashToArray : function(hash) {
      var array = []
      for (var key in hash)
        if (hash.hasOwnProperty(key))
          array.push([key, hash[key]])
      return array
    },

    /**
     * Return hash generated from an
     * associative array.
     *
     * @param  {array} array
     * @return {hash}
     * @api public
     */

    arrayToHash : function(array) {
      var hash = {}
      for (i = 0, len = array.length; i < len; ++i)
        hash[array[i][0]] = array[i][1]
      return hash
    },

    /**
     * Set response status to _value_. Where value may be
     * a case-insensitive string such as 'Not Found', 'forbidden',
     * or a numeric HTTP response status code.
     *
     * @param  {int, string} value
     * @return {int}
     * @api public
     */

    status : function(value) {
      if (typeof value == 'number') return this.response.status = value
      for (var code in node.http.STATUS_CODES)
        if (node.http.STATUS_CODES.hasOwnProperty(code))
          if (node.http.STATUS_CODES[code].toLowerCase() == value.toLowerCase())
            return this.response.status = code
    },

    /**
     * Sets _name_ header to _value_. When _value_
     * is not present the value of the header _name_
     * will be returned (if available).
     *
     * @param {string} name
     * @param {string} value
     * @api public
     */

    header : function(name, value) {
      return value ? this.response.headers[name] = value :
               this.response.headers[name]
    },

    /**
     * Return param _key_'s value or _defaultValue_ when
     * the param has not been set.
     *
     * @param  {string} key
     * @param  {mixed} defaultValue
     * @return {mixed}
     * @api public
     */

    param : function(key, defaultValue) {
      return this.request.uri.params[key] || defaultValue
    },

    /**
     * Return cookie _key_. When _value_ is present
     * then a response cookie field will be set.
     *
     * @param  {string} key
     * @param  {string} value
     * @return {string, hash}
     * @api public
     */

    cookie : function(key, value) {
      return value ? this.response.cookie[key] = value :
               this.response.cookie[key]
    },

    /**
     * Parse _params_, splitting { user[info][name] : 'tj' } into
     * { user : { info : { name : 'tj' }}}
     *
     * @param  {hash} params
     * @return {hash}
     * @api public
     */

    parseNestedParams : function(params) {
      for (var key in params)
        if (params.hasOwnProperty(key))
          if (parts = key.split('['))
            if (parts.length > 1)
              for (i = 0, prop = params, len = parts.length; i < len; ++i) {
                if (i == len - 1) {
                  var name = parts[i].replace(']', '')
                  prop[name] = params[key]
                  prop = params, delete params[key]
                }
                else {
                  var name = parts[i].replace(']', '')
                  prop = prop[name] = prop[name] || {}
                }
              }

      return params
    },

    /**
     * Parse _cookie_ string into an object (hash).
     *
     * @param  {string} cookie
     * @return {hash}
     * @api public
     */

    parseCookie : function(cookie) {
      var hash = {}
      if (!cookie) return hash
      var attrs = cookie.split(/\s*;\s*/)
      for (i = 0; i < attrs.length; ++i)
        hash[attrs[i].split('=')[0]] = unescape(attrs[i].split('=')[1])
      return hash
    },

    /**
     * Normalize a path. Strips trailing / leading whitespace
     * and slashes ('/').
     *
     * @param  {string} path
     * @return {string}
     * @api public
     */

    normalizePath : function(path) {
      if (typeof path != 'string') return path
      return path.replace(/^(\s|\/)*|(\s|\/)*$/g, '')
    },

    /**
     * Normalize _path_. When a RegExp it is simply returned,
     * otherwise a string is converted to a regular expression
     * surrounded by ^$. So /user/:id/edit would become:
     *
     * \^/user/(.*?)\/edit\$/
     *
     * Each param key (:id) will be captured and placed in the
     * params array, so param('id') would give the string captured.
     *
     * @param  {string} path
     * @return {regexp}
     * @api public
     */

    pathToRegexp : function(path) {
      Express.regexpKeys = []
      if (path.constructor == RegExp) return path
      path = path.replace(/:(\w+)/g, function(_, key){
        Express.regexpKeys.push(key)
        return '(.*?)'
      })
      return new RegExp('^' + this.escapeRegexp(path, '/ [ ]') + '$', 'i')
    },

    /**
     * Escape RegExp _chars_ in _string_. Where _chars_
     * defaults to regular expression special characters.
     *
     * _chars_ should be a space delimited list of characters,
     * for example '[ ] ( )'.
     *
     * @param  {string} string
     * @param  {string} chars
     * @return {Type}
     * @api public
     */

    escapeRegexp : function(string, chars) {
      var specials = (chars || '/ . * + ? | ( ) [ ] { } \\').split(' ').join('|\\')
      return string.replace(new RegExp('(\\' + specials + ')', 'g'), '\\$1')
    },

    /**
     * Return the contents of a function body.
     *
     * @param  {function} body
     * @return {string}
     * @api public
     */

    contentsOf : function(body) {
      return body.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1]
    },

    /**
     * Eval _string_ in context of Express.
     *
     * @param  {string} string
     * @return {mixed}
     * @api public
     */

    eval : function(string) {
      return eval('with (Express){' + string + '}')
    },

    /**
     * Escape special characters in _html_.
     *
     * @param  {string} html
     * @return {string}
     * @api public
     */

    escape : function(html) {
      return html.
        replace(/&/g, '&').
        replace(/"/g, '"').
        replace(/</g, '<').
        replace(/>/g, '>')
    },

    /**
     * Convert native arguments object into an
     * array with optional _offset_.
     *
     * @param  {arguments} args
     * @param  {int} offset
     * @return {array}
     * @api public
     */

    argsArray : function(args, offset) {
      return Array.prototype.slice.call(args, offset)
    },

    /**
     * Check if _route_ matches the proper _request_ method.
     *
     * @param  {hash} route
     * @param  {hash} request
     * @return {bool}
     * @api private
     */

    routeMethod : function(route, request) {
      return route.method.toUpperCase() == request.method
    },

    /**
     * Check if _route_ matches provides the proper
     * encoding types listed in _request_'s Accept header.
     *
     * @param  {hash} route
     * @param  {hash} request
     * @return {bool}
     * @api private
     */

    routeProvides : function(route, request) {
      if (!route.options.provides) return true
      if (route.options.provides.constructor != Array)
        route.options.provides = [route.options.provides]
      for (i = 0, len = route.options.provides.length; i < len; ++i)
        if (request.headers['Accept'].match(route.options.provides[i]))
          return true
      return false
    },

    /**
     * Attept to match and call a route for
     * the given _request_, returning the data
     * returned by the route callback.
     *
     * @param  {object} request
     * @return {mixed}
     * @api private
     */

    callRouteFor : function(request) {
      var route = this.findRouteFor(request) || this.defaults.route
      if (route.keys)
        for (i = 0, len = route.keys.length; i < len; ++i)
          this.request.uri.params[route.keys[i]] = Express.captures[i+1] || null
      return this.eval(Express.contentsOf(route.callback)).toString()
    },

    /**
     * Attemp to find and return a route matching _request_.
     *
     * @param  {object} request
     * @return {object}
     * @api private
     */

    findRouteFor : function(request) {
      for (i = 0, len = this.routes.length; i < len; ++i)
        if (this.routeMatches(this.routes[i], request))
          return this.routes[i]
    },

    /**
     * Check if _route_ matches _request_
     *
     * @param  {object} route
     * @param  {object} request
     * @return {bool}
     * @api private
     */

    routeMatches : function(route, request) {
      // var conditions = [Express.routeMethod]
      // for (i = 0, len = conditions.length; i < len; ++i)
      //   if (!conditions[i](route, request))
      //     return false
      switch (route.path.constructor) {
        case String: return route.path == request.uri.path
        case RegExp: return !! (Express.captures = request.uri.path.match(route.path))
      }
    },

    /**
     * Return a routing function for _method_.
     *
     * @param  {string} method
     * @return {function}
     * @api private
     */

    routeFunctionFor : function(method) {
      return function(path, options, callback) {
        if (options.constructor == Function) callback = options, options = {}
        path = Express.pathToRegexp(Express.normalizePath(path))
        Express.routes.push({
          keys : Express.regexpKeys,
          path : path,
          method : method,
          options : options,
          callback : callback
        })
      }
    },

    readFile : function(path, callback, errorCallback) {
      var promise = node.fs.cat(path, "utf8")
      errorCallback = errorCallback || function(){
        throw "failed to read file `" + path + "'"
      }
      promise.addCallback(callback)
      promise.addErrback(errorCallback)
    },

    parseView : function(contents, context) {

    },

    display : function(path) {

    }
  }

  get = Express.routeFunctionFor('get')
  post = Express.routeFunctionFor('post')
  del = Express.routeFunctionFor('delete')
  put = Express.routeFunctionFor('put')

})()

get('user/:name/:operation', function(){
 p(request.headers['User-Agent'])
 p(request.headers['Accept'])
 p(request.headers['Accept-Encoding'])
 p(request.headers['Cookie'])
 p(request.cookie)
 param('operation') + 'ing ' + param('name')
})

get('cookies', function(){
  cookie('foo', 'bar')
  cookie('some-thing', 'some value')
  cookie('max-age', '1000')
  p(request.headers)
  p(response.headers)
  'Wahoo!'
})

get('articles', function(){
  display('spec/data/example.html.js')
  'list of articles'
})

get(/articles\/(\d+)/, function(){
  'article id ' + captures[1]
})

get('articles/:name', function(){
  if (param('name') == 'tj')
    'hello tj'
  else
    'article name ' + param('name')
})

Express.start()
<|endoftext|>


<commit_before>
// Express - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)

process.mixin(GLOBAL, require('sys'))

// --- Route

Route = Class({
  init: function(method, path, fn, options){
    this.method = method
    this.path = path
    this.fn = fn
  },
  run: function(){
    return process.compile('with(Express.helpers){ (' + this.fn + ')() }', this.method + '("' + this.path + '")')
  }
})

// --- Router

Router = Class({
  route: function(request){
    this.request = request
    return this.matchingRoute().run()
  },

  matchingRoute: function(){
    for (var i = 0, len = Express.routes.length; i < len; ++i)
      if (this.match(Express.routes[i]))
        return Express.routes[i]
  },

  /**
   * Check if _route_ matches the current request.
   *
   * @param  {object} route
   * @return {bool}
   * @api private
   */

  match: function(route) {
    if (this.request.method.toLowerCase() == route.method)
      return route.path == this.request.uri.path
  }
})

// --- Server

Server = Class({
  port: 3000,
  host: 'localhost',
  router: new Router,
  run: function(host, port){
    var self = this
    if (host) this.host = host
    if (port) this.port = port
    require('http')
      .createServer(function(request, response){
        request.addListener('body', function(chunk){ request.body += chunk })
        request.addListener('complete', function(){ self.route(request, response) })
      })
      .listen(this.port, this.host)
    puts('Express started at http://' + this.host + ':' + this.port + '/')
  },
  route: function(request, response){
    this.request = request, this.response = response
    if (typeof (this.response.body = this.router.route(request)) == 'string')
      this.respond()
  },
  respond: function(body){
    if (body) this.response.body = body
    this.response.sendHeader(this.response.status || 404, this.response.headers || {})
    this.response.sendBody(this.response.body || '')
    this.response.finish()
  }
})

// --- Express

Express = {
  version: '0.0.1',
  routes: [],
  helpers: {},
  settings: {},
  server: new Server
}

// --- Helpers

/**
 * Return a routing function for _method_.
 *
 * @param  {string} method
 * @return {function}
 * @api private
 */

function route(method) {
  return function(path, options, fn){
    if (options instanceof Function)
      fn = options, options = {}
    Express.routes.push(new Route(method, path, fn, options))
  }
}

set = function(option, val) {
  return val == undefined ?
    Express.settings[option] :
      Express.settings[option] = val
}

enable = function(option) {
  set(option, true)
}

disable = function(option) {
  set(option, false)
}

// --- Routing API

get = view = route('get')
post = create = route('post')
del = destroy = route('delete')
put = update = route('put')
<commit_msg>Added normalizePath()<commit_after>
// Express - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)

process.mixin(GLOBAL, require('sys'))

// --- Route

Route = Class({
  init: function(method, path, fn, options){
    this.method = method
    this.path = normalizePath(path)
    this.fn = fn
  },
  run: function(){
    return process.compile('with(Express.helpers){ (' + this.fn + ')() }', this.method + '("' + this.path + '")')
  }
})

// --- Router

Router = Class({
  route: function(request){
    this.request = request
    return this.matchingRoute().run()
  },

  matchingRoute: function(){
    for (var i = 0, len = Express.routes.length; i < len; ++i)
      if (this.match(Express.routes[i]))
        return Express.routes[i]
  },

  /**
   * Check if _route_ matches the current request.
   *
   * @param  {object} route
   * @return {bool}
   * @api private
   */

  match: function(route) {
    if (this.request.method.toLowerCase() == route.method)
      return route.path == this.request.uri.path
  }
})

// --- Server

Server = Class({
  port: 3000,
  host: 'localhost',
  router: new Router,
  run: function(host, port){
    var self = this
    if (host) this.host = host
    if (port) this.port = port
    require('http')
      .createServer(function(request, response){
        request.addListener('body', function(chunk){ request.body += chunk })
        request.addListener('complete', function(){ self.route(request, response) })
      })
      .listen(this.port, this.host)
    puts('Express started at http://' + this.host + ':' + this.port + '/')
  },
  route: function(request, response){
    this.request = request, this.response = response
    this.request.uri.path = normalizePath(this.request.uri.path)
    if (typeof (this.response.body = this.router.route(request)) == 'string')
      this.respond()
  },
  respond: function(body){
    if (body) this.response.body = body
    this.response.sendHeader(this.response.status || 404, this.response.headers || {})
    this.response.sendBody(this.response.body || '')
    this.response.finish()
  }
})

// --- Express

Express = {
  version: '0.0.1',
  routes: [],
  helpers: {},
  settings: {},
  server: new Server
}

// --- Helpers

function normalizePath(path) {
  return path.replace(/[\s\/]*$/g, '')
}

/**
 * Return a routing function for _method_.
 *
 * @param  {string} method
 * @return {function}
 * @api private
 */

function route(method) {
  return function(path, options, fn){
    if (options instanceof Function)
      fn = options, options = {}
    Express.routes.push(new Route(method, path, fn, options))
  }
}

set = function(option, val) {
  return val == undefined ?
    Express.settings[option] :
      Express.settings[option] = val
}

enable = function(option) {
  set(option, true)
}

disable = function(option) {
  set(option, false)
}

// --- Routing API

get = view = route('get')
post = create = route('post')
del = destroy = route('delete')
put = update = route('put')
<|endoftext|>


<commit_before>/**
 * Send Google Analytics data to Graphite
 * Copyright (c) 2015, Peter Hedenskog
 * and other contributors
 * Released under the Apache 2.0 License
 */
'use strict';
var google = require('googleapis'),
	moment = require('moment'),
	util = require('./util'),
	GraphiteSender = require('./graphiteSender');

module.exports = {
	collect: function(conf) {
		var analytics = google.analytics('v3');

		var jwtClient = new google.auth.JWT(
			conf.email,
			conf.pemPath,
			null, ['https://www.googleapis.com/auth/analytics.readonly']
		);

		// setup the dates
		var dateFormat = 'YYYY-MM-DD';
		var endDate = moment().format(dateFormat);
		var startDate;
		var daysBack = 1;
		if (conf._.length === 1) {
			daysBack = conf._[0];
		}
		// default is one day back
		if (isNaN(daysBack)) {
			startDate = daysBack;
			endDate = daysBack;
			console.log('Fetch data from ' + startDate);

		} else {
			startDate = moment().subtract(daysBack, 'days').format(dateFormat);
			if (daysBack===1) {
				endDate = startDate;
			}
			console.log('Fetch data from ' + daysBack + ' day(s) back, starting from ' + startDate + ' to ' + endDate);
		}

		jwtClient.authorize(function(err, tokens) {
			if (err) {
				console.error('Couldn\'t authorize. Check your pem file, email and view id:' + err);
				return;
			} else {

				analytics.data.ga.get({
						auth: jwtClient,
						'ids': 'ga:' + conf.viewId,
						'metrics': conf.metrics,
						'start-date': startDate,
						'end-date': endDate,
						'dimensions': 'ga:hostname,ga:pagePath,ga:date,ga:hour' + ((conf.useMinutes === 'true') ? ',ga:minute' : ''),
						'sort': '-ga:pagePath',
						'max-results': conf.maxResults
					}, function(error, response) {
						if (error) {
							console.error('Couldn\'t fetch the data from GA:' + error);
							return;
						}

						if (conf.debug) {
							console.log('API response:' + JSON.stringify(response));
						}

						var metrics = [];

						response.columnHeaders.forEach(function(column) {
							if (column.columnType === 'METRIC') {
								metrics.push(column.name.substring(3));
							}
						});

						console.log('Got ' + response.rows.length + ' results, configured max result is ' + conf.maxResults);
						var result = getGraphiteData(metrics, response.rows, conf);
						if (conf.debug) {
							console.log('Sending the following data to Graphite:' + result);
						}
						var sender = new GraphiteSender(conf.graphiteHost, conf.graphitePort);
						sender.send(result, function() {console.log('Finished sending the metrics to Graphite');});
					}

				);
			}
		});
	}
};

function getGraphiteData(metrics, rows, conf) {
	var result = '';
	rows.forEach(function(row) {
		// the two first columns : domain and path
		var fullPath = row[0] + row[1];
		var time;
		var metricsArray;

		if (conf.useMinutes === 'true') {
			time = row[2] + ' ' + row[3] + ':' + row[4] + ':00';
			metricsArray = row.splice(5, row.length);
		} else {
			time = row[2] + ' ' + row[3] + ':00:00';
			metricsArray = row.splice(4, row.length);
		}

		var secondsSinceEpoch = (moment(time, 'YYYYMMDD HH:mm:ss')).unix();

		for (var i = 0; i < metricsArray.length; i++) {

			result += conf.graphiteNameSpace + '.' + util.getGraphiteURLKey('http://' + fullPath) + '.' + metrics[i] + ' ' + metricsArray[i] +
				' ' + secondsSinceEpoch + '\n';
		}
	});

	return result;
}
<commit_msg>dates back in time<commit_after>/**
 * Send Google Analytics data to Graphite
 * Copyright (c) 2015, Peter Hedenskog
 * and other contributors
 * Released under the Apache 2.0 License
 */
'use strict';
var google = require('googleapis'),
	moment = require('moment'),
	util = require('./util'),
	GraphiteSender = require('./graphiteSender');

module.exports = {
	collect: function(conf) {
		var analytics = google.analytics('v3');

		var jwtClient = new google.auth.JWT(
			conf.email,
			conf.pemPath,
			null, ['https://www.googleapis.com/auth/analytics.readonly']
		);

		// setup the dates
		var dateFormat = 'YYYY-MM-DD';
		var endDate = moment().format(dateFormat);
		var startDate;
		var daysBack = 1;
		if (conf._.length === 1) {
			daysBack = conf._[0];
		}
		// default is one day back
		if (isNaN(daysBack)) {
			startDate = daysBack;
			endDate = daysBack;
			console.log('Fetch data from ' + startDate);

		} else {
			startDate = moment().subtract(daysBack, 'days').format(dateFormat);
			endDate = moment().subtract(1, 'days').format(dateFormat);
			console.log('Fetch data from ' + daysBack + ' day(s) back, starting from ' + startDate + ' to ' + endDate);
		}

		jwtClient.authorize(function(err, tokens) {
			if (err) {
				console.error('Couldn\'t authorize. Check your pem file, email and view id:' + err);
				return;
			} else {

				analytics.data.ga.get({
						auth: jwtClient,
						'ids': 'ga:' + conf.viewId,
						'metrics': conf.metrics,
						'start-date': startDate,
						'end-date': endDate,
						'dimensions': 'ga:hostname,ga:pagePath,ga:date,ga:hour' + ((conf.useMinutes === 'true') ? ',ga:minute' : ''),
						'sort': '-ga:pagePath',
						'max-results': conf.maxResults
					}, function(error, response) {
						if (error) {
							console.error('Couldn\'t fetch the data from GA:' + error);
							return;
						}

						if (conf.debug) {
							console.log('API response:' + JSON.stringify(response));
						}

						var metrics = [];

						response.columnHeaders.forEach(function(column) {
							if (column.columnType === 'METRIC') {
								metrics.push(column.name.substring(3));
							}
						});

						if (response.rows.length === conf.maxResults) {
							console.log('Ooops we got ' + response.rows.length + ' rows from Google Analytics the same amount as the max results.');
						}

						var result = getGraphiteData(metrics, response.rows, conf);
						if (conf.debug) {
							console.log('Sending the following data to Graphite:' + result);
						}
						var sender = new GraphiteSender(conf.graphiteHost, conf.graphitePort);
						sender.send(result, function() {console.log('Finished sending the metrics to Graphite');});
					}

				);
			}
		});
	}
};

function getGraphiteData(metrics, rows, conf) {
	var result = '';
	rows.forEach(function(row) {
		// the two first columns : domain and path
		var fullPath = row[0] + row[1];
		var time;
		var metricsArray;

		if (conf.useMinutes === 'true') {
			time = row[2] + ' ' + row[3] + ':' + row[4] + ':00';
			metricsArray = row.splice(5, row.length);
		} else {
			time = row[2] + ' ' + row[3] + ':00:00';
			metricsArray = row.splice(4, row.length);
		}

		var secondsSinceEpoch = (moment(time, 'YYYYMMDD HH:mm:ss')).unix();

		for (var i = 0; i < metricsArray.length; i++) {

			result += conf.graphiteNameSpace + '.' + util.getGraphiteURLKey('http://' + fullPath) + '.' + metrics[i] + ' ' + metricsArray[i] +
				' ' + secondsSinceEpoch + '\n';
		}
	});

	return result;
}
<|endoftext|>


<commit_before>const request = require('request');
const keyval = require('../keyval');

const username = 'arnellebalane';
const endpoint = `https://api.github.com/users/${username}/repos?type=owner&sort=created`;

function fetchLatestRepositories() {
    const options = {
        url: endpoint,
        headers: {
            'Accept': 'applicaiton/vnd.github.v3+json',
            'User-Agent': username
        }
    };
    return new Promise((resolve, reject) => {
        request(options, (err, response, body) => {
            const data = JSON.parse(body);
            return keyval.set('github', data).then(resolve);
        });
    });
}

function insertLatestRepository(repository) {
    return keyval.get('github')
        .then((repositories) => {
            repositories = [repository, ...repositories];
            return keyval.set('github', repositories);
        })
        .catch(fetchLatestRepositories);
}

function getLatestRepositories() {
    return keyval.get('github').catch(fetchLatestRepositories);
}

function getFormattedLatestRepositories() {
    return getLatestRepositories().then((repositories) => {
        return repositories.map((repository) => ({
            name: repository.name,
            description: repository.description,
            url: repository.html_url
        }));
    });
}

exports.fetchLatestRepositories = fetchLatestRepositories;
exports.insertLatestRepository = insertLatestRepository;
exports.getLatestRepositories = getLatestRepositories;
exports.getFormattedLatestRepositories = getFormattedLatestRepositories;
<commit_msg>fix typo in accept header to github api request<commit_after>const request = require('request');
const keyval = require('../keyval');

const username = 'arnellebalane';
const endpoint = `https://api.github.com/users/${username}/repos?type=owner&sort=created`;

function fetchLatestRepositories() {
    const options = {
        url: endpoint,
        headers: {
            'Accept': 'application/vnd.github.v3+json',
            'User-Agent': username
        }
    };
    return new Promise((resolve, reject) => {
        request(options, (err, response, body) => {
            const data = JSON.parse(body);
            return keyval.set('github', data).then(resolve);
        });
    });
}

function insertLatestRepository(repository) {
    return keyval.get('github')
        .then((repositories) => {
            repositories = [repository, ...repositories];
            return keyval.set('github', repositories);
        })
        .catch(fetchLatestRepositories);
}

function getLatestRepositories() {
    return keyval.get('github').catch(fetchLatestRepositories);
}

function getFormattedLatestRepositories() {
    return getLatestRepositories().then((repositories) => {
        return repositories.map((repository) => ({
            name: repository.name,
            description: repository.description,
            url: repository.html_url
        }));
    });
}

exports.fetchLatestRepositories = fetchLatestRepositories;
exports.insertLatestRepository = insertLatestRepository;
exports.getLatestRepositories = getLatestRepositories;
exports.getFormattedLatestRepositories = getFormattedLatestRepositories;
<|endoftext|>


<commit_before>const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')

const passport = require('passport')
const GitHubStrategy = require('passport-github').Strategy

const authlib = require(path.join(path.dirname(require.main.filename), '../lib/authlib'))
const auth = require(path.join(path.dirname(require.main.filename), '../lib/game/api/auth'))

const app = new express.Router()

module.exports = function (config) {
  const clientId = process.env.GITHUB_CLIENT_ID || (config.auth.screepsrc.github && config.auth.screepsrc.github.clientId) || null
  const clientSecret = process.env.GITHUB_CLIENT_SECRET || (config.auth.screepsrc.github && config.auth.screepsrc.github.clientSecret) || null
  const enabled = !!(clientId && clientSecret)

  config.auth.info.github = enabled
  let registered = false

  app.use(cookieParser())

  app.get('/', (req, res, next) => {
    let { token } = req.query
    if (token) res.cookie('auth_token', token)
    if (!registered) {
      registered = true
      let proto = req.get('X-Forwarded-Proto') || req.protocol || 'http'
      let baseUrl = `${proto}://${req.get('host')}`
      passport.use('github', new GitHubStrategy({
        callbackURL: baseUrl + '/api/auth/github/return',
        clientID: clientId,
        clientSecret
      }, (accessToken, refreshTokem, profile, done) => done(null, profile.id)))
    }
    setTimeout(next, 100)
  }, passport.authenticate('github'))

  app.get('/return', passport.authenticate('github', { failureRedirect: '/' }), (req, res) => {
    let user = null
    let token = req.cookies.auth_token
    res.clearCookie('auth_token')
    if (token) user = authlib.checkToken(token)
    githubFindOrCreateUser(user, req.user)
      .then(user => authlib.genToken(user._id))
      .then(token => {
        let json = JSON.stringify({ username: req.user.username, token })
        res.end(`<html><body><script type="text/javascript">opener.postMessage(JSON.stringify(${json}), '*');window.close();</script></body>`)
      })
      .catch(err => res.end('Failed to auth'))
  })
    // })
  config.auth.router.use('/api/auth/github', app)
  config.auth.router.post('/api/user/unlink-github', auth.tokenAuth, (req, res) => {
    if (!req.user) return
    config.common.storage.db.users.update({ _id: req.user._id }, { $unset: { github: true }})
    res.json({ ok: 1 })
  })

  function githubFindOrCreateUser(user, id) {
    let { db, env } = config.common.storage
    if (user) {
      return user.then((user)=>{
        return db.users.update({ _id: user._id }, { $set: { github: { id }}})
          .then(()=>user)
      })
    }
    return db.users.findOne({ 'github.id': id })
      .then((user) => {
        if (user) return user
        user = {
          github: { id },
          cpu: 100,
          cpuAvailable: 0,
          registeredDate: new Date(),
          money: 0,
          gcl: 0
        };
        return db.users.insert(user)
          .then(result => {
            user = result;
            return db['users.code'].insert({
              user: user._id,
              modules: {main: ''},
              branch: 'default',
              activeWorld: true,
              activeSim: true
            })
          })
          .then(() => env.set('scrUserMemory:'+user._id, JSON.stringify({})))
          .then(() => user)
      })
  }
}
<commit_msg>Update GitHub with .writeHead<commit_after>const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')

const passport = require('passport')
const GitHubStrategy = require('passport-github').Strategy

const authlib = require(path.join(path.dirname(require.main.filename), '../lib/authlib'))
const auth = require(path.join(path.dirname(require.main.filename), '../lib/game/api/auth'))

const app = new express.Router()

module.exports = function (config) {
  const clientId = process.env.GITHUB_CLIENT_ID || (config.auth.screepsrc.github && config.auth.screepsrc.github.clientId) || null
  const clientSecret = process.env.GITHUB_CLIENT_SECRET || (config.auth.screepsrc.github && config.auth.screepsrc.github.clientSecret) || null
  const enabled = !!(clientId && clientSecret)

  config.auth.info.github = enabled
  let registered = false

  app.use(cookieParser())

  app.get('/', (req, res, next) => {
    let { token } = req.query
    if (token) res.cookie('auth_token', token)
    if (!registered) {
      registered = true
      let proto = req.get('X-Forwarded-Proto') || req.protocol || 'http'
      let baseUrl = `${proto}://${req.get('host')}`
      passport.use('github', new GitHubStrategy({
        callbackURL: baseUrl + '/api/auth/github/return',
        clientID: clientId,
        clientSecret
      }, (accessToken, refreshTokem, profile, done) => done(null, profile.id)))
    }
    setTimeout(next, 100)
  }, passport.authenticate('github'))

  app.get('/return', passport.authenticate('github', { failureRedirect: '/' }), (req, res) => {
    let user = null
    let token = req.cookies.auth_token
    res.clearCookie('auth_token')
    if (token) user = authlib.checkToken(token)
    githubFindOrCreateUser(user, req.user)
      .then(user => authlib.genToken(user._id))
      .then(token => {
        let json = JSON.stringify({ username: req.user.username, token })
        res.writeHead(200, { 'Content-Type':'text/html' }).end(`<html><body><script type="text/javascript">opener.postMessage(JSON.stringify(${json}), '*');window.close();</script></body></html>`)
      })
      .catch(err => res.end('Failed to auth'))
  })
    // })
  config.auth.router.use('/api/auth/github', app)
  config.auth.router.post('/api/user/unlink-github', auth.tokenAuth, (req, res) => {
    if (!req.user) return
    config.common.storage.db.users.update({ _id: req.user._id }, { $unset: { github: true }})
    res.json({ ok: 1 })
  })

  function githubFindOrCreateUser(user, id) {
    let { db, env } = config.common.storage
    if (user) {
      return user.then((user)=>{
        return db.users.update({ _id: user._id }, { $set: { github: { id }}})
          .then(()=>user)
      })
    }
    return db.users.findOne({ 'github.id': id })
      .then((user) => {
        if (user) return user
        user = {
          github: { id },
          cpu: 100,
          cpuAvailable: 0,
          registeredDate: new Date(),
          money: 0,
          gcl: 0
        };
        return db.users.insert(user)
          .then(result => {
            user = result;
            return db['users.code'].insert({
              user: user._id,
              modules: {main: ''},
              branch: 'default',
              activeWorld: true,
              activeSim: true
            })
          })
          .then(() => env.set('scrUserMemory:'+user._id, JSON.stringify({})))
          .then(() => user)
      })
  }
}
<|endoftext|>


<commit_before>'use strict';

var restify = require('restify');
var rewire = require('rewire');

// load controllers, using rewire for variable injection
var applications = rewire('./../controllers/applications');
var leaderboard = rewire('./../controllers/leaderboard');
var users = rewire('./../controllers/users');
var events = rewire('./../controllers/events');
var event_types = rewire('./../controllers/event_types');
var rules = rewire('./../controllers/rules');
var badges = rewire('./../controllers/badges');
var badge_cats = rewire('./../controllers/badge_categories');

// load db
var db = require('./../db/static');

// load message factory
var msg_fact = require('./../helpers/reply_message_factory');

var server = restify.createServer();
// Allow CORS response. Need to be called before the "server.listen"
server.use(restify.CORS());
server.use(restify.fullResponse());

server.use(restify.bodyParser()); // parse form data (post)
server.listen(8080, function () {
	console.log('%s listening at %s', server.name, server.url);
});

// TODO this is needed for your tests to pass.....
exports.awesome = function () {
	return 'awesome';
};

// configure controllers
var controllers = [applications, leaderboard, users, events,
	event_types, rules, badges, badge_cats];
for (var i = 0; i < controllers.length; i++) {
	controllers[i].__set__("db", db);
	controllers[i].__set__("msg_fact", msg_fact);
}

////////////////////////////////////////////////////////////////////////////////////
// Applications
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications', applications.findAll);
server.get('/applications/:appid', applications.findById);

// post
server.post('/applications', applications.create);

////////////////////////////////////////////////////////////////////////////////////
// Leaderboard
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/leaderboard', leaderboard.findAll);

////////////////////////////////////////////////////////////////////////////////////
// Users
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/users', users.findAll);
server.get('/applications/:appid/users/:userid', users.findById);
server.get('/applications/:appid/users/:userid/badges', users.findBadgesById);

// post
server.post('/applications/:appid/users', users.create);

// put
server.put('/applications/:appid/users/:userid', users.update);

// delete
server.del('/applications/:appid/users/:userid', users.remove);

////////////////////////////////////////////////////////////////////////////////////
// Events
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/events', events.findAll);
server.get('/applications/:appid/events/:eventid', events.findById);

// post
server.post('/applications/:appid/events', events.create);

////////////////////////////////////////////////////////////////////////////////////
// Event Types
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/events/types', event_types.findAll);
server.get('/applications/:appid/events/types/:typeid', event_types.findById);

// post
server.post('/applications/:appid/events/types', event_types.create);

////////////////////////////////////////////////////////////////////////////////////
// Rules
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/rules', rules.findAll);
server.get('/applications/:appid/rules/:ruleid', rules.findById);

// post
server.post('/applications/:appid/rules', rules.create);

// put
server.put('/applications/:appid/rules/:ruleid', rules.update);

// delete
server.del('/applications/:appid/rules/:ruleid', rules.remove);

////////////////////////////////////////////////////////////////////////////////////
// Badges
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/badges', badges.findAll);
server.get('/applications/:appid/badges/:badgeid', badges.findById);

// post
server.post('/applications/:appid/badges', badges.create);

// put
server.put('/applications/:appid/badges/:badgeid', badges.update);

////////////////////////////////////////////////////////////////////////////////////
// Badge Categories
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/badges/categories', badge_cats.findAll);
server.get('/applications/:appid/badges/categories', badge_cats.findById);

// post
server.post('/applications/:appid/badges/categories/', badge_cats.create);

// put
server.put('/applications/:appid/badges/categories/:categoryid', badge_cats.update);

////////////////////////////////////////////////////////////////////////////////////
// Trick for CORS... needed for angular
////////////////////////////////////////////////////////////////////////////////////

// Response to an unknow MethodHandler
// Validation scheme for CORS request: http://www.html5rocks.com/static/images/cors_server_flowchart.png
// Based on : https://github.com/mcavage/node-restify/issues/284
function unknownMethodHandler(req, res) {
	if (req.method.toLowerCase() === 'options') {
		//Angular.js send a x-resquested-with. The following line verify if the header is correct
		var allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'x-requested-with'];

		if (res.methods.indexOf('OPTIONS') === -1) {
			res.methods.push('OPTIONS');
		}

		res.header('Access-Control-Allow-Credentials', true);
		res.header('Access-Control-Allow-Origin', req.headers.origin);
		res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
		res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
		//response with "204 No content"
		return res.send(204);
	}
	else {
		return res.send(new restify.MethodNotAllowedError());
	}
}

server.on('MethodNotAllowed', unknownMethodHandler);
<commit_msg>corrected get category id request<commit_after>'use strict';

var restify = require('restify');
var rewire = require('rewire');

// load controllers, using rewire for variable injection
var applications = rewire('./../controllers/applications');
var leaderboard = rewire('./../controllers/leaderboard');
var users = rewire('./../controllers/users');
var events = rewire('./../controllers/events');
var event_types = rewire('./../controllers/event_types');
var rules = rewire('./../controllers/rules');
var badges = rewire('./../controllers/badges');
var badge_cats = rewire('./../controllers/badge_categories');

// load db
var db = require('./../db/static');

// load message factory
var msg_fact = require('./../helpers/reply_message_factory');

var server = restify.createServer();
// Allow CORS response. Need to be called before the "server.listen"
server.use(restify.CORS());
server.use(restify.fullResponse());

server.use(restify.bodyParser()); // parse form data (post)
server.listen(8080, function () {
	console.log('%s listening at %s', server.name, server.url);
});

// TODO this is needed for your tests to pass.....
exports.awesome = function () {
	return 'awesome';
};

// configure controllers
var controllers = [applications, leaderboard, users, events,
	event_types, rules, badges, badge_cats];
for (var i = 0; i < controllers.length; i++) {
	controllers[i].__set__("db", db);
	controllers[i].__set__("msg_fact", msg_fact);
}

////////////////////////////////////////////////////////////////////////////////////
// Applications
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications', applications.findAll);
server.get('/applications/:appid', applications.findById);

// post
server.post('/applications', applications.create);

////////////////////////////////////////////////////////////////////////////////////
// Leaderboard
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/leaderboard', leaderboard.findAll);

////////////////////////////////////////////////////////////////////////////////////
// Users
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/users', users.findAll);
server.get('/applications/:appid/users/:userid', users.findById);
server.get('/applications/:appid/users/:userid/badges', users.findBadgesById);

// post
server.post('/applications/:appid/users', users.create);

// put
server.put('/applications/:appid/users/:userid', users.update);

// delete
server.del('/applications/:appid/users/:userid', users.remove);

////////////////////////////////////////////////////////////////////////////////////
// Events
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/events', events.findAll);
server.get('/applications/:appid/events/:eventid', events.findById);

// post
server.post('/applications/:appid/events', events.create);

////////////////////////////////////////////////////////////////////////////////////
// Event Types
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/events/types', event_types.findAll);
server.get('/applications/:appid/events/types/:typeid', event_types.findById);

// post
server.post('/applications/:appid/events/types', event_types.create);

////////////////////////////////////////////////////////////////////////////////////
// Rules
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/rules', rules.findAll);
server.get('/applications/:appid/rules/:ruleid', rules.findById);

// post
server.post('/applications/:appid/rules', rules.create);

// put
server.put('/applications/:appid/rules/:ruleid', rules.update);

// delete
server.del('/applications/:appid/rules/:ruleid', rules.remove);

////////////////////////////////////////////////////////////////////////////////////
// Badges
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/badges', badges.findAll);
server.get('/applications/:appid/badges/:badgeid', badges.findById);

// post
server.post('/applications/:appid/badges', badges.create);

// put
server.put('/applications/:appid/badges/:badgeid', badges.update);

////////////////////////////////////////////////////////////////////////////////////
// Badge Categories
////////////////////////////////////////////////////////////////////////////////////

// get
server.get('/applications/:appid/badges/categories', badge_cats.findAll);
server.get('/applications/:appid/badges/categories/:categoryid', badge_cats.findById);

// post
server.post('/applications/:appid/badges/categories/', badge_cats.create);

// put
server.put('/applications/:appid/badges/categories/:categoryid', badge_cats.update);

////////////////////////////////////////////////////////////////////////////////////
// Trick for CORS... needed for angular
////////////////////////////////////////////////////////////////////////////////////

// Response to an unknow MethodHandler
// Validation scheme for CORS request: http://www.html5rocks.com/static/images/cors_server_flowchart.png
// Based on : https://github.com/mcavage/node-restify/issues/284
function unknownMethodHandler(req, res) {
	if (req.method.toLowerCase() === 'options') {
		//Angular.js send a x-resquested-with. The following line verify if the header is correct
		var allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'x-requested-with'];

		if (res.methods.indexOf('OPTIONS') === -1) {
			res.methods.push('OPTIONS');
		}

		res.header('Access-Control-Allow-Credentials', true);
		res.header('Access-Control-Allow-Origin', req.headers.origin);
		res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
		res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
		//response with "204 No content"
		return res.send(204);
	}
	else {
		return res.send(new restify.MethodNotAllowedError());
	}
}

server.on('MethodNotAllowed', unknownMethodHandler);
<|endoftext|>


<commit_before>import {
    a, abbr, address, article, aside,
    b, base,
    fieldset, legend, input,
    header, nav, form, button,
    label, select, option,
    div, ul, ol, li, dl, dd, dt,
    main, section, details, summary,
    dfn, sup, sub, i, strong, p, variable,
    htmldom, span
} from './htmldom';

import chai from 'chai';

const {
    Node,
    HTMLElement,
    HTMLAnchorElement,
    HTMLBaseElement,
    HTMLSpanElement,
} = window;
const { TEXT_NODE, ELEMENT_NODE } = Node;
const { assert } = chai;

describe('HTMLDOM library', () => {

    describe('Elements', () => {
        it('a', () => {
            const node = a({
                href : 'https://www.w3.org/TR/html',
                target : '_parent',
                download : 'spec.html',
                ping : 'https://www.w3.org',
                rel : 'external help',
                hreflang : 'en',
                type : 'text/html',
                referrerPolicy : 'no-referrer',
                children : 'HTML5 specification'
            });
            assert.equal(node.tagName, 'A');
            assert.equal(node.constructor, HTMLAnchorElement);

            assert(node.hasAttributes(), 'has attributes');
            assert.equal(node.attributes.length, 8);

            assert.equal(node.href, 'https://www.w3.org/TR/html');
            assert.equal(node.target, '_parent');
            assert.equal(node.download, 'spec.html');
            assert.equal(node.ping, 'https://www.w3.org');
            assert.equal(node.rel, 'external help');
            assert.equal(node.hreflang, 'en');
            assert.equal(node.type, 'text/html');
            assert.equal(node.referrerPolicy, 'no-referrer');

            assert.equal(node.textContent, 'HTML5 specification');
        });
        it('abbr', () => {
            const node = abbr({
                title : 'Hyper text markup language',
                children : 'HTML'
            });
            assert.equal(node.tagName, 'ABBR');
            assert.equal(node.constructor, HTMLElement);

            assert(node.hasAttributes(), 'has attributes');
            assert.equal(node.attributes.length, 1);
            assert.equal(node.title, 'Hyper text markup language');
            assert.equal(node.textContent, 'HTML');

            assert.equal(node.outerHTML, 'HTML');
        });
        it('address', () => {
            const node = address('test@example.com');

            assert.equal(node.tagName, 'ADDRESS');
            assert.equal(node.constructor, HTMLElement);

            assert(!node.hasAttributes(), 'has no attributes');
            assert.equal(node.textContent, 'test@example.com');

            assert.equal(node.outerHTML, '<address>test@example.com</address>');
        });
        it('article', () => {
            const node = article('Hello world!');

            assert.equal(node.tagName, 'ARTICLE');
            assert.equal(node.constructor, HTMLElement);

            assert(!node.hasAttributes(), 'has no attributes');
            assert.equal(node.textContent, 'Hello world!');

            assert.equal(node.outerHTML, '
Hello world!
');
        });
        it('aside', () => {
            const node = aside('Your advert may be here!');

            assert.equal(node.tagName, 'ASIDE');
            assert.equal(node.constructor, HTMLElement);

            assert(!node.hasAttributes(), 'has no attributes');
            assert.equal(node.textContent, 'Your advert may be here!');

            assert.equal(node.outerHTML, 'Your advert may be here!');
        });
        it('b', () => {
            const node = b('warning');

            assert.equal(node.tagName, 'B');
            assert.equal(node.constructor, HTMLElement);

            assert(!node.hasAttributes(), 'has no attributes');
            assert.equal(node.textContent, 'warning');

            assert.equal(node.outerHTML, 'warning');
        });
        it('base', () => {
            const node = base({ href : 'https://w3.org', target : '_top' });

            assert.equal(node.tagName, 'BASE');
            assert.equal(node.constructor, HTMLBaseElement);

            assert(node.hasAttributes(), 'has attributes');
            assert.equal(node.attributes.length, 2);
            assert(/^https:\/\/w3\.org\/?$/.test(node.href), 'proper href');
            assert.equal(node.target, '_top');

            assert(!node.hasChildNodes(), 'has no child nodes');
        });
    });

    describe('Various structures', () => {
        describe('Authorization fieldset', () => {
            it('properly build form authorization fieldset', () => {
                const element =
                    fieldset([
                        legend('Authorization'),
                        input({ type : 'email' }),
                        input({ type : 'password' })
                    ]);
                assert.equal(element.outerHTML,
                    '<fieldset>' +
                        '<legend>Authorization</legend>' +
                        '<input type="email">' +
                        '<input type="password">' +
                    '</fieldset>');
            });
        });
        describe('Header with navigation', () => {
            it('properly build header with navigational links inside', () => {
                const element =
                    header(nav([
                        a({ href : '/lib.html', textContent : 'Library' }),
                        a({ href : '/spec.html', textContent : 'Specifications' }),
                        a({ href : '/home.html', textContent : 'Go home' })
                    ]));
                assert.equal(element.outerHTML,
                    '' +
                        'Library' +
                        'Specifications' +
                        'Go home' +
                    '');
            });
        });
        describe('Select box widget', () => {
            let widget, selected;
            const element =
                label([
                    'Select technology ',
                    widget = select([
                        option('DOM'),
                        option('XML'),
                        selected = option({ selected : true, textContent : 'HTML' }),
                        option('SVG'),
                        option('MathML'),
                        option('WAI-ARIA')
                    ])
                ]);
            it('properly build label with select box option list inside', () => {
                assert.equal(element.outerHTML,
                    '' +
                        'Select technology ' +
                        '<select>' +
                            '<option>DOM</option>' +
                            '<option>XML</option>' +
                            '<option>HTML</option>' +
                            '<option>SVG</option>' +
                            '<option>MathML</option>' +
                            '<option>WAI-ARIA</option>' +
                        '</select>' +
                    '');
            });
            it('proper selected option reference', () => {
                assert.equal(widget.selectedOptions.length, 1);
                assert.equal(widget.selectedOptions[0], selected);
            });
        });
        describe('Search form', () => {
            it('properly build form with search input and submit button inside', () => {
                const element =
                    form({
                        attrset : { role : 'search' },
                        children : [
                            input({ type : 'search' }),
                            button('Search')
                        ]
                    });
                assert.equal(element.outerHTML,
                    '<form role="search">' +
                        '<input type="search">' +
                        '<button>Search</button>' +
                    '</form>');
            });
        });
        describe('Checkboxes', () => {
            let simple, checked, indeterminate;
            const element =
                div([
                    simple = input({ type : 'checkbox' }),
                    checked = input({ type : 'checkbox', checked : true }),
                    indeterminate = input({ type : 'checkbox', indeterminate : true })
                ]);
            it('proper HTML rendered', () => {
                assert.equal(element.outerHTML,
                    '
' +
                        '<input type="checkbox">' +
                        '<input type="checkbox">' +
                        '<input type="checkbox">' +
                    '
');
            });
            it('check current state of widgets', () => {
                assert(!simple.checked);
                assert(checked.checked);
                assert(indeterminate.indeterminate);
            });
            it('proper initial state assignment', () => {
                const sample = input({ type : 'checkbox', attrset : { checked : '' } });
                const container = div({ innerHTML : '<input type=checkbox checked>' });
                assert(sample.isEqualNode(container.firstChild));
            });
        });
        describe('Various list examples', () => {
            it('properly build ul + li', () => {
                assert.equal(
                    ul([
                        li('Ampeg'),
                        li('Fender'),
                        li('Warwick')
                    ]).outerHTML,
                    '
' +
                        '
Ampeg
' +
                        '
Fender
' +
                        '
Warwick
' +
                    '
'
                );
            });
            it('properly build ol + li', () => {
                assert.equal(
                    ol([
                        li('Moscow'),
                        li('Amsterdam'),
                        li('New York')
                    ]).outerHTML,
                    '
' +
                        '
Moscow
' +
                        '
Amsterdam
' +
                        '
New York
' +
                    '
'
                );
            });
            it('properly build dl + dt + dd', () => {
                assert.equal(
                    dl([
                        dt('DOM'),
                        dd('Document object model'),
                        dt('XML'),
                        dd('Extensible markup language'),
                        dt('HTML'),
                        dd('Hyper text markup language')
                    ]).outerHTML,
                    '
' +
                        '
DOM
' +
                        '
Document object model
' +
                        '
XML
' +
                        '
Extensible markup language
' +
                        '
HTML
' +
                        '
Hyper text markup language
' +
                    '
'
                );
            });
        });
        describe('Details with summary', () => {
            it('properly build widget', () => {
                const element =
                    details([
                        summary('Show details'),
                        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, ',
                        'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
                    ]);
                assert.equal(element.outerHTML,
                    '' +
                        'Show details' +
                        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, ' +
                        'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' +
                    '');
            });
        });
        describe('Other', () => {
            it('property build DOM fragment', () => {
                const element =
                    main([
                        section(dfn('htmlmodule — DOM assembler library')),
                        section(p([
                            variable('var'),
                            ' — is reserved JavaScript keyword, ',
                            'so we use `variable` function name instead.'
                        ])),
                        section([
                            sup('supertext'),
                            sub('subtext'),
                            i('alternative voice'),
                            strong('important!')
                        ])
                    ]);
                assert.equal(element.outerHTML,
                    '' +
                        '
<dfn>' +
                            'htmlmodule — DOM assembler library' +
                        '</dfn>
' +
                        '

' +
                            '<var>var</var>' +
                            ' — is reserved JavaScript keyword, ' +
                            'so we use `variable` function name instead.' +
                        '

' +
                        '
' +
                            'supertext' +
                            'subtext' +
                            'alternative voice' +
                            'important!' +
                        '
' +
                    '');
            });
            it('htmldom, span', () => {
                const node1 = htmldom('span', {
                    id : '00101',
                    className :'fa fi fu',
                    tabIndex : 0,
                    children : ['a', span('a b'), 'b']
                });
                const node2 = span({
                    id : '00101',
                    className :'fa fi fu',
                    tabIndex : 0,
                    children : ['a', span('a b'), 'b']
                });
                [node1, node2].forEach(node => {
                    assert.equal(node.nodeType, ELEMENT_NODE);
                    assert.equal(node.tagName, 'SPAN');
                    assert.equal(node.constructor, HTMLSpanElement);
                    assert.equal(node.attributes.length, 3);
                    assert.equal(node.id, '00101');
                    assert.equal(node.className, 'fa fi fu');
                    assert.equal(node.tabIndex, 0);
                    assert.equal(node.children.length, 1);
                    assert.equal(node.childNodes.length, 3);
                    assert.equal(node.childNodes[0].nodeType, TEXT_NODE);
                    assert.equal(node.childNodes[1].constructor, HTMLSpanElement);
                    assert.equal(node.childNodes[2].textContent, 'b');
                });
                assert(node1.isEqualNode(node2), 'htmldom() and span() work differently');
            });
        });
    });

});
<commit_msg>blockquote spec<commit_after>import {
    a, abbr, address, article, aside,
    b, base, blockquote,
    fieldset, legend, input,
    header, nav, form, button,
    label, select, option,
    div, ul, ol, li, dl, dd, dt,
    main, section, details, summary,
    dfn, sup, sub, i, strong, p, variable,
    htmldom, span
} from './htmldom';

import chai from 'chai';

const {
    Node,
    HTMLElement,
    HTMLAnchorElement,
    HTMLBaseElement,
    HTMLSpanElement,
} = window;
const { TEXT_NODE, ELEMENT_NODE } = Node;
const { assert } = chai;

describe('HTMLDOM library', () => {

    describe('Elements', () => {
        it('a', () => {
            const node = a({
                href : 'https://www.w3.org/TR/html',
                target : '_parent',
                download : 'spec.html',
                ping : 'https://www.w3.org',
                rel : 'external help',
                hreflang : 'en',
                type : 'text/html',
                referrerPolicy : 'no-referrer',
                children : 'HTML5 specification'
            });
            assert.equal(node.tagName, 'A');
            assert.equal(node.constructor, HTMLAnchorElement);

            assert(node.hasAttributes(), 'has attributes');
            assert.equal(node.attributes.length, 8);

            assert.equal(node.href, 'https://www.w3.org/TR/html');
            assert.equal(node.target, '_parent');
            assert.equal(node.download, 'spec.html');
            assert.equal(node.ping, 'https://www.w3.org');
            assert.equal(node.rel, 'external help');
            assert.equal(node.hreflang, 'en');
            assert.equal(node.type, 'text/html');
            assert.equal(node.referrerPolicy, 'no-referrer');

            assert(node.hasChildNodes(), 'has child nodes');

            assert.equal(node.textContent, 'HTML5 specification');
        });
        it('abbr', () => {
            const node = abbr({
                title : 'Hyper text markup language',
                children : 'HTML'
            });
            assert.equal(node.tagName, 'ABBR');
            assert.equal(node.constructor, HTMLElement);

            assert(node.hasAttributes(), 'has attributes');
            assert.equal(node.attributes.length, 1);
            assert.equal(node.title, 'Hyper text markup language');
            assert.equal(node.textContent, 'HTML');

            assert(node.hasChildNodes(), 'has child nodes');

            assert.equal(node.outerHTML, 'HTML');
        });
        it('address', () => {
            const node = address('test@example.com');

            assert.equal(node.tagName, 'ADDRESS');
            assert.equal(node.constructor, HTMLElement);

            assert(!node.hasAttributes(), 'has no attributes');
            assert.equal(node.textContent, 'test@example.com');

            assert(node.hasChildNodes(), 'has child nodes');

            assert.equal(node.outerHTML, '<address>test@example.com</address>');
        });
        it('article', () => {
            const node = article('Hello world!');

            assert.equal(node.tagName, 'ARTICLE');
            assert.equal(node.constructor, HTMLElement);

            assert(!node.hasAttributes(), 'has no attributes');
            assert.equal(node.textContent, 'Hello world!');

            assert(node.hasChildNodes(), 'has child nodes');

            assert.equal(node.outerHTML, '
Hello world!
');
        });
        it('aside', () => {
            const node = aside('Your advert may be here!');

            assert.equal(node.tagName, 'ASIDE');
            assert.equal(node.constructor, HTMLElement);

            assert(!node.hasAttributes(), 'has no attributes');
            assert.equal(node.textContent, 'Your advert may be here!');

            assert(node.hasChildNodes(), 'has child nodes');

            assert.equal(node.outerHTML, 'Your advert may be here!');
        });
        it('b', () => {
            const node = b('warning');

            assert.equal(node.tagName, 'B');
            assert.equal(node.constructor, HTMLElement);

            assert(!node.hasAttributes(), 'has no attributes');
            assert.equal(node.textContent, 'warning');

            assert(node.hasChildNodes(), 'has child nodes');

            assert.equal(node.outerHTML, 'warning');
        });
        it('base', () => {
            const node = base({ href : 'https://w3.org', target : '_top' });

            assert.equal(node.tagName, 'BASE');
            assert.equal(node.constructor, HTMLBaseElement);

            assert(node.hasAttributes(), 'has attributes');
            assert.equal(node.attributes.length, 2);
            assert(/^https:\/\/w3\.org\/?$/.test(node.href), 'proper href');
            assert.equal(node.target, '_top');

            assert(!node.hasChildNodes(), 'has no child nodes');
        });
        it('blockquote', () => {
            const node = blockquote({
                cite : 'https://html.spec.whatwg.org/#the-blockquote-element',
                children : 'The blockquote element represents a section that is quoted from another source.'
            });
            assert.equal(node.tagName, 'BLOCKQUOTE');
            assert.equal(node.constructor, HTMLQuoteElement);

            assert(node.hasAttributes(), 'has attributes');
            assert.equal(node.attributes.length, 1);
            assert.equal(node.cite, 'https://html.spec.whatwg.org/#the-blockquote-element');
            assert.equal(node.textContent, 'The blockquote element represents a section that is quoted from another source.');

            assert(node.hasChildNodes(), 'has child nodes');

            assert.equal(node.outerHTML,
                '
' +
                    'The blockquote element represents a section that is quoted from another source.' +
                '
');
        });
    });

    describe('Various structures', () => {
        describe('Authorization fieldset', () => {
            it('properly build form authorization fieldset', () => {
                const element =
                    fieldset([
                        legend('Authorization'),
                        input({ type : 'email' }),
                        input({ type : 'password' })
                    ]);
                assert.equal(element.outerHTML,
                    '<fieldset>' +
                        '<legend>Authorization</legend>' +
                        '<input type="email">' +
                        '<input type="password">' +
                    '</fieldset>');
            });
        });
        describe('Header with navigation', () => {
            it('properly build header with navigational links inside', () => {
                const element =
                    header(nav([
                        a({ href : '/lib.html', textContent : 'Library' }),
                        a({ href : '/spec.html', textContent : 'Specifications' }),
                        a({ href : '/home.html', textContent : 'Go home' })
                    ]));
                assert.equal(element.outerHTML,
                    '' +
                        'Library' +
                        'Specifications' +
                        'Go home' +
                    '');
            });
        });
        describe('Select box widget', () => {
            let widget, selected;
            const element =
                label([
                    'Select technology ',
                    widget = select([
                        option('DOM'),
                        option('XML'),
                        selected = option({ selected : true, textContent : 'HTML' }),
                        option('SVG'),
                        option('MathML'),
                        option('WAI-ARIA')
                    ])
                ]);
            it('properly build label with select box option list inside', () => {
                assert.equal(element.outerHTML,
                    '' +
                        'Select technology ' +
                        '<select>' +
                            '<option>DOM</option>' +
                            '<option>XML</option>' +
                            '<option>HTML</option>' +
                            '<option>SVG</option>' +
                            '<option>MathML</option>' +
                            '<option>WAI-ARIA</option>' +
                        '</select>' +
                    '');
            });
            it('proper selected option reference', () => {
                assert.equal(widget.selectedOptions.length, 1);
                assert.equal(widget.selectedOptions[0], selected);
            });
        });
        describe('Search form', () => {
            it('properly build form with search input and submit button inside', () => {
                const element =
                    form({
                        attrset : { role : 'search' },
                        children : [
                            input({ type : 'search' }),
                            button('Search')
                        ]
                    });
                assert.equal(element.outerHTML,
                    '<form role="search">' +
                        '<input type="search">' +
                        '<button>Search</button>' +
                    '</form>');
            });
        });
        describe('Checkboxes', () => {
            let simple, checked, indeterminate;
            const element =
                div([
                    simple = input({ type : 'checkbox' }),
                    checked = input({ type : 'checkbox', checked : true }),
                    indeterminate = input({ type : 'checkbox', indeterminate : true })
                ]);
            it('proper HTML rendered', () => {
                assert.equal(element.outerHTML,
                    '
' +
                        '<input type="checkbox">' +
                        '<input type="checkbox">' +
                        '<input type="checkbox">' +
                    '
');
            });
            it('check current state of widgets', () => {
                assert(!simple.checked);
                assert(checked.checked);
                assert(indeterminate.indeterminate);
            });
            it('proper initial state assignment', () => {
                const sample = input({ type : 'checkbox', attrset : { checked : '' } });
                const container = div({ innerHTML : '<input type=checkbox checked>' });
                assert(sample.isEqualNode(container.firstChild));
            });
        });
        describe('Various list examples', () => {
            it('properly build ul + li', () => {
                assert.equal(
                    ul([
                        li('Ampeg'),
                        li('Fender'),
                        li('Warwick')
                    ]).outerHTML,
                    '
' +
                        '
Ampeg
' +
                        '
Fender
' +
                        '
Warwick
' +
                    '
'
                );
            });
            it('properly build ol + li', () => {
                assert.equal(
                    ol([
                        li('Moscow'),
                        li('Amsterdam'),
                        li('New York')
                    ]).outerHTML,
                    '
' +
                        '
Moscow
' +
                        '
Amsterdam
' +
                        '
New York
' +
                    '
'
                );
            });
            it('properly build dl + dt + dd', () => {
                assert.equal(
                    dl([
                        dt('DOM'),
                        dd('Document object model'),
                        dt('XML'),
                        dd('Extensible markup language'),
                        dt('HTML'),
                        dd('Hyper text markup language')
                    ]).outerHTML,
                    '
' +
                        '
DOM
' +
                        '
Document object model
' +
                        '
XML
' +
                        '
Extensible markup language
' +
                        '
HTML
' +
                        '
Hyper text markup language
' +
                    '
'
                );
            });
        });
        describe('Details with summary', () => {
            it('properly build widget', () => {
                const element =
                    details([
                        summary('Show details'),
                        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, ',
                        'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
                    ]);
                assert.equal(element.outerHTML,
                    '' +
                        'Show details' +
                        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, ' +
                        'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' +
                    '');
            });
        });
        describe('Other', () => {
            it('property build DOM fragment', () => {
                const element =
                    main([
                        section(dfn('htmlmodule — DOM assembler library')),
                        section(p([
                            variable('var'),
                            ' — is reserved JavaScript keyword, ',
                            'so we use `variable` function name instead.'
                        ])),
                        section([
                            sup('supertext'),
                            sub('subtext'),
                            i('alternative voice'),
                            strong('important!')
                        ])
                    ]);
                assert.equal(element.outerHTML,
                    '' +
                        '
<dfn>' +
                            'htmlmodule — DOM assembler library' +
                        '</dfn>
' +
                        '

' +
                            '<var>var</var>' +
                            ' — is reserved JavaScript keyword, ' +
                            'so we use `variable` function name instead.' +
                        '

' +
                        '
' +
                            'supertext' +
                            'subtext' +
                            'alternative voice' +
                            'important!' +
                        '
' +
                    '');
            });
            it('htmldom, span', () => {
                const node1 = htmldom('span', {
                    id : '00101',
                    className :'fa fi fu',
                    tabIndex : 0,
                    children : ['a', span('a b'), 'b']
                });
                const node2 = span({
                    id : '00101',
                    className :'fa fi fu',
                    tabIndex : 0,
                    children : ['a', span('a b'), 'b']
                });
                [node1, node2].forEach(node => {
                    assert.equal(node.nodeType, ELEMENT_NODE);
                    assert.equal(node.tagName, 'SPAN');
                    assert.equal(node.constructor, HTMLSpanElement);
                    assert.equal(node.attributes.length, 3);
                    assert.equal(node.id, '00101');
                    assert.equal(node.className, 'fa fi fu');
                    assert.equal(node.tabIndex, 0);
                    assert.equal(node.children.length, 1);
                    assert.equal(node.childNodes.length, 3);
                    assert.equal(node.childNodes[0].nodeType, TEXT_NODE);
                    assert.equal(node.childNodes[1].constructor, HTMLSpanElement);
                    assert.equal(node.childNodes[2].textContent, 'b');
                });
                assert(node1.isEqualNode(node2), 'htmldom() and span() work differently');
            });
        });
    });

});
<|endoftext|>