<commit_before>'use strict'

var Store = require('./lib/store')
var responseKeys = [ 'status', 'message', 'header', 'body' ]

class Cache {
  configure(routes, options) {
    if (options.debug) {
      const util = require('util')

      options._debug = function() {
        process.stdout.write((new Date).toISOString() + ' ' + util.format.apply(null, arguments) + '\n')
      }
    }

    if (options.debug) options._debug('cache options:', options)
    this.routes = routes
    this.options = options

    return this
  }

  init() {
    if (!this.routes)
      this.routes = { '*': 'increasing' }

    if (!this.options)
      this.options = {}

    this.options.expireOpts = new Map()
    this.defaultTimeout = 5000
    this.store = new Store(this.options)

    for (let key of Object.keys(this.routes)) {
      // validate and reorganize route values
      if (typeof this.routes[key] !== 'object'
        && typeof this.routes[key] !== 'boolean'
        && this.routes[key] !== 'increasing'
        && isNaN(this.routes[key])) {

        if (this.options.debug) this.options._debug('invalid value for key', key)

        delete this.routes[key]
        continue
      }

      if (!isNaN(this.routes[key]))
        this.routes[key] = {
          timeout: this.routes[key]
        }
      else if (this.routes[key] === 'increasing') {
        this.routes[key] = {
          timeout: 'increasing'
        }

        if (!this.callCnt) this.callCnt = new Map()
      }

      if (this.routes[key].cacheKeyArgs instanceof Array) {
        if (this.options.debug) this.options._debug('cacheKeyArgs of array type not supported:', key)
        delete this.routes[key]
        continue
      }

      if (typeof this.routes[key].cacheKeyArgs === 'string') {
        this.routes[key].cacheKeyArgs = {
          custom: this.routes[key].cacheKeyArgs
        }
      }

      if (this.routes[key].cacheKeyArgs && typeof this.routes[key].cacheKeyArgs.headers === 'string') {
        this.routes[key].cacheKeyArgs.headers = [ this.routes[key].cacheKeyArgs.headers ]
      }

      if (this.routes[key].cacheKeyArgs && typeof this.routes[key].cacheKeyArgs.query === 'string') {
        this.routes[key].cacheKeyArgs.query = [ this.routes[key].cacheKeyArgs.query ]
      }

      // parse caching route params
      if (key.indexOf(':') !== -1) {
        this.routes[key]['regex'] = new RegExp(
          key.replace(/:[A-z0-9]+/g, '[A-z0-9]+')
          .replace(/^\//, '^\/')
          .replace(/$/, '(?:\/)?$')
          .replace(/\//g, '\\/'))

      }

      if (key.indexOf('*') !== -1) {
        this.routes[key]['regex'] = new RegExp(
          key.replace('*', '.*'))
      }
    }

    this.routeKeys = Object.keys(this.routes)
    this.routeKeysLength = this.routeKeys.length

    // set default increasing options if not defined
    if (this.callCnt) {
      if (this.options.increasing === undefined) {
        this.options.increasing = {
          1: 5000,
          3: 15000,
          10: 30000,
          20: 60000,
          50: 120000
        }
      }

      this.cntStep = Object.keys(this.options.increasing)

      for (let key of this.cntStep) {
        if (typeof this.options.increasing[key] === 'string') {
          if (this.options.increasing[key].search(/[0-9]+s$/) !== -1)
            this.options.increasing[key] = Number(this.options.increasing[key].replace('s', '')) * 1000
          else if (this.options.increasing[key].search(/[0-9]+m$/) !== -1)
            this.options.increasing[key] = Number(this.options.increasing[key].replace('m', '')) * 60000
          else if (this.options.increasing[key].search(/[0-9]+h$/) !== -1)
            this.options.increasing[key] = Number(this.options.increasing[key].replace('h', '')) * 60000 * 60
          else if (this.options.increasing[key].search(/[0-9]+d$/) !== -1)
            this.options.increasing[key] = Number(this.options.increasing[key].replace('d', '')) * 60000 * 60 * 24
          else {
            if (this.options.debug) this.options._debug('increasing timeout value invalid:', this.options.increasing[key])
            delete this.options.increasing[key]
          }
        }
      }

      // clear call hit counter every minute
      setInterval(() => {
        if (this.options.debug) this.options._debug('clearing call hit counter')
        this.callCnt = new Map()
      }, 60000)
    }

    return this
  }

  middleware() {
    var that = this

    if (!this.store) this.init()

    return function *(next) {
      try {
        // check if route is permitted to be cached FIXME?
        if (!that.routeKeysLength) return yield next;

        // create key
        let cacheKey, requestKey = this.request.path

        for (let i = 0; i < that.routeKeysLength; i++) {
          cacheKey = that.routeKeys[i]

          // first pass - exact match
          if (cacheKey === this.request.path) {
            if (that.options.debug)
              that.options._debug('exact matched route:', this.request.path)

            if (that.routes[cacheKey].cacheKeyArgs)
              requestKey = yield setRequestKey(requestKey, cacheKey, this.request)

            let ok = yield setExpires(i, requestKey)
            if (!ok) return yield next

            break
          }
          else if (!that.routes[that.routeKeys[i]].regex) continue

          // second pass - regex match
          else if (that.routes[that.routeKeys[i]].regex.test(this.request.path)) {
            if (that.options.debug)
              that.options._debug('regex matched route:', this.request.url, that.routes[that.routeKeys[i]].regex)

            if (that.routes[cacheKey].cacheKeyArgs)
              requestKey = yield setRequestKey(requestKey, cacheKey, this.request)

            let ok = yield setExpires(i, requestKey)
            if (!ok) return yield next

            break
          }

          if (i === that.routeKeys.length - 1) return yield next
          else continue
        }

        // check if no-cache is provided
        if (this.request.header['cache-control'] === 'no-cache') {
          return yield next
        }

        // check if HTTP methods other than GET are sent and invalidate cache if true
        if (this.request.method !== 'GET') {
          for (let i = 0; i < that.routeKeysLength; i++) {
            let key = that.routeKeys[i]

            if (requestKey.indexOf(key) != -1) {
              that.store.remove(requestKey)
            }
          }
          return yield next
        }

        // return cached response
        let requestKeyHeaders, requestKeyBody

        if ('undefined' !== typeof that.routes[cacheKey].cacheKeyPrefix) {
          requestKeyHeaders = that.routes[cacheKey].cacheKeyPrefix + ':' + requestKey + ':headers'
          requestKeyBody = that.routes[cacheKey].cacheKeyPrefix + ':' + requestKey + ':body'
        }
        else if ('undefined' !== typeof that.options.cacheKeyPrefix) {
          requestKeyHeaders = that.options.cacheKeyPrefix + ':' + requestKey + ':headers'
          requestKeyBody = that.options.cacheKeyPrefix + ':' + requestKey + ':body'
        }
        else {
          requestKeyHeaders = requestKey + ':headers'
          requestKeyBody = requestKey + ':body'
        }

        let exists = yield that.store.has(requestKeyHeaders)

        if (exists) {
          let body, headers = yield that.store.get(requestKeyHeaders)

          if ('string' === typeof(headers)) headers = JSON.parse(headers)
          if (that.options.debug) that.options._debug('returning from cache for url', requestKey)

          for (let key in headers) {
            if (key === 'header') {
              let value = headers[key]

              for (let hkey in value) {
                this.set(hkey, value[hkey])
              }

              continue
            }

            this[key] = headers[key]
          }

          if (this.type === 'application/octet-stream' || this.type.indexOf('image/' !== -1))
            body = yield that.store.getBuffer(requestKeyBody)
          else
            body = yield that.store.get(requestKeyBody)

          if (body) this['body'] = body
          return
        }

        // call next middleware and cache response on return
        yield next

        let _response_body, _response_headers = new Object()

        for (let key in this.response) {
          if (key === 'body') continue

          if (responseKeys.indexOf(key) !== -1)
            _response_headers[key] = this.response[key]
        }

        if (this.response.body)
          _response_body = this.response.body

        if (that.options.debug) that.options._debug('caching', requestKey)

        // set new caching entry
        let storeRequest = {}
        storeRequest[requestKeyHeaders] = JSON.stringify(_response_headers)
        storeRequest[requestKeyBody] = _response_body

        that.store.setMultiple(requestKey, storeRequest)
      }
      catch (error) {
        if (that.options.debug) console.error(error)
        this.throw(error)
      }
    }

    function *setExpires(routeKeysIndex, requestKey) {
      let routeExpire = that.routes[that.routeKeys[routeKeysIndex]].timeout

      if (routeExpire === false) {
        return false
      }

      // override default timeout
      if (typeof routeExpire === 'boolean') routeExpire = that.options.defaultTimeout
      else if (routeExpire === 'increasing' && that.options.increasing) {
        let count = that.callCnt.has(requestKey)

        if (count) {
          count = that.callCnt.get(requestKey) + 1
          that.callCnt.set(requestKey, count)
          let steps = that.cntStep.length

          for (let i = 0; i < steps; i++) {
            if (count === that.cntStep[i]) {
              that.options.expireOpts.set(requestKey, that.options.increasing[that.cntStep[i]])
              break
            }
          }
        }
        else {
          that.callCnt.set(requestKey, 1)
          that.options.expireOpts.set(requestKey, that.options.increasing[that.cntStep[0]])
        }
      }
      else that.options.expireOpts.set(requestKey, routeExpire)

      return true
    }

    function *setRequestKey(requestKey, routeKey, ctx) {
      // append specified http headers to requestKey
      if (that.routes[routeKey].cacheKeyArgs.headers instanceof Array) {
        requestKey += '#'

        for (let name of that.routes[routeKey].cacheKeyArgs.headers) {
          requestKey += ctx.header[name]
        }
      }

      // ...or append all http headers to requestKey
      else if (that.routes[routeKey].cacheKeyArgs.headers === true) {
        requestKey += '#'

        for (let name of Object.keys(ctx.headers)) {
          requestKey += ctx.headers[name]
        }
      }

      // append specified http url query parameters to requestKey
      if (that.routes[routeKey].cacheKeyArgs.query instanceof Array) {
        requestKey += '?'

        for (let name of Object.keys(ctx.query)) {
          requestKey += ctx.query[name]
        }
      }

      // ...or append all http url query parameters to requestKey
      else if (that.routes[routeKey].cacheKeyArgs.query === true)
        requestKey += '?' + ctx.querystring

      return requestKey
    }
  }

  clear(keys) {
    if (!keys) {
      if (this.options.cacheKeyPrefix)
        this.store.remove(this.options.cacheKeyPrefix + ':*')
      else
        this.store.remove()

      return
    }

    if (this.options.cacheKeyPrefix)
      this.store.remove(this.options.cacheKeyPrefix + ':' + keys)
    else
      this.store.remove(keys)
  }

  currentCacheType() {
    return this.store.storeType()
  }
}

module.exports = new Cache()
<commit_msg>use const instead of var for module imports<commit_after>'use strict'

const Store = require('./lib/store')
const responseKeys = [ 'status', 'message', 'header', 'body' ]

class Cache {
  configure(routes, options) {
    if (options.debug) {
      const util = require('util')

      options._debug = function() {
        process.stdout.write((new Date).toISOString() + ' ' + util.format.apply(null, arguments) + '\n')
      }
    }

    if (options.debug) options._debug('cache options:', options)
    this.routes = routes
    this.options = options

    return this
  }

  init() {
    if (!this.routes)
      this.routes = { '*': 'increasing' }

    if (!this.options)
      this.options = {}

    this.options.expireOpts = new Map()
    this.defaultTimeout = 5000
    this.store = new Store(this.options)

    for (let key of Object.keys(this.routes)) {
      // validate and reorganize route values
      if (typeof this.routes[key] !== 'object'
        && typeof this.routes[key] !== 'boolean'
        && this.routes[key] !== 'increasing'
        && isNaN(this.routes[key])) {

        if (this.options.debug) this.options._debug('invalid value for key', key)

        delete this.routes[key]
        continue
      }

      if (!isNaN(this.routes[key]))
        this.routes[key] = {
          timeout: this.routes[key]
        }
      else if (this.routes[key] === 'increasing') {
        this.routes[key] = {
          timeout: 'increasing'
        }

        if (!this.callCnt) this.callCnt = new Map()
      }

      if (this.routes[key].cacheKeyArgs instanceof Array) {
        if (this.options.debug) this.options._debug('cacheKeyArgs of array type not supported:', key)
        delete this.routes[key]
        continue
      }

      if (typeof this.routes[key].cacheKeyArgs === 'string') {
        this.routes[key].cacheKeyArgs = {
          custom: this.routes[key].cacheKeyArgs
        }
      }

      if (this.routes[key].cacheKeyArgs && typeof this.routes[key].cacheKeyArgs.headers === 'string') {
        this.routes[key].cacheKeyArgs.headers = [ this.routes[key].cacheKeyArgs.headers ]
      }

      if (this.routes[key].cacheKeyArgs && typeof this.routes[key].cacheKeyArgs.query === 'string') {
        this.routes[key].cacheKeyArgs.query = [ this.routes[key].cacheKeyArgs.query ]
      }

      // parse caching route params
      if (key.indexOf(':') !== -1) {
        this.routes[key]['regex'] = new RegExp(
          key.replace(/:[A-z0-9]+/g, '[A-z0-9]+')
          .replace(/^\//, '^\/')
          .replace(/$/, '(?:\/)?$')
          .replace(/\//g, '\\/'))

      }

      if (key.indexOf('*') !== -1) {
        this.routes[key]['regex'] = new RegExp(
          key.replace('*', '.*'))
      }
    }

    this.routeKeys = Object.keys(this.routes)
    this.routeKeysLength = this.routeKeys.length

    // set default increasing options if not defined
    if (this.callCnt) {
      if (this.options.increasing === undefined) {
        this.options.increasing = {
          1: 5000,
          3: 15000,
          10: 30000,
          20: 60000,
          50: 120000
        }
      }

      this.cntStep = Object.keys(this.options.increasing)

      for (let key of this.cntStep) {
        if (typeof this.options.increasing[key] === 'string') {
          if (this.options.increasing[key].search(/[0-9]+s$/) !== -1)
            this.options.increasing[key] = Number(this.options.increasing[key].replace('s', '')) * 1000
          else if (this.options.increasing[key].search(/[0-9]+m$/) !== -1)
            this.options.increasing[key] = Number(this.options.increasing[key].replace('m', '')) * 60000
          else if (this.options.increasing[key].search(/[0-9]+h$/) !== -1)
            this.options.increasing[key] = Number(this.options.increasing[key].replace('h', '')) * 60000 * 60
          else if (this.options.increasing[key].search(/[0-9]+d$/) !== -1)
            this.options.increasing[key] = Number(this.options.increasing[key].replace('d', '')) * 60000 * 60 * 24
          else {
            if (this.options.debug) this.options._debug('increasing timeout value invalid:', this.options.increasing[key])
            delete this.options.increasing[key]
          }
        }
      }

      // clear call hit counter every minute
      setInterval(() => {
        if (this.options.debug) this.options._debug('clearing call hit counter')
        this.callCnt = new Map()
      }, 60000)
    }

    return this
  }

  middleware() {
    var that = this

    if (!this.store) this.init()

    return function *(next) {
      try {
        // check if route is permitted to be cached FIXME?
        if (!that.routeKeysLength) return yield next;

        // create key
        let cacheKey, requestKey = this.request.path

        for (let i = 0; i < that.routeKeysLength; i++) {
          cacheKey = that.routeKeys[i]

          // first pass - exact match
          if (cacheKey === this.request.path) {
            if (that.options.debug)
              that.options._debug('exact matched route:', this.request.path)

            if (that.routes[cacheKey].cacheKeyArgs)
              requestKey = yield setRequestKey(requestKey, cacheKey, this.request)

            let ok = yield setExpires(i, requestKey)
            if (!ok) return yield next

            break
          }
          else if (!that.routes[that.routeKeys[i]].regex) continue

          // second pass - regex match
          else if (that.routes[that.routeKeys[i]].regex.test(this.request.path)) {
            if (that.options.debug)
              that.options._debug('regex matched route:', this.request.url, that.routes[that.routeKeys[i]].regex)

            if (that.routes[cacheKey].cacheKeyArgs)
              requestKey = yield setRequestKey(requestKey, cacheKey, this.request)

            let ok = yield setExpires(i, requestKey)
            if (!ok) return yield next

            break
          }

          if (i === that.routeKeys.length - 1) return yield next
          else continue
        }

        // check if no-cache is provided
        if (this.request.header['cache-control'] === 'no-cache') {
          return yield next
        }

        // check if HTTP methods other than GET are sent and invalidate cache if true
        if (this.request.method !== 'GET') {
          for (let i = 0; i < that.routeKeysLength; i++) {
            let key = that.routeKeys[i]

            if (requestKey.indexOf(key) != -1) {
              that.store.remove(requestKey)
            }
          }
          return yield next
        }

        // return cached response
        let requestKeyHeaders, requestKeyBody

        if ('undefined' !== typeof that.routes[cacheKey].cacheKeyPrefix) {
          requestKeyHeaders = that.routes[cacheKey].cacheKeyPrefix + ':' + requestKey + ':headers'
          requestKeyBody = that.routes[cacheKey].cacheKeyPrefix + ':' + requestKey + ':body'
        }
        else if ('undefined' !== typeof that.options.cacheKeyPrefix) {
          requestKeyHeaders = that.options.cacheKeyPrefix + ':' + requestKey + ':headers'
          requestKeyBody = that.options.cacheKeyPrefix + ':' + requestKey + ':body'
        }
        else {
          requestKeyHeaders = requestKey + ':headers'
          requestKeyBody = requestKey + ':body'
        }

        let exists = yield that.store.has(requestKeyHeaders)

        if (exists) {
          let body, headers = yield that.store.get(requestKeyHeaders)

          if ('string' === typeof(headers)) headers = JSON.parse(headers)
          if (that.options.debug) that.options._debug('returning from cache for url', requestKey)

          for (let key in headers) {
            if (key === 'header') {
              let value = headers[key]

              for (let hkey in value) {
                this.set(hkey, value[hkey])
              }

              continue
            }

            this[key] = headers[key]
          }

          if (this.type === 'application/octet-stream' || this.type.indexOf('image/' !== -1))
            body = yield that.store.getBuffer(requestKeyBody)
          else
            body = yield that.store.get(requestKeyBody)

          if (body) this['body'] = body
          return
        }

        // call next middleware and cache response on return
        yield next

        let _response_body, _response_headers = new Object()

        for (let key in this.response) {
          if (key === 'body') continue

          if (responseKeys.indexOf(key) !== -1)
            _response_headers[key] = this.response[key]
        }

        if (this.response.body)
          _response_body = this.response.body

        if (that.options.debug) that.options._debug('caching', requestKey)

        // set new caching entry
        let storeRequest = {}
        storeRequest[requestKeyHeaders] = JSON.stringify(_response_headers)
        storeRequest[requestKeyBody] = _response_body

        that.store.setMultiple(requestKey, storeRequest)
      }
      catch (error) {
        if (that.options.debug) console.error(error)
        this.throw(error)
      }
    }

    function *setExpires(routeKeysIndex, requestKey) {
      let routeExpire = that.routes[that.routeKeys[routeKeysIndex]].timeout

      if (routeExpire === false) {
        return false
      }

      // override default timeout
      if (typeof routeExpire === 'boolean') routeExpire = that.options.defaultTimeout
      else if (routeExpire === 'increasing' && that.options.increasing) {
        let count = that.callCnt.has(requestKey)

        if (count) {
          count = that.callCnt.get(requestKey) + 1
          that.callCnt.set(requestKey, count)
          let steps = that.cntStep.length

          for (let i = 0; i < steps; i++) {
            if (count === that.cntStep[i]) {
              that.options.expireOpts.set(requestKey, that.options.increasing[that.cntStep[i]])
              break
            }
          }
        }
        else {
          that.callCnt.set(requestKey, 1)
          that.options.expireOpts.set(requestKey, that.options.increasing[that.cntStep[0]])
        }
      }
      else that.options.expireOpts.set(requestKey, routeExpire)

      return true
    }

    function *setRequestKey(requestKey, routeKey, ctx) {
      // append specified http headers to requestKey
      if (that.routes[routeKey].cacheKeyArgs.headers instanceof Array) {
        requestKey += '#'

        for (let name of that.routes[routeKey].cacheKeyArgs.headers) {
          requestKey += ctx.header[name]
        }
      }

      // ...or append all http headers to requestKey
      else if (that.routes[routeKey].cacheKeyArgs.headers === true) {
        requestKey += '#'

        for (let name of Object.keys(ctx.headers)) {
          requestKey += ctx.headers[name]
        }
      }

      // append specified http url query parameters to requestKey
      if (that.routes[routeKey].cacheKeyArgs.query instanceof Array) {
        requestKey += '?'

        for (let name of Object.keys(ctx.query)) {
          requestKey += ctx.query[name]
        }
      }

      // ...or append all http url query parameters to requestKey
      else if (that.routes[routeKey].cacheKeyArgs.query === true)
        requestKey += '?' + ctx.querystring

      return requestKey
    }
  }

  clear(keys) {
    if (!keys) {
      if (this.options.cacheKeyPrefix)
        this.store.remove(this.options.cacheKeyPrefix + ':*')
      else
        this.store.remove()

      return
    }

    if (this.options.cacheKeyPrefix)
      this.store.remove(this.options.cacheKeyPrefix + ':' + keys)
    else
      this.store.remove(keys)
  }

  currentCacheType() {
    return this.store.storeType()
  }
}

module.exports = new Cache()
<|endoftext|>


<commit_before>var Joi = require('joi');
var Hapi = require('hapi');
var exec = require('child_process').exec,
var path = require('path');

var GITHUB_TOKEN = process.env.GITHUB_TOKEN;
var DOCKER_USER = process.env.DOCKER_USER;

// Create a server with a host and port
var server = new Hapi.Server('0.0.0.0', process.env.port || 8080);

// Add the route
server.route({
    method: 'POST',
    path: '/docker-build',
    handler: function (request, reply) {
      var body = request.payload,
          repository_url = body.repository.ssh_url,
          repository_name = body.repository.name,
          cwd = process.cwd();
      var timecode = +(new Date());

      var workDir = path.join(cwd, 'tmp', timecode);

      var cleanup = function (cb) {
        fs.rmdir(workDir, cb);
      }
      exec('git clone ' + repository + ' '+workDir, function (error, stdout, stderr) {
        if (err) {
          console.error("Failed to clone repository");
          console.error(err);
          cleanup();
        } else {
          exec('cd ' + workDir + ';  docker build -t '+DOCKER_USER+'/'+repository_name+' .', function (error, stdout, stderr) {
            if (err) {
              console.error("Failed to build docker image");
              console.error(err);
              cleanup();
            } else {
              exec('cd ' + workDir + ';  docker push', function (error, stdout, stderr) {
                if (err) {
                  console.error("Failed to publish docker image");
                  console.error(err);
                  cleanup();
                } else {
                  exec('cd ' + workDir + ';  docker push', function (err, stdout, stderr) {
                    cleanup();
                  });
                }
              });
            }
          });
        }
      });
      reply('Build Away');

    },
    config: {
        validate: {
            payload: {
                hook: {
                  config: {
                    secret: Joi.any().valid(GITHUB_TOKEN)
                  }
                }
              }
            }
        }
    },
    {
      method: '*',
      path: '/*',
      handler: function(request, reply) {
         reply('The page was not found').code(404);
      }
    }
});

// Start the server
server.start();<commit_msg>Update.<commit_after>var Joi = require('joi'),
    Hapi = require('hapi'),
    exec = require('child_process').exec,
    path = require('path');

var GITHUB_TOKEN = process.env.GITHUB_TOKEN;
var DOCKER_USER = process.env.DOCKER_USER;

// Create a server with a host and port
var server = new Hapi.Server('0.0.0.0', process.env.port || 8080);

// Add the route
server.route({
    method: 'POST',
    path: '/docker-build',
    handler: function (request, reply) {
      var body = request.payload,
          repository_url = body.repository.ssh_url,
          repository_name = body.repository.name,
          cwd = process.cwd();
      var timecode = +(new Date());

      var workDir = path.join(cwd, 'tmp', timecode);

      var cleanup = function (cb) {
        fs.rmdir(workDir, cb);
      }
      exec('git clone ' + repository + ' '+workDir, function (error, stdout, stderr) {
        if (err) {
          console.error('Failed to clone repository');
          console.error(err);
          cleanup();
        } else {
          exec('cd ' + workDir + ';  docker build -t '+DOCKER_USER+'/'+repository_name+' .', function (error, stdout, stderr) {
            if (err) {
              console.error('Failed to build docker image');
              console.error(err);
              cleanup();
            } else {
              exec('cd ' + workDir + ';  docker push', function (error, stdout, stderr) {
                if (err) {
                  console.error('Failed to publish docker image');
                  console.error(err);
                  cleanup();
                } else {
                  exec('cd ' + workDir + ';  docker push', function (err, stdout, stderr) {
                    cleanup();
                  });
                }
              });
            }
          });
        }
      });
      reply('Build Away');

    },
    config: {
        validate: {
            payload: {
                hook: {
                  config: {
                    secret: Joi.any().valid(GITHUB_TOKEN)
                  }
                }
              }
            }
        }
    },
    {
      method: '*',
      path: '/*',
      handler: function(request, reply) {
         reply('The page was not found').code(404);
      }
    }
});

// Start the server
server.start();<|endoftext|>


<commit_before>/**
 * Based on Kendo UI Core expression code <https://github.com/telerik/kendo-ui-core#license-information>
 */
'use strict'

function Cache(maxSize) {
  this._maxSize = maxSize
  this.clear()
}
Cache.prototype.clear = function () {
  this._size = 0
  this._values = Object.create(null)
}
Cache.prototype.get = function (key) {
  return this._values[key]
}
Cache.prototype.set = function (key, value) {
  this._size >= this._maxSize && this.clear()
  if (!(key in this._values)) this._size++

  return (this._values[key] = value)
}

var SPLIT_REGEX = /[^.^\]^[]+|(?=\[\]|\.\.)/g,
  DIGIT_REGEX = /^\d+$/,
  LEAD_DIGIT_REGEX = /^\d/,
  SPEC_CHAR_REGEX = /[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g,
  CLEAN_QUOTES_REGEX = /^\s*(['"]?)(.*?)(\1)\s*$/,
  MAX_CACHE_SIZE = 512

var pathCache = new Cache(MAX_CACHE_SIZE),
  setCache = new Cache(MAX_CACHE_SIZE),
  getCache = new Cache(MAX_CACHE_SIZE)

var config

module.exports = {
  Cache: Cache,

  split: split,

  normalizePath: normalizePath,

  setter: function (path) {
    var parts = normalizePath(path)

    return (
      setCache.get(path) ||
      setCache.set(path, function setter(obj, value) {
        var index = 0
        var len = parts.length
        var data = obj

        while (index < len - 1) {
          let part = parts[index]
          if (
            part === '__proto__' ||
            part === 'constructor' ||
            part === 'prototype'
          ) {
            return obj
          }

          data = data[parts[index++]]
        }
        data[parts[index]] = value
      })
    )
  },

  getter: function (path, safe) {
    var parts = normalizePath(path)
    return (
      getCache.get(path) ||
      getCache.set(path, function getter(data) {
        var index = 0,
          len = parts.length
        while (index < len) {
          if (data != null || !safe) data = data[parts[index++]]
          else return
        }
        return data
      })
    )
  },

  join: function (segments) {
    return segments.reduce(function (path, part) {
      return (
        path +
        (isQuoted(part) || DIGIT_REGEX.test(part)
          ? '[' + part + ']'
          : (path ? '.' : '') + part)
      )
    }, '')
  },

  forEach: function (path, cb, thisArg) {
    forEach(Array.isArray(path) ? path : split(path), cb, thisArg)
  },
}

function normalizePath(path) {
  return (
    pathCache.get(path) ||
    pathCache.set(
      path,
      split(path).map(function (part) {
        return part.replace(CLEAN_QUOTES_REGEX, '$2')
      })
    )
  )
}

function split(path) {
  return path.match(SPLIT_REGEX)
}

function forEach(parts, iter, thisArg) {
  var len = parts.length,
    part,
    idx,
    isArray,
    isBracket

  for (idx = 0; idx < len; idx++) {
    part = parts[idx]

    if (part) {
      if (shouldBeQuoted(part)) {
        part = '"' + part + '"'
      }

      isBracket = isQuoted(part)
      isArray = !isBracket && /^\d+$/.test(part)

      iter.call(thisArg, part, isBracket, isArray, idx, parts)
    }
  }
}

function isQuoted(str) {
  return (
    typeof str === 'string' && str && ["'", '"'].indexOf(str.charAt(0)) !== -1
  )
}

function hasLeadingNumber(part) {
  return part.match(LEAD_DIGIT_REGEX) && !part.match(DIGIT_REGEX)
}

function hasSpecialChars(part) {
  return SPEC_CHAR_REGEX.test(part)
}

function shouldBeQuoted(part) {
  return !isQuoted(part) && (hasLeadingNumber(part) || hasSpecialChars(part))
}
<commit_msg>Using 'var' instead of 'let' (#14)<commit_after>/**
 * Based on Kendo UI Core expression code <https://github.com/telerik/kendo-ui-core#license-information>
 */
'use strict'

function Cache(maxSize) {
  this._maxSize = maxSize
  this.clear()
}
Cache.prototype.clear = function () {
  this._size = 0
  this._values = Object.create(null)
}
Cache.prototype.get = function (key) {
  return this._values[key]
}
Cache.prototype.set = function (key, value) {
  this._size >= this._maxSize && this.clear()
  if (!(key in this._values)) this._size++

  return (this._values[key] = value)
}

var SPLIT_REGEX = /[^.^\]^[]+|(?=\[\]|\.\.)/g,
  DIGIT_REGEX = /^\d+$/,
  LEAD_DIGIT_REGEX = /^\d/,
  SPEC_CHAR_REGEX = /[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g,
  CLEAN_QUOTES_REGEX = /^\s*(['"]?)(.*?)(\1)\s*$/,
  MAX_CACHE_SIZE = 512

var pathCache = new Cache(MAX_CACHE_SIZE),
  setCache = new Cache(MAX_CACHE_SIZE),
  getCache = new Cache(MAX_CACHE_SIZE)

var config

module.exports = {
  Cache: Cache,

  split: split,

  normalizePath: normalizePath,

  setter: function (path) {
    var parts = normalizePath(path)

    return (
      setCache.get(path) ||
      setCache.set(path, function setter(obj, value) {
        var index = 0
        var len = parts.length
        var data = obj

        while (index < len - 1) {
          var part = parts[index]
          if (
            part === '__proto__' ||
            part === 'constructor' ||
            part === 'prototype'
          ) {
            return obj
          }

          data = data[parts[index++]]
        }
        data[parts[index]] = value
      })
    )
  },

  getter: function (path, safe) {
    var parts = normalizePath(path)
    return (
      getCache.get(path) ||
      getCache.set(path, function getter(data) {
        var index = 0,
          len = parts.length
        while (index < len) {
          if (data != null || !safe) data = data[parts[index++]]
          else return
        }
        return data
      })
    )
  },

  join: function (segments) {
    return segments.reduce(function (path, part) {
      return (
        path +
        (isQuoted(part) || DIGIT_REGEX.test(part)
          ? '[' + part + ']'
          : (path ? '.' : '') + part)
      )
    }, '')
  },

  forEach: function (path, cb, thisArg) {
    forEach(Array.isArray(path) ? path : split(path), cb, thisArg)
  },
}

function normalizePath(path) {
  return (
    pathCache.get(path) ||
    pathCache.set(
      path,
      split(path).map(function (part) {
        return part.replace(CLEAN_QUOTES_REGEX, '$2')
      })
    )
  )
}

function split(path) {
  return path.match(SPLIT_REGEX)
}

function forEach(parts, iter, thisArg) {
  var len = parts.length,
    part,
    idx,
    isArray,
    isBracket

  for (idx = 0; idx < len; idx++) {
    part = parts[idx]

    if (part) {
      if (shouldBeQuoted(part)) {
        part = '"' + part + '"'
      }

      isBracket = isQuoted(part)
      isArray = !isBracket && /^\d+$/.test(part)

      iter.call(thisArg, part, isBracket, isArray, idx, parts)
    }
  }
}

function isQuoted(str) {
  return (
    typeof str === 'string' && str && ["'", '"'].indexOf(str.charAt(0)) !== -1
  )
}

function hasLeadingNumber(part) {
  return part.match(LEAD_DIGIT_REGEX) && !part.match(DIGIT_REGEX)
}

function hasSpecialChars(part) {
  return SPEC_CHAR_REGEX.test(part)
}

function shouldBeQuoted(part) {
  return !isQuoted(part) && (hasLeadingNumber(part) || hasSpecialChars(part))
}
<|endoftext|>


<commit_before>'use strict';

var gutil = require('gulp-util');
var through = require('through2');
var assign = require('object-assign');
var path = require('path');
var applySourceMap = require('vinyl-sourcemaps-apply');

var PLUGIN_NAME = 'gulp-sass';

//////////////////////////////
// Main Gulp Sass function
//////////////////////////////
var gulpSass = function gulpSass(options, sync) {
  return through.obj(function(file, enc, cb) {
    var opts,
        filePush,
        errorM,
        callback,
        result;

    if (file.isNull()) {
      return cb(null, file);
    }
    if (file.isStream()) {
      return cb(new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
    }
    if (path.basename(file.path).indexOf('_') === 0) {
      return cb();
    }

    opts = assign({}, options);
    opts.data = file.contents.toString();

    // Ensure `indentedSyntax` is true if a `.sass` file
    if (path.extname(file.path) === '.sass') {
      opts.indentedSyntax = true;
    }

    // Ensure file's parent directory in the include path
    if (opts.includePaths) {
      if (typeof opts.includePaths === 'string') {
        opts.includePaths = [opts.includePaths];
      }
    }
    else {
      opts.includePaths = [];
    }

    opts.includePaths.push(path.dirname(file.path));

    // Generate Source Maps if plugin source-map present
    if (file.sourceMap) {
      opts.sourceMap = file.path;
      opts.omitSourceMapUrl = true;
    }

    //////////////////////////////
    // Handles returning the file to the stream
    //////////////////////////////
    filePush = function filePush(sassObj) {
      var sassMap,
          sassMapFile,
          sassFileSrc;

      // Build Source Maps!
      if (sassObj.map) {
        // Transform map into JSON
        sassMap = JSON.parse(sassObj.map.toString());
        // Grab the stdout and transform it into stdin
        sassMapFile = sassMap.file.replace('stdout', 'stdin');
        // Grab the base file name that's being worked on
        sassFileSrc = file.path.split('/').pop();
        // Replace the stdin with the original file name
        sassMap.sources[sassMap.sources.indexOf(sassMapFile)] = sassFileSrc;
        // Replace the map file with the original file name
        sassMap.file = sassFileSrc;
        // Apply the map
        applySourceMap(file, sassMap);
      }

      file.contents = sassObj.css;
      file.path = gutil.replaceExtension(file.path, '.css');

      cb(null, file);
    };

    //////////////////////////////
    // Handles error message
    //////////////////////////////
    errorM = function errorM(error) {
      var relativePath = '',
          filePath = error.file === 'stdin' ? file.path : error.file,
          message = '';

      filePath = filePath ? filePath : file.path;
      relativePath = path.relative(process.cwd(), filePath);

      if (options.errLogToCSS) {
        var err_msg_css = 'html { padding: 18px 36px; }' +
                       'head { display: block; }' +
                       'body { margin: 0; padding: 0; }' +
                       'body > * { display: none !important; }' +
                       'head:after, body:before, body:after { display: block !important; }' +
                       'head:after { font-family: sans-serif; font-size: large; font-weight: bold; content: "Error compiling CSS asset"; }' +
                       'body:before, body:after { font-family: monospace; white-space: pre-wrap; }';

        err_msg_css += 'body:before { content: "\\00000a';
        err_msg_css += error.message.replace(/"/g, '\\000022').replace(/\n/g, '\\00000a').replace(/\t/g, '    ');
        err_msg_css += '"; }';

        err_msg_css += 'body:after { content: "\\00000a';
        err_msg_css += relativePath.replace('/', '\\00002f');
        err_msg_css += ':';
        err_msg_css += err.line;
        err_msg_css += ':';
        err_msg_css += err.column;
        err_msg_css += '"; }';

        file.contents = new Buffer(err_msg_css);
        file.path = gutil.replaceExtension(file.path, '.css');

        return cb(null, file);
      }

      message += gutil.colors.underline(relativePath) + '\n';
      message += gutil.colors.gray('  ' + error.line + ':' + error.column) + '  ';
      message += error.message;

      return cb(new gutil.PluginError(
          PLUGIN_NAME, message
        ));
    };

    if (sync !== true) {
      //////////////////////////////
      // Async Sass render
      //////////////////////////////
      callback = function(error, obj) {
        if (error) {
          return errorM(error);
        }
        filePush(obj);
      };

      gulpSass.compiler.render(opts, callback);
    }
    else {
      //////////////////////////////
      // Sync Sass render
      //////////////////////////////
      try {
        result = gulpSass.compiler.renderSync(opts);

        filePush(result);
      }
      catch(error) {
        return errorM(error);
      }
    }
  });
};

//////////////////////////////
// Sync Sass render
//////////////////////////////
gulpSass.sync = function sync(options) {
  return gulpSass(options, true);
};

//////////////////////////////
// Log errors nicely
//////////////////////////////
gulpSass.logError = function logError(error) {
  gutil.log(gutil.colors.red('[' + PLUGIN_NAME + '] ') + error.message);
};

//////////////////////////////
// Store compiler in a prop
//////////////////////////////
gulpSass.compiler = require('node-sass');

module.exports = gulpSass;
<commit_msg>try to fix build<commit_after>'use strict';

var gutil = require('gulp-util');
var through = require('through2');
var assign = require('object-assign');
var path = require('path');
var applySourceMap = require('vinyl-sourcemaps-apply');

var PLUGIN_NAME = 'gulp-sass';

//////////////////////////////
// Main Gulp Sass function
//////////////////////////////
var gulpSass = function gulpSass(options, sync) {
  return through.obj(function(file, enc, cb) {
    var opts,
        filePush,
        errorM,
        callback,
        result;

    if (file.isNull()) {
      return cb(null, file);
    }
    if (file.isStream()) {
      return cb(new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
    }
    if (path.basename(file.path).indexOf('_') === 0) {
      return cb();
    }

    opts = assign({}, options);
    opts.data = file.contents.toString();

    // Ensure `indentedSyntax` is true if a `.sass` file
    if (path.extname(file.path) === '.sass') {
      opts.indentedSyntax = true;
    }

    // Ensure file's parent directory in the include path
    if (opts.includePaths) {
      if (typeof opts.includePaths === 'string') {
        opts.includePaths = [opts.includePaths];
      }
    }
    else {
      opts.includePaths = [];
    }

    opts.includePaths.push(path.dirname(file.path));

    // Generate Source Maps if plugin source-map present
    if (file.sourceMap) {
      opts.sourceMap = file.path;
      opts.omitSourceMapUrl = true;
    }

    //////////////////////////////
    // Handles returning the file to the stream
    //////////////////////////////
    filePush = function filePush(sassObj) {
      var sassMap,
          sassMapFile,
          sassFileSrc;

      // Build Source Maps!
      if (sassObj.map) {
        // Transform map into JSON
        sassMap = JSON.parse(sassObj.map.toString());
        // Grab the stdout and transform it into stdin
        sassMapFile = sassMap.file.replace('stdout', 'stdin');
        // Grab the base file name that's being worked on
        sassFileSrc = file.path.split('/').pop();
        // Replace the stdin with the original file name
        sassMap.sources[sassMap.sources.indexOf(sassMapFile)] = sassFileSrc;
        // Replace the map file with the original file name
        sassMap.file = sassFileSrc;
        // Apply the map
        applySourceMap(file, sassMap);
      }

      file.contents = sassObj.css;
      file.path = gutil.replaceExtension(file.path, '.css');

      cb(null, file);
    };

    //////////////////////////////
    // Handles error message
    //////////////////////////////
    errorM = function errorM(error) {
      var relativePath = '',
          filePath = error.file === 'stdin' ? file.path : error.file,
          message = '';

      filePath = filePath ? filePath : file.path;
      relativePath = path.relative(process.cwd(), filePath);

      if (opts.errLogToCSS) {
        message = 'html { padding: 18px 36px; }' +
                  'head { display: block; }' +
                  'body { margin: 0; padding: 0; }' +
                  'body > * { display: none !important; }' +
                  'head:after, body:before, body:after { display: block !important; }' +
                  'head:after { font-family: sans-serif; font-size: large; font-weight: bold; content: "Error compiling CSS asset"; }' +
                  'body:before, body:after { font-family: monospace; white-space: pre-wrap; }';

        message += 'body:before { content: "\\00000a';
        message += error.message.replace(/"/g, '\\000022').replace(/\n/g, '\\00000a').replace(/\t/g, '    ');
        message += '"; }';

        message += 'body:after { content: "\\00000a';
        message += relativePath.replace('/', '\\00002f');
        message += ':';
        message += error.line;
        message += ':';
        message += error.column;
        message += '"; }';

        file.contents = new Buffer(message);
        file.path = gutil.replaceExtension(file.path, '.css');

        return cb(null, file);
      }

      message += gutil.colors.underline(relativePath) + '\n';
      message += gutil.colors.gray('  ' + error.line + ':' + error.column) + '  ';
      message += error.message;

      return cb(new gutil.PluginError(
          PLUGIN_NAME, message
        ));
    };

    if (sync !== true) {
      //////////////////////////////
      // Async Sass render
      //////////////////////////////
      callback = function(error, obj) {
        if (error) {
          return errorM(error);
        }
        filePush(obj);
      };

      gulpSass.compiler.render(opts, callback);
    }
    else {
      //////////////////////////////
      // Sync Sass render
      //////////////////////////////
      try {
        result = gulpSass.compiler.renderSync(opts);

        filePush(result);
      }
      catch(error) {
        return errorM(error);
      }
    }
  });
};

//////////////////////////////
// Sync Sass render
//////////////////////////////
gulpSass.sync = function sync(options) {
  return gulpSass(options, true);
};

//////////////////////////////
// Log errors nicely
//////////////////////////////
gulpSass.logError = function logError(error) {
  gutil.log(gutil.colors.red('[' + PLUGIN_NAME + '] ') + error.message);
};

//////////////////////////////
// Store compiler in a prop
//////////////////////////////
gulpSass.compiler = require('node-sass');

module.exports = gulpSass;
<|endoftext|>


<commit_before>'use babel';

import { CompositeDisposable } from 'atom';
import { type } from 'os';
import { normalize, join } from 'path';
import execa from 'execa';

const unix = normalize(join(__dirname, 'node_modules', '.bin', 'csso'));
const win = normalize(join(__dirname, 'node_modules', '.bin', 'csso.cmd'));
const csso = type() === 'Windows_NT' ? win : unix;

let subscriptions;
let restructure;

export function activate(state) {
  subscriptions = new CompositeDisposable();
  subscriptions.add(atom.config.observe('csso.restructure', value => {
    restructure = value;
  }));

  atom.commands.add('atom-workspace', 'csso:minify', () => minify());
};

export function deactivate() {
  subscriptions.dispose();
}

function minify() {
  const editor = atom.workspace.getActiveTextEditor();

  if (!editor) {
    return;
  }

  const args = restructure ? [] : ['--restructure-off'];
  const buffer = Buffer.from(editor.getText());

  execa.stdout(csso, args, {
    encoding: null,
    input: buffer
  }).then(stdout => {
    const position = editor.getCursorBufferPosition();
    editor.setText(stdout.toString());
    editor.setCursorBufferPosition(position);
  }).catch(error => {
    atom.notifications.addError(errors.toString(), {});
  });
};
<commit_msg>Fix error.toString()<commit_after>'use babel';

import { CompositeDisposable } from 'atom';
import { type } from 'os';
import { normalize, join } from 'path';
import execa from 'execa';

const unix = normalize(join(__dirname, 'node_modules', '.bin', 'csso'));
const win = normalize(join(__dirname, 'node_modules', '.bin', 'csso.cmd'));
const csso = type() === 'Windows_NT' ? win : unix;

let subscriptions;
let restructure;

export function activate(state) {
  subscriptions = new CompositeDisposable();
  subscriptions.add(atom.config.observe('csso.restructure', value => {
    restructure = value;
  }));

  atom.commands.add('atom-workspace', 'csso:minify', () => minify());
};

export function deactivate() {
  subscriptions.dispose();
}

function minify() {
  const editor = atom.workspace.getActiveTextEditor();

  if (!editor) {
    return;
  }

  const args = restructure ? [] : ['--restructure-off'];
  const buffer = Buffer.from(editor.getText());

  execa.stdout(csso, args, {
    encoding: null,
    input: buffer
  }).then(stdout => {
    const position = editor.getCursorBufferPosition();
    editor.setText(stdout.toString());
    editor.setCursorBufferPosition(position);
  }).catch(error => {
    atom.notifications.addError(error.toString(), {});
  });
};
<|endoftext|>


<commit_before>var fs = require('fs')
module.exports = function (property) {
    var list = JSON.parse(fs.readFileSync('list.json', 'utf-8'))
    var types = Object.keys(list)
    var ret
    types.forEach(function (type, i) {
        if (list[type].indexOf(property) !== -1) {
            ret = types[i]
        }
    })

    return ret
}
<commit_msg>tweak<commit_after>var fs = require('fs')

module.exports = function (property) {
    var list = JSON.parse(fs.readFileSync('list.json', 'utf-8'))
    var types = Object.keys(list)
    var ret

    types.forEach(function (type, i) {
        if (list[type].indexOf(property) !== -1) {
            ret = types[i]
        }
    })

    return ret
}
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

var path = require('path');
var fs = require('fs');
var hashForDep = require('hash-for-dep');
var HTMLBarsInlinePrecompilePlugin = require('babel-plugin-htmlbars-inline-precompile');

module.exports = {
  name: 'ember-cli-htmlbars-inline-precompile',

  setupPreprocessorRegistry: function(type, registry) {
    if (type === 'parent') {
      this.parentRegistry = registry;
    }
  },

  included: function(app) {
    this._super.included.apply(this, arguments);

    var emberCLIHtmlBars = this.project.findAddonByName('ember-cli-htmlbars');

    if(emberCLIHtmlBars && emberCLIHtmlBars.inlinePrecompilerRegistered) {
      return;
    }

    app.options = app.options || {};
    app.options.babel = app.options.babel || {};
    app.options.babel.plugins = app.options.babel.plugins || [];

    // borrowed from ember-cli-htmlbars http://git.io/vJDrW
    var projectConfig = this.projectConfig() || {};
    var EmberENV = projectConfig.EmberENV || {};
    var templateCompilerPath = this.templateCompilerPath();

    // ensure we get a fresh templateCompilerModuleInstance per ember-addon
    // instance NOTE: this is a quick hack, and will only work as long as
    // templateCompilerPath is a single file bundle
    //
    // (╯°□°）╯︵ ɹǝqɯǝ
    //
    // we will also fix this in ember for future releases
    delete require.cache[templateCompilerPath];

    global.EmberENV = EmberENV;

    var pluginInfo = this.astPlugins();
    var Compiler = require(templateCompilerPath);
    var templateCompilerFullPath = require.resolve(templateCompilerPath);
    var templateCompilerCacheKey = fs.readFileSync(templateCompilerFullPath, { encoding: 'utf-8' });

    pluginInfo.plugins.forEach(function(plugin) {
      Compiler.registerPlugin('ast', plugin);
    });

    var PrecompileInlineHTMLBarsPlugin = HTMLBarsInlinePrecompilePlugin(Compiler.precompile, {
      cacheKey: [templateCompilerCacheKey].concat(pluginInfo.cacheKeys).join('|')
    });

    delete require.cache[templateCompilerPath];
    delete global.Ember;
    delete global.EmberENV;

    // add the HTMLBarsInlinePrecompilePlugin to the list of plugins used by
    // the `ember-cli-babel` addon
    if (!this._registeredWithBabel) {
      app.options.babel.plugins.push(PrecompileInlineHTMLBarsPlugin);
      this._registeredWithBabel = true;
    }
  },

  // from ember-cli-htmlbars :(
  astPlugins: function() {
    var pluginWrappers = this.parentRegistry.load('htmlbars-ast-plugin');
    var plugins = [];
    var cacheKeys = [];

    for (var i = 0; i < pluginWrappers.length; i++) {
      var wrapper = pluginWrappers[i];

      plugins.push(wrapper.plugin);

      if (typeof wrapper.baseDir === 'function') {
        var pluginHashForDep = hashForDep(wrapper.baseDir());
        cacheKeys.push(pluginHashForDep);
      } else {
        // support for ember-cli < 2.2.0
        var log = this.ui.writeDeprecateLine || this.ui.writeLine;

        log.call(this.ui, 'ember-cli-htmlbars-inline-precompile is opting out of caching due to an AST plugin that does not provide a caching strategy: `' + wrapper.name + '`.');
        cacheKeys.push((new Date()).getTime() + '|' + Math.random());
      }
    }

    return {
      plugins: plugins,
      cacheKeys: cacheKeys
    };
  },

  // borrowed from ember-cli-htmlbars http://git.io/vJDrW
  projectConfig: function () {
    return this.project.config(process.env.EMBER_ENV);
  },

  // borrowed from ember-cli-htmlbars http://git.io/vJDrw
  templateCompilerPath: function() {
    var config = this.projectConfig();
    var templateCompilerPath = config['ember-cli-htmlbars'] && config['ember-cli-htmlbars'].templateCompilerPath;

    var ember = this.project.findAddonByName('ember-source');
    if (ember) {
      return ember.absolutePaths.templateCompiler;
    } else if (!templateCompilerPath) {
      templateCompilerPath = this.project.bowerDirectory + '/ember/ember-template-compiler';
    }

    return path.resolve(this.project.root, templateCompilerPath);
  }
};
<commit_msg>Update for babel@6.<commit_after>/* jshint node: true */
'use strict';

var path = require('path');
var fs = require('fs');
var hashForDep = require('hash-for-dep');
var HTMLBarsInlinePrecompilePlugin = require('babel-plugin-htmlbars-inline-precompile');

module.exports = {
  name: 'ember-cli-htmlbars-inline-precompile',

  setupPreprocessorRegistry: function(type, registry) {
    if (type === 'parent') {
      this.parentRegistry = registry;
    }
  },

  included: function() {
    this._super.included.apply(this, arguments);

    var emberCLIHtmlBars = this.project.findAddonByName('ember-cli-htmlbars');

    if(emberCLIHtmlBars && emberCLIHtmlBars.inlinePrecompilerRegistered) {
      return;
    }

    var addonOptions = this._getAddonOptions();
    addonOptions.babel = addonOptions.babel || {};
    addonOptions.babel.plugins = addonOptions.babel.plugins || [];

    // borrowed from ember-cli-htmlbars http://git.io/vJDrW
    var projectConfig = this.projectConfig() || {};
    var EmberENV = projectConfig.EmberENV || {};
    var templateCompilerPath = this.templateCompilerPath();

    // ensure we get a fresh templateCompilerModuleInstance per ember-addon
    // instance NOTE: this is a quick hack, and will only work as long as
    // templateCompilerPath is a single file bundle
    //
    // (╯°□°）╯︵ ɹǝqɯǝ
    //
    // we will also fix this in ember for future releases
    delete require.cache[templateCompilerPath];

    global.EmberENV = EmberENV;

    var pluginInfo = this.astPlugins();
    var Compiler = require(templateCompilerPath);
    var templateCompilerFullPath = require.resolve(templateCompilerPath);
    var templateCompilerCacheKey = fs.readFileSync(templateCompilerFullPath, { encoding: 'utf-8' });

    pluginInfo.plugins.forEach(function(plugin) {
      Compiler.registerPlugin('ast', plugin);
    });

    var precompile = Compiler.precompile;

    precompile.baseDir = () => path.dirname(templateCompilerFullPath);
    precompile.cacheKey = () => [templateCompilerCacheKey].concat(pluginInfo.cacheKeys).join('|');

    delete require.cache[templateCompilerPath];
    delete global.Ember;
    delete global.EmberENV;

    // add the HTMLBarsInlinePrecompilePlugin to the list of plugins used by
    // the `ember-cli-babel` addon
    if (!this._registeredWithBabel) {
      addonOptions.babel.plugins.push([HTMLBarsInlinePrecompilePlugin, { precompile: Compiler.precompile  }]);
      this._registeredWithBabel = true;
    }
  },

  _getAddonOptions: function() {
    return (this.parent && this.parent.options) || (this.app && this.app.options) || {};
  },

  // from ember-cli-htmlbars :(
  astPlugins: function() {
    var pluginWrappers = this.parentRegistry.load('htmlbars-ast-plugin');
    var plugins = [];
    var cacheKeys = [];

    for (var i = 0; i < pluginWrappers.length; i++) {
      var wrapper = pluginWrappers[i];

      plugins.push(wrapper.plugin);

      if (typeof wrapper.baseDir === 'function') {
        var pluginHashForDep = hashForDep(wrapper.baseDir());
        cacheKeys.push(pluginHashForDep);
      } else {
        // support for ember-cli < 2.2.0
        var log = this.ui.writeDeprecateLine || this.ui.writeLine;

        log.call(this.ui, 'ember-cli-htmlbars-inline-precompile is opting out of caching due to an AST plugin that does not provide a caching strategy: `' + wrapper.name + '`.');
        cacheKeys.push((new Date()).getTime() + '|' + Math.random());
      }
    }

    return {
      plugins: plugins,
      cacheKeys: cacheKeys
    };
  },

  // borrowed from ember-cli-htmlbars http://git.io/vJDrW
  projectConfig: function () {
    return this.project.config(process.env.EMBER_ENV);
  },

  // borrowed from ember-cli-htmlbars http://git.io/vJDrw
  templateCompilerPath: function() {
    var config = this.projectConfig();
    var templateCompilerPath = config['ember-cli-htmlbars'] && config['ember-cli-htmlbars'].templateCompilerPath;

    var ember = this.project.findAddonByName('ember-source');
    if (ember) {
      return ember.absolutePaths.templateCompiler;
    } else if (!templateCompilerPath) {
      templateCompilerPath = this.project.bowerDirectory + '/ember/ember-template-compiler';
    }

    return path.resolve(this.project.root, templateCompilerPath);
  }
};
<|endoftext|>


<commit_before>'use strict';

var EventEmitter = require('eventemitter3')
  , Tick = require('tick-tock');

/**
 * Proper type checking.
 *
 * @param {Mixed} of Thing we want to know the type of.
 * @returns {String} The type.
 * @api private
 */
function type(of) {
  return Object.prototype.toString.call(of).slice(8, -1).toLowerCase();
}

/**
 * Generate a somewhat unique UUID.
 *
 * @see stackoverflow.com/q/105034
 * @returns {String} UUID.
 * @api private
 */
function UUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function gen(c) {
    var random = Math.random() * 16 | 0
      , value = c !== 'x'
        ? (random & 0x3 | 0x8)
        : random;

    return value.toString(16);
  });
}

/**
 * Representation of a single node in the cluster.
 *
 * Options:
 *
 * - `id`: An unique id of this given node.
 * - `heartbeat min`: Minimum heartbeat timeout.
 * - `heartbeat max`: Maximum heartbeat timeout.
 * - `election min`: Minimum election timeout.
 * - `election max`: Maximum election timeout.
 * - `threshold`: Threshold when the heartbeat RTT is close to the election
 *   timeout.
 *
 * @constructor
 * @param {Object} options Node configuration.
 * @api public
 */
function Node(options) {
  if (!(this instanceof Node)) return new Node(options);

  options = options || {};

  this.election = {
    min: Tick.parse(options['election min'] || '150 ms'),
    max: Tick.parse(options['election max'] || '300 ms')
  };

  this.beat = {
    min: Tick.parse(options['heartbeat min'] || this.election.min),
    max: Tick.parse(options['heartbeat max'] || this.election.max)
  };

  this.votes = {
    for: null,                // Who did we vote for in this current term.
    granted: 0                // How many votes we're granted to us.
  };

  this.threshold = options.threshold || 0.8;
  this.name = options.name || UUID();
  this.timers = new Tick(this);
  this.nodes = [];

  //
  // Raft §5.2:
  //
  // When a server starts, it's always started as Follower and it will remain in
  // this state until receive a message from a Leader or Candidate.
  //
  this.state = Node.FOLLOWER; // Our current state.
  this.leader = null;         // Leader in our cluster.
  this.term = 0;              // Our current term.

  this.initialize(options);
}

//
// Add some sugar and spice and everything nice. Oh, and also inheritance.
//
Node.extend = require('extendable');
Node.prototype = new EventEmitter();
Node.prototype.constructor = Node;

/**
 * Raft §5.1:
 *
 * A Node can be in only one of the various states. The stopped state is not
 * something that is part of the Raft protocol but something we might want to
 * use internally while we're starting or shutting down our node.
 *
 * @type {Number}
 * @private
 */
Node.LEADER    = 1;   // We're selected as leader process.
Node.CANDIDATE = 2;   // We want to be promoted to leader.
Node.FOLLOWER  = 3;   // We're just following a leader.
Node.STOPPED   = 4;   // Assume we're dead.

/**
 * Initialize the node and start listening to the various of events we're
 * emitting as we're quite chatty to provide the maximum amount of flexibility
 * and reconfigurability.
 *
 * @param {Object} options The configuration you passed in the constructor.
 * @api private
 */
Node.prototype.initialize = function initialize(options) {
  //
  // Reset our vote as we're starting a new term. Votes only last one term.
  //
  this.on('term change', function change() {
    this.votes.for = null;
    this.votes.granted = 0;
  });

  //
  // Reset our times and start the heartbeat again. If we're promoted to leader
  // the heartbeat will automatically be broadcasted to users as well.
  //
  this.on('state change', function change(currently, previously) {
    this.timers.clear();
    this.heartbeat();
  });

  //
  // Receive incoming messages and process them.
  //
  this.on('data', function incoming(packet) {
    if ('object' !== type(packet)) {
      return; /* Invalid packet structure, G.T.F.O. */
    }

    //
    // Raft §5.1:
    //
    // Applies to all states. If a response contains a higher term then our
    // current term need to change our state to FOLLOWER and set the received
    // term.
    //
    // If the node receives a request with a stale term number it should be
    // rejected.
    //
    if (packet.term > this.term) {
      this.change({
        leader: packet.leader,
        state: Node.FOLLOWER,
        term: packet.term
      });
    } else if (packet.term < this.term) {
      return;
    }

    //
    // Raft §5.2:
    //
    // If we receive a message from someone who claims to be leader and shares
    // our same term while we're in candidate mode we will recognize their
    // leadership and return as follower
    //
    if (Node.LEADER === packet.state && Node.FOLLOWER !== this.state) {
      this.change({ state: Node.FOLLOWER, leader: packet.leader });
    }

    //
    // Always when we receive an message from the Leader we need to reset our
    // heartbeat.
    //
    if (Node.LEADER === packet.state) {
      this.heartbeat();
    }

    switch (packet.type) {
      //
      // Raft §5.2:
      // Raft §5.4:
      //
      // A node asked us to vote on them. We can only vote to them if they
      // represent a higher term (and last log term, last log index).
      //
      case 'vote':
        //
        // The term of the vote is bigger then ours so we need to update it. If
        // it's the same and we already voted, we need to deny the vote.
        //
        if (this.votes.for && this.votes.for !== packet.name) {
          this.emit('vote', packet, false);
          return this.write('vote', { granted: false });
        }

        //
        // If we maintain a log, check if the candidates log is as up to date as
        // ours.
        //

        //
        // We've made our decision, we haven't voted for this term yet and this
        // candidate came in first so it gets our vote as all requirements are
        // met.
        //
        this.votes.for = packet.name;
        this.emit('vote', packet, true);
        this.write('vote', { granted: true });
      break;

      //
      // A new incoming vote.
      //
      case 'voted':
        //
        // Only accepts votes while we're still in a CANDIDATE state.
        //
        if (Node.CANDIDATE !== this.state) return;

        //
        // Increment our received votes when our voting request has been
        // granted by the node that received the data.
        //
        if (packet.data.granted) this.votes.granted++;

        //
        // Check if we've received the minimal amount of votes required for this
        // current voting round to be considered valid
        //
        if (this.quorum(this.votes.granted)) {
          this.change({ leader: this.name, state: Node.LEADER });
          // @TODO broadcast start heartbeat.
        }
      break;

      case 'append':
      break;

      case 'log':

      break;
    }
  });

  //
  // Setup the log appends.
  //

  //
  // The node is now listening to events so we can start our heartbeat timeout.
  // So that if we don't hear anything from a leader we can promote our selfs to
  // a candidate state.
  //
  this.heartbeat();
};

/**
 * Check if we've reached our quorum (a.k.a. minimum amount of votes requires
 * for a voting round to be considered valid) for the given amount of votes.
 *
 * @param {Number} responses Amount of responses received.
 * @returns {Boolean}
 * @api private
 */
Node.prototype.quorum = function quorum(responses) {
  if (!this.nodes.length || !responses) return false;
  return responses >= this.majority();
};

/**
 * The majority required to reach our the quorum.
 *
 * @returns {Number}
 * @api private
 */
Node.prototype.majority = function majority() {
  return Math.ceil(this.nodes.length / 2) + 1;
};

/**
 * Process a change in the node.
 *
 * @param {Object} changed Data that is changed.
 * @returns {Node}
 * @api private
 */
Node.prototype.change = function change(changed) {
  var changes = ['term', 'leader', 'state']
    , currently, previously
    , i = 0;

  if (!changed) return this;

  for (; i < changes.length; i++) {
    if (changes[i] in changed && changed[changes[i]] !== this[changes[i]]) {
      currently = changed[changes[i]];
      previously = this[changes[i]];

      this[changes[i]] = currently;
      this.emit(changes[i] +' change', currently, previously);
    }
  }

  return this;
};

/**
 * Start or update the heartbeat of the Node. If we detect that we've received
 * a heartbeat timeout we will promote our selfs to a candidate to take over the
 * leadership.
 *
 * @param {String|Number} duration Time it would take for the heartbeat to timeout.
 * @returns {Node}
 * @api public
 */
Node.prototype.heartbeat = function heartbeat(duration) {
  duration = duration || this.timeout('beat');

  if (this.timers.active('heartbeat')) {
    this.timers.adjust('heartbeat', duration);
    return this;
  }

  this.timers.setTimeout('heartbeat', function () {
    if (Node.LEADER !== this.state) {
      this.emit('heartbeat timeout');
      return this.promote();
    }

    //
    // We're the LEADER so we should be broadcasting.
    //
    this.broadcast('heartbeat');
  }, duration);

  return this;
};

/**
 * Generate the various of timeouts.
 *
 * @param {String} which Type of timeout we want to generate.
 * @returns {Number}
 * @api public
 */
Node.prototype.timeout = function timeout(which) {
  var times = this[which];

  return Math.floor(Math.random() * (times.max - times.min + 1) + times.min);
};

/**
 * Raft §5.2:
 *
 * We've detected a timeout from the leaders heartbeats and need to start a new
 * election for leadership. We increment our current term, set the CANDIDATE
 * state, vote our selfs and ask all others nodes to vote for us.
 *
 * @returns {Node}
 * @api public
 */
Node.prototype.promote = function promote() {
  this.change({
    state: Node.CANDIDATE,  // We're now a candidate,
    term: this.term + 1,    // but only for this term.
    leader: ''              // We no longer have a leader.
  });

  //
  // Candidates are always biased and vote for them selfs first before sending
  // out a voting request to all other nodes in the cluster.
  //
  this.votes.for = this.name;
  this.votes.granted = 1;

  //
  // Set the election timeout. This gives the nodes some time to reach
  // consensuses about who they want to vote for. If no consensus has been
  // reached within the set timeout we will attempt it again.
  //
  this.timers.setTimeout('election', this.promote, this.timeout('election'));

  return this;
};

/**
 * While we don't really adapt the Stream interface here from node, we still
 * want to follow it's API signature. So we assume that the `write` method will
 * return a boolean indicating if the packet has been written.
 *
 * @param {Object} packet The data that needs to be written.
 * @returns {Boolean} Indication that the message was written.
 * @api public
 */
Node.prototype.write = function write(packet) {
  return false;
};

/**
 * Read and process an incoming data packet.
 *
 * @returns {Boolean} Did we read the message.
 * @api public
 */
Node.prototype.read = function read(packet) {
  return this.emit('data', packet);
};

/**
 * Broadcast a message.
 *
 * @param {String} type Message type we're trying to send.
 * @param {Mixed} data Data to be transfered.
 * @returns {Boolean} Successful write.
 * @api public
 */
Node.prototype.broadcast = function broadcast(type, data) {
  var packet = this.packet(type, data);
};

/**
 * Wrap the outgoing messages in an object with additional required data.
 *
 * @param {String} type Message type we're trying to send.
 * @param {Mixed} data Data to be transfered.
 * @returns {Object} Packet.
 * @api private
 */
Node.prototype.packet = function packet(type, data) {
  return {
    state:  this.state,   // So you know if we're a leader, candidate or follower.
    term:   this.term,    // Our current term so we can find mis matches.
    name:   this.name,    // Name of the sender.
    data:   data,         // Custom data we send.
    type:   type,         // Message type.
    leader: this.leader   // Who is our leader.
  };
};

/**
 * This Node needs to be shut down.
 *
 * @returns {Boolean} Successful destruction.
 * @api public
 */
Node.prototype.end = function end() {
  if (!this.state) return false;

  this.timers.end();
  this.removeAllListeners();

  this.timers = this.state = this.write = this.read = null;

  return true;
};

//
// Expose the module interface.
//
module.exports = Node;
<commit_msg>[fix] Remove the write method, it's silly we need req->res pattern.<commit_after>'use strict';

var EventEmitter = require('eventemitter3')
  , Tick = require('tick-tock');

/**
 * Proper type checking.
 *
 * @param {Mixed} of Thing we want to know the type of.
 * @returns {String} The type.
 * @api private
 */
function type(of) {
  return Object.prototype.toString.call(of).slice(8, -1).toLowerCase();
}

/**
 * Generate a somewhat unique UUID.
 *
 * @see stackoverflow.com/q/105034
 * @returns {String} UUID.
 * @api private
 */
function UUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function gen(c) {
    var random = Math.random() * 16 | 0
      , value = c !== 'x'
        ? (random & 0x3 | 0x8)
        : random;

    return value.toString(16);
  });
}

/**
 * A nope function for when people don't want message acknowledgements. Because
 * they don't care about CAP.
 *
 * @api private
 */
function nope() {}

/**
 * Representation of a single node in the cluster.
 *
 * Options:
 *
 * - `id`: An unique id of this given node.
 * - `heartbeat min`: Minimum heartbeat timeout.
 * - `heartbeat max`: Maximum heartbeat timeout.
 * - `election min`: Minimum election timeout.
 * - `election max`: Maximum election timeout.
 * - `threshold`: Threshold when the heartbeat RTT is close to the election
 *   timeout.
 *
 * @constructor
 * @param {Object} options Node configuration.
 * @api public
 */
function Node(options) {
  if (!(this instanceof Node)) return new Node(options);

  options = options || {};

  this.election = {
    min: Tick.parse(options['election min'] || '150 ms'),
    max: Tick.parse(options['election max'] || '300 ms')
  };

  this.beat = {
    min: Tick.parse(options['heartbeat min'] || this.election.min),
    max: Tick.parse(options['heartbeat max'] || this.election.max)
  };

  this.votes = {
    for: null,                // Who did we vote for in this current term.
    granted: 0                // How many votes we're granted to us.
  };

  this.threshold = options.threshold || 0.8;
  this.name = options.name || UUID();
  this.timers = new Tick(this);
  this.nodes = [];

  //
  // Raft §5.2:
  //
  // When a server starts, it's always started as Follower and it will remain in
  // this state until receive a message from a Leader or Candidate.
  //
  this.state = Node.FOLLOWER; // Our current state.
  this.leader = null;         // Leader in our cluster.
  this.term = 0;              // Our current term.

  this.initialize(options);
}

//
// Add some sugar and spice and everything nice. Oh, and also inheritance.
//
Node.extend = require('extendable');
Node.prototype = new EventEmitter();
Node.prototype.constructor = Node;

/**
 * Raft §5.1:
 *
 * A Node can be in only one of the various states. The stopped state is not
 * something that is part of the Raft protocol but something we might want to
 * use internally while we're starting or shutting down our node.
 *
 * @type {Number}
 * @private
 */
Node.LEADER    = 1;   // We're selected as leader process.
Node.CANDIDATE = 2;   // We want to be promoted to leader.
Node.FOLLOWER  = 3;   // We're just following a leader.
Node.STOPPED   = 4;   // Assume we're dead.

/**
 * Initialize the node and start listening to the various of events we're
 * emitting as we're quite chatty to provide the maximum amount of flexibility
 * and reconfigurability.
 *
 * @param {Object} options The configuration you passed in the constructor.
 * @api private
 */
Node.prototype.initialize = function initialize(options) {
  //
  // Reset our vote as we're starting a new term. Votes only last one term.
  //
  this.on('term change', function change() {
    this.votes.for = null;
    this.votes.granted = 0;
  });

  //
  // Reset our times and start the heartbeat again. If we're promoted to leader
  // the heartbeat will automatically be broadcasted to users as well.
  //
  this.on('state change', function change(currently, previously) {
    this.timers.clear();
    this.heartbeat();
  });

  //
  // Receive incoming messages and process them.
  //
  this.on('data', function incoming(packet, write) {
    write = write || nope;

    if ('object' !== type(packet)) {
      return write(new Error('Invalid packet received'));
    }

    //
    // Raft §5.1:
    //
    // Applies to all states. If a response contains a higher term then our
    // current term need to change our state to FOLLOWER and set the received
    // term.
    //
    // If the node receives a request with a stale term number it should be
    // rejected.
    //
    if (packet.term > this.term) {
      this.change({
        leader: packet.leader,
        state: Node.FOLLOWER,
        term: packet.term
      });
    } else if (packet.term < this.term) {
      return write(new Error('Stale term detected, we are at '+ this.term));
    }

    //
    // Raft §5.2:
    //
    // If we receive a message from someone who claims to be leader and shares
    // our same term while we're in candidate mode we will recognize their
    // leadership and return as follower
    //
    if (Node.LEADER === packet.state && Node.FOLLOWER !== this.state) {
      this.change({ state: Node.FOLLOWER, leader: packet.leader });
    }

    //
    // Always when we receive an message from the Leader we need to reset our
    // heartbeat.
    //
    if (Node.LEADER === packet.state) {
      this.heartbeat();
    }

    switch (packet.type) {
      //
      // Raft §5.2:
      // Raft §5.4:
      //
      // A node asked us to vote on them. We can only vote to them if they
      // represent a higher term (and last log term, last log index).
      //
      case 'vote':
        //
        // The term of the vote is bigger then ours so we need to update it. If
        // it's the same and we already voted, we need to deny the vote.
        //
        if (this.votes.for && this.votes.for !== packet.name) {
          this.emit('vote', packet, false);
          return write(undefined, this.packet('vote', { granted: false }));
        }

        //
        // If we maintain a log, check if the candidates log is as up to date as
        // ours.
        //

        //
        // We've made our decision, we haven't voted for this term yet and this
        // candidate came in first so it gets our vote as all requirements are
        // met.
        //
        this.votes.for = packet.name;
        this.emit('vote', packet, true);
        write(undefined, this.packet('vote', { granted: true }));
      break;

      //
      // A new incoming vote.
      //
      case 'voted':
        //
        // Only accepts votes while we're still in a CANDIDATE state.
        //
        if (Node.CANDIDATE !== this.state) {
          return write(new Error('No longer a candidate'));
        }

        //
        // Increment our received votes when our voting request has been
        // granted by the node that received the data.
        //
        if (packet.data.granted) this.votes.granted++;

        //
        // Check if we've received the minimal amount of votes required for this
        // current voting round to be considered valid
        //
        if (this.quorum(this.votes.granted)) {
          this.change({ leader: this.name, state: Node.LEADER });
        }

        //
        // Empty write, nothing to do.
        //
        write();
      break;

      case 'append':
      break;

      case 'log':
      break;

      //
      // Unknown event, we have no idea how to process this so we're going to
      // return an error.
      //
      default:
        write(new Error('Unknown message type: '+ packet.type));
    }
  });

  //
  // Setup the log appends.
  //

  //
  // The node is now listening to events so we can start our heartbeat timeout.
  // So that if we don't hear anything from a leader we can promote our selfs to
  // a candidate state.
  //
  this.heartbeat();
};

/**
 * Check if we've reached our quorum (a.k.a. minimum amount of votes requires
 * for a voting round to be considered valid) for the given amount of votes.
 *
 * @param {Number} responses Amount of responses received.
 * @returns {Boolean}
 * @api private
 */
Node.prototype.quorum = function quorum(responses) {
  if (!this.nodes.length || !responses) return false;
  return responses >= this.majority();
};

/**
 * The majority required to reach our the quorum.
 *
 * @returns {Number}
 * @api private
 */
Node.prototype.majority = function majority() {
  return Math.ceil(this.nodes.length / 2) + 1;
};

/**
 * Process a change in the node.
 *
 * @param {Object} changed Data that is changed.
 * @returns {Node}
 * @api private
 */
Node.prototype.change = function change(changed) {
  var changes = ['term', 'leader', 'state']
    , currently, previously
    , i = 0;

  if (!changed) return this;

  for (; i < changes.length; i++) {
    if (changes[i] in changed && changed[changes[i]] !== this[changes[i]]) {
      currently = changed[changes[i]];
      previously = this[changes[i]];

      this[changes[i]] = currently;
      this.emit(changes[i] +' change', currently, previously);
    }
  }

  return this;
};

/**
 * Start or update the heartbeat of the Node. If we detect that we've received
 * a heartbeat timeout we will promote our selfs to a candidate to take over the
 * leadership.
 *
 * @param {String|Number} duration Time it would take for the heartbeat to timeout.
 * @returns {Node}
 * @api public
 */
Node.prototype.heartbeat = function heartbeat(duration) {
  duration = duration || this.timeout('beat');

  if (this.timers.active('heartbeat')) {
    this.timers.adjust('heartbeat', duration);
    return this;
  }

  this.timers.setTimeout('heartbeat', function () {
    if (Node.LEADER !== this.state) {
      this.emit('heartbeat timeout');
      return this.promote();
    }

    //
    // We're the LEADER so we should be broadcasting.
    //
    this.broadcast('heartbeat');
  }, duration);

  return this;
};

/**
 * Generate the various of timeouts.
 *
 * @param {String} which Type of timeout we want to generate.
 * @returns {Number}
 * @api public
 */
Node.prototype.timeout = function timeout(which) {
  var times = this[which];

  return Math.floor(Math.random() * (times.max - times.min + 1) + times.min);
};

/**
 * Raft §5.2:
 *
 * We've detected a timeout from the leaders heartbeats and need to start a new
 * election for leadership. We increment our current term, set the CANDIDATE
 * state, vote our selfs and ask all others nodes to vote for us.
 *
 * @returns {Node}
 * @api public
 */
Node.prototype.promote = function promote() {
  this.change({
    state: Node.CANDIDATE,  // We're now a candidate,
    term: this.term + 1,    // but only for this term.
    leader: ''              // We no longer have a leader.
  });

  //
  // Candidates are always biased and vote for them selfs first before sending
  // out a voting request to all other nodes in the cluster.
  //
  this.votes.for = this.name;
  this.votes.granted = 1;

  //
  // Set the election timeout. This gives the nodes some time to reach
  // consensuses about who they want to vote for. If no consensus has been
  // reached within the set timeout we will attempt it again.
  //
  this.timers.setTimeout('election', this.promote, this.timeout('election'));

  return this;
};

/**
 * Broadcast a message.
 *
 * @param {String} type Message type we're trying to send.
 * @param {Mixed} data Data to be transfered.
 * @returns {Boolean} Successful write.
 * @api public
 */
Node.prototype.broadcast = function broadcast(type, data) {
  var packet = this.packet(type, data);
};

/**
 * Wrap the outgoing messages in an object with additional required data.
 *
 * @param {String} type Message type we're trying to send.
 * @param {Mixed} data Data to be transfered.
 * @returns {Object} Packet.
 * @api private
 */
Node.prototype.packet = function packet(type, data) {
  return {
    state:  this.state,   // So you know if we're a leader, candidate or follower.
    term:   this.term,    // Our current term so we can find mis matches.
    name:   this.name,    // Name of the sender.
    data:   data,         // Custom data we send.
    type:   type,         // Message type.
    leader: this.leader   // Who is our leader.
  };
};

/**
 * This Node needs to be shut down.
 *
 * @returns {Boolean} Successful destruction.
 * @api public
 */
Node.prototype.end = function end() {
  if (!this.state) return false;

  this.timers.end();
  this.removeAllListeners();

  this.timers = this.state = this.write = this.read = null;

  return true;
};

//
// Expose the module interface.
//
module.exports = Node;
<|endoftext|>


<commit_before>var request = require("request");
var progress = require("request-progress");
var fs = require("fs");
var uuid = require("node-uuid");

var app = require("express")();
var serveStatic = require("serve-static");
var server = require("http").createServer(app);

var logger = new (require("winston").Logger)({
	transports: [
		new (winston.transports.Console)()
	],
	levels: {
		"info": 0,
		"notable": 1,
		"warning": 2,
		"error": 3
	}
});

var state = {
	"logger": logger,
	"downloads": {},
	"config": {
		"downloadDir": "./download/", // The directorie to download files to
		"port": process.env.PORT || 8080 // Port to serve on
	},
	"server": server,
	"app": app,
	"emitter": new (require('events').EventEmitter),
	"funcs": {}
}

// Make sure the download directorie exists
if(!fs.existsSync(state.config.downloadDir)) {
	fs.mkdirSync(state.config.downloadDir);
	logger.log("info", "created download directorie", state.config.downloadDir);
}

/**
 * Functions
 */

state.funcs.download = function(filename, url, executor) {
	if (filename == null || typeof filename !== "string" || filename.length <= 0 ||
		url == null      || typeof url !== "string"      || url.length <= 0) {
			logger.log("warning", "invalid arguments to download", {
				"connectionMethod": executor.protocol,
				"clientIp": executor.ip,
				"data": data
			});
			return;
	}

	// Start the download
	var d = {
		request: progress(request(url)),	// The Request object
		id: uuid.v4(),							// ID
		filename: filename,						// Filename
		url: url,								// Url downloaded from
		status: "working",						// Initial status
		progress: 0,							// Percent downloaded
		startedBy: executor.ip,					// The ip who initiated the download
		startedWith: executor.protocol			// The protocol the download was started with
	}

	state.downloads[d.id] = d;// List the download for further reference

	// Sends out progress status when we get them
	d.request.on("progress", function (download) {
		d.progress = download.percent;
		state.emitter.emit("progress", d);
	});

	// Open a write stream for writing the downloaded file to disk
	var f = fs.createWriteStream(state.config.downloadDir + filename);

	// Triggerd when when the stream is closed
	f.on("close", function (err) {
		if (d.status !== "aborted") {
			d.status = "finished";
			state.emitter.emit("status changed", d);
		}
	});

	// Write downloaded data to the stream
	d.request.pipe(f);

	// Incase the download fails
	d.request.on("error", function (err) {
		d.status = "failed";
		state.emitter.emit("status changed", d);

		logger.log("error", "download failed", {
			"filename": d.filename,
			"url": d.url,
			"startedBy": d.startedBy,
			"error": err
		});
	});

	// Info all clients that there is a new download
	state.emitter.emit("download started", d);

	logger.log("notable", "download started", {
		"connectionMethod": executor.protocol,
		"clientIp": executor.ip,
		"filename": filename,
		"url": url
	});
}

state.funcs.abort = function(id, executor) {
	var d = state.downloads[id];
	if (d === null || d == undefined) {
		logger.log("warning", "invalid id given to abort", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"undefined": id === undefined,
			"null": id === null
		});
		return;
	}
	if (d.status == "working") {
		d.request.abort();
		d.status = "aborted";

		state.emitter.emit("status changed", d);

		logger.log("notable", "download aborted", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"filename": d.filename
		});
	} else {
		logger.log("warning", "attempted to abort non-working download", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"filename": d.filename,
			"status": d.status
		});
	}
}

state.funcs.exists = function(filename, cb) {
	fs.exists(state.config.downloadDir + filename, function(exists) {
		cb(exists);
	});
}

state.funcs.remove = function(id, executor) {
	var d = state.downloads[id];
	if (d === null || d == undefined) {
		logger.log("warning", "invalid id given to remove", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"undefined": id === undefined,
			"null": id === null
		});
		return;
	}
	if (d.status != "working") {
		delete state.downloads[id];

		state.emitter.emit("download removed", d);

		logger.log("info", "download removed", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"filename": d.filename
		});
	} else {
		logger.log("warning", "attempted to remove working download", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"filename": d.filename,
			"status": d.status
		});
	}
}

// Setup websocket
require(__dirname + "/libs/websocket.js")(state);

// Serves static files that a system specific
app.use("/", serveStatic(__dirname + "/public", {
	extension: ["html"],
	lastModified: true,
	dotfiles: "ignore"
}));

// Serves bower components
app.use("/bower_components", serveStatic(__dirname + "/bower_components", {
	extension: ["html"],
	lastModified: true,
	dotfiles: "ignore"
}));

//Start the server
server.listen(state.config.port);
<commit_msg>Fix<commit_after>var request = require("request");
var progress = require("request-progress");
var fs = require("fs");
var uuid = require("node-uuid");
var winston = require("winston");

var app = require("express")();
var serveStatic = require("serve-static");
var server = require("http").createServer(app);

var logger = new (winston.Logger)({
	transports: [
		new (winston.transports.Console)()
	],
	levels: {
		"info": 0,
		"notable": 1,
		"warning": 2,
		"error": 3
	}
});

var state = {
	"logger": logger,
	"downloads": {},
	"config": {
		"downloadDir": "./download/", // The directorie to download files to
		"port": process.env.PORT || 8080 // Port to serve on
	},
	"server": server,
	"app": app,
	"emitter": new (require('events').EventEmitter),
	"funcs": {}
}

// Make sure the download directorie exists
if(!fs.existsSync(state.config.downloadDir)) {
	fs.mkdirSync(state.config.downloadDir);
	logger.log("info", "created download directorie", state.config.downloadDir);
}

/**
 * Functions
 */

state.funcs.download = function(filename, url, executor) {
	if (filename == null || typeof filename !== "string" || filename.length <= 0 ||
		url == null      || typeof url !== "string"      || url.length <= 0) {
			logger.log("warning", "invalid arguments to download", {
				"connectionMethod": executor.protocol,
				"clientIp": executor.ip,
				"data": data
			});
			return;
	}

	// Start the download
	var d = {
		request: progress(request(url)),	// The Request object
		id: uuid.v4(),							// ID
		filename: filename,						// Filename
		url: url,								// Url downloaded from
		status: "working",						// Initial status
		progress: 0,							// Percent downloaded
		startedBy: executor.ip,					// The ip who initiated the download
		startedWith: executor.protocol			// The protocol the download was started with
	}

	state.downloads[d.id] = d;// List the download for further reference

	// Sends out progress status when we get them
	d.request.on("progress", function (download) {
		d.progress = download.percent;
		state.emitter.emit("progress", d);
	});

	// Open a write stream for writing the downloaded file to disk
	var f = fs.createWriteStream(state.config.downloadDir + filename);

	// Triggerd when when the stream is closed
	f.on("close", function (err) {
		if (d.status !== "aborted") {
			d.status = "finished";
			state.emitter.emit("status changed", d);
		}
	});

	// Write downloaded data to the stream
	d.request.pipe(f);

	// Incase the download fails
	d.request.on("error", function (err) {
		d.status = "failed";
		state.emitter.emit("status changed", d);

		logger.log("error", "download failed", {
			"filename": d.filename,
			"url": d.url,
			"startedBy": d.startedBy,
			"error": err
		});
	});

	// Info all clients that there is a new download
	state.emitter.emit("download started", d);

	logger.log("notable", "download started", {
		"connectionMethod": executor.protocol,
		"clientIp": executor.ip,
		"filename": filename,
		"url": url
	});
}

state.funcs.abort = function(id, executor) {
	var d = state.downloads[id];
	if (d === null || d == undefined) {
		logger.log("warning", "invalid id given to abort", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"undefined": id === undefined,
			"null": id === null
		});
		return;
	}
	if (d.status == "working") {
		d.request.abort();
		d.status = "aborted";

		state.emitter.emit("status changed", d);

		logger.log("notable", "download aborted", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"filename": d.filename
		});
	} else {
		logger.log("warning", "attempted to abort non-working download", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"filename": d.filename,
			"status": d.status
		});
	}
}

state.funcs.exists = function(filename, cb) {
	fs.exists(state.config.downloadDir + filename, function(exists) {
		cb(exists);
	});
}

state.funcs.remove = function(id, executor) {
	var d = state.downloads[id];
	if (d === null || d == undefined) {
		logger.log("warning", "invalid id given to remove", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"undefined": id === undefined,
			"null": id === null
		});
		return;
	}
	if (d.status != "working") {
		delete state.downloads[id];

		state.emitter.emit("download removed", d);

		logger.log("info", "download removed", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"filename": d.filename
		});
	} else {
		logger.log("warning", "attempted to remove working download", {
			"connectionMethod": executor.protocol,
			"clientIp": executor.ip,
			"filename": d.filename,
			"status": d.status
		});
	}
}

// Setup websocket
require(__dirname + "/libs/websocket.js")(state);

// Serves static files that a system specific
app.use("/", serveStatic(__dirname + "/public", {
	extension: ["html"],
	lastModified: true,
	dotfiles: "ignore"
}));

// Serves bower components
app.use("/bower_components", serveStatic(__dirname + "/bower_components", {
	extension: ["html"],
	lastModified: true,
	dotfiles: "ignore"
}));

//Start the server
server.listen(state.config.port);
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-sauce-material-design'
};
<commit_msg>Fixed v-get could not be found issue https://github.com/offirgolan/ember-cp-validations/issues/334<commit_after>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-sauce-material-design',
  setupPreprocessorRegistry(type, registry) {
    this.eachAddonInvoke('setupPreprocessorRegistry', [type, registry]);
  },
};
<|endoftext|>


<commit_before>'use strict';

var raml2obj = require('raml2obj');
var pjson = require('./package.json');
var Q = require('q');
var path = require('path');

/**
 * Render the source RAML object using the config's processOutput function
 *
 * The config object should contain at least the following property:
 * processRamlObj: function that takes the raw RAML object and returns a promise with the rendered HTML
 *
 * @param {(String|Object)} source - The source RAML file. Can be a filename, url, contents of the RAML file,
 * or an already-parsed RAML object.
 * @param {Object} config
 * @param {Function} config.processRamlObj
 * @returns a promise
 */
function render(source, config) {
  config = config || {};
  config.raml2HtmlVersion = pjson.version;

  return raml2obj.parse(source).then(function(ramlObj) {
    ramlObj.config = config;

    if (config.processRamlObj) {
      return config.processRamlObj(ramlObj).then(function(html) {
        if (config.postProcessHtml) {
          return config.postProcessHtml(html);
        }

        return html;
      });
    }

    return ramlObj;
  });
}

/**
 * @param {String} [mainTemplate] - The filename of the main template, leave empty to use default templates
 * @param {String} [templatesPath] - Optional, by default it uses the current working directory
 * @returns {{processRamlObj: Function, postProcessHtml: Function}}
 */
function getDefaultConfig(mainTemplate, templatesPath) {
  if (!mainTemplate) {
    // When using the default templates, using raml2html's lib folder as the templates path
    mainTemplate = 'template.nunjucks';
    templatesPath = path.join(__dirname, 'lib');
  }

  return {
    processRamlObj: function(ramlObj) {
      var nunjucks = require('nunjucks');
      var markdown = require('nunjucks-markdown');
      var marked = require('marked');
      var renderer = new marked.Renderer();
      renderer.table = function(thead, tbody) {
        // Render Bootstrap style tables
        return '

' + thead + '

' + tbody + '

';
      };

      // Setup the Nunjucks environment with the markdown parser
      var env = nunjucks.configure(templatesPath, {watch: false});
      markdown.register(env, marked);

      // Render the main template using the raml object and fix the double quotes
      var html = nunjucks.render(mainTemplate, ramlObj);
      html = html.replace(/"/g, '"');

      // Return the promise with the html
      return Q.fcall(function() {
        return html;
      });
    },

    postProcessHtml: function(html) {
      // Minimize the generated html and return the promise with the result
      var Minimize = require('minimize');
      var minimize = new Minimize({quotes: true});

      var deferred = Q.defer();

      minimize.parse(html, function(error, result) {
        if (error) {
          deferred.reject(new Error(error));
        } else {
          deferred.resolve(result);
        }
      });

      return deferred.promise;
    }
  };
}

module.exports.getDefaultConfig = getDefaultConfig;
module.exports.render = render;
<commit_msg>Nicer exports<commit_after>'use strict';

var raml2obj = require('raml2obj');
var pjson = require('./package.json');
var Q = require('q');
var path = require('path');

/**
 * Render the source RAML object using the config's processOutput function
 *
 * The config object should contain at least the following property:
 * processRamlObj: function that takes the raw RAML object and returns a promise with the rendered HTML
 *
 * @param {(String|Object)} source - The source RAML file. Can be a filename, url, contents of the RAML file,
 * or an already-parsed RAML object.
 * @param {Object} config
 * @param {Function} config.processRamlObj
 * @returns a promise
 */
function render(source, config) {
  config = config || {};
  config.raml2HtmlVersion = pjson.version;

  return raml2obj.parse(source).then(function(ramlObj) {
    ramlObj.config = config;

    if (config.processRamlObj) {
      return config.processRamlObj(ramlObj).then(function(html) {
        if (config.postProcessHtml) {
          return config.postProcessHtml(html);
        }

        return html;
      });
    }

    return ramlObj;
  });
}

/**
 * @param {String} [mainTemplate] - The filename of the main template, leave empty to use default templates
 * @param {String} [templatesPath] - Optional, by default it uses the current working directory
 * @returns {{processRamlObj: Function, postProcessHtml: Function}}
 */
function getDefaultConfig(mainTemplate, templatesPath) {
  if (!mainTemplate) {
    // When using the default templates, using raml2html's lib folder as the templates path
    mainTemplate = 'template.nunjucks';
    templatesPath = path.join(__dirname, 'lib');
  }

  return {
    processRamlObj: function(ramlObj) {
      var nunjucks = require('nunjucks');
      var markdown = require('nunjucks-markdown');
      var marked = require('marked');
      var renderer = new marked.Renderer();
      renderer.table = function(thead, tbody) {
        // Render Bootstrap style tables
        return '

' + thead + '

' + tbody + '

';
      };

      // Setup the Nunjucks environment with the markdown parser
      var env = nunjucks.configure(templatesPath, {watch: false});
      markdown.register(env, marked);

      // Render the main template using the raml object and fix the double quotes
      var html = nunjucks.render(mainTemplate, ramlObj);
      html = html.replace(/"/g, '"');

      // Return the promise with the html
      return Q.fcall(function() {
        return html;
      });
    },

    postProcessHtml: function(html) {
      // Minimize the generated html and return the promise with the result
      var Minimize = require('minimize');
      var minimize = new Minimize({quotes: true});

      var deferred = Q.defer();

      minimize.parse(html, function(error, result) {
        if (error) {
          deferred.reject(new Error(error));
        } else {
          deferred.resolve(result);
        }
      });

      return deferred.promise;
    }
  };
}

module.exports = {
  getDefaultConfig: getDefaultConfig,
  render: render
};
<|endoftext|>