<commit_before>
/**
 * Module dependencies.
 */

var citizen = require('citizen');
var config = require('config');
var o = require('dom');
var markdown = require('marked');
var request = require('request');
var template = require('./template');
var CommentsEditView = require('comments-edit');
var CommentsRepliesView = require('comments-replies');
var View = require('view');
var t = require('t');
var log = require('debug')('democracyos:comments-view');
var CommentVote = require('comment-vote');

/**
 * Expose CommentCard
 */

module.exports = CommentCard;

/**
 * Create CommentCard
 */

function CommentCard(comment) {
  if (!(this instanceof CommentCard)) {
    return new CommentCard(comment);
  }

  this.comment = comment;
  this.setLocals();
  View.call(this, template, this.locals);

  this.initializeVote();
  this.editButton = this.find('.btn-edit');
  this.scoreCounter = this.find('.comment-counter');
  this.mediaBody = this.find('.media-body');
}

View(CommentCard);

CommentCard.prototype.switchOn = function() {
  this.bind('click', '.link-report', 'onflag');
  this.bind('click', '.btn-edit', 'onedit');
  this.bind('click', '.btn-remove', 'onremove');
  this.bind('click', 'a.cancel-remove', 'oncancelremove');
  this.bind('click', 'a.confirm-remove', 'onconfirmremove');
  this.bind('click', 'span.show-spam a', 'onshowspam');
  this.bind('click', 'a.comment-reply', 'onreplyclick');
};

CommentCard.prototype.switchOff = function() {
  if (this.commentsRepliesView) {
    this.commentsRepliesView.off('post', this.bound('newreply'));
    this.commentsRepliesView.off('remove', this.bound('removereply'));
  }
};

CommentCard.prototype.setLocals = function () {
  var locals = {};
  var comment = locals.comment = this.comment;
  locals.markdown = markdown;
  locals.flags = !!~comment.flags.map(function(v) { return v.author; }).indexOf(citizen.id);
  locals.own = comment.author.id == citizen.id;
  locals.repliesCounter = comment.replies.length;
  if (config['spam limit']) {
    locals.spam = comment.flags.length > config['spam limit'];
  } else {
    locals.spam = comment.flags.length > (comment.upvotes.length - comment.downvotes.length);
  }
  locals.profilePictureUrl = comment.author.profilePictureUrl ? comment.author.profilePictureUrl : comment.author.gravatar;
  locals.classes = [];
  if (locals.own) locals.classes.push('own');
  if (locals.spam) locals.classes.push('spam');
  this.locals = locals;
};

CommentCard.prototype.initializeVote = function () {
  this.commentVote = new CommentVote(this.comment);
  this.el.find('.comment-actions').prepend(this.commentVote.render());
  this.commentVote.on('error', this.bound('voteerror'));
};

CommentCard.prototype.voteerror = function (message) {
  message = message || '';
  this.find('.error').html(message);
};

CommentCard.prototype.onflag = function(ev) {
  ev.preventDefault();

  var comment = this.comment;
  var target = this.find('.link-report');
  var isSpam = this.locals.spam;
  var flagging = !this.locals.flags;

  target.toggleClass('selected');
  flagging ? target.attr('title', t('Not spam')) : target.attr('title', t('Spam'));
  var flagsCounter = comment.flags.length + (flagging ? 1 : -1);
  var spam;
  if (config['spam limit']) {
    spam = flagsCounter > config['spam limit'];
  } else {
    spam = flagsCounter > (comment.upvotes.length - comment.downvotes.length)
  }
  if (spam) {
    this.el.addClass('spam');
  } else {
    this.el.removeClass('spam');
  }

  var self = this;
  request
  .post(this.url() + '/:action'.replace(':action', flagging ? 'flag' : 'unflag'))
  .end(function(err, res) {
    if (err) return handleError(err);
    if (!res.ok) return handleError(res.error);
    if (res.body && res.body.error) return handleError(res.body.error);

    log('successfull %s as spam %s', flagging ? 'flag' : 'unflag', self.comment.id);
    var count = target.find('.count');
    var innerCount = count.html() != '' ? parseInt(count.html()) : 0;
    innerCount += (flagging ? 1 : -1)
    count.html(innerCount ? innerCount : '');
    self.locals.flags = flagging;

    function handleError(error) {
      log('Fetch response error: %s', error)
      if (flagging) self.el.removeClass('spam');
      return target.removeClass('selected');
    }
  });
}

CommentCard.prototype.onshowspam = function(ev) {
  ev.preventDefault();

  this.el.removeClass('spam');
}

CommentCard.prototype.onedit = function(ev) {
  ev.preventDefault();

  this.find('a.btn-edit').addClass('hide');
  var form = this.mediaBody.find('form');

  if (!form.length) {
    var commentsEdit = this.commentsEdit = new CommentsEditView(this.comment);
    commentsEdit.render(this.mediaBody[0]);
    commentsEdit.on('put', this.onsuccessedit.bind(this));
    commentsEdit.on('off', this.oncanceledit.bind(this));
  }

  this.mediaBody.addClass('edit');
};

CommentCard.prototype.oncanceledit = function(el) {
  this.mediaBody.removeClass('edit');
  this.find('.btn-edit').removeClass('hide');
  el.parentNode.removeChild(el);
};

CommentCard.prototype.onsuccessedit = function(data) {
  var el = data.el;
  var data = data.data;
  var commentText = this.find('.comment-text');
  var commentTime = this.find('.ago')[0];
  var edited = this.find('.edited');

  commentText.html(markdown(data.text));

  if (!edited.length) {
    var small = o('');
    small.addClass('edited');
    small.html(' · ' + t('comments.edited'));
    commentTime.parentNode.insertBefore(small.els[0], commentTime.nextSibling);
  }

  this.find('.btn-edit').removeClass('hide');
  this.mediaBody.removeClass('edit');
  o(el).remove();

  this.comment.text = data.text;
  this.comment.editedAt = data.editedAt;
};

CommentCard.prototype.onremove = function(ev) {
  ev.preventDefault();

  this.el.addClass('remove');
  this.editButton.removeClass('hide');
  this.mediaBody.removeClass('edit');
};

CommentCard.prototype.oncancelremove = function(ev) {
  ev.preventDefault();

  this.el.removeClass('remove');
};

/**
 * Confirm comment removal
 *
 * @param {Event} ev
 * @api private
 */

CommentCard.prototype.onconfirmremove = function(ev) {
  ev.preventDefault();

  var comment = this.comment;
  var author = comment.author;
  var own = author.id == citizen.id;
  var self = this;
  var id = comment.id;

  request
    .del(this.url())
    .end(function(err, res) {
      if (err) return log('Fetch error: %s', err);
      if (!res.ok) err = res.error, log('Fetch error: %s', err);
      if (res.body && res.body.error) err = res.body.error, log('Fetch response error: %s', err);

      self.el.removeClass('remove');
      var messageEl = self.find('.oncomment.message');
      messageEl.css('display', 'block');
      if (err) {
        messageEl.html(err);
      } else {
        log('successfull upvote %s', id);
        messageEl.html(t('comments.removed'));
        setTimeout(function () {
          self.el.remove();
          self.emit('delete', self.comment);
        }, 2500);
      }
  });
};

/**
 * Show comment replies
 */

CommentCard.prototype.onreplyclick = function(ev) {
  ev.preventDefault();

  var target = this.find('a.reply-comments');
  var repliesContainer = this.find('.replies-container');
  repliesContainer.empty().toggleClass('no-hide');
  if (repliesContainer.hasClass('no-hide')) {
    var commentsRepliesView = this.commentsRepliesView = new CommentsRepliesView(this.comment);
    commentsRepliesView.render(repliesContainer[0]);
    commentsRepliesView.on('post', this.bound('newreply'));
    commentsRepliesView.on('remove', this.bound('removereply'));
  }
}

/**
 * New reply submitted
 */

CommentCard.prototype.newreply = function(reply) {
  var replyCounter = this.find('.reply-counter');
  var counter = replyCounter.html() != '' ? parseInt(replyCounter.html()) : 0;
  this.find('.comment-action.btn-remove').addClass('hide');
  counter++;
  replyCounter.html(counter);
}

/**
 * Reply deleted
 */

CommentCard.prototype.removereply = function(data) {
  var replyCounter = this.find('.reply-counter');
  var counter = replyCounter.html() != '' ? parseInt(replyCounter.html()) : 0;
  var btnRemove = this.find('.comment-action.btn-remove');
  counter--;
  if (counter == 0) {
    btnRemove.removeClass('hide');
    replyCounter.html('');
  } else {
    replyCounter.html(counter);
  }
}

CommentCard.prototype.url = function() {
  return '/api/comment/:id'.replace(':id', this.comment.id);
};<commit_msg>[comment-vote] - Update code styling, variable and function names, etc. Remove unnecesary dependencies #471<commit_after>
/**
 * Module dependencies.
 */

var citizen = require('citizen');
var config = require('config');
var o = require('dom');
var markdown = require('marked');
var request = require('request');
var template = require('./template');
var CommentsEditView = require('comments-edit');
var CommentsRepliesView = require('comments-replies');
var View = require('view');
var t = require('t');
var log = require('debug')('democracyos:comments-view');
var CommentVote = require('comment-vote');

/**
 * Expose CommentCard
 */

module.exports = CommentCard;

/**
 * Create CommentCard
 */

function CommentCard(comment) {
  if (!(this instanceof CommentCard)) {
    return new CommentCard(comment);
  }

  this.comment = comment;
  this.setLocals();
  View.call(this, template, this.locals);

  this.initializeVote();
  this.editButton = this.find('.btn-edit');
  this.scoreCounter = this.find('.comment-counter');
  this.mediaBody = this.find('.media-body');
}

View(CommentCard);

CommentCard.prototype.switchOn = function() {
  this.bind('click', '.link-report', 'onflag');
  this.bind('click', '.btn-edit', 'onedit');
  this.bind('click', '.btn-remove', 'onremove');
  this.bind('click', 'a.cancel-remove', 'oncancelremove');
  this.bind('click', 'a.confirm-remove', 'onconfirmremove');
  this.bind('click', 'span.show-spam a', 'onshowspam');
  this.bind('click', 'a.comment-reply', 'onreplyclick');
};

CommentCard.prototype.switchOff = function() {
  if (this.commentsRepliesView) {
    this.commentsRepliesView.off('post', this.bound('newreply'));
    this.commentsRepliesView.off('remove', this.bound('removereply'));
  }
};

CommentCard.prototype.setLocals = function () {
  var locals = {};
  var comment = locals.comment = this.comment;
  locals.markdown = markdown;
  locals.flags = !!~comment.flags.map(function(v) { return v.author; }).indexOf(citizen.id);
  locals.own = comment.author.id == citizen.id;
  locals.repliesCounter = comment.replies.length;
  if (config['spam limit']) {
    locals.spam = comment.flags.length > config['spam limit'];
  } else {
    locals.spam = comment.flags.length > (comment.upvotes.length - comment.downvotes.length);
  }
  locals.profilePictureUrl = comment.author.profilePictureUrl ? comment.author.profilePictureUrl : comment.author.gravatar;
  locals.classes = [];
  if (locals.own) locals.classes.push('own');
  if (locals.spam) locals.classes.push('spam');
  this.locals = locals;
};

CommentCard.prototype.initializeVote = function () {
  this.commentVote = new CommentVote(this.comment);
  this.el.find('.comment-actions').prepend(this.commentVote.render());
  this.commentVote.on('error', this.bound('voteError'));
};

CommentCard.prototype.voteError = function (message) {
  message = message || '';
  this.find('.error').html(message);
};

CommentCard.prototype.onflag = function(ev) {
  ev.preventDefault();

  var comment = this.comment;
  var target = this.find('.link-report');
  var isSpam = this.locals.spam;
  var flagging = !this.locals.flags;

  target.toggleClass('selected');
  flagging ? target.attr('title', t('Not spam')) : target.attr('title', t('Spam'));
  var flagsCounter = comment.flags.length + (flagging ? 1 : -1);
  var spam;
  if (config['spam limit']) {
    spam = flagsCounter > config['spam limit'];
  } else {
    spam = flagsCounter > (comment.upvotes.length - comment.downvotes.length)
  }
  if (spam) {
    this.el.addClass('spam');
  } else {
    this.el.removeClass('spam');
  }

  var self = this;
  request
  .post(this.url() + '/:action'.replace(':action', flagging ? 'flag' : 'unflag'))
  .end(function(err, res) {
    if (err) return handleError(err);
    if (!res.ok) return handleError(res.error);
    if (res.body && res.body.error) return handleError(res.body.error);

    log('successfull %s as spam %s', flagging ? 'flag' : 'unflag', self.comment.id);
    var count = target.find('.count');
    var innerCount = count.html() != '' ? parseInt(count.html()) : 0;
    innerCount += (flagging ? 1 : -1)
    count.html(innerCount ? innerCount : '');
    self.locals.flags = flagging;

    function handleError(error) {
      log('Fetch response error: %s', error)
      if (flagging) self.el.removeClass('spam');
      return target.removeClass('selected');
    }
  });
}

CommentCard.prototype.onshowspam = function(ev) {
  ev.preventDefault();

  this.el.removeClass('spam');
}

CommentCard.prototype.onedit = function(ev) {
  ev.preventDefault();

  this.find('a.btn-edit').addClass('hide');
  var form = this.mediaBody.find('form');

  if (!form.length) {
    var commentsEdit = this.commentsEdit = new CommentsEditView(this.comment);
    commentsEdit.render(this.mediaBody[0]);
    commentsEdit.on('put', this.onsuccessedit.bind(this));
    commentsEdit.on('off', this.oncanceledit.bind(this));
  }

  this.mediaBody.addClass('edit');
};

CommentCard.prototype.oncanceledit = function(el) {
  this.mediaBody.removeClass('edit');
  this.find('.btn-edit').removeClass('hide');
  el.parentNode.removeChild(el);
};

CommentCard.prototype.onsuccessedit = function(data) {
  var el = data.el;
  var data = data.data;
  var commentText = this.find('.comment-text');
  var commentTime = this.find('.ago')[0];
  var edited = this.find('.edited');

  commentText.html(markdown(data.text));

  if (!edited.length) {
    var small = o('');
    small.addClass('edited');
    small.html(' · ' + t('comments.edited'));
    commentTime.parentNode.insertBefore(small.els[0], commentTime.nextSibling);
  }

  this.find('.btn-edit').removeClass('hide');
  this.mediaBody.removeClass('edit');
  o(el).remove();

  this.comment.text = data.text;
  this.comment.editedAt = data.editedAt;
};

CommentCard.prototype.onremove = function(ev) {
  ev.preventDefault();

  this.el.addClass('remove');
  this.editButton.removeClass('hide');
  this.mediaBody.removeClass('edit');
};

CommentCard.prototype.oncancelremove = function(ev) {
  ev.preventDefault();

  this.el.removeClass('remove');
};

/**
 * Confirm comment removal
 *
 * @param {Event} ev
 * @api private
 */

CommentCard.prototype.onconfirmremove = function(ev) {
  ev.preventDefault();

  var comment = this.comment;
  var author = comment.author;
  var own = author.id == citizen.id;
  var self = this;
  var id = comment.id;

  request
    .del(this.url())
    .end(function(err, res) {
      if (err) return log('Fetch error: %s', err);
      if (!res.ok) err = res.error, log('Fetch error: %s', err);
      if (res.body && res.body.error) err = res.body.error, log('Fetch response error: %s', err);

      self.el.removeClass('remove');
      var messageEl = self.find('.oncomment.message');
      messageEl.css('display', 'block');
      if (err) {
        messageEl.html(err);
      } else {
        log('successfull upvote %s', id);
        messageEl.html(t('comments.removed'));
        setTimeout(function () {
          self.el.remove();
          self.emit('delete', self.comment);
        }, 2500);
      }
  });
};

/**
 * Show comment replies
 */

CommentCard.prototype.onreplyclick = function(ev) {
  ev.preventDefault();

  var target = this.find('a.reply-comments');
  var repliesContainer = this.find('.replies-container');
  repliesContainer.empty().toggleClass('no-hide');
  if (repliesContainer.hasClass('no-hide')) {
    var commentsRepliesView = this.commentsRepliesView = new CommentsRepliesView(this.comment);
    commentsRepliesView.render(repliesContainer[0]);
    commentsRepliesView.on('post', this.bound('newreply'));
    commentsRepliesView.on('remove', this.bound('removereply'));
  }
}

/**
 * New reply submitted
 */

CommentCard.prototype.newreply = function(reply) {
  var replyCounter = this.find('.reply-counter');
  var counter = replyCounter.html() != '' ? parseInt(replyCounter.html()) : 0;
  this.find('.comment-action.btn-remove').addClass('hide');
  counter++;
  replyCounter.html(counter);
}

/**
 * Reply deleted
 */

CommentCard.prototype.removereply = function(data) {
  var replyCounter = this.find('.reply-counter');
  var counter = replyCounter.html() != '' ? parseInt(replyCounter.html()) : 0;
  var btnRemove = this.find('.comment-action.btn-remove');
  counter--;
  if (counter == 0) {
    btnRemove.removeClass('hide');
    replyCounter.html('');
  } else {
    replyCounter.html(counter);
  }
}

CommentCard.prototype.url = function() {
  return '/api/comment/:id'.replace(':id', this.comment.id);
};<|endoftext|>


<commit_before>var geo = require('../geo');
var utils = require('../utils');

exports.initialize = function initializeSchema(dataSource, callback) {
    dataSource.connector = new Memory();
    dataSource.connector.connect(callback);
};

exports.Memory = Memory;

function Memory(m) {
    if (m) {
        this.isTransaction = true;
        this.cache = m.cache;
        this.ids = m.ids;
        this._models = m._models;
    } else {
        this.isTransaction = false;
        this.cache = {};
        this.ids = {};
        this._models = {};
    }
}

Memory.prototype.connect = function(callback) {
    if (this.isTransaction) {
        this.onTransactionExec = callback;
    } else {
        process.nextTick(callback);
    }
};

Memory.prototype.define = function defineModel(descr) {
    var m = descr.model.modelName;
    this._models[m] = descr;
    this.cache[m] = {};
    this.ids[m] = 1;
};

/**
 * Get the id property name for the given model
 * @param {String} model The model name
 * @returns {String} The id property name
 *
 * @private
 */
Memory.prototype.idName = function(model) {
    return (this.dataSource && this.dataSource.idName && this.dataSource.idName(model)) || 'id';
};

/**
 * Get the id value for the given model
 * @param {String} model The model name
 * @param {Object} data The model instance data
 * @returns {*} The id value
 *
 * @private
 */
Memory.prototype.getIdValue = function(model, data) {
    return data && data[this.idName(model)];
};

/**
 * Set the id value for the given model
 * @param {String} model The model name
 * @param {Object} data The model instance data
 * @param {*} value The id value
 *
 * @private
 */
Memory.prototype.setIdValue = function(model, data, value) {
    if(data) {
        data[this.idName(model)] = value;
    }
};

Memory.prototype.create = function create(model, data, callback) {
    // FIXME: [rfeng] We need to generate unique ids based on the id type
    // FIXME: [rfeng] We don't support composite ids yet
    var currentId = this.ids[model];
    if(currentId === undefined) {
        // First time
        this.ids[model] = 1;
        currentId = 1;
    }
    var id = this.getIdValue(model, data) || currentId;
    if(id > currentId) {
        // If the id is passed in and the value is greater than the current id
        currentId = id;
    }
    this.ids[model] = Number(currentId) + 1;

    var props = this._models[model].properties;
    id = props[this.idName(model)].type(id);
    this.setIdValue(model, data, id);
    this.cache[model][id] = JSON.stringify(data);
    process.nextTick(function() {
        callback(null, id);
    });
};

Memory.prototype.updateOrCreate = function (model, data, callback) {
    var self = this;
    this.exists(model, self.getIdValue(model, data), function (err, exists) {
        if (exists) {
            self.save(model, data, callback);
        } else {
            self.create(model, data, function (err, id) {
                self.setIdValue(model, data, id);
                callback(err, data);
            });
        }
    });
};

Memory.prototype.save = function save(model, data, callback) {
    this.cache[model][this.getIdValue(model, data)] = JSON.stringify(data);
    process.nextTick(function () {
        callback(null, data);
    });
};

Memory.prototype.exists = function exists(model, id, callback) {
    process.nextTick(function () {
        callback(null, this.cache[model] && this.cache[model].hasOwnProperty(id));
    }.bind(this));
};

Memory.prototype.find = function find(model, id, callback) {
    var self = this;
    process.nextTick(function () {
        callback(null, id in this.cache[model] && this.fromDb(model, this.cache[model][id]));
    }.bind(this));
};

Memory.prototype.destroy = function destroy(model, id, callback) {
    delete this.cache[model][id];
    process.nextTick(callback);
};

Memory.prototype.fromDb = function(model, data) {
    if (!data) return null;
    data = JSON.parse(data);
    var props = this._models[model].properties;
    Object.keys(data).forEach(function (key) {
        var val = data[key];
        if (typeof val === 'undefined' || val === null) {
            return;
        }
        if (props[key]) {
            switch(props[key].type.name) {
                case 'Date':
                    val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));
                    break;
                case 'Boolean':
                    val = Boolean(val);
                    break;
                case 'Number':
                    val = Number(val);
                    break;
            }
        }
        data[key] = val;
    });
    return data;
};

Memory.prototype.all = function all(model, filter, callback) {
    var self = this;
    var nodes = Object.keys(this.cache[model]).map(function (key) {
        return this.fromDb(model, this.cache[model][key]);
    }.bind(this));

    if (filter) {
        // do we need some sorting?
        if (filter.order) {
            var orders = filter.order;
            if (typeof filter.order === "string") {
                orders = [filter.order];
            }
            orders.forEach(function (key, i) {
                var reverse = 1;
                var m = key.match(/\s+(A|DE)SC$/i);
                if (m) {
                    key = key.replace(/\s+(A|DE)SC/i, '');
                    if (m[1].toLowerCase() === 'de') reverse = -1;
                }
                orders[i] = {"key": key, "reverse": reverse};
            });
            nodes = nodes.sort(sorting.bind(orders));
        }

        var nearFilter = geo.nearFilter(filter.where);

        // geo sorting
        if(nearFilter) {
            nodes = geo.filter(nodes, nearFilter);
        }

        // do we need some filtration?
        if (filter.where) {
            nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
        }

        // field selection
        if(filter.fields) {
            nodes = nodes.map(utils.selectFields(filter.fields));
        }

        // limit/skip
        filter.skip = filter.skip || 0;
        filter.limit = filter.limit || nodes.length;
        nodes = nodes.slice(filter.skip, filter.skip + filter.limit);
    }

    process.nextTick(function () {
        if (filter && filter.include) {
            self._models[model].model.include(nodes, filter.include, callback);
        } else {
            callback(null, nodes);
        }
    });

    function sorting(a, b) {
        for (var i=0, l=this.length; i<l; i++) {
            if (a[this[i].key] > b[this[i].key]) {
                return 1*this[i].reverse;
            } else  if (a[this[i].key] < b[this[i].key]) {
                return -1*this[i].reverse;
            }
        }
        return 0;
    }
};

function applyFilter(filter) {
    if (typeof filter.where === 'function') {
        return filter.where;
    }
    var keys = Object.keys(filter.where);
    return function (obj) {
        var pass = true;
        keys.forEach(function (key) {
            if (!test(filter.where[key], obj[key])) {
                pass = false;
            }
        });
        return pass;
    }

    function test(example, value) {
        if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
            return value.match(example);
        }
        if (typeof example === 'undefined') return undefined;
        if (typeof value === 'undefined') return undefined;
        if (typeof example === 'object') {
            // ignore geo near filter
            if(example.near) return true;

            if (example.inq) {
                if (!value) return false;
                for (var i = 0; i < example.inq.length; i += 1) {
                    if (example.inq[i] == value) return true;
                }
                return false;
            }

            if(isNum(example.gt) && example.gt < value) return true;
            if(isNum(example.gte) && example.gte <= value) return true;
            if(isNum(example.lt) && example.lt > value) return true;
            if(isNum(example.lte) && example.lte >= value) return true;
        }
        // not strict equality
        return (example !== null ? example.toString() : example) == (value !== null ? value.toString() : value);
    }

    function isNum(n) {
        return typeof n === 'number';
    }
}

Memory.prototype.destroyAll = function destroyAll(model, where, callback) {
    if(!callback && 'function' === typeof where) {
        callback = where;
        where = undefined;
    }
    var cache = this.cache[model];
    var filter = null;
    if (where) {
        filter = applyFilter({where: where});
    }
    Object.keys(cache).forEach(function (id) {
        if(!filter || filter(this.fromDb(model, cache[id]))) {
            delete cache[id];
        }
    }.bind(this));
    if(!where) {
        this.cache[model] = {};
    }
    process.nextTick(callback);
};

Memory.prototype.count = function count(model, callback, where) {
    var cache = this.cache[model];
    var data = Object.keys(cache);
    if (where) {
        var filter = {where: where};
        data = data.map(function (id) {
          return this.fromDb(model, cache[id]);
        }.bind(this));
        data = data.filter(applyFilter(filter));
    }
    process.nextTick(function () {
        callback(null, data.length);
    });
};

Memory.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
    if(!id) {
      var err = new Error('You must provide an id when updating attributes!');
      if(cb) {
        return cb(err);
      } else {
        throw err;
      }
    }

    this.setIdValue(model, data, id);

    var cachedModels = this.cache[model];
    var modelAsString = cachedModels && this.cache[model][id];
    var modelData = modelAsString && JSON.parse(modelAsString);

    if(modelData) {
      this.save(model, merge(modelData, data), cb);
    } else {
      cb(new Error('Could not update attributes. Object with id ' + id + ' does not exist!'));
    }
};

Memory.prototype.transaction = function () {
    return new Memory(this);
};

Memory.prototype.exec = function(callback) {
    this.onTransactionExec();
    setTimeout(callback, 50);
};

Memory.prototype.buildNearFilter = function (filter) {
  // noop
}

function merge(base, update) {
    if (!base) return update;
    Object.keys(update).forEach(function (key) {
        base[key] = update[key];
    });
    return base;
}<commit_msg>Check the existence of id<commit_after>var geo = require('../geo');
var utils = require('../utils');

exports.initialize = function initializeSchema(dataSource, callback) {
    dataSource.connector = new Memory();
    dataSource.connector.connect(callback);
};

exports.Memory = Memory;

function Memory(m) {
    if (m) {
        this.isTransaction = true;
        this.cache = m.cache;
        this.ids = m.ids;
        this._models = m._models;
    } else {
        this.isTransaction = false;
        this.cache = {};
        this.ids = {};
        this._models = {};
    }
}

Memory.prototype.connect = function(callback) {
    if (this.isTransaction) {
        this.onTransactionExec = callback;
    } else {
        process.nextTick(callback);
    }
};

Memory.prototype.define = function defineModel(descr) {
    var m = descr.model.modelName;
    this._models[m] = descr;
    this.cache[m] = {};
    this.ids[m] = 1;
};

/**
 * Get the id property name for the given model
 * @param {String} model The model name
 * @returns {String} The id property name
 *
 * @private
 */
Memory.prototype.idName = function(model) {
    return (this.dataSource && this.dataSource.idName && this.dataSource.idName(model)) || 'id';
};

/**
 * Get the id value for the given model
 * @param {String} model The model name
 * @param {Object} data The model instance data
 * @returns {*} The id value
 *
 * @private
 */
Memory.prototype.getIdValue = function(model, data) {
    return data && data[this.idName(model)];
};

/**
 * Set the id value for the given model
 * @param {String} model The model name
 * @param {Object} data The model instance data
 * @param {*} value The id value
 *
 * @private
 */
Memory.prototype.setIdValue = function(model, data, value) {
    if(data) {
        data[this.idName(model)] = value;
    }
};

Memory.prototype.create = function create(model, data, callback) {
    // FIXME: [rfeng] We need to generate unique ids based on the id type
    // FIXME: [rfeng] We don't support composite ids yet
    var currentId = this.ids[model];
    if(currentId === undefined) {
        // First time
        this.ids[model] = 1;
        currentId = 1;
    }
    var id = this.getIdValue(model, data) || currentId;
    if(id > currentId) {
        // If the id is passed in and the value is greater than the current id
        currentId = id;
    }
    this.ids[model] = Number(currentId) + 1;

    var props = this._models[model].properties;
    var idName = this.idName(model);
    id = (props[idName] && props[idName].type && props[idName].type(id)) || id;
    this.setIdValue(model, data, id);
    this.cache[model][id] = JSON.stringify(data);
    process.nextTick(function() {
        callback(null, id);
    });
};

Memory.prototype.updateOrCreate = function (model, data, callback) {
    var self = this;
    this.exists(model, self.getIdValue(model, data), function (err, exists) {
        if (exists) {
            self.save(model, data, callback);
        } else {
            self.create(model, data, function (err, id) {
                self.setIdValue(model, data, id);
                callback(err, data);
            });
        }
    });
};

Memory.prototype.save = function save(model, data, callback) {
    this.cache[model][this.getIdValue(model, data)] = JSON.stringify(data);
    process.nextTick(function () {
        callback(null, data);
    });
};

Memory.prototype.exists = function exists(model, id, callback) {
    process.nextTick(function () {
        callback(null, this.cache[model] && this.cache[model].hasOwnProperty(id));
    }.bind(this));
};

Memory.prototype.find = function find(model, id, callback) {
    var self = this;
    process.nextTick(function () {
        callback(null, id in this.cache[model] && this.fromDb(model, this.cache[model][id]));
    }.bind(this));
};

Memory.prototype.destroy = function destroy(model, id, callback) {
    delete this.cache[model][id];
    process.nextTick(callback);
};

Memory.prototype.fromDb = function(model, data) {
    if (!data) return null;
    data = JSON.parse(data);
    var props = this._models[model].properties;
    Object.keys(data).forEach(function (key) {
        var val = data[key];
        if (typeof val === 'undefined' || val === null) {
            return;
        }
        if (props[key]) {
            switch(props[key].type.name) {
                case 'Date':
                    val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));
                    break;
                case 'Boolean':
                    val = Boolean(val);
                    break;
                case 'Number':
                    val = Number(val);
                    break;
            }
        }
        data[key] = val;
    });
    return data;
};

Memory.prototype.all = function all(model, filter, callback) {
    var self = this;
    var nodes = Object.keys(this.cache[model]).map(function (key) {
        return this.fromDb(model, this.cache[model][key]);
    }.bind(this));

    if (filter) {
        // do we need some sorting?
        if (filter.order) {
            var orders = filter.order;
            if (typeof filter.order === "string") {
                orders = [filter.order];
            }
            orders.forEach(function (key, i) {
                var reverse = 1;
                var m = key.match(/\s+(A|DE)SC$/i);
                if (m) {
                    key = key.replace(/\s+(A|DE)SC/i, '');
                    if (m[1].toLowerCase() === 'de') reverse = -1;
                }
                orders[i] = {"key": key, "reverse": reverse};
            });
            nodes = nodes.sort(sorting.bind(orders));
        }

        var nearFilter = geo.nearFilter(filter.where);

        // geo sorting
        if(nearFilter) {
            nodes = geo.filter(nodes, nearFilter);
        }

        // do we need some filtration?
        if (filter.where) {
            nodes = nodes ? nodes.filter(applyFilter(filter)) : nodes;
        }

        // field selection
        if(filter.fields) {
            nodes = nodes.map(utils.selectFields(filter.fields));
        }

        // limit/skip
        filter.skip = filter.skip || 0;
        filter.limit = filter.limit || nodes.length;
        nodes = nodes.slice(filter.skip, filter.skip + filter.limit);
    }

    process.nextTick(function () {
        if (filter && filter.include) {
            self._models[model].model.include(nodes, filter.include, callback);
        } else {
            callback(null, nodes);
        }
    });

    function sorting(a, b) {
        for (var i=0, l=this.length; i<l; i++) {
            if (a[this[i].key] > b[this[i].key]) {
                return 1*this[i].reverse;
            } else  if (a[this[i].key] < b[this[i].key]) {
                return -1*this[i].reverse;
            }
        }
        return 0;
    }
};

function applyFilter(filter) {
    if (typeof filter.where === 'function') {
        return filter.where;
    }
    var keys = Object.keys(filter.where);
    return function (obj) {
        var pass = true;
        keys.forEach(function (key) {
            if (!test(filter.where[key], obj[key])) {
                pass = false;
            }
        });
        return pass;
    }

    function test(example, value) {
        if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
            return value.match(example);
        }
        if (typeof example === 'undefined') return undefined;
        if (typeof value === 'undefined') return undefined;
        if (typeof example === 'object') {
            // ignore geo near filter
            if(example.near) return true;

            if (example.inq) {
                if (!value) return false;
                for (var i = 0; i < example.inq.length; i += 1) {
                    if (example.inq[i] == value) return true;
                }
                return false;
            }

            if(isNum(example.gt) && example.gt < value) return true;
            if(isNum(example.gte) && example.gte <= value) return true;
            if(isNum(example.lt) && example.lt > value) return true;
            if(isNum(example.lte) && example.lte >= value) return true;
        }
        // not strict equality
        return (example !== null ? example.toString() : example) == (value !== null ? value.toString() : value);
    }

    function isNum(n) {
        return typeof n === 'number';
    }
}

Memory.prototype.destroyAll = function destroyAll(model, where, callback) {
    if(!callback && 'function' === typeof where) {
        callback = where;
        where = undefined;
    }
    var cache = this.cache[model];
    var filter = null;
    if (where) {
        filter = applyFilter({where: where});
    }
    Object.keys(cache).forEach(function (id) {
        if(!filter || filter(this.fromDb(model, cache[id]))) {
            delete cache[id];
        }
    }.bind(this));
    if(!where) {
        this.cache[model] = {};
    }
    process.nextTick(callback);
};

Memory.prototype.count = function count(model, callback, where) {
    var cache = this.cache[model];
    var data = Object.keys(cache);
    if (where) {
        var filter = {where: where};
        data = data.map(function (id) {
          return this.fromDb(model, cache[id]);
        }.bind(this));
        data = data.filter(applyFilter(filter));
    }
    process.nextTick(function () {
        callback(null, data.length);
    });
};

Memory.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
    if(!id) {
      var err = new Error('You must provide an id when updating attributes!');
      if(cb) {
        return cb(err);
      } else {
        throw err;
      }
    }

    this.setIdValue(model, data, id);

    var cachedModels = this.cache[model];
    var modelAsString = cachedModels && this.cache[model][id];
    var modelData = modelAsString && JSON.parse(modelAsString);

    if(modelData) {
      this.save(model, merge(modelData, data), cb);
    } else {
      cb(new Error('Could not update attributes. Object with id ' + id + ' does not exist!'));
    }
};

Memory.prototype.transaction = function () {
    return new Memory(this);
};

Memory.prototype.exec = function(callback) {
    this.onTransactionExec();
    setTimeout(callback, 50);
};

Memory.prototype.buildNearFilter = function (filter) {
  // noop
}

function merge(base, update) {
    if (!base) return update;
    Object.keys(update).forEach(function (key) {
        base[key] = update[key];
    });
    return base;
}<|endoftext|>


<commit_before>const {Disposable, Emitter, CompositeDisposable} = require("atom")
const globalState = require("./global-state")
const VimState = require("./vim-state")
const Base = require("./base")

module.exports = class DemoModeSupport {
  constructor({onWillAddItem, onDidStart, onDidStop, onWillFadeoutHover, onDidRemoveHover}) {
    this.disposables = new CompositeDisposable(
      onDidStart(() => globalState.set("demoModeIsActive", true)),
      onDidStop(() => globalState.set("demoModeIsActive", false)),
      onDidRemoveHover(this.destroyAllDemoModeFlasheMarkers.bind(this)),
      onWillFadeoutHover(this.destroyAllDemoModeFlasheMarkers.bind(this)),
      onWillAddItem(({item, event}) => {
        if (event.binding.command.startsWith("vim-mode-plus:")) {
          const commandElement = item.getElementsByClassName("command")[0]
          commandElement.textContent = commandElement.textContent.replace(/^vim-mode-plus:/, "")
        }
        const element = document.createElement("span")
        element.classList.add("kind", "pull-right")
        element.textContent = this.getKindForCommand(event.binding.command)
        item.appendChild(element)
      })
    )
  }

  destroyAllDemoModeFlasheMarkers() {
    VimState.forEach(vimState => vimState.flashManager.destroyDemoModeMarkers())
  }

  destroy() {
    this.disposables.dispose()
  }

  getKindForCommand(command) {
    if (command.startsWith("vim-mode-plus")) {
      return command.startsWith("vim-mode-plus:operator-modifier")
        ? "op-modifier"
        : Base.getKindForCommandName(command) || "vmp-other"
    } else {
      return "non-vmp"
    }
  }
}
<commit_msg>DRY bind<commit_after>const {Disposable, Emitter, CompositeDisposable} = require("atom")
const globalState = require("./global-state")
const VimState = require("./vim-state")
const Base = require("./base")

module.exports = class DemoModeSupport {
  constructor({onWillAddItem, onDidStart, onDidStop, onWillFadeoutHover, onDidRemoveHover}) {
    destroyAllDemoModeFlasheMarkers = this.destroyAllDemoModeFlasheMarkers.bind(this)

    this.disposables = new CompositeDisposable(
      onDidStart(() => globalState.set("demoModeIsActive", true)),
      onDidStop(() => globalState.set("demoModeIsActive", false)),
      onDidRemoveHover(destroyAllDemoModeFlasheMarkers),
      onWillFadeoutHover(destroyAllDemoModeFlasheMarkers),
      onWillAddItem(({item, event}) => {
        if (event.binding.command.startsWith("vim-mode-plus:")) {
          const commandElement = item.getElementsByClassName("command")[0]
          commandElement.textContent = commandElement.textContent.replace(/^vim-mode-plus:/, "")
        }
        const element = document.createElement("span")
        element.classList.add("kind", "pull-right")
        element.textContent = this.getKindForCommand(event.binding.command)
        item.appendChild(element)
      })
    )
  }

  destroyAllDemoModeFlasheMarkers() {
    VimState.forEach(vimState => vimState.flashManager.destroyDemoModeMarkers())
  }

  destroy() {
    this.disposables.dispose()
  }

  getKindForCommand(command) {
    if (command.startsWith("vim-mode-plus")) {
      return command.startsWith("vim-mode-plus:operator-modifier")
        ? "op-modifier"
        : Base.getKindForCommandName(command) || "vmp-other"
    } else {
      return "non-vmp"
    }
  }
}
<|endoftext|>


<commit_before>import {get} from 'lodash/object'
import {partialRight} from 'lodash/function'
import log from 'npmlog'
import fs from 'fs'
import errorBuffer from 'contentful-batch-libs/utils/error-buffer'

export default function dumpErrorBuffer (params, message = 'Additional errors were found') {
  const {destinationSpace, sourceSpace, errorLogFile} = params
  const loggedErrors = errorBuffer.drain()
  if (loggedErrors.length > 0) {
    const errors = loggedErrors.reduce(partialRight(logErrorsWithAppLinks, sourceSpace, destinationSpace), '')
    fs.writeFileSync(errorLogFile, errors)
    log.warn(message)
    log.warn(`Check ${errorLogFile} for details.`)
  }
}

function logErrorsWithAppLinks (accumulatedErrorStr, err, idx, loggedErrors, sourceSpace, destinationSpace) {
  const requestUri = get(err, 'request.uri')
  if (requestUri) {
    return accumulatedErrorStr +
      `Error ${idx + 1}:\n` +
      'in ' + parseEntityUrl(sourceSpace, destinationSpace, requestUri) +
      '\n' +
      JSON.stringify(err, null, '  ') +
      '\n\n'
  } else {
    return accumulatedErrorStr +
      `Error ${idx + 1}:\n` +
      JSON.stringify(err, null, '  ') +
      '\n\n'
  }
}

function parseEntityUrl (sourceSpace, destinationSpace, url) {
  return url.replace(/api.contentful/, 'app.contentful')
            .replace(/:443/, '')
            .replace(destinationSpace, sourceSpace)
            .split('/').splice(0, 7).join('/')
}
<commit_msg>feat(output): Improve output in case of unresolved links<commit_after>import {get} from 'lodash/object'
import {partialRight} from 'lodash/function'
import {find} from 'lodash/collection'
import log from 'npmlog'
import fs from 'fs'
import errorBuffer from 'contentful-batch-libs/utils/error-buffer'

export default function dumpErrorBuffer (params, message = 'Additional errors were found') {
  const {destinationSpace, sourceSpace, errorLogFile} = params
  const loggedErrors = errorBuffer.drain()
  if (loggedErrors.length > 0) {
    const errorOutputPrefix = additionalInfoForUnresolvedLinks(loggedErrors)
    const errors = loggedErrors.reduce(
      partialRight(logErrorsWithAppLinks, sourceSpace, destinationSpace),
      errorOutputPrefix || '')
    fs.writeFileSync(errorLogFile, errors)
    log.warn(message)
    log.warn(`Check ${errorLogFile} for details.`)
  }
}

function logErrorsWithAppLinks (accumulatedErrorStr, err, idx, loggedErrors, sourceSpace, destinationSpace) {
  const requestUri = get(err, 'request.uri')
  if (requestUri) {
    return accumulatedErrorStr +
      `Error ${idx + 1}:\n` +
      'in ' + parseEntityUrl(sourceSpace, destinationSpace, requestUri) +
      '\n' +
      JSON.stringify(err, null, '  ') +
      '\n\n'
  } else {
    return accumulatedErrorStr +
      `Error ${idx + 1}:\n` +
      JSON.stringify(err, null, '  ') +
      '\n\n'
  }
}

function parseEntityUrl (sourceSpace, destinationSpace, url) {
  return url.replace(/api.contentful/, 'app.contentful')
            .replace(/:443/, '')
            .replace(destinationSpace, sourceSpace)
            .split('/').splice(0, 7).join('/')
}

function additionalInfoForUnresolvedLinks (errors) {
  if (find(errors, {name: 'UnresolvedLinks'})) {
    return 'Unresolved links were found in your entries. See below for more details.\n' +
           'Look at https://github.com/contentful/contentful-link-cleaner if you\'d like ' +
           'a quicker way to fix all unresolved links in your space.\n\n'
  }
}
<|endoftext|>


<commit_before>'use babel';

import { CompositeDisposable, Point, Range } from 'atom';

export default class EditorController {
  constructor(editor) {
    this.editor = editor;

    this.updateView();

    this.cursorsSub = new CompositeDisposable();
    this.cursorsSub.add(this.editor.onDidAddCursor(() => {
      this.updateView();
    }));
    this.cursorsSub.add(this.editor.onDidRemoveCursor(() => {
      this.updateView();
    }));
    this.cursorsSub.add(this.editor.onDidChangeCursorPosition(event => {
      if (event.newBufferPosition.row !== event.oldBufferPosition.row) {
        this.updateView();
      }
    }));
    this.cursorsSub.add(this.editor.onDidStopChanging(() => {
      this.updateView();
    }));
  }

  isInTable() {
    // TODO: check grammar
    if (this.editor.hasMultipleCursors()) {
      return false;
    }
    const pos  = this.editor.getCursorBufferPosition();
    const line = this.editor.lineTextForBufferRow(pos.row);
    return line.trimLeft()[0] === '|';
  }

  updateView() {
    if (this.isInTable()) {
      this.editor.element.classList.add('markdown-table-editor-active');
    }
    else {
      this.editor.element.classList.remove('markdown-table-editor-active');
    }
  }

  findTable() {
    if (!this.isInTable()) {
      return undefined;
    }
    const pos    = this.editor.getCursorBufferPosition();
    const maxRow = this.editor.getLineCount() - 1;

    const rows = [];
    const range = new Range(
      new Point(pos.row, 0),
      new Point(pos.row, 0)
    );
    const focus = new Point(0, 0);

    {
      const line = this.editor.lineTextForBufferRow(pos.row);
      const row = readTableRow(line);
      if (!row) {
        return undefined;
      }
      rows.push(row);
      range.end.column = line.length;
      if (row.margin + 1 > pos.column) {
        focus.column = -1;
      }
      else {
        const ws = row.cells.map(cell => cell.raw.length);
        let c = row.margin + 1;
        let i;
        for (i = 0; i < ws.length; i++) {
          c += ws[i] + 1;
          if (c > pos.column) {
            break;
          }
        }
        focus.column = i;
      }
    }

    for (let r = pos.row - 1; r >= 0; r--) {
      const line = this.editor.lineTextForBufferRow(r);
      const row = readTableRow(line);
      if (!row) {
        break;
      }
      rows.unshift(row);
      range.start.row = r;
    }

    for (let r = pos.row + 1; r <= maxRow; r++) {
      const line = this.editor.lineTextForBufferRow(r);
      const row = readTableRow(line);
      if (!row) {
        break;
      }
      rows.push(row);
      range.end.row    = r;
      range.end.column = line.length;
    }

    focus.row = pos.row - range.start.row;

    return { rows, range, focus };
  }

  nextCell() {
    if (!this.isInTable()) {
      return;
    }
    // TODO
  }

  previousCell() {
    if (!this.isInTable()) {
      return;
    }
    // TODO
  }

  destroy() {
    this.cursorsSub.dispose();
  }
}

function readBackquotes(str) {
  let i = 0;
  for (; i < str.length; i++) {
    if (str[i] !== '`') {
      break;
    }
  }
  return [str.substr(0, i), str.substr(i)];
}

function readTableRow(line) {
  if (line.trimLeft()[0] !== '|') {
    return undefined;
  }
  let rawCells = [];
  // split cells
  {
    let rest = line;
    let buf  = '';
    while (rest !== '') {
      switch (rest[0]) {
      case '`':
        {
          const start = readBackquotes(rest);
          const quote = start[0];
          let rest1   = start[1];
          let content = '';
          let closed  = false;
          while (rest1 !== '') {
            if (rest1[0] === '`') {
              const end = readBackquotes(rest1);
              if (end[0].length === quote.length) {
                closed = true;
                rest1  = end[1];
                break;
              }
              else {
                content += end[0];
                rest1    = end[1];
              }
            }
            else {
              content += rest1[0];
              rest1    = rest1.substr(1);
            }
          }
          if (closed) {
            buf += quote + content + quote;
            rest = rest1;
          }
          else {
            buf += '`';
            rest = rest.substr(1);
          }
        }
        break;
      case '\\':
        if (rest.length >= 2) {
          buf += rest.substr(0, 2);
          rest = rest.substr(2);
        }
        else {
          buf += '\\';
          rest = rest.substr(1);
        }
        break;
      case '|':
        rawCells.push(buf);
        buf  = '';
        rest = rest.substr(1);
        break;
      default:
        buf += rest[0];
        rest = rest.substr(1);
      }
    }
    rawCells.push(buf);
  }
  const margin = rawCells[0].length;
  rawCells = rawCells[rawCells.length - 1].trim() === ''
    ? rawCells.slice(1, rawCells.length - 1)
    : rawCells.slice(1);
  const cells = rawCells.map(cell => ({
    raw    : cell,
    content: cell.trim()
  }));
  return { margin, cells };
}
<commit_msg>Separate functions<commit_after>'use babel';

import { CompositeDisposable, Point, Range } from 'atom';

export default class EditorController {
  constructor(editor) {
    this.editor = editor;

    this.updateView();

    this.cursorsSub = new CompositeDisposable();
    this.cursorsSub.add(this.editor.onDidAddCursor(() => {
      this.updateView();
    }));
    this.cursorsSub.add(this.editor.onDidRemoveCursor(() => {
      this.updateView();
    }));
    this.cursorsSub.add(this.editor.onDidChangeCursorPosition(event => {
      if (event.newBufferPosition.row !== event.oldBufferPosition.row) {
        this.updateView();
      }
    }));
    this.cursorsSub.add(this.editor.onDidStopChanging(() => {
      this.updateView();
    }));
  }

  isInTable() {
    // TODO: check grammar
    if (this.editor.hasMultipleCursors()) {
      return false;
    }
    const pos  = this.editor.getCursorBufferPosition();
    const line = this.editor.lineTextForBufferRow(pos.row);
    return line.trimLeft()[0] === '|';
  }

  updateView() {
    if (this.isInTable()) {
      this.editor.element.classList.add('markdown-table-editor-active');
    }
    else {
      this.editor.element.classList.remove('markdown-table-editor-active');
    }
  }

  findTable() {
    if (!this.isInTable()) {
      return undefined;
    }
    const pos    = this.editor.getCursorBufferPosition();
    const maxRow = this.editor.getLineCount() - 1;

    const rows = [];
    const range = new Range(
      new Point(pos.row, 0),
      new Point(pos.row, 0)
    );
    const focus = new Point(0, 0);

    {
      const line = this.editor.lineTextForBufferRow(pos.row);
      const row = readTableRow(line);
      if (!row) {
        return undefined;
      }
      rows.push(row);
      range.end.column = line.length;
      if (row.margin + 1 > pos.column) {
        focus.column = -1;
      }
      else {
        const ws = row.cells.map(cell => cell.raw.length);
        let c = row.margin + 1;
        let i;
        for (i = 0; i < ws.length; i++) {
          c += ws[i] + 1;
          if (c > pos.column) {
            break;
          }
        }
        focus.column = i;
      }
    }

    for (let r = pos.row - 1; r >= 0; r--) {
      const line = this.editor.lineTextForBufferRow(r);
      const row = readTableRow(line);
      if (!row) {
        break;
      }
      rows.unshift(row);
      range.start.row = r;
    }

    for (let r = pos.row + 1; r <= maxRow; r++) {
      const line = this.editor.lineTextForBufferRow(r);
      const row = readTableRow(line);
      if (!row) {
        break;
      }
      rows.push(row);
      range.end.row    = r;
      range.end.column = line.length;
    }

    focus.row = pos.row - range.start.row;

    return { rows, range, focus };
  }

  nextCell() {
    if (!this.isInTable()) {
      return;
    }
    // TODO
  }

  previousCell() {
    if (!this.isInTable()) {
      return;
    }
    // TODO
  }

  destroy() {
    this.cursorsSub.dispose();
  }
}

function readBackquotes(str) {
  let i = 0;
  for (; i < str.length; i++) {
    if (str[i] !== '`') {
      break;
    }
  }
  return [str.substr(0, i), str.substr(i)];
}

function splitCells(str) {
  const cells = [];
  let rest = str;
  let buf  = '';
  while (rest !== '') {
    switch (rest[0]) {
    case '`':
      {
        const start = readBackquotes(rest);
        const quote = start[0];
        let rest1   = start[1];
        let content = '';
        let closed  = false;
        while (rest1 !== '') {
          if (rest1[0] === '`') {
            const end = readBackquotes(rest1);
            if (end[0].length === quote.length) {
              closed = true;
              rest1  = end[1];
              break;
            }
            else {
              content += end[0];
              rest1    = end[1];
            }
          }
          else {
            content += rest1[0];
            rest1    = rest1.substr(1);
          }
        }
        if (closed) {
          buf += quote + content + quote;
          rest = rest1;
        }
        else {
          buf += '`';
          rest = rest.substr(1);
        }
      }
      break;
    case '\\':
      if (rest.length >= 2) {
        buf += rest.substr(0, 2);
        rest = rest.substr(2);
      }
      else {
        buf += '\\';
        rest = rest.substr(1);
      }
      break;
    case '|':
      cells.push(buf);
      buf  = '';
      rest = rest.substr(1);
      break;
    default:
      buf += rest[0];
      rest = rest.substr(1);
    }
  }
  cells.push(buf);
  return cells;
}

function readTableRow(line) {
  if (line.trimLeft()[0] !== '|') {
    return undefined;
  }
  let rawCells = splitCells(line);
  const margin = rawCells[0].length;
  rawCells = rawCells[rawCells.length - 1].trim() === ''
    ? rawCells.slice(1, rawCells.length - 1)
    : rawCells.slice(1);
  const cells = rawCells.map(cell => ({
    raw    : cell,
    content: cell.trim()
  }));
  return { margin, cells };
}
<|endoftext|>


<commit_before>module.exports = Messages

var h = require('virtual-dom/h')
var inherits = require('util').inherits
var BaseElement = require('./base-element')

var htmlToVDom = require('html-to-vdom')
var VNode = require('virtual-dom/vnode/vnode')
var VText = require('virtual-dom/vnode/vtext')

var convertHTML = htmlToVDom({
  VNode: VNode,
  VText: VText
})

function makeVDom (html) {
  return convertHTML('
' + html + '
')
}

function Messages (target) {
  BaseElement.call(this, target)
  this.shouldAutoScroll = true
  // keep track of the scrollTop property here to avoid odd behavior when
  // changing scrollHeight while rerendering
  this.scrollTop = 0
  this.composerHeight = 48
}
inherits(Messages, BaseElement)

Messages.prototype.render = function (channel, users) {
  var self = this
  var childViews

  if (channel && channel.messages.length === 0) {
    var starterMessage = 'This is a new channel. Send a message to start things off!'
    childViews = h('.messages.starterMessage', starterMessage)
  } else {
    var messages = (channel ? channel.messages : []).map(function (msg) {
      var user = users[msg.username]
      if (user && user.blocked) return null

      var verified = !/Anonymous/i.test(msg.username) && msg.valid
      var userUrl = verified ? 'http://github.com/' + msg.username : '#'
      return h('li.message.clearfix', [
        h('img.avatar', { src: msg.avatar }),
        h(verified ? 'a.username' : '.username', { href: userUrl, style: {textDecoration: 'none', color: 'inherit' } }, msg.username),
        verified ? h('.verified') : null,
        h('.timestamp', msg.timeago),
        makeVDom(msg.html) || h('.text', msg.text)
      ])
    })
    childViews = h('.messages', {
      onscroll: function () {
        if (this.scrollHeight <= this.clientHeight + this.scrollTop) self.shouldAutoScroll = true
        else self.shouldAutoScroll = false
      },
      style: {
        paddingBottom: this.composerHeight
      },
      scrollTop: this.scrollTop
    }, messages)
  }

  var onleave = function () {
    if (!channel || channel.name === 'friends') return
    self.send('leaveChannel', channel.name)
  }

  var leavableChannel = channel.name !== 'friends'

  return h('.messages-container', [
    h('div', { className: 'top-bar' }, [
      h('.channelName', '#' + (channel ? channel.name : 'friends') + ' (' + channel.peers + ' peer' + (channel.peers === 1 ? '' : 's') + ')'),
      leavableChannel ? h('button.button.leaveButton', {onclick: onleave}, 'Leave') : null
    ]),
    childViews
  ])
}

Messages.prototype.scrollToBottom = function (force) {
  if (!force && !this.shouldAutoScroll) return
  var messagesDiv = document.querySelector('.messages')
  if (messagesDiv) messagesDiv.scrollTop = messagesDiv.scrollHeight
}

Messages.prototype.notifyComposerHeight = function (height) {
  var messagesDiv = document.querySelector('.messages')
  if (messagesDiv) {
    var heightChange = height - this.composerHeight
    this.scrollTop = messagesDiv.scrollTop + heightChange
  }

  this.composerHeight = height
}
<commit_msg>Link to gh-profile on message gravatar.<commit_after>module.exports = Messages

var h = require('virtual-dom/h')
var inherits = require('util').inherits
var BaseElement = require('./base-element')

var htmlToVDom = require('html-to-vdom')
var VNode = require('virtual-dom/vnode/vnode')
var VText = require('virtual-dom/vnode/vtext')

var convertHTML = htmlToVDom({
  VNode: VNode,
  VText: VText
})

function makeVDom (html) {
  return convertHTML('
' + html + '
')
}

function Messages (target) {
  BaseElement.call(this, target)
  this.shouldAutoScroll = true
  // keep track of the scrollTop property here to avoid odd behavior when
  // changing scrollHeight while rerendering
  this.scrollTop = 0
  this.composerHeight = 48
}
inherits(Messages, BaseElement)

Messages.prototype.render = function (channel, users) {
  var self = this
  var childViews

  if (channel && channel.messages.length === 0) {
    var starterMessage = 'This is a new channel. Send a message to start things off!'
    childViews = h('.messages.starterMessage', starterMessage)
  } else {
    var messages = (channel ? channel.messages : []).map(function (msg) {
      var user = users[msg.username]
      if (user && user.blocked) return null

      var verified = !/Anonymous/i.test(msg.username) && msg.valid
      var userUrl = verified ? 'http://github.com/' + msg.username : '#'
      return h('li.message.clearfix', [
        h('img.avatar', { src: msg.avatar , style: { cursor: 'pointer' },
          onclick: function (e) {
            if (userUrl !== '#')
            shell.openExternal(userUrl)
          }),
        h(verified ? 'a.username' : '.username', { href: userUrl, style: {textDecoration: 'none', color: 'inherit' } }, msg.username),
        verified ? h('.verified') : null,
        h('.timestamp', msg.timeago),
        makeVDom(msg.html) || h('.text', msg.text)
      ])
    })
    childViews = h('.messages', {
      onscroll: function () {
        if (this.scrollHeight <= this.clientHeight + this.scrollTop) self.shouldAutoScroll = true
        else self.shouldAutoScroll = false
      },
      style: {
        paddingBottom: this.composerHeight
      },
      scrollTop: this.scrollTop
    }, messages)
  }

  var onleave = function () {
    if (!channel || channel.name === 'friends') return
    self.send('leaveChannel', channel.name)
  }

  var leavableChannel = channel.name !== 'friends'

  return h('.messages-container', [
    h('div', { className: 'top-bar' }, [
      h('.channelName', '#' + (channel ? channel.name : 'friends') + ' (' + channel.peers + ' peer' + (channel.peers === 1 ? '' : 's') + ')'),
      leavableChannel ? h('button.button.leaveButton', {onclick: onleave}, 'Leave') : null
    ]),
    childViews
  ])
}

Messages.prototype.scrollToBottom = function (force) {
  if (!force && !this.shouldAutoScroll) return
  var messagesDiv = document.querySelector('.messages')
  if (messagesDiv) messagesDiv.scrollTop = messagesDiv.scrollHeight
}

Messages.prototype.notifyComposerHeight = function (height) {
  var messagesDiv = document.querySelector('.messages')
  if (messagesDiv) {
    var heightChange = height - this.composerHeight
    this.scrollTop = messagesDiv.scrollTop + heightChange
  }

  this.composerHeight = height
}
<|endoftext|>


<commit_before>/*
 * This binds the node-validator library to the req object so that
 * the validation / sanitization methods can be called on parameter
 * names rather than the actual strings.
 *
 * 1. Be sure to include `req.mixinParams()` as middleware to merge
 *    query string, body and named parameters into `req.params`
 *
 * 2. To validate parameters, use `req.check(param_name, [err_message])`
 *        e.g. req.check('param1').len(1, 6).isInt();
 *        e.g. req.checkHeader('referer').contains('mydomain.com');
 *
 *    Each call to `check()` will throw an exception by default. To
 *    specify a custom err handler, use `req.onValidationError(errback)`
 *    where errback receives a parameter containing the error message
 *
 * 3. To sanitize parameters, use `req.sanitize(param_name)`
 *        e.g. req.sanitize('large_text').xss();
 *        e.g. req.sanitize('param2').toInt();
 *
 * 4. Done! Access your validated and sanitized paramaters through the
 *    `req.params` object
 */

var Validator = require('validator').Validator,
    Filter = require('validator').Filter;

var validator = new Validator();

var expressValidator = function(req, res, next) {

  req.mixinParams = function() {
    this.params = this.params || {};
    // this.params is an array, we want an object instead
    if (Array.isArray(this.params)) {
      var params = {};
      for (var c in this.params) {
        params[c] = this.params[c];
      }
      this.params = params;
    }
    this.query = this.query || {};
    this.body = this.body || {};

    // Merge params from the query string
    for (var i in this.query) {
      if (typeof this.params[i] === 'undefined') {
        this.params[i] = this.query[i];
      }
    }

    // Merge params from the request body
    for (var j in this.body) {
      if (typeof this.params[j] === 'undefined') {
        this.params[j] = this.body[j];
      }
    }
  };

  req.check = function(param, fail_msg) {
    return validator.check(this.param(param), fail_msg);
  };

  req.checkHeader = function(param, fail_msg) {
    var to_check;
    if (header === 'referrer' || header === 'referer') {
      to_check = this.headers.referer;
    } else {
      to_check = this.headers[header];
    }
    return validator.check(to_check || '', fail_msg);
  };

  req.onValidationError = function(errback) {
    validator.error = errback;
  };

  req.filter = function(param) {
    var self = this;
    var filter = new Filter();
    filter.modify = function(str) {
      this.str = str;
      self.params[param] = str; // Replace the param with the filtered version
    };
    return filter.sanitize(this.params[param]);
  };

  // Create some aliases - might help with code readability
  req.sanitize = req.filter;
  req.assert = req.check;

  return next();
};
module.exports = expressValidator;
<commit_msg>Use req.param() instead of req.params + req.mixinParams() for filter() as well. Introduce new updateParam() method to replace params with the filtered version See #1<commit_after>/*
 * This binds the node-validator library to the req object so that
 * the validation / sanitization methods can be called on parameter
 * names rather than the actual strings.
 *
 * 1. Be sure to include `req.mixinParams()` as middleware to merge
 *    query string, body and named parameters into `req.params`
 *
 * 2. To validate parameters, use `req.check(param_name, [err_message])`
 *        e.g. req.check('param1').len(1, 6).isInt();
 *        e.g. req.checkHeader('referer').contains('mydomain.com');
 *
 *    Each call to `check()` will throw an exception by default. To
 *    specify a custom err handler, use `req.onValidationError(errback)`
 *    where errback receives a parameter containing the error message
 *
 * 3. To sanitize parameters, use `req.sanitize(param_name)`
 *        e.g. req.sanitize('large_text').xss();
 *        e.g. req.sanitize('param2').toInt();
 *
 * 4. Done! Access your validated and sanitized paramaters through the
 *    `req.params` object
 */

var Validator = require('validator').Validator,
    Filter = require('validator').Filter;

var validator = new Validator();

var expressValidator = function(req, res, next) {

  req.mixinParams = function() {
    this.params = this.params || {};
    // this.params is an array, we want an object instead
    if (Array.isArray(this.params)) {
      var params = {};
      for (var c in this.params) {
        params[c] = this.params[c];
      }
      this.params = params;
    }
    this.query = this.query || {};
    this.body = this.body || {};

    // Merge params from the query string
    for (var i in this.query) {
      if (typeof this.params[i] === 'undefined') {
        this.params[i] = this.query[i];
      }
    }

    // Merge params from the request body
    for (var j in this.body) {
      if (typeof this.params[j] === 'undefined') {
        this.params[j] = this.body[j];
      }
    }
  };

  req.updateParam = function(name, value) {
    // route params like /user/:id
    if (this.params && this.params.hasOwnProperty(name) && undefined !== this.params[name]) {
      return this.params[name] = value;
    }
    // query string params
    if (undefined !== this.query[name]) {
      return this.query[name] = value;
    }
    // request body params via connect.bodyParser
    if (this.body && undefined !== this.body[name]) {
      return this.body[name] = value;
    }
    return false;
  };

  req.check = function(param, fail_msg) {
    return validator.check(this.param(param), fail_msg);
  };

  req.checkHeader = function(param, fail_msg) {
    var to_check;
    if (header === 'referrer' || header === 'referer') {
      to_check = this.headers.referer;
    } else {
      to_check = this.headers[header];
    }
    return validator.check(to_check || '', fail_msg);
  };

  req.onValidationError = function(errback) {
    validator.error = errback;
  };

  req.filter = function(param) {
    var self = this;
    var filter = new Filter();
    filter.modify = function(str) {
      this.str = str;
      self.updateParam(param, str); // Replace the param with the filtered version
    };
    return filter.sanitize(this.param(param));
  };

  // Create some aliases - might help with code readability
  req.sanitize = req.filter;
  req.assert = req.check;

  return next();
};
module.exports = expressValidator;
<|endoftext|>


<commit_before>/**  veneer.js custom html tag definition
 {
	tagName: 'veneer-time',
	version: '1.0.0', tags: 'native date',
	example: "<veneer-time></veneer-time>",
	purpose: 'turns a GMT or UTC or ISO Date stamp into the local time (ex 11:59 PM)',
	attribs: { time: 'a standard datestamp parse-able by window.Date() ' },
	events:  [ 'update' ]
 }
**/

//////////////////////////////////////////////

 veneer("veneer-time", {
	events: {
		update: function(e){
			e.target.innerHTML=new Date( +e.target.time  || e.target.time || new Date()).toLocaleTimeString();
			e.target.className="busy";
			setTimeout(function(){e.target.className="time";}, 250);
		}
	},
	props:{
		time: veneer.k
	}
  });
  <commit_msg>added support for value attrib<commit_after>/**  veneer.js custom html tag definition
 {
	tagName: 'veneer-time',
	version: '1.0.1', tags: 'native date',
	example: "<veneer-time></veneer-time>",
	purpose: 'turns a GMT or UTC or ISO Date stamp into the local time (ex 11:59 PM)',
	attribs: {
		time: 'a standard datestamp parse-able by window.Date() ',
		value: 'alias for time attribute (for API consistency)'
	},
	events:  [ 'update' ]
 }
**/

//////////////////////////////////////////////

 veneer("veneer-time", {
	events: {
		update: function(e){
			var m=e.target, d=veneer.date(+m.time||m.time||+m.value||m.value||new Date());
			m.innerHTML=d.toLocaleTimeString();
		}
	},
	props:{
		time: veneer.k,
		value: veneer.k
	}
  });
  <|endoftext|>


<commit_before>var Promise = require('bluebird')
var inspect = require('eyes').inspector()
var _ = require('lodash')

var xml2js = Promise.promisifyAll(require('xml2js'));

module.exports = {
    init: init,
    find: find
}

function init(env){
    return Promise.resolve(env)
}

var _ = require('lodash')
var Promise = require('bluebird')
var fs = Promise.promisifyAll(require('fs'))

function unpickle(src){

    return fs.readFileAsync(src, 'utf8')
        .then(function(contents){

            var data = []
            var JSONPickle = function(o){
                data.push(o)
            }
            eval(contents)

            var gs = _.groupBy(data, '$type')
            return {
                appData: gs['edu.colorado.permgrep.appData'][0],
                perms: gs['edu.colorado.permgrep.onePerm']
            }
        })
}

function find(env, query, options) {

    return xml2js
        .parseStringAsync(query)
        .then(function(parsedQuery){
            return Promise.all(options.scope.map(_.partial(match, env, parsedQuery)))
        })
        .then(_.compact)
        .then(function(results){
            return results
        })
}

// q must be parsed
function match(env, q, item){

    var methodNamePattern  = q.callpath.$['from']
    var permissionPattern  = q.callpath.$['uses-permission'] || '.'

    return env.apps
        .get(item.id, {perm: true})
        .then(function(app){

            var o = app.perm

            var matches = _(o.perms)
                .map(function(p) {

                    var permission = p.permissions.elems[0].value

                    if (permission.match(permissionPattern)) {

                        var rs = _.map(p.path.elems, function (e) {
                            return e.methodName.methodName.match(methodNamePattern) ?
                                e : null
                        })

                        rs = _.compact(rs)
                        if (rs.length > 0) {
                            return {permission: p.permissions.elems, views: rs}
                        }
                    }
                })
                .compact()
                .value()

            if (matches.length > 0){
                item.perm = matches
                return item
            }
        })
}<commit_msg>return scope when no query is given and fix style issues<commit_after>var Promise = require('bluebird');
var inspect = require('eyes').inspector();
var _ = require('lodash');

var xml2js = Promise.promisifyAll(require('xml2js'));

module.exports = {
    init: init,
    find: find
};

function init(env) {
    return Promise.resolve(env)
}

var _ = require('lodash');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));

function unpickle(src) {

    return fs.readFileAsync(src, 'utf8')
        .then(function (contents) {

            var data = [];
            var JSONPickle = function (o) {
                data.push(o)
            };
            eval(contents);

            var gs = _.groupBy(data, '$type');
            return {
                appData: gs['edu.colorado.permgrep.appData'][0],
                perms: gs['edu.colorado.permgrep.onePerm']
            }
        })
}

function find(env, query, options) {

    // If query is not specified, return everything in scope
    if (!query) {
        return Promise.resolve(options.scope);
    }
    return xml2js
        .parseStringAsync(query)
        .then(function (parsedQuery) {
            return Promise.all(options.scope.map(_.partial(match, env, parsedQuery)))
        })
        .then(_.compact)
        .then(function (results) {
            return results
        })
}

// q must be parsed
function match(env, q, item) {

    var methodNamePattern = q.callpath.$['from'];
    var permissionPattern = q.callpath.$['uses-permission'] || '.';

    return env.apps
        .get(item, {perm: true})
        .then(function (app) {

            var o = app.perm;

            var matches = _(o.perms)
                .map(function (p) {

                    var permission = p.permissions.elems[0].value;

                    if (permission.match(permissionPattern)) {

                        var rs = _.map(p.path.elems, function (e) {
                            return e.methodName.methodName.match(methodNamePattern) ?
                                e : null
                        });

                        rs = _.compact(rs);
                        if (rs.length > 0) {
                            return {permission: p.permissions.elems, views: rs}
                        }
                    }
                })
                .compact()
                .value();

            if (matches.length > 0) {
                item.perm = matches;
                return item
            }
        })
}<|endoftext|>


<commit_before>/**
 * FlightDesignator
 * @constructor
 * @param {String} airline
 * @param {String} number
 * @param {String} suffix
 * @return {FlightDesignator}
 */
function FlightDesignator( airline, number, suffix ) {

  if( !(this instanceof FlightDesignator) )
    return new FlightDesignator( airline, number, suffix )

  this.airlineCode = airline || ''
  this.flightNumber = number || ''
  this.operationalSuffix = suffix || ''

}

/**
 * Flight designator pattern (IATA/ICAO)
 * @type {RegExp}
 */
FlightDesignator.pattern = /^([A-Z0-9]{2}[A-Z]?)\s*([0-9]{1,4})\s*([A-Z]?)$/i

/**
 * Parses a flight designator
 * @param  {String} value
 * @return {FlightDesignator}
 */
FlightDesignator.parse = function( value ) {
  try { return new FlightDesignator().parse( value ) }
  catch( e ) { return null }
}

/**
 * FlightDesignator prototype
 * @type {Object}
 */
FlightDesignator.prototype = {

  constructor: FlightDesignator,

  parse: function( value ) {

    var parts = ( value + '' )
      .match( FlightDesignator.pattern )

    if( parts == null || /^0{1,4}$/.test( parts[2] ) )
      throw new Error( 'Invalid flight designator "' + value + '"' )

    this.operationalSuffix = parts.pop()
    this.flightNumber = parts.pop()
    this.airlineCode = parts.pop()

    return this

  },

  toString: function( spaces ) {
    return [
      this.airlineCode,
      this.flightNumber,
      this.operationalSuffix
    ].join( spaces ? ' ' : '' )
  },

}

// Exports
module.exports = FlightDesignator
<commit_msg>Update lib: Add `.isValidAirlineCode()`<commit_after>/**
 * FlightDesignator
 * @constructor
 * @param {String} airline
 * @param {String} number
 * @param {String} suffix
 * @return {FlightDesignator}
 */
function FlightDesignator( airline, number, suffix ) {

  if( !(this instanceof FlightDesignator) )
    return new FlightDesignator( airline, number, suffix )

  this.airlineCode = airline || ''
  this.flightNumber = number || ''
  this.operationalSuffix = suffix || ''

}

/**
 * Flight designator pattern (IATA/ICAO)
 * @type {RegExp}
 */
FlightDesignator.pattern = /^([A-Z0-9]{2}[A-Z]?)\s*([0-9]{1,4})\s*([A-Z]?)$/i

/**
 * Determines whether the input is a valid airline code
 * @param  {String} airlineCode
 * @return {Boolean}
 */
FlightDesignator.isValidAirlineCode = function( airlineCode ) {
  return /^([A-Z0-9]{2}[A-Z]?)$/i.test( airlineCode )
}

/**
 * Parses a flight designator
 * @param  {String} value
 * @return {FlightDesignator}
 */
FlightDesignator.parse = function( value ) {
  try { return new FlightDesignator().parse( value ) }
  catch( e ) { return null }
}

/**
 * FlightDesignator prototype
 * @type {Object}
 */
FlightDesignator.prototype = {

  constructor: FlightDesignator,

  parse: function( value ) {

    var parts = ( value + '' )
      .match( FlightDesignator.pattern )

    if( parts == null || /^0{1,4}$/.test( parts[2] ) )
      throw new Error( 'Invalid flight designator "' + value + '"' )

    this.operationalSuffix = parts.pop()
    this.flightNumber = parts.pop()
    this.airlineCode = parts.pop()

    return this

  },

  toString: function( spaces ) {
    return [
      this.airlineCode,
      this.flightNumber,
      this.operationalSuffix
    ].join( spaces ? ' ' : '' )
  },

}

// Exports
module.exports = FlightDesignator
<|endoftext|>


<commit_before>/*!
 * contentstack-express
 * copyright (c) Built.io Contentstack
 * MIT Licensed
 */

'use strict';

/*!
 * Module dependencies
 */
var fs = require('graceful-fs'),
    path = require('path'),
    _ = require('lodash'),
    sift = require('sift'),
    utils = require('./../utils'),
    InMemory = require('./../utils/db/inmemory');

var context = utils.context,
    config = utils.config,
    languages = config.get('languages'),
    cache = config.get('cache');

module.exports = function(app) {
    // To get the partials
    app.locals.get = function(partial, limit, language, includeReference) {
        var language = language || context.get('lang'),
            limit = limit || 1,
            entry = find({"content_type": partial, "language": language, "include_references": includeReference});
        if (entry && entry.length) entry = (limit == 1) ? entry[0] : entry.slice(0, limit);
        return entry;
    };

    // get the asset url
    app.locals.getAssetUrl = function(asset) {
        return (asset && asset._internal_url) ? encodeURI(asset._internal_url) : "";
    };

    // To get the current url
    app.locals.getUrl = function(url) {
        var lang = context.get('lang'),
            prefix = getRelativePrefix(lang).slice(0, -1);
        url =  prefix + ((!url) ? context.get('entry').url : url);
        return url;
    };

    // To get the title of the current page
    app.locals.getTitle = function() {
        return context.get('entry').title;
    };
};

function find(query) {
    var references = (_.isPlainObject(arguments[1]) && !_.isEmpty(arguments[1])) ? arguments[1] : {};
    var __data,
        contentTypeUid = query.content_type,
        contentPath = path.join.call(null, getContentPath(query.language), contentTypeUid + '.json'),
        language = query.language,
        data = (process.env.SYNC !== "false") ? InMemory.get(language, contentTypeUid, {}, true) : false,
        include_references = (typeof query.include_references === 'boolean') ? query.include_references : true,
        query = filterQuery(query);
    if(data) {
        data = sift(query, data);
    } else if(fs.existsSync(contentPath)) {
        var model = JSON.parse(fs.readFileSync(contentPath, 'utf-8'));
        InMemory.set(language, contentTypeUid, null, data, true);
        data = sift(query, model);
    }
    if(data) {
        __data = _.pluck(_.clone(data, true), '_data');

        if(include_references) __data = includeReferences(__data, language, references);
    }
    return __data;
};

function includeReferences(data, language, references) {
    if (_.isEmpty(references)) references = {};
    var flag = false;
    var _includeReferences = function (data, parentID) {
        for (var _key in data) {
            if ((_.isUndefined(parentID) || _.isNull(parentID)) && data._metadata && data._metadata.uid) parentID = data._metadata.uid
            if (typeof data[_key] === "object") {
                if (data[_key] && data[_key]["_content_type_id"]) {
                    flag = true;
                    references[parentID] = references[parentID] || [];
                    references[parentID] = _.uniq(references[parentID].concat(data[_key]["values"]));
                    var _query = {"content_type": data[_key]["_content_type_id"], "_uid": {"$in": data[_key]["values"]}, "language": language};

                    _query["_uid"]["$in"] = _.filter(_query["_uid"]["$in"], function (uid) {
                        var flag = checkCyclic(uid, references)
                        return !flag
                    });

                    var _data = find(_query, references);
                    data[_key] = (_data && _data.length) ? _data :  [];
                } else {
                    _includeReferences(data[_key], parentID);
                }
            }
        }
    };

    var recursive = function (data) {
        _includeReferences(data);
        if (flag) {
            flag = false;
            return setImmediate(function () {
                return recursive(data);
            });
        }
    };

    try {
        recursive(data);
    } catch (e) {
        console.error("View-Helper Include Reference Error: ", e.message);
    }
    return data;
};

function getContentPath(langCode) {
    var idx = _.findIndex(languages, {"code": langCode});
    if(~idx) {
        return languages[idx]['contentPath'];
    } else {
        console.error("Language doesn't exists");
    }
};

function getRelativePrefix(langCode) {
    var idx = _.findIndex(languages, {"code": langCode});
    if(~idx) {
        return languages[idx]['relative_url_prefix'];
    } else {
        console.error("Language doesn't exists");
    }
};

function filterQuery(_query) {
    var keys = ['include_references', 'language', 'content_type'];
    for(var i = 0, total = keys.length; i < total; i++) {
        delete _query[keys[i]];
    }
    return _query;
};

function checkCyclic (uid, mapping) {
    var flag = false
    var list = [uid]
    var getParents = function (child) {
        var parents = []
        for(var key in mapping) {
            if(~mapping[key].indexOf(child)) {
                parents.push(key)
            }
        }
        return parents
    }
    for(var i = 0; i < list.length; i++)    {
        var parent = getParents(list[i])
        if(~parent.indexOf(uid)) {
            flag = true
            break
        }
        list = _.uniq(list.concat(parent))

    }
    return flag
}<commit_msg>added url path as _uid for rte assets added sync as option false fix the bug: partial not working if sync is disable<commit_after>/*!
 * contentstack-express
 * copyright (c) Built.io Contentstack
 * MIT Licensed
 */

'use strict';

/*!
 * Module dependencies
 */
var fs = require('graceful-fs'),
    path = require('path'),
    _ = require('lodash'),
    sift = require('sift'),
    utils = require('./../utils'),
    InMemory = require('./../utils/db/inmemory');

var context = utils.context,
    config = utils.config,
    languages = config.get('languages'),
    cache = config.get('cache');

module.exports = function(app) {
    // To get the partials
    app.locals.get = function(partial, limit, language, includeReference) {
        var language = language || context.get('lang'),
            limit = limit || 1,
            entry = find({"content_type": partial, "language": language, "include_references": includeReference});
        if (entry && entry.length) entry = (limit == 1) ? entry[0] : entry.slice(0, limit);
        return entry;
    };

    // get the asset url
    app.locals.getAssetUrl = function(asset) {
        return (asset && asset._internal_url) ? encodeURI(asset._internal_url) : "";
    };

    // To get the current url
    app.locals.getUrl = function(url) {
        var lang = context.get('lang'),
            prefix = getRelativePrefix(lang).slice(0, -1);
        url =  prefix + ((!url) ? context.get('entry').url : url);
        return url;
    };

    // To get the title of the current page
    app.locals.getTitle = function() {
        return context.get('entry').title;
    };
};

function find(query) {
    var references = (_.isPlainObject(arguments[1]) && !_.isEmpty(arguments[1])) ? arguments[1] : {};
    var __data,
        contentTypeUid = query.content_type,
        contentPath = path.join.call(null, getContentPath(query.language), contentTypeUid + '.json'),
        language = query.language,
        data = (cache && process.env.SYNC !== "false") ? InMemory.get(language, contentTypeUid, {}, true) : false,
        include_references = (typeof query.include_references === 'boolean') ? query.include_references : true,
        query = filterQuery(query);
    if(data) {
        data = sift(query, data);
    } else if(fs.existsSync(contentPath)) {
        var model = JSON.parse(fs.readFileSync(contentPath, 'utf-8'));
        InMemory.set(language, contentTypeUid, null, data, true);
        data = sift(query, model);
    }
    if(data) {
        __data = _.pluck(_.clone(data, true), '_data');

        if(include_references) __data = includeReferences(__data, language, references);
    }
    return __data;
};

function includeReferences(data, language, references) {
    if (_.isEmpty(references)) references = {};
    var flag = false;
    var _includeReferences = function (data, parentID) {
        for (var _key in data) {
            if ((_.isUndefined(parentID) || _.isNull(parentID)) && data._metadata && data._metadata.uid) parentID = data._metadata.uid
            if (typeof data[_key] === "object") {
                if (data[_key] && data[_key]["_content_type_id"]) {
                    flag = true;
                    references[parentID] = references[parentID] || [];
                    references[parentID] = _.uniq(references[parentID].concat(data[_key]["values"]));
                    var _query = {"content_type": data[_key]["_content_type_id"], "_uid": {"$in": data[_key]["values"]}, "language": language};

                    _query["_uid"]["$in"] = _.filter(_query["_uid"]["$in"], function (uid) {
                        var flag = checkCyclic(uid, references)
                        return !flag
                    });

                    var _data = find(_query, references);
                    data[_key] = (_data && _data.length) ? _data :  [];
                } else {
                    _includeReferences(data[_key], parentID);
                }
            }
        }
    };

    var recursive = function (data) {
        _includeReferences(data);
        if (flag) {
            flag = false;
            return setImmediate(function () {
                return recursive(data);
            });
        }
    };

    try {
        recursive(data);
    } catch (e) {
        console.error("View-Helper Include Reference Error: ", e.message);
    }
    return data;
};

function getContentPath(langCode) {
    var idx = _.findIndex(languages, {"code": langCode});
    if(~idx) {
        return languages[idx]['contentPath'];
    } else {
        console.error("Language doesn't exists");
    }
};

function getRelativePrefix(langCode) {
    var idx = _.findIndex(languages, {"code": langCode});
    if(~idx) {
        return languages[idx]['relative_url_prefix'];
    } else {
        console.error("Language doesn't exists");
    }
};

function filterQuery(_query) {
    var keys = ['include_references', 'language', 'content_type'];
    for(var i = 0, total = keys.length; i < total; i++) {
        delete _query[keys[i]];
    }
    return _query;
};

function checkCyclic (uid, mapping) {
    var flag = false
    var list = [uid]
    var getParents = function (child) {
        var parents = []
        for(var key in mapping) {
            if(~mapping[key].indexOf(child)) {
                parents.push(key)
            }
        }
        return parents
    }
    for(var i = 0; i < list.length; i++)    {
        var parent = getParents(list[i])
        if(~parent.indexOf(uid)) {
            flag = true
            break
        }
        list = _.uniq(list.concat(parent))

    }
    return flag
}<|endoftext|>