<commit_before>
var _ = require('lodash')
var AccessControlProcedure = require('access-controls')

var DEBUG = false

var ACL_ERROR_CODE = 'perm/fail/acl'

function debug() {
  if(DEBUG) {
    console.log.apply(console, arguments)
  }
}

function ACLMicroservicesBuilder(seneca) {
  this._ACLProcedureResolver = undefined
  this._seneca = seneca
  this._allowedProperties = [];

  var self = this

//   seneca.add({role: 'entity', cmd: 'save'}, function(args, callback) {
//     console.log(JSON.stringify(args))
//     this.prior(args, callback)
//   })

  this._executeReadPermissionsWrapper = function(args, callback) {

    if(args.perm$) {

      self._executeReadPermissions(args, callback)

    } else {

      this.prior(args, callback)

    }
  }

  this._executeSavePermissionsWrapper = function(args, callback) {

    if(args.perm$) {

      debug(JSON.stringify(args))
      self._executeSavePermissions(args, callback)

    } else {

      this.prior(args, callback)

    }
  }

  this._executeListPermissionsWrapper = function(args, callback) {

    if(args.perm$) {

      debug(JSON.stringify(args))
      self._executeListPermissions(args, callback)

    } else {

      this.prior(args, callback)

    }
  }

  this._executeRemovePermissionsWrapper = function(args, callback) {
    if(args.perm$) {

      debug(JSON.stringify(args))
      self._executeRemovePermissions(args, callback)

    } else {

      this.prior(args, callback)

    }
  }
}

ACLMicroservicesBuilder.prototype.register = function(accessControls, properties) {
  this._ACLProcedureResolver = AccessControlProcedure.generateActionsMapping(accessControls)
  this._allowedProperties = properties;
}

ACLMicroservicesBuilder.prototype.augmentSeneca = function(seneca) {

  var filterList = this._ACLProcedureResolver.list()
  for(var i = 0 ; i < filterList.length ; i++) {

    switch(filterList[i].match.cmd) {
      case 'load':
        seneca.add(filterList[i].match, this._executeReadPermissionsWrapper)
        break
      case 'save':
        seneca.add(filterList[i].match, this._executeSavePermissionsWrapper)
        break
      case 'list':
        seneca.add(filterList[i].match, this._executeListPermissionsWrapper)
        break
      case 'remove':
        seneca.add(filterList[i].match, this._executeRemovePermissionsWrapper)
        break
      default:
        console.warn('Permissions: command [' + filterList[i].match.cmd + '] is not implemented but is used in an ACL rule.')
    }

  }
}

ACLMicroservicesBuilder.prototype._executeRemovePermissions = function(args, callback) {
  var self = this

  var roles = extractRoles(args)
  var context = extractContext(args)
  var entityDef = extractEntityDef(args)

  delete args.perm$

  if(args.q.id) {

    this._loadAndAuthorize(entityDef, args.q.id, args.cmd, roles, context, function(err, dbEntity) {

      if(err) {

        callback(err, undefined)

      } else {

        self._seneca.act(args, function(err, entity) {
          if(err) {
            return callback(err, undefined)
          }
          // the entity returned by the remove needs to be filtered again
          self._filter(entityDef, entity, 'load', roles, context, function(err, entity) {
            callback(err, entity)
          })
        })

      }
    })

  } else {
    var err = new Error('ACL permissions deny multi delete. A query id is required')
    callback(err, undefined)
  }

}

ACLMicroservicesBuilder.prototype._executeReadPermissions = function(args, callback) {
  var self = this
  var roles = extractRoles(args)
  var context = extractContext(args)
  var entityDef = extractEntityDef(args)

  delete args.perm$

  this._seneca.act(args, function(err, entity) {

    if(err || !entity) {
      callback(err, undefined)
    } else {
      // console.log('ENTITY', entity)
      // console.log('CONTEXT', context)
      self._deepAuthorize(entityDef, entity, args.cmd, args.cmd, roles, context, true, function(err, entity) {
        callback(err, entity)
      })

    }

  })
}

ACLMicroservicesBuilder.prototype._executeListPermissions = function(args, callback) {
  var self = this
  var roles = extractRoles(args)
  var context = extractContext(args)
  var entityDef = extractEntityDef(args)

  delete args.perm$

  this._seneca.act(args, function(err, entities) {

    if(err) {
      callback(err, undefined)
    } else if(entities && entities.length > 0) {

      var filteredEntities = []
      var callbackCount = 0
      var stopAll = false

      // this closure is evil
      function processAuthResultForEntity(err, entity) {

        if(stopAll) return

        if(err && err.code !== ACL_ERROR_CODE) {
          stopAll = true
          callback(err, undefined)
        } else {

          if(entity) {
            filteredEntities.push(entity)
          }
          callbackCount ++
          if(callbackCount === entities.length) {
            callback(undefined, filteredEntities)
          }
        }
      }

      for(var i = 0 ; i < entities.length ; i++) {
        self._deepAuthorize(entityDef, entities[i], args.cmd, args.cmd, roles, context, true, processAuthResultForEntity)
      }

    } else {
      callback(undefined, [])
    }

  })
}

ACLMicroservicesBuilder.prototype._executeSavePermissions = function(args, callback) {
  var self = this

  var roles = extractRoles(args)
  var context = extractContext(args)
  var entityDef = extractEntityDef(args)

  delete args.perm$

  if(args.ent.id) { // update

    this._loadAndAuthorize(entityDef, args.ent.id, args.cmd, roles, context, function(err, dbEntity) {

      if(err) {

        callback(err, undefined)

      } else {

        // also execute permission checks on the new attributes
        self._deepAuthorize(entityDef, args.ent, args.cmd, 'save_new', roles, context, true, function(err, filteredEntity) {

          if(err) {

            callback(err, undefined)

          } else {

            merge(dbEntity, args.ent)

            delete args.perm$

            self._seneca.act(args, function(err, entity) {
              if(err) {
                return callback(err, undefined)
              }
              // the entity returned by the save needs to be filtered again
              self._filter(entityDef, entity, 'load', roles, context, function(err, entity) {
                callback(err, entity)
              })

            })
          }

        })
      }
    })

  } else { // create

    self._deepAuthorize(entityDef, args.ent, args.cmd, 'save_new', roles, context, true, function(err, filteredEntity) {

      if(err) {
        callback(err, undefined)
      } else {

        delete args.perm$

        self._seneca.act(args, function(err, entity) {
          if(err) {
            return callback(err, undefined)
          }
          // the entity returned by the save needs to be filtered again
          self._filter(entityDef, entity, 'load', roles, context, function(err, entity) {
            callback(err, entity)
          })
        })
      }

    })
  }

}

ACLMicroservicesBuilder.prototype._loadAndAuthorize = function(entityDef, entityId, action, roles, context, callback) {

  var self = this

  var ent = this._seneca.make(canonize(entityDef))

  ent.load$(entityId, function(err, dbEntity) {
    if(err || !dbEntity) {
      return callback(err, null)
    }

    if(action === 'save') {
      var ruleAction = 'save_existing'
    } else {
      ruleAction = action
    }

    self._deepAuthorize(entityDef, dbEntity, action, ruleAction, roles, context, false, function(err, entity) {
      callback(err, err ? undefined : dbEntity)
    })
  })
}

ACLMicroservicesBuilder.prototype._filter = function(entityDef, entity, action, roles, context, callback) {
  var aclProcedure = AccessControlProcedure.getProcedureForEntity(this._ACLProcedureResolver, entityDef, action)
  if(aclProcedure) {
    aclProcedure.authorize(entity, action, roles, context, function(err, authDecision) {
      if(err) {
        callback(err, undefined)
      } else {
        aclProcedure.applyFilters(authDecision.filters, entity, action)
        callback(undefined, entity)
      }
    })
  } else {
    setImmediate(function() {
      callback(undefined, entity)
    })
  }
}

ACLMicroservicesBuilder.prototype._deepAuthorize = function(entityDef, entity, action, ruleAction, roles, context, applyFilters, callback) {
  var self = this

  var aclProcedure = AccessControlProcedure.getProcedureForEntity(self._ACLProcedureResolver, entityDef, action)

  var allowedProperties = this._allowedProperties

  debug('_deepAuthorize', action, entityDef, 'id=', entity.id, 'roles=', roles, aclProcedure ? 'with procedure' : 'no procedure')
  if(aclProcedure) {
    aclProcedure.authorize(entity, ruleAction, roles, context, function(err, authDecision) {
      if(err) {
        callback(err, undefined)
      } else {
        //console.log(JSON.stringify(authDecision, null, 2))
        debug('_deepAuthorize decision', JSON.stringify(authDecision))
        var inheritDetails = inherit(authDecision)

        if(applyFilters) {
          aclProcedure.applyFilters(authDecision.filters, entity, action)
        }

        if(inheritDetails) {

          // TODO: log
          self._loadAndAuthorize(inheritDetails.entity, inheritDetails.id, action, roles, context, function(err, inheritedEntity) {

            if(err) {
              callback(err, undefined)
            } else {
              callback(undefined, entity)
            }

          })

        } else if(authDecision.authorize) {

          //TODO: log auth granted
          callback(undefined, entity)

        } else if(!authDecision.authorize && !authDecision.hard && action === 'list') {
          for(var property in entity) {
            if(entity.hasOwnProperty(property)) {
              var propertyAllowed = allowedProperties.indexOf(property);
              if(propertyAllowed === -1) {
                delete entity[property];
              }
            }
          }
          callback(undefined, entity)

        } else if(!authDecision.authorize && authDecision.hard && action === 'list') {
          callback(error(self._seneca, authDecision), undefined)
        } else {

          // TODO: log
          callback(error(self._seneca, authDecision), undefined)
        }

      }
    })
  } else {
    console.log('no acls for', JSON.stringify(entityDef), action)
    callback(undefined, entity)
  }
}

function error(seneca, authDecision) {
  var err = new Error('Permission Denied')
  err.reason = authDecision
  err.code = ACL_ERROR_CODE
  err.status = 401
  err.httpstatus = 401
  err.seneca = seneca
  err.toString = selfErrorString
  return err
}

function selfErrorString() {
  var jsonReadyError = {
    message: this.message,
    status: this.status,
    code: this.code,
    reason: this.reason
  };
  return JSON.stringify(jsonReadyError);
}

function extractRoles(args) {
  return args.perm$.roles
}

function extractContext(args) {
  return {
    user: args.user$
  }
}

function extractEntityDef(args) {
  return {
    zone: args.zone,
    base: args.base,
    name: args.name
  }
}

function canonize(entityDef) {
  return (entityDef.zone || '-') + '/' + (entityDef.base || '-') + '/' + entityDef.name
}

function inherit(authDecision) {
  if(authDecision.authorize && authDecision.inherit && authDecision.inherit.length > 0) {
    return authDecision.inherit[0]
  }
  return false
}

/** Unfortunately, this is mostly for the unit tests to pass.
 * The in-memory store behaviour will completely replace an existing object with
 *   the one being saved. Hence we need to do an in-memory merge before saving.
 * Bug opened against seneca: https://github.com/rjrodger/seneca/issues/43
 */
function merge(source, destination) {
  for(var attr in source) {
    if(!destination.hasOwnProperty(attr) && !/\$$/.test(attr)) {
      destination[attr] = source[attr]
    }
  }
}

ACLMicroservicesBuilder.ACL_ERROR_CODE = ACL_ERROR_CODE

module.exports = ACLMicroservicesBuilder
<commit_msg>check for data type<commit_after>
var _ = require('lodash')
var AccessControlProcedure = require('access-controls')

var DEBUG = false

var ACL_ERROR_CODE = 'perm/fail/acl'

function debug() {
  if(DEBUG) {
    console.log.apply(console, arguments)
  }
}

function ACLMicroservicesBuilder(seneca) {
  this._ACLProcedureResolver = undefined
  this._seneca = seneca
  this._allowedProperties = [];

  var self = this

//   seneca.add({role: 'entity', cmd: 'save'}, function(args, callback) {
//     console.log(JSON.stringify(args))
//     this.prior(args, callback)
//   })

  this._executeReadPermissionsWrapper = function(args, callback) {

    if(args.perm$) {

      self._executeReadPermissions(args, callback)

    } else {

      this.prior(args, callback)

    }
  }

  this._executeSavePermissionsWrapper = function(args, callback) {

    if(args.perm$) {

      debug(JSON.stringify(args))
      self._executeSavePermissions(args, callback)

    } else {

      this.prior(args, callback)

    }
  }

  this._executeListPermissionsWrapper = function(args, callback) {

    if(args.perm$) {

      debug(JSON.stringify(args))
      self._executeListPermissions(args, callback)

    } else {

      this.prior(args, callback)

    }
  }

  this._executeRemovePermissionsWrapper = function(args, callback) {
    if(args.perm$) {

      debug(JSON.stringify(args))
      self._executeRemovePermissions(args, callback)

    } else {

      this.prior(args, callback)

    }
  }
}

ACLMicroservicesBuilder.prototype.register = function(accessControls, properties) {
  this._ACLProcedureResolver = AccessControlProcedure.generateActionsMapping(accessControls)
  this._allowedProperties = properties;
}

ACLMicroservicesBuilder.prototype.augmentSeneca = function(seneca) {

  var filterList = this._ACLProcedureResolver.list()
  for(var i = 0 ; i < filterList.length ; i++) {

    switch(filterList[i].match.cmd) {
      case 'load':
        seneca.add(filterList[i].match, this._executeReadPermissionsWrapper)
        break
      case 'save':
        seneca.add(filterList[i].match, this._executeSavePermissionsWrapper)
        break
      case 'list':
        seneca.add(filterList[i].match, this._executeListPermissionsWrapper)
        break
      case 'remove':
        seneca.add(filterList[i].match, this._executeRemovePermissionsWrapper)
        break
      default:
        console.warn('Permissions: command [' + filterList[i].match.cmd + '] is not implemented but is used in an ACL rule.')
    }

  }
}

ACLMicroservicesBuilder.prototype._executeRemovePermissions = function(args, callback) {
  var self = this

  var roles = extractRoles(args)
  var context = extractContext(args)
  var entityDef = extractEntityDef(args)

  delete args.perm$

  if(args.q.id) {

    this._loadAndAuthorize(entityDef, args.q.id, args.cmd, roles, context, function(err, dbEntity) {

      if(err) {

        callback(err, undefined)

      } else {

        self._seneca.act(args, function(err, entity) {
          if(err) {
            return callback(err, undefined)
          }
          // the entity returned by the remove needs to be filtered again
          self._filter(entityDef, entity, 'load', roles, context, function(err, entity) {
            callback(err, entity)
          })
        })

      }
    })

  } else {
    var err = new Error('ACL permissions deny multi delete. A query id is required')
    callback(err, undefined)
  }

}

ACLMicroservicesBuilder.prototype._executeReadPermissions = function(args, callback) {
  var self = this
  var roles = extractRoles(args)
  var context = extractContext(args)
  var entityDef = extractEntityDef(args)

  delete args.perm$

  this._seneca.act(args, function(err, entity) {

    if(err || !entity) {
      callback(err, undefined)
    } else {
      // console.log('ENTITY', entity)
      // console.log('CONTEXT', context)
      self._deepAuthorize(entityDef, entity, args.cmd, args.cmd, roles, context, true, function(err, entity) {
        callback(err, entity)
      })

    }

  })
}

ACLMicroservicesBuilder.prototype._executeListPermissions = function(args, callback) {
  var self = this
  var roles = extractRoles(args)
  var context = extractContext(args)
  var entityDef = extractEntityDef(args)

  delete args.perm$

  this._seneca.act(args, function(err, entities) {

    if(err) {
      callback(err, undefined)
    } else if(entities && entities.length > 0) {

      var filteredEntities = []
      var callbackCount = 0
      var stopAll = false

      // this closure is evil
      function processAuthResultForEntity(err, entity) {

        if(stopAll) return

        if(err && err.code !== ACL_ERROR_CODE) {
          stopAll = true
          callback(err, undefined)
        } else {

          if(entity) {
            filteredEntities.push(entity)
          }
          callbackCount ++
          if(callbackCount === entities.length) {
            callback(undefined, filteredEntities)
          }
        }
      }

      for(var i = 0 ; i < entities.length ; i++) {
        self._deepAuthorize(entityDef, entities[i], args.cmd, args.cmd, roles, context, true, processAuthResultForEntity)
      }

    } else {
      callback(undefined, [])
    }

  })
}

ACLMicroservicesBuilder.prototype._executeSavePermissions = function(args, callback) {
  var self = this

  var roles = extractRoles(args)
  var context = extractContext(args)
  var entityDef = extractEntityDef(args)

  delete args.perm$

  if(args.ent.id) { // update

    this._loadAndAuthorize(entityDef, args.ent.id, args.cmd, roles, context, function(err, dbEntity) {

      if(err) {

        callback(err, undefined)

      } else {

        // also execute permission checks on the new attributes
        self._deepAuthorize(entityDef, args.ent, args.cmd, 'save_new', roles, context, true, function(err, filteredEntity) {

          if(err) {

            callback(err, undefined)

          } else {

            merge(dbEntity, args.ent)

            delete args.perm$

            self._seneca.act(args, function(err, entity) {
              if(err) {
                return callback(err, undefined)
              }
              // the entity returned by the save needs to be filtered again
              self._filter(entityDef, entity, 'load', roles, context, function(err, entity) {
                callback(err, entity)
              })

            })
          }

        })
      }
    })

  } else { // create

    self._deepAuthorize(entityDef, args.ent, args.cmd, 'save_new', roles, context, true, function(err, filteredEntity) {

      if(err) {
        callback(err, undefined)
      } else {

        delete args.perm$

        self._seneca.act(args, function(err, entity) {
          if(err) {
            return callback(err, undefined)
          }
          // the entity returned by the save needs to be filtered again
          self._filter(entityDef, entity, 'load', roles, context, function(err, entity) {
            callback(err, entity)
          })
        })
      }

    })
  }

}

ACLMicroservicesBuilder.prototype._loadAndAuthorize = function(entityDef, entityId, action, roles, context, callback) {

  var self = this

  var ent = this._seneca.make(canonize(entityDef))

  ent.load$(entityId, function(err, dbEntity) {
    if(err || !dbEntity) {
      return callback(err, null)
    }

    if(action === 'save') {
      var ruleAction = 'save_existing'
    } else {
      ruleAction = action
    }

    self._deepAuthorize(entityDef, dbEntity, action, ruleAction, roles, context, false, function(err, entity) {
      callback(err, err ? undefined : dbEntity)
    })
  })
}

ACLMicroservicesBuilder.prototype._filter = function(entityDef, entity, action, roles, context, callback) {
  var aclProcedure = AccessControlProcedure.getProcedureForEntity(this._ACLProcedureResolver, entityDef, action)
  if(aclProcedure) {
    aclProcedure.authorize(entity, action, roles, context, function(err, authDecision) {
      if(err) {
        callback(err, undefined)
      } else {
        aclProcedure.applyFilters(authDecision.filters, entity, action)
        callback(undefined, entity)
      }
    })
  } else {
    setImmediate(function() {
      callback(undefined, entity)
    })
  }
}

ACLMicroservicesBuilder.prototype._deepAuthorize = function(entityDef, entity, action, ruleAction, roles, context, applyFilters, callback) {
  var self = this

  var aclProcedure = AccessControlProcedure.getProcedureForEntity(self._ACLProcedureResolver, entityDef, action)

  var allowedProperties = this._allowedProperties
  var allowedFields = [];
  for(var i = 0; i < allowedProperties.length; i++) {
    if(allowedProperties[i]['entities'][0]['zone'] === entityDef['zone'] && allowedProperties[i]['entities'][0]['base'] === entityDef['base'] && allowedProperties[i]['entities'][0]['name'] === entityDef['name']) {
      allowedFields = allowedProperties[i].fields;
    }
  }

  debug('_deepAuthorize', action, entityDef, 'id=', entity.id, 'roles=', roles, aclProcedure ? 'with procedure' : 'no procedure')
  if(aclProcedure) {
    aclProcedure.authorize(entity, ruleAction, roles, context, function(err, authDecision) {
      if(err) {
        callback(err, undefined)
      } else {
        //console.log(JSON.stringify(authDecision, null, 2))
        debug('_deepAuthorize decision', JSON.stringify(authDecision))
        var inheritDetails = inherit(authDecision)

        if(applyFilters) {
          aclProcedure.applyFilters(authDecision.filters, entity, action)
        }

        if(inheritDetails) {

          // TODO: log
          self._loadAndAuthorize(inheritDetails.entity, inheritDetails.id, action, roles, context, function(err, inheritedEntity) {

            if(err) {
              callback(err, undefined)
            } else {
              callback(undefined, entity)
            }

          })

        } else if(authDecision.authorize) {
          //TODO: log auth granted
          callback(undefined, entity)

        } else if(!authDecision.authorize && !authDecision.hard && action === 'list') {
          for(var property in entity) {
            if(entity.hasOwnProperty(property)) {
              var propertyAllowed = allowedFields.indexOf(property);
              if(propertyAllowed === -1) {
                delete entity[property];
              }
            }
          }

          callback(undefined, entity)

        } else if(!authDecision.authorize && authDecision.hard && action === 'list') {
          callback(error(self._seneca, authDecision), undefined)
        } else {

          // TODO: log
          callback(error(self._seneca, authDecision), undefined)
        }

      }
    })
  } else {
    console.log('no acls for', JSON.stringify(entityDef), action)
    callback(undefined, entity)
  }
}

function error(seneca, authDecision) {
  var err = new Error('Permission Denied')
  err.reason = authDecision
  err.code = ACL_ERROR_CODE
  err.status = 401
  err.httpstatus = 401
  err.seneca = seneca
  err.toString = selfErrorString
  return err
}

function selfErrorString() {
  var jsonReadyError = {
    message: this.message,
    status: this.status,
    code: this.code,
    reason: this.reason
  };
  return JSON.stringify(jsonReadyError);
}

function extractRoles(args) {
  return args.perm$.roles
}

function extractContext(args) {
  return {
    user: args.user$
  }
}

function extractEntityDef(args) {
  return {
    zone: args.zone,
    base: args.base,
    name: args.name
  }
}

function canonize(entityDef) {
  return (entityDef.zone || '-') + '/' + (entityDef.base || '-') + '/' + entityDef.name
}

function inherit(authDecision) {
  if(authDecision.authorize && authDecision.inherit && authDecision.inherit.length > 0) {
    return authDecision.inherit[0]
  }
  return false
}

/** Unfortunately, this is mostly for the unit tests to pass.
 * The in-memory store behaviour will completely replace an existing object with
 *   the one being saved. Hence we need to do an in-memory merge before saving.
 * Bug opened against seneca: https://github.com/rjrodger/seneca/issues/43
 */
function merge(source, destination) {
  for(var attr in source) {
    if(!destination.hasOwnProperty(attr) && !/\$$/.test(attr)) {
      destination[attr] = source[attr]
    }
  }
}

ACLMicroservicesBuilder.ACL_ERROR_CODE = ACL_ERROR_CODE

module.exports = ACLMicroservicesBuilder
<|endoftext|>


<commit_before>"use strict";

const hooks = require('./hooks');
const telegram = require('./telegram');
const express = require('./express');
const monitor = require('./monitor');
const local = require('./local');
const logger = require('./logger');
const rpc = require('./rpc');
const path = require('path');
const Promise = require('promise');
const commandLineCommands = require('command-line-commands');
const getUsage = require("command-line-usage");
const ansi = require('ansi-escape-sequences');
const package_desc = require('../package.json');

const _ = require('underscore');
const s = require("underscore.string");
_.mixin(s.exports());

let tcid = null;
let pid_path = path.resolve(__dirname, '..', '.pid');

const cli_common_conf = [{
  name: 'verbose',
  alias: 'v',
  type: Boolean
}, {
  name: 'telegramid',
  alias: 'T',
  type: String
}];

let monitor_control_def = _.union([], cli_common_conf, [{
  name: 'hook',
  alias: 'H',
  type: String,
  defaultOption: true
}]);

let help_def = _.union([], cli_common_conf, [{
  name: 'hook',
  alias: 'H',
  type: String,
  defaultOption: true
}]);

const main_service = {

  help: function (config, hook_name) {
    return new Promise(function (resolve, reject) {

      hooks.load().then(function () {
        let cm_hooks = hooks.get_hooks("has_command_line_hook");

        let help = "";
        let footer = "-----------------------------";
        hook_name = (hook_name || "");

        let header = [
          "",
          ansi.format(ansi.format(require('../assets/ansi-header'), 'cyan')),
          "",
          ansi.format(`${package_desc.name} v${package_desc.version}`, 'bold'),
          `${package_desc.description}`,
          ""
        ];

        if (hook_name) {
          switch (hook_name) {
          case "help":
            help = getUsage(help_def, {
              header: header,
              description: "This Help",
              title: "Command: help",
              synopsis: "The output of this help will change according to installed hooks"
            });
            break;
          case "start":
            help = getUsage(cli_common_conf, {
              header: header,
              description: "Start the server",
              title: "Command: start",
              synopsis: "Will start the main receiving server"
            });
            break;
          case "reload":
            help = getUsage(cli_common_conf, {
              header: header,
              description: "Reload hooks",
              title: "Command: reload",
              synopsis: "Will reload hook in the main server"
            });
            break;
          case "stop":
            help = getUsage(cli_common_conf, {
              header: header,
              description: "Stop the server",
              title: "Command: stop",
              synopsis: "Will stop the main receiving server"
            });
            break;
          case "monitor:start":
            help = getUsage(monitor_control_def, {
              header: header,
              description: "Start a monitor",
              title: "Command: monitor:start",
              synopsis: "Will start a monitoring hook"
            });
            break;
          case "monitor:stop":
            help = getUsage(monitor_control_def, {
              header: header,
              description: "Stop a monitor",
              title: "Command: monitor:stop",
              synopsis: "Will stop a monitoring hook"
            });
            break;
          case "monitor:restart":
            help = getUsage(monitor_control_def, {
              header: header,
              description: "Restart a monitor",
              title: "Command: monitor:restart",
              synopsis: "Will restart a monitoring hook"
            });
            break;
          default:
            if (config.get("commandline:active") !== false) {
              for (let i = 0; i < cm_hooks.length; i++) {
                let cml = cm_hooks[i];
                if (_.isArray(cml.params)) {
                  help = getUsage(_.union([], cli_common_conf, cml.params), {
                    header: header,
                    description: cml.description,
                    synopsis: cml.help,
                    title: `Command: ${cml.cmd_name}`
                  });
                  break;
                } else {
                  help = getUsage(cli_common_conf, {
                    header: header,
                    description: cml.description,
                    synopsis: cml.help,
                    title: `Command: ${cml.cmd_name}`
                  });
                  break;
                }
              }
            }
            break;
          }
        } else {
          let commands = ["help", "start", "stop", "reload", "monitor:start", "monitor:stop", "monitor:restart"];
          if (config.get("commandline:active") !== false) {
            for (let i = 0; i < cm_hooks.length; i++) {
              let cml = cm_hooks[i];
              commands.push(cml.cmd_name);
            }
          }
          help = getUsage([], {
            header: header,
            synopsis: [
              ansi.format(`${commands.length} commands defined:`, 'bold'),
              "",
              commands.join(", "),
              "",
              footer,
              "",
              "use command " + ansi.format('help', 'cyan') + " followed by " + ansi.format('command name', 'cyan') + " to print command specific help"
            ]
          });
        }
        return resolve(help);
      }).catch(reject);
    });
  },

  parse_commands: function (config, cmd_arguments) {

    return new Promise(function (resolve, reject) {

      hooks.load().then(function () {
        const commandline = require('./commandline');
        let cm_hooks = hooks.get_hooks("has_command_line_hook");

        let cla = [{
          name: 'help',
          definitions: help_def
        }, {
          name: 'start',
          definitions: cli_common_conf
        }, {
          name: 'stop',
          definitions: cli_common_conf
        }, {
          name: 'reload',
          definitions: cli_common_conf
        }, {
          name: 'monitor:start',
          definitions: monitor_control_def
        }, {
          name: 'monitor:stop',
          definitions: monitor_control_def
        }, {
          name: 'monitor:restart',
          definitions: monitor_control_def
        }];

        if (config.get("commandline:active") !== false) {
          for (let i = 0; i < cm_hooks.length; i++) {
            let cml = cm_hooks[i];
            if (_.isArray(cml.params)) {
              cla.push({
                name: cml.cmd_name,
                definitions: _.union([], cli_common_conf, cml.params)
              });
            } else {
              cla.push({
                name: cml.cmd_name,
                definitions: cli_common_conf
              });
            }
          }
        }

        const cli = commandLineCommands(cla);

        let command_line_res = null;

        try {
          if (cmd_arguments) {
            command_line_res = cli.parse(cmd_arguments);
          } else {
            command_line_res = cli.parse();
          }
        } catch (e) {
          logger.error(e);
        }

        const command = _.extend({}, command_line_res);

        tcid = command.telegramid;

        command.name = (command.name || "");
        command.options = (command.options || {});

        resolve(command);

      }).catch(reject);

    });
  },

  start_server: function () {
    return new Promise(function (resolve, reject) {

      hooks.load().then(function () {
        let cm_hooks = hooks.get_hooks("has_command_line_hook");

        const npid = require('npid');
        const pid = npid.create(pid_path, true);
        pid.removeOnExit();
        process.on('uncaughtException', function (err) {
          pid.remove();
          return reject(err);
        });
        process.on('SIGINT', function () {
          pid.remove();
          resolve(`${package_desc.name} v${package_desc.version} stopped.`);
        });
        logger.log(`${package_desc.name} v${package_desc.version} starting...`);

        return telegram.init(tcid).then(local.init).then(monitor.init).then(express.init).then(rpc.init).then(function () {
          logger.log(`${package_desc.name} v${package_desc.version} started.`);
        }).catch(function (error) {
          reject(error);
        });
      }).catch(reject);
    });
  },

  stop_server: function () {
    return new Promise(function (resolve, reject) {
      let fs = require('fs');
      let terminate = Promise.denodeify(require('terminate'));
      const read = Promise.denodeify(fs.readFile);
      let mainpid = "";
      return read(pid_path, 'utf8').then(function (running_pid) {
        mainpid = running_pid;
        return Promise.resolve(mainpid);
      }).then(terminate).then(function (done) {
        return new Promise(function (resolve, reject) {
          if (done) {
            const exec = require('child_process').exec;
            exec(`kill -2 ${mainpid}`, function (error, stdout, stderr) {
              if (error) {
                return reject(error);
              }
              if (stderr.length > 0) {
                return reject(stderr.toString('utf8'));
              } else {
                logger.log(`${package_desc.name} v${package_desc.version} has been stopped.`);
              }
              resolve(true);
            });
          } else {
            resolve(false);
          }
        });
      }).catch(function (error) {
        if (error.code != "ENOENT") {
          logger.error(error);
        } else {
          logger.log(`${package_desc.name} v${package_desc.version} is not running.`);
        }
      }).finally(function () {
        resolve();
      });
    });
  },

  main: function (config, cmd_arguments) {
    return new Promise(function (resolve, reject) {
      return main_service.parse_commands(config, cmd_arguments).then(function (command) {
        if (command.options.verbose) {
          config.set("verbose", true);
        }
        switch (command.name) {
        case 'help':
          main_service.help(config, command.options.hook).then(resolve).catch(reject);
          break
        case '':
          return reject(new Error("No command specified"));
        case 'monitor:start':
          rpc.send("start_monitor", command.options.hook).then(resolve).catch(reject);
          break
        case 'monitor:stop':
          rpc.send("stop_monitor", command.options.hook).then(resolve).catch(reject);
          break
        case 'monitor:restart':
          rpc.send("restart_monitor", command.options.hook).then(resolve).catch(reject);
          break
        case 'stop':
          return main_service.stop_server().then(resolve).catch(reject);
          break
        case 'start':
          return main_service.start_server().then(resolve).catch(reject);
          break
        case 'reload':
          rpc.send("reload_hooks").then(resolve).catch(reject);
          break
        default:
          if (config.get("commandline:active") !== false) {
            telegram.init(tcid).then(commandline.init).then(function () {
              commandline.execute(command.name, command.options).then(resolve).catch(reject)
            }).catch(function (error) {
              logger.error(error);
            });
          }
          break
        }
      }).catch(reject);
    });
  }
}

module.exports = main_service;
<commit_msg>GPIO signaling and monitor<commit_after>"use strict";

const hooks = require('./hooks');
const telegram = require('./telegram');
const express = require('./express');
const monitor = require('./monitor');
const local = require('./local');
const logger = require('./logger');
const rpc = require('./rpc');
const path = require('path');
const Promise = require('promise');
const commandLineCommands = require('command-line-commands');
const getUsage = require("command-line-usage");
const ansi = require('ansi-escape-sequences');
const package_desc = require('../package.json');

const _ = require('underscore');
const s = require("underscore.string");
_.mixin(s.exports());

let tcid = null;
let pid_path = path.resolve(__dirname, '..', '.pid');

const cli_common_conf = [{
  name: 'verbose',
  alias: 'v',
  type: Boolean
}, {
  name: 'telegramid',
  alias: 'T',
  type: String
}, {
  name: 'token',
  alias: 'K',
  type: String
}];

let monitor_control_def = _.union([], cli_common_conf, [{
  name: 'hook',
  alias: 'H',
  type: String,
  defaultOption: true
}]);

let help_def = _.union([], cli_common_conf, [{
  name: 'hook',
  alias: 'H',
  type: String,
  defaultOption: true
}]);

const main_service = {

  help: function (config, hook_name) {
    return new Promise(function (resolve, reject) {

      hooks.load().then(function () {
        let cm_hooks = hooks.get_hooks("has_command_line_hook");

        let help = "";
        let footer = "-----------------------------";
        hook_name = (hook_name || "");

        let header = [
          "",
          ansi.format(ansi.format(require('../assets/ansi-header'), 'cyan')),
          "",
          ansi.format(`${package_desc.name} v${package_desc.version}`, 'bold'),
          `${package_desc.description}`,
          ""
        ];

        if (hook_name) {
          switch (hook_name) {
          case "help":
            help = getUsage(help_def, {
              header: header,
              description: "This Help",
              title: "Command: help",
              synopsis: "The output of this help will change according to installed hooks"
            });
            break;
          case "start":
            help = getUsage(cli_common_conf, {
              header: header,
              description: "Start the server",
              title: "Command: start",
              synopsis: "Will start the main receiving server"
            });
            break;
          case "reload":
            help = getUsage(cli_common_conf, {
              header: header,
              description: "Reload hooks",
              title: "Command: reload",
              synopsis: "Will reload hook in the main server"
            });
            break;
          case "stop":
            help = getUsage(cli_common_conf, {
              header: header,
              description: "Stop the server",
              title: "Command: stop",
              synopsis: "Will stop the main receiving server"
            });
            break;
          case "monitor:start":
            help = getUsage(monitor_control_def, {
              header: header,
              description: "Start a monitor",
              title: "Command: monitor:start",
              synopsis: "Will start a monitoring hook"
            });
            break;
          case "monitor:stop":
            help = getUsage(monitor_control_def, {
              header: header,
              description: "Stop a monitor",
              title: "Command: monitor:stop",
              synopsis: "Will stop a monitoring hook"
            });
            break;
          case "monitor:restart":
            help = getUsage(monitor_control_def, {
              header: header,
              description: "Restart a monitor",
              title: "Command: monitor:restart",
              synopsis: "Will restart a monitoring hook"
            });
            break;
          default:
            if (config.get("commandline:active") !== false) {
              for (let i = 0; i < cm_hooks.length; i++) {
                let cml = cm_hooks[i];
                if (_.isArray(cml.params)) {
                  help = getUsage(_.union([], cli_common_conf, cml.params), {
                    header: header,
                    description: cml.description,
                    synopsis: cml.help,
                    title: `Command: ${cml.cmd_name}`
                  });
                  break;
                } else {
                  help = getUsage(cli_common_conf, {
                    header: header,
                    description: cml.description,
                    synopsis: cml.help,
                    title: `Command: ${cml.cmd_name}`
                  });
                  break;
                }
              }
            }
            break;
          }
        } else {
          let commands = ["help", "start", "stop", "reload", "monitor:start", "monitor:stop", "monitor:restart"];
          if (config.get("commandline:active") !== false) {
            for (let i = 0; i < cm_hooks.length; i++) {
              let cml = cm_hooks[i];
              commands.push(cml.cmd_name);
            }
          }
          help = getUsage([], {
            header: header,
            synopsis: [
              ansi.format(`${commands.length} commands defined:`, 'bold'),
              "",
              commands.join(", "),
              "",
              footer,
              "",
              "use command " + ansi.format('help', 'cyan') + " followed by " + ansi.format('command name', 'cyan') + " to print command specific help"
            ]
          });
        }
        return resolve(help);
      }).catch(reject);
    });
  },

  parse_commands: function (config, cmd_arguments) {

    return new Promise(function (resolve, reject) {

      hooks.load().then(function () {
        const commandline = require('./commandline');
        let cm_hooks = hooks.get_hooks("has_command_line_hook");

        let cla = [{
          name: 'help',
          definitions: help_def
        }, {
          name: 'start',
          definitions: cli_common_conf
        }, {
          name: 'stop',
          definitions: cli_common_conf
        }, {
          name: 'reload',
          definitions: cli_common_conf
        }, {
          name: 'monitor:start',
          definitions: monitor_control_def
        }, {
          name: 'monitor:stop',
          definitions: monitor_control_def
        }, {
          name: 'monitor:restart',
          definitions: monitor_control_def
        }];

        if (config.get("commandline:active") !== false) {
          for (let i = 0; i < cm_hooks.length; i++) {
            let cml = cm_hooks[i];
            if (_.isArray(cml.params)) {
              cla.push({
                name: cml.cmd_name,
                definitions: _.union([], cli_common_conf, cml.params)
              });
            } else {
              cla.push({
                name: cml.cmd_name,
                definitions: cli_common_conf
              });
            }
          }
        }

        const cli = commandLineCommands(cla);

        let command_line_res = null;

        try {
          if (cmd_arguments) {
            command_line_res = cli.parse(cmd_arguments);
          } else {
            command_line_res = cli.parse();
          }
        } catch (e) {
          logger.error(e);
        }

        const command = _.extend({}, command_line_res);

        tcid = command.telegramid;

        if(command.token){
          config.set("telegram:token", command.token);
        }

        command.name = (command.name || "");
        command.options = (command.options || {});

        resolve(command);

      }).catch(reject);

    });
  },

  start_server: function () {
    return new Promise(function (resolve, reject) {

      hooks.load().then(function () {
        let cm_hooks = hooks.get_hooks("has_command_line_hook");

        const npid = require('npid');
        const pid = npid.create(pid_path, true);
        pid.removeOnExit();
        process.on('uncaughtException', function (err) {
          pid.remove();
          return reject(err);
        });
        process.on('SIGINT', function () {
          pid.remove();
          resolve(`${package_desc.name} v${package_desc.version} stopped.`);
        });
        logger.log(`${package_desc.name} v${package_desc.version} starting...`);

        return telegram.init(tcid).then(local.init).then(monitor.init).then(express.init).then(rpc.init).then(function () {
          logger.log(`${package_desc.name} v${package_desc.version} started.`);
        }).catch(function (error) {
          reject(error);
        });
      }).catch(reject);
    });
  },

  stop_server: function () {
    return new Promise(function (resolve, reject) {
      let fs = require('fs');
      let terminate = Promise.denodeify(require('terminate'));
      const read = Promise.denodeify(fs.readFile);
      let mainpid = "";
      return read(pid_path, 'utf8').then(function (running_pid) {
        mainpid = running_pid;
        return Promise.resolve(mainpid);
      }).then(terminate).then(function (done) {
        return new Promise(function (resolve, reject) {
          if (done) {
            const exec = require('child_process').exec;
            exec(`kill -2 ${mainpid}`, function (error, stdout, stderr) {
              if (error) {
                return reject(error);
              }
              if (stderr.length > 0) {
                return reject(stderr.toString('utf8'));
              } else {
                logger.log(`${package_desc.name} v${package_desc.version} has been stopped.`);
              }
              resolve(true);
            });
          } else {
            resolve(false);
          }
        });
      }).catch(function (error) {
        if (error.code != "ENOENT") {
          logger.error(error);
        } else {
          logger.log(`${package_desc.name} v${package_desc.version} is not running.`);
        }
      }).finally(function () {
        resolve();
      });
    });
  },

  main: function (config, cmd_arguments) {
    return new Promise(function (resolve, reject) {
      return main_service.parse_commands(config, cmd_arguments).then(function (command) {
        if (command.options.verbose) {
          config.set("verbose", true);
        }
        switch (command.name) {
        case 'help':
          main_service.help(config, command.options.hook).then(resolve).catch(reject);
          break
        case '':
          return reject(new Error("No command specified"));
        case 'monitor:start':
          rpc.send("start_monitor", command.options.hook).then(resolve).catch(reject);
          break
        case 'monitor:stop':
          rpc.send("stop_monitor", command.options.hook).then(resolve).catch(reject);
          break
        case 'monitor:restart':
          rpc.send("restart_monitor", command.options.hook).then(resolve).catch(reject);
          break
        case 'stop':
          return main_service.stop_server().then(resolve).catch(reject);
          break
        case 'start':
          return main_service.start_server().then(resolve).catch(reject);
          break
        case 'reload':
          rpc.send("reload_hooks").then(resolve).catch(reject);
          break
        default:
          if (config.get("commandline:active") !== false) {
            telegram.init(tcid).then(commandline.init).then(function () {
              commandline.execute(command.name, command.options).then(resolve).catch(reject)
            }).catch(function (error) {
              logger.error(error);
            });
          }
          break
        }
      }).catch(reject);
    });
  }
}

module.exports = main_service;
<|endoftext|>


<commit_before>const ExtendableError = require('./ExtendableError')

/**
 * Error thrown to indicate awilix was expecting a function (or class)
 */
class AwilixNotAFunctionError extends ExtendableError {
  /**
   * Constructor, takes the registered modules and unresolved tokens
   * to create a message.
   *
   * @param {string} name
   * The name of the module that could not be resolved.
   *
   * @param  {string[]} resolutionStack
   * The current resolution stack
   */
  constructor (functionName, expectedType, givenType) {
    super(`The function ${functionName} expected a ${expectedType}, ${givenType} given.`)
  }
}

module.exports = AwilixNotAFunctionError
<commit_msg>Fixed doc comment.<commit_after>const ExtendableError = require('./ExtendableError')

/**
 * Error thrown to indicate Awilix was expecting a function (or a class)
 */
class AwilixNotAFunctionError extends ExtendableError {
  /**
   * Constructor, takes the function name, expected and given
   * type to produce an error.
   *
   * @param {string} functionName
   * Name of the function being guarded.
   *
   * @param {string} expectedType
   * Name of the expected type.
   *
   * @param {string} givenType
   * Name of the given type.
   */
  constructor (functionName, expectedType, givenType) {
    super(`The function ${functionName} expected a ${expectedType}, ${givenType} given.`)
  }
}

module.exports = AwilixNotAFunctionError
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Sgt. Kabukiman, https://bitbucket.org/sgt-kabukiman/
 *
 * This file is released under the terms of the MIT license. You can find the
 * complete text in the attached LICENSE file or online at:
 *
 * http://www.opensource.org/licenses/mit-license.php
 */

var
	ModeMessage   = require('./../ModeMessage.js'),
	TextMessage   = require('./../TextMessage.js'),
	TwitchMessage = require('./../TwitchMessage.js');

var ConsoleOutputPlugin = function(console) {
	this.console = console || window.console;
};

ConsoleOutputPlugin.prototype = {
	process: function(message, twitch) {

		if (message instanceof TextMessage) {
			console.log(message.getUser().getPrefix() + message.getUsername() + ': ' + message.getMessage());
		}
				/*
		else if (message instanceof ModeMessage) {
			console.log('MODE ' + message.getMode() + ' on ' + message.getUsername());
		}
		else {
			console.log(message);
		}
	*/

		return message;
	}
};

module.exports = ConsoleOutputPlugin;
<commit_msg>we don't need this anymore<commit_after>/*
 * Copyright (c) 2014, Sgt. Kabukiman, https://bitbucket.org/sgt-kabukiman/
 *
 * This file is released under the terms of the MIT license. You can find the
 * complete text in the attached LICENSE file or online at:
 *
 * http://www.opensource.org/licenses/mit-license.php
 */

var
	ModeMessage   = require('./../ModeMessage.js'),
	TextMessage   = require('./../TextMessage.js'),
	TwitchMessage = require('./../TwitchMessage.js');

var ConsoleOutputPlugin = function(console) {
	this.console = console || window.console;
};

ConsoleOutputPlugin.prototype = {
	process: function(message, twitch) {
		if (message instanceof TextMessage) {
			console.log(message.getUser().getPrefix() + message.getUsername() + ': ' + message.getMessage());
		}

		return message;
	}
};

module.exports = ConsoleOutputPlugin;
<|endoftext|>


<commit_before>var fs = require("fs");
var files = require("./files");
var index = require("./index");
var objects = require("./objects");
var refs = require("./refs");
var diff = require("./diff");
var checkout = require("./checkout");
var util = require("./util");

var gitletApi = module.exports = {
  init: function(_) {
    if (files.inRepo()) { return; }

    files.writeFilesFromTree({
      ".gitlet": {
        HEAD: "ref: refs/heads/master\n",
        objects: {},
        refs: {
          heads: {},
          remotes: {
            origin: {}
          },
        }
      }
    }, process.cwd());
  },

  add: function(path, _) {
    files.assertInRepo();

    var addedFiles = files.lsRecursive(path);
    if (addedFiles.length === 0) {
      throw "fatal: pathspec '" + files.pathFromRepoRoot(path) + "' did not match any files";
    } else {
      for (var i = 0; i < addedFiles.length; i++) {
        this.update_index(addedFiles[i], { add: true });
      }
    }
  },

  update_index: function(path, opts) {
    files.assertInRepo();
    opts = opts || {};

    var pathFromRoot = files.pathFromRepoRoot(path)
    if (!fs.existsSync(path)) {
      throw "error: " + pathFromRoot + ": does not exist\n";
    } else if (fs.statSync(path).isDirectory()) {
      throw "error: " + pathFromRoot + ": is a directory - add files inside instead\n";
    } else if (!index.readHasFile(path) && opts.add === undefined) {
      throw "error: " + pathFromRoot  + ": cannot add to the index - missing --add option?\n";
    } else {
      index.writeFile(path);
    }
  },

  hash_object: function(file, opts) {
    files.assertInRepo();
    opts = opts || {};

    if (!fs.existsSync(file)) {
      throw "fatal: Cannot open '" + file + "': No such file or directory"
    } else {
      var fileContents = files.read(file);
      if (opts.w) {
        return objects.write(fileContents);
      }

      return util.hash(fileContents);
    }
  },

  write_tree: function(_) {
    files.assertInRepo();
    return objects.writeTree(files.nestFlatTree(index.read()));
  },

  commit: function(opts) {
    files.assertInRepo();

    var headHash = refs.readHash("HEAD");
    var treeHash = this.write_tree();

    if (headHash !== undefined &&
        treeHash === objects.treeHash(objects.read(headHash))) {
      throw "# On " + refs.readCurrentBranchName() + "\n" +
        "nothing to commit, working directory clean";
    } else {
      var isFirstCommit = refs.readHash("HEAD") === undefined;
      var parentHashes = isFirstCommit ? [] : [refs.readHash("HEAD")];
      var commmitHash = objects.write(objects.composeCommit(treeHash, opts.m, parentHashes));
      this.update_ref("HEAD", commmitHash);
      return "[" + refs.readCurrentBranchName() + " " + commmitHash + "] " + opts.m;
    }
  },

  branch: function(name, _) {
    files.assertInRepo();

    if (name === undefined) {
      return refs.readLocalHeads().map(function(branchName) {
        var marker = branchName === refs.readCurrentBranchName() ? "* " : "  ";
        return marker + branchName;
      }).join("\n") + "\n";
    } else if (refs.readHash("HEAD") === undefined) {
      throw "fatal: Not a valid object name: 'master'.";
    } else if (refs.readLocalHeads().filter(function(h) { return h === name; }).length > 0) {
      throw "fatal: A branch named '" + name + "' already exists.";
    } else {
      refs.write(refs.nameToBranchRef(name), refs.readHash("HEAD"));
    }
  },

  update_ref: function(refToUpdate, refToUpdateTo, _) {
    files.assertInRepo();

    if (!refs.isRef(refToUpdate)) {
      throw "fatal: Cannot lock the ref " + refToUpdate + ".";
    } else {
      var hash = refs.readHash(refToUpdateTo);
      if (!objects.readExists(hash)) {
        throw "fatal: " + refToUpdateTo + ": not a valid SHA1";
      } else if (!(objects.type(objects.read(hash)) === "commit")) {
        throw "error: Trying to write non-commit object " + hash + " to branch " +
          refs.readTerminalRef(refToUpdate) + "\n";
      } else {
        refs.write(refs.readTerminalRef(refToUpdate), hash);
      }
    }
  },

  checkout: function(ref, _) {
    files.assertInRepo();

    var hash = refs.readHash(ref);
    if (!objects.readExists(hash)) {
      throw "error: pathspec " + ref + " did not match any file(s) known to gitlet."
    } else if (objects.type(objects.read(hash)) !== "commit") {
      throw "fatal: reference is not a tree: " + ref;
    } else {
      var paths = checkout.readChangedFilesCheckoutWouldOverwrite(hash);
      if (paths.length > 0) {
        throw "error: Aborting. Your local changes to these files would be overwritten:\n" +
	        paths.join("\n") + "\n";
      } else {
        process.chdir(files.repoDir());
        checkout.writeCheckout(ref);
        return objects.readExists(ref) ?
          "Note: checking out " + ref + "\nYou are in 'detached HEAD' state." :
          "Switched to branch '" + ref + "'\n";
      }
    }
  },

  diff: function(ref1, ref2, opts) {
    files.assertInRepo();

    if (ref1 !== undefined && refs.readHash(ref1) === undefined) {
      throw "fatal: ambiguous argument " + ref1 + ": unknown revision";
    } else if (ref2 !== undefined && refs.readHash(ref2) === undefined) {
      throw "fatal: ambiguous argument " + ref2 + ": unknown revision";
    } else {
      if (opts["name-status"] !== true) {
        throw "unsupported"; // for now
      } else {
        var nameToStatus = diff.readDiff(ref1, ref2);
        return Object.keys(nameToStatus)
          .map(function(path) { return nameToStatus[path] + " " + path; })
          .join("\n") + "\n";
      }
    }
  }
};
<commit_msg>Simplify code, reuse vars<commit_after>var fs = require("fs");
var files = require("./files");
var index = require("./index");
var objects = require("./objects");
var refs = require("./refs");
var diff = require("./diff");
var checkout = require("./checkout");
var util = require("./util");

var gitletApi = module.exports = {
  init: function(_) {
    if (files.inRepo()) { return; }

    files.writeFilesFromTree({
      ".gitlet": {
        HEAD: "ref: refs/heads/master\n",
        objects: {},
        refs: {
          heads: {},
          remotes: {
            origin: {}
          },
        }
      }
    }, process.cwd());
  },

  add: function(path, _) {
    files.assertInRepo();

    var addedFiles = files.lsRecursive(path);
    if (addedFiles.length === 0) {
      throw "fatal: pathspec '" + files.pathFromRepoRoot(path) + "' did not match any files";
    } else {
      for (var i = 0; i < addedFiles.length; i++) {
        this.update_index(addedFiles[i], { add: true });
      }
    }
  },

  update_index: function(path, opts) {
    files.assertInRepo();
    opts = opts || {};

    var pathFromRoot = files.pathFromRepoRoot(path)
    if (!fs.existsSync(path)) {
      throw "error: " + pathFromRoot + ": does not exist\n";
    } else if (fs.statSync(path).isDirectory()) {
      throw "error: " + pathFromRoot + ": is a directory - add files inside instead\n";
    } else if (!index.readHasFile(path) && opts.add === undefined) {
      throw "error: " + pathFromRoot  + ": cannot add to the index - missing --add option?\n";
    } else {
      index.writeFile(path);
    }
  },

  hash_object: function(file, opts) {
    files.assertInRepo();
    opts = opts || {};

    if (!fs.existsSync(file)) {
      throw "fatal: Cannot open '" + file + "': No such file or directory"
    } else {
      var fileContents = files.read(file);
      if (opts.w) {
        return objects.write(fileContents);
      }

      return util.hash(fileContents);
    }
  },

  write_tree: function(_) {
    files.assertInRepo();
    return objects.writeTree(files.nestFlatTree(index.read()));
  },

  commit: function(opts) {
    files.assertInRepo();

    var headHash = refs.readHash("HEAD");
    var treeHash = this.write_tree();

    if (headHash !== undefined &&
        treeHash === objects.treeHash(objects.read(headHash))) {
      throw "# On " + refs.readCurrentBranchName() + "\n" +
        "nothing to commit, working directory clean";
    } else {
      var parentHashes = headHash === undefined ? [] : [headHash];
      var commmitHash = objects.write(objects.composeCommit(treeHash, opts.m, parentHashes));
      this.update_ref("HEAD", commmitHash);
      return "[" + refs.readCurrentBranchName() + " " + commmitHash + "] " + opts.m;
    }
  },

  branch: function(name, _) {
    files.assertInRepo();

    if (name === undefined) {
      return refs.readLocalHeads().map(function(branchName) {
        var marker = branchName === refs.readCurrentBranchName() ? "* " : "  ";
        return marker + branchName;
      }).join("\n") + "\n";
    } else if (refs.readHash("HEAD") === undefined) {
      throw "fatal: Not a valid object name: 'master'.";
    } else if (refs.readLocalHeads().filter(function(h) { return h === name; }).length > 0) {
      throw "fatal: A branch named '" + name + "' already exists.";
    } else {
      refs.write(refs.nameToBranchRef(name), refs.readHash("HEAD"));
    }
  },

  update_ref: function(refToUpdate, refToUpdateTo, _) {
    files.assertInRepo();

    if (!refs.isRef(refToUpdate)) {
      throw "fatal: Cannot lock the ref " + refToUpdate + ".";
    } else {
      var hash = refs.readHash(refToUpdateTo);
      if (!objects.readExists(hash)) {
        throw "fatal: " + refToUpdateTo + ": not a valid SHA1";
      } else if (!(objects.type(objects.read(hash)) === "commit")) {
        throw "error: Trying to write non-commit object " + hash + " to branch " +
          refs.readTerminalRef(refToUpdate) + "\n";
      } else {
        refs.write(refs.readTerminalRef(refToUpdate), hash);
      }
    }
  },

  checkout: function(ref, _) {
    files.assertInRepo();

    var hash = refs.readHash(ref);
    if (!objects.readExists(hash)) {
      throw "error: pathspec " + ref + " did not match any file(s) known to gitlet."
    } else if (objects.type(objects.read(hash)) !== "commit") {
      throw "fatal: reference is not a tree: " + ref;
    } else {
      var paths = checkout.readChangedFilesCheckoutWouldOverwrite(hash);
      if (paths.length > 0) {
        throw "error: Aborting. Your local changes to these files would be overwritten:\n" +
	        paths.join("\n") + "\n";
      } else {
        process.chdir(files.repoDir());
        checkout.writeCheckout(ref);
        return objects.readExists(ref) ?
          "Note: checking out " + ref + "\nYou are in 'detached HEAD' state." :
          "Switched to branch '" + ref + "'\n";
      }
    }
  },

  diff: function(ref1, ref2, opts) {
    files.assertInRepo();

    if (ref1 !== undefined && refs.readHash(ref1) === undefined) {
      throw "fatal: ambiguous argument " + ref1 + ": unknown revision";
    } else if (ref2 !== undefined && refs.readHash(ref2) === undefined) {
      throw "fatal: ambiguous argument " + ref2 + ": unknown revision";
    } else {
      if (opts["name-status"] !== true) {
        throw "unsupported"; // for now
      } else {
        var nameToStatus = diff.readDiff(ref1, ref2);
        return Object.keys(nameToStatus)
          .map(function(path) { return nameToStatus[path] + " " + path; })
          .join("\n") + "\n";
      }
    }
  }
};
<|endoftext|>


<commit_before>// ===========================================================================
// Purpose          : Lazy Image Loading
// Contributors     : jaw-sh
// Widget Version   : 2
// ===========================================================================

(function(window, $, undefined) {
    var blueprint = ib.getBlueprint();

    var options = {};

    blueprint.prototype.defaults = {
        refresh  : 3000,//ms
        interval : 1000,//ms

        selector : {
            'toggle' : '.overwatch-toggle',
            'label-pause' : '.label-pause',
            'label-reading' : '.label-reading',

            'logo' : "#logo",

            'thread-list' : '#CatalogMix',
            'thread-item' : '.thread',
            'post-container' : '.post-container',
        }
    };

    /* https://mixitup.kunkalabs.com/docs */
    blueprint.prototype.mixItUp = {
        animation: {
            enabled: false
        },
        load: {
            sort: 'bumped:desc'
        },
        callbacks: {
            onMixEnd: function(state) {
                state.$targets.css({
                    transition: "",
                    transform: "",
                    display: 'inline-block'
                });
            }
        }
    };

    blueprint.prototype.scanning       = false;
    blueprint.prototype.paused         = false;
    blueprint.prototype.hasFocus       = false;
    blueprint.prototype.updating       = false;
    blueprint.prototype.updateLast     = false;
    blueprint.prototype.updateLastSeen = false;
    blueprint.prototype.updateTimer    = false;
    blueprint.prototype.updateTime     = false;
    blueprint.prototype.updateCount    = 0
    blueprint.prototype.viewedRecently = false;
    blueprint.prototype.viewedLast     = false;

    blueprint.prototype.events = {
        toggle : function(event) {
            event.data.widget.scanning = $(this).prop('checked');

            if (event.data.widget.scanning) {
                event.data.$widget.trigger('scanstart');
            }
            else {
                event.data.$widget.trigger('scanstop');
            }
        },

        threadHoverCheck : function(event) {
            // mixItUp tacks on this bullshit CSS3 stuff I can't get rid of
            // any other way. It fucks up how my catalog works.
            $(event.currentTarget).parents(".thread-item:first").css({
                'transition' : "",
                'transform' : ""
            });

            var widget = event.data.widget;
            var $widget = event.data.$widget;
            var $catalog = event.data.$catalog;

            if (!widget.scanning) {
                return true;
            }

            setTimeout(function() {
                widget.paused = $(widget.options.selector['post-container']+":hover", $catalog).length > 0;
                $(widget.options.selector['label-reading'], $widget)
                    .css('visibility', widget.paused ? 'visible' : 'hidden');
            }, 100);
        },

        scanStop : function(event) {
            var widget = event.data.widget;
            var $widget = event.data.$widget;

            widget.scanning = false;

            var $logo = $(widget.options.selector['logo'])
            $logo.attr('src', $logo.data('original'));
        },

        // Overscan start
        scanStart : function(event) {
            var widget = event.data.widget;
            var $widget = event.data.$widget;

            widget.scanning = true;
            widget.timer = widget.options.refresh;

            var $logo = $(widget.options.selector['logo'])
            //$logo.data('original', $logo.attr('src'));
            //$logo.attr('src', window.app.media_url+'static/img/logo_overscan.gif');
        },

        updateAlways : function(json, textStatus, jqXHR) {
            if (jqXHR.widget !== undefined) {
                jqXHR.widget.updating = false;
            }
            else if (json.widget !== undefined) {
                json.widget.updating = false;
            }
        },

        updateDone : function(data, textStatus, jqXHR) {
            var widget = jqXHR.widget;
            var $catalog = widget.$catalog;
            var replacements = 0;
            var $alreadySeen = $();

            data = data.reverse();

            if (widget.viewedRecently && !widget.hasFocus) {
                $alreadySeen = $(widget.options.selector['thread-item'], $catalog);
            }

            $.each(data, function(index, item) {
                var hidePosts = localStorage.getItem("hidePosts."+item.board_uri);
                if (hidePosts !== null && hidePosts.split(",").indexOf(item.post_id.toString()) > -1) {
                    return true; // continue if we're hidden
                }

                var $thread = $(item.html);
                var $existing = $catalog.children("[data-id="+$thread.data('post_id')+"]");

                // DOM prep
                var $li = $("

");
                var $article = $("

");

                $li.attr({
                    'data-id' : item.post_id,
                    'data-bumped' : item.global_bumped_last
                }).data({
                    'id' : item.post_id,
                    'bumped' : item.global_bumped_last
                }).addClass('board-'+item.board_uri);

                $article.append(item.html);
                $li.append($article);

                // Insertion
                if ($existing.length) {
                    $existing.remove();
                }

                ++replacements;

                // Add the item
                $catalog.mixItUp('insert', 0, $li[0]);
                ib.bindAll($li[0]);
                $li.css({
                    'display' : 'inline-block'
                });

                // Track the last time the user saw a post.
                widget.updateLast = Math.max(item.bumped_last || 0, item.global_bumped_last || 0, widget.updateLast || 0);
                console.log(item.bumped_last || 0, item.global_bumped_last || 0, widget.updateLast || 0, widget.updateLast);

                if (!widget.hasFocus) {
                    ++widget.updateCount;
                }
                else {
                    widget.updateLastSeen = widget.updateLast;
                }
            });

            if (replacements > 0) {
                $catalog.mixItUp('sort', 'bumped:desc');

                if ($alreadySeen.length > 0) {
                    $alreadySeen.addClass('already-seen');
                    widget.viewedRecently = false;
                }
            }

            if (!widget.hasFocus && widget.updateCount > 0)
            {
                $("#favicon").attr('href', window.app.favicon.alert);
                document.title = "(" + widget.updateCount + ") " + $('
').html(window.app.title).text();
            }
            else
            {
                $("#favicon").attr('href', window.app.favicon.normal);
                document.title = $('
').html(window.app.title).text();
            }
        },

        windowFocus : function(event) {
            var widget = event.data.widget;
            var $widget = event.data.$widget;

            widget.hasFocus = true;
            widget.updateCount = 0;
            widget.viewedRecently = true;

            document.title = $('
').html(window.app.title).text();
            $("#favicon").attr('href', window.app.favicon.normal);
        },

        windowUnfocus : function(event) {
            var widget = event.data.widget;
            var $catalog = widget.$catalog;

            widget.hasFocus = false;
        }
    };

    blueprint.prototype.updateInterval = function() {
        var widget  = this;
        var $widget = this.$widget;
        clearInterval(widget.updateTimer);

        if (widget.scanning && !widget.paused  && !widget.updating)
        {
            var time = parseInt(widget.updateTime, 10);

            if (isNaN(time))
            {
                time = widget.options.refresh;
            }

            time -= widget.options.interval;

            if (time <= 0)
            {
                widget.updateQuery.apply(widget);
                time = widget.options.refresh;
            }

            widget.updateTime = time;
        }

        widget.updateTimer = setInterval(function() {
            widget.updateInterval.apply(widget);
        }, 1000);
    };

    blueprint.prototype.updateQuery = function() {
        var widget = this;
        var $widget = this.$widget;
        var $catalog = this.$catalog;

        var data = {
            updatedSince : $(widget.options.selector['thread-item']+":first", $catalog)
        };

        var jqXHR = $.ajax(window.location.pathname+".json", {
            data : {
                'updatedSince' : widget.updateLast,
                'messenger'    : 1
            }
        });

        jqXHR.widget = widget;
        jqXHR.done(widget.events.updateDone)
        jqXHR.always(widget.events.updateAlways);

        widget.updating = true;
    };

    blueprint.prototype.bind = function() {
        var widget = this;
        var $catalog = widget.$catalog = $(widget.options.selector['thread-list']);
        var data = {
            widget   : widget,
            $widget  : widget.$widget,
            $catalog : widget.$catalog
        };

        widget.$widget
            .on('change.ib-overscan', widget.options.selector['toggle'], data, widget.events.toggle)
            .on('scanstart.ib-overscan', data, widget.events.scanStart)
            .on('scanstop.ib-overscan', data, widget.events.scanStop)
        ;

        $(document)
            .on('mouseenter.ib-overwatch', widget.options.selector['post-container'], data, widget.events.threadHoverCheck)
            .on('mouseleave.ib-overwatch', widget.options.selector['post-container'], data, widget.events.threadHoverCheck)
        ;

        $(window)
            .on('focus.ib-overwatch', data, widget.events.windowFocus)
            .on('blur.ib-overwatch', data, widget.events.windowUnfocus)
        ;

        document.addEventListener('DOMContentLoaded', function() {
            // hide collapsed threads
            $catalog.children().children(".post-collapsed").parent().remove();
            $catalog.mixItUp(widget.mixItUp);

            widget.hasFocus = document.hasFocus();
            widget.updateLast = $(widget.options.selector['thread-item']).data('bumped');
            widget.viewedLast = widget.updateLast;

            widget.updateTimer = setInterval(function() {
                widget.updateInterval.apply(widget);
            }, 100);

            widget.$widget.trigger('scanstart');
        }, false);

        return true;
    };

    ib.widget("overwatch", blueprint, options);
})(window, window.jQuery);
<commit_msg>Overwatch error.<commit_after>// ===========================================================================
// Purpose          : Lazy Image Loading
// Contributors     : jaw-sh
// Widget Version   : 2
// ===========================================================================

(function(window, $, undefined) {
    var blueprint = ib.getBlueprint();

    var options = {};

    blueprint.prototype.defaults = {
        refresh  : 3000,//ms
        interval : 1000,//ms

        selector : {
            'toggle' : '.overwatch-toggle',
            'label-pause' : '.label-pause',
            'label-reading' : '.label-reading',

            'logo' : "#logo",

            'thread-list' : '#CatalogMix',
            'thread-item' : '.thread',
            'post-container' : '.post-container',
        }
    };

    /* https://mixitup.kunkalabs.com/docs */
    blueprint.prototype.mixItUp = {
        animation: {
            enabled: false
        },
        load: {
            sort: 'bumped:desc'
        },
        callbacks: {
            onMixEnd: function(state) {
                state.$targets.css({
                    transition: "",
                    transform: "",
                    display: 'inline-block'
                });
            }
        }
    };

    blueprint.prototype.scanning       = false;
    blueprint.prototype.paused         = false;
    blueprint.prototype.hasFocus       = false;
    blueprint.prototype.updating       = false;
    blueprint.prototype.updateLast     = false;
    blueprint.prototype.updateLastSeen = false;
    blueprint.prototype.updateTimer    = false;
    blueprint.prototype.updateTime     = false;
    blueprint.prototype.updateCount    = 0
    blueprint.prototype.viewedRecently = false;
    blueprint.prototype.viewedLast     = false;

    blueprint.prototype.events = {
        toggle : function(event) {
            event.data.widget.scanning = $(this).prop('checked');

            if (event.data.widget.scanning) {
                event.data.$widget.trigger('scanstart');
            }
            else {
                event.data.$widget.trigger('scanstop');
            }
        },

        threadHoverCheck : function(event) {
            // mixItUp tacks on this bullshit CSS3 stuff I can't get rid of
            // any other way. It fucks up how my catalog works.
            $(event.currentTarget).parents(".thread-item:first").css({
                'transition' : "",
                'transform' : ""
            });

            var widget = event.data.widget;
            var $widget = event.data.$widget;
            var $catalog = event.data.$catalog;

            if (!widget.scanning) {
                return true;
            }

            setTimeout(function() {
                widget.paused = $(widget.options.selector['post-container']+":hover", $catalog).length > 0;
                $(widget.options.selector['label-reading'], $widget)
                    .css('visibility', widget.paused ? 'visible' : 'hidden');
            }, 100);
        },

        scanStop : function(event) {
            var widget = event.data.widget;
            var $widget = event.data.$widget;

            widget.scanning = false;

            var $logo = $(widget.options.selector['logo'])
            $logo.attr('src', $logo.data('original'));
        },

        // Overscan start
        scanStart : function(event) {
            var widget = event.data.widget;
            var $widget = event.data.$widget;

            widget.scanning = true;
            widget.timer = widget.options.refresh;

            var $logo = $(widget.options.selector['logo'])
            //$logo.data('original', $logo.attr('src'));
            //$logo.attr('src', window.app.media_url+'static/img/logo_overscan.gif');
        },

        updateAlways : function(json, textStatus, jqXHR) {
            if (jqXHR.widget !== undefined) {
                jqXHR.widget.updating = false;
            }
            else if (json.widget !== undefined) {
                json.widget.updating = false;
            }
        },

        updateDone : function(data, textStatus, jqXHR) {
            var widget = jqXHR.widget;
            var $catalog = widget.$catalog;
            var replacements = 0;
            var $alreadySeen = $();

            data = data.reverse();

            if (widget.viewedRecently && !widget.hasFocus) {
                $alreadySeen = $(widget.options.selector['thread-item'], $catalog);
            }

            $.each(data, function(index, item) {
                var hidePosts = localStorage.getItem("hidePosts."+item.board_uri);
                if (hidePosts !== null && hidePosts.split(",").indexOf(item.post_id.toString()) > -1) {
                    return true; // continue if we're hidden
                }

                var $thread = $(item.html);
                var $existing = $catalog.children("[data-id="+$thread.data('post_id')+"]");

                // DOM prep
                var $li = $("

");
                var $article = $("

");

                $li.attr({
                    'data-id' : item.post_id,
                    'data-bumped' : item.global_bumped_last
                }).data({
                    'id' : item.post_id,
                    'bumped' : item.global_bumped_last
                }).addClass('board-'+item.board_uri);

                $article.append(item.html);
                $li.append($article);

                // Insertion
                if ($existing.length) {
                    $existing.remove();
                }

                ++replacements;

                // Add the item
                $catalog.mixItUp('insert', 0, $li[0]);
                ib.bindAll($li[0]);
                $li.css({
                    'display' : 'inline-block'
                });

                // Track the last time the user saw a post.
                widget.updateLast = Math.max(item.bumped_last || 0, widget.updateLast || 0);

                if (!widget.hasFocus) {
                    ++widget.updateCount;
                }
                else {
                    widget.updateLastSeen = widget.updateLast;
                }
            });

            if (replacements > 0) {
                $catalog.mixItUp('sort', 'bumped:desc');

                if ($alreadySeen.length > 0) {
                    $alreadySeen.addClass('already-seen');
                    widget.viewedRecently = false;
                }
            }

            if (!widget.hasFocus && widget.updateCount > 0)
            {
                $("#favicon").attr('href', window.app.favicon.alert);
                document.title = "(" + widget.updateCount + ") " + $('
').html(window.app.title).text();
            }
            else
            {
                $("#favicon").attr('href', window.app.favicon.normal);
                document.title = $('
').html(window.app.title).text();
            }
        },

        windowFocus : function(event) {
            var widget = event.data.widget;
            var $widget = event.data.$widget;

            widget.hasFocus = true;
            widget.updateCount = 0;
            widget.viewedRecently = true;

            document.title = $('
').html(window.app.title).text();
            $("#favicon").attr('href', window.app.favicon.normal);
        },

        windowUnfocus : function(event) {
            var widget = event.data.widget;
            var $catalog = widget.$catalog;

            widget.hasFocus = false;
        }
    };

    blueprint.prototype.updateInterval = function() {
        var widget  = this;
        var $widget = this.$widget;
        clearInterval(widget.updateTimer);

        if (widget.scanning && !widget.paused  && !widget.updating)
        {
            var time = parseInt(widget.updateTime, 10);

            if (isNaN(time))
            {
                time = widget.options.refresh;
            }

            time -= widget.options.interval;

            if (time <= 0)
            {
                widget.updateQuery.apply(widget);
                time = widget.options.refresh;
            }

            widget.updateTime = time;
        }

        widget.updateTimer = setInterval(function() {
            widget.updateInterval.apply(widget);
        }, 1000);
    };

    blueprint.prototype.updateQuery = function() {
        var widget = this;
        var $widget = this.$widget;
        var $catalog = this.$catalog;

        var data = {
            updatedSince : $(widget.options.selector['thread-item']+":first", $catalog)
        };

        var jqXHR = $.ajax(window.location.pathname+".json", {
            data : {
                'updatedSince' : widget.updateLast,
                'messenger'    : 1
            }
        });

        jqXHR.widget = widget;
        jqXHR.done(widget.events.updateDone)
        jqXHR.always(widget.events.updateAlways);

        widget.updating = true;
    };

    blueprint.prototype.bind = function() {
        var widget = this;
        var $catalog = widget.$catalog = $(widget.options.selector['thread-list']);
        var data = {
            widget   : widget,
            $widget  : widget.$widget,
            $catalog : widget.$catalog
        };

        widget.$widget
            .on('change.ib-overscan', widget.options.selector['toggle'], data, widget.events.toggle)
            .on('scanstart.ib-overscan', data, widget.events.scanStart)
            .on('scanstop.ib-overscan', data, widget.events.scanStop)
        ;

        $(document)
            .on('mouseenter.ib-overwatch', widget.options.selector['post-container'], data, widget.events.threadHoverCheck)
            .on('mouseleave.ib-overwatch', widget.options.selector['post-container'], data, widget.events.threadHoverCheck)
        ;

        $(window)
            .on('focus.ib-overwatch', data, widget.events.windowFocus)
            .on('blur.ib-overwatch', data, widget.events.windowUnfocus)
        ;

        document.addEventListener('DOMContentLoaded', function() {
            // hide collapsed threads
            $catalog.children().children(".post-collapsed").parent().remove();
            $catalog.mixItUp(widget.mixItUp);

            widget.hasFocus = document.hasFocus();
            widget.updateLast = $(widget.options.selector['thread-item']).data('bumped');
            widget.viewedLast = widget.updateLast;

            widget.updateTimer = setInterval(function() {
                widget.updateInterval.apply(widget);
            }, 100);

            widget.$widget.trigger('scanstart');
        }, false);

        return true;
    };

    ib.widget("overwatch", blueprint, options);
})(window, window.jQuery);
<|endoftext|>