<commit_before>(function ($) {
  var apiKey = apiKeyService.getApiExploreKey();
  var initialValObj;
  function initialVal(config) {
    var values = {};
    config.forEach(function (el) {
      values[el] = $('#js-'+el+'-counter').text();
    });
    initialValObj = values;
  }

  $(function() {
    initEventCountersPanel(); // Counter panel init
  });

  /**
   * Initialization of counter panel
   */
  function initEventCountersPanel() {
    var intervals = [],
      config = ['events', 'venues', 'attractions', 'countries'],
      timeLeap = 60000;

    initialVal(config);
    config.forEach(function (el) {
      var val = el === 'countries' && 7,
        quantityStorage = getSessionStorage(el);
      renderValue(el, val);
      if(val !== null || val !== false) {
        if(!quantityStorage) {
          updateEventpanelCounters(el,intervals);
        }else{
          countAnimate(el, quantityStorage);
        }
        //intervals.push(setInterval(updateEventpanelCounters.bind(null, el), timeLeap));
      }
    });

    //clear requests when user leave current page
    $(window).on('unload', function(){
      for(var i = 1; i < intervals.length; i++) {
        clearTimeout(i);
      }
    });
  }

  /**
   * Get date for Counter Panel
   * @param url {string}
   */
  function updateEventpanelCounters(url) {
    if (url !== 'countries') {
      $.ajax({
        method: 'GET',
        url: ['https://app.ticketmaster.com/discovery/v2/', url, '.json?apikey=', apiKey].join(''),
        async: true,
        dataType: "json"
      }).then(function (data) {
        var quantity = data.page && data.page.totalElements || 'none';
        setSessionStorage(url, quantity);
        renderValue(url, quantity);
        countAnimate(url, quantity);
      }).fail(function (err) {
        onFailHandler(url, 0.15);
        console.error('Error: ', err);
      })
    }
  }

  /**
   * Handler for invalid apiKey
   * @param selector {string} - 'events', 'venues', 'attractions'
   * @param minutes {number} -  time to resend request if storage empty
   */
  function onFailHandler(selector, minutes) {
    var delay = minutes * 60000;
    if(getSessionStorage(selector)) {
     renderValue(selector, getSessionStorage(selector));
     countAnimate(selector, getSessionStorage(selector));
    }else{
      setTimeout(function() {
        updateEventpanelCounters(selector);
      },delay);
    }
  }
  function setSessionStorage(key, val) {
    if (Storage) {
      localStorage.setItem(key, val);
    }
  }

  function getSessionStorage(key) {
    if (localStorage[key]) {
      return localStorage.getItem(key);
    }
    return null;
  }

  function addCommas(str) {
    var parts = (str + "").split("."),
      main = parts[0],
      len = main.length,
      output = "",
      first = main.charAt(0),
      i;

    if (first === '-') {
      main = main.slice(1);
      len = main.length;
    } else {
      first = "";
    }
    i = len - 1;
    while(i >= 0) {
      output = main.charAt(i) + output;
      if ((len - i) % 3 === 0 && i > 0) {
        output = "," + output;
      }
      --i;
    }
    // put sign back
    output = first + output;
    // put decimal part back
    if (parts.length > 1) {
      output += "." + parts[1];
    }
    return output;
  }

  function renderValue(el, val) {
    var value = getSessionStorage(el) || val || initialValObj[el] || '';
    var formattedNumber = addCommas(value);
    $(['#js-', el,'-counter'].join('')).text(formattedNumber);
  }

  function removeCommas(str) {
    while (str.search(",") >= 0) {
      str = (str + "").replace(',', '');
    }
    parseInt(str,10);
    return str;
  }

  function countAnimate(selectorEl,val) {
    $('#js-'+selectorEl+'-counter').prop('Counter',  initialValObj[selectorEl] ).animate({
      Counter: val
    }, {
      duration: 3000,
      easing: 'swing',
      step: function (now) {
        $(this).text(Math.ceil(now).toLocaleString());
      }
    });

    //RemoveCommas from recived values to parse as integer
    //Update values after animation is finished (animation duration: 3000)
    setTimeout(function () {
      initialValObj[selectorEl] = removeCommas ( $('#js-'+selectorEl+'-counter').text() );
      }, 3100
    );

  }
}(jQuery));
<commit_msg>Update events-counter.js<commit_after>(function ($) {
  var apiKey = apiKeyService.getApiExploreKey();
  var initialValObj;
  function initialVal(config) {
    var values = {};
    config.forEach(function (el) {
      values[el] = $('#js-'+el+'-counter').text();
    });
    initialValObj = values;
  }

  $(function() {
    initEventCountersPanel(); // Counter panel init
  });

  /**
   * Initialization of counter panel
   */
  function initEventCountersPanel() {
    var intervals = [],
      config = ['events', 'venues', 'attractions', 'countries'],
      timeLeap = 60000;

    initialVal(config);
    config.forEach(function (el) {
      var val = el === 'countries' && 83,
        quantityStorage = getSessionStorage(el);
      renderValue(el, val);

      if(val !== null || val !== false) {
        if(!quantityStorage) {
          updateEventpanelCounters(el,intervals);
        }else{
          countAnimate(el, quantityStorage);
        }
        //intervals.push(setInterval(updateEventpanelCounters.bind(null, el), timeLeap));
      }
    });

    //clear requests when user leave current page
    $(window).on('unload', function(){
      for(var i = 1; i < intervals.length; i++) {
        clearTimeout(i);
      }
    });
  }

  /**
   * Get date for Counter Panel
   * @param url {string}
   */
  function updateEventpanelCounters(url) {
    if (url !== 'countries') {
      $.ajax({
        method: 'GET',
        url: ['https://app.ticketmaster.com/discovery/v2/', url, '.json?apikey=', apiKey].join(''),
        async: true,
        dataType: "json"
      }).then(function (data) {
        var quantity = data.page && data.page.totalElements || 'none', quantityObj = {value: quantity, timestamp: new Date().getTime()};
        setSessionStorage(url, JSON.stringify(quantityObj));
        renderValue(url, quantity);
        countAnimate(url, quantity);
      }).fail(function (err) {
        onFailHandler(url, 0.15);
        console.error('Error: ', err);
      })
    }
  }

  /**
   * Handler for invalid apiKey
   * @param selector {string} - 'events', 'venues', 'attractions'
   * @param minutes {number} -  time to resend request if storage empty
   */
  function onFailHandler(selector, minutes) {
    var delay = minutes * 60000;
    if(getSessionStorage(selector)) {
     renderValue(selector, getSessionStorage(selector));
     countAnimate(selector, getSessionStorage(selector));
    }else{
      setTimeout(function() {
        updateEventpanelCounters(selector);
      },delay);
    }
  }
  function setSessionStorage(key, val) {
    if (Storage) {
      localStorage.setItem(key, val);
    }
  }

  function getSessionStorage(key) {
    if (localStorage[key]) {
      var object = JSON.parse(localStorage.getItem(key)),
  		 dateString = object.timestamp,
       now = new Date().getTime().toString(),
 			 shiftMinutes = 1,
 			 value;

 			 value=(compareTime(dateString, now , shiftMinutes)) ? JSON.parse(localStorage.getItem(key)).value : null;

       return value;
    }
    return null;
  }

	function compareTime(dateString, now , shiftMinutes) {
 	  return dateString+(shiftMinutes*60000) > now;
  }

  function addCommas(str) {
    var parts = (str + "").split("."),
      main = parts[0],
      len = main.length,
      output = "",
      first = main.charAt(0),
      i;

    if (first === '-') {
      main = main.slice(1);
      len = main.length;
    } else {
      first = "";
    }
    i = len - 1;
    while(i >= 0) {
      output = main.charAt(i) + output;
      if ((len - i) % 3 === 0 && i > 0) {
        output = "," + output;
      }
      --i;
    }
    // put sign back
    output = first + output;
    // put decimal part back
    if (parts.length > 1) {
      output += "." + parts[1];
    }
    return output;
  }

  function renderValue(el, val) {
    var value = getSessionStorage(el) || val || initialValObj[el] || '';
    var formattedNumber = addCommas(value);
    $(['#js-', el,'-counter'].join('')).text(formattedNumber);
  }

  function removeCommas(str) {
    while (str.search(",") >= 0) {
      str = (str + "").replace(',', '');
    }
    parseInt(str,10);
    return str;
  }

  function countAnimate(selectorEl,val) {
    $('#js-'+selectorEl+'-counter').prop('Counter',  initialValObj[selectorEl] ).animate({
      Counter: val
    }, {
      duration: 3000,
      easing: 'swing',
      step: function (now) {
        $(this).text(Math.ceil(now).toLocaleString());
      }
    });

    //RemoveCommas from recived values to parse as integer
    //Update values after animation is finished (animation duration: 3000)
    setTimeout(function () {
      initialValObj[selectorEl] = removeCommas ( $('#js-'+selectorEl+'-counter').text() );
      }, 3100
    );

  }
}(jQuery));
<|endoftext|>


<commit_before>pc.extend(pc.fw, function () {
    /**
     * @component
     * @name pc.fw.PickComponent
     * @constructor Create a new PickComponent
     * @class Allows an Entity to be picked from the scene using a pc.fw.picking.Picker Object
    * @param {pc.fw.PickComponentSystem} system The ComponentSystem that created this Component
    * @param {pc.fw.Entity} entity The Entity that this Component is attached to.
     * @extends pc.fw.Component
     */
    var PickComponent = function PickComponent(system, entity) {
    };
    PickComponent = pc.inherits(PickComponent, pc.fw.Component);

    pc.extend(PickComponent.prototype, {
        addShape: function (shape, shapeName) {
            var material = this.data.material;
            var mesh = null;

            switch (shape.type) {
                case pc.shape.Type.BOX:
                    mesh = pc.scene.procedural.createBox(system.context.graphicsDevice, {
                        halfExtents: shape.halfExtents
                    });
                    break;
                case pc.shape.Type.SPHERE:
                    mesh = pc.scene.procedural.createSphere(system.context.graphicsDevice, {
                        radius: shape.radius
                    });
                    break;
                case pc.shape.Type.TORUS:
                    mesh = pc.scene.procedural.createTorus(system.context.graphicsDevice, {
                        tubeRadius: shape.iradius,
                        ringRadius: shape.oradius
                    });
                    break;
            }

            var node = new pc.scene.GraphNode();
            var meshInstance = new pc.scene.MeshInstance(node, mesh, material);

            meshInstance._entity = this.entity;

            var model = new pc.scene.Model();
            model.graph = node;
            model.meshInstances = [ meshInstance ];

            var shape = {
                shape: shape,
                shapeName: shapeName,
                model: model
            };

            this.data.shapes.push(shape);
            this.system.addShape(this.data.layer, shape);
        },

        deleteShapes: function () {
            this.system.deleteShapes(this.data.layer, this.data.shapes);
            this.data.shapes = [];
        }
    });

    return {
        PickComponent: PickComponent
    };
}());
<commit_msg>Correct pick component.<commit_after>pc.extend(pc.fw, function () {
    /**
     * @component
     * @name pc.fw.PickComponent
     * @constructor Create a new PickComponent
     * @class Allows an Entity to be picked from the scene using a pc.fw.picking.Picker Object
    * @param {pc.fw.PickComponentSystem} system The ComponentSystem that created this Component
    * @param {pc.fw.Entity} entity The Entity that this Component is attached to.
     * @extends pc.fw.Component
     */
    var PickComponent = function PickComponent(system, entity) {
    };
    PickComponent = pc.inherits(PickComponent, pc.fw.Component);

    pc.extend(PickComponent.prototype, {
        addShape: function (shape, shapeName) {
            var material = this.data.material;
            var mesh = null;

            switch (shape.type) {
                case pc.shape.Type.BOX:
                    mesh = pc.scene.procedural.createBox(this.system.context.graphicsDevice, {
                        halfExtents: shape.halfExtents
                    });
                    break;
                case pc.shape.Type.SPHERE:
                    mesh = pc.scene.procedural.createSphere(this.system.context.graphicsDevice, {
                        radius: shape.radius
                    });
                    break;
                case pc.shape.Type.TORUS:
                    mesh = pc.scene.procedural.createTorus(this.system.context.graphicsDevice, {
                        tubeRadius: shape.iradius,
                        ringRadius: shape.oradius
                    });
                    break;
            }

            var node = new pc.scene.GraphNode();
            var meshInstance = new pc.scene.MeshInstance(node, mesh, material);

            meshInstance._entity = this.entity;

            var model = new pc.scene.Model();
            model.graph = node;
            model.meshInstances = [ meshInstance ];

            var shape = {
                shape: shape,
                shapeName: shapeName,
                model: model
            };

            this.data.shapes.push(shape);
            this.system.addShape(this.data.layer, shape);
        },

        deleteShapes: function () {
            this.system.deleteShapes(this.data.layer, this.data.shapes);
            this.data.shapes = [];
        }
    });

    return {
        PickComponent: PickComponent
    };
}());
<|endoftext|>


<commit_before>/*global ErrorUtils:false*/

/**
 * react-native plugin for Raven
 *
 * Usage:
 *   var Raven = require('raven-js');
 *   require('raven-js/plugins/react-native')(Raven);
 */

var DEVICE_PATH_RE = /^\/var\/mobile\/Containers\/Bundle\/Application\/[^\/]+\/[^\.]+\.app/;
function normalizeUrl(url) {
    "use strict";

    return url
        .replace(/file\:\/\//, '')
        .replace(DEVICE_PATH_RE, '');
}

module.exports = function (Raven) {
    "use strict";

    function urlencode(obj) {
        var pairs = [];
        for (var key in obj) {
          if ({}.hasOwnProperty.call(obj, key))
            pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
        }
        return pairs.join('&');
    }

    function xhrTransport(options) {
        options.auth.sentry_data = JSON.stringify(options.data);

        var request = new XMLHttpRequest();
        request.onreadystatechange = function (e) {
            if (request.readyState !== 4) {
                return;
            }

            if (request.status === 200) {
                if (options.onSuccess) {
                    options.onSuccess();
                }
            } else {
                if (options.onError) {
                    options.onError();
                }
            }
        };

        request.open('GET', options.url + '?' + urlencode(options.auth));
        request.send();
    }

    // react-native doesn't have a document, so can't use default Image
    // transport - use XMLHttpRequest instead
    Raven.setTransport(xhrTransport);

    // Use data callback to strip device-specific paths from stack traces
    Raven.setDataCallback(function (data) {
        if (data.culprit) {
          data.culprit = normalizeUrl(data.culprit);
        }

        if (data.stacktrace && data.stacktrace.frames && data.stacktrace.frames.length) {
          data.stacktrace.frames.forEach(function (frame) {
            frame.filename = normalizeUrl(frame.filename);
          });
        }
    });

    ErrorUtils.setGlobalHandler(Raven.captureException);
};
<commit_msg>Tell react-native plugin to use the right stacktrace<commit_after>/*global ErrorUtils:false*/

/**
 * react-native plugin for Raven
 *
 * Usage:
 *   var Raven = require('raven-js');
 *   require('raven-js/plugins/react-native')(Raven);
 */

var DEVICE_PATH_RE = /^\/var\/mobile\/Containers\/Bundle\/Application\/[^\/]+\/[^\.]+\.app/;
function normalizeUrl(url) {
    "use strict";

    return url
        .replace(/file\:\/\//, '')
        .replace(DEVICE_PATH_RE, '');
}

module.exports = function (Raven) {
    "use strict";

    function urlencode(obj) {
        var pairs = [];
        for (var key in obj) {
          if ({}.hasOwnProperty.call(obj, key))
            pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
        }
        return pairs.join('&');
    }

    function xhrTransport(options) {
        options.auth.sentry_data = JSON.stringify(options.data);

        var request = new XMLHttpRequest();
        request.onreadystatechange = function (e) {
            if (request.readyState !== 4) {
                return;
            }

            if (request.status === 200) {
                if (options.onSuccess) {
                    options.onSuccess();
                }
            } else {
                if (options.onError) {
                    options.onError();
                }
            }
        };

        request.open('GET', options.url + '?' + urlencode(options.auth));
        request.send();
    }

    // react-native doesn't have a document, so can't use default Image
    // transport - use XMLHttpRequest instead
    Raven.setTransport(xhrTransport);

    // Use data callback to strip device-specific paths from stack traces
    Raven.setDataCallback(function (data) {
        if (data.culprit) {
          data.culprit = normalizeUrl(data.culprit);
        }

        if (data.exception) {
          // if data.exception exists, all of the other keys are guaranteed to exist
          data.exception.values[0].stacktrace.frames.forEach(function (frame) {
            frame.filename = normalizeUrl(frame.filename);
          });
        }
    });

    ErrorUtils.setGlobalHandler(Raven.captureException);
};
<|endoftext|>


<commit_before>import { Observable, Scheduler } from 'rx';
import debug from 'debug';

const log = debug('freecc:migrate');
const challengeTypes = {
  html: 0,
  js: 1,
  video: 2,
  zipline: 3,
  basejump: 4,
  bonfire: 5,
  hikes: 6,
  step: 7,
  waypoint: 0
};

const challengeTypeReg = /^(waypoint|hike|zipline|basejump)/i;
const challengeTypeRegWithColon =
  /^(bonfire|checkpoint|waypoint|hike|zipline|basejump):\s+/i;

function updateName(challenge) {
  challenge = challenge && typeof challenge.toJSON === 'function' ?
    challenge.toJSON() :
    challenge;

  if (
    challenge.name &&
    challenge.challengeType === 5 &&
    challengeTypeReg.test(challenge.name)
  ) {

    challenge.name.replace(challengeTypeReg, match => {
      // find the correct type
      const type = challengeTypes[''.toLowerCase.call(match)];
      // if type found, replace current type
      //
      if (type) {
        challenge.challengeType = type;
      }

      return match;
    });

  }

  if (challenge.name) {
    challenge.oldName = challenge.name;
    challenge.name = challenge.name.replace(challengeTypeRegWithColon, '');
  }
  return challenge;
}

// buildChallengeMap(
//  userId: String,
//  completedChallenges: Object[],
//  User: User
// ) => Observable
function buildChallengeMap(userId, completedChallenges = [], User) {
  return Observable.from(
    completedChallenges,
    null,
    null,
    Scheduler.default
  )
    .map(updateName)
    .reduce((challengeMap, challenge) => {
      const id = challenge.id || challenge._id;

      challengeMap[id] = challenge;
      return challengeMap;
    }, {})
    .flatMap(challengeMap => {
      const updateData = {
        '$set': {
          challengeMap,
          isChallengeMapMigrated: true
        }
      };
      return Observable.fromNodeCallback(User.updateAll, User)(
        { id: userId },
        updateData,
        { allowExtendedOperators: true }
      );
    });
}

export default function migrateCompletedChallenges() {
  return ({ user, app }, res, next) => {
    const User = app.models.User;
    if (!user || user.isChallengeMapMigrated) {
      return next();
    }
    return buildChallengeMap(
      user.id.toString(),
      user.completedChallenges,
      User
    )
      .subscribe(
        count => log('documents update', count),
        // errors go here
        next,
        next
      );
  };
}
<commit_msg>Filter out bad id's<commit_after>import { Observable, Scheduler } from 'rx';
import { ObjectID } from 'mongodb';
import debug from 'debug';

const log = debug('freecc:migrate');
const challengeTypes = {
  html: 0,
  js: 1,
  video: 2,
  zipline: 3,
  basejump: 4,
  bonfire: 5,
  hikes: 6,
  step: 7,
  waypoint: 0
};

const challengeTypeReg = /^(waypoint|hike|zipline|basejump)/i;
const challengeTypeRegWithColon =
  /^(bonfire|checkpoint|waypoint|hike|zipline|basejump):\s+/i;

function updateName(challenge) {
  challenge = challenge && typeof challenge.toJSON === 'function' ?
    challenge.toJSON() :
    challenge;

  if (
    challenge.name &&
    challenge.challengeType === 5 &&
    challengeTypeReg.test(challenge.name)
  ) {

    challenge.name.replace(challengeTypeReg, match => {
      // find the correct type
      const type = challengeTypes[''.toLowerCase.call(match)];
      // if type found, replace current type
      //
      if (type) {
        challenge.challengeType = type;
      }

      return match;
    });

  }

  if (challenge.name) {
    challenge.oldName = challenge.name;
    challenge.name = challenge.name.replace(challengeTypeRegWithColon, '');
  }
  return challenge;
}

// buildChallengeMap(
//  userId: String,
//  completedChallenges: Object[],
//  User: User
// ) => Observable
function buildChallengeMap(userId, completedChallenges = [], User) {
  return Observable.from(
    completedChallenges,
    null,
    null,
    Scheduler.default
  )
    .filter(({ id, _id }) => ObjectID.isValid(id || _id))
    .map(updateName)
    .reduce((challengeMap, challenge) => {
      const id = challenge.id || challenge._id;

      challengeMap[id] = challenge;
      return challengeMap;
    }, {})
    .flatMap(challengeMap => {
      const updateData = {
        '$set': {
          challengeMap,
          isChallengeMapMigrated: true
        }
      };
      return Observable.fromNodeCallback(User.updateAll, User)(
        { id: userId },
        updateData,
        { allowExtendedOperators: true }
      );
    });
}

export default function migrateCompletedChallenges() {
  return ({ user, app }, res, next) => {
    const User = app.models.User;
    if (!user || user.isChallengeMapMigrated) {
      return next();
    }
    return buildChallengeMap(
      user.id.toString(),
      user.completedChallenges,
      User
    )
      .subscribe(
        count => log('documents update', count),
        // errors go here
        next,
        next
      );
  };
}
<|endoftext|>


<commit_before>'use strict';

const mongoose = require('mongoose');
mongoose.Promise = Promise;
const Mockgoose = require('mockgoose').Mockgoose;
const mockgoose = new Mockgoose(mongoose);
const expect = require('chai').expect;

const ContentItem = require('./ContentItem');

describe('ContentItem Model', function() {
  //extend timeout for mockgoose
  this.timeout(120000);

  before(function(done) {

    mockgoose.prepareStorage().then(function() {
      mongoose.connect('mongodb://example.com/TestingDB', function(err) {
        done(err);
      });
    });
  });

  it('should require title', function (done) {
    const testContentItem = new ContentItem({
      description: 'the quick brown fox jumped over the lazy brown dog'
    });

    testContentItem.save((err) => {
      expect(err).to.exist;
      expect(err.message).to.equal('ContentItem validation failed: title: Path `title` is required.');
      done();
    });
  });

  it('should create a ContentItem when title is included title', function (done) {
    const testContentItem = new ContentItem({
      title: 'Gulliver\'s Travels'
    });

    testContentItem.save((err, item) => {
      expect(err).to.not.exist;
      expect(item.title).to.equal(testContentItem.title);
      done();
    });
  });

  it('should create a ContentItem and set the uniqueTitle', function (done) {
    const testContentItem = new ContentItem({
      title: 'Gulliver\'s Travels'
    });

    testContentItem.save((err, item) => {
      expect(err).to.not.exist;
      expect(item.uniqueTitle).to.contain('gulliver-s-travels-');
      expect(item.uniqueTitle.length).to.equal(32);
      done();
    });
  });

  // restoring everything back
  after( (done) => {

    mockgoose.helper.reset().then(() => {
      done();
    });
  });
});<commit_msg>add timeout to before hook<commit_after>'use strict';

const mongoose = require('mongoose');
mongoose.Promise = Promise;
const Mockgoose = require('mockgoose').Mockgoose;
const mockgoose = new Mockgoose(mongoose);
const expect = require('chai').expect;

const ContentItem = require('./ContentItem');

describe('ContentItem Model', function() {
  //extend timeout for mockgoose
  this.timeout(120000);

  before(function(done) {
    this.timeout(120000);

    mockgoose.prepareStorage().then(function() {
      mongoose.connect('mongodb://example.com/TestingDB', function(err) {
        done(err);
      });
    });
  });

  it('should require title', function (done) {
    const testContentItem = new ContentItem({
      description: 'the quick brown fox jumped over the lazy brown dog'
    });

    testContentItem.save((err) => {
      expect(err).to.exist;
      expect(err.message).to.equal('ContentItem validation failed: title: Path `title` is required.');
      done();
    });
  });

  it('should create a ContentItem when title is included title', function (done) {
    const testContentItem = new ContentItem({
      title: 'Gulliver\'s Travels'
    });

    testContentItem.save((err, item) => {
      expect(err).to.not.exist;
      expect(item.title).to.equal(testContentItem.title);
      done();
    });
  });

  it('should create a ContentItem and set the uniqueTitle', function (done) {
    const testContentItem = new ContentItem({
      title: 'Gulliver\'s Travels'
    });

    testContentItem.save((err, item) => {
      expect(err).to.not.exist;
      expect(item.uniqueTitle).to.contain('gulliver-s-travels-');
      expect(item.uniqueTitle.length).to.equal(32);
      done();
    });
  });

  // restoring everything back
  after( (done) => {

    mockgoose.helper.reset().then(() => {
      done();
    });
  });
});<|endoftext|>


<commit_before>var _ = require("lodash");
var fs = require("fs");
var path = require("path");
var async = require("async");
var leveldown = require("leveldown");
var krl_stdlib = require("krl-stdlib");//pico-engine-core requires this for us
var RulesetLoader = require("./RulesetLoader");
var PicoEngineCore = require("pico-engine-core");

var setupRootPico = function(pe, callback){
    pe.getRootECI(function(err, root_eci){
        if(err) return callback(err);

        pe.runQuery({
            eci: root_eci,
            rid: "io.picolabs.pico",
            name: "myself",
        }, function(err, myself){
            if(err) return callback(err);
            if(myself.eci === root_eci){
                //already initialized
                return callback();
            }

            var signal = function(event){
                return function(next){
                    pe.signalEvent(_.assign({eci: root_eci}, event), next);
                };
            };

            async.series([
                signal({
                    eid: "19",
                    domain: "pico",
                    type: "root_created",
                    attrs: {
                        eci: root_eci,
                    },
                }),
                signal({
                    eid: "31",
                    domain: "visual",
                    type: "update",
                    attrs: {
                        dname: "Root Pico",
                        color: "#87cefa",
                    },
                }),
            ], callback);
        });
    });
};

var github_prefix = "https://raw.githubusercontent.com/Picolab/node-pico-engine/master/krl/";

var getSystemRulesets = function(pe, callback){
    var krl_dir = path.resolve(__dirname, "../krl");
    fs.readdir(krl_dir, function(err, files){
        if(err) return callback(err);
        //.series b/c dependent modules must be registered in order
        async.map(files, function(filename, next){
            var file = path.resolve(krl_dir, filename);
            if(!/\.krl$/.test(file)){
                //only auto-load krl files in the top level
                return next();
            }
            fs.readFile(file, "utf8", function(err, src){
                if(err) return next(err);
                next(null, {
                    src: src,
                    meta: {url: github_prefix + filename},
                });
            });
        }, function(err, system_rulesets){
            callback(err, _.compact(system_rulesets));
        });
    });
};

var setupLogging = function(pe){

    var toKRLjson = function(val, indent){
        return krl_stdlib.encode({}, val, indent);
    };

    var logs = {};
    var logRID = "io.picolabs.logging";
    var needAttributes = function(context,message){
        if (context.event) {
            return message.startsWith("event received:") ||
                message.startsWith("adding raised event to schedule:");
        } else {
            return false;
        }
    };
    var logEntry = function(context,message){
        var episode_id = context.txn_id;
        var timestamp = (new Date()).toISOString();
        var episode = logs[episode_id];
        if (episode) {
            if (needAttributes(context,message)) {
                episode.logs.push(timestamp+" "+message+" attributes "+JSON.stringify(context.event.attrs));
            } else {
                episode.logs.push(timestamp+" "+message);
            }
        } else {
            console.log("[ERROR]","no episode found for",episode_id);
        }
    };
    pe.emitter.on("episode_start", function(context){
        var episode_id = context.txn_id;
        console.log("[EPISODE_START]",episode_id);
        var timestamp = (new Date()).toISOString();
        var episode = logs[episode_id];
        if (episode) {
            console.log("[ERROR]","episode already exists for",episode_id);
        } else {
            episode = {};
            episode.key = (
                timestamp + " - " + episode_id
                    + " - " + context.eci
                    + " - " + ((context.event) ? context.event.eid : "query")
            ).replace(/[.]/g, "-");
            episode.logs = [];
            logs[episode_id] = episode;
        }
    });
    pe.emitter.on("klog", function(context, val, message){
        console.log("[KLOG]", message, val);
        logEntry(context,"[KLOG] " + message + " " + toKRLjson(val));
    });
    pe.emitter.on("log-error", function(context_info, expression){
        console.log("[LOG-ERROR]",context_info,expression);
        logEntry(context_info,"[LOG-ERROR] " + toKRLjson(expression));
    });
    pe.emitter.on("log-warn", function(context_info, expression){
        console.log("[LOG-WARN]",context_info,expression);
        logEntry(context_info,"[LOG-WARN] " + toKRLjson(expression));
    });
    pe.emitter.on("log-info", function(context_info, expression){
        console.log("[LOG-INFO]",context_info,expression);
        logEntry(context_info,"[LOG-INFO] " + toKRLjson(expression));
    });
    pe.emitter.on("log-debug", function(context_info, expression){
        console.log("[LOG-DEBUG]",context_info,expression);
        logEntry(context_info,"[LOG-DEBUG] " + toKRLjson(expression));
    });
    pe.emitter.on("debug", function(context, message){
        console.log("[DEBUG]", context, message);
        if (typeof message === "string") {
            logEntry(context, message);
        } else {
            logEntry(context, toKRLjson(message));
        }
    });
    pe.emitter.on("error", function(err, context){
        console.error("[ERROR]", context, err);
        if(context) logEntry(context, err);
    });
    pe.emitter.on("episode_stop", function(context){
        var pico_id = context.pico_id;
        var episode_id = context.txn_id;

        console.log("[EPISODE_STOP]", episode_id);

        var episode = logs[episode_id];
        if (!episode) {
            console.error("[ERROR]","no episode found for", episode_id);
            return;
        }

        var onRemoved = function(err){
            delete logs[episode_id];
            if(err){
                console.error("[EPISODE_REMOVED]", episode_id, err + "");
            }else{
                console.log("[EPISODE_REMOVED]", episode_id);
            }
        };

        pe.getEntVar(pico_id, logRID, "status", function(err, is_logs_on){
            if(err) return onRemoved(err);
            if(!is_logs_on){
                onRemoved();
                return;
            }
            pe.getEntVar(pico_id, logRID, "logs", function(err, data){
                if(err) return onRemoved(err);

                data[episode.key] = episode.logs;

                pe.putEntVar(pico_id, logRID, "logs", data, onRemoved);
            });
        });
    });
};

module.exports = function(conf, callback){

    var pe = PicoEngineCore({

        host: conf.host,

        compileAndLoadRuleset: RulesetLoader({
            rulesets_dir: path.resolve(conf.home, "rulesets"),
        }),

        db: {
            db: leveldown,
            location: path.join(conf.home, "db"),
        },

        modules: conf.modules || {},

        //RIDs that will be automatically installed on the root pico
        rootRIDs: [
            "io.picolabs.pico",
            "io.picolabs.visual_params",
        ],
    });

    if(conf.no_logging){
        //no setupLogging
    }else{
        setupLogging(pe);
    }

    //system rulesets should be registered/updated first
    getSystemRulesets(pe, function(err, system_rulesets){
        if(err) return callback(err);

        pe.start(system_rulesets, function(err){
            if(err) return callback(err);

            setupRootPico(pe, function(err){
                if(err) return callback(err);
                callback(null, pe);
            });
        });
    });
};
<commit_msg>alternate format for stdout logs<commit_after>var _ = require("lodash");
var fs = require("fs");
var path = require("path");
var async = require("async");
var leveldown = require("leveldown");
var krl_stdlib = require("krl-stdlib");//pico-engine-core requires this for us
var RulesetLoader = require("./RulesetLoader");
var PicoEngineCore = require("pico-engine-core");

var setupRootPico = function(pe, callback){
    pe.getRootECI(function(err, root_eci){
        if(err) return callback(err);

        pe.runQuery({
            eci: root_eci,
            rid: "io.picolabs.pico",
            name: "myself",
        }, function(err, myself){
            if(err) return callback(err);
            if(myself.eci === root_eci){
                //already initialized
                return callback();
            }

            var signal = function(event){
                return function(next){
                    pe.signalEvent(_.assign({eci: root_eci}, event), next);
                };
            };

            async.series([
                signal({
                    eid: "19",
                    domain: "pico",
                    type: "root_created",
                    attrs: {
                        eci: root_eci,
                    },
                }),
                signal({
                    eid: "31",
                    domain: "visual",
                    type: "update",
                    attrs: {
                        dname: "Root Pico",
                        color: "#87cefa",
                    },
                }),
            ], callback);
        });
    });
};

var github_prefix = "https://raw.githubusercontent.com/Picolab/node-pico-engine/master/krl/";

var getSystemRulesets = function(pe, callback){
    var krl_dir = path.resolve(__dirname, "../krl");
    fs.readdir(krl_dir, function(err, files){
        if(err) return callback(err);
        //.series b/c dependent modules must be registered in order
        async.map(files, function(filename, next){
            var file = path.resolve(krl_dir, filename);
            if(!/\.krl$/.test(file)){
                //only auto-load krl files in the top level
                return next();
            }
            fs.readFile(file, "utf8", function(err, src){
                if(err) return next(err);
                next(null, {
                    src: src,
                    meta: {url: github_prefix + filename},
                });
            });
        }, function(err, system_rulesets){
            callback(err, _.compact(system_rulesets));
        });
    });
};

var setupLogging = function(pe){

    var toKRLjson = function(val, indent){
        return krl_stdlib.encode({}, val, indent);
    };

    var logs = {};
    var logRID = "io.picolabs.logging";
    var needAttributes = function(context,message){
        if (context.event) {
            return message.startsWith("event received:") ||
                message.startsWith("adding raised event to schedule:");
        } else {
            return false;
        }
    };
    var logEntry = function(level, context, message){
        var episode_id = context.txn_id;
        var timestamp = (new Date()).toISOString();

        if(!_.isString(message)){
            message = toKRLjson(message);
        }
        var shell_log = "[" + level.toUpperCase() + "] ";
        if(context.event){
            shell_log += "event"
                + "/" + context.event.eci
                + "/" + context.event.eid
                + "/" + context.event.domain
                + "/" + context.event.type
                ;
        }else if(context.query){
            shell_log += "query"
                + "/" + context.query.eci
                + "/" + context.query.rid
                + "/" + context.query.name
                ;
        }else{
            shell_log += toKRLjson(context);
        }
        shell_log += " | " + message;
        if(shell_log.length > 300){
            shell_log = shell_log.substring(0, 300) + "...";
        }
        if(/error/i.test(level)){
            console.log(shell_log);//use stderr
        }else{
            console.log(shell_log);
        }

        var episode = logs[episode_id];
        if (episode) {
            if (needAttributes(context,message)) {
                episode.logs.push(timestamp + " [" + level.toUpperCase() + "] " + message + " attributes " + JSON.stringify(context.event.attrs));
            } else {
                episode.logs.push(timestamp + " [" + level.toUpperCase() + "] " + message);
            }
        } else {
            console.error("[ERROR]", "no episode found for", episode_id);
        }
    };
    pe.emitter.on("episode_start", function(context){
        var episode_id = context.txn_id;
        console.log("[EPISODE_START]",episode_id);
        var timestamp = (new Date()).toISOString();
        var episode = logs[episode_id];
        if (episode) {
            console.error("[ERROR]", "episode already exists for", episode_id);
        } else {
            episode = {};
            episode.key = (
                timestamp + " - " + episode_id
                    + " - " + context.eci
                    + " - " + ((context.event) ? context.event.eid : "query")
            ).replace(/[.]/g, "-");
            episode.logs = [];
            logs[episode_id] = episode;
        }
    });
    pe.emitter.on("klog", function(context, expression, message){
        logEntry("klog", context, message + " " + toKRLjson(expression));
    });
    pe.emitter.on("log-error", function(context, expression){
        logEntry("log-error", context, expression);
    });
    pe.emitter.on("log-warn", function(context, expression){
        logEntry("log-warn", context, expression);
    });
    pe.emitter.on("log-info", function(context, expression){
        logEntry("log-info", context, expression);
    });
    pe.emitter.on("log-debug", function(context, expression){
        logEntry("log-debug", context, expression);
    });
    pe.emitter.on("debug", function(context, expression){
        if (typeof expression === "string") {
            logEntry("debug", context, expression);
        } else {
            logEntry("debug", context, toKRLjson(expression));
        }
    });
    pe.emitter.on("error", function(err, context){
        if(context) logEntry("error", context, err);
    });
    pe.emitter.on("episode_stop", function(context){
        var pico_id = context.pico_id;
        var episode_id = context.txn_id;

        console.log("[EPISODE_STOP]", episode_id);

        var episode = logs[episode_id];
        if (!episode) {
            console.error("[ERROR]","no episode found for", episode_id);
            return;
        }

        var onRemoved = function(err){
            delete logs[episode_id];
            if(err){
                console.error("[EPISODE_REMOVED]", episode_id, err + "");
            }else{
                console.log("[EPISODE_REMOVED]", episode_id);
            }
        };

        pe.getEntVar(pico_id, logRID, "status", function(err, is_logs_on){
            if(err) return onRemoved(err);
            if(!is_logs_on){
                onRemoved();
                return;
            }
            pe.getEntVar(pico_id, logRID, "logs", function(err, data){
                if(err) return onRemoved(err);

                data[episode.key] = episode.logs;

                pe.putEntVar(pico_id, logRID, "logs", data, onRemoved);
            });
        });
    });
};

module.exports = function(conf, callback){

    var pe = PicoEngineCore({

        host: conf.host,

        compileAndLoadRuleset: RulesetLoader({
            rulesets_dir: path.resolve(conf.home, "rulesets"),
        }),

        db: {
            db: leveldown,
            location: path.join(conf.home, "db"),
        },

        modules: conf.modules || {},

        //RIDs that will be automatically installed on the root pico
        rootRIDs: [
            "io.picolabs.pico",
            "io.picolabs.visual_params",
        ],
    });

    if(conf.no_logging){
        //no setupLogging
    }else{
        setupLogging(pe);
    }

    //system rulesets should be registered/updated first
    getSystemRulesets(pe, function(err, system_rulesets){
        if(err) return callback(err);

        pe.start(system_rulesets, function(err){
            if(err) return callback(err);

            setupRootPico(pe, function(err){
                if(err) return callback(err);
                callback(null, pe);
            });
        });
    });
};
<|endoftext|>


<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, vars: true, white: true, plusplus: true */
/*global Backbone, templateEngine, $, arangoHelper, window*/

(function() {
  "use strict";
  window.FooterView = Backbone.View.extend({
    el: '#footerBar',
    system: {},
    isOffline: true,
    isOfflineCounter: 0,
    firstLogin: true,

    initialize: function () {
      //also server online check
      var self = this;
      window.setInterval(function(){
        self.getVersion();
      }, 15000);
      self.getVersion();
    },

    template: templateEngine.createTemplate("footerView.ejs"),

    getVersion: function () {
      var self = this;

      // always retry this call, because it also checks if the server is online
      $.ajax({
        type: "GET",
        cache: false,
        url: "/_api/version",
        contentType: "application/json",
        processData: false,
        async: true,
        success: function(data) {
          if (self.isOffline === true) {
            self.isOffline = false;
            self.isOfflineCounter = 0;
            if (!self.firstLogin) {
              window.setTimeout(function(){
                //Heiko: notification for connected server
              }, 1000);
            } else {
              self.firstLogin = false;
            }
            self.system.name = data.server;
            self.system.version = data.version;
            self.render();
          }
        },
        error: function (data) {
          self.isOffline = true;
          self.isOfflineCounter++;
          if (self.isOfflineCounter >= 3) {
            arangoHelper.arangoError("Server", "Server is offline");
          }
        }
      });

      if (! self.system.hasOwnProperty('database')) {
        $.ajax({
          type: "GET",
          cache: false,
          url: "/_api/database/current",
          contentType: "application/json",
          processData: false,
          async: true,
          success: function(data) {
            var name = data.result.name;
            self.system.database = name;

            var timer = window.setInterval(function () {
              var navElement = $('#databaseNavi');

              if (navElement) {
                window.clearTimeout(timer);
                timer = null;

                if (name === '_system') {
                  // show "logs" button
                  $('.logs-menu').css('visibility', 'visible');
                  $('.logs-menu').css('display', 'inline');
                  // show dbs menues
                  $('#databaseNavi').css('display','inline');
                  $('#databaseNaviSelect').css('display','inline');
                }
                else {
                  // hide "logs" button
                  $('.logs-menu').css('visibility', 'hidden');
                  $('.logs-menu').css('display', 'none');
                }
                self.render();
              }
            }, 50);
          }
        });
      }
    },

    renderVersion: function () {
      if (this.system.hasOwnProperty('database') && this.system.hasOwnProperty('name')) {
        $(this.el).html(this.template.render({
          name: this.system.name,
          version: this.system.version,
          database: this.system.database
        }));
      }
    },

    render: function () {
      if (!this.system.version) {
        this.getVersion();
      }
      $(this.el).html(this.template.render({
        name: this.system.name,
        version: this.system.version
      }));
      return this;
    }

  });
}());
<commit_msg>changed delay for notifications<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, vars: true, white: true, plusplus: true */
/*global Backbone, templateEngine, $, arangoHelper, window*/

(function() {
  "use strict";
  window.FooterView = Backbone.View.extend({
    el: '#footerBar',
    system: {},
    isOffline: true,
    isOfflineCounter: 0,
    firstLogin: true,

    initialize: function () {
      //also server online check
      var self = this;
      window.setInterval(function(){
        self.getVersion();
      }, 15000);
      self.getVersion();
    },

    template: templateEngine.createTemplate("footerView.ejs"),

    getVersion: function () {
      var self = this;

      // always retry this call, because it also checks if the server is online
      $.ajax({
        type: "GET",
        cache: false,
        url: "/_api/version",
        contentType: "application/json",
        processData: false,
        async: true,
        success: function(data) {
          if (self.isOffline === true) {
            self.isOffline = false;
            self.isOfflineCounter = 0;
            if (!self.firstLogin) {
              window.setTimeout(function(){
                //Heiko: notification for connected server
              }, 1000);
            } else {
              self.firstLogin = false;
            }
            self.system.name = data.server;
            self.system.version = data.version;
            self.render();
          }
        },
        error: function (data) {
          self.isOffline = true;
          self.isOfflineCounter++;
          if (self.isOfflineCounter >= 2) {
            arangoHelper.arangoError("Server", "Server is offline");
          }
        }
      });

      if (! self.system.hasOwnProperty('database')) {
        $.ajax({
          type: "GET",
          cache: false,
          url: "/_api/database/current",
          contentType: "application/json",
          processData: false,
          async: true,
          success: function(data) {
            var name = data.result.name;
            self.system.database = name;

            var timer = window.setInterval(function () {
              var navElement = $('#databaseNavi');

              if (navElement) {
                window.clearTimeout(timer);
                timer = null;

                if (name === '_system') {
                  // show "logs" button
                  $('.logs-menu').css('visibility', 'visible');
                  $('.logs-menu').css('display', 'inline');
                  // show dbs menues
                  $('#databaseNavi').css('display','inline');
                  $('#databaseNaviSelect').css('display','inline');
                }
                else {
                  // hide "logs" button
                  $('.logs-menu').css('visibility', 'hidden');
                  $('.logs-menu').css('display', 'none');
                }
                self.render();
              }
            }, 50);
          }
        });
      }
    },

    renderVersion: function () {
      if (this.system.hasOwnProperty('database') && this.system.hasOwnProperty('name')) {
        $(this.el).html(this.template.render({
          name: this.system.name,
          version: this.system.version,
          database: this.system.database
        }));
      }
    },

    render: function () {
      if (!this.system.version) {
        this.getVersion();
      }
      $(this.el).html(this.template.render({
        name: this.system.name,
        version: this.system.version
      }));
      return this;
    }

  });
}());
<|endoftext|>


<commit_before>define([
    'require',
    'jquery',
    "underscore_cdn",
    'moment_cdn',
    'date_filter'
], function (require, $, _, moment, date_filter) {
  "use strict";

  var dependencies_loaded = false;
  var grids_to_initialize = []

  var DataGrid = function (parent_elem, grid_elem_selector, data_frame, column_types) {
    this.parent_elem = parent_elem;
    this.grid_elem_selector = grid_elem_selector;
    this.data_frame = data_frame;

    this.row_data = [];
    this.columns = [];
    this.filters = {};
    this.filter_list = [];
    this.sort_field = "id";
    this.sort_ascending = true;

    this.python_types = {
      Character: "string",
      Float: "number",
      Complex: "number",
      Datetime: "date",
      Integer: "number",
      UnsignedInteger: "number"
    };

    var self = this;

    if (column_types.length > 0) {
      for (var i = 0; i < column_types.length; i++){
        var cur_column = column_types[i];

        if (!cur_column.type){
          cur_column.type = "string";
        }else{
          cur_column.type = this.python_types[cur_column.type];
        }

        if (i === 0){
          this.sort_field = cur_column.field;
        }

        cur_column = {
          name: cur_column.field,
          field: cur_column.field,
          id: cur_column.field,
          type: cur_column.type,
          formatter: this["format_" + cur_column.type],
          sortable: true,
          resizable: true
        };

        var filter_generator = this["create_" + cur_column.type + "_filter"];
        if (filter_generator){
          var cur_filter = filter_generator(cur_column.field);
          $(cur_filter).on("filter_changed", $.proxy(this.handle_filter_changed, this))
          this.filters[cur_column.id] = cur_filter;
          this.filter_list.push(cur_filter);
        }

        this.columns.push(cur_column);
      }
    }

    var row_count = 0;
    _.each(this.data_frame, function (cur_row, key, list) {
      cur_row.id = "row" + row_count;
      row_count++;
      this.row_data.push(cur_row);
      this.filter_list.forEach(function(cur_filter){
        cur_filter.handle_row_data(cur_row);
      }, this);
    }, this);
  }

  DataGrid.prototype.initialize = function () {
    if (this.parent_elem.find(this.grid_elem_selector).length == 0){
      this.initialize_slick_grid_after_append();
    }else {
      this.initialize_slick_grid();
    }
  }

  DataGrid.prototype.initialize_slick_grid = function () {
    this.data_view = new Slick.Data.DataView({
      inlineFilters: false,
      enableTextSelectionOnCells: true
    })

    this.data_view.beginUpdate();
    var sort_comparer = this.get_sort_comparer(this.sort_field, this.sort_ascending)
    this.data_view.sort(sort_comparer, this.sort_ascending);
    this.data_view.setItems(this.row_data);
    this.data_view.setFilter($.proxy(this.include_row, this));
    this.data_view.endUpdate();

    var options = {
      enableCellNavigation: true,
      fullWidthRows: true,
      syncColumnCellResize: true,
      forceFitColumns: true,
      rowHeight: 28,
      enableColumnReorder: false
    };

    this.slick_grid = new Slick.Grid(this.grid_elem_selector, this.data_view, this.columns, options);
    this.update_sort_indicators();
    this.slick_grid.render();

    this.slick_grid.onSort.subscribe($.proxy(this.handle_sort_changed, this));
    this.slick_grid.onHeaderCellRendered.subscribe($.proxy(this.handle_header_cell_rendered, this))

    // Force the grid to re-render the column headers so the onHeaderCellRendered event is triggered.
    this.slick_grid.setColumns(this.slick_grid.getColumns());

    var self = this;
    this.data_view.onRowCountChanged.subscribe(function(e, args){
      self.slick_grid.updateRowCount();
      self.slick_grid.render();
    });

    this.data_view.onRowsChanged.subscribe(function(e, args){
      self.slick_grid.invalidateRows(args.rows)
      self.slick_grid.render()
    });

    $(window).resize(function(){
      self.slick_grid.resizeCanvas();
    });
  }

  DataGrid.prototype.handle_filter_changed = function(e, exclude_this_filter){
    var show_clear_filter_button = false;
    for (var i=0; i < this.filter_list.length; i++){
      var cur_filter = this.filter_list[i];
      var filter_button = this.parent_elem.find(".slick-header-column." + cur_filter.field + "-header .filter-button");
      if (cur_filter.is_active()){
        show_clear_filter_button = true;
        filter_button.addClass("filter-active");
      }
      else {
        filter_button.removeClass("filter-active");
      }
    }
//    if (show_clear_filter_button){
//      this.tab_elem.find(".clear-filters").show();
//    }
//    else {
//      this.tab_elem.find(".clear-filters").hide();
//    }

    this.apply_filters(exclude_this_filter ? e.target : null)
  }

  DataGrid.prototype.apply_filters = function(excluded_filter){
//    for (var i=0; i < this.filters; i++){
//      if cur_filter instanceof quanto.SliderFilter  && cur_filter != excluded_filter
//        cur_filter.reset_min_max();
//    }
    this.data_view.refresh();
//    for (var i=0; i < this.filters; i++){
//      if cur_filter instanceof quanto.SliderFilter && cur_filter != excluded_filter
//        cur_filter.handle_filtering_done()
//    }
  }

  DataGrid.prototype.include_row = function(item, args){
    item.include = true;
    item.excluded_by = {};
    for (var i=0; i < this.filter_list.length; i++){
      var cur_filter = this.filter_list[i];
      if (!cur_filter.include_item(item)){
        item.include = false;
        item.excluded_by[cur_filter.field] = true;
      }
    }

//    for (var i=0; i < this.filters; i++){
//      if cur_filter instanceof quanto.SliderFilter
//        cur_filter.update_min_max(item)
//    }

    return item.include;
  }

  DataGrid.prototype.handle_sort_changed = function(e, args){
    this.sort_field = args.sortCol.field;
    this.sort_ascending = args.sortAsc;

    var sort_comparer = this.get_sort_comparer(this.sort_field, this.sort_ascending);
    this.data_view.sort(sort_comparer, this.sort_ascending);
  }

  DataGrid.prototype.update_sort_indicators = function(){
    this.slick_grid.setSortColumns([ {columnId: this.sort_field, sortAsc: this.sort_ascending} ]);
  }

  DataGrid.prototype.get_sort_comparer = function(field, ascending){
    return function(x, y){
      var x_value = x[field];
      var y_value = y[field];

      return (x_value > y_value) ? 1 : -1;
    }
  }

  DataGrid.prototype.handle_header_cell_rendered = function(e, args){
    var cur_filter = this.filters[args.column.id];
    if (cur_filter){
      $.proxy(cur_filter.render_filter_button($(args.node), this.slick_grid), cur_filter);
    }
  }

  DataGrid.prototype.format_date = function(row, cell, value, columnDef, dataContext){
    var date = new Date(value);
    return moment(date).format("YYYY-MM-DD");
  }

  DataGrid.prototype.format_string = function(row, cell, value, columnDef, dataContext){
    return value;
  }

  DataGrid.prototype.format_number = function(row, cell, value, columnDef, dataContext){
    return value;
  }

  DataGrid.prototype.create_date_filter = function(field){
    return new date_filter.DateFilter(field);
  }
//
//  DataGrid.prototype.create_number_filter = function(field){
//    return new quanto.SliderFilter(@$tab_elem, field);
//  }
//
//  DataGrid.prototype.create_money_filter = function(field){
//    return new quanto.SliderFilter(@$tab_elem, field, quanto.safe_to_money);
//  }
//
//  DataGrid.prototype.create_ticker_filter = function(field){
//    return new quanto.SecurityFilter(@$tab_elem, field);
//  }
//
//  DataGrid.prototype.create_text_filter = function(field){
//    return new quanto.TextFilter(@$tab_elem, field);
//  }

//  DataGrid.prototype.format_money = function(row, cell, value, columnDef, dataContext){
//    if (!value.value)
//      return "- -";
//    else
//      return "#{quanto.safe_to_money(value)}";
//  }

//  DataGrid.prototype.format_total = function(totals, columnDef){
//    val = totals.sum.value ? totals.sum[columnDef.field] : null;
//    if (val.value)
//      return "total:#{quanto.safe_to_money(val)}";
//    return "- -";
//  }

  // If the target div for slick grid has not yet been added to parent_elem, we have
  // to hook up a MutationObserver to be notified when that happens.  This is because
  // slick grid cannot be initialized until its target div been added to the DOM.
  DataGrid.prototype.initialize_slick_grid_after_append = function () {
    var self = this;
    MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    var observer = new MutationObserver(function(mutations, observer) {
      // Once the target div for slick grid was added to the parent_elem
      // then we're safe to initialize slick grid (and disconnect this observer).
      if (mutations.length == 1 && mutations[0].addedNodes.length == 1 &&
          $(mutations[0].addedNodes[0]).find(self.grid_elem_selector).length == 1){
        self.initialize_slick_grid();
        observer.disconnect()
      }
    });

    // define what element should be observed by the observer
    // and what types of mutations trigger the callback
    observer.observe(this.parent_elem.get(0), {
      childList: true
    });
  }

  return { "DataGrid": DataGrid };

});
<commit_msg>Changing back...using a fallback path in requirejs instead.<commit_after>define([
    'require',
    'jquery',
    "underscore",
    'moment',
    'date_filter'
], function (require, $, _, moment, date_filter) {
  "use strict";

  var dependencies_loaded = false;
  var grids_to_initialize = []

  var DataGrid = function (parent_elem, grid_elem_selector, data_frame, column_types) {
    this.parent_elem = parent_elem;
    this.grid_elem_selector = grid_elem_selector;
    this.data_frame = data_frame;

    this.row_data = [];
    this.columns = [];
    this.filters = {};
    this.filter_list = [];
    this.sort_field = "id";
    this.sort_ascending = true;

    this.python_types = {
      Character: "string",
      Float: "number",
      Complex: "number",
      Datetime: "date",
      Integer: "number",
      UnsignedInteger: "number"
    };

    var self = this;

    if (column_types.length > 0) {
      for (var i = 0; i < column_types.length; i++){
        var cur_column = column_types[i];

        if (!cur_column.type){
          cur_column.type = "string";
        }else{
          cur_column.type = this.python_types[cur_column.type];
        }

        if (i === 0){
          this.sort_field = cur_column.field;
        }

        cur_column = {
          name: cur_column.field,
          field: cur_column.field,
          id: cur_column.field,
          type: cur_column.type,
          formatter: this["format_" + cur_column.type],
          sortable: true,
          resizable: true
        };

        var filter_generator = this["create_" + cur_column.type + "_filter"];
        if (filter_generator){
          var cur_filter = filter_generator(cur_column.field);
          $(cur_filter).on("filter_changed", $.proxy(this.handle_filter_changed, this))
          this.filters[cur_column.id] = cur_filter;
          this.filter_list.push(cur_filter);
        }

        this.columns.push(cur_column);
      }
    }

    var row_count = 0;
    _.each(this.data_frame, function (cur_row, key, list) {
      cur_row.id = "row" + row_count;
      row_count++;
      this.row_data.push(cur_row);
      this.filter_list.forEach(function(cur_filter){
        cur_filter.handle_row_data(cur_row);
      }, this);
    }, this);
  }

  DataGrid.prototype.initialize = function () {
    if (this.parent_elem.find(this.grid_elem_selector).length == 0){
      this.initialize_slick_grid_after_append();
    }else {
      this.initialize_slick_grid();
    }
  }

  DataGrid.prototype.initialize_slick_grid = function () {
    this.data_view = new Slick.Data.DataView({
      inlineFilters: false,
      enableTextSelectionOnCells: true
    })

    this.data_view.beginUpdate();
    var sort_comparer = this.get_sort_comparer(this.sort_field, this.sort_ascending)
    this.data_view.sort(sort_comparer, this.sort_ascending);
    this.data_view.setItems(this.row_data);
    this.data_view.setFilter($.proxy(this.include_row, this));
    this.data_view.endUpdate();

    var options = {
      enableCellNavigation: true,
      fullWidthRows: true,
      syncColumnCellResize: true,
      forceFitColumns: true,
      rowHeight: 28,
      enableColumnReorder: false
    };

    this.slick_grid = new Slick.Grid(this.grid_elem_selector, this.data_view, this.columns, options);
    this.update_sort_indicators();
    this.slick_grid.render();

    this.slick_grid.onSort.subscribe($.proxy(this.handle_sort_changed, this));
    this.slick_grid.onHeaderCellRendered.subscribe($.proxy(this.handle_header_cell_rendered, this))

    // Force the grid to re-render the column headers so the onHeaderCellRendered event is triggered.
    this.slick_grid.setColumns(this.slick_grid.getColumns());

    var self = this;
    this.data_view.onRowCountChanged.subscribe(function(e, args){
      self.slick_grid.updateRowCount();
      self.slick_grid.render();
    });

    this.data_view.onRowsChanged.subscribe(function(e, args){
      self.slick_grid.invalidateRows(args.rows)
      self.slick_grid.render()
    });

    $(window).resize(function(){
      self.slick_grid.resizeCanvas();
    });
  }

  DataGrid.prototype.handle_filter_changed = function(e, exclude_this_filter){
    var show_clear_filter_button = false;
    for (var i=0; i < this.filter_list.length; i++){
      var cur_filter = this.filter_list[i];
      var filter_button = this.parent_elem.find(".slick-header-column." + cur_filter.field + "-header .filter-button");
      if (cur_filter.is_active()){
        show_clear_filter_button = true;
        filter_button.addClass("filter-active");
      }
      else {
        filter_button.removeClass("filter-active");
      }
    }
//    if (show_clear_filter_button){
//      this.tab_elem.find(".clear-filters").show();
//    }
//    else {
//      this.tab_elem.find(".clear-filters").hide();
//    }

    this.apply_filters(exclude_this_filter ? e.target : null)
  }

  DataGrid.prototype.apply_filters = function(excluded_filter){
//    for (var i=0; i < this.filters; i++){
//      if cur_filter instanceof quanto.SliderFilter  && cur_filter != excluded_filter
//        cur_filter.reset_min_max();
//    }
    this.data_view.refresh();
//    for (var i=0; i < this.filters; i++){
//      if cur_filter instanceof quanto.SliderFilter && cur_filter != excluded_filter
//        cur_filter.handle_filtering_done()
//    }
  }

  DataGrid.prototype.include_row = function(item, args){
    item.include = true;
    item.excluded_by = {};
    for (var i=0; i < this.filter_list.length; i++){
      var cur_filter = this.filter_list[i];
      if (!cur_filter.include_item(item)){
        item.include = false;
        item.excluded_by[cur_filter.field] = true;
      }
    }

//    for (var i=0; i < this.filters; i++){
//      if cur_filter instanceof quanto.SliderFilter
//        cur_filter.update_min_max(item)
//    }

    return item.include;
  }

  DataGrid.prototype.handle_sort_changed = function(e, args){
    this.sort_field = args.sortCol.field;
    this.sort_ascending = args.sortAsc;

    var sort_comparer = this.get_sort_comparer(this.sort_field, this.sort_ascending);
    this.data_view.sort(sort_comparer, this.sort_ascending);
  }

  DataGrid.prototype.update_sort_indicators = function(){
    this.slick_grid.setSortColumns([ {columnId: this.sort_field, sortAsc: this.sort_ascending} ]);
  }

  DataGrid.prototype.get_sort_comparer = function(field, ascending){
    return function(x, y){
      var x_value = x[field];
      var y_value = y[field];

      return (x_value > y_value) ? 1 : -1;
    }
  }

  DataGrid.prototype.handle_header_cell_rendered = function(e, args){
    var cur_filter = this.filters[args.column.id];
    if (cur_filter){
      $.proxy(cur_filter.render_filter_button($(args.node), this.slick_grid), cur_filter);
    }
  }

  DataGrid.prototype.format_date = function(row, cell, value, columnDef, dataContext){
    var date = new Date(value);
    return moment(date).format("YYYY-MM-DD");
  }

  DataGrid.prototype.format_string = function(row, cell, value, columnDef, dataContext){
    return value;
  }

  DataGrid.prototype.format_number = function(row, cell, value, columnDef, dataContext){
    return value;
  }

  DataGrid.prototype.create_date_filter = function(field){
    return new date_filter.DateFilter(field);
  }
//
//  DataGrid.prototype.create_number_filter = function(field){
//    return new quanto.SliderFilter(@$tab_elem, field);
//  }
//
//  DataGrid.prototype.create_money_filter = function(field){
//    return new quanto.SliderFilter(@$tab_elem, field, quanto.safe_to_money);
//  }
//
//  DataGrid.prototype.create_ticker_filter = function(field){
//    return new quanto.SecurityFilter(@$tab_elem, field);
//  }
//
//  DataGrid.prototype.create_text_filter = function(field){
//    return new quanto.TextFilter(@$tab_elem, field);
//  }

//  DataGrid.prototype.format_money = function(row, cell, value, columnDef, dataContext){
//    if (!value.value)
//      return "- -";
//    else
//      return "#{quanto.safe_to_money(value)}";
//  }

//  DataGrid.prototype.format_total = function(totals, columnDef){
//    val = totals.sum.value ? totals.sum[columnDef.field] : null;
//    if (val.value)
//      return "total:#{quanto.safe_to_money(val)}";
//    return "- -";
//  }

  // If the target div for slick grid has not yet been added to parent_elem, we have
  // to hook up a MutationObserver to be notified when that happens.  This is because
  // slick grid cannot be initialized until its target div been added to the DOM.
  DataGrid.prototype.initialize_slick_grid_after_append = function () {
    var self = this;
    MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    var observer = new MutationObserver(function(mutations, observer) {
      // Once the target div for slick grid was added to the parent_elem
      // then we're safe to initialize slick grid (and disconnect this observer).
      if (mutations.length == 1 && mutations[0].addedNodes.length == 1 &&
          $(mutations[0].addedNodes[0]).find(self.grid_elem_selector).length == 1){
        self.initialize_slick_grid();
        observer.disconnect()
      }
    });

    // define what element should be observed by the observer
    // and what types of mutations trigger the callback
    observer.observe(this.parent_elem.get(0), {
      childList: true
    });
  }

  return { "DataGrid": DataGrid };

});
<|endoftext|>


<commit_before>var config = require('./config');
var async = require('async');

var Maki = require('maki');
var converse = new Maki( config );

var ObjectId = converse.mongoose.SchemaTypes.ObjectId;

var Passport = require('maki-passport-local');
var passport = new Passport({
  resource: 'Person'
});

converse.use( passport );

converse.use({
  extends: {
    services: {
      http: {
        middleware: function(req, res, next) {
          if (!req.user) return next();
          Notification.Model.count({
            _to: req.user._id,
            status: 'unread'
          }, function(err, notificationCount) {
            res.locals.unreadNotifications = new Array(notificationCount);
            next();
          });
        }
      }
    }
  }
});

var Person = converse.define('Person', {
  attributes: {
    username: { type: String , max: 35 , required: true , slug: true },
    password: { type: String , max: 70 , masked: true },
    created:  { type: Date , default: Date.now , render: { query: false } },
    bio:      { type: String , max: 250 },
    image:    { type: 'File' }
  },
  icon: 'user'
});

/* converse.define('Board', {
  attributes: {
    name: { type: String, required: true, max: 200 , slug: true },
    description: { type: String, max: 1024 },
    created: { type: Date, required: true, default: Date.now },
    _creator: { type: ObjectId, required: true, ref: 'Person' },
    _owner: { type: ObjectId, required: true, ref: 'Person' },
    _moderators: [ { type: ObjectId, ref: 'Person' } ]
  },
  icon: 'slack'
}); */

var Post = converse.define('Post', {
  attributes: {
    created:     { type: Date, required: true, default: Date.now },
    hashcash:    { type: String },
    name:        { type: String, required: true, max: 200 },
    description: { type: String },
    sticky:      { type: Boolean , default: false },
    _author:     { type: ObjectId, required: true, ref: 'Person', populate: ['get', 'query'] },
    //_board:      { type: ObjectId, /* required: true, */ ref: 'Board' },
    link:        { type: String },
    score:       { type: Number , required: true , default: 0 },
    _document:     { type: ObjectId , ref: 'Document', populate: ['get', 'query'] },
    stats:       {
      comments:  { type: Number , default: 0 },
    },
    attribution: {
      _author: { type: ObjectId , ref: 'Person', populate: ['get', 'query'] }
    }
  },
  requires: {
    'Comment': {
      filter: function() {
        var post = this;
        return { _post: post._id , _parent: { $exists: false } };
      },
      populate: '_author _parent'
    }
  },
  icon: 'pin'
});

Post.pre('create', function(next, done) {
  var post = this;
  if (!post.link) return next();

  // TODO: automatic parsing
  Document.create({
    url: post.link,
    title: post.name,
    description: post.description
  }, function(err, document) {
    post._document = document._id;
    next();
  });
});

var Document = converse.define('Document', {
  attributes: {
    url: { type: String , required: true },
    title: { type: String , max: 1024 },
    description: { type: String , max: 1024 },
    image: { type: 'File' }
  }
});

var Comment = converse.define('Comment', {
  attributes: {
    _author: { type: ObjectId, required: true, ref: 'Person', populate: ['query', 'get'] },
    _post:   { type: ObjectId, required: true , ref: 'Post', populate: ['get'] },
    _parent: { type: ObjectId, ref: 'Comment' },
    created: { type: Date, required: true, default: Date.now },
    updated: { type: Date },
    hashcash: { type: String },
    content: { type: String, min: 1 },
    score: { type: Number , required: 0 , default: 0 },
    stats: {
      comments: { type: Number , default: 0 }
    }
  },
  requires: {
    'Comment': {
      filter: function() {
        var comment = this;
        return { _parent: comment._id };
      },
      populate: '_author _parent'
    }
  },
  handlers: {
    html: {
      create: function(req, res) {
        var comment = this;
        req.flash('info', 'Comment created successfully!');
        if (comment._parent) {
          res.status( 303 ).redirect('/comments/' + comment._parent + '#comments' + comment._id );
        } else {
          res.status( 303 ).redirect('/posts/' + comment._post );
        }

      }
    }
  },
  icon: 'comment'
});

Comment.post('create', function(next, cb) {
  var comment = this;

  var pipeline = {};

  pipeline.post = function updatePostStats(done) {
    Post.Model.update({
      _id: comment._post
    }, {
      $inc: { 'stats.comments': 1 }
    }, done);
  };

  pipeline.authorNotification = function notifyAuthor(done) {
    Post.get({ _id: comment._post }, function(err, post) {
      Notification.create({
        _to: post._author,
        _comment: comment._id
      }, done);
    });
  };

  if (comment._parent) {
    pipeline.parent = function updateParentComment(done) {
      Comment.Model.update({
        _id: comment._parent
      }, {
        $inc: { 'stats.comments': 1 }
      }, done);
    };

    pipeline.parentNotification = function notifyParentAuthor(done) {
      Comment.get({ _id: comment._parent }, function(err, parent) {
        Notification.create({
          _to: parent._author,
          _comment: comment._id
        }, done);
      });
    };
  }

  async.parallel(pipeline, function(err, results) {
    if (err) return cb(err);
    next();
  });

});

var Notification = converse.define('Notification', {
  attributes: {
    _to: { type: ObjectId , ref: 'Person', required: true },
    _comment: { type: ObjectId , ref: 'Comment', populate: ['query', 'get'] },
    created: { type: Date , required: true , default: Date.now },
    status: { type: String , enum: ['unread', 'read'], default: 'unread' }
  },
  handlers: {
    html: {
      query: function(req, res, next) {
        if (!req.user) return next();
        Notification.query({ _to: req.user._id }, function(err, notifications) {
          Comment.Model.populate(notifications, {
            path: '_comment'
          }, function(err, notifications) {
            Person.Model.populate(notifications, {
              path: '_comment._author'
            }, function(err, notifications) {
              Notification.Model.update({
                _id: {
                  $in: notifications.map(function(n) { return n._id; })
                }
              }, { $set: { status: 'read' } }, { multi: true }, function(err) {
                return res.render('notifications', {
                  notifications: notifications,
                  unreadNotifications: [] // a bit of a hack
                });
              });
            });
          });
        });
      }
    }
  }
});

var Tip = converse.define('Tip', {
  attributes: {
    _from: { type: ObjectId , ref: 'Person', required: true },
    _to: { type: ObjectId , ref: 'Person', required: true },
    _for: { type: ObjectId },
    context: { type: String , enum: ['post', 'comment'] },
    amount: { type: Number, ref: 'Person', required: true },
  }
});

Tip.post('create', function(next, cb) {
  var tip = this;

  var pipeline = {};

  pipeline.post = function updatePostStats(done) {
    if (tip.context === 'post') {
      Post.Model.update({
        _id: tip._for
      }, {
        $inc: { 'score': 1 }
      }, done);
    }
    if (tip.context === 'comment') {
      Comment.Model.update({
        _id: tip._for
      }, {
        $inc: { 'score': 1 }
      }, done);
    }
  };

  async.parallel(pipeline, function(err, results) {
    if (err) return cb(err);
    next();
  });
});

converse.define('Index', {
  name: 'Index',
  static: true,
  internal: true,
  routes: {
    query: '/'
  },
  templates: {
    query: 'posts'
  },
  requires: {
    'Post': {
      filter: {},
      populate: '_author _document',
      sort: '-score'
    }
  }
});

converse.start(function(err) {

});
<commit_msg>Add date tiebreaker.<commit_after>var config = require('./config');
var async = require('async');

var Maki = require('maki');
var converse = new Maki( config );

var ObjectId = converse.mongoose.SchemaTypes.ObjectId;

var Passport = require('maki-passport-local');
var passport = new Passport({
  resource: 'Person'
});

converse.use( passport );

converse.use({
  extends: {
    services: {
      http: {
        middleware: function(req, res, next) {
          if (!req.user) return next();
          Notification.Model.count({
            _to: req.user._id,
            status: 'unread'
          }, function(err, notificationCount) {
            res.locals.unreadNotifications = new Array(notificationCount);
            next();
          });
        }
      }
    }
  }
});

var Person = converse.define('Person', {
  attributes: {
    username: { type: String , max: 35 , required: true , slug: true },
    password: { type: String , max: 70 , masked: true },
    created:  { type: Date , default: Date.now , render: { query: false } },
    bio:      { type: String , max: 250 },
    image:    { type: 'File' }
  },
  icon: 'user'
});

/* converse.define('Board', {
  attributes: {
    name: { type: String, required: true, max: 200 , slug: true },
    description: { type: String, max: 1024 },
    created: { type: Date, required: true, default: Date.now },
    _creator: { type: ObjectId, required: true, ref: 'Person' },
    _owner: { type: ObjectId, required: true, ref: 'Person' },
    _moderators: [ { type: ObjectId, ref: 'Person' } ]
  },
  icon: 'slack'
}); */

var Post = converse.define('Post', {
  attributes: {
    created:     { type: Date, required: true, default: Date.now },
    hashcash:    { type: String },
    name:        { type: String, required: true, max: 200 },
    description: { type: String },
    sticky:      { type: Boolean , default: false },
    _author:     { type: ObjectId, required: true, ref: 'Person', populate: ['get', 'query'] },
    //_board:      { type: ObjectId, /* required: true, */ ref: 'Board' },
    link:        { type: String },
    score:       { type: Number , required: true , default: 0 },
    _document:     { type: ObjectId , ref: 'Document', populate: ['get', 'query'] },
    stats:       {
      comments:  { type: Number , default: 0 },
    },
    attribution: {
      _author: { type: ObjectId , ref: 'Person', populate: ['get', 'query'] }
    }
  },
  requires: {
    'Comment': {
      filter: function() {
        var post = this;
        return { _post: post._id , _parent: { $exists: false } };
      },
      populate: '_author _parent'
    }
  },
  icon: 'pin'
});

Post.pre('create', function(next, done) {
  var post = this;
  if (!post.link) return next();

  // TODO: automatic parsing
  Document.create({
    url: post.link,
    title: post.name,
    description: post.description
  }, function(err, document) {
    post._document = document._id;
    next();
  });
});

var Document = converse.define('Document', {
  attributes: {
    url: { type: String , required: true },
    title: { type: String , max: 1024 },
    description: { type: String , max: 1024 },
    image: { type: 'File' }
  }
});

var Comment = converse.define('Comment', {
  attributes: {
    _author: { type: ObjectId, required: true, ref: 'Person', populate: ['query', 'get'] },
    _post:   { type: ObjectId, required: true , ref: 'Post', populate: ['get'] },
    _parent: { type: ObjectId, ref: 'Comment' },
    created: { type: Date, required: true, default: Date.now },
    updated: { type: Date },
    hashcash: { type: String },
    content: { type: String, min: 1 },
    score: { type: Number , required: 0 , default: 0 },
    stats: {
      comments: { type: Number , default: 0 }
    }
  },
  requires: {
    'Comment': {
      filter: function() {
        var comment = this;
        return { _parent: comment._id };
      },
      populate: '_author _parent'
    }
  },
  handlers: {
    html: {
      create: function(req, res) {
        var comment = this;
        req.flash('info', 'Comment created successfully!');
        if (comment._parent) {
          res.status( 303 ).redirect('/comments/' + comment._parent + '#comments' + comment._id );
        } else {
          res.status( 303 ).redirect('/posts/' + comment._post );
        }

      }
    }
  },
  icon: 'comment'
});

Comment.post('create', function(next, cb) {
  var comment = this;

  var pipeline = {};

  pipeline.post = function updatePostStats(done) {
    Post.Model.update({
      _id: comment._post
    }, {
      $inc: { 'stats.comments': 1 }
    }, done);
  };

  pipeline.authorNotification = function notifyAuthor(done) {
    Post.get({ _id: comment._post }, function(err, post) {
      Notification.create({
        _to: post._author,
        _comment: comment._id
      }, done);
    });
  };

  if (comment._parent) {
    pipeline.parent = function updateParentComment(done) {
      Comment.Model.update({
        _id: comment._parent
      }, {
        $inc: { 'stats.comments': 1 }
      }, done);
    };

    pipeline.parentNotification = function notifyParentAuthor(done) {
      Comment.get({ _id: comment._parent }, function(err, parent) {
        Notification.create({
          _to: parent._author,
          _comment: comment._id
        }, done);
      });
    };
  }

  async.parallel(pipeline, function(err, results) {
    if (err) return cb(err);
    next();
  });

});

var Notification = converse.define('Notification', {
  attributes: {
    _to: { type: ObjectId , ref: 'Person', required: true },
    _comment: { type: ObjectId , ref: 'Comment', populate: ['query', 'get'] },
    created: { type: Date , required: true , default: Date.now },
    status: { type: String , enum: ['unread', 'read'], default: 'unread' }
  },
  handlers: {
    html: {
      query: function(req, res, next) {
        if (!req.user) return next();
        Notification.query({ _to: req.user._id }, function(err, notifications) {
          Comment.Model.populate(notifications, {
            path: '_comment'
          }, function(err, notifications) {
            Person.Model.populate(notifications, {
              path: '_comment._author'
            }, function(err, notifications) {
              Notification.Model.update({
                _id: {
                  $in: notifications.map(function(n) { return n._id; })
                }
              }, { $set: { status: 'read' } }, { multi: true }, function(err) {
                return res.render('notifications', {
                  notifications: notifications,
                  unreadNotifications: [] // a bit of a hack
                });
              });
            });
          });
        });
      }
    }
  }
});

var Tip = converse.define('Tip', {
  attributes: {
    _from: { type: ObjectId , ref: 'Person', required: true },
    _to: { type: ObjectId , ref: 'Person', required: true },
    _for: { type: ObjectId },
    context: { type: String , enum: ['post', 'comment'] },
    amount: { type: Number, ref: 'Person', required: true },
  }
});

Tip.post('create', function(next, cb) {
  var tip = this;

  var pipeline = {};

  pipeline.post = function updatePostStats(done) {
    if (tip.context === 'post') {
      Post.Model.update({
        _id: tip._for
      }, {
        $inc: { 'score': 1 }
      }, done);
    }
    if (tip.context === 'comment') {
      Comment.Model.update({
        _id: tip._for
      }, {
        $inc: { 'score': 1 }
      }, done);
    }
  };

  async.parallel(pipeline, function(err, results) {
    if (err) return cb(err);
    next();
  });
});

converse.define('Index', {
  name: 'Index',
  static: true,
  internal: true,
  routes: {
    query: '/'
  },
  templates: {
    query: 'posts'
  },
  requires: {
    'Post': {
      filter: {},
      populate: '_author _document',
      sort: '-score -created'
    }
  }
});

converse.start(function(err) {

});
<|endoftext|>


<commit_before>/// @file JSRootPainter.v7more.js
/// JavaScript ROOT v7 graphics for different classes

(function( factory ) {
   if ( typeof define === "function" && define.amd ) {
      define( ['JSRootPainter', 'd3'], factory );
   } else
   if (typeof exports === 'object' && typeof module !== 'undefined') {
       factory(require("./JSRootCore.js"), require("d3"));
   } else {

      if (typeof d3 != 'object')
         throw new Error('This extension requires d3.js', 'JSRootPainter.v7hist.js');

      if (typeof JSROOT == 'undefined')
         throw new Error('JSROOT is not defined', 'JSRootPainter.v7hist.js');

      if (typeof JSROOT.Painter != 'object')
         throw new Error('JSROOT.Painter not defined', 'JSRootPainter.v7hist.js');

      factory(JSROOT, d3);
   }
} (function(JSROOT, d3) {

   "use strict";

   JSROOT.sources.push("v7more");

   // =================================================================================

   function drawText() {
      var text         = this.GetObject(),
          opts         = text.fOpts,
          pp           = this.canv_painter(),
          w            = this.pad_width(),
          h            = this.pad_height(),
          use_frame    = false,
          text_size    = opts.fTextSize.fAttr,
          text_angle   = -opts.fTextAngle.fAttr,
          text_align   = opts.fTextAlign.fAttr,
          text_color   = pp.GetOldColor(opts.fTextColor),
          text_font    = opts.fTextFont.fAttr,
          p            = this.GetCoordinate(text.fP);

      this.CreateG(use_frame);

      var arg = { align: text_align, x: p.x, y: p.y, text: text.fText, rotate: text_angle, color: text_color, latex: 1 };

      // if (text.fTextAngle) arg.rotate = -text.fTextAngle;
      // if (text._typename == 'TLatex') { arg.latex = 1; fact = 0.9; } else
      // if (text._typename == 'TMathText') { arg.latex = 2; fact = 0.8; }

      this.StartTextDrawing(text_font, text_size);

      this.DrawText(arg);

      this.FinishTextDrawing();
   }

   function drawLine() {

       var line         = this.GetObject(),
           opts         = line.fOpts,
           pp           = this.canv_painter(),

           line_width   = pp.GetNewOpt(opts, "line.width", 1.),
           line_style   = pp.GetNewOpt(opts, "line.style", 1),
           line_color   = pp.GetNewColor(opts, "line.color", "black"),
           line_opacity = pp.GetNewColor(opts, "line.opacity", 1.),
           p1           = this.GetCoordinate(line.fP1),
           p2           = this.GetCoordinate(line.fP2);

    this.CreateG();

    this.draw_g
        .append("svg:line")
        .attr("x1", p1.x)
        .attr("y1", p1.y)
        .attr("x2", p2.x)
        .attr("y2", p2.y)
        .style("stroke", line_color)
        .attr("stroke-width", line_width)
        .attr("stroke-opacity", line_opacity)
        .style("stroke-dasharray", JSROOT.Painter.root_line_styles[line_style]);
   }

   function drawBox() {

       var box          = this.GetObject(),
           opts         = box.fOpts,
           pp           = this.canv_painter(),
           line_width   = opts.fLineWidth.fAttr,
           line_opacity = opts.fLineOpacity.fAttr,
           line_style   = opts.fLineStyle.fAttr,
           line_color   = pp.GetOldColor(opts.fLineColor),
           fill_opacity = opts.fFillOpacity.fAttr,
           fill_color   = pp.GetOldColor(opts.fFillColor),
           fill_style   = opts.fFillStyle.fAttr,
           round_width  = opts.fRoundWidth.fAttr,
           round_height = opts.fRoundHeight.fAttr,
           p1           = this.GetCoordinate(box.fP1),
           p2           = this.GetCoordinate(box.fP2);

    this.CreateG();

    if (fill_style == 0 ) fill_color = "none";

    this.draw_g
        .append("svg:rect")
        .attr("x", p1.x)
        .attr("width", p2.x-p1.x)
        .attr("y", p2.y)
        .attr("height", p1.y-p2.y)
        .attr("rx", round_width)
        .attr("ry", round_height)
        .style("stroke", line_color)
        .attr("stroke-width", line_width)
        .attr("stroke-opacity", line_opacity)
        .attr("fill", fill_color)
        .attr("fill-opacity", fill_opacity)
        .style("stroke-dasharray", JSROOT.Painter.root_line_styles[line_style]);
   }

   function drawMarker() {
       var marker         = this.GetObject(),
           opts           = marker.fOpts,
           pp             = this.canv_painter(),
           marker_size    = opts.fSize.fAttr,
           marker_opacity = opts.fOpacity.fAttr,
           marker_style   = opts.fStyle.fAttr,
           marker_color   = pp.GetOldColor(opts.fColor),
           p              = this.GetCoordinate(marker.fP);

           var att = new JSROOT.TAttMarkerHandler({ style: marker_style, color: marker_color, size: marker_size });

           this.CreateG();

           var  path = att.create(p.x, p.y);

           if (path)
              this.draw_g.append("svg:path")
                  .attr("d", path)
                  .call(att.func);
   }

   // ================================================================================

   JSROOT.v7.drawText   = drawText;
   JSROOT.v7.drawLine   = drawLine;
   JSROOT.v7.drawBox    = drawBox;
   JSROOT.v7.drawMarker = drawMarker;

   return JSROOT;

}));
<commit_msg>Fix - v7 line and box drawing<commit_after>/// @file JSRootPainter.v7more.js
/// JavaScript ROOT v7 graphics for different classes

(function( factory ) {
   if ( typeof define === "function" && define.amd ) {
      define( ['JSRootPainter', 'd3'], factory );
   } else
   if (typeof exports === 'object' && typeof module !== 'undefined') {
       factory(require("./JSRootCore.js"), require("d3"));
   } else {

      if (typeof d3 != 'object')
         throw new Error('This extension requires d3.js', 'JSRootPainter.v7hist.js');

      if (typeof JSROOT == 'undefined')
         throw new Error('JSROOT is not defined', 'JSRootPainter.v7hist.js');

      if (typeof JSROOT.Painter != 'object')
         throw new Error('JSROOT.Painter not defined', 'JSRootPainter.v7hist.js');

      factory(JSROOT, d3);
   }
} (function(JSROOT, d3) {

   "use strict";

   JSROOT.sources.push("v7more");

   // =================================================================================

   function drawText() {
      var text         = this.GetObject(),
          opts         = text.fOpts,
          pp           = this.canv_painter(),
          w            = this.pad_width(),
          h            = this.pad_height(),
          use_frame    = false,
          text_size    = opts.fTextSize.fAttr,
          text_angle   = -opts.fTextAngle.fAttr,
          text_align   = opts.fTextAlign.fAttr,
          text_color   = pp.GetOldColor(opts.fTextColor),
          text_font    = opts.fTextFont.fAttr,
          p            = this.GetCoordinate(text.fP);

      this.CreateG(use_frame);

      var arg = { align: text_align, x: p.x, y: p.y, text: text.fText, rotate: text_angle, color: text_color, latex: 1 };

      // if (text.fTextAngle) arg.rotate = -text.fTextAngle;
      // if (text._typename == 'TLatex') { arg.latex = 1; fact = 0.9; } else
      // if (text._typename == 'TMathText') { arg.latex = 2; fact = 0.8; }

      this.StartTextDrawing(text_font, text_size);

      this.DrawText(arg);

      this.FinishTextDrawing();
   }

   function drawLine() {

       var line         = this.GetObject(),
           opts         = line.fOpts,
           pp           = this.canv_painter(),

           line_width   = pp.GetNewOpt(opts, "line.width", 1),
           line_style   = pp.GetNewOpt(opts, "line.style", 1),
           line_color   = pp.GetNewColor(opts, "line.color", "black"),
           line_opacity = pp.GetNewOpt(opts, "line.opacity", 1),
           p1           = this.GetCoordinate(line.fP1),
           p2           = this.GetCoordinate(line.fP2);

    this.CreateG();

    this.draw_g
        .append("svg:line")
        .attr("x1", p1.x)
        .attr("y1", p1.y)
        .attr("x2", p2.x)
        .attr("y2", p2.y)
        .style("stroke", line_color)
        .attr("stroke-width", line_width)
        .attr("stroke-opacity", line_opacity)
        .style("stroke-dasharray", JSROOT.Painter.root_line_styles[line_style]);
   }

   function drawBox() {

       var box          = this.GetObject(),
           opts         = box.fOpts,
           pp           = this.canv_painter(),
           line_width   = pp.GetNewOpt(opts, "box.border.width", 1),
           line_opacity = pp.GetNewOpt(opts, "box.border.opacity", 1),
           line_style   = pp.GetNewOpt(opts, "box.border.style", 1),
           line_color   = pp.GetNewColor(opts, "box.border.color", "black"),
           fill_opacity = pp.GetNewOpt(opts, "box.fill.opacity", 1),
           fill_color   = pp.GetNewColor(opts, "box.fill.color", "white"),
           fill_style   = pp.GetNewOpt(opts, "box.fill.style", 1),
           round_width  = pp.GetNewOpt(opts, "box.round.width", 0),
           round_height = pp.GetNewOpt(opts, "box.round.height", 0),
           p1           = this.GetCoordinate(box.fP1),
           p2           = this.GetCoordinate(box.fP2);

    this.CreateG();

    if (fill_style == 0 ) fill_color = "none";

    this.draw_g
        .append("svg:rect")
        .attr("x", p1.x)
        .attr("width", p2.x-p1.x)
        .attr("y", p2.y)
        .attr("height", p1.y-p2.y)
        .attr("rx", round_width)
        .attr("ry", round_height)
        .style("stroke", line_color)
        .attr("stroke-width", line_width)
        .attr("stroke-opacity", line_opacity)
        .attr("fill", fill_color)
        .attr("fill-opacity", fill_opacity)
        .style("stroke-dasharray", JSROOT.Painter.root_line_styles[line_style]);
   }

   function drawMarker() {
       var marker         = this.GetObject(),
           opts           = marker.fOpts,
           pp             = this.canv_painter(),
           marker_size    = opts.fSize.fAttr,
           marker_opacity = opts.fOpacity.fAttr,
           marker_style   = opts.fStyle.fAttr,
           marker_color   = pp.GetOldColor(opts.fColor),
           p              = this.GetCoordinate(marker.fP);

           var att = new JSROOT.TAttMarkerHandler({ style: marker_style, color: marker_color, size: marker_size });

           this.CreateG();

           var  path = att.create(p.x, p.y);

           if (path)
              this.draw_g.append("svg:path")
                  .attr("d", path)
                  .call(att.func);
   }

   // ================================================================================

   JSROOT.v7.drawText   = drawText;
   JSROOT.v7.drawLine   = drawLine;
   JSROOT.v7.drawBox    = drawBox;
   JSROOT.v7.drawMarker = drawMarker;

   return JSROOT;

}));
<|endoftext|>