<commit_before>SoapStone.User = function(args) {
  this.username = args.username;
};

SoapStone.UserView = function() {
  this.setUpEventHandlers()
};

SoapStone.UserView.prototype.setUpEventHandlers = function(){
  $("[data-role='follow']").on('click', function(event){
    debugger;
    var followee = event.target.value;
    debugger;
    $("[data-role='follow']").hide();
    $("[data-role='unfollow']").show();\
    SoapStone.app.createFollow({user: user}
  })

  $("[data-role='unfollow']").on('click', function(event){
    $("[data-role='unfollow']").hide();
    $("[data-role='follow']").show();
  })
};

SoapStone.Controller = function() {
  this.view = new SoapStone.UserView();
  this.view.controller = this;
};

SoapStone.Controller.prototype.createfollow = function(followParams) {
  var follow = new SoapStone.Follow(followParams);
  debugger;
  follow.save()
  .then(function(response) {console.log(response);})
  .fail(function(response) {console.log(response);});
};

SoapStone.Follow.prototype.save = function() {
  var data = {};
  data.follow = {};
  return $.ajax({
    type: "POST",
    url:  "/drops",
    data: data
  });
};

//this needs to go in the event handler for form posting
// $( document ).ready(function() {
//   SoapStone.app = new SoapStone.Controller();
// });
<commit_msg>Create user js mvc<commit_after>SoapStone.User = function(args) {
  // this.id = args.id;
  // this.username = args.username;
};

SoapStone.User.prototype.loadFollows = function(id) {
  var self = this;
  debugger;
  return new Promise(function(resolve, reject) {
    $.ajax({
      type: "GET",
      url: "/users/" + id + "/follows",
      dataType: 'json'
     })
    .then(function (response) {
      debugger;
      self.setAttributes(response);
      resolve(self);
    })
    .fail(function () {
      reject();
    });
  });
};

SoapStone.UserView = function() {
  var showTemplateSource   = $("[data-template='show-user']").html();
  this.showTemplate = Handlebars.compile(showTemplateSource);
  // this.setUpEventHandlers();
};

SoapStone.Controller = function() {
  this.user = new SoapStone.User();
  this.userView = new SoapStone.UserView();
  this.loadFollows();
};

SoapStone.Controller.prototype.loadFollows = function() {
  var self = this;
  id = location.href.split('/').slice(-1)
  debugger
  return this.user.loadFollows(id).then(function () {
    self.userView.showFollows(self.user);
  });
};

SoapStone.UserView.prototype.showFollows = function (user) {
  var followItems = $(document.createDocumentFragment());
  var self = this;
  user.followers.forEach( function (follower) {
    followItems.append(self.template(follower));
  });
  user.followees.forEach( function (followee) {
    followItems.append(self.template(followee));
  });
  $("[data-role='follows-list']").html(followItems);
};

// SoapStone.UserView.prototype.setUpEventHandlers = function(){
//   $("#follow_form").on('submit', function(event){
//     event.preventDefault();
//     debugger;
//     SoapStone.app.createFollow($(event.target).serializeArray()[2]);
//   });
// };

// SoapStone.Controller.prototype.createfollow = function(followParams) {
//   var follow = new SoapStone.Follow({followee_id: followParams.value});
//   debugger;
//   follow.save()
//   .then(function(response) {console.log(response);})
//   .fail(function(response) {console.log(response);});
// };

SoapStone.UserView.prototype.showFollowers = function(user) {
  var self = this;
  $('body').append(this.showTemplate(user));
};

<|endoftext|>


<commit_before>'use strict'

const C = require('../constants/constants')
const utils = require('../utils/utils')

const actionToKey = utils.reverseMap(C.ACTIONS)
const RULES_MAP = {}
const RULE_TYPES = {}

/**
 * Different rule types support different features. Generally, all rules can
 * use cross referencing _() to reference records, but only record writes, incoming events
 * or RPC requests carry data and only existing records have a concept of oldData
 *
 * @type {Object}
 */
RULE_TYPES.CREATE = { name: 'create', data: false, oldData: false }
RULE_TYPES.READ = { name: 'read', data: false, oldData: true }
RULE_TYPES.WRITE = { name: 'write', data: true, oldData: true }
RULE_TYPES.DELETE = { name: 'delete', data: false, oldData: true }
RULE_TYPES.LISTEN = { name: 'listen', data: false, oldData: false }
RULE_TYPES.PUBLISH = { name: 'publish', data: true, oldData: false }
RULE_TYPES.SUBSCRIBE = { name: 'subscribe', data: true, oldData: false }
RULE_TYPES.PROVIDE = { name: 'provide', data: false, oldData: false }
RULE_TYPES.REQUEST = { name: 'request', data: true, oldData: false }
RULE_TYPES.ALLOW = { name: 'allow', data: false, oldData: false }

/**
 * This class maps topic / action combinations to applicable
 * rules. It combines actions of a similar character (e.g. READ,
 * SNAPSHOT, HAS) into high level permissions (e.g. read)
 *
 * Lower level permissioning on a per action basis can still be achieved
 * by virtue of using the action variable within the rule, e.g.
 *
 * {
 *    //allow read, but not listen
 *    'read': 'user.id === $userId && action !== LISTEN'
 * }
 */
RULES_MAP[C.TOPIC.RECORD] = {}
RULES_MAP[C.TOPIC.RECORD].section = 'record'
RULES_MAP[C.TOPIC.RECORD].actions = {}
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.READ] = RULE_TYPES.READ
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.HAS] = RULE_TYPES.READ
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.SNAPSHOT] = RULE_TYPES.READ
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.LISTEN] = RULE_TYPES.LISTEN
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.LISTEN_SNAPSHOT] = RULE_TYPES.LISTEN
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.CREATE] = RULE_TYPES.CREATE
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.UPDATE] = RULE_TYPES.WRITE
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.PATCH] = RULE_TYPES.WRITE
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.DELETE] = RULE_TYPES.DELETE

RULES_MAP[C.TOPIC.EVENT] = {}
RULES_MAP[C.TOPIC.EVENT].section = 'event'
RULES_MAP[C.TOPIC.EVENT].actions = {}
RULES_MAP[C.TOPIC.EVENT].actions[C.ACTIONS.LISTEN] = RULE_TYPES.LISTEN
RULES_MAP[C.TOPIC.EVENT].actions[C.ACTIONS.SUBSCRIBE] = RULE_TYPES.SUBSCRIBE
RULES_MAP[C.TOPIC.EVENT].actions[C.ACTIONS.EVENT] = RULE_TYPES.PUBLISH

RULES_MAP[C.TOPIC.RPC] = {}
RULES_MAP[C.TOPIC.RPC].section = 'rpc'
RULES_MAP[C.TOPIC.RPC].actions = {}
RULES_MAP[C.TOPIC.RPC].actions[C.ACTIONS.SUBSCRIBE] = RULE_TYPES.PROVIDE
RULES_MAP[C.TOPIC.RPC].actions[C.ACTIONS.REQUEST] = RULE_TYPES.REQUEST

RULES_MAP[C.TOPIC.PRESENCE] = {}
RULES_MAP[C.TOPIC.PRESENCE].section = 'presence'
RULES_MAP[C.TOPIC.PRESENCE].actions = {}
RULES_MAP[C.TOPIC.PRESENCE].actions[C.ACTIONS.SUBSCRIBE] = RULE_TYPES.ALLOW
RULES_MAP[C.TOPIC.PRESENCE].actions[C.ACTIONS.QUERY] = RULE_TYPES.ALLOW

/**
 * Returns a map of applicable rule-types for a topic
 * action combination
 *
 * @param   {Message} message a parsed and validated deepstream.io message
 *
 * @public
 * @returns {Object} ruleTypes a map with <String> section, <Array> rules, <String> action
 */
exports.getRulesForMessage = function (message) {
  if (RULES_MAP[message.topic] === undefined) {
    return null
  }

  if (RULES_MAP[message.topic].actions[message.action] === undefined) {
    return null
  }

  return {
    section: RULES_MAP[message.topic].section,
    type: RULES_MAP[message.topic].actions[message.action].name,
    action: actionToKey[message.action]
  }
}

/**
 * Returns true if a given rule supports references to incoming data
 *
 * @param   {String} type one of RULE_TYPES
 *
 * @public
 * @returns {Boolean}
 */
exports.supportsData = function (type) {
  return RULE_TYPES[type.toUpperCase()].data
}

/**
 * Returns true if a given rule supports references to existing data
 *
 * @param   {String} type one of RULE_TYPES
 *
 * @public
 * @returns {Boolean}
 */
exports.supportsOldData = function (type) {
  return RULE_TYPES[type.toUpperCase()].oldData
}
<commit_msg>Figured out how permissions work, need to add permission check to new message.<commit_after>'use strict'

const C = require('../constants/constants')
const utils = require('../utils/utils')

const actionToKey = utils.reverseMap(C.ACTIONS)
const RULES_MAP = {}
const RULE_TYPES = {}

/**
 * Different rule types support different features. Generally, all rules can
 * use cross referencing _() to reference records, but only record writes, incoming events
 * or RPC requests carry data and only existing records have a concept of oldData
 *
 * @type {Object}
 */
RULE_TYPES.CREATE = { name: 'create', data: false, oldData: false }
RULE_TYPES.READ = { name: 'read', data: false, oldData: true }
RULE_TYPES.WRITE = { name: 'write', data: true, oldData: true }
RULE_TYPES.DELETE = { name: 'delete', data: false, oldData: true }
RULE_TYPES.LISTEN = { name: 'listen', data: false, oldData: false }
RULE_TYPES.PUBLISH = { name: 'publish', data: true, oldData: false }
RULE_TYPES.SUBSCRIBE = { name: 'subscribe', data: true, oldData: false }
RULE_TYPES.PROVIDE = { name: 'provide', data: false, oldData: false }
RULE_TYPES.REQUEST = { name: 'request', data: true, oldData: false }
RULE_TYPES.ALLOW = { name: 'allow', data: false, oldData: false }

/**
 * This class maps topic / action combinations to applicable
 * rules. It combines actions of a similar character (e.g. READ,
 * SNAPSHOT, HAS) into high level permissions (e.g. read)
 *
 * Lower level permissioning on a per action basis can still be achieved
 * by virtue of using the action variable within the rule, e.g.
 *
 * {
 *    //allow read, but not listen
 *    'read': 'user.id === $userId && action !== LISTEN'
 * }
 */
RULES_MAP[C.TOPIC.RECORD] = {}
RULES_MAP[C.TOPIC.RECORD].section = 'record'
RULES_MAP[C.TOPIC.RECORD].actions = {}
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.READ] = RULE_TYPES.READ
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.HAS] = RULE_TYPES.READ
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.SNAPSHOT] = RULE_TYPES.READ
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.HEAD] = RULE_TYPES.READ
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.LISTEN] = RULE_TYPES.LISTEN
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.LISTEN_SNAPSHOT] = RULE_TYPES.LISTEN
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.CREATE] = RULE_TYPES.CREATE
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.UPDATE] = RULE_TYPES.WRITE
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.PATCH] = RULE_TYPES.WRITE
RULES_MAP[C.TOPIC.RECORD].actions[C.ACTIONS.DELETE] = RULE_TYPES.DELETE

RULES_MAP[C.TOPIC.EVENT] = {}
RULES_MAP[C.TOPIC.EVENT].section = 'event'
RULES_MAP[C.TOPIC.EVENT].actions = {}
RULES_MAP[C.TOPIC.EVENT].actions[C.ACTIONS.LISTEN] = RULE_TYPES.LISTEN
RULES_MAP[C.TOPIC.EVENT].actions[C.ACTIONS.SUBSCRIBE] = RULE_TYPES.SUBSCRIBE
RULES_MAP[C.TOPIC.EVENT].actions[C.ACTIONS.EVENT] = RULE_TYPES.PUBLISH

RULES_MAP[C.TOPIC.RPC] = {}
RULES_MAP[C.TOPIC.RPC].section = 'rpc'
RULES_MAP[C.TOPIC.RPC].actions = {}
RULES_MAP[C.TOPIC.RPC].actions[C.ACTIONS.SUBSCRIBE] = RULE_TYPES.PROVIDE
RULES_MAP[C.TOPIC.RPC].actions[C.ACTIONS.REQUEST] = RULE_TYPES.REQUEST

RULES_MAP[C.TOPIC.PRESENCE] = {}
RULES_MAP[C.TOPIC.PRESENCE].section = 'presence'
RULES_MAP[C.TOPIC.PRESENCE].actions = {}
RULES_MAP[C.TOPIC.PRESENCE].actions[C.ACTIONS.SUBSCRIBE] = RULE_TYPES.ALLOW
RULES_MAP[C.TOPIC.PRESENCE].actions[C.ACTIONS.QUERY] = RULE_TYPES.ALLOW

/**
 * Returns a map of applicable rule-types for a topic
 * action combination
 *
 * @param   {Message} message a parsed and validated deepstream.io message
 *
 * @public
 * @returns {Object} ruleTypes a map with <String> section, <Array> rules, <String> action
 */
exports.getRulesForMessage = function (message) {
  if (RULES_MAP[message.topic] === undefined) {
    return null
  }

  if (RULES_MAP[message.topic].actions[message.action] === undefined) {
    return null
  }

  return {
    section: RULES_MAP[message.topic].section,
    type: RULES_MAP[message.topic].actions[message.action].name,
    action: actionToKey[message.action]
  }
}

/**
 * Returns true if a given rule supports references to incoming data
 *
 * @param   {String} type one of RULE_TYPES
 *
 * @public
 * @returns {Boolean}
 */
exports.supportsData = function (type) {
  return RULE_TYPES[type.toUpperCase()].data
}

/**
 * Returns true if a given rule supports references to existing data
 *
 * @param   {String} type one of RULE_TYPES
 *
 * @public
 * @returns {Boolean}
 */
exports.supportsOldData = function (type) {
  return RULE_TYPES[type.toUpperCase()].oldData
}
<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import Promise from 'bluebird';
import es3ify from 'es3ify';
import read from 'fs-readdir-recursive';
import flatten from 'lodash.flatten';
import { createPatch, diffChars } from 'diff';

const { transform } = es3ify;
const readFile = Promise.promisify(fs.readFile);
const writeFile = Promise.promisify(fs.writeFile);

export default (files = [], { savePatchToDisk, directory } = {}) => {
  const filesArray = Array.isArray(files) ? files : [files]
    .map(filename => {
      if (fs.lstatSync(filename).isDirectory()) {
        return read(filename).filter(file => path.extname(file) === '.js').map(file => path.join(filename, file));
      }

      return filename;
    });

  return Promise
    .map(flatten(filesArray), filename => Promise.props({ content: readFile(filename, 'utf-8'), filename }))
    .map(({ content, filename }) => {
      const hash = crypto.createHash('md5').update(content).digest('hex');
      const es3Content = transform(content);
      const es3Hash = crypto.createHash('md5').update(es3Content).digest('hex');

      return Promise.props({
        filename,
        content,
        hash,
        es3Content,
        es3Hash,
      });
    })
    .filter(({ hash, es3Hash }) => hash !== es3Hash)
    .map(({ filename, content, es3Content }) => Promise.props({
      filename,
      patch: createPatch(filename, content, es3Content),
      textDiff: diffChars(content, es3Content),
    }))
    .tap(arr => {
      if (savePatchToDisk) return arr.map(res => writeFile(path.join(directory, `${res.filename}.patch`), res.patch));

      return Promise.resolve();
    });
};
<commit_msg>Fix array initializer<commit_after>import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import Promise from 'bluebird';
import es3ify from 'es3ify';
import read from 'fs-readdir-recursive';
import flatten from 'lodash.flatten';
import { createPatch, diffChars } from 'diff';

const { transform } = es3ify;
const readFile = Promise.promisify(fs.readFile);
const writeFile = Promise.promisify(fs.writeFile);

export default (files = [], { savePatchToDisk, directory } = {}) => {
  const filesArray = (Array.isArray(files) ? files : [files])
    .map(filename => {
      if (fs.lstatSync(filename).isDirectory()) {
        return read(filename).filter(file => path.extname(file) === '.js').map(file => path.join(filename, file));
      }

      return filename;
    });

  return Promise
    .map(flatten(filesArray), filename => Promise.props({ content: readFile(filename, 'utf-8'), filename }))
    .map(({ content, filename }) => {
      const hash = crypto.createHash('md5').update(content).digest('hex');
      const es3Content = transform(content);
      const es3Hash = crypto.createHash('md5').update(es3Content).digest('hex');

      return Promise.props({
        filename,
        content,
        hash,
        es3Content,
        es3Hash,
      });
    })
    .filter(({ hash, es3Hash }) => hash !== es3Hash)
    .map(({ filename, content, es3Content }) => Promise.props({
      filename,
      patch: createPatch(filename, content, es3Content),
      textDiff: diffChars(content, es3Content),
    }))
    .tap(arr => {
      if (savePatchToDisk) return arr.map(res => writeFile(path.join(directory, `${res.filename}.patch`), res.patch));

      return Promise.resolve();
    });
};
<|endoftext|>


<commit_before>var Backbone = require('Backbone');
var Router = require('../../../javascripts/cartodb3/routes/router');
Backbone.history.start({ pushState: false, hashChange: false, root: 'builder/id' });
Router.init();

// Mock this, because it fails
Router.getCurrentRoute = function () {
  return '/la/promosio';
};
<commit_msg>Use lowercase backbone in requires<commit_after>var Backbone = require('backbone');
var Router = require('../../../javascripts/cartodb3/routes/router');
Backbone.history.start({ pushState: false, hashChange: false, root: 'builder/id' });
Router.init();

// Mock this, because it fails
Router.getCurrentRoute = function () {
  return '/la/promosio';
};
<|endoftext|>


<commit_before>
/**
 * view used to render each row
 */
cdb.admin.RowView = cdb.ui.common.RowView.extend({
  classLabel: 'cdb.admin.RowView',
  events: {
    'click .row_header': 'click_header',
    // 'mouseout .row_header': 'mouseout_event'
  },

  cellRenderers: {
    'default': '_renderDefault',
    'boolean': '_renderBoolean',
    'number': '_renderNumber',
    'geometry': '_renderGeometry'
  },

  initialize: function() {
    var self = this;
    this.elder('initialize');
    _.bindAll(this, 'mouseout_header', 'click_header',
      'mousein_event', 'mouseout_event')
    this.options.row_header = true;
    this.model.bind('destroy', function() {
      self.trigger('destroyRow');
    })
    this.retrigger('saving', this.model);
    this.retrigger('saved', this.model);
    this.retrigger('savingError', this.model);

    this.$el.bind('mouseover', this.mousein_event);
    this.$el.bind('mouseout', this.mouseout_event);

  },
  /**
   * When the mouse steps over the row, mark the attribute 'hasMouse'
   */
  mousein_event: function() {
    this.hasMouse = true;
  },
  /**
   * Here be dragons: this is a hack to be able to detect when
   * the mouse has left a row for real. Mouseout event is not enough,
   * because it gets triggered when you change between tds.
   * It listen for this changes and mark the row as 'unmoused',
   * waiting for another event to step in and mark this row as
   * 'moused' again.
   *
   * @param  {Event} ev
   */
  mouseout_event: function(ev) {
    this.hasMouse = false;
    setTimeout(this.checkDropdownOpen.bind(this),25);
  },
  /**
   * Check if the cursor is not over this row and if the option menu is
   * opened, and if so, clear the menu
   */
  checkDropdownOpen: function() {
    if(!this.hasMouse && this.rowOptions) {
      this.rowOptions.hide();
    }
  },
  _getRowOptions: function() {
    if(!cdb.admin.RowView.rowOptions) {
       var rowOptions = cdb.admin.RowView.rowOptions= new cdb.admin.RowHeaderDropdown({
        position: 'position',
        template_base: "table/views/table_row_header_options",
        tick: "top",
        horizontal_position: "left",
        tableData: this.getTableView().dataModel
      });
      rowOptions.render();
      this.retrigger('destroyRow', rowOptions);
      this.retrigger('createRow', rowOptions);

    }
    return cdb.admin.RowView.rowOptions;
  },
  mouseout_header: function(e) {
    if(this.rowOptions) {
      // this.rowOptions.hide();
    }
  },
  click_header: function(e) {
    var rowOptions, tableData, pos, tableOffset, left, top;

    $target = $(e.target);

    tableData = this.getTableView().dataModel;
    if(tableData.isReadOnly()) {
      // if data is read only do not allow
      // to add or remove rows
      return;
    }
    rowOptions = this._getRowOptions();
    e.preventDefault();
    $target.append(rowOptions.el);
    pos = $target.position();

    // xabel: Yep, browser specific code. I'm so sorry for thiw. What's this? 2007?
    if($.browser.mozilla) {
      pos = $target.offset();
      tableOffset = $target.parents('table').offset() || 0;
      left = pos.left - tableOffset.left + 20;
      top = pos.top - tableOffset.top - 15;
    } else {
      left = pos.left + 30;
      top = pos.top + 0;
    }
    rowOptions.setRow(this.model);
    rowOptions.openAt(left, top);
    this.rowOptions = rowOptions; // to make it testable;
    return false;
  },

  /**
   * return each cell view
   */
  valueView: function(colName, value) {
    if((colName == 'the_geom' || colName == 'the_geom_webmercator' ) &&
      this.getTableView().dataModel.isReadOnly() ) {
      value = 'GeoJSON'
    }
    this.table = this.table || this.getTableView().model;
    var render = '_renderDefault';
    if(colName.length) {
      var colType = this.table.getColumnType(colName);
      render = this.cellRenderers[colType] || render;
    }

    var obj = this[render](value);
    obj.addClass('cell');
    if(cdb.admin.Row.isReservedColumn(colName)) {
      obj.addClass('disabled');
    }
    if(colName === '' && value === '') {
      obj.addClass('row_header');
      //some space
      //TODO: do it with css
      obj.append('    ');
    }
    return obj;
  },

  _renderDefault: function(value) {
    var additionalClasses = '';
    if(value === null) {
      additionalClasses = "isNull"
    }
    var cell =  $('
').append(_.escape(value));

    return cell;
  },

  _renderBoolean: function(value) {
    var v = '';
    if(value === '' || value === null) {
    } else if(value) {
      v = 'true';
    } else {
      v = 'false';
    }
    return $('
').append(v);
  },

  _renderNumber: function(value) {
    var d = this._renderDefault(value);
    return d.addClass('number');
  },

  _renderGeometry: function(value) {
    var objValue = {};
    try {
      objValue = JSON.parse(value);
      if(objValue.type === 'Point') {

        value = objValue.coordinates[0] + ', ' + objValue.coordinates[1];
      }
    } catch (e) {

    }
    return this._renderDefault(value)
  }

});

<commit_msg>simplified boolean cell render function to show all possible values, like null<commit_after>
/**
 * view used to render each row
 */
cdb.admin.RowView = cdb.ui.common.RowView.extend({
  classLabel: 'cdb.admin.RowView',
  events: {
    'click .row_header': 'click_header',
    // 'mouseout .row_header': 'mouseout_event'
  },

  cellRenderers: {
    'default': '_renderDefault',
    'boolean': '_renderBoolean',
    'number': '_renderNumber',
    'geometry': '_renderGeometry'
  },

  initialize: function() {
    var self = this;
    this.elder('initialize');
    _.bindAll(this, 'mouseout_header', 'click_header',
      'mousein_event', 'mouseout_event')
    this.options.row_header = true;
    this.model.bind('destroy', function() {
      self.trigger('destroyRow');
    })
    this.retrigger('saving', this.model);
    this.retrigger('saved', this.model);
    this.retrigger('savingError', this.model);

    this.$el.bind('mouseover', this.mousein_event);
    this.$el.bind('mouseout', this.mouseout_event);

  },
  /**
   * When the mouse steps over the row, mark the attribute 'hasMouse'
   */
  mousein_event: function() {
    this.hasMouse = true;
  },
  /**
   * Here be dragons: this is a hack to be able to detect when
   * the mouse has left a row for real. Mouseout event is not enough,
   * because it gets triggered when you change between tds.
   * It listen for this changes and mark the row as 'unmoused',
   * waiting for another event to step in and mark this row as
   * 'moused' again.
   *
   * @param  {Event} ev
   */
  mouseout_event: function(ev) {
    this.hasMouse = false;
    setTimeout(this.checkDropdownOpen.bind(this),25);
  },
  /**
   * Check if the cursor is not over this row and if the option menu is
   * opened, and if so, clear the menu
   */
  checkDropdownOpen: function() {
    if(!this.hasMouse && this.rowOptions) {
      this.rowOptions.hide();
    }
  },
  _getRowOptions: function() {
    if(!cdb.admin.RowView.rowOptions) {
       var rowOptions = cdb.admin.RowView.rowOptions= new cdb.admin.RowHeaderDropdown({
        position: 'position',
        template_base: "table/views/table_row_header_options",
        tick: "top",
        horizontal_position: "left",
        tableData: this.getTableView().dataModel
      });
      rowOptions.render();
      this.retrigger('destroyRow', rowOptions);
      this.retrigger('createRow', rowOptions);

    }
    return cdb.admin.RowView.rowOptions;
  },
  mouseout_header: function(e) {
    if(this.rowOptions) {
      // this.rowOptions.hide();
    }
  },
  click_header: function(e) {
    var rowOptions, tableData, pos, tableOffset, left, top;

    $target = $(e.target);

    tableData = this.getTableView().dataModel;
    if(tableData.isReadOnly()) {
      // if data is read only do not allow
      // to add or remove rows
      return;
    }
    rowOptions = this._getRowOptions();
    e.preventDefault();
    $target.append(rowOptions.el);
    pos = $target.position();

    // xabel: Yep, browser specific code. I'm so sorry for thiw. What's this? 2007?
    if($.browser.mozilla) {
      pos = $target.offset();
      tableOffset = $target.parents('table').offset() || 0;
      left = pos.left - tableOffset.left + 20;
      top = pos.top - tableOffset.top - 15;
    } else {
      left = pos.left + 30;
      top = pos.top + 0;
    }
    rowOptions.setRow(this.model);
    rowOptions.openAt(left, top);
    this.rowOptions = rowOptions; // to make it testable;
    return false;
  },

  /**
   * return each cell view
   */
  valueView: function(colName, value) {
    if((colName == 'the_geom' || colName == 'the_geom_webmercator' ) &&
      this.getTableView().dataModel.isReadOnly() ) {
      value = 'GeoJSON'
    }
    this.table = this.table || this.getTableView().model;
    var render = '_renderDefault';
    if(colName.length) {
      var colType = this.table.getColumnType(colName);
      render = this.cellRenderers[colType] || render;
    }

    var obj = this[render](value);
    obj.addClass('cell');
    if(cdb.admin.Row.isReservedColumn(colName)) {
      obj.addClass('disabled');
    }
    if(colName === '' && value === '') {
      obj.addClass('row_header');
      //some space
      //TODO: do it with css
      obj.append('    ');
    }
    return obj;
  },

  _renderDefault: function(value) {
    var additionalClasses = '';
    if(value === null) {
      additionalClasses = "isNull"
    }
    var cell =  $('
').append(_.escape(value));

    return cell;
  },

  _renderBoolean: function(value) {
    return this._renderDefault(value).addClass('boolean');
  },

  _renderNumber: function(value) {
    var d = this._renderDefault(value);
    return d.addClass('number');
  },

  _renderGeometry: function(value) {
    var objValue = {};
    try {
      objValue = JSON.parse(value);
      if(objValue.type === 'Point') {

        value = objValue.coordinates[0] + ', ' + objValue.coordinates[1];
      }
    } catch (e) {

    }
    return this._renderDefault(value)
  }

});

<|endoftext|>


<commit_before>'use strict'

var watch = require('chokidar').watch

process.once('message', function (msg) {
  var watcher = watch(msg.path, msg.opts)

  watcher.on('all', function (event, path) {
    process.send({ event: event, path: path })
  })
})

process.on('error', function () {})
<commit_msg>Close the child if the parent disconnects.<commit_after>'use strict'

var watch = require('chokidar').watch

process.once('message', function (msg) {
  var watcher = watch(msg.path, msg.opts)

  watcher.on('all', function (event, path) {
    process.send({ event: event, path: path })
  })
})

process.on('error', function () {})

process.on('disconnect', function() {
  process.exit();
});
<|endoftext|>


<commit_before>'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace statistics
*/
var statistics = {};

/**
* @name chi2gof
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/chi2gof}
*/
setReadOnly( statistics, 'chi2gof', require( '@stdlib/math/stats/chi2gof' ) );

/**
* @name incrcount
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/count}
*/
setReadOnly( statistics, 'incrcount', require( '@stdlib/math/stats/incr/count' ) );

/**
* @name incrkurtosis
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/kurtosis}
*/
setReadOnly( statistics, 'incrkurtosis', require( '@stdlib/math/stats/incr/kurtosis' ) );

/**
* @name incrmax
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/max}
*/
setReadOnly( statistics, 'incrmax', require( '@stdlib/math/stats/incr/max' ) );

/**
* @name incrmean
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/mean}
*/
setReadOnly( statistics, 'incrmean', require( '@stdlib/math/stats/incr/mean' ) );

/**
* @name incrmidrange
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/midrange}
*/
setReadOnly( statistics, 'incrmidrange', require( '@stdlib/math/stats/incr/midrange' ) );

/**
* @name incrmin
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/min}
*/
setReadOnly( statistics, 'incrmin', require( '@stdlib/math/stats/incr/min' ) );

/**
* @name incrmmean
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/mmean}
*/
setReadOnly( statistics, 'incrmmean', require( '@stdlib/math/stats/incr/mmean' ) );

/**
* @name incrmstdev
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/mstdev}
*/
setReadOnly( statistics, 'incrmstdev', require( '@stdlib/math/stats/incr/mstdev' ) );

/**
* @name incrmsum
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/msum}
*/
setReadOnly( statistics, 'incrmsum', require( '@stdlib/math/stats/incr/msum' ) );

/**
* @name incrmsummary
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/msummary}
*/
setReadOnly( statistics, 'incrmsummary', require( '@stdlib/math/stats/incr/msummary' ) );

/**
* @name incrmvariance
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/mvariance}
*/
setReadOnly( statistics, 'incrmvariance', require( '@stdlib/math/stats/incr/mvariance' ) );

/**
* @name incrprod
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/prod}
*/
setReadOnly( statistics, 'incrprod', require( '@stdlib/math/stats/incr/prod' ) );

/**
* @name incrrange
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/range}
*/
setReadOnly( statistics, 'incrrange', require( '@stdlib/math/stats/incr/range' ) );

/**
* @name incrskewness
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/skewness}
*/
setReadOnly( statistics, 'incrskewness', require( '@stdlib/math/stats/incr/skewness' ) );

/**
* @name incrstdev
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/stdev}
*/
setReadOnly( statistics, 'incrstdev', require( '@stdlib/math/stats/incr/stdev' ) );

/**
* @name incrsum
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/sum}
*/
setReadOnly( statistics, 'incrsum', require( '@stdlib/math/stats/incr/sum' ) );

/**
* @name incrsummary
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/summary}
*/
setReadOnly( statistics, 'incrsummary', require( '@stdlib/math/stats/incr/summary' ) );

/**
* @name incrvariance
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/variance}
*/
setReadOnly( statistics, 'incrvariance', require( '@stdlib/math/stats/incr/variance' ) );

/**
* @name kstest
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/kstest}
*/
setReadOnly( statistics, 'kstest', require( '@stdlib/math/stats/kstest' ) );

/**
* @name pcorrtest
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/pcorrtest}
*/
setReadOnly( statistics, 'pcorrtest', require( '@stdlib/math/stats/pcorrtest' ) );

/**
* @name ttest
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/ttest}
*/
setReadOnly( statistics, 'ttest', require( '@stdlib/math/stats/ttest' ) );

/**
* @name ttest2
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/ttest2}
*/
setReadOnly( statistics, 'ttest2', require( '@stdlib/math/stats/ttest2' ) );

/**
* @name ztest
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/ztest}
*/
setReadOnly( statistics, 'ztest', require( '@stdlib/math/stats/ztest' ) );

/**
* @name ztest2
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/2}
*/
setReadOnly( statistics, 'ztest2', require( '@stdlib/math/stats/ztest2' ) );

// EXPORTS //

module.exports = statistics;
<commit_msg>Add function to stats namespace<commit_after>'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace statistics
*/
var statistics = {};

/**
* @name chi2gof
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/chi2gof}
*/
setReadOnly( statistics, 'chi2gof', require( '@stdlib/math/stats/chi2gof' ) );

/**
* @name incrcount
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/count}
*/
setReadOnly( statistics, 'incrcount', require( '@stdlib/math/stats/incr/count' ) );

/**
* @name incrkurtosis
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/kurtosis}
*/
setReadOnly( statistics, 'incrkurtosis', require( '@stdlib/math/stats/incr/kurtosis' ) );

/**
* @name incrmax
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/max}
*/
setReadOnly( statistics, 'incrmax', require( '@stdlib/math/stats/incr/max' ) );

/**
* @name incrmean
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/mean}
*/
setReadOnly( statistics, 'incrmean', require( '@stdlib/math/stats/incr/mean' ) );

/**
* @name incrmidrange
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/midrange}
*/
setReadOnly( statistics, 'incrmidrange', require( '@stdlib/math/stats/incr/midrange' ) );

/**
* @name incrmin
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/min}
*/
setReadOnly( statistics, 'incrmin', require( '@stdlib/math/stats/incr/min' ) );

/**
* @name incrmmean
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/mmean}
*/
setReadOnly( statistics, 'incrmmean', require( '@stdlib/math/stats/incr/mmean' ) );

/**
* @name incrmstdev
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/mstdev}
*/
setReadOnly( statistics, 'incrmstdev', require( '@stdlib/math/stats/incr/mstdev' ) );

/**
* @name incrmsum
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/msum}
*/
setReadOnly( statistics, 'incrmsum', require( '@stdlib/math/stats/incr/msum' ) );

/**
* @name incrmsummary
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/msummary}
*/
setReadOnly( statistics, 'incrmsummary', require( '@stdlib/math/stats/incr/msummary' ) );

/**
* @name incrmvariance
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/mvariance}
*/
setReadOnly( statistics, 'incrmvariance', require( '@stdlib/math/stats/incr/mvariance' ) );

/**
* @name incrprod
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/prod}
*/
setReadOnly( statistics, 'incrprod', require( '@stdlib/math/stats/incr/prod' ) );

/**
* @name incrrange
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/range}
*/
setReadOnly( statistics, 'incrrange', require( '@stdlib/math/stats/incr/range' ) );

/**
* @name incrskewness
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/skewness}
*/
setReadOnly( statistics, 'incrskewness', require( '@stdlib/math/stats/incr/skewness' ) );

/**
* @name incrstdev
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/stdev}
*/
setReadOnly( statistics, 'incrstdev', require( '@stdlib/math/stats/incr/stdev' ) );

/**
* @name incrsum
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/sum}
*/
setReadOnly( statistics, 'incrsum', require( '@stdlib/math/stats/incr/sum' ) );

/**
* @name incrsummary
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/summary}
*/
setReadOnly( statistics, 'incrsummary', require( '@stdlib/math/stats/incr/summary' ) );

/**
* @name incrvariance
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/incr/variance}
*/
setReadOnly( statistics, 'incrvariance', require( '@stdlib/math/stats/incr/variance' ) );

/**
* @name kstest
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/kstest}
*/
setReadOnly( statistics, 'kstest', require( '@stdlib/math/stats/kstest' ) );

/**
* @name lowess
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/lowess}
*/
setReadOnly( statistics, 'lowess', require( '@stdlib/math/stats/lowess' ) );

/**
* @name pcorrtest
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/pcorrtest}
*/
setReadOnly( statistics, 'pcorrtest', require( '@stdlib/math/stats/pcorrtest' ) );

/**
* @name ttest
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/ttest}
*/
setReadOnly( statistics, 'ttest', require( '@stdlib/math/stats/ttest' ) );

/**
* @name ttest2
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/ttest2}
*/
setReadOnly( statistics, 'ttest2', require( '@stdlib/math/stats/ttest2' ) );

/**
* @name ztest
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/ztest}
*/
setReadOnly( statistics, 'ztest', require( '@stdlib/math/stats/ztest' ) );

/**
* @name ztest2
* @memberof statistics
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/stats/2}
*/
setReadOnly( statistics, 'ztest2', require( '@stdlib/math/stats/ztest2' ) );

// EXPORTS //

module.exports = statistics;
<|endoftext|>


<commit_before>'use strict';

require('./_navbar.scss');

module.exports = {
  template: require('./navbar.html'),
  controller: ['$log', '$location', '$window', '$rootScope', 'authService', 'hospitalService', NavController],
  controllerAs: 'navCtrl',
};

function NavController($log, $location, $window, $rootScope, authService, hospitalService){
  $log.debug('init navCtrl');

  this.pageLoadHandler = function(){
    $log.debug('navCtrl.pageLoadHandler()');
    let path = $location.path();

    if (path === '/join'){
      this.hideLogout = true;
      this.logoPic = require('../../assets/imgs/heretogether-logo.png');
    } else {
      this.hideLogout = false;
      this.logoPic = require('../../assets/imgs/heretogether-mobile-logo.png');
    }

    authService.getToken()
     .then(() => {
       if(path === '/join'){
         $location.url('/home');
       }
     })
     .catch(() => {
       let query = $location.search();
       if (query.token) {
         return authService.setToken(query.token)
         .then(() => {
           $location.url('/home');
         });
       }
       if (path !== '/join' ){
         $location.url('/join');
       }
     });
  };

  $window.onload = this.pageLoadHandler.bind(this);
  $rootScope.$on('$stateChangeStart', this.pageLoadHandler.bind(this));
}
<commit_msg>added logout function<commit_after>'use strict';

require('./_navbar.scss');

module.exports = {
  template: require('./navbar.html'),
  controller: ['$log', '$location', '$window', '$rootScope', 'authService', 'hospitalService', NavController],
  controllerAs: 'navCtrl',
};

function NavController($log, $location, $window, $rootScope, authService, hospitalService){
  $log.debug('init navCtrl');

  this.pageLoadHandler = function(){
    $log.debug('navCtrl.pageLoadHandler()');
    let path = $location.path();

    if (path === '/join'){
      this.hideLogout = true;
      this.logoPic = require('../../assets/imgs/heretogether-logo.png');
    } else {
      this.hideLogout = false;
      this.logoPic = require('../../assets/imgs/heretogether-mobile-logo.png');
    }

    authService.getToken()
     .then(() => {
       if(path === '/join'){
         $location.url('/home');
       }
     })
     .catch(() => {
       let query = $location.search();
       if (query.token) {
         return authService.setToken(query.token)
         .then(() => {
           $location.url('/home');
         });
       }
       if (path !== '/join' ){
         $location.url('/join');
       }
     });
  };

  this.logout = function() {
    $log.log('navbarCtrl.logout()');
    this.hideLogout = true;
    this.hideLogin = false;
    authService.logout()
      .then(() => {
        $location.url('/');
      });
  };

  $window.onload = this.pageLoadHandler.bind(this);
  $rootScope.$on('$stateChangeStart', this.pageLoadHandler.bind(this));
}
<|endoftext|>


<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace ns
*/
var ns = {};

/**
* @name dists
* @memberof ns
* @readonly
* @type {Namespace}
* @see {@link module:@stdlib/stats/base/dists}
*/
setReadOnly( ns, 'dists', require( '@stdlib/stats/base/dists' ) );

/**
* @name dmean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/dmean}
*/
setReadOnly( ns, 'dmean', require( '@stdlib/stats/base/dmean' ) );

/**
* @name dnanmean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/dnanmean}
*/
setReadOnly( ns, 'dnanmean', require( '@stdlib/stats/base/dnanmean' ) );

/**
* @name mean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/mean}
*/
setReadOnly( ns, 'mean', require( '@stdlib/stats/base/mean' ) );

/**
* @name nanmean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/nanmean}
*/
setReadOnly( ns, 'nanmean', require( '@stdlib/stats/base/nanmean' ) );

/**
* @name smean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/smean}
*/
setReadOnly( ns, 'smean', require( '@stdlib/stats/base/smean' ) );

/**
* @name snanmean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/snanmean}
*/
setReadOnly( ns, 'snanmean', require( '@stdlib/stats/base/snanmean' ) );

// EXPORTS //

module.exports = ns;
<commit_msg>Update namespace<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace ns
*/
var ns = {};

/**
* @name dists
* @memberof ns
* @readonly
* @type {Namespace}
* @see {@link module:@stdlib/stats/base/dists}
*/
setReadOnly( ns, 'dists', require( '@stdlib/stats/base/dists' ) );

/**
* @name dmax
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/dmax}
*/
setReadOnly( ns, 'dmax', require( '@stdlib/stats/base/dmax' ) );

/**
* @name dmean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/dmean}
*/
setReadOnly( ns, 'dmean', require( '@stdlib/stats/base/dmean' ) );

/**
* @name dnanmean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/dnanmean}
*/
setReadOnly( ns, 'dnanmean', require( '@stdlib/stats/base/dnanmean' ) );

/**
* @name mean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/mean}
*/
setReadOnly( ns, 'mean', require( '@stdlib/stats/base/mean' ) );

/**
* @name nanmean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/nanmean}
*/
setReadOnly( ns, 'nanmean', require( '@stdlib/stats/base/nanmean' ) );

/**
* @name smean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/smean}
*/
setReadOnly( ns, 'smean', require( '@stdlib/stats/base/smean' ) );

/**
* @name snanmean
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/stats/base/snanmean}
*/
setReadOnly( ns, 'snanmean', require( '@stdlib/stats/base/snanmean' ) );

// EXPORTS //

module.exports = ns;
<|endoftext|>


<commit_before>import React from 'react';
import Relay from 'react-relay';
import { second } from 'metrick/duration';
import DocumentTitle from 'react-document-title';
import shallowCompare from 'react-addons-shallow-compare';

import PageHeader from '../shared/PageHeader';
import Panel from '../shared/Panel';
import Button from '../shared/Button';
import SearchField from '../shared/SearchField';
import Spinner from '../shared/Spinner';
import permissions from '../../lib/permissions';
import { formatNumber } from '../../lib/number';

import InvitationRow from './InvitationRow';
import Row from './Row';

const PAGE_SIZE = 10;

class MemberIndex extends React.Component {
  static propTypes = {
    organization: React.PropTypes.shape({
      name: React.PropTypes.string.isRequired,
      slug: React.PropTypes.string.isRequired,
      permissions: React.PropTypes.object.isRequired,
      members: React.PropTypes.shape({
        count: React.PropTypes.number.isRequired,
        pageInfo: React.PropTypes.shape({
          hasNextPage: React.PropTypes.bool.isRequired
        }).isRequired,
        edges: React.PropTypes.arrayOf(
          React.PropTypes.shape({
            node: React.PropTypes.object.isRequired
          }).isRequired
        ).isRequired
      }),
      invitations: React.PropTypes.shape({
        pageInfo: React.PropTypes.shape({
          hasNextPage: React.PropTypes.bool.isRequired
        }).isRequired,
        edges: React.PropTypes.arrayOf(
          React.PropTypes.shape({
            node: React.PropTypes.object.isRequired
          })
        ).isRequired
      })
    }).isRequired,
    relay: React.PropTypes.object.isRequired
  };

  state = {
    loadingMembers: false,
    searchingMembersIsSlow: false,
    loadingInvitations: false
  };

  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
  }

  componentDidMount() {
    // Use a `forceFetch` so every time the user comes back to this page we'll
    // grab fresh data.
    this.props.relay.forceFetch({ isMounted: true });
  }

  render() {
    return (
      <DocumentTitle title={`Users · ${this.props.organization.name}`}>

          <PageHeader>
            <PageHeader.Title>
              Users
            </PageHeader.Title>
            <PageHeader.Description>
              Invite people to this organization so they can see and create builds, manage pipelines, and customize their notification preferences.
            </PageHeader.Description>
            <PageHeader.Menu>{this.renderNewMemberButton()}</PageHeader.Menu>
          </PageHeader>
          <Panel className="mb4">
            <Panel.Row>
              <SearchField
                placeholder="Search users…"
                searching={this.state.searchingMembersIsSlow}
                onChange={this.handleMemberSearch}
              />
            </Panel.Row>
            {this.renderMemberSearchInfo()}
            {this.renderMembers()}
            {this.renderMemberFooter()}
          </Panel>

          <Panel>
            <Panel.Header>Invitations</Panel.Header>
            {this.renderInvitations()}
            {this.renderInvitationFooter()}
          </Panel>

      </DocumentTitle>
    );
  }

  renderNewMemberButton() {
    return permissions(this.props.organization.permissions).check(
      {
        allowed: "organizationInvitationCreate",
        render: () => <PageHeader.Button link={`/organizations/${this.props.organization.slug}/users/new`} theme="default" outline={true}>Invite Users</PageHeader.Button>
      }
    );
  }

  renderMemberSearchInfo() {
    const { organization: { members }, relay: { variables: { memberSearch } } } = this.props;

    if (memberSearch && members) {
      return (

            {formatNumber(members.count)} matching members

      );
    }
  }

  renderMembers() {
    const { members } = this.props.organization;

    if (!members) {
      return (
        <Panel.Section className="center">
          <Spinner />
        </Panel.Section>
      );
    } else {
      return members.edges.map((edge) => {
        return (
          <Row
            key={edge.node.id}
            organization={this.props.organization}
            organizationMember={edge.node}
          />
        );
      });
    }
  }

  renderMemberFooter() {
    // don't show any footer if we haven't ever loaded
    // any members, or if there's no next page
    if (!this.props.organization.members || !this.props.organization.members.pageInfo.hasNextPage) {
      return;
    }

    let footerContent = (
      <Button
        outline={true}
        theme="default"
        onClick={this.handleLoadMoreMembersClick}
      >
        Show more users…
      </Button>
    );

    // show a spinner if we're loading more members
    if (this.state.loadingMembers) {
      footerContent = <Spinner style={{ margin: 9.5 }} />;
    }

    return (
      <Panel.Footer className="center">
        {footerContent}
      </Panel.Footer>
    );
  }

  handleMemberSearch = (memberSearch) => {
    this.setState({ searchingMembers: true });

    if (this.memberSearchIsSlowTimeout) {
      clearTimeout(this.memberSearchIsSlowTimeout);
    }

    this.memberSearchIsSlowTimeout = setTimeout(() => {
      this.setState({ searchingMembersIsSlow: true });
    }, 1::second);

    this.props.relay.forceFetch(
      { memberSearch },
      (readyState) => {
        if (readyState.done) {
          if (this.memberSearchIsSlowTimeout) {
            clearTimeout(this.memberSearchIsSlowTimeout);
          }
          this.setState({
            searchingMembers: false,
            searchingMembersIsSlow: false
          });
        }
      }
    );
  };

  handleLoadMoreMembersClick = () => {
    this.setState({ loadingMembers: true });

    let { memberPageSize } = this.props.relay.variables;

    memberPageSize += PAGE_SIZE;

    this.props.relay.setVariables(
      { memberPageSize },
      (readyState) => {
        if (readyState.done) {
          this.setState({ loadingMembers: false });
        }
      }
    );
  };

  renderInvitations() {
    const invitations = this.props.organization.invitations;

    if (!invitations) {
      return (
        <Panel.Section className="center">
          <Spinner />
        </Panel.Section>
      );
    } else {
      if (invitations.edges.length > 0) {
        return (
          invitations.edges.map((edge) => {
            return (
              <InvitationRow
                key={edge.node.id}
                organization={this.props.organization}
                organizationInvitation={edge.node}
              />
            );
          })
        );
      } else {
        return (
          <Panel.Section>

There are no pending invitations

          </Panel.Section>
        );
      }
    }
  }

  renderInvitationFooter() {
    // don't show any footer if we haven't ever loaded
    // any invitations, or if there's no next page
    if (!this.props.organization.invitations || !this.props.organization.invitations.pageInfo.hasNextPage) {
      return;
    }

    let footerContent = (
      <Button
        outline={true}
        theme="default"
        onClick={this.handleLoadMoreInvitationsClick}
      >
        Show more invitations…
      </Button>
    );

    // show a spinner if we're loading more invitations
    if (this.state.loadingInvitations) {
      footerContent = <Spinner style={{ margin: 9.5 }} />;
    }

    return (
      <Panel.Footer className="center">
        {footerContent}
      </Panel.Footer>
    );
  }

  handleLoadMoreInvitationsClick = () => {
    this.setState({ loadingInvitations: true });

    let { invitationPageSize } = this.props.relay.variables;

    invitationPageSize += PAGE_SIZE;

    this.props.relay.setVariables(
      { invitationPageSize },
      (readyState) => {
        if (readyState.done) {
          this.setState({ loadingInvitations: false });
        }
      }
    );
  };
}

export default Relay.createContainer(MemberIndex, {
  initialVariables: {
    isMounted: false,
    memberPageSize: PAGE_SIZE,
    memberSearch: null,
    invitationPageSize: PAGE_SIZE
  },

  fragments: {
    organization: () => Relay.QL`
      fragment on Organization {
        name
        slug
        ${Row.getFragment('organization')}
        permissions {
          organizationInvitationCreate {
            allowed
          }
        }
        members(first: $memberPageSize, search: $memberSearch, order: NAME) @include(if: $isMounted) {
          count
          edges {
            node {
              id
              ${Row.getFragment('organizationMember')}
            }
          }
          pageInfo {
            hasNextPage
          }
        }
        invitations(first: $invitationPageSize, state: PENDING) @include(if: $isMounted) {
          edges {
            node {
              id
              ${InvitationRow.getFragment('organizationInvitation')}
            }
          }
          pageInfo {
            hasNextPage
          }
        }
      }
    `
  }
});
<commit_msg>Add role filtering to user management<commit_after>import React from 'react';
import Relay from 'react-relay';
import { second } from 'metrick/duration';
import DocumentTitle from 'react-document-title';
import shallowCompare from 'react-addons-shallow-compare';

import Button from '../shared/Button';
import Dropdown from '../shared/Dropdown';
import PageHeader from '../shared/PageHeader';
import Panel from '../shared/Panel';
import SearchField from '../shared/SearchField';
import Spinner from '../shared/Spinner';
import permissions from '../../lib/permissions';
import { formatNumber } from '../../lib/number';

import InvitationRow from './InvitationRow';
import Row from './Row';

import TeamMemberRoleConstants from '../../constants/TeamMemberRoleConstants';

const TEAM_ROLES =  [
  { name: 'Everyone', id: null },
  { name: 'Administrators', id: TeamMemberRoleConstants.ADMIN },
  { name: 'Users', id: TeamMemberRoleConstants.MEMBER }
];

const PAGE_SIZE = 10;

class MemberIndex extends React.Component {
  static propTypes = {
    organization: React.PropTypes.shape({
      name: React.PropTypes.string.isRequired,
      slug: React.PropTypes.string.isRequired,
      permissions: React.PropTypes.object.isRequired,
      members: React.PropTypes.shape({
        count: React.PropTypes.number.isRequired,
        pageInfo: React.PropTypes.shape({
          hasNextPage: React.PropTypes.bool.isRequired
        }).isRequired,
        edges: React.PropTypes.arrayOf(
          React.PropTypes.shape({
            node: React.PropTypes.object.isRequired
          }).isRequired
        ).isRequired
      }),
      invitations: React.PropTypes.shape({
        pageInfo: React.PropTypes.shape({
          hasNextPage: React.PropTypes.bool.isRequired
        }).isRequired,
        edges: React.PropTypes.arrayOf(
          React.PropTypes.shape({
            node: React.PropTypes.object.isRequired
          })
        ).isRequired
      })
    }).isRequired,
    relay: React.PropTypes.object.isRequired
  };

  state = {
    loadingMembers: false,
    searchingMembersIsSlow: false,
    loadingInvitations: false
  };

  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
  }

  componentDidMount() {
    // Use a `forceFetch` so every time the user comes back to this page we'll
    // grab fresh data.
    this.props.relay.forceFetch({ isMounted: true });
  }

  render() {
    return (
      <DocumentTitle title={`Users · ${this.props.organization.name}`}>

          <PageHeader>
            <PageHeader.Title>
              Users
            </PageHeader.Title>
            <PageHeader.Description>
              Invite people to this organization so they can see and create builds, manage pipelines, and customize their notification preferences.
            </PageHeader.Description>
            <PageHeader.Menu>{this.renderNewMemberButton()}</PageHeader.Menu>
          </PageHeader>
          <Panel className="mb4">

                <SearchField
                  className="flex-auto"
                  placeholder="Search users…"
                  searching={this.state.searchingMembersIsSlow}
                  onChange={this.handleMemberSearch}
                />

                  <Dropdown width={150} ref={(_memberRoleDropdown) => this._memberRoleDropdown = _memberRoleDropdown}>

{TEAM_ROLES.find((role) => role.id === this.props.relay.variables.memberRole).name}

                    {this.renderMemberRoles()}
                  </Dropdown>

            {this.renderMemberSearchInfo()}
            {this.renderMembers()}
            {this.renderMemberFooter()}
          </Panel>

          <Panel>
            <Panel.Header>Invitations</Panel.Header>
            {this.renderInvitations()}
            {this.renderInvitationFooter()}
          </Panel>

      </DocumentTitle>
    );
  }

  renderNewMemberButton() {
    return permissions(this.props.organization.permissions).check(
      {
        allowed: "organizationInvitationCreate",
        render: () => <PageHeader.Button link={`/organizations/${this.props.organization.slug}/users/new`} theme="default" outline={true}>Invite Users</PageHeader.Button>
      }
    );
  }

  renderMemberRoles() {
    return TEAM_ROLES.map((role, index) => {
      return (

 { this._memberRoleDropdown.setShowing(false); this.handleMemberRoleSelect(role.id); }}>
          {role.name}

      );
    });
  }

  handleMemberRoleSelect = (memberRole) => {
    this.handleMemberFilterChange({ memberRole });
  };

  renderMemberSearchInfo() {
    const { organization: { members }, relay: { variables: { memberSearch } } } = this.props;

    if (memberSearch && members) {
      return (

            {formatNumber(members.count)} matching members

      );
    }
  }

  renderMembers() {
    const { members } = this.props.organization;

    if (!members) {
      return (
        <Panel.Section className="center">
          <Spinner />
        </Panel.Section>
      );
    } else {
      return members.edges.map((edge) => {
        return (
          <Row
            key={edge.node.id}
            organization={this.props.organization}
            organizationMember={edge.node}
          />
        );
      });
    }
  }

  renderMemberFooter() {
    // don't show any footer if we haven't ever loaded
    // any members, or if there's no next page
    if (!this.props.organization.members || !this.props.organization.members.pageInfo.hasNextPage) {
      return;
    }

    let footerContent = (
      <Button
        outline={true}
        theme="default"
        onClick={this.handleLoadMoreMembersClick}
      >
        Show more users…
      </Button>
    );

    // show a spinner if we're loading more members
    if (this.state.loadingMembers) {
      footerContent = <Spinner style={{ margin: 9.5 }} />;
    }

    return (
      <Panel.Footer className="center">
        {footerContent}
      </Panel.Footer>
    );
  }

  handleMemberSearch = (memberSearch) => {
    this.handleMemberFilterChange({ memberSearch });
  };

  handleMemberFilterChange = (varibles) => {
    this.setState({ searchingMembers: true });

    if (this.memberSearchIsSlowTimeout) {
      clearTimeout(this.memberSearchIsSlowTimeout);
    }

    this.memberSearchIsSlowTimeout = setTimeout(() => {
      this.setState({ searchingMembersIsSlow: true });
    }, 1::second);

    this.props.relay.forceFetch(
      varibles,
      (readyState) => {
        if (readyState.done) {
          if (this.memberSearchIsSlowTimeout) {
            clearTimeout(this.memberSearchIsSlowTimeout);
          }
          this.setState({
            searchingMembers: false,
            searchingMembersIsSlow: false
          });
        }
      }
    );
  };

  handleLoadMoreMembersClick = () => {
    this.setState({ loadingMembers: true });

    let { memberPageSize } = this.props.relay.variables;

    memberPageSize += PAGE_SIZE;

    this.props.relay.setVariables(
      { memberPageSize },
      (readyState) => {
        if (readyState.done) {
          this.setState({ loadingMembers: false });
        }
      }
    );
  };

  renderInvitations() {
    const invitations = this.props.organization.invitations;

    if (!invitations) {
      return (
        <Panel.Section className="center">
          <Spinner />
        </Panel.Section>
      );
    } else {
      if (invitations.edges.length > 0) {
        return (
          invitations.edges.map((edge) => {
            return (
              <InvitationRow
                key={edge.node.id}
                organization={this.props.organization}
                organizationInvitation={edge.node}
              />
            );
          })
        );
      } else {
        return (
          <Panel.Section>

There are no pending invitations

          </Panel.Section>
        );
      }
    }
  }

  renderInvitationFooter() {
    // don't show any footer if we haven't ever loaded
    // any invitations, or if there's no next page
    if (!this.props.organization.invitations || !this.props.organization.invitations.pageInfo.hasNextPage) {
      return;
    }

    let footerContent = (
      <Button
        outline={true}
        theme="default"
        onClick={this.handleLoadMoreInvitationsClick}
      >
        Show more invitations…
      </Button>
    );

    // show a spinner if we're loading more invitations
    if (this.state.loadingInvitations) {
      footerContent = <Spinner style={{ margin: 9.5 }} />;
    }

    return (
      <Panel.Footer className="center">
        {footerContent}
      </Panel.Footer>
    );
  }

  handleLoadMoreInvitationsClick = () => {
    this.setState({ loadingInvitations: true });

    let { invitationPageSize } = this.props.relay.variables;

    invitationPageSize += PAGE_SIZE;

    this.props.relay.setVariables(
      { invitationPageSize },
      (readyState) => {
        if (readyState.done) {
          this.setState({ loadingInvitations: false });
        }
      }
    );
  };
}

export default Relay.createContainer(MemberIndex, {
  initialVariables: {
    isMounted: false,
    memberPageSize: PAGE_SIZE,
    memberSearch: null,
    memberRole: null,
    invitationPageSize: PAGE_SIZE
  },

  fragments: {
    organization: () => Relay.QL`
      fragment on Organization {
        name
        slug
        ${Row.getFragment('organization')}
        permissions {
          organizationInvitationCreate {
            allowed
          }
        }
        members(first: $memberPageSize, search: $memberSearch, role: $memberRole, order: NAME) @include(if: $isMounted) {
          count
          edges {
            node {
              id
              ${Row.getFragment('organizationMember')}
            }
          }
          pageInfo {
            hasNextPage
          }
        }
        invitations(first: $invitationPageSize, state: PENDING) @include(if: $isMounted) {
          edges {
            node {
              id
              ${InvitationRow.getFragment('organizationInvitation')}
            }
          }
          pageInfo {
            hasNextPage
          }
        }
      }
    `
  }
});
<|endoftext|>


<commit_before>// init
var fs = require('fs-extra');
var epub = require('epub-gen');
var kg = require('./kindlegen.js');
var pathF = require('path');

var converter = function() {

    var self = this;
    var path = 'data/books/';
    var taskPath = 'data/tasks/converter.task';
    var tempEpudPath = 'node_modules/epub-gen/tempDir';
    var tempCleanCount = 0;  // clean temp dir if count > 3
    var maxTempCleanCount = 5;
    var taskList = [];
    var status;
	var taskLimit = 200;

    const READY = 0,
        WORKING = 1;

    this.init = function() {

        fs.readJson(taskPath, function(err, t) {

            status = READY;

            if (!err) {
                taskList = t;

            } else {

                taskList = [];
            }

            console.log('Converter > Initialized.', taskList.length, 'tasks waiting.');

            if (taskList.length > 0) self.convertBook();
        });
    };

    this.isDuplicate = function (task) {

        var result = false;

        taskList.forEach(function (e, i, a) {

            if (e.cid == task.cid && e.bookInfo.id == task.bookInfo.id) result = true;

        });

        return result;

    }

    this.valid = function (task) {

        // check if the book was converted within 1 day

        var result = false;

        var one_hour = 1000 * 60 * 60;

        var lastConvert = task.bookInfo.chapters[task.cid].lastConvert;
        var diff = ((Date.now() - lastConvert) / one_hour).toFixed(0);

        if (!lastConvert || lastConvert == 0 || diff >= 20) result = true;

        return result;

    }

    this.queue = function (cid, bookInfo, callback) {

        // callback(err, type{'epup' || 'mobi' || 'busy'}, bookInfo)

        var task = {
            cid: cid,
            bookInfo: bookInfo,
            callback: callback
        };

		// check if tasks is over the limit

		if(taskList.length >= taskLimit) return false;

        // check duplicate

        if (self.isDuplicate(task)) {

            if (callback) callback(new Error('task is already in the list'));

            console.log('Converter > Task is already in the list!');

            return false;
        }

        // check if the book is updated within 1 day.

        if (!self.valid(task)) {

            if (callback) callback(new Error('Task has been converted within 1 day.'));

            console.log('Converter > Task has been converted within 1 day.');

            return false;
        }

        fs.access('data/books/' + bookInfo.id + '/txt/' + bookInfo.chapters[cid].vid + '.txt', fs.R_OK | fs.W_OK, (err) => {

            if (!err) {

                // no error opening the file

                console.log('Converter > Queued task:', bookInfo.title, bookInfo.chapters[cid].title);

                taskList.push(task);

                self.saveTask();
                self.convertBook();

                if (taskList.length > 0) {
                    if (callback) callback(null, 'busy', bookInfo);
                }

                console.log('Converter > Tasks:', taskList.length);

            } else {

                console.log('Converter > Failed to queue task:', bookInfo.title, bookInfo.chapters[cid].title);
                callback(err, null);

            }
        });

        //self.convertBook();

        return true;
    }

    this.convertBook = function () {

        // check status
        if (status == READY && taskList.length > 0) {

            if (!taskList[0].bookInfo) {

                taskList[0].callback(new Error('bookInfo is empty'), null);

                // if no bookinfo, remove then return.
                self.remove(0);

                // after converted to mobi, keep convert
                self.convertBook();

            }

            // set status to busy

            status = WORKING;

            // if no callback set default callback

            if(!taskList[0].callback) taskList[0].callback = function(){

                console.log('Converter > No callback!');
            };

            // Start

            var chapters;

            self.readBook(taskList[0].cid, taskList[0].bookInfo, function(err, c) {

                if (!err) {
                    // no err parse the book, start converting
                    console.log('Converter > Start converting!');

                    // start generating epub
                    var vPath = path + taskList[0].bookInfo.id;
                    var epubPath = vPath + "/epub/" + taskList[0].bookInfo.chapters[taskList[0].cid].vid + '.epub'

                    if (taskList[0].bookInfo.chapters[taskList[0].cid].images[0]) {

                        // if there is a cover for chapter exist

						//console.log('Converter > Cover for chapter exist!');

                        var coverPath = taskList[0].bookInfo.chapters[taskList[0].cid].images[0];

						console.log('Converter > Cover path is: ' + coverPath);

                        if (coverPath.startsWith('./')) {

							coverPath = pathF.resolve(__dirname + '/../', coverPath);

							console.log('Converter > Resolved Cover path is: ' + coverPath);

							if (!fs.accessSync(coverPath, fs.R_OK)){

								//console.log('Converter > However, cover for chapter does not exist! Using default image!');
								console.log('Converter > Local cover exists! Using it.');

							} else {

								coverPath = null;
								console.log('Converter > However, cover for chapter does not exist! Not using cover!');
							}

						} else {

								//var coverPath = './' + vPath + '/image.jpg';

								coverPath = null;
								console.log('Converter > However, cover for chapter does not exist locally! Using default image!');

						}

                    } else {

                        // else use the default cover image

                        //coverPath = './' + vPath + '/image.jpg';

						coverPath = null;
						console.log('Converter > Cover for chapter does not exist, using default cover image!');

                    }

                    var option = {
                        title: taskList[0].bookInfo.title + ' ' + taskList[0].bookInfo.chapters[taskList[0].cid].title, // *Required, title of the book.
                        author: taskList[0].bookInfo.author,
                        publisher: taskList[0].bookInfo.publisher,
                        cover: coverPath,
                        appendChapterTitles: false,
                        content: [],
                        description: taskList[0].bookInfo.desc,
                    };

                    console.log('Converter > Finished init epub generate options.');

                    // add title page

                    var chapter = {
                        title: taskList[0].bookInfo.title,
                        data: '

' + taskList[0].bookInfo.chapters[taskList[0].cid].title + '

内容简介

' + taskList[0].bookInfo.desc + '
'
                    };

                    option.content.push(chapter);

                    // add chapters

                    c.forEach(function (element, index, array) {

                        var chapter;

                        if (element.title.includes('插图')) {

                            // if the chapter is image chapter

                            console.log('Converter > Adding images to the book.');

                            var images = taskList[0].bookInfo.chapters[taskList[0].cid].images;
                            var data = '

' + element.title + '

';

                            images.forEach(function (element, index, array) {

                                if (element.startsWith('./')) {

									// local file check

									var imagePath = pathF.resolve(__dirname + '/../', element);

									if(!fs.accessSync(imagePath, fs.R_OK )){

										data += '
';

									} else {

										console.log("Converter > Image is not available right now. ");

									}

                                    //data += '
';

                                } else {

                                    data += '
';
                                }

                            });

                            data += element.content + '
';

                            chapter = {

                                title: element.title,
                                data: data

                            };

                        } else {

                            // if it isnt image chapter

							// trim the title if it is too long (> 30)
                            chapter = {
                                title: element.title.length > 30 ? element.title.substring(0,30) + '...' : element.title,
                                data: '

' + element.title + '

' + element.content + '
'
                            };
                        }

                        option.content.push(chapter);

                        console.log('Converter > Added chapter', element.title);
                    });

                    var chapter = {
                        title: 'Kindle Light',
                        data: '
本图书由Kindle Light 在线生成工具自动生成的哦！看更多的Kindle轻小说，请来: Kindle Light!

'
                    };

                    option.content.push(chapter);

                    console.log('Converter > Chapters setup complete.');

                    // start converting

                    fs.ensureDir(vPath + "/epub/", function(err) {

                        if (!err) {

                            // no error ensure the dir : /epub/

							try {

								new epub(option, epubPath).promise.then(function() {

									console.log("Converter > Ebook Generated Successfully!");

									// callback epub file generated

									taskList[0].callback(null, 'epub');

									// start convert the book to .mobi

									// sudo ./bin/kindlegen/kindlegen -c2 ./data/books/1657/epub/57218.epub -o 57218.mobi

									fs.ensureDir(vPath + '/mobi/', function(err) {

										if (!err) {

											// no error when ensuring the mobi dir

											//start converting

											console.log('Converter > Converting .epub to .mobi.');

											var epubPath = vPath + "/epub/" + taskList[0].bookInfo.chapters[taskList[0].cid].vid + '.epub';
											var mobiPath = vPath + "/mobi/" + taskList[0].bookInfo.chapters[taskList[0].cid].vid + '.mobi';
											var orimobiPath = vPath + "/epub/" + taskList[0].bookInfo.chapters[taskList[0].cid].vid + '.mobi';

											// start converting , from epub to mobi

											kg.convert(epubPath, function (err, out) {

												fs.move(orimobiPath, mobiPath, {
													clobber: true // set overwrite
												}, function (err) {

													if (!err) {
														// no err moving the file

														console.log('Converter > Convert successful! File:', mobiPath);

														taskList[0].callback(null, 'mobi');

													} else {

														// err moving the file

														console.log('Converter > Error moving the file! File:', mobiPath);

													}

													self.remove(0);

													// after converted to mobi, keep convert
													self.convertBook();
												});

											});

											// done converting epub

										} else {

											// err ensuring mobi path
											console.log('Converter > Error ensoring mobi folder');

											self.remove(0);

											// after converted to mobi, keep convert
											self.convertBook();

										}

									});

									// keep convert

								}, function (err) {

									// err when converting to epub

									console.error("Converter > Failed to generate Ebook because of ", err);

									taskList[0].callback(err,null);

									// err

									self.remove(0);

									console.log('Converter > Error when converting:', err);

									// keep convert

									self.convertBook();
								});

							} catch (err){

								// caught error when converting to epub

								console.log('Converter > Error when converting:', err );

								console.log('Converter > Will ignore current task and move on.');

								// err

								self.remove(0);

								// keep convert

								self.convertBook();
							}

                        } else {

                            // error when ensure /epub/ dir

                            taskList[0].callback(err,null);

                            // err

                            self.remove(0);

                            console.log('Converter > Error when converting:', err);

                            // keep convert

                            self.convertBook();

                        }

                    })

                } else {

                    // Error parse the book

                    taskList[0].callback(err,null);

                    // err

                    self.remove(0);

                    console.log('Converter > Error when reading file:', err);

                    // keep convert

                    self.convertBook();

                }

            });

        } else {

            console.log('Converter > No task to do or Converter is working.');

            if (status == READY) taskList = [];

            //self.saveTask();

        }

    }

    this.readBook = function(cid, bookInfo, callback) {

        var cid = cid;
        var chapters = [];
        var title = bookInfo.chapters[cid].title.replace('\r\n', '');
        var file = path + bookInfo.id + '/txt/' + bookInfo.chapters[cid].vid + '.txt';

        // open file

        console.log('Converter > Reading local file:', file);

        fs.readFile(file, function(err, data) {

            if (!err) {

                // file opened

                console.log('Converter > Parsing Book.');

                // parse the book/chapters

                var book = String(data).replace('undefined', '').split(title);
                var chapters = [];

                // remove the first chapter : ★☆★☆★☆轻小说文库(Www.WenKu8.com)☆★☆★☆★
                book.splice(0, 1);

                book.forEach(function(element, index, array) {

                    var ctitle = element.substr(1, element.indexOf('\r\n', 1)).replace('\r', '');
                    var cdata = element.substr(element.indexOf('\r\n', 1), element.length).replace(/(\r\n|\n|\r)/g, '
');

                    chapters.push({
                        id: index,
                        title: ctitle,
                        content: cdata
                    });

                });

                callback(err, chapters);

            } else {

                console.log('Conveter > Err opening file', file);

                callback(err, null);

                self.remove(0);
            }

        });

    };

    this.remove = function(id) {

        if (taskList[id])
            taskList.splice(id, 1);
        status = READY;

        self.saveTask();

        // empty the temp files

        if (tempCleanCount >= maxTempCleanCount) {

            fs.emptyDir(tempEpudPath, function (err) {
                if (!err) console.log('Converter > Clean temp file successful!')
            });

            tempCleanCount = 0;

        } else {

            tempCleanCount++;
        }

    }

    this.saveTask = function() {

        console.log('Converter > Saving tasks..');

        fs.outputJson(taskPath, taskList, function(err) {

            if (!err) {

                console.log('Converter > Task list saved.');

            } else {

                console.log('Converter > Task list save failed.');
            }

        });
    }

    this.getTaskNum = function () {

        return taskList.length;

    }

}

// export module
module.exports = new converter();
<commit_msg>Fixed converter bug<commit_after>// init
var fs = require('fs-extra');
var epub = require('epub-gen');
var kg = require('./kindlegen.js');
var pathF = require('path');

var converter = function() {

    var self = this;
    var path = 'data/books/';
    var taskPath = 'data/tasks/converter.task';
    var tempEpudPath = 'node_modules/epub-gen/tempDir';
    var tempCleanCount = 0;  // clean temp dir if count > 3
    var maxTempCleanCount = 5;
    var taskList = [];
    var status;
	var taskLimit = 200;

    const READY = 0,
        WORKING = 1;

    this.init = function() {

        fs.readJson(taskPath, function(err, t) {

            status = READY;

            if (!err) {
                taskList = t;

            } else {

                taskList = [];
            }

            console.log('Converter > Initialized.', taskList.length, 'tasks waiting.');

            if (taskList.length > 0) self.convertBook();
        });
    };

    this.isDuplicate = function (task) {

        var result = false;

        taskList.forEach(function (e, i, a) {

            if (e.cid == task.cid && e.bookInfo.id == task.bookInfo.id) result = true;

        });

        return result;

    }

    this.valid = function (task) {

        // check if the book was converted within 1 day

        var result = false;

        var one_hour = 1000 * 60 * 60;

        var lastConvert = task.bookInfo.chapters[task.cid].lastConvert;
        var diff = ((Date.now() - lastConvert) / one_hour).toFixed(0);

        if (!lastConvert || lastConvert == 0 || diff >= 20) result = true;

        return result;

    }

    this.queue = function (cid, bookInfo, callback) {

        // callback(err, type{'epup' || 'mobi' || 'busy'}, bookInfo)

        var task = {
            cid: cid,
            bookInfo: bookInfo,
            callback: callback
        };

		// check if tasks is over the limit

		if(taskList.length >= taskLimit) return false;

        // check duplicate

        if (self.isDuplicate(task)) {

            if (callback) callback(new Error('task is already in the list'));

            console.log('Converter > Task is already in the list!');

            return false;
        }

        // check if the book is updated within 1 day.

        if (!self.valid(task)) {

            if (callback) callback(new Error('Task has been converted within 1 day.'));

            console.log('Converter > Task has been converted within 1 day.');

            return false;
        }

        fs.access('data/books/' + bookInfo.id + '/txt/' + bookInfo.chapters[cid].vid + '.txt', fs.R_OK | fs.W_OK, (err) => {

            if (!err) {

                // no error opening the file

                console.log('Converter > Queued task:', bookInfo.title, bookInfo.chapters[cid].title);

                taskList.push(task);

                self.saveTask();
                self.convertBook();

                if (taskList.length > 0) {
                    if (callback) callback(null, 'busy', bookInfo);
                }

                console.log('Converter > Tasks:', taskList.length);

            } else {

                console.log('Converter > Failed to queue task:', bookInfo.title, bookInfo.chapters[cid].title);
                callback(err, null);

            }
        });

        //self.convertBook();

        return true;
    }

    this.convertBook = function () {

        // check status
        if (status == READY && taskList.length > 0) {

            if (!taskList[0].bookInfo) {

                taskList[0].callback(new Error('bookInfo is empty'), null);

                // if no bookinfo, remove then return.
                self.remove(0);

                // after converted to mobi, keep convert
                self.convertBook();

            }

            // set status to busy

            status = WORKING;

            // if no callback set default callback

            if(!taskList[0].callback) taskList[0].callback = function(){

                console.log('Converter > No callback!');
            };

            // Start

            var chapters;

            self.readBook(taskList[0].cid, taskList[0].bookInfo, function(err, c) {

                if (!err) {
                    // no err parse the book, start converting
                    console.log('Converter > Start converting!');

                    // start generating epub
                    var vPath = path + taskList[0].bookInfo.id;
                    var epubPath = vPath + "/epub/" + taskList[0].bookInfo.chapters[taskList[0].cid].vid + '.epub'

                    if (taskList[0].bookInfo.chapters[taskList[0].cid].images[0]) {

                        // if there is a cover for chapter exist

						//console.log('Converter > Cover for chapter exist!');

                        var coverPath = taskList[0].bookInfo.chapters[taskList[0].cid].images[0];

						console.log('Converter > Cover path is: ' + coverPath);

                        if (coverPath.startsWith('./')) {

							coverPath = pathF.resolve(__dirname + '/../', coverPath);

							console.log('Converter > Resolved Cover path is: ' + coverPath);

							if (!fs.accessSync(coverPath, fs.R_OK)){

								//console.log('Converter > However, cover for chapter does not exist! Using default image!');
								console.log('Converter > Local cover exists! Using it.');

							} else {

								//coverPath = null;

								var coverPath = '' + vPath + '/image.jpg';

								fs.ensureFileSync(coverPath);

								console.log('Converter > However, cover for chapter does not exist! Using default image!');
							}

						} else {

								var coverPath = '' + vPath + '/image.jpg';

								fs.ensureFileSync(coverPath);

								//coverPath = null;
								console.log('Converter > However, cover for chapter does not exist locally! Using default image!');

						}

                    } else {

                        // else use the default cover image

                        coverPath = './' + vPath + '/image.jpg';

						fs.ensureFileSync(coverPath);

						//coverPath = null;
						console.log('Converter > Cover for chapter does not exist, using default cover image!');

                    }

					var option = {
						title: taskList[0].bookInfo.title + ' ' + taskList[0].bookInfo.chapters[taskList[0].cid].title, // *Required, title of the book.
						author: taskList[0].bookInfo.author,
						publisher: taskList[0].bookInfo.publisher,
						cover: coverPath,
						appendChapterTitles: false,
						content: [],
						description: taskList[0].bookInfo.desc,
					};

                    console.log('Converter > Finished init epub generate options.');

                    // add title page

                    var chapter = {
                        title: taskList[0].bookInfo.title,
                        data: '

' + taskList[0].bookInfo.chapters[taskList[0].cid].title + '

内容简介

' + taskList[0].bookInfo.desc + '
'
                    };

                    option.content.push(chapter);

                    // add chapters

                    c.forEach(function (element, index, array) {

                        var chapter;

                        if (element.title.includes('插图')) {

                            // if the chapter is image chapter

                            console.log('Converter > Adding images to the book.');

                            var images = taskList[0].bookInfo.chapters[taskList[0].cid].images;
                            var data = '

' + element.title + '

';

                            images.forEach(function (element, index, array) {

                                if (element.startsWith('./')) {

									// local file check

									var imagePath = pathF.resolve(__dirname + '/../', element);

									if(!fs.accessSync(imagePath, fs.R_OK )){

										data += '
';

									} else {

										console.log("Converter > Image is not available right now. ");

									}

                                    //data += '
';

                                } else {

                                    data += '
';
                                }

                            });

                            data += element.content + '
';

                            chapter = {

                                title: element.title,
                                data: data

                            };

                        } else {

                            // if it isnt image chapter

							// trim the title if it is too long (> 30)
                            chapter = {
                                title: element.title.length > 30 ? element.title.substring(0,30) + '...' : element.title,
                                data: '

' + element.title + '

' + element.content + '
'
                            };
                        }

                        option.content.push(chapter);

                        console.log('Converter > Added chapter', element.title);
                    });

                    var chapter = {
                        title: 'Kindle Light',
                        data: '
本图书由Kindle Light 在线生成工具自动生成的哦！看更多的Kindle轻小说，请来: Kindle Light!

'
                    };

                    option.content.push(chapter);

                    console.log('Converter > Chapters setup complete.');

                    // start converting

                    fs.ensureDir(vPath + "/epub/", function(err) {

                        if (!err) {

                            // no error ensure the dir : /epub/

							try {

								new epub(option, epubPath).promise.then(function() {

									console.log("Converter > Ebook Generated Successfully!");

									// callback epub file generated

									taskList[0].callback(null, 'epub');

									// start convert the book to .mobi

									// sudo ./bin/kindlegen/kindlegen -c2 ./data/books/1657/epub/57218.epub -o 57218.mobi

									fs.ensureDir(vPath + '/mobi/', function(err) {

										if (!err) {

											// no error when ensuring the mobi dir

											//start converting

											console.log('Converter > Converting .epub to .mobi.');

											var epubPath = vPath + "/epub/" + taskList[0].bookInfo.chapters[taskList[0].cid].vid + '.epub';
											var mobiPath = vPath + "/mobi/" + taskList[0].bookInfo.chapters[taskList[0].cid].vid + '.mobi';
											var orimobiPath = vPath + "/epub/" + taskList[0].bookInfo.chapters[taskList[0].cid].vid + '.mobi';

											// start converting , from epub to mobi

											kg.convert(epubPath, function (err, out) {

												fs.move(orimobiPath, mobiPath, {
													clobber: true // set overwrite
												}, function (err) {

													if (!err) {
														// no err moving the file

														console.log('Converter > Convert successful! File:', mobiPath);

														taskList[0].callback(null, 'mobi');

													} else {

														// err moving the file

														console.log('Converter > Error moving the file! File:', mobiPath);

													}

													self.remove(0);

													// after converted to mobi, keep convert
													self.convertBook();
												});

											});

											// done converting epub

										} else {

											// err ensuring mobi path
											console.log('Converter > Error ensoring mobi folder');

											self.remove(0);

											// after converted to mobi, keep convert
											self.convertBook();

										}

									});

									// keep convert

								}, function (err) {

									// err when converting to epub

									console.error("Converter > Failed to generate Ebook because of ", err);

									taskList[0].callback(err,null);

									// err

									self.remove(0);

									console.log('Converter > Error when converting:', err);

									// keep convert

									self.convertBook();
								});

							} catch (err){

								// caught error when converting to epub

								console.log('Converter > Error when converting:', err );

								console.log('Converter > Will ignore current task and move on.');

								// err

								self.remove(0);

								// keep convert

								self.convertBook();
							}

                        } else {

                            // error when ensure /epub/ dir

                            taskList[0].callback(err,null);

                            // err

                            self.remove(0);

                            console.log('Converter > Error when converting:', err);

                            // keep convert

                            self.convertBook();

                        }

                    })

                } else {

                    // Error parse the book

                    taskList[0].callback(err,null);

                    // err

                    self.remove(0);

                    console.log('Converter > Error when reading file:', err);

                    // keep convert

                    self.convertBook();

                }

            });

        } else {

            console.log('Converter > No task to do or Converter is working.');

            if (status == READY) taskList = [];

            //self.saveTask();

        }

    }

    this.readBook = function(cid, bookInfo, callback) {

        var cid = cid;
        var chapters = [];
        var title = bookInfo.chapters[cid].title.replace('\r\n', '');
        var file = path + bookInfo.id + '/txt/' + bookInfo.chapters[cid].vid + '.txt';

        // open file

        console.log('Converter > Reading local file:', file);

        fs.readFile(file, function(err, data) {

            if (!err) {

                // file opened

                console.log('Converter > Parsing Book.');

                // parse the book/chapters

                var book = String(data).replace('undefined', '').split(title);
                var chapters = [];

                // remove the first chapter : ★☆★☆★☆轻小说文库(Www.WenKu8.com)☆★☆★☆★
                book.splice(0, 1);

                book.forEach(function(element, index, array) {

                    var ctitle = element.substr(1, element.indexOf('\r\n', 1)).replace('\r', '');
                    var cdata = element.substr(element.indexOf('\r\n', 1), element.length).replace(/(\r\n|\n|\r)/g, '
');

                    chapters.push({
                        id: index,
                        title: ctitle,
                        content: cdata
                    });

                });

                callback(err, chapters);

            } else {

                console.log('Conveter > Err opening file', file);

                callback(err, null);

                self.remove(0);
            }

        });

    };

    this.remove = function(id) {

        if (taskList[id])
            taskList.splice(id, 1);
        status = READY;

        self.saveTask();

        // empty the temp files

        if (tempCleanCount >= maxTempCleanCount) {

            fs.emptyDir(tempEpudPath, function (err) {
                if (!err) console.log('Converter > Clean temp file successful!')
            });

            tempCleanCount = 0;

        } else {

            tempCleanCount++;
        }

    }

    this.saveTask = function() {

        console.log('Converter > Saving tasks..');

        fs.outputJson(taskPath, taskList, function(err) {

            if (!err) {

                console.log('Converter > Task list saved.');

            } else {

                console.log('Converter > Task list save failed.');
            }

        });
    }

    this.getTaskNum = function () {

        return taskList.length;

    }

}

// export module
module.exports = new converter();
<|endoftext|>