<commit_before>// go.campaign.dialogue.states
// ===========================
// Structures for each dialogue state type

(function(exports) {
  var maybeByName = go.utils.maybeByName,
      GridView = go.components.grid.GridView,
      ConfirmView = go.components.views.ConfirmView,
      TemplateView = go.components.views.TemplateView;

  var plumbing = go.components.plumbing;

  var states = plumbing.states,
      StateView = states.StateView,
      StateViewCollection = states.StateViewCollection;

  var endpoints = plumbing.endpoints,
      ParametricEndpointView = endpoints.ParametricEndpointView,
      AligningEndpointCollection = endpoints.AligningEndpointCollection;

  var DialogueEndpointView = ParametricEndpointView.extend();

  var EntryEndpointView = DialogueEndpointView.extend({
    side: 'left',
    isSource: false
  });

  var ExitEndpointView = DialogueEndpointView.extend({
    side: 'right',
    isTarget: false
  });

  // Base 'mode' for state views. Each mode acts as a 'delegate view',
  // targeting a dialogue view's element and acting according to the mode type
  // (for eg, `edit`) and state type (for eg, `freetext`).
  var DialogueStateModeView = TemplateView.extend({
    data: function() {
      return {
        mode: this,
        state: this.state,
        model: this.state.model
      };
    },

    bodyOptions: {},

    initialize: function(options) {
      DialogueStateModeView.__super__.initialize.call(this, options);
      this.state = options.state;

      this.partials.body = new TemplateView(
        _({data: this.data.bind(this)}).extend(
        _(this).result('bodyOptions')));
    },

    destroy: function() {
      this.$el.remove();
      return this;
    },

    detach: function() {
      this.$el.detach();
      return this;
    }
  });

  // Mode allowing the user to make changes to the dialogue state. Acts as a
  // base for each state type's `edit` mode
  var DialogueStateEditView = DialogueStateModeView.extend({
    jst: 'JST.campaign_dialogue_states_modes_edit',

    className: 'edit mode',

    events: {
      'click .ok': 'onOk',
      'click .cancel': 'onCancel',
      'change .type': 'onTypeChange',
      'change .name': 'onNameChange'
    },

    resetModal: new ConfirmView({
      optional: true,
      content: "Changing the message's type will break its connections " +
               "and reset its content."
    }),

    initialize: function(options) {
      DialogueStateEditView.__super__.initialize.call(this, options);
      this.backupModel();

      this.on('activate', this.backupModel, this);
    },

    onOk: function(e) {
      e.preventDefault();
      this.state.preview();
    },

    onCancel: function(e) {
      e.preventDefault();
      this.cancel();
      this.state.preview();
    },

    onTypeChange: function(e) {
      var $option = $(e.target);

      // Using `on` is okay, since the events are unbound when either of the
      // buttons are clicked. Simply using `once` won't work, since the event
      // for the unclicked button will remain bound.
      this.resetModal
        .on(
          'ok',
          function() { this.state.reset($option.val()); }, this)
        .on(
          'cancel',
          function() { this.$('.type').val(this.state.typeName); }, this)
        .show();
    },

    onNameChange: function(e) {
      this.state.model.set('name', $(e.target).val(), {silent: true});
      return this;
    },

    // Keep a backup to restore the model for when the user cancels the edit
    backupModel: function() {
      this.modelBackup = this.state.model.toJSON();
      return this;
    },

    cancel: function() {
      var model = this.state.model;
      if (this.modelBackup) { model.set(this.modelBackup); }
      return this;
    },

    render: function() {
      DialogueStateEditView.__super__.render.call(this);
      this.$('.type').val(this.state.typeName);
      return this;
    }
  });

  // Mode for a 'read-only' preview of the dialogue state. Acts as a base for
  // each state type's `preview` mode
  var DialogueStatePreviewView = DialogueStateModeView.extend({
    jst: 'JST.campaign_dialogue_states_modes_preview',

    className: 'preview mode',

    events: {
      'click .edit-switch': 'onEditSwitch'
    },

    onEditSwitch: function(e) {
      e.preventDefault();
      this.state.edit();
    }
  });

  // Base view for dialogue states. Dynamically switches between modes
  // (`edit`, `preview`).
  var DialogueStateView = StateView.extend({
    switchModeDefaults: {render: true, silent: false},

    className: function() { return 'box item state ' + this.typeName || ''; },

    editModeType: DialogueStateEditView,
    previewModeType: DialogueStatePreviewView,

    endpointType: DialogueEndpointView,
    endpointCollectionType: AligningEndpointCollection,

    subtypes: {
      dummy: 'go.campaign.dialogue.states.dummy.DummyStateView',
      choice: 'go.campaign.dialogue.states.choice.ChoiceStateView',
      freetext: 'go.campaign.dialogue.states.freetext.FreeTextStateView',
      end: 'go.campaign.dialogue.states.end.EndStateView'
    },

    events: {
      'mousedown .titlebar': 'onTitlebarHold',
      'click .titlebar .remove': 'onRemove'
    },

    initialize: function(options) {
      StateView.prototype.initialize.call(this, options);

      if (!this.model.has('ordinal')) {
        this.model.set('ordinal', this.collection.size(), {silent: true});
      }

      this.modes = {
        edit: new this.editModeType({state: this}),
        preview: new this.previewModeType({state: this})
      };

      this.switchMode(options.mode || 'preview', {render: false});
    },

    onTitlebarHold: function(e) {
      if (this.isConnected()) { this.$el.addClass('locked'); }
      else { this.$el.removeClass('locked'); }
    },

    onRemove: function(e) {
      e.preventDefault();
      this.collection.remove(this);
    },

    // 'Resets' a state to a new type by removing the current state, and
    // replacing it with a new state in the same position
    reset: function(type) {
      // TODO warn the user of the destruction involved
      this.collection.reset(this, type);
    },

    switchMode: function(modeName, options) {
      options = _(options || {}).defaults(this.switchModeDefaults);
      var mode = this.modes[modeName] || this.modes.preview;

      if (this.mode) {
        if (!options.silent) { this.mode.trigger('deactivate'); }
        this.mode.detach();
      }

      this.mode = mode;
      this.modeName = modeName;

      if (!options.silent) { this.mode.trigger('activate'); }
      if (options.render) {
        this.render();
        jsPlumb.repaintEverything();
      }
      return this;
    },

    preview: function(options) {
      return this.switchMode('preview', options);
    },

    edit: function(options) {
      return this.switchMode('edit', options);
    },

    render: function() {
      this.mode
        .render()
        .$el
        .appendTo(this.$el);

      this.endpoints.render();
      return this;
    }
  });

  var DialogueStateGridView = GridView.extend({
    className: 'grid container boxes',

    events: {
      'click .add': 'onAddClick'
    },

    sortableOptions: {
      items: '.item:not(.add-container)',
      cancel: '.locked,input',
      handle: '.titlebar',
      placeholder: 'placeholder',
      sort: function() { jsPlumb.repaintEverything(); },
      stop: function() { jsPlumb.repaintEverything(); }
    },

    initialize: function(options) {
      DialogueStateGridView.__super__.initialize.call(this, options);

      this.states = options.states;
      this.states.eachItem(
        function(id, state) { this.addState(id, state, {sort: false}); },
        this);
      this.items.sort();

      var $add = $('<button>')
        .addClass('add btn btn-primary')
        .text('+');

      var $addContainer = $('<div>')
        .addClass('item add-container')
        .append($add);

      this.add('add-btn', $addContainer, {index: Infinity});

      this.listenTo(this.states, 'add', this.addState);
      this.listenTo(this.states, 'remove', this.remove);
      this.on('reorder', this.onReorder, this);
    },

    onAddClick: function(e) {
      e.preventDefault();
      this.states.add();
    },

    onReorder: function(keys) {
      // The grid items have their indices reset when the user sorts the items
      // in the UI. We need to ensure the add button stays at the end, so we
      // need to change it back to `Infinity` each reorder
      this.items
        .get('add-btn')
        .data('grid:index', Infinity);

      // Remove the add button from the keys
      keys.pop();

      this.states.rearrange(keys);
    },

    addState: function(id, state, options) {
      options = _(options || {}).defaults({index: state.model.get('ordinal')});
      return this.add(id, state, options);
    }
  });

  var DialogueStateCollection = StateViewCollection.extend({
    type: DialogueStateView,

    ordered: true,
    comparator: function(state) { return state.model.get('ordinal'); },

    arrangeable: true,
    arranger: function(state, ordinal) {
      state.model.set('ordinal', ordinal, {silent: true});
    },

    defaultMode: 'preview',

    viewOptions: function() {
      var opts = DialogueStateCollection.__super__.viewOptions.call(this);
      return _({mode: this.defaultMode}).defaults(opts);
    },

    modelDefaults: function() {
      return {
        type: 'choice',
        name: '',
        ordinal: this.size()
      };
    },

    constructor: function(options) {
      DialogueStateCollection.__super__.constructor.call(this, options);
      this.grid = new DialogueStateGridView({states: this});

      // Change the default mode to edit once initialisation is done so new
      // states can be rendered in edit mode.
      this.defaultMode = 'edit';
    },

    // Removes a state and creates a new state of a different type in the same
    // position as the old state
    reset: function(state, type) {
      this.remove(state);

      this.add({
        model: {
          type: type,
          name: state.model.get('name'),
          ordinal: state.model.get('ordinal')
        }
      });

      return this;
    },

    render: function() {
      this.view.$el.append(this.grid.$el);
      this.grid.render();

      this.each(function(s) { s.render(); });
      return this;
    }
  });

  _(exports).extend({
    EntryEndpointView: EntryEndpointView,
    ExitEndpointView: ExitEndpointView,

    DialogueStateModeView: DialogueStateModeView,
    DialogueStatePreviewView: DialogueStatePreviewView,
    DialogueStateEditView: DialogueStateEditView,

    DialogueStateView: DialogueStateView,
    DialogueStateGridView: DialogueStateGridView,
    DialogueStateCollection: DialogueStateCollection
  });
})(go.campaign.dialogue.states = {});
<commit_msg>Namespace '.ok' and '.cancel' click events better to avoid conflict with the 'ok' and 'cancel' buttons in choice extras<commit_after>// go.campaign.dialogue.states
// ===========================
// Structures for each dialogue state type

(function(exports) {
  var maybeByName = go.utils.maybeByName,
      GridView = go.components.grid.GridView,
      ConfirmView = go.components.views.ConfirmView,
      TemplateView = go.components.views.TemplateView;

  var plumbing = go.components.plumbing;

  var states = plumbing.states,
      StateView = states.StateView,
      StateViewCollection = states.StateViewCollection;

  var endpoints = plumbing.endpoints,
      ParametricEndpointView = endpoints.ParametricEndpointView,
      AligningEndpointCollection = endpoints.AligningEndpointCollection;

  var DialogueEndpointView = ParametricEndpointView.extend();

  var EntryEndpointView = DialogueEndpointView.extend({
    side: 'left',
    isSource: false
  });

  var ExitEndpointView = DialogueEndpointView.extend({
    side: 'right',
    isTarget: false
  });

  // Base 'mode' for state views. Each mode acts as a 'delegate view',
  // targeting a dialogue view's element and acting according to the mode type
  // (for eg, `edit`) and state type (for eg, `freetext`).
  var DialogueStateModeView = TemplateView.extend({
    data: function() {
      return {
        mode: this,
        state: this.state,
        model: this.state.model
      };
    },

    bodyOptions: {},

    initialize: function(options) {
      DialogueStateModeView.__super__.initialize.call(this, options);
      this.state = options.state;

      this.partials.body = new TemplateView(
        _({data: this.data.bind(this)}).extend(
        _(this).result('bodyOptions')));
    },

    destroy: function() {
      this.$el.remove();
      return this;
    },

    detach: function() {
      this.$el.detach();
      return this;
    }
  });

  // Mode allowing the user to make changes to the dialogue state. Acts as a
  // base for each state type's `edit` mode
  var DialogueStateEditView = DialogueStateModeView.extend({
    jst: 'JST.campaign_dialogue_states_modes_edit',

    className: 'edit mode',

    events: {
      'click .actions .ok': 'onOk',
      'click .actions .cancel': 'onCancel',
      'change .type': 'onTypeChange',
      'change .name': 'onNameChange'
    },

    resetModal: new ConfirmView({
      optional: true,
      content: "Changing the message's type will break its connections " +
               "and reset its content."
    }),

    initialize: function(options) {
      DialogueStateEditView.__super__.initialize.call(this, options);
      this.backupModel();

      this.on('activate', this.backupModel, this);
    },

    onOk: function(e) {
      e.preventDefault();
      this.state.preview();
    },

    onCancel: function(e) {
      e.preventDefault();
      this.cancel();
      this.state.preview();
    },

    onTypeChange: function(e) {
      var $option = $(e.target);

      // Using `on` is okay, since the events are unbound when either of the
      // buttons are clicked. Simply using `once` won't work, since the event
      // for the unclicked button will remain bound.
      this.resetModal
        .on(
          'ok',
          function() { this.state.reset($option.val()); }, this)
        .on(
          'cancel',
          function() { this.$('.type').val(this.state.typeName); }, this)
        .show();
    },

    onNameChange: function(e) {
      this.state.model.set('name', $(e.target).val(), {silent: true});
      return this;
    },

    // Keep a backup to restore the model for when the user cancels the edit
    backupModel: function() {
      this.modelBackup = this.state.model.toJSON();
      return this;
    },

    cancel: function() {
      var model = this.state.model;
      if (this.modelBackup) { model.set(this.modelBackup); }
      return this;
    },

    render: function() {
      DialogueStateEditView.__super__.render.call(this);
      this.$('.type').val(this.state.typeName);
      return this;
    }
  });

  // Mode for a 'read-only' preview of the dialogue state. Acts as a base for
  // each state type's `preview` mode
  var DialogueStatePreviewView = DialogueStateModeView.extend({
    jst: 'JST.campaign_dialogue_states_modes_preview',

    className: 'preview mode',

    events: {
      'click .edit-switch': 'onEditSwitch'
    },

    onEditSwitch: function(e) {
      e.preventDefault();
      this.state.edit();
    }
  });

  // Base view for dialogue states. Dynamically switches between modes
  // (`edit`, `preview`).
  var DialogueStateView = StateView.extend({
    switchModeDefaults: {render: true, silent: false},

    className: function() { return 'box item state ' + this.typeName || ''; },

    editModeType: DialogueStateEditView,
    previewModeType: DialogueStatePreviewView,

    endpointType: DialogueEndpointView,
    endpointCollectionType: AligningEndpointCollection,

    subtypes: {
      dummy: 'go.campaign.dialogue.states.dummy.DummyStateView',
      choice: 'go.campaign.dialogue.states.choice.ChoiceStateView',
      freetext: 'go.campaign.dialogue.states.freetext.FreeTextStateView',
      end: 'go.campaign.dialogue.states.end.EndStateView'
    },

    events: {
      'mousedown .titlebar': 'onTitlebarHold',
      'click .titlebar .remove': 'onRemove'
    },

    initialize: function(options) {
      StateView.prototype.initialize.call(this, options);

      if (!this.model.has('ordinal')) {
        this.model.set('ordinal', this.collection.size(), {silent: true});
      }

      this.modes = {
        edit: new this.editModeType({state: this}),
        preview: new this.previewModeType({state: this})
      };

      this.switchMode(options.mode || 'preview', {render: false});
    },

    onTitlebarHold: function(e) {
      if (this.isConnected()) { this.$el.addClass('locked'); }
      else { this.$el.removeClass('locked'); }
    },

    onRemove: function(e) {
      e.preventDefault();
      this.collection.remove(this);
    },

    // 'Resets' a state to a new type by removing the current state, and
    // replacing it with a new state in the same position
    reset: function(type) {
      // TODO warn the user of the destruction involved
      this.collection.reset(this, type);
    },

    switchMode: function(modeName, options) {
      options = _(options || {}).defaults(this.switchModeDefaults);
      var mode = this.modes[modeName] || this.modes.preview;

      if (this.mode) {
        if (!options.silent) { this.mode.trigger('deactivate'); }
        this.mode.detach();
      }

      this.mode = mode;
      this.modeName = modeName;

      if (!options.silent) { this.mode.trigger('activate'); }
      if (options.render) {
        this.render();
        jsPlumb.repaintEverything();
      }
      return this;
    },

    preview: function(options) {
      return this.switchMode('preview', options);
    },

    edit: function(options) {
      return this.switchMode('edit', options);
    },

    render: function() {
      this.mode
        .render()
        .$el
        .appendTo(this.$el);

      this.endpoints.render();
      return this;
    }
  });

  var DialogueStateGridView = GridView.extend({
    className: 'grid container boxes',

    events: {
      'click .add': 'onAddClick'
    },

    sortableOptions: {
      items: '.item:not(.add-container)',
      cancel: '.locked,input',
      handle: '.titlebar',
      placeholder: 'placeholder',
      sort: function() { jsPlumb.repaintEverything(); },
      stop: function() { jsPlumb.repaintEverything(); }
    },

    initialize: function(options) {
      DialogueStateGridView.__super__.initialize.call(this, options);

      this.states = options.states;
      this.states.eachItem(
        function(id, state) { this.addState(id, state, {sort: false}); },
        this);
      this.items.sort();

      var $add = $('<button>')
        .addClass('add btn btn-primary')
        .text('+');

      var $addContainer = $('<div>')
        .addClass('item add-container')
        .append($add);

      this.add('add-btn', $addContainer, {index: Infinity});

      this.listenTo(this.states, 'add', this.addState);
      this.listenTo(this.states, 'remove', this.remove);
      this.on('reorder', this.onReorder, this);
    },

    onAddClick: function(e) {
      e.preventDefault();
      this.states.add();
    },

    onReorder: function(keys) {
      // The grid items have their indices reset when the user sorts the items
      // in the UI. We need to ensure the add button stays at the end, so we
      // need to change it back to `Infinity` each reorder
      this.items
        .get('add-btn')
        .data('grid:index', Infinity);

      // Remove the add button from the keys
      keys.pop();

      this.states.rearrange(keys);
    },

    addState: function(id, state, options) {
      options = _(options || {}).defaults({index: state.model.get('ordinal')});
      return this.add(id, state, options);
    }
  });

  var DialogueStateCollection = StateViewCollection.extend({
    type: DialogueStateView,

    ordered: true,
    comparator: function(state) { return state.model.get('ordinal'); },

    arrangeable: true,
    arranger: function(state, ordinal) {
      state.model.set('ordinal', ordinal, {silent: true});
    },

    defaultMode: 'preview',

    viewOptions: function() {
      var opts = DialogueStateCollection.__super__.viewOptions.call(this);
      return _({mode: this.defaultMode}).defaults(opts);
    },

    modelDefaults: function() {
      return {
        type: 'choice',
        name: '',
        ordinal: this.size()
      };
    },

    constructor: function(options) {
      DialogueStateCollection.__super__.constructor.call(this, options);
      this.grid = new DialogueStateGridView({states: this});

      // Change the default mode to edit once initialisation is done so new
      // states can be rendered in edit mode.
      this.defaultMode = 'edit';
    },

    // Removes a state and creates a new state of a different type in the same
    // position as the old state
    reset: function(state, type) {
      this.remove(state);

      this.add({
        model: {
          type: type,
          name: state.model.get('name'),
          ordinal: state.model.get('ordinal')
        }
      });

      return this;
    },

    render: function() {
      this.view.$el.append(this.grid.$el);
      this.grid.render();

      this.each(function(s) { s.render(); });
      return this;
    }
  });

  _(exports).extend({
    EntryEndpointView: EntryEndpointView,
    ExitEndpointView: ExitEndpointView,

    DialogueStateModeView: DialogueStateModeView,
    DialogueStatePreviewView: DialogueStatePreviewView,
    DialogueStateEditView: DialogueStateEditView,

    DialogueStateView: DialogueStateView,
    DialogueStateGridView: DialogueStateGridView,
    DialogueStateCollection: DialogueStateCollection
  });
})(go.campaign.dialogue.states = {});
<|endoftext|>


<commit_before>
dateEqual = function(a, b, message) {
  var format = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}{tz}'
  var buffer = 50; // Number of milliseconds of "play" to make sure these tests pass.
  if(typeof b == 'number') {
    var d = new Date();
    d.setTime(d.getTime() + b);
    b = d;
  }
  var offset = Math.abs(a.getTime() - b.getTime());
  equal(offset < buffer, true, message + ' | expected: ' + b.format(format) + ' got: ' + a.format(format));
}

dateRangeEqual = function(a, b, message) {
  dateEqual(a.start, b.start, message);
  dateEqual(a.end, b.end, message);
}

getRelativeDate = function(year, month, day, hours, minutes, seconds, milliseconds) {
  var d = this.getFullYear ? new Date(this.getTime()) : new Date();
  var setYear  = d.getFullYear() + (year || 0)
  var setMonth = d.getMonth() + (month || 0)
  var setDate  = d.getDate() + (day || 0);
  // Relative dates that have no more specificity than months only walk
  // the bounds of months, they can't traverse into a new month if the
  // target month doesn't have the same number of days.
  if(day === undefined && month !== undefined) {
    setDate = Math.min(setDate, new Date(setYear, setMonth).daysInMonth());
    d.setDate(setDate);
  }
  d.setFullYear(setYear);
  d.setMonth(setMonth);
  d.setDate(setDate);
  d.setHours(d.getHours() + (hours || 0));
  d.setMinutes(d.getMinutes() + (minutes || 0));
  d.setSeconds(d.getSeconds() + (seconds || 0));
  d.setMilliseconds(d.getMilliseconds() + (milliseconds || 0));
  return d;
}

getUTCDate = function(year, month, day, hours, minutes, seconds, milliseconds) {
  var d = new Date();
  if(year) d.setFullYear(year);
  d.setUTCDate(15); // Pre-emptively preventing a month overflow situation
  d.setUTCMonth(month === undefined ? 0 : month - 1);
  d.setUTCDate(day === undefined ? 1 : day);
  d.setUTCHours(hours === undefined ? 0 : hours);
  d.setUTCMinutes(minutes === undefined ? 0 : minutes);
  d.setUTCSeconds(seconds === undefined ? 0 : seconds);
  d.setUTCMilliseconds(milliseconds === undefined ? 0 : milliseconds);
  return d;
}

getDateWithWeekdayAndOffset = function(weekday, offset, hours, minutes, seconds, milliseconds) {
  var d = new Date();
  if(offset) d.setDate(d.getDate() + offset);
  d.setDate(d.getDate() + (weekday - d.getDay()));
  d.setHours(hours || 0);
  d.setMinutes(minutes || 0);
  d.setSeconds(seconds || 0);
  d.setMilliseconds(milliseconds || 0);
  return d;
}

getDaysInMonth = function(year, month) {
  return 32 - new Date(year, month, 32).getDate();
}

getWeekdayFromDate = function(d, utc) {
  var day = utc ? d.getUTCDay() : d.getDay();
  return ['sunday','monday','tuesday','wednesday','thursday','friday','saturday','sunday'][day];
}

getMonthFromDate = function(d, utc) {
  var month = utc ? d.getUTCMonth() : d.getMonth();
  return ['january','february','march','april','may','june','july','august','september','october','november','december'][month];
}

getHours = function(num) {
  return Math.floor(num < 0 ? 24 + num : num);
}

toUTC = function(d) {
  return d.addMinutes(-d.getTimezoneOffset());
}
<commit_msg>Fix dateEqual error not showing right file in test reports<commit_after>
dateEqual = function(a, b, message) {
  var format = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}{tz}'
  var buffer = 50; // Number of milliseconds of "play" to make sure these tests pass.
  if(typeof b == 'number') {
    var d = new Date();
    d.setTime(d.getTime() + b);
    b = d;
  }
  var offset = Math.abs(a.getTime() - b.getTime());
  equal(offset < buffer, true, message + ' | expected: ' + b.format(format) + ' got: ' + a.format(format), null, 1);
}

dateRangeEqual = function(a, b, message) {
  dateEqual(a.start, b.start, message);
  dateEqual(a.end, b.end, message);
}

getRelativeDate = function(year, month, day, hours, minutes, seconds, milliseconds) {
  var d = this.getFullYear ? new Date(this.getTime()) : new Date();
  var setYear  = d.getFullYear() + (year || 0)
  var setMonth = d.getMonth() + (month || 0)
  var setDate  = d.getDate() + (day || 0);
  // Relative dates that have no more specificity than months only walk
  // the bounds of months, they can't traverse into a new month if the
  // target month doesn't have the same number of days.
  if(day === undefined && month !== undefined) {
    setDate = Math.min(setDate, new Date(setYear, setMonth).daysInMonth());
    d.setDate(setDate);
  }
  d.setFullYear(setYear);
  d.setMonth(setMonth);
  d.setDate(setDate);
  d.setHours(d.getHours() + (hours || 0));
  d.setMinutes(d.getMinutes() + (minutes || 0));
  d.setSeconds(d.getSeconds() + (seconds || 0));
  d.setMilliseconds(d.getMilliseconds() + (milliseconds || 0));
  return d;
}

getUTCDate = function(year, month, day, hours, minutes, seconds, milliseconds) {
  var d = new Date();
  if(year) d.setFullYear(year);
  d.setUTCDate(15); // Pre-emptively preventing a month overflow situation
  d.setUTCMonth(month === undefined ? 0 : month - 1);
  d.setUTCDate(day === undefined ? 1 : day);
  d.setUTCHours(hours === undefined ? 0 : hours);
  d.setUTCMinutes(minutes === undefined ? 0 : minutes);
  d.setUTCSeconds(seconds === undefined ? 0 : seconds);
  d.setUTCMilliseconds(milliseconds === undefined ? 0 : milliseconds);
  return d;
}

getDateWithWeekdayAndOffset = function(weekday, offset, hours, minutes, seconds, milliseconds) {
  var d = new Date();
  if(offset) d.setDate(d.getDate() + offset);
  d.setDate(d.getDate() + (weekday - d.getDay()));
  d.setHours(hours || 0);
  d.setMinutes(minutes || 0);
  d.setSeconds(seconds || 0);
  d.setMilliseconds(milliseconds || 0);
  return d;
}

getDaysInMonth = function(year, month) {
  return 32 - new Date(year, month, 32).getDate();
}

getWeekdayFromDate = function(d, utc) {
  var day = utc ? d.getUTCDay() : d.getDay();
  return ['sunday','monday','tuesday','wednesday','thursday','friday','saturday','sunday'][day];
}

getMonthFromDate = function(d, utc) {
  var month = utc ? d.getUTCMonth() : d.getMonth();
  return ['january','february','march','april','may','june','july','august','september','october','november','december'][month];
}

getHours = function(num) {
  return Math.floor(num < 0 ? 24 + num : num);
}

toUTC = function(d) {
  return d.addMinutes(-d.getTimezoneOffset());
}
<|endoftext|>


<commit_before>require('cesium/Source/Widgets/widgets.css');

var _ = require('lodash');
var csvParser = require('csv-parse');
var d3 = require("d3");
var config = require('config');
var Cesium = getModules();

Cesium.BuildModuleUrl.setBaseUrl('./');
Cesium.BingMapsApi.defaultKey = config.bingMapsKey;

var viewer = new Cesium.Viewer('cesiumContainer', {
  targetFrameRate: 60,
  homeButton: false,
  sceneModePicker: false,
  navigationHelpButton: false,
  baseLayerPicker: false,
  fullscreenButton: false,
  animation: false,
  timeline: false,
  infoBox: false,
  imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
    url: '//services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer',
    enablePickFeatures: false
  }),
  //Saves GPU memory
  scene3DOnly: true,
  automaticallyTrackDataSourceClocks: false
});

viewer.scene.debugShowFramesPerSecond = config.debugShowFramesPerSecond;
viewer.scene.screenSpaceCameraController.enableTranslate = false;
viewer.scene.screenSpaceCameraController.enableTilt = false;
viewer.scene.screenSpaceCameraController.enableLook = false;
viewer.scene.screenSpaceCameraController.enableCollisionDetection = false;
// viewer.scene.screenSpaceCameraController.minimumZoomDistance = 100100;
// viewer.scene.screenSpaceCameraController.maximumZoomDistance = 160000000;
// viewer.scene.screenSpaceCameraController._minimumZoomRate = 50000;
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

viewer.imageryLayers.get(0).brightness = 0.7;

function mapGazes(gazes) {
  var fov = 1.0471975511965976;
  //TODO: Get aspect ratio
  //aspectRatio = canvas.clientWidth / canvas.clientHeight
  var aspectRatio = 1.5;

  _.chain(gazes)
    .filter(function (gaze) {
      return gaze.gazeX <= 0.5;
    })
    // .slice(0, 4)
    .forEach(function (gaze) {
      var frustumHeight = 2 * gaze.cameraZ * Math.tan(fov * 0.5) / 111111;

      //TODO: More accurate meters->degrees calculation
      var frustum = {
        x: gaze.cameraX,
        y: gaze.cameraY,
        height: frustumHeight,
        width: frustumHeight * aspectRatio
      };

      // Convert gaze coordinates into longitude and latitude
      var gazeXMap = d3.scale.linear()
        .domain([0, 0.5])
        .range([frustum.x - frustum.width / 2, frustum.x + frustum.width / 2]);

      var gazeYMap = d3.scale.linear()
        .domain([0, 1])
        .range([frustum.y - frustum.height / 2, frustum.y + frustum.height / 2]);

      //TODO: Fix the gaze mapping so it works properly.
      // console.log("frustum", frustum);
      // console.log("gazeXMap(gaze.gazeX), gazeYMap(gaze.gazeY)", gazeXMap(gaze.gazeX), gazeYMap(gaze.gazeY));
      // console.log("Degrees", Cesium.Cartesian3.fromDegrees(gazeXMap(gaze.gazeX), gazeYMap(gaze.gazeY)));
      viewer.entities.add({
        position: new Cesium.ConstantPositionProperty(Cesium.Cartesian3.fromDegrees(gazeXMap(gaze.gazeX), gazeYMap(gaze.gazeY))),
        point: new Cesium.PointGraphics({pixelSize: 2})
      });
    }).value();
}

//Load in CSV
//main
(function main() {
  asyncLoadCsv(config.gaze, function (gaze) {
    //Create Cesium elements?
    mapGazes(gaze);
  });
})();

//Using camera (x, y, z), map each gaze point appropriately. Gaze x is only between 0 and 0.5
function asyncLoadCsv(filename, cb) {
  fetch(filename)
    .then(function (response) {
      return response.text();
    })
    .then(function (data) {
      csvParser(data, {columns: true, auto_parse: true}, function (err, csv) {
        if (err) {
          throw err;
        }
        else {
          return cb(csv);
        }
      });
    })
    .catch(function (err) {
      console.log(filename, err)
    });
}

function getModules() {
  return {
    BuildModuleUrl: require('cesium/Source/Core/buildModuleUrl'),
    BingMapsApi: require('cesium/Source/Core/BingMapsApi'),
    ArcGisMapServerImageryProvider: require('cesium/Source/Scene/ArcGisMapServerImageryProvider'),
    Viewer: require('cesium/Source/Widgets/Viewer/Viewer'),
    ConstantPositionProperty: require('cesium/Source/DataSources/ConstantPositionProperty'),
    Cartesian3: require('cesium/Source/Core/Cartesian3'),
    ScreenSpaceEventType: require('cesium/Source/Core/ScreenSpaceEventType'),
    PointGraphics: require('cesium/Source/DataSources/PointGraphics')
  };
}
<commit_msg>Limiting which points are plotted. Still evenly distributed however<commit_after>require('cesium/Source/Widgets/widgets.css');

var _ = require('lodash');
var csvParser = require('csv-parse');
var d3 = require("d3");
var config = require('config');
var Cesium = getModules();

Cesium.BuildModuleUrl.setBaseUrl('./');
Cesium.BingMapsApi.defaultKey = config.bingMapsKey;

var viewer = new Cesium.Viewer('cesiumContainer', {
  targetFrameRate: 60,
  homeButton: false,
  sceneModePicker: false,
  navigationHelpButton: false,
  baseLayerPicker: false,
  fullscreenButton: false,
  animation: false,
  timeline: false,
  infoBox: false,
  imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
    url: '//services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer',
    enablePickFeatures: false
  }),
  //Saves GPU memory
  scene3DOnly: true,
  automaticallyTrackDataSourceClocks: false
});

viewer.scene.debugShowFramesPerSecond = config.debugShowFramesPerSecond;
viewer.scene.screenSpaceCameraController.enableTranslate = false;
viewer.scene.screenSpaceCameraController.enableTilt = false;
viewer.scene.screenSpaceCameraController.enableLook = false;
viewer.scene.screenSpaceCameraController.enableCollisionDetection = false;
// viewer.scene.screenSpaceCameraController.minimumZoomDistance = 100100;
// viewer.scene.screenSpaceCameraController.maximumZoomDistance = 160000000;
// viewer.scene.screenSpaceCameraController._minimumZoomRate = 50000;
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

viewer.imageryLayers.get(0).brightness = 0.7;

function mapGazes(gazes) {
  var fov = 1.0471975511965976;
  //TODO: Get aspect ratio
  //aspectRatio = canvas.clientWidth / canvas.clientHeight
  var aspectRatio = 1.5;
  var inRange = 0;
  var outRange = 0;

  _.chain(gazes)
    .filter(function (gaze) {
      return gaze.gazeX <= 0.5;
    })
    // .slice(0, 1000)
    .forEach(function (gaze) {
      //Create a camera with the x, y, and z provided. LookAt should be the same. (Camera rotation?)

      //The camera is defined by a position, orientation, and view frustum.

      var frustumHeight = 2 * gaze.cameraZ * Math.tan(fov * 0.5) / 111111;

      //TODO: More accurate meters->degrees calculation
      var frustum = {
        x: gaze.cameraX,
        y: gaze.cameraY,
        height: frustumHeight,
        width: frustumHeight * aspectRatio
      };

      // Convert gaze coordinates into longitude and latitude
      var gazeXMap = d3.scale.linear()
        .domain([0, 0.5])
        .range([frustum.x - frustum.width / 2, frustum.x + frustum.width / 2]);

      var gazeYMap = d3.scale.linear()
        .domain([0, 1])
        .range([frustum.y - frustum.height / 2, frustum.y + frustum.height / 2]);

      var gazeX = Cesium.CesiumMath.toDegrees(gazeXMap(gaze.gazeX));
      var gazeY = Cesium.CesiumMath.toDegrees(gazeYMap(gaze.gazeY));

      //Only plot if on globe
      if (gazeX >= -180 && gazeX <= 180 && gazeY >= -90 && gazeY <= 90) {
        viewer.entities.add({
          position: new Cesium.ConstantPositionProperty(Cesium.Cartesian3.fromDegrees(gazeX, gazeY)),
          point: new Cesium.PointGraphics({pixelSize: 4})
        });
        inRange++;
      }
      else {
        outRange++;
      }
    })
    .tap(function () {
      console.log("inRange", inRange);
      console.log("outRange", outRange);
    })
    .value();
}

//Load in CSV
//main
(function main() {
  asyncLoadCsv(config.gaze, function (gaze) {
    //Create Cesium elements?
    mapGazes(gaze);
  });
})();

//Using camera (x, y, z), map each gaze point appropriately. Gaze x is only between 0 and 0.5
function asyncLoadCsv(filename, cb) {
  fetch(filename)
    .then(function (response) {
      return response.text();
    })
    .then(function (data) {
      csvParser(data, {columns: true, auto_parse: true}, function (err, csv) {
        if (err) {
          throw err;
        }
        else {
          return cb(csv);
        }
      });
    })
    .catch(function (err) {
      console.log(filename, err)
    });
}

function getModules() {
  return {
    BuildModuleUrl: require('cesium/Source/Core/buildModuleUrl'),
    BingMapsApi: require('cesium/Source/Core/BingMapsApi'),
    ArcGisMapServerImageryProvider: require('cesium/Source/Scene/ArcGisMapServerImageryProvider'),
    Viewer: require('cesium/Source/Widgets/Viewer/Viewer'),
    ConstantPositionProperty: require('cesium/Source/DataSources/ConstantPositionProperty'),
    Cartesian3: require('cesium/Source/Core/Cartesian3'),
    ScreenSpaceEventType: require('cesium/Source/Core/ScreenSpaceEventType'),
    PointGraphics: require('cesium/Source/DataSources/PointGraphics'),
    CesiumMath: require('cesium/Source/Core/Math'),
  };
}
<|endoftext|>


<commit_before>//Temp namespace so we can easily refactor later when we come up with a name.
var SFX = {
    master: {}, //Global or master effect nodes.

    createContext: function() {
        window.AudioContext = window.AudioContext||window.webkitAudioContext;
        SFX.context = new AudioContext();

        SFX.master.gainNode = SFX.context.createGain();
        SFX.master.gainNode.connect(SFX.context.destination);
    },

    loadSound: function(url, onLoad) {
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
        request.responseType = 'arraybuffer';

        // Decode asynchronously
        request.onload = function() {
            SFX.context.decodeAudioData(request.response, function(buffer) {
                if (onLoad) {
                    onLoad(buffer);
                }
            }, function(e) {
                console.error(e);
            });
        }

        request.send();
    },

    createSource: function(buffer) {
        var source = SFX.context.createBufferSource();
        source.buffer = buffer;
        return source;
    },

    playSource: function(source, opt) {
        var gainNode = SFX.context.createGain();

        var loop = false;
        var delay = 0;
        var gain = 1.0;

        if (opt) {
            loop = opt.loop || loop;
            delay = opt.delay || delay;
            gain = opt.gain || gain;
            source.onended = opt.onEnd;
        }

        source.loop = loop;
        gainNode.gain.value = gain;

        //Connect the source to the gain node and connect the gain node to the destination.
        //Source -> Gain -> Master Gain -> Destination
        source.connect(gainNode);
        gainNode.connect(SFX.master.gainNode);

        source.start(delay);
    },

    //Creates a unique source from buffer, plays it and returns it.
    playSound: function(buffer, opt) {
        var source = SFX.createSource(buffer);
        SFX.playSource(source, opt);
        return source;
    },

    stopSource: function(source, delay) {
        source.stop(delay);
    }
};

SFX.createSound = function(buffer, opt) {
    var source = SFX.createSource(buffer);
    var gainNode = SFX.context.createGain();

    function setOptions(opt) {
        var loop = false;
        var gain = 1.0;

        if (opt) {
            loop = opt.loop || loop;
            gain = opt.gain || gain;
            source.onended = opt.onEnd;
        }

        source.loop = loop;
        gainNode.gain.value = gain;
    }
    setOptions(opt);

    //Connect the source to the gain node and connect the gain node to the destination.
    //Source -> Gain -> Master Gain -> Destination
    source.connect(gainNode);
    gainNode.connect(SFX.master.gainNode);

    return {
        source: source,
        opt: opt,

        play: function(delay) {
            source.start(delay);
        },

        playNew: function(delay, opt) {
            var newSound = SFX.createSound(this.source.buffer, opt || this.opt);
            newSound.play(delay);
            return newSound;
        },

        stop: function(delay) {
            source.stop(delay);
        },

        fade: function(type, rate, length, onComplete) {
            var setGain = this.setGain;
            var gainTarget = this.getGain();
            var timer = 0;
            var interval = setInterval(function() {
                timer += rate;

                var ratio = timer / (length * 1000);
                if (type === 'out') {
                    ratio = (1 - ratio);
                }

                setGain(ratio * gainTarget);
            }, rate);

            setGain(type === 'in' ? 0 : gainTarget);

            setTimeout(function() {
                clearInterval(interval);
                setGain(type === 'in' ? gainTarget : 0);
                if (onComplete) {
                    onComplete();
                }
            }, length * 1000);
        },

        setLooping: function(loop) {
            source.loop = loop;
        },

        setGain: function(gain) {
            gainNode.gain.value = gain;
        },

        setOnEnd: function(onEnd) {
            source.onended = onEnd;
        },

        setOptions: function(opt) {
            this.opt = opt;
            setOptions(opt);
        },

        isLooping: function() {
            return source.loop;
        },

        getGain: function() {
            return gainNode.gain.value;
        },

        getOptions: function() {
            return this.opt;
        },
    }
};

//Used to load multiple sounds.
SFX.createLoader = function() {
    var holders = [];
    var loaded = 0;

    return {
        add: function(path) {
            var holder = {path: path};
            holders.push(holder);
            return holder;
        },

        //Loads all the sound paths added and fills 'buffer' in the holder object. Specify a callback function to continue after the sounds have been loaded.
        load: function(callback) {
            var onLoad = this.onLoad;

            for (var i=0; i<holders.length; i++) {
                var holder = holders[i];
                (function(holder) { //Requires an anonymous function since holder is used in another callback.
                    SFX.loadSound(holder.path, function(buffer) {
                        holder.buffer = buffer;

                        loaded++;

                        //Meant to be overidden. Gives you the ratio of sounds loaded.
                        if (onLoad) {
                            onLoad(loaded / holders.length);
                        }

                        if (loaded >= holders.length) {
                            callback();
                        }
                    });
                })(holder);
            }
        }
    };
};
<commit_msg>Added optional 3D panning to sounds.<commit_after>//Temp namespace so we can easily refactor later when we come up with a name.
var SFX = {
    master: {}, //Global or master effect nodes.

    createContext: function() {
        window.AudioContext = window.AudioContext||window.webkitAudioContext;
        SFX.context = new AudioContext();

        SFX.master.gainNode = SFX.context.createGain();
        SFX.master.gainNode.connect(SFX.context.destination);
    },

    loadSound: function(url, onLoad) {
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
        request.responseType = 'arraybuffer';

        // Decode asynchronously
        request.onload = function() {
            SFX.context.decodeAudioData(request.response, function(buffer) {
                if (onLoad) {
                    onLoad(buffer);
                }
            }, function(e) {
                console.error(e);
            });
        }

        request.send();
    },

    createSource: function(buffer) {
        var source = SFX.context.createBufferSource();
        source.buffer = buffer;
        return source;
    },

    playSource: function(source, opt) {
        var gainNode = SFX.context.createGain();

        var loop = false;
        var delay = 0;
        var gain = 1.0;

        if (opt) {
            loop = opt.loop || loop;
            delay = opt.delay || delay;
            gain = opt.gain || gain;
            source.onended = opt.onEnd;
        }

        source.loop = loop;
        gainNode.gain.value = gain;

        //Connect the source to the gain node and connect the gain node to the destination.
        //Source -> Gain -> Master Gain -> Destination
        source.connect(gainNode);
        gainNode.connect(SFX.master.gainNode);

        source.start(delay);
    },

    //Creates a unique source from buffer, plays it and returns it.
    playSound: function(buffer, opt) {
        var source = SFX.createSource(buffer);
        SFX.playSource(source, opt);
        return source;
    },

    stopSource: function(source, delay) {
        source.stop(delay);
    }
};

SFX.createSound = function(buffer, opt) {
    var source = SFX.createSource(buffer);
    var gainNode = SFX.context.createGain();
    var panNode = SFX.context.createPanner();

    function setOptions(opt, reconnect) {
        var loop = false;
        var gain = 1.0;

        if (opt) {
            if (opt.loop !== undefined) {
                loop = opt.loop;
            }
            gain = opt.gain || gain;
            source.onended = opt.onEnd;
        }

        source.loop = loop;
        gainNode.gain.value = gain;

        if (reconnect) {
            source.disconnect();
            gainNode.disconnect();
            panNode.disconnect();
        }

        //Connect the source to the gain node and connect the gain node to the destination.
        //Source -> Gain -> Master Gain -> Destination
        source.connect(gainNode);
        if (opt.pan) {
            gainNode.connect(panNode);
            panNode.connect(SFX.master.gainNode);
        } else {
            gainNode.connect(SFX.master.gainNode);
        }
    }

    setOptions(opt, false);

    return {
        source: source,
        opt: opt,
        panNode: panNode,

        play: function(delay) {
            source.start(delay);
        },

        playNew: function(delay, opt) {
            var newSound = SFX.createSound(this.source.buffer, opt || this.opt);
            newSound.play(delay);
            return newSound;
        },

        stop: function(delay) {
            source.stop(delay);
        },

        fade: function(type, rate, length, onComplete) {
            var setGain = this.setGain;
            var gainTarget = this.getGain();
            var timer = 0;
            var interval = setInterval(function() {
                timer += rate;

                var ratio = timer / (length * 1000);
                if (type === 'out') {
                    ratio = (1 - ratio);
                }

                setGain(ratio * gainTarget);
            }, rate);

            setGain(type === 'in' ? 0 : gainTarget);

            setTimeout(function() {
                clearInterval(interval);
                setGain(type === 'in' ? gainTarget : 0);
                if (onComplete) {
                    onComplete();
                }
            }, length * 1000);
        },

        setLooping: function(loop) {
            source.loop = loop;
        },

        setGain: function(gain) {
            gainNode.gain.value = gain;
        },

        setOnEnd: function(onEnd) {
            source.onended = onEnd;
        },

        setOptions: function(opt) {
            this.opt = opt;
            setOptions(opt, true);
        },

        isLooping: function() {
            return source.loop;
        },

        getGain: function() {
            return gainNode.gain.value;
        },

        getOptions: function() {
            return this.opt;
        },
    }
};

//Used to load multiple sounds.
SFX.createLoader = function() {
    var holders = [];
    var loaded = 0;

    return {
        add: function(path) {
            var holder = {path: path};
            holders.push(holder);
            return holder;
        },

        //Loads all the sound paths added and fills 'buffer' in the holder object. Specify a callback function to continue after the sounds have been loaded.
        load: function(callback) {
            var onLoad = this.onLoad;

            for (var i=0; i<holders.length; i++) {
                var holder = holders[i];
                (function(holder) { //Requires an anonymous function since holder is used in another callback.
                    SFX.loadSound(holder.path, function(buffer) {
                        holder.buffer = buffer;

                        loaded++;

                        //Meant to be overidden. Gives you the ratio of sounds loaded.
                        if (onLoad) {
                            onLoad(loaded / holders.length);
                        }

                        if (loaded >= holders.length) {
                            callback();
                        }
                    });
                })(holder);
            }
        }
    };
};
<|endoftext|>


<commit_before>var WorldFeed = React.createClass({

    getInitialState: function(){
        return { searchString: '', data: {} };
    },

    handleChange: function(e){
        this.setState({ searchString:e.target.value });
    },

    pushData: function(d) {
        var v          = JSON.parse(d);
        start_ts       = v['start'];
        end_ts         = v['end'];
        server_country = v['server_country'];
        language       = v['language'];
        count          = v['count'];

        data           = this.state.data;

        if (! (start_ts in data))
            data[start_ts] = {language: {}, country: {}};
        if (! (server_country in data[start_ts]))
            data[start_ts]['country'][server_country] = 0;
        if (! (language in data[start_ts]))
            data[start_ts]['language'][language] = 0;

        data[start_ts]['country'][server_country] += count;
        data[start_ts]['language'][language] += count;

        console.log(data);
        this.setState({data: data});
    },

    componentDidMount: function(){
        var socket = io();
        socket.on('message', this.pushData);
    },

    render: function() {
        var that = this;
        return

                  { Object.keys(that.state.data).map(function (key) {
                      return

{key}

Languages

                                 { Object.keys(that.state.data[key]['language']).map(function (key2) {
                                   return
{key2}: {that.state.data[key]['language'][key2]}

                                 }) }

Countries

                                 { Object.keys(that.state.data[key]['country']).map(function (key2) {
                                   return
{key2}: {that.state.data[key]['country'][key2]}

                                 }) }

                  }) }

;

    }
});

var libraries = [

    { name: 'Backbone.js', url: 'http://documentcloud.github.io/backbone/'},
    { name: 'AngularJS', url: 'https://angularjs.org/'},
    { name: 'jQuery', url: 'http://jquery.com/'},
    { name: 'Prototype', url: 'http://www.prototypejs.org/'},
    { name: 'React', url: 'http://facebook.github.io/react/'},
    { name: 'Ember', url: 'http://emberjs.com/'},
    { name: 'Knockout.js', url: 'http://knockoutjs.com/'},
    { name: 'Dojo', url: 'http://dojotoolkit.org/'},
    { name: 'Mootools', url: 'http://mootools.net/'},
    { name: 'Underscore', url: 'http://documentcloud.github.io/underscore/'},
    { name: 'Lodash', url: 'http://lodash.com/'},
    { name: 'Moment', url: 'http://momentjs.com/'},
    { name: 'Express', url: 'http://expressjs.com/'},
    { name: 'Koa', url: 'http://koajs.com/'},

];

var WorldFeedInstance = React.render(
    <WorldFeed items={libraries} />,
    document.body
);
<commit_msg>Anpassungen an der React-App<commit_after>var WorldFeed = React.createClass({

    getInitialState: function(){
        return { searchString: '', data: {} };
    },

    handleChange: function(e){
        this.setState({ searchString:e.target.value });
    },

    pushData: function(d) {
        var v          = JSON.parse(d);
        start_ts       = v['start'];
        end_ts         = v['end'];
        server_country = v['server_country'];
        language       = v['language'];
        count          = v['count'];

        data           = this.state.data;

        if (! (start_ts in data))
            data[start_ts] = {language: {}, country: {}};
        if (! (server_country in data[start_ts]['country']))
            data[start_ts]['country'][server_country] = 0;
        if (! (language in data[start_ts]['language']))
            data[start_ts]['language'][language] = 0;

        data[start_ts]['country'][server_country] += count;
        data[start_ts]['language'][language] += count;

        console.log(data);
        this.setState({data: data});
    },

    componentDidMount: function(){
        var socket = io();
        socket.on('message', this.pushData);
    },

    render: function() {
        var that = this;
        const config = {
          /* HighchartsConfig */
        };

        return

                  <Highcharts config = {config}></Highcharts>
                  { Object.keys(that.state.data).map(function (key) {
                      return

{key}

Languages

                                 { Object.keys(that.state.data[key]['language']).map(function (key2) {
                                   return
{key2}: {that.state.data[key]['language'][key2]}

                                 }) }

Countries

                                 { Object.keys(that.state.data[key]['country']).map(function (key2) {
                                   return
{key2}: {that.state.data[key]['country'][key2]}

                                 }) }

                  }) }

;

    }
});

var WorldFeedInstance = React.render(
    <WorldFeed />,
    document.body
);
<|endoftext|>


<commit_before>var jinterest = new Object();

jinterest.init = function(list) {

	$.get("jinterest-form.html", function(form) {
		$('.jt-body').html(form);

		$.get("jinterest-content-view.html", function(result) {

			for (var n = 0; n < list.length; n++) {
				var data = list[n];
				var push = $('.jt-push');

				var content = $('.hidden').html();

				var height = 9999;
				var index;

				for (var i = 0; i < 4; i++) {
					var c = push[i];
					if (c.offsetHeight < height) {
						height = c.offsetHeight;
						index = i;
					}
				}

				var html = result.replace('{ID}', data.id).replace('{JT_IMG_URL}', data.img_url).replace('{JT_TITLE}', data.title).replace('{JT_CONTENT}', data.content);
				html = html.replace('{JT_DATE}', data.date).replace('{JT_LIKE_COUNT}', data.like_count).replace('{JT_REPLY_COUNT}', data.reply_count);

				$('.jt-push').get(index).innerHTML += html;

			}

		});

	});

};
<commit_msg>Update jinterest.js<commit_after>function Jinterest(list) {
	$.get("jinterest-form.html", function(form) {
		$('.jt-body').html(form);

		$.get("jinterest-content-view.html", function(result) {

			for (var n = 0; n < list.length; n++) {
				var data = list[n];
				var push = $('.jt-push');

				var content = $('.hidden').html();

				var height = 9999;
				var index;

				for (var i = 0; i < 4; i++) {
					var c = push[i];
					if (c.offsetHeight < height) {
						height = c.offsetHeight;
						index = i;
					}
				}

				var html = result.replace('{ID}', data.id).replace('{JT_IMG_URL}', data.img_url).replace('{JT_TITLE}', data.title).replace('{JT_CONTENT}', data.content);
				html = html.replace('{JT_DATE}', data.date).replace('{JT_LIKE_COUNT}', data.like_count).replace('{JT_REPLY_COUNT}', data.reply_count);

				$('.jt-push').get(index).innerHTML += html;

			}

		});

	});
}
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name oncokbApp.controller:NavCtrl
 * @description
 * # NavCtrl
 * Controller of the oncokbApp
 */
angular.module('oncokbApp')
.controller('NavCtrl', function ($scope, $location, $rootScope, config, gapi, user, storage, access) {
    var tabs = {
        'tree': 'Tree',
        'variant': 'Variant Annotation',
        'genes': 'Genes'
    };

    var accessLevels = config.accessLevels;

    function loginCallback() {
        // console.log('In login callback.')
        if(!$scope.$$phase) {
            $scope.$apply(setParams);
        }else {
            setParams();
        }
        $rootScope.$apply(function() {
            var url = access.getURL();
            if(url) {
                if(access.isLoggedIn()){
                    access.setURL('');
                    $location.path(url);
                }
            }else {
                if (access.isLoggedIn() && !access.getURL() && access.authorize(config.accessLevels.curator)) {
                    $location.path('/genes');
                }else {
                    $location.path('/');
                }
            }
        });
    }

    function setParams() {
        var filterTabs = [];
        $scope.user = $rootScope.user;
        if(access.authorize(accessLevels.curator)) {
            filterTabs.push({key: 'genes', value: tabs.genes});
        }
        // if(access.authorize(accessLevels.admin)) {
        //     var keys = ['tree', 'variant'];

        //     keys.forEach(function(e){
        //         filterTabs.push({'key': e, 'value': tabs[e]});
        //     });
        // }
        $scope.signedIn = access.isLoggedIn();
        $scope.tabs = filterTabs;
    }

    // Render the sign in button.
    $scope.renderSignInButton = function() {
        storage.requireAuth().then(function(result){
            $scope.signInCallback(result);
        });
    };

    $scope.signOut = function() {
        access.logout();
        $scope.signedIn = false;
        $scope.user = $rootScope.user;
        $location.path('/');
        gapi.auth.signOut();
    };

    $scope.tabIsActive = function(route) {
        if( route instanceof Array) {
            for (var i = route.length - 1; i >= 0; i--) {
                if(route[i] === $location.path()) {
                    return true;
                }
            }
            return false;
        }else {
            return route === $location.path();
        }
    };

    // When callback is received, we need to process authentication.
    $scope.signInCallback = function(authResult) {
        // Do a check if authentication has been successful.
        // console.log('In processAuth');

        if(authResult.access_token) {
            // Successful sign in.
            // $scope.signedIn = true;
            // console.log('access success', authResult);
            access.login(loginCallback);
        } else if(authResult.error) {
            // Error while signing in.
            // $scope.signedIn = false;
            // console.log('access failed', authResult);
            loginCallback();
            // Report error.
        }
    };

    // This flag we use to show or hide the button in our HTML.
    $scope.signedIn = false;
    $scope.user = $rootScope.user;

    $rootScope.$watch('user', setParams);
    // Call start function on load.
    // $scope.init = $scope.renderSignInButton();
});
<commit_msg>Added 'Tools' tab<commit_after>'use strict';

/**
 * @ngdoc function
 * @name oncokbApp.controller:NavCtrl
 * @description
 * # NavCtrl
 * Controller of the oncokbApp
 */
angular.module('oncokbApp')
.controller('NavCtrl', function ($scope, $location, $rootScope, config, gapi, user, storage, access) {
    var tabs = {
        'tree': 'Tree',
        'variant': 'Variant Annotation',
        'genes': 'Genes',
        'reportGenerator': 'Tools'
    };

    var accessLevels = config.accessLevels;

    function loginCallback() {
        // console.log('In login callback.')
        if(!$scope.$$phase) {
            $scope.$apply(setParams);
        }else {
            setParams();
        }
        $rootScope.$apply(function() {
            var url = access.getURL();
            if(url) {
                if(access.isLoggedIn()){
                    access.setURL('');
                    $location.path(url);
                }
            }else {
                if (access.isLoggedIn() && !access.getURL() && access.authorize(config.accessLevels.curator)) {
                    $location.path('/genes');
                }else {
                    $location.path('/');
                }
            }
        });
    }

    function setParams() {
        var filterTabs = [];
        $scope.user = $rootScope.user;
        if(access.authorize(accessLevels.curator)) {
            filterTabs.push({key: 'genes', value: tabs.genes});
        }
        // if(access.authorize(accessLevels.admin)) {
        //     var keys = ['tree', 'variant', 'reportGenerator'];

        //     keys.forEach(function(e){
        //         filterTabs.push({'key': e, 'value': tabs[e]});
        //     });
        // }
        $scope.signedIn = access.isLoggedIn();
        $scope.tabs = filterTabs;
    }

    // Render the sign in button.
    $scope.renderSignInButton = function() {
        storage.requireAuth().then(function(result){
            $scope.signInCallback(result);
        });
    };

    $scope.signOut = function() {
        access.logout();
        $scope.signedIn = false;
        $scope.user = $rootScope.user;
        $location.path('/');
        gapi.auth.signOut();
    };

    $scope.tabIsActive = function(route) {
        if( route instanceof Array) {
            for (var i = route.length - 1; i >= 0; i--) {
                if(route[i] === $location.path()) {
                    return true;
                }
            }
            return false;
        }else {
            return route === $location.path();
        }
    };

    // When callback is received, we need to process authentication.
    $scope.signInCallback = function(authResult) {
        // Do a check if authentication has been successful.
        // console.log('In processAuth');

        if(authResult.access_token) {
            // Successful sign in.
            // $scope.signedIn = true;
            // console.log('access success', authResult);
            access.login(loginCallback);
        } else if(authResult.error) {
            // Error while signing in.
            // $scope.signedIn = false;
            // console.log('access failed', authResult);
            loginCallback();
            // Report error.
        }
    };

    // This flag we use to show or hide the button in our HTML.
    $scope.signedIn = false;
    $scope.user = $rootScope.user;

    $rootScope.$watch('user', setParams);
    // Call start function on load.
    // $scope.init = $scope.renderSignInButton();
});
<|endoftext|>


<commit_before>/**
 * Author: Vova Zaytsev <zaytsev@usc.edu>
 */

app.controller("NlcdClientController", ["$scope", "$location", "$sce", "NcldApiFactory",
    function ($scope, $location, $sce, NcldApiFactory) {

        /**
          *
          **/

        var graphId = $location.search().g;

        $scope.central              = null;
        $scope.related              = [];
        $scope.meta                 = null;
        $scope.selection            = [];
        $scope.textSelection        = null;
        $scope.dateDistr            = null;
        $scope.selectedDateEntry    = null;

        $scope.display = {

            // Tab 'ALL'
            relatedTabAllReversed:        false,
            relatedTabAllPredicate:       "inSelection",

            // Tab 'SOURCES'
            relatedTabSourcesReversed:    false,
            relatedTabSourcesPredicate:   "referenceCount",

            // Tab 'AUTHORS'
            relatedTabAuthorsReversed:    false,
            relatedTabAuthorsPredicate:   "referenceCount",

            // Tab 'DATES'
            relatedTabDatesReversed:      false,
            relatedTabDatesPredicate:     "documentsCount"

        };

        // Init bootstrap javascript
        $("#relatedTabs a").click(function (e) {
            e.preventDefault();
            $(this).tab("show");
        });
        $("#relatedTabs a:first").tab("show");

        // Init tooltipe
        $(".tip-tooltip").tooltip({
            "animation": true,
            "placement": "top",
        });

        $("body").popover({
              "container": "body",
              "trigger": "hover",
              "delay": 1,
              "html": true,
              "placement": "right",
              "selector": ".tip-popover"
        });

        NcldApiFactory.getTestGraph(graphId).success(function(data){

            $scope.sg = new StoryGraph(data);
            $scope.central = $scope.sg.getCentralNode();
            $scope.related = $scope.sg.getNodes();
            $scope.meta = data.meta;

            var distrPlaceId = "storyDistribution";
            var nwPlaceId = "storyNetwork";

            var distrWidth = document.getElementById(distrPlaceId).offsetWidth;
            var nwWidth = document.getElementById(nwPlaceId).offsetWidth;

            var height = 300;

            $scope.sg.drawDistribution(distrPlaceId, distrWidth, height);
            $scope.sg.drawNetwork(nwPlaceId, nwWidth, height);
            $scope.dateDistr = $scope.sg.distr.dateDistr;

        });

        //
        $scope.RelatedAllTabOrderBy = function(predicate) {
            if ($scope.display.relatedTabAllPredicate == predicate) {
                $scope.display.relatedTabAllReversed = !$scope.display.relatedTabAllReversed;
            }
            $scope.display.relatedTabAllPredicate = predicate;
        }

        //
        $scope.RelatedDatesTabOrderBy = function(predicate) {
            if ($scope.display.relatedTabDatesPredicate == predicate) {
                $scope.display.relatedTabDatesReversed = !$scope.display.relatedTabDatesReversed;
            }
            $scope.display.relatedTabDatesPredicate = predicate;
        }

        //
        $scope.SetSelection = function(referencesList) {

            for (var i in $scope.selection) {
                $scope.selection[i].inSelection = null;
            };
            $scope.selection = [];
            for (var i in referencesList) {
                var refId = referencesList[i];
                var item = $scope.sg.getNode(refId);
                item.inSelection = true;
                $scope.selection.push(item);
            };

            $scope.sg.gfx.SetDistributionSelection(referencesList);
            $scope.sg.gfx.SetNetworkSelection(referencesList);
        };

        //
        $scope.TextSelection = function(chunk, referencesList) {

            $scope.SetSelection([]);

            if ($scope.selectedDateEntry) {
                $scope.SelectDate($scope.selectedDateEntry);
            }

            if ($scope.textSelection) {
                $scope.textSelection.isSelected = false;
                if ($scope.textSelection.tagId == chunk.tagId) {
                    $scope.textSelection = null;
                    return;
                }
            }
            $scope.textSelection = chunk;
            $scope.textSelection.isSelected = true;
            $scope.SetSelection(referencesList);

        };

        //
        $scope.SelectDate = function(dateEntry) {

            if ($scope.textSelection) {
                $scope.TextSelection($scope.textSelection, []);
            }

            $scope.SetSelection([]);

            if ($scope.selectedDateEntry == dateEntry) {

                $scope.selectedDateEntry.selected = false;
                $scope.selectedDateEntry = null;

            } else {

                $scope.selectedDateEntry.selected = false;
                $scope.selectedDateEntry = dateEntry;
                $scope.SetSelection(dateEntry.selection);
                $scope.selectedDateEntry.selected = true;

            }

        };

        //
        $scope.toolPopoverContent = function(node) {

            var authors = node.authors.join(", ").toTitleCase();
            var source = "";
            var len = 10000;
            for (var i in node.sources) {
                if (node.sources[i].length < len) {
                    source = node.sources[i];
                    len = node.sources[i].length;
                }
            }

            return "

authror: "
                   + authors
                   + "

source: "
                   + source
                   + "

"
                   + String.prototype.CutStr(node.body, true, 256, "...")
                   + "
";
        }

}]);<commit_msg>update contrib data<commit_after>/**
 * Author: Vova Zaytsev <zaytsev@usc.edu>
 */

app.controller("NlcdClientController", ["$scope", "$location", "$sce", "NcldApiFactory",
    function ($scope, $location, $sce, NcldApiFactory) {

        /**
          *
          **/

        var graphId = $location.search().g;

        $scope.central              = null;
        $scope.related              = [];
        $scope.meta                 = null;
        $scope.selection            = [];
        $scope.textSelection        = null;
        $scope.dateDistr            = null;
        $scope.selectedDateEntry    = null;

        $scope.display = {

            // Tab 'ALL'
            relatedTabAllReversed:        false,
            relatedTabAllPredicate:       "inSelection",

            // Tab 'SOURCES'
            relatedTabSourcesReversed:    false,
            relatedTabSourcesPredicate:   "referenceCount",

            // Tab 'AUTHORS'
            relatedTabAuthorsReversed:    false,
            relatedTabAuthorsPredicate:   "referenceCount",

            // Tab 'DATES'
            relatedTabDatesReversed:      false,
            relatedTabDatesPredicate:     "documentsCount"

        };

        // Init bootstrap javascript
        $("#relatedTabs a").click(function (e) {
            e.preventDefault();
            $(this).tab("show");
        });
        $("#relatedTabs a:first").tab("show");

        // Init tooltipe
        $(".tip-tooltip").tooltip({
            "animation": true,
            "placement": "top",
        });

        $("body").popover({
              "container": "body",
              "trigger": "hover",
              "delay": 1,
              "html": true,
              "placement": "right",
              "selector": ".tip-popover"
        });

        NcldApiFactory.getTestGraph(graphId).success(function(data){

            $scope.sg = new StoryGraph(data);
            $scope.central = $scope.sg.getCentralNode();
            $scope.related = $scope.sg.getNodes();
            $scope.meta = data.meta;

            var distrPlaceId = "storyDistribution";
            var nwPlaceId = "storyNetwork";

            var distrWidth = document.getElementById(distrPlaceId).offsetWidth;
            var nwWidth = document.getElementById(nwPlaceId).offsetWidth;

            var height = 300;

            $scope.sg.drawDistribution(distrPlaceId, distrWidth, height);
            $scope.sg.drawNetwork(nwPlaceId, nwWidth, height);
            $scope.dateDistr = $scope.sg.distr.dateDistr;

        });

        //
        $scope.RelatedAllTabOrderBy = function(predicate) {
            if ($scope.display.relatedTabAllPredicate == predicate) {
                $scope.display.relatedTabAllReversed = !$scope.display.relatedTabAllReversed;
            }
            $scope.display.relatedTabAllPredicate = predicate;
        }

        //
        $scope.RelatedDatesTabOrderBy = function(predicate) {
            if ($scope.display.relatedTabDatesPredicate == predicate) {
                $scope.display.relatedTabDatesReversed = !$scope.display.relatedTabDatesReversed;
            }
            $scope.display.relatedTabDatesPredicate = predicate;
        }

        //
        $scope.SetSelection = function(referencesList) {

            for (var i in $scope.selection) {
                $scope.selection[i].inSelection = null;
            };
            $scope.selection = [];
            for (var i in referencesList) {
                var refId = referencesList[i];
                var item = $scope.sg.getNode(refId);
                item.inSelection = true;
                $scope.selection.push(item);
            };

            $scope.sg.gfx.SetDistributionSelection(referencesList);
            $scope.sg.gfx.SetNetworkSelection(referencesList);
        };

        //
        $scope.TextSelection = function(chunk, referencesList) {

            $scope.SetSelection([]);

            if ($scope.selectedDateEntry) {
                $scope.SelectDate($scope.selectedDateEntry);
            }

            if ($scope.textSelection) {
                $scope.textSelection.isSelected = false;
                if ($scope.textSelection.tagId == chunk.tagId) {
                    $scope.textSelection = null;
                    return;
                }
            }
            $scope.textSelection = chunk;
            $scope.textSelection.isSelected = true;
            $scope.SetSelection(referencesList);

        };

        //
        $scope.SelectDate = function(dateEntry) {

            if ($scope.textSelection) {
                $scope.TextSelection($scope.textSelection, []);
            }

            $scope.SetSelection([]);

            if ($scope.selectedDateEntry == dateEntry) {

                $scope.selectedDateEntry.selected = false;
                $scope.selectedDateEntry = null;

            } else {

                $scope.SetSelection(dateEntry.selection);
                $scope.selectedDateEntry.selected = false;
                $scope.selectedDateEntry = dateEntry;
                $scope.selectedDateEntry.selected = true;

            }

        };

        //
        $scope.toolPopoverContent = function(node) {

            var authors = node.authors.join(", ").toTitleCase();
            var source = "";
            var len = 10000;
            for (var i in node.sources) {
                if (node.sources[i].length < len) {
                    source = node.sources[i];
                    len = node.sources[i].length;
                }
            }

            return "

authror: "
                   + authors
                   + "

source: "
                   + source
                   + "

"
                   + String.prototype.CutStr(node.body, true, 256, "...")
                   + "
";
        }

}]);<|endoftext|>


<commit_before>import path from 'path'
import fs from 'fs'
import webpack from 'webpack'
import rimraf from 'rimraf'
import config from '../config'
import isomorphicWebpackConfig from '../webpack.isomorphic'
import nodeExternals from 'webpack-node-externals'
const {SENTRY_DSN, CLIENT_STATIC_PATH, CLIENT_ASSETS_MANIFEST, publicPath, isProduction} = config

// Clear dist dir before run
rimraf(`${config.distPath}/server`, {}, () => {})

const definePluginArgs = {
	'process.env.BROWSER': JSON.stringify(false),
	'process.env.SENTRY_DSN': JSON.stringify(SENTRY_DSN),
	'process.env.CLIENT_STATIC_PATH': JSON.stringify(CLIENT_STATIC_PATH),
	'process.env.CLIENT_ASSETS_MANIFEST': JSON.stringify(CLIENT_ASSETS_MANIFEST)
}

const devtool = isProduction ? 'cheap-source-map' : 'eval'
const chunkFilename = isProduction ? '[name].[chunkhash:6].js' : '[name].js'

const baseWebpackConfig = {
	name: 'server',
	entry: config.srcPath,
	devtool,
	target: 'node',
	output: {
		path: path.join(config.distPath, './server'),
		filename: 'index.js',
		chunkFilename,
		publicPath
	},
	externals: [
		nodeExternals({
			whitelist: [
				!isProduction ? 'webpack/hot/poll?300' : null,
				/\.(eot|woff|woff2|ttf|otf)$/,
				/\.(svg|png|jpg|jpeg|gif|ico)$/,
				/\.(mp4|mp3|ogg|swf|webp)$/,
				/\.(css|scss|sass|sss|less)$/
			].filter(x => x)
		})
	],
	performance: {
		hints: false
	},
	resolve: {
		extensions: isomorphicWebpackConfig.resolve.extensions,
		modules: isomorphicWebpackConfig.resolve.modules,
		alias: isomorphicWebpackConfig.resolve.alias
	},
	module: {
		rules: isomorphicWebpackConfig.module.rules
	},
	plugins: isomorphicWebpackConfig.plugins.concat([
		new webpack.DefinePlugin(definePluginArgs),
		new webpack.optimize.LimitChunkCountPlugin({
			maxChunks: 1
		})
	]),
	node: {
		__dirname: true,
		__filename: true,
		console: true,
		global: true
	}
}

export default baseWebpackConfig
<commit_msg>fix(webpack): prevent server from handling css<commit_after>import path from 'path'
import fs from 'fs'
import webpack from 'webpack'
import rimraf from 'rimraf'
import config from '../config'
import isomorphicWebpackConfig from '../webpack.isomorphic'
import nodeExternals from 'webpack-node-externals'
const {SENTRY_DSN, CLIENT_STATIC_PATH, CLIENT_ASSETS_MANIFEST, publicPath, isProduction} = config

// Clear dist dir before run
rimraf(`${config.distPath}/server`, {}, () => {})

const definePluginArgs = {
	'process.env.BROWSER': JSON.stringify(false),
	'process.env.SENTRY_DSN': JSON.stringify(SENTRY_DSN),
	'process.env.CLIENT_STATIC_PATH': JSON.stringify(CLIENT_STATIC_PATH),
	'process.env.CLIENT_ASSETS_MANIFEST': JSON.stringify(CLIENT_ASSETS_MANIFEST)
}

const devtool = isProduction ? 'cheap-source-map' : 'eval'
const chunkFilename = isProduction ? '[name].[chunkhash:6].js' : '[name].js'

const baseWebpackConfig = {
	name: 'server',
	entry: config.srcPath,
	devtool,
	target: 'node',
	output: {
		path: path.join(config.distPath, './server'),
		filename: 'index.js',
		chunkFilename,
		publicPath
	},
	externals: [
		nodeExternals({
			whitelist: [
				!isProduction ? 'webpack/hot/poll?300' : null,
				/\.(eot|woff|woff2|ttf|otf)$/,
				/\.(svg|png|jpg|jpeg|gif|ico)$/,
				/\.(mp4|mp3|ogg|swf|webp)$/,
				/\.(css|scss|sass|sss|less)$/
			].filter(x => x)
		})
	],
	performance: {
		hints: false
	},
	resolve: {
		extensions: isomorphicWebpackConfig.resolve.extensions,
		modules: isomorphicWebpackConfig.resolve.modules,
		alias: isomorphicWebpackConfig.resolve.alias
	},
	module: {
		rules: isomorphicWebpackConfig.module.rules
	},
	plugins: isomorphicWebpackConfig.plugins.concat([
		new webpack.DefinePlugin(definePluginArgs),
		new webpack.optimize.LimitChunkCountPlugin({
			maxChunks: 1
		}),
		new webpack.NormalModuleReplacementPlugin(/\.(css|sass|less|scss)$/, 'node-noop')
	]),
	node: {
		__dirname: true,
		__filename: true,
		console: true,
		global: true
	}
}

export default baseWebpackConfig
<|endoftext|>