<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/**
 * @fileoverview TimelineView visualizes TRACE_EVENT events using the
 * tracing.Timeline component and adds in selection summary and control buttons.
 */
base.requireStylesheet('timeline_view');

base.require('timeline');
base.require('timeline_analysis');
base.require('timeline_category_filter_dialog');
base.require('timeline_filter');
base.require('timeline_find_control');
base.require('overlay');
base.require('trace_event_importer');
base.require('linux_perf_importer');
base.require('settings');

base.exportTo('tracing', function() {

  /**
   * TimelineView
   * @constructor
   * @extends {HTMLDivElement}
   */
  var TimelineView = base.ui.define('div');

  TimelineView.prototype = {
    __proto__: HTMLDivElement.prototype,

    decorate: function() {
      this.classList.add('timeline-view');

      // Create individual elements.
      this.titleEl_ = document.createElement('div');
      this.titleEl_.textContent = 'Tracing: ';
      this.titleEl_.className = 'title';

      this.controlDiv_ = document.createElement('div');
      this.controlDiv_.className = 'control';

      this.leftControlsEl_ = document.createElement('div');
      this.leftControlsEl_.className = 'controls';
      this.rightControlsEl_ = document.createElement('div');
      this.rightControlsEl_.className = 'controls';

      var spacingEl = document.createElement('div');
      spacingEl.className = 'spacer';

      this.timelineContainer_ = document.createElement('div');
      this.timelineContainer_.className = 'timeline-container';

      var analysisContainer_ = document.createElement('div');
      analysisContainer_.className = 'analysis-container';

      this.analysisEl_ = new tracing.TimelineAnalysisView();

      this.dragEl_ = new TimelineDragHandle();
      this.dragEl_.target = analysisContainer_;

      this.findCtl_ = new tracing.TimelineFindControl();
      this.findCtl_.controller = new tracing.TimelineFindController();

      this.importErrorsButton_ = this.createImportErrorsButton_();
      this.categoryFilterButton_ = this.createCategoryFilterButton_();
      this.categoryFilterButton_.callback =
        this.updateCategoryFilterFromSettings_.bind(this);
      this.metadataButton_ = this.createMetadataButton_();

      // Connect everything up.
      this.rightControls.appendChild(this.importErrorsButton_);
      this.rightControls.appendChild(this.categoryFilterButton_);
      this.rightControls.appendChild(this.metadataButton_);
      this.rightControls.appendChild(this.findCtl_);
      this.controlDiv_.appendChild(this.titleEl_);
      this.controlDiv_.appendChild(this.leftControlsEl_);
      this.controlDiv_.appendChild(spacingEl);
      this.controlDiv_.appendChild(this.rightControlsEl_);
      this.appendChild(this.controlDiv_);

      this.appendChild(this.timelineContainer_);
      this.appendChild(this.dragEl_);

      analysisContainer_.appendChild(this.analysisEl_);
      this.appendChild(analysisContainer_);

      this.rightControls.appendChild(this.createHelpButton_());

      // Bookkeeping.
      this.onSelectionChangedBoundToThis_ = this.onSelectionChanged_.bind(this);
      document.addEventListener('keypress', this.onKeypress_.bind(this), true);
    },

    createImportErrorsButton_: function() {
      var dlg = new tracing.Overlay();
      dlg.classList.add('timeline-view-import-errors-overlay');
      dlg.autoClose = true;

      var showEl = document.createElement('div');
      showEl.className = 'timeline-button timeline-view-import-errors-button' +
          ' timeline-view-info-button';
      showEl.textContent = 'Import errors!';

      var textEl = document.createElement('div');
      textEl.className = 'info-button-text import-errors-dialog-text';

      var containerEl = document.createElement('div');
      containerEl.className = 'info-button-container' +
          'import-errors-dialog';

      containerEl.textContent = 'Errors occurred during import:';
      containerEl.appendChild(textEl);
      dlg.appendChild(containerEl);

      var that = this;
      function onClick() {
        dlg.visible = true;
        textEl.textContent = that.model.importErrors.join("\n");
      }
      showEl.addEventListener('click', onClick.bind(this));

      function updateVisibility() {
        if (that.model &&
            that.model.importErrors.length)
          showEl.style.display = '';
        else
          showEl.style.display = 'none';
      }
      updateVisibility();
      that.addEventListener('modelChange', updateVisibility);

      return showEl;
    },

    createCategoryFilterButton_: function() {
      // Set by the embedder of the help button that we create in this function.
      var callback;

      var showEl = document.createElement('div');
      showEl.className = 'timeline-button timeline-view-info-button';
      showEl.textContent = 'Category Filters';
      showEl.__defineSetter__('callback', function(value) {
        callback = value;
      });

      var that = this;
      function onClick() {
        var dlg = new tracing.TimelineCategoryFilterDialog();
        dlg.model = that.model;
        dlg.settings = that.settings;
        dlg.settingUpdatedCallback = callback;
        dlg.visible = true;
      }

      function updateVisibility() {
        if (that.model)
          showEl.style.display = 'none';
        else
          showEl.style.display = '';
      }
      updateVisibility();
      that.addEventListener('modelChange', updateVisibility);

      showEl.addEventListener('click', onClick.bind(this));
      return showEl;
    },

    createHelpButton_: function() {
      var dlg = new tracing.Overlay();
      dlg.classList.add('timeline-view-help-overlay');
      dlg.autoClose = true;
      dlg.additionalCloseKeyCodes.push('?'.charCodeAt(0));

      var showEl = document.createElement('div');
      showEl.className = 'timeline-button timeline-view-help-button';
      showEl.textContent = '?';

      var helpTextEl = document.createElement('div');
      helpTextEl.style.whiteSpace = 'pre';
      helpTextEl.style.fontFamily = 'monospace';
      dlg.appendChild(helpTextEl);

      function onClick(e) {
        dlg.visible = true;
        if (this.timeline_)
          helpTextEl.textContent = this.timeline_.keyHelp;
        else
          helpTextEl.textContent = 'No content loaded. For interesting help,' +
              ' load something.';
        document.addEventListener('click', bgClick);

        // Stop event so it doesn't trigger new click listener on document.
        e.stopPropagation();
        return false;
      }

      showEl.addEventListener('click', onClick.bind(this));

      return showEl;
    },

    createMetadataButton_: function() {
      var dlg = new tracing.Overlay();
      dlg.classList.add('timeline-view-metadata-overlay');
      dlg.autoClose = true;

      var showEl = document.createElement('div');
      showEl.className = 'timeline-button timeline-view-metadata-button' +
          ' timeline-view-info-button';
      showEl.textContent = 'Metadata';

      var textEl = document.createElement('div');
      textEl.className = 'info-button-text metadata-dialog-text';

      var containerEl = document.createElement('div');
      containerEl.className = 'info-button-container metadata-dialog';

      containerEl.textContent = 'Metadata Info:';
      containerEl.appendChild(textEl);
      dlg.appendChild(containerEl);

      var that = this;
      function onClick() {
        dlg.visible = true;

        var metadataStrings = [];

        var model = that.model;
        for (var data in model.metadata) {
          metadataStrings.push(JSON.stringify(model.metadata[data].name) +
            ": " + JSON.stringify(model.metadata[data].value));
        }
        textEl.textContent = metadataStrings.join("\n");
      }
      showEl.addEventListener('click', onClick.bind(this));

      function updateVisibility() {
        if (that.model &&
            that.model.metadata.length)
          showEl.style.display = '';
        else
          showEl.style.display = 'none';
      }
      updateVisibility();
      that.addEventListener('modelChange', updateVisibility);

      return showEl;
    },

    get leftControls() {
      return this.leftControlsEl_;
    },

    get rightControls() {
      return this.rightControlsEl_;
    },

    get title() {
      return this.titleEl_.textContent.substring(
        this.titleEl_.textContent.length - 2);
    },

    set title(text) {
      this.titleEl_.textContent = text + ':';
    },

    set traceData(traceData) {
      this.model = new tracing.TimelineModel(traceData);
    },

    get model() {
      if (this.timeline_)
        return this.timeline_.model;
      return undefined;
    },

    set model(model) {
      var modelInstanceChanged = model != this.model;
      var modelValid = model && model.minTimestamp !== undefined;

      // Remove old timeline if the model has completely changed.
      if (modelInstanceChanged) {
        this.timelineContainer_.textContent = '';
        if (this.timeline_) {
          this.timeline_.removeEventListener(
              'selectionChange', this.onSelectionChangedBoundToThis_);
          this.timeline_.detach();
          this.timeline_ = undefined;
          this.findCtl_.controller.timeline = undefined;
        }
      }

      // Create new timeline if needed.
      if (modelValid && !this.timeline_) {
        this.timeline_ = new tracing.Timeline();
        this.timeline_.focusElement =
            this.focusElement_ ? this.focusElement_ : this.parentElement;
        this.timelineContainer_.appendChild(this.timeline_);
        this.findCtl_.controller.timeline = this.timeline_;
        this.timeline_.addEventListener(
            'selectionChange', this.onSelectionChangedBoundToThis_);
        this.updateCategoryFilterFromSettings_();
      }

      // Set the model.
      if (modelValid)
        this.timeline_.model = model;
      base.dispatchSimpleEvent(this, 'modelChange');

      // Do things that are selection specific
      if (modelInstanceChanged)
        this.onSelectionChanged_();
    },

    get timeline() {
      return this.timeline_;
    },

    get settings() {
      if (!this.settings_)
        this.settings_ = new base.Settings();
      return this.settings_;
    },

    /**
     * Sets the element whose focus state will determine whether
     * to respond to keybaord input.
     */
    set focusElement(value) {
      this.focusElement_ = value;
      if (this.timeline_)
        this.timeline_.focusElement = value;
    },

    /**
     * @return {Element} The element whose focused state determines
     * whether to respond to keyboard inputs.
     * Defaults to the parent element.
     */
    get focusElement() {
      if (this.focusElement_)
        return this.focusElement_;
      return this.parentElement;
    },

    /**
     * @return {boolean} Whether the current timeline is attached to the
     * document.
     */
    get isAttachedToDocument_() {
      var cur = this;
      while (cur.parentNode)
        cur = cur.parentNode;
      return cur == this.ownerDocument;
    },

    get listenToKeys_() {
      if (!this.isAttachedToDocument_)
        return;
      if (!this.focusElement_)
        return true;
      if (this.focusElement.tabIndex >= 0)
        return document.activeElement == this.focusElement;
      return true;
    },

    onKeypress_: function(e) {
      if (!this.listenToKeys_)
        return;

      if (event.keyCode == '/'.charCodeAt(0)) { // / key
        this.findCtl_.focus();
        event.preventDefault();
        return;
      } else if (e.keyCode == '?'.charCodeAt(0)) {
        this.querySelector('.timeline-view-help-button').click();
        e.preventDefault();
      }
    },

    beginFind: function() {
      if (this.findInProgress_)
        return;
      this.findInProgress_ = true;
      var dlg = tracing.TimelineFindControl();
      dlg.controller = new tracing.TimelineFindController();
      dlg.controller.timeline = this.timeline;
      dlg.visible = true;
      dlg.addEventListener('close', function() {
        this.findInProgress_ = false;
      }.bind(this));
      dlg.addEventListener('findNext', function() {
      });
      dlg.addEventListener('findPrevious', function() {
      });
    },

    onSelectionChanged_: function(e) {
      var oldScrollTop = this.timelineContainer_.scrollTop;

      var selection = this.timeline_ ?
        this.timeline_.selection :
        new tracing.TimelineSelection();
      this.analysisEl_.selection = selection;
      this.timelineContainer_.scrollTop = oldScrollTop;
    },

    updateCategoryFilterFromSettings_: function() {
      if (!this.timeline_)
        return;

      // Get the disabled categories from settings.
      var categories = this.settings.keys('categories');
      var disabledCategories = [];
      for (var i = 0; i < categories.length; i++) {
        if (this.settings.get(categories[i], 'true', 'categories') == 'false')
          disabledCategories.push(categories[i]);
      }

      this.timeline_.categoryFilter =
          new tracing.TimelineCategoryFilter(disabledCategories);
    }
  };

  /**
   * Timeline Drag Handle
   * Detects when user clicks handle determines new height of container based
   * on user's vertical mouse move and resizes the target.
   * @constructor
   * @extends {HTMLDivElement}
   * You will need to set target to be the draggable element
   */
  var TimelineDragHandle = base.ui.define('div');

  TimelineDragHandle.prototype = {
    __proto__: HTMLDivElement.prototype,

    decorate: function() {
      this.className = 'timeline-drag-handle';
      this.lastMousePosY = 0;
      this.dragAnalysis = this.dragAnalysis.bind(this);
      this.onMouseUp = this.onMouseUp.bind(this);
      this.addEventListener('mousedown', this.onMouseDown);
    },

    dragAnalysis: function(e) {
      // Compute the difference in height position.
      var dy = this.lastMousePosY - e.clientY;
      // If style is not set, start off with computed height.
      if (!this.target.style.height)
        this.target.style.height = window.getComputedStyle(this.target).height;
      // Calculate new height of the container.
      this.target.style.height = parseInt(this.target.style.height) + dy + 'px';
      this.lastMousePosY = e.clientY;
    },

    onMouseDown: function(e) {
      this.lastMousePosY = e.clientY;
      document.addEventListener('mousemove', this.dragAnalysis);
      document.addEventListener('mouseup', this.onMouseUp);
      e.stopPropagation();
      return false;
    },

    onMouseUp: function(e) {
      document.removeEventListener('mousemove', this.dragAnalysis);
      document.removeEventListener('mouseup', this.onMouseUp);
    }
  };

  return {
    TimelineView: TimelineView
  };
});
<commit_msg>Fix for categories not showing up<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/**
 * @fileoverview TimelineView visualizes TRACE_EVENT events using the
 * tracing.Timeline component and adds in selection summary and control buttons.
 */
base.requireStylesheet('timeline_view');

base.require('timeline');
base.require('timeline_analysis');
base.require('timeline_category_filter_dialog');
base.require('timeline_filter');
base.require('timeline_find_control');
base.require('overlay');
base.require('trace_event_importer');
base.require('linux_perf_importer');
base.require('settings');

base.exportTo('tracing', function() {

  /**
   * TimelineView
   * @constructor
   * @extends {HTMLDivElement}
   */
  var TimelineView = base.ui.define('div');

  TimelineView.prototype = {
    __proto__: HTMLDivElement.prototype,

    decorate: function() {
      this.classList.add('timeline-view');

      // Create individual elements.
      this.titleEl_ = document.createElement('div');
      this.titleEl_.textContent = 'Tracing: ';
      this.titleEl_.className = 'title';

      this.controlDiv_ = document.createElement('div');
      this.controlDiv_.className = 'control';

      this.leftControlsEl_ = document.createElement('div');
      this.leftControlsEl_.className = 'controls';
      this.rightControlsEl_ = document.createElement('div');
      this.rightControlsEl_.className = 'controls';

      var spacingEl = document.createElement('div');
      spacingEl.className = 'spacer';

      this.timelineContainer_ = document.createElement('div');
      this.timelineContainer_.className = 'timeline-container';

      var analysisContainer_ = document.createElement('div');
      analysisContainer_.className = 'analysis-container';

      this.analysisEl_ = new tracing.TimelineAnalysisView();

      this.dragEl_ = new TimelineDragHandle();
      this.dragEl_.target = analysisContainer_;

      this.findCtl_ = new tracing.TimelineFindControl();
      this.findCtl_.controller = new tracing.TimelineFindController();

      this.importErrorsButton_ = this.createImportErrorsButton_();
      this.categoryFilterButton_ = this.createCategoryFilterButton_();
      this.categoryFilterButton_.callback =
        this.updateCategoryFilterFromSettings_.bind(this);
      this.metadataButton_ = this.createMetadataButton_();

      // Connect everything up.
      this.rightControls.appendChild(this.importErrorsButton_);
      this.rightControls.appendChild(this.categoryFilterButton_);
      this.rightControls.appendChild(this.metadataButton_);
      this.rightControls.appendChild(this.findCtl_);
      this.controlDiv_.appendChild(this.titleEl_);
      this.controlDiv_.appendChild(this.leftControlsEl_);
      this.controlDiv_.appendChild(spacingEl);
      this.controlDiv_.appendChild(this.rightControlsEl_);
      this.appendChild(this.controlDiv_);

      this.appendChild(this.timelineContainer_);
      this.appendChild(this.dragEl_);

      analysisContainer_.appendChild(this.analysisEl_);
      this.appendChild(analysisContainer_);

      this.rightControls.appendChild(this.createHelpButton_());

      // Bookkeeping.
      this.onSelectionChangedBoundToThis_ = this.onSelectionChanged_.bind(this);
      document.addEventListener('keypress', this.onKeypress_.bind(this), true);
    },

    createImportErrorsButton_: function() {
      var dlg = new tracing.Overlay();
      dlg.classList.add('timeline-view-import-errors-overlay');
      dlg.autoClose = true;

      var showEl = document.createElement('div');
      showEl.className = 'timeline-button timeline-view-import-errors-button' +
          ' timeline-view-info-button';
      showEl.textContent = 'Import errors!';

      var textEl = document.createElement('div');
      textEl.className = 'info-button-text import-errors-dialog-text';

      var containerEl = document.createElement('div');
      containerEl.className = 'info-button-container' +
          'import-errors-dialog';

      containerEl.textContent = 'Errors occurred during import:';
      containerEl.appendChild(textEl);
      dlg.appendChild(containerEl);

      var that = this;
      function onClick() {
        dlg.visible = true;
        textEl.textContent = that.model.importErrors.join("\n");
      }
      showEl.addEventListener('click', onClick.bind(this));

      function updateVisibility() {
        if (that.model &&
            that.model.importErrors.length)
          showEl.style.display = '';
        else
          showEl.style.display = 'none';
      }
      updateVisibility();
      that.addEventListener('modelChange', updateVisibility);

      return showEl;
    },

    createCategoryFilterButton_: function() {
      // Set by the embedder of the help button that we create in this function.
      var callback;

      var showEl = document.createElement('div');
      showEl.className = 'timeline-button timeline-view-info-button';
      showEl.textContent = 'Categories';
      showEl.__defineSetter__('callback', function(value) {
        callback = value;
      });

      var that = this;
      function onClick() {
        var dlg = new tracing.TimelineCategoryFilterDialog();
        dlg.model = that.model;
        dlg.settings = that.settings;
        dlg.settingUpdatedCallback = callback;
        dlg.visible = true;
      }

      function updateVisibility() {
        if (that.model)
          showEl.style.display = '';
        else
          showEl.style.display = 'none';
      }
      updateVisibility();
      that.addEventListener('modelChange', updateVisibility);

      showEl.addEventListener('click', onClick.bind(this));
      return showEl;
    },

    createHelpButton_: function() {
      var dlg = new tracing.Overlay();
      dlg.classList.add('timeline-view-help-overlay');
      dlg.autoClose = true;
      dlg.additionalCloseKeyCodes.push('?'.charCodeAt(0));

      var showEl = document.createElement('div');
      showEl.className = 'timeline-button timeline-view-help-button';
      showEl.textContent = '?';

      var helpTextEl = document.createElement('div');
      helpTextEl.style.whiteSpace = 'pre';
      helpTextEl.style.fontFamily = 'monospace';
      dlg.appendChild(helpTextEl);

      function onClick(e) {
        dlg.visible = true;
        if (this.timeline_)
          helpTextEl.textContent = this.timeline_.keyHelp;
        else
          helpTextEl.textContent = 'No content loaded. For interesting help,' +
              ' load something.';
        document.addEventListener('click', bgClick);

        // Stop event so it doesn't trigger new click listener on document.
        e.stopPropagation();
        return false;
      }

      showEl.addEventListener('click', onClick.bind(this));

      return showEl;
    },

    createMetadataButton_: function() {
      var dlg = new tracing.Overlay();
      dlg.classList.add('timeline-view-metadata-overlay');
      dlg.autoClose = true;

      var showEl = document.createElement('div');
      showEl.className = 'timeline-button timeline-view-metadata-button' +
          ' timeline-view-info-button';
      showEl.textContent = 'Metadata';

      var textEl = document.createElement('div');
      textEl.className = 'info-button-text metadata-dialog-text';

      var containerEl = document.createElement('div');
      containerEl.className = 'info-button-container metadata-dialog';

      containerEl.textContent = 'Metadata Info:';
      containerEl.appendChild(textEl);
      dlg.appendChild(containerEl);

      var that = this;
      function onClick() {
        dlg.visible = true;

        var metadataStrings = [];

        var model = that.model;
        for (var data in model.metadata) {
          metadataStrings.push(JSON.stringify(model.metadata[data].name) +
            ": " + JSON.stringify(model.metadata[data].value));
        }
        textEl.textContent = metadataStrings.join("\n");
      }
      showEl.addEventListener('click', onClick.bind(this));

      function updateVisibility() {
        if (that.model &&
            that.model.metadata.length)
          showEl.style.display = '';
        else
          showEl.style.display = 'none';
      }
      updateVisibility();
      that.addEventListener('modelChange', updateVisibility);

      return showEl;
    },

    get leftControls() {
      return this.leftControlsEl_;
    },

    get rightControls() {
      return this.rightControlsEl_;
    },

    get title() {
      return this.titleEl_.textContent.substring(
        this.titleEl_.textContent.length - 2);
    },

    set title(text) {
      this.titleEl_.textContent = text + ':';
    },

    set traceData(traceData) {
      this.model = new tracing.TimelineModel(traceData);
    },

    get model() {
      if (this.timeline_)
        return this.timeline_.model;
      return undefined;
    },

    set model(model) {
      var modelInstanceChanged = model != this.model;
      var modelValid = model && model.minTimestamp !== undefined;

      // Remove old timeline if the model has completely changed.
      if (modelInstanceChanged) {
        this.timelineContainer_.textContent = '';
        if (this.timeline_) {
          this.timeline_.removeEventListener(
              'selectionChange', this.onSelectionChangedBoundToThis_);
          this.timeline_.detach();
          this.timeline_ = undefined;
          this.findCtl_.controller.timeline = undefined;
        }
      }

      // Create new timeline if needed.
      if (modelValid && !this.timeline_) {
        this.timeline_ = new tracing.Timeline();
        this.timeline_.focusElement =
            this.focusElement_ ? this.focusElement_ : this.parentElement;
        this.timelineContainer_.appendChild(this.timeline_);
        this.findCtl_.controller.timeline = this.timeline_;
        this.timeline_.addEventListener(
            'selectionChange', this.onSelectionChangedBoundToThis_);
        this.updateCategoryFilterFromSettings_();
      }

      // Set the model.
      if (modelValid)
        this.timeline_.model = model;
      base.dispatchSimpleEvent(this, 'modelChange');

      // Do things that are selection specific
      if (modelInstanceChanged)
        this.onSelectionChanged_();
    },

    get timeline() {
      return this.timeline_;
    },

    get settings() {
      if (!this.settings_)
        this.settings_ = new base.Settings();
      return this.settings_;
    },

    /**
     * Sets the element whose focus state will determine whether
     * to respond to keybaord input.
     */
    set focusElement(value) {
      this.focusElement_ = value;
      if (this.timeline_)
        this.timeline_.focusElement = value;
    },

    /**
     * @return {Element} The element whose focused state determines
     * whether to respond to keyboard inputs.
     * Defaults to the parent element.
     */
    get focusElement() {
      if (this.focusElement_)
        return this.focusElement_;
      return this.parentElement;
    },

    /**
     * @return {boolean} Whether the current timeline is attached to the
     * document.
     */
    get isAttachedToDocument_() {
      var cur = this;
      while (cur.parentNode)
        cur = cur.parentNode;
      return cur == this.ownerDocument;
    },

    get listenToKeys_() {
      if (!this.isAttachedToDocument_)
        return;
      if (!this.focusElement_)
        return true;
      if (this.focusElement.tabIndex >= 0)
        return document.activeElement == this.focusElement;
      return true;
    },

    onKeypress_: function(e) {
      if (!this.listenToKeys_)
        return;

      if (event.keyCode == '/'.charCodeAt(0)) { // / key
        this.findCtl_.focus();
        event.preventDefault();
        return;
      } else if (e.keyCode == '?'.charCodeAt(0)) {
        this.querySelector('.timeline-view-help-button').click();
        e.preventDefault();
      }
    },

    beginFind: function() {
      if (this.findInProgress_)
        return;
      this.findInProgress_ = true;
      var dlg = tracing.TimelineFindControl();
      dlg.controller = new tracing.TimelineFindController();
      dlg.controller.timeline = this.timeline;
      dlg.visible = true;
      dlg.addEventListener('close', function() {
        this.findInProgress_ = false;
      }.bind(this));
      dlg.addEventListener('findNext', function() {
      });
      dlg.addEventListener('findPrevious', function() {
      });
    },

    onSelectionChanged_: function(e) {
      var oldScrollTop = this.timelineContainer_.scrollTop;

      var selection = this.timeline_ ?
        this.timeline_.selection :
        new tracing.TimelineSelection();
      this.analysisEl_.selection = selection;
      this.timelineContainer_.scrollTop = oldScrollTop;
    },

    updateCategoryFilterFromSettings_: function() {
      if (!this.timeline_)
        return;

      // Get the disabled categories from settings.
      var categories = this.settings.keys('categories');
      var disabledCategories = [];
      for (var i = 0; i < categories.length; i++) {
        if (this.settings.get(categories[i], 'true', 'categories') == 'false')
          disabledCategories.push(categories[i]);
      }

      this.timeline_.categoryFilter =
          new tracing.TimelineCategoryFilter(disabledCategories);
    }
  };

  /**
   * Timeline Drag Handle
   * Detects when user clicks handle determines new height of container based
   * on user's vertical mouse move and resizes the target.
   * @constructor
   * @extends {HTMLDivElement}
   * You will need to set target to be the draggable element
   */
  var TimelineDragHandle = base.ui.define('div');

  TimelineDragHandle.prototype = {
    __proto__: HTMLDivElement.prototype,

    decorate: function() {
      this.className = 'timeline-drag-handle';
      this.lastMousePosY = 0;
      this.dragAnalysis = this.dragAnalysis.bind(this);
      this.onMouseUp = this.onMouseUp.bind(this);
      this.addEventListener('mousedown', this.onMouseDown);
    },

    dragAnalysis: function(e) {
      // Compute the difference in height position.
      var dy = this.lastMousePosY - e.clientY;
      // If style is not set, start off with computed height.
      if (!this.target.style.height)
        this.target.style.height = window.getComputedStyle(this.target).height;
      // Calculate new height of the container.
      this.target.style.height = parseInt(this.target.style.height) + dy + 'px';
      this.lastMousePosY = e.clientY;
    },

    onMouseDown: function(e) {
      this.lastMousePosY = e.clientY;
      document.addEventListener('mousemove', this.dragAnalysis);
      document.addEventListener('mouseup', this.onMouseUp);
      e.stopPropagation();
      return false;
    },

    onMouseUp: function(e) {
      document.removeEventListener('mousemove', this.dragAnalysis);
      document.removeEventListener('mouseup', this.onMouseUp);
    }
  };

  return {
    TimelineView: TimelineView
  };
});
<|endoftext|>


<commit_before><commit_msg>fix preview bug<commit_after><|endoftext|>


<commit_before><commit_msg>gcal: Fix script to be async<commit_after><|endoftext|>


<commit_before><commit_msg>Updated preparing bower asset (handlebars)<commit_after><|endoftext|>


<commit_before><commit_msg>Do not run mongo if mongo is available.<commit_after><|endoftext|>


<commit_before><commit_msg>Fix a bug about img.width and img.height<commit_after><|endoftext|>


<commit_before>'use strict';

/*
 * The purpose of this module for executing Saved Scheduled Queries (SSQ)
 * to determine whether to set a notification.
 */

module.exports = function(logger, client, userIndex, userType, dataIndex, dateField, sendAlertEmailCallback) {

  var createSavedQueryBody = function(savedQuery) {
    var savedQueryBody = {
      filter: JSON.parse(savedQuery.esState.filter),
      query: JSON.parse(savedQuery.esState.query),
      size: 1,
      sort: {}
    };
    savedQueryBody.sort[dateField] = {
      order: 'desc'
    };
    return savedQueryBody;
  };

  var checkAndSaveAlert = function(savedQuery, results) {
    if(results.hits.hits.length) {
      // Check the date of the newest item and compare it with the date on which the saved query was last run.
      var resultDate = new Date(results.hits.hits[0]._source[dateField]);
      var lastDate = new Date(savedQuery.lastRunDate);
      if(resultDate.getTime() > lastDate.getTime()) {
        // Update the notification date so the app knows to show an alert.
        savedQuery.notificationHasRun = false;
        savedQuery.notificationDate = new Date();
      }
    }
    return savedQuery;
  };

  var updateUser = function(user, savedQueries, callback) {
    // Update the saved queries for the user in the database.
    client.update({
      index: userIndex,
      type: userType,
      id: user._id,
      body: {
        doc: {
          savedQueries: savedQueries
        }
      }
    }, function(error, response) {
      if(error) {
        logger.error(error, 'Error updating user ' + user._id);
      }
      callback(savedQueries);
    });
  };

  var checkNextQuery = function(savedQueries, updatedQueries, callback) {
    if(!savedQueries.length) {
      callback(updatedQueries);
      return;
    }

    var done = function(savedQuery) {
      // Add the saved query to the updated query list.  Then check the next saved query.
      updatedQueries.push(savedQuery);
      checkNextQuery(savedQueries.slice(1), updatedQueries, callback);
    };

    var savedQuery = savedQueries[0];

    // Check if we need to run the saved query.
    if(savedQuery.sendEmailNotification && savedQuery.esType === 'webpage') {
      client.search({
        index: dataIndex,
        body: createSavedQueryBody(savedQuery)
      }).then(function(results) {
        // Check the results of the saved query for new items.
        done(checkAndSaveAlert(savedQuery, results));
      }, function(error) {
        logger.error(error, 'Error running saved query');
        done(savedQuery);
      });
    } else {
      done(savedQuery);
    }
  };

  var sendAlertEmailIfNeeded = function(user, updatedQueries, callback) {
    var savedQueryNames = updatedQueries.filter(function(query) {
      return query.sendEmailNotification && !query.notificationHasRun;
    }).map(function(query) {
      return query.name;
    });
    if(sendAlertEmailCallback && savedQueryNames.length) {
      sendAlertEmailCallback(user._source.emailAddress, savedQueryNames, function(error, response) {
        if(error) {
          logger.error(error);
        }
        callback();
      });
    } else {
      callback();
    }
  };

  var checkAndSaveNextUser = function(users, period) {
    if(!users.length) {
      return;
    }

    var done = function(updatedQueries) {
      // Send an alert email to the user if needed.  Then check the saved queries for the next user.
      sendAlertEmailIfNeeded(users[0], updatedQueries || [], function() {
        checkAndSaveNextUser(users.slice(1), period);
      });
    };

    var user = users[0];

    // Check if we need to run the saved queries for the user.
    if(user._source.notificationFrequency === period) {
      checkNextQuery(user._source.savedQueries, [], function(updatedQueries) {
        updateUser(user, updatedQueries, done);
      });
    } else {
      done();
    }
  };

  var checkUsers = function(period) {
    return function() {
      // Get the list of all users.
      client.search({
        index: userIndex,
        type: userType,
        body: {}
      }).then(function(users) {
        checkAndSaveNextUser(users.hits.hits, period);
      }, function(error) {
        logger.error(error, 'Error getting users');
      });
    };
  };

  return {
    checkUsersDaily: checkUsers('daily'),
    checkUsersWeekly: checkUsers('weekly')
  };
};
<commit_msg>Adding filter check for running queries in notifyapp and only querying for new webpage types.<commit_after>'use strict';

/*
 * The purpose of this module for executing Saved Scheduled Queries (SSQ)
 * to determine whether to set a notification.
 */

module.exports = function(logger, client, userIndex, userType, dataIndex, dateField, sendAlertEmailCallback) {

  var createSavedQueryBody = function(savedQuery) {
    var savedQueryBody = {
      query: JSON.parse(savedQuery.esState.query),
      size: 1,
      sort: {}
    };
    if(savedQuery.filter) {
      savedQuery.filter = JSON.parse(savedQuery.esState.filter);
    }
    savedQueryBody.sort[dateField] = {
      order: 'desc'
    };
    return savedQueryBody;
  };

  var checkAndSaveAlert = function(savedQuery, results) {
    if(results.hits.hits.length) {
      // Check the date of the newest item and compare it with the date on which the saved query was last run.
      var resultDate = new Date(results.hits.hits[0]._source[dateField]);
      var lastDate = new Date(savedQuery.lastRunDate);
      if(resultDate.getTime() > lastDate.getTime()) {
        // Update the notification date so the app knows to show an alert.
        savedQuery.notificationHasRun = false;
        savedQuery.notificationDate = new Date();
      }
    }
    return savedQuery;
  };

  var updateUser = function(user, savedQueries, callback) {
    // Update the saved queries for the user in the database.
    client.update({
      index: userIndex,
      type: userType,
      id: user._id,
      body: {
        doc: {
          savedQueries: savedQueries
        }
      }
    }, function(error, response) {
      if(error) {
        logger.error(error, 'Error updating user ' + user._id);
      }
      callback(savedQueries);
    });
  };

  var checkNextQuery = function(savedQueries, updatedQueries, callback) {
    if(!savedQueries.length) {
      callback(updatedQueries);
      return;
    }

    var done = function(savedQuery) {
      // Add the saved query to the updated query list.  Then check the next saved query.
      updatedQueries.push(savedQuery);
      checkNextQuery(savedQueries.slice(1), updatedQueries, callback);
    };

    var savedQuery = savedQueries[0];

    // Check if we need to run the saved query.
    if(savedQuery.sendEmailNotification) {
      client.search({
        index: dataIndex,
        type: ['webpage'],
        body: createSavedQueryBody(savedQuery)
      }).then(function(results) {
        // Check the results of the saved query for new items.
        done(checkAndSaveAlert(savedQuery, results));
      }, function(error) {
        logger.error(error, 'Error running saved query');
        done(savedQuery);
      });
    } else {
      done(savedQuery);
    }
  };

  var sendAlertEmailIfNeeded = function(user, updatedQueries, callback) {
    var savedQueryNames = updatedQueries.filter(function(query) {
      return query.sendEmailNotification && !query.notificationHasRun;
    }).map(function(query) {
      return query.name;
    });
    if(sendAlertEmailCallback && savedQueryNames.length) {
      sendAlertEmailCallback(user._source.emailAddress, savedQueryNames, function(error, response) {
        if(error) {
          logger.error(error);
        }
        callback();
      });
    } else {
      callback();
    }
  };

  var checkAndSaveNextUser = function(users, period) {
    if(!users.length) {
      return;
    }

    var done = function(updatedQueries) {
      // Send an alert email to the user if needed.  Then check the saved queries for the next user.
      sendAlertEmailIfNeeded(users[0], updatedQueries || [], function() {
        checkAndSaveNextUser(users.slice(1), period);
      });
    };

    var user = users[0];

    // Check if we need to run the saved queries for the user.
    if(user._source.notificationFrequency === period) {
      checkNextQuery(user._source.savedQueries, [], function(updatedQueries) {
        updateUser(user, updatedQueries, done);
      });
    } else {
      done();
    }
  };

  var checkUsers = function(period) {
    return function() {
      // Get the list of all users.
      client.search({
        index: userIndex,
        type: userType,
        body: {}
      }).then(function(users) {
        checkAndSaveNextUser(users.hits.hits, period);
      }, function(error) {
        logger.error(error, 'Error getting users');
      });
    };
  };

  return {
    checkUsersDaily: checkUsers('daily'),
    checkUsersWeekly: checkUsers('weekly')
  };
};
<|endoftext|>


<commit_before>var _ = require("lodash");
var fs = require("fs");
var path = require("path");
var jsbeautify = require("js-beautify");
var esprima = require("esprima");
var es = require("./es");
var ast = require("./ast");

// TODO: Statically analyze use of undeclared variables.
// TODO: Switch to generating an AST and using escodegen to generate JS.

function transformAst(node) {
    if (!_.isObject(node)) {
        throw new Error("Not a node: " + jsonify(node));
    }
    if (handlers.hasOwnProperty(node.type)) {
        return handlers[node.type](node);
    }
    throw new Error("Unknown AST node: " + jsonify(node));
}

function jsonify(x) {
    return JSON.stringify(x);
}

function literal(node) {
    return es.Literal(node.data);
}

var f = path.join(__dirname, '../runtime/predef.js');
var PREDEF = esprima.parse(fs.readFileSync(f));

function moduleExportsEq(x) {
    return es.ExpressionStatement(
        es.AssignmentExpression('=',
            es.MemberExpression(false,
                es.Identifier('module'),
                es.Identifier('exports')
            ),
            x
        )
    );
}

function cleanIdentifier(s) {
    if (/^if|else|while|do$/.test(s)) {
        return '$' + s;
    }
    return s
        .replace(/\+/g, '$plus')
        .replace(/-/g, '$minus')
        .replace(/\*/g, '$star')
        .replace(/\//g, '$slash')
        .replace(/!/g, '$bang')
        .replace(/\?/g, '$question')
        .replace(/\~/g, '$tilde')
        .replace(/\&/g, '$and')
        .replace(/</g, '$lt')
        .replace(/>/g, '$gt')
        .replace(/=/g, '$eq');
}

var handlers = {
    Root: function(node) {
        var value = transformAst(node.expr);
        var expr = moduleExportsEq(value);
        var body = PREDEF.body.concat([expr]);
        return es.Program(body);
    },
    GetMethod: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_method_get'),
                [prop, obj]
            )
        );
    },
    CallMethod: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        var args = ast.List(node.args);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_method_call'),
                [prop, obj, args]
            )
        );
    },
    GetProperty: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_get'),
                [prop, obj]
            )
        );
    },
    Identifier: function(node) {
        return es.Identifier(cleanIdentifier(node.data));
    },
    Call: function(node) {
        var f = transformAst(node.f);
        var args = node.args.map(transformAst);
        return es.CallExpression(f, args);
    },
    Function: function(node) {
        var params = node
            .parameters
            .map(transformAst);
        var returnExpr = es.ReturnStatement(transformAst(node.body));
        var n = node.parameters.length;
        var arityCheck = esprima.parse(
            "if (arguments.length !== " + n + ") { " +
            "throw new LANG$$js_Error(" +
                "'expected " + n + " argument(s), " +
                "got ' + arguments.length" +
                "); " +
            "}"
        ).body;
        var body = arityCheck.concat([returnExpr]);
        return es.FunctionExpression(
            null,
            params,
            es.BlockStatement(body)
        );
    },
    If: function(node) {
        var p = transformAst(node.p);
        var t = transformAst(node.t);
        var f = transformAst(node.f);
        return es.ConditionalExpression(p, t, f);
    },
    Let: function(node) {
        var declarations = node.bindings.map(function(b) {
            var i = transformAst(b[0]);
            var e = transformAst(b[1]);
            return es.VariableDeclaration('var', [
                es.VariableDeclarator(i, e)
            ]);
        });
        var e = transformAst(node.expr);
        var returnExpr = es.ReturnStatement(e);
        var body = declarations.concat([returnExpr]);
        return es.CallExpression(
            es.FunctionExpression(
                null,
                [],
                es.BlockStatement(body)
            ),
            []
        );
    },
    List: function(node) {
        var pairs = node.data.map(transformAst);
        var array = es.ArrayExpression(pairs);
        var callee = es.Identifier('LANG$$freeze');
        return es.CallExpression(callee, [array]);
    },
    Map: function(node) {
        var pairs = _.flatten(node.data).map(transformAst);
        return es.CallExpression(
            es.Identifier('LANG$$object'),
            [es.ArrayExpression(pairs)]
        );
    },
    Number: literal,
    String: literal,
};

module.exports = transformAst;
<commit_msg>Removes TODO which is already TODONE<commit_after>var _ = require("lodash");
var fs = require("fs");
var path = require("path");
var jsbeautify = require("js-beautify");
var esprima = require("esprima");
var es = require("./es");
var ast = require("./ast");

// TODO: Statically analyze use of undeclared variables.

function transformAst(node) {
    if (!_.isObject(node)) {
        throw new Error("Not a node: " + jsonify(node));
    }
    if (handlers.hasOwnProperty(node.type)) {
        return handlers[node.type](node);
    }
    throw new Error("Unknown AST node: " + jsonify(node));
}

function jsonify(x) {
    return JSON.stringify(x);
}

function literal(node) {
    return es.Literal(node.data);
}

var f = path.join(__dirname, '../runtime/predef.js');
var PREDEF = esprima.parse(fs.readFileSync(f));

function moduleExportsEq(x) {
    return es.ExpressionStatement(
        es.AssignmentExpression('=',
            es.MemberExpression(false,
                es.Identifier('module'),
                es.Identifier('exports')
            ),
            x
        )
    );
}

function cleanIdentifier(s) {
    if (/^if|else|while|do$/.test(s)) {
        return '$' + s;
    }
    return s
        .replace(/\+/g, '$plus')
        .replace(/-/g, '$minus')
        .replace(/\*/g, '$star')
        .replace(/\//g, '$slash')
        .replace(/!/g, '$bang')
        .replace(/\?/g, '$question')
        .replace(/\~/g, '$tilde')
        .replace(/\&/g, '$and')
        .replace(/</g, '$lt')
        .replace(/>/g, '$gt')
        .replace(/=/g, '$eq');
}

var handlers = {
    Root: function(node) {
        var value = transformAst(node.expr);
        var expr = moduleExportsEq(value);
        var body = PREDEF.body.concat([expr]);
        return es.Program(body);
    },
    GetMethod: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_method_get'),
                [prop, obj]
            )
        );
    },
    CallMethod: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        var args = ast.List(node.args);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_method_call'),
                [prop, obj, args]
            )
        );
    },
    GetProperty: function(node) {
        var obj = node.obj;
        var prop = ast.String(node.prop.data);
        return transformAst(
            ast.Call(
                ast.Identifier('LANG$$js_get'),
                [prop, obj]
            )
        );
    },
    Identifier: function(node) {
        return es.Identifier(cleanIdentifier(node.data));
    },
    Call: function(node) {
        var f = transformAst(node.f);
        var args = node.args.map(transformAst);
        return es.CallExpression(f, args);
    },
    Function: function(node) {
        var params = node
            .parameters
            .map(transformAst);
        var returnExpr = es.ReturnStatement(transformAst(node.body));
        var n = node.parameters.length;
        var arityCheck = esprima.parse(
            "if (arguments.length !== " + n + ") { " +
            "throw new LANG$$js_Error(" +
                "'expected " + n + " argument(s), " +
                "got ' + arguments.length" +
                "); " +
            "}"
        ).body;
        var body = arityCheck.concat([returnExpr]);
        return es.FunctionExpression(
            null,
            params,
            es.BlockStatement(body)
        );
    },
    If: function(node) {
        var p = transformAst(node.p);
        var t = transformAst(node.t);
        var f = transformAst(node.f);
        return es.ConditionalExpression(p, t, f);
    },
    Let: function(node) {
        var declarations = node.bindings.map(function(b) {
            var i = transformAst(b[0]);
            var e = transformAst(b[1]);
            return es.VariableDeclaration('var', [
                es.VariableDeclarator(i, e)
            ]);
        });
        var e = transformAst(node.expr);
        var returnExpr = es.ReturnStatement(e);
        var body = declarations.concat([returnExpr]);
        return es.CallExpression(
            es.FunctionExpression(
                null,
                [],
                es.BlockStatement(body)
            ),
            []
        );
    },
    List: function(node) {
        var pairs = node.data.map(transformAst);
        var array = es.ArrayExpression(pairs);
        var callee = es.Identifier('LANG$$freeze');
        return es.CallExpression(callee, [array]);
    },
    Map: function(node) {
        var pairs = _.flatten(node.data).map(transformAst);
        return es.CallExpression(
            es.Identifier('LANG$$object'),
            [es.ArrayExpression(pairs)]
        );
    },
    Number: literal,
    String: literal,
};

module.exports = transformAst;
<|endoftext|>


<commit_before>import http2 from 'http2';
import { TcpInbound, TcpOutbound } from './tcp';
import { logger } from '../utils';

const { HTTP2_HEADER_PATH } = http2.constants;

export class Http2Inbound extends TcpInbound {

  get name() {
    return 'h2:inbound';
  }

}

export class Http2Outbound extends TcpOutbound {

  get name() {
    return 'h2:outbound';
  }

  async _connect({ host, port }) {
    logger.info(`[h2:outbound] [${this.remote}] connecting to h2://${host}:${port}`);
    const session = http2.connect(`https://${host}:${port}`, { ca: [this._config.tls_cert] });
    return session.request({ [HTTP2_HEADER_PATH]: '/' });
  }

}
<commit_msg>transports: http2 now supported<commit_after>import http2 from 'http2';
import { Inbound, Outbound } from './defs';
import { logger } from '../utils';

import {
  CONNECT_TO_REMOTE,
  CONNECTED_TO_REMOTE,
  PIPE_DECODE,
  PIPE_ENCODE,
} from '../constants';

const { HTTP2_HEADER_PATH, HTTP2_HEADER_METHOD } = http2.constants;

export class Http2Inbound extends Inbound {

  _session = null;

  _stream = null;

  _destroyed = false;

  constructor(props) {
    super(props);
    this.onError = this.onError.bind(this);
    this.onReceive = this.onReceive.bind(this);
    this.onTimeout = this.onTimeout.bind(this);
    this.onClose = this.onClose.bind(this);
    if (this.ctx.socket) {
      this._stream = this.ctx.socket;
      this._session = this._stream.session;
      this._stream.on('data', this.onReceive);
      this._session.on('error', this.onError);
      this._session.on('timeout', this.onTimeout);
      this._session.on('close', this.onClose);
      this._session.setTimeout(this._config.timeout);
    }
  }

  get name() {
    return 'h2:inbound';
  }

  get writable() {
    return this._stream && this._stream.writable;
  }

  write(buffer) {
    if (this.writable) {
      this._stream.write(buffer);
    }
  }

  onError(err) {
    logger.warn(`[${this.name}] [${this.remote}] ${err.message}`);
    this.emit('_error', err);
  }

  onReceive(buffer) {
    const direction = this._config.is_client ? PIPE_ENCODE : PIPE_DECODE;
    this.ctx.pipe.feed(direction, buffer);
  }

  onTimeout() {
    logger.warn(`[${this.name}] [${this.remote}] timeout: no I/O on the connection for ${this._config.timeout / 1e3}s`);
    this.onClose();
  }

  onClose() {
    this.close();
    if (this._outbound) {
      this._outbound.close();
      this._outbound = null;
    }
  }

  close() {
    if (this._session) {
      this._session.destroy();
      this._session = null;
    }
    if (!this._destroyed) {
      this._destroyed = true;
      this.emit('close');
    }
  }

}

export class Http2Outbound extends Outbound {

  _session = null;

  _stream = null;

  _destroyed = false;

  constructor(props) {
    super(props);
    this.onError = this.onError.bind(this);
    this.onReceive = this.onReceive.bind(this);
    this.onTimeout = this.onTimeout.bind(this);
    this.onClose = this.onClose.bind(this);
  }

  get name() {
    return 'h2:outbound';
  }

  get writable() {
    return this._stream && this._stream.writable;
  }

  write(buffer) {
    if (this.writable) {
      this._stream.write(buffer);
    }
  }

  onError(err) {
    logger.warn(`[${this.name}] [${this.remote}] ${err.message}`);
    this.emit('_error', err);
  }

  onReceive(buffer) {
    const direction = this._config.is_client ? PIPE_DECODE : PIPE_ENCODE;
    this.ctx.pipe.feed(direction, buffer);
  }

  onTimeout() {
    logger.warn(`[${this.name}] [${this.remote}] timeout: no I/O on the connection for ${this._config.timeout / 1e3}s`);
    this.onClose();
  }

  onClose() {
    this.close();
    if (this._inbound) {
      this._inbound.close();
      this._inbound = null;
    }
  }

  close() {
    if (this._session) {
      this._session.destroy();
      this._session = null;
    }
    if (!this._destroyed) {
      this._destroyed = true;
      this.emit('close');
    }
  }

  onBroadcast(action) {
    switch (action.type) {
      case CONNECT_TO_REMOTE:
        this.onConnectToRemote(action);
        break;
      default:
        break;
    }
  }

  async onConnectToRemote(action) {
    const { host, port, keepAlive, onConnected } = action.payload;
    if (!keepAlive || !this._session) {
      const { server_host, server_port, server_pathname } = this._config;
      try {
        await this.connect({
          host: server_host,
          port: server_port,
          pathname: server_pathname,
        });

        // session
        this._session.on('connect', () => {
          if (typeof onConnected === 'function') {
            try {
              onConnected((buffer) => {
                if (buffer) {
                  const type = this._config.is_client ? PIPE_ENCODE : PIPE_DECODE;
                  this.ctx.pipe.feed(type, buffer, { cid: this.ctx.proxyRequest.cid, host, port });
                }
              });
            } catch (err) {
              logger.error(`[${this.name}] [${this.remote}] onConnected callback error: ${err.message}`);
              this.emit('_error', err);
            }
          }
          this.broadcast({ type: CONNECTED_TO_REMOTE, payload: { host, port } });
        });

        // stream
        this._stream = this._session.request({
          [HTTP2_HEADER_METHOD]: ':post',
          [HTTP2_HEADER_PATH]: server_pathname || '/',
        }, {
          endStream: false,
        });
        this._stream.on('error', this.onError);
        this._stream.on('data', this.onReceive);

      } catch (err) {
        logger.warn(`[${this.name}] [${this.remote}] cannot connect to ${server_host}:${server_port}, ${err.message}`);
        this.emit('_error', err);
        this.onClose();
      }
    } else {
      this.broadcast({ type: CONNECTED_TO_REMOTE, payload: { host, port } });
    }
  }

  async connect({ host, port, pathname }) {
    // close alive connection before create a new one
    if (this._session && !this._session.closed) {
      this._session.destroy();
    }

    const address = `h2://${host}:${port}` + (pathname ? pathname : '');
    logger.info(`[${this.name}] [${this.remote}] connecting to ${address}`);

    const options = {};
    if (this._config.tls_cert_self_signed) {
      options.ca = this._config.tls_cert;
    }
    this._session = http2.connect(`https://${host}:${port}`, options);
    this._session.on('close', this.onClose);
    this._session.on('timeout', this.onTimeout);
    this._session.on('error', this.onError);
    this._session.setTimeout(this._config.timeout);
  }

}
<|endoftext|>


<commit_before>// Copyright (c) 2012, David Haglund
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//     * Redistributions of source code must retain the above
//       copyright notice, this list of conditions and the following
//       disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials
//       provided with the distribution.
//
//     * Neither the name of the copyright holder nor the names of its
//       contributors may be used to endorse or promote products
//       derived from this software without specific prior written
//       permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

/*globals $,document,BigInteger,localStorage */
// TODO: Create a new class for the fetching of the user timeline.
// TODO: Visualize the data with d3.js
// TODO: User workers for the calculations
// TODO: count all hashtags in the tweets
// TODO: count all the user_mentions in the tweets
$(document).ready(function () {
    var userInfoUrl = 'https://api.twitter.com/1/users/show.json?callback=?&include_entities=true&screen_name=',
        userTimelineUrlBase = ('https://api.twitter.com/1/statuses/user_timeline.json'
                            + '?callback=?'
                            + '&count=100'
                            + '&trim_user=1'
                            + '&include_entities=1'
                            + '&include_rts=1'
                            + '&contributor_details=1'
                            + '&screen_name='),
        requestNumber = 0,
        tweets = [],
        maxId = BigInteger(0),
        sinceId = BigInteger(0),
        expected_tweet_count = 0,
        twitterUsername = '';

    function clearErrors() {
        $(".alert").alert('close');
    }

    function postError(msg) {
        $('#alert_container').html(
        '
' +
        '  <button class="close" data-dismiss="alert">x</button>' +
        '
' + msg + '
' +
        '
');
        $(".alert").alert();
    }

    function updateProgressBar() {
        var width = Math.floor(tweets.length / expected_tweet_count * 100);
        $('.bar').width(width + '%');
        $('#progressbar').removeClass('invisible');
    }

    function completeBar() {
        $('.bar').width('100%');
    }

    function hideProgressBar(duration) {
        $('#progressbar').fadeOut(duration, function () {
            $(this).addClass('invisible');
            $('.bar').width('0%');
        });
    }

    function getLocalStorageKey(username) {
        return 'user=' + username.toLowerCase();
    }

    function saveTweetsToLocalStorage() {
        try {
            localStorage[getLocalStorageKey(twitterUsername)] = JSON.stringify(tweets);
        } catch (e) {
            console.log("Local storage is full, failed to store tweets for " + twitterUsername);
        }
    }

    function addTweetsToTag(tag) {
        $.each(tweets, function (i, tweet) {
            $(tag).append('
' + tweet.text + '
');
        });
    }

    function addMaxIdIfPresent(currentUrl) {
        var result = currentUrl;
        if (!maxId.isZero()) {
            result += '&max_id=' + maxId.prev().toString();
        }
        return result;
    }

    function addSinceIdIfPresent(currentUrl) {
        var result = currentUrl;
        if (!sinceId.isZero()) {
            result += "&since_id=" + sinceId.next().toString();
        }
        return result;
    }

    function error(d, msg) {
        hideProgressBar('fast');
        postError('Failed to fetch user timeline: ' + msg);
    }

    function makeSuccessFunction(currentRequestNumber, baseUrl) {
        return function (response) {
            if (currentRequestNumber === requestNumber) {
                if (response.length > 0) { // did get new data
                    if (sinceId.isZero()) { // a response with older tweets
                        tweets = tweets.concat(response);
                    } else if (maxId.isZero()) { // a response with newer tweets
                        tweets = response.concat(tweets);
                    } else { // need to sort!
                        tweets = tweets.concat(response);
                        tweets.sort(function (a, b) {
                            return BigInteger(a.id_str).compare(BigInteger(b.id_str));
                        });
                    }
                    updateProgressBar();
                    maxId = BigInteger(response[response.length - 1].id_str); // The oldest is last
                    fetchUserTimeline(currentRequestNumber, baseUrl);
                } else {
                    completeBar();
                    saveTweetsToLocalStorage();
                    addTweetsToTag('#tweets');
                    hideProgressBar('slow');
                }
            } else {
                console.log('Received response from old search!', currentRequestNumber, requestNumber);
            }
        };
    }

    function makeRequest(currentRequestNumber, baseUrl, requestUrl) {
        $.jsonp({
            url: requestUrl,
            success: makeSuccessFunction(currentRequestNumber, baseUrl),
            error: error
        });
    }

    function fetchUserTimeline(currentRequestNumber, baseUrl) {
        var currentUrl = baseUrl;

        // https://dev.twitter.com/docs/working-with-timelines
        currentUrl = addMaxIdIfPresent(currentUrl);
        currentUrl = addSinceIdIfPresent(currentUrl);
        makeRequest(currentRequestNumber, baseUrl, currentUrl);
    }

    function fetchUserTweets(currentRequestNumber) {
        var localStorageKey = getLocalStorageKey(twitterUsername),
            currentUrl = userTimelineUrlBase + twitterUsername;
        if (localStorage[localStorageKey]) {
            tweets = JSON.parse(localStorage[localStorageKey]);
            updateProgressBar();
            console.log('Found ' + tweets.length + ' tweets in localStorage!');
            if (tweets.length > 0) {
                // set sinceId to only fetch new feeds
                sinceId = BigInteger(tweets[0].id_str);
            }
        }

        $('#tweets').html('');
        fetchUserTimeline(currentRequestNumber, currentUrl);
    }

    function insertLabeledText(selector, label, text) {
        if (text !== '') {
            selector.append('
' + label + '

' + text + '
');
        }
    }

    $('#userSearch').submit(function () {
        var currentRequestNumber, userInfo;
        requestNumber += 1;
        currentRequestNumber = requestNumber;

        // Reset the internal state, for the new request
        tweets = [];
        maxId = BigInteger(0);
        sinceId = BigInteger(0);
        twitterUsername = $('#twitter_username_query').val().toLowerCase();

        clearErrors();

        $.jsonp({
            url: userInfoUrl + twitterUsername,
            success: function (response) {
                userInfo = $('#user_info');
                userInfo.html('');
                insertLabeledText(userInfo, 'Name', response.name);
                insertLabeledText(userInfo, 'Screen name', '@' + response.screen_name);
                insertLabeledText(userInfo, 'Id', response.id);
                insertLabeledText(userInfo, 'Location', response.location);
                insertLabeledText(userInfo, 'Followers', response.followers_count);
                insertLabeledText(userInfo, 'Following', response.friends_count);
                insertLabeledText(userInfo, 'Favorites', response.favourites_count);
                insertLabeledText(userInfo, 'Tweets', response.statuses_count);
                insertLabeledText(userInfo, 'Created', response.created_at);

                $('#user_image').html('');
                $('#user_description').html('
' + response.description + '
');

                expected_tweet_count = response.statuses_count;
                updateProgressBar();
                fetchUserTweets(currentRequestNumber);
            },
            error: function (d, msg) {
                hideProgressBar('fast');
                postError('Failed to find user ' + twitterUsername);
            }
        });
        return false;
    });
});
<commit_msg>Making it more OO creating a TwitterUserTimeline object more changes is needed to make it not know so much about the world.<commit_after>// Copyright (c) 2012, David Haglund
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//     * Redistributions of source code must retain the above
//       copyright notice, this list of conditions and the following
//       disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials
//       provided with the distribution.
//
//     * Neither the name of the copyright holder nor the names of its
//       contributors may be used to endorse or promote products
//       derived from this software without specific prior written
//       permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

/*globals $,document,BigInteger,localStorage */
// TODO: Create a new class for the fetching of the user timeline.
// TODO: Visualize the data with d3.js
// TODO: User workers for the calculations
// TODO: count all hashtags in the tweets
// TODO: count all the user_mentions in the tweets

$(document).ready(function () {
    var userInfoUrl = 'https://api.twitter.com/1/users/show.json?callback=?&include_entities=true&screen_name=',
        globalTwitterUsername = '',
        twitterUserTimeline = null;

    function postError(msg) {
        $('#alert_container').html(
        '
' +
        '  <button class="close" data-dismiss="alert">x</button>' +
        '
' + msg + '
' +
        '
');
        $(".alert").alert();
    }

    function completeBar() {
        $('.bar').width('100%');
    }

    function hideProgressBar(duration) {
        $('#progressbar').fadeOut(duration, function () {
            $(this).addClass('invisible');
            $('.bar').width('0%');
        });
    }

    function TwitterUserTimeline() {
        var userTimelineUrlBase = ('https://api.twitter.com/1/statuses/user_timeline.json'
                + '?callback=?'
                + '&count=100'
                + '&trim_user=1'
                + '&include_entities=1'
                + '&include_rts=1'
                + '&contributor_details=1'
                + '&screen_name='),
            requestNumber = 0,
            tweets = [],
            maxId = BigInteger(0),
            sinceId = BigInteger(0),
            expectedTweetCount = 0,
            twitterUsername = '';

        function updateProgressBar() {
            var width = Math.floor(tweets.length / expectedTweetCount * 100);
            $('.bar').width(width + '%');
            $('#progressbar').removeClass('invisible');
        }

        function getLocalStorageKey(username) {
            return 'user=' + username.toLowerCase();
        }

        function saveTweetsToLocalStorage() {
            try {
                localStorage[getLocalStorageKey(twitterUsername)] = JSON.stringify(tweets);
            } catch (e) {
                console.log("Local storage is full, failed to store tweets for " + twitterUsername);
            }
        }

        function addTweetsToTag(tag) {
            $.each(tweets, function (i, tweet) {
                $(tag).append('
' + tweet.text + '
');
            });
        }

        function addMaxIdIfPresent(currentUrl) {
            var result = currentUrl;
            if (!maxId.isZero()) {
                result += '&max_id=' + maxId.prev().toString();
            }
            return result;
        }

        function addSinceIdIfPresent(currentUrl) {
            var result = currentUrl;
            if (!sinceId.isZero()) {
                result += "&since_id=" + sinceId.next().toString();
            }
            return result;
        }

        function error(d, msg) {
            hideProgressBar('fast');
            postError('Failed to fetch user timeline: ' + msg);
        }

        function makeSuccessFunction(currentRequestNumber, baseUrl) {
            return function (response) {
                if (currentRequestNumber === requestNumber) {
                    if (response.length > 0) { // did get new data
                        if (sinceId.isZero()) { // a response with older tweets
                            tweets = tweets.concat(response);
                        } else if (maxId.isZero()) { // a response with newer tweets
                            tweets = response.concat(tweets);
                        } else { // need to sort!
                            tweets = tweets.concat(response);
                            tweets.sort(function (a, b) {
                                return BigInteger(a.id_str).compare(BigInteger(b.id_str));
                            });
                        }
                        updateProgressBar();
                        maxId = BigInteger(response[response.length - 1].id_str); // The oldest is last
                        fetchUserTimeline(currentRequestNumber, baseUrl);
                    } else {
                        completeBar();
                        saveTweetsToLocalStorage();
                        addTweetsToTag('#tweets');
                        hideProgressBar('slow');
                    }
                } else {
                    console.log('Received response from old search!', currentRequestNumber, requestNumber);
                }
            };
        }

        function makeRequest(currentRequestNumber, baseUrl, requestUrl) {
            $.jsonp({
                url: requestUrl,
                success: makeSuccessFunction(currentRequestNumber, baseUrl),
                error: error
            });
        }

        function fetchUserTimeline(currentRequestNumber, baseUrl) {
            var currentUrl = baseUrl;

            // https://dev.twitter.com/docs/working-with-timelines
            currentUrl = addMaxIdIfPresent(currentUrl);
            currentUrl = addSinceIdIfPresent(currentUrl);
            makeRequest(currentRequestNumber, baseUrl, currentUrl);
        }

        this.fetchUserTweets = function (username,  tweetCount) {
            var currentRequestNumber;
            requestNumber += 1;
            currentRequestNumber = requestNumber;
            twitterUsername = username;
            expectedTweetCount = tweetCount;
            tweets = [];
            maxId = BigInteger(0);
            sinceId = BigInteger(0);
            updateProgressBar();

            var localStorageKey = getLocalStorageKey(twitterUsername),
            currentUrl = userTimelineUrlBase + twitterUsername;
            if (localStorage[localStorageKey]) {
                tweets = JSON.parse(localStorage[localStorageKey]);
                updateProgressBar();
                console.log('Found ' + tweets.length + ' tweets in localStorage!');
                if (tweets.length > 0) {
                    // set sinceId to only fetch new feeds
                    sinceId = BigInteger(tweets[0].id_str);
                }
            }

            $('#tweets').html('');
            fetchUserTimeline(currentRequestNumber, currentUrl);
        };
    }

    function clearErrors() {
        $(".alert").alert('close');
    }

    function insertLabeledText(selector, label, text) {
        if (text !== '') {
            selector.append('
' + label + '

' + text + '
');
        }
    }

    twitterUserTimeline = new TwitterUserTimeline();

    $('#userSearch').submit(function () {
        var userInfo;

        // Reset the internal state, for the new request

        globalTwitterUsername = $('#twitter_username_query').val().toLowerCase();

        clearErrors();

        $.jsonp({
            url: userInfoUrl + globalTwitterUsername,
            success: function (response) {
                userInfo = $('#user_info');
                userInfo.html('');
                insertLabeledText(userInfo, 'Name', response.name);
                insertLabeledText(userInfo, 'Screen name', '@' + response.screen_name);
                insertLabeledText(userInfo, 'Id', response.id);
                insertLabeledText(userInfo, 'Location', response.location);
                insertLabeledText(userInfo, 'Followers', response.followers_count);
                insertLabeledText(userInfo, 'Following', response.friends_count);
                insertLabeledText(userInfo, 'Favorites', response.favourites_count);
                insertLabeledText(userInfo, 'Tweets', response.statuses_count);
                insertLabeledText(userInfo, 'Created', response.created_at);

                $('#user_image').html('');
                $('#user_description').html('
' + response.description + '
');

                twitterUserTimeline.fetchUserTweets(globalTwitterUsername, response.statuses_count);
            },
            error: function (d, msg) {
                hideProgressBar('fast');
                postError('Failed to find user ' + globalTwitterUsername);
            }
        });
        return false;
    });
});
<|endoftext|>


<commit_before>import _ from 'lodash';
import React from 'react';
import {Row, Col, ControlLabel} from 'react-bootstrap';
// import {change, changeWithKey} from 'redux-form';

class Complex extends React.Component {

  constructor() {
    super();
    this.state = {
      children: [],
      collapsed: false,
    };
  }

  componentWillMount() {
    if (this.props.field && this.props.field.collapsed) {
      let state = false;
      if (this.props.field.collapsed === true) {
        state = true;
      }
      this.setState({'collapsed': state});
    }
  }

  render() {
    const labelSize = () => {
      if (_.has(this.props.field, 'labelSize')) {
        return this.props.field.labelSize;
      }

      return {sm: 2};
    };

    const fieldSize = () => {
      if (_.has(this.props.field, 'fieldSize')) {
        return this.props.field.fieldSize;
      }
      return {sm: 10};
    };

    const toggle = () => {
      let state = false;
      if (this.state.collapsed === false) {
        state = true;
      }
      this.setState({'collapsed': state});
    };

    if (this.state.collapsed === true) {
      return (
        <Row>
          <Col componentClass={ControlLabel} {...labelSize()}>
            <button type="button" onClick={toggle} className="btn btn-link">+</button>
            {this.props.field.label}
          </Col>
        </Row>
      );
    }

    return (
      <Row>
        <Col componentClass={ControlLabel} {...labelSize()}>
          <button type="button" onClick={toggle} className="btn btn-link">-</button>
          {this.props.field.label}
        </Col>
        <Col {...fieldSize()}>
          {this.props.properties.length > 0 && this.props.properties.map((child, index) =>

              {this.props.field.fields.length > 0 && this.props.field.fields.map((field, fieldIndex) => {
                const re = new RegExp(RegExp.quote(this.props.field.name + '.'), 'g');
                return (

                   {this.props.addComplexField(field, this.props.size, child[field.name.replace(re, '')])}

                );
              })}

                <button type="button" className={'btn btn-danger ' + _.get(this.props.field.removeBtn, 'className')} onClick={() => {
                  this.props.properties.removeField(index);
                }}> {this.props.field.removeBtn.label}
                </button>

          )}
          <button
            type="button"
            onClick={() => this.props.properties.addField()}
            className={'btn btn-default ' + _.get(this.props.field.addBtn, 'className')}>
              {this.props.field.addBtn.label}
            </button>
        </Col>
      </Row>
    );
  }
}

Complex.propTypes = {
  properties: React.PropTypes.array,
  addComplexField: React.PropTypes.func,
  size: React.PropTypes.string,
  field: React.PropTypes.object
};
Complex.defaultProps = {};

export default Complex;
<commit_msg>added complex toggle<commit_after>import _ from 'lodash';
import React from 'react';
import {Row, Col, ControlLabel} from 'react-bootstrap';
// import {change, changeWithKey} from 'redux-form';

class Complex extends React.Component {

  constructor() {
    super();
    this.state = {
      children: []
    };
  }

  render() {

    const labelSize = () => {
      if (_.has(this.props.field, 'labelSize')) {
        return this.props.field.labelSize;
      }

      return {sm: 2};
    };

    const fieldSize = () => {
      if (_.has(this.props.field, 'fieldSize')) {
        return this.props.field.fieldSize;
      }
      return {sm: 10};
    };

    return (
      <Row>
        <Col componentClass={ControlLabel} {...labelSize()}>{this.props.field.label}</Col>
        <Col {...fieldSize()}>
          {this.props.static === false &&
            <button type="button" onClick={() => this.props.properties.addField({})}
                  className={'btn btn-default ' + _.get(this.props.field.addBtn, 'className')}>
              {this.props.field.addBtn.label}
            </button>
          }
          {this.props.properties.length > 0 && this.props.properties.map((child, index) =>

              {this.props.field.fields.length > 0 && this.props.field.fields.map((field, fieldIndex) => {
                const re = new RegExp(RegExp.quote(this.props.field.name + '.'), 'g');
                return (

                   {this.props.addComplexField(field, this.props.size, child[field.name.replace(re, '')])}

                );
              })}

              {this.props.static === false &&

                  <button type="button" className={'btn btn-danger ' + _.get(this.props.field.removeBtn, 'className')} onClick={() => {
                    this.props.properties.removeField(index);
                  }}> {this.props.field.removeBtn.label}
                  </button>

              }

          )}
        </Col>
      </Row>
    );
  }
}

Complex.propTypes = {
  properties: React.PropTypes.array,
  addComplexField: React.PropTypes.func,
  size: React.PropTypes.string,
  field: React.PropTypes.object
};
Complex.defaultProps = {};

export default Complex;
<|endoftext|>


<commit_before><commit_msg>Vector3 type<commit_after>let sqrMagnitude = function(v) {
  return Vector3.dot(v, v);
};

class Vector3 {
  constructor(x = 0, y = 0, z = 0) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  get magnitude() {
    return Math.sqrt(sqrMagnitude(this));
  }

  get sqrMagnitude() {
    return sqrMagnitude(this);
  }

  static dot(vec1, vec2) {
    return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
  }

  static cross(vec1, vec2) {
    return new Vector3(vec1.y * vec2.z - vec2.y * vec1.z, vec1.z * vec2.x - vec2.z * vec1.x, vec1.x * vec2.y - vec2.x * vec1.y);
  }

  clone() {
    return new Vector2(this.x, this.y, this.z);
  }

  add(vector) {
    this.x += vector.x;
    this.y += vector.y;
    this.z += vector.z;
  }

  subtract(vector) {
    this.x -= vector.x;
    this.y -= vector.y;
    this.z -= vector.z;
  }

  multiply(vector) {
    this.x *= vector.x;
    this.y *= vector.y;
    this.z *= vector.z;
  }

  divide(vector) {
    this.x /= vector.x;
    this.y /= vector.y;
    this.z /= vector.z;
  }

  normalize() {
    this.x = this.x / this.magnitude;
    this.y = this.y / this.magnitude;
    this.z = this.z / this.magnitude;
  }

  equals(v) {
    return (this.x === v.x && this.y === v.y && this.z === v.z);
  }
}

export default Vector3;
<|endoftext|>


<commit_before>import DText from "../dtext.js";

export default class WikiPages {
  static initialize() {
    if ($("#c-wiki-pages").length === 0) {
      return;
    }

    WikiPages.initializeCollapsibleHeadings();
    WikiPages.initializeTableOfContents();
  }

  // Add collapse/expand button to headings.
  static initializeCollapsibleHeadings() {
    const $headings = $("#wiki-page-body :header");

    if ($headings.length < 3) {
      return;
    }

    $headings.prepend(
      $('')
    ).click(e => {
      const $button = $(e.target);

      // Collapse everything up to the next heading at the same
      // level, or up to the alias/implication list at the bottom of the page.
      $button.toggleClass('ui-icon-triangle-1-e ui-icon-triangle-1-s');
      $button.parent('h1').nextUntil('p.hint, h1').slideToggle();
      $button.parent('h2').nextUntil('p.hint, h1, h2').slideToggle();
      $button.parent('h3').nextUntil('p.hint, h1, h2, h3').slideToggle();
      $button.parent('h4').nextUntil('p.hint, h1, h2, h3, h4').slideToggle();
      $button.parent('h5').nextUntil('p.hint, h1, h2, h3, h4, h5').slideToggle();
      $button.parent('h6').nextUntil('p.hint, h1, h2, h3, h4, h5, h6').slideToggle();
    });
  }

  // Add Table of Contents expandable.
  static initializeTableOfContents() {
    const $headings = $("#wiki-page-body :header");

    const hasToC =
      $("div.expandable-header > span")
      .filter((i, e) => $(e).text().match(/table of contents/i))
      .length > 0;

    if ($headings.length < 3 || hasToC) {
      return;
    }

    const $toc =
      DText.createExpandable(
        'Table of Contents',
        '
This table of contents was autogenerated by Danbooru EX.

'
      ).prependTo('#wiki-page-body');

    // Build ToC. Create a nested heirarchy matching the hierarchy of
    // headings on the page; an h5 following an h4 opens a new submenu,
    // another h4 closes the submenu. Likewise for h5, h6, etc.
    let $submenu = null;
    let $menu = $toc.find('ul');
    let level = $headings.length > 0
              ? parseInt($headings.first().get(0).tagName[1])
              : undefined;

    $headings.each((i, e) => {
      const header = $(e).text();
      const anchor =
        'dtext-' + header.toLowerCase()
                    .replace(/[^a-z]+/g, '-')
                    .replace(/^-|-$/, '');

      const nextLevel = parseInt(e.tagName[1]);
      if (nextLevel > level) {
        $submenu = $('

');
        $menu.append($submenu);
        $menu = $submenu;
      } else if (nextLevel < level) {
        $menu = $menu.parent();
      }

      $(e).attr('id', anchor);
      $menu.append($(`<li><a href="#${anchor}">${header}</a></li>`));

      level = nextLevel;
    });
  }
}
<commit_msg>[fix] Fix clicking links in collapsible wiki headers.<commit_after>import DText from "../dtext.js";

export default class WikiPages {
  static initialize() {
    if ($("#c-wiki-pages").length === 0) {
      return;
    }

    WikiPages.initializeCollapsibleHeadings();
    WikiPages.initializeTableOfContents();
  }

  // Add collapse/expand button to headings.
  static initializeCollapsibleHeadings() {
    const $headings = $("#wiki-page-body :header");

    if ($headings.length < 3) {
      return;
    }

    $headings.prepend($(''));
    $headings.find("a.collapsible-header").click(e => {
      const $button = $(e.target);

      // Collapse everything up to the next heading at the same
      // level, or up to the alias/implication list at the bottom of the page.
      $button.toggleClass('ui-icon-triangle-1-e ui-icon-triangle-1-s');
      $button.parent('h1').nextUntil('p.hint, h1').slideToggle();
      $button.parent('h2').nextUntil('p.hint, h1, h2').slideToggle();
      $button.parent('h3').nextUntil('p.hint, h1, h2, h3').slideToggle();
      $button.parent('h4').nextUntil('p.hint, h1, h2, h3, h4').slideToggle();
      $button.parent('h5').nextUntil('p.hint, h1, h2, h3, h4, h5').slideToggle();
      $button.parent('h6').nextUntil('p.hint, h1, h2, h3, h4, h5, h6').slideToggle();
    });
  }

  // Add Table of Contents expandable.
  static initializeTableOfContents() {
    const $headings = $("#wiki-page-body :header");

    const hasToC =
      $("div.expandable-header > span")
      .filter((i, e) => $(e).text().match(/table of contents/i))
      .length > 0;

    if ($headings.length < 3 || hasToC) {
      return;
    }

    const $toc =
      DText.createExpandable(
        'Table of Contents',
        '
This table of contents was autogenerated by Danbooru EX.

'
      ).prependTo('#wiki-page-body');

    // Build ToC. Create a nested heirarchy matching the hierarchy of
    // headings on the page; an h5 following an h4 opens a new submenu,
    // another h4 closes the submenu. Likewise for h5, h6, etc.
    let $submenu = null;
    let $menu = $toc.find('ul');
    let level = $headings.length > 0
              ? parseInt($headings.first().get(0).tagName[1])
              : undefined;

    $headings.each((i, e) => {
      const header = $(e).text();
      const anchor =
        'dtext-' + header.toLowerCase()
                    .replace(/[^a-z]+/g, '-')
                    .replace(/^-|-$/, '');

      const nextLevel = parseInt(e.tagName[1]);
      if (nextLevel > level) {
        $submenu = $('

');
        $menu.append($submenu);
        $menu = $submenu;
      } else if (nextLevel < level) {
        $menu = $menu.parent();
      }

      $(e).attr('id', anchor);
      $menu.append($(`<li><a href="#${anchor}">${header}</a></li>`));

      level = nextLevel;
    });
  }
}
<|endoftext|>


<commit_before>// build-dependencies: _

var UpdateBarrier = Bacon.UpdateBarrier = (function() {
  var rootEvent;
  var waiterObs = [];
  var waiters = {};
  var aftersStack = []
  var aftersStackHeight = 0
  var flushed = {}

  function ensureStackHeight(h) {
    if (h <= aftersStackHeight) return
    if (!aftersStack[h-1]) {
      aftersStack[h-1]=[[],0]
    }
    aftersStackHeight = h
  }

  var afterTransaction = function(obs, f) {
    if (rootEvent || aftersStack.length) {
      ensureStackHeight(1)
      var stackIndexForThisObs = 0
      while (stackIndexForThisObs < aftersStackHeight - 1) {
        if (containsObs(obs, aftersStack[stackIndexForThisObs][0])) {
          // this observable is already being processed at this stack index -> use this index
          break;
        }
        stackIndexForThisObs++
      }
      var listFromStack = aftersStack[stackIndexForThisObs][0]
      listFromStack.push([obs, f]);
      if (!rootEvent) {
        processAfters() // wouldn't be called otherwise
      }
    } else {
      return f();
    }
  };

  function containsObs(obs, aftersList) {
    for (var i = 0; i < aftersList.length; i++) {
      if (aftersList[i][0].id == obs.id) return true
    }
    return false
  }

  function processAfters() {
    let stackSizeAtStart = aftersStackHeight
    if (!stackSizeAtStart) return
    while (aftersStackHeight >= stackSizeAtStart) { // to prevent sinking to levels started by others
      var topOfStack = aftersStack[aftersStackHeight - 1]
      if (!topOfStack) throw new Error("Unexpected stack top: " + topOfStack)
      var [topAfters, index] = topOfStack
      if (index < topAfters.length) {
        var [obs, after] = topAfters[index];
        topOfStack[1]++ // increase index already here to indicate that this level is being processed
        ensureStackHeight(aftersStackHeight+1) // to ensure there's a new level for recursively added afters
        var callSuccess = false
        try {
          after()
          callSuccess = true
          while (aftersStackHeight > stackSizeAtStart && aftersStack[aftersStackHeight-1][0].length == 0) {
            aftersStackHeight--
          }
        } finally {
          if (!callSuccess) {
            aftersStack = []
            aftersStackHeight = 0 // reset state to prevent stale updates after error
          }
        }
      } else {
        topOfStack[0] = []
        topOfStack[1] = 0 // reset this level
        break
      }
    }
  }

  var whenDoneWith = function(obs, f) {
    if (rootEvent) {
      var obsWaiters = waiters[obs.id];
      if (!(typeof obsWaiters !== "undefined" && obsWaiters !== null)) {
        obsWaiters = waiters[obs.id] = [f];
        return waiterObs.push(obs);
      } else {
        return obsWaiters.push(f);
      }
    } else {
      return f();
    }
  };

  var flush = function() {
    while (waiterObs.length > 0) {
      flushWaiters(0, true);
    }
    flushed = {}
  };

  var flushWaiters = function(index, deps) {
    var obs = waiterObs[index];
    var obsId = obs.id;
    var obsWaiters = waiters[obsId];
    waiterObs.splice(index, 1);
    delete waiters[obsId];
    if (deps && waiterObs.length > 0) {
      flushDepsOf(obs);
    }
    for (var i = 0, f; i < obsWaiters.length; i++) {
      f = obsWaiters[i];
      f();
    }
  };

  var flushDepsOf = function(obs) {
    if (flushed[obs.id]) return
    var deps = obs.internalDeps();
    for (var i = 0, dep; i < deps.length; i++) {
      dep = deps[i];
      flushDepsOf(dep);
      if (waiters[dep.id]) {
        var index = _.indexOf(waiterObs, dep);
        flushWaiters(index, false);
      }
    }
    flushed[obs.id] = true
  };

  var inTransaction = function(event, context, f, args) {
    if (rootEvent) {
      //console.log("in tx")
      return f.apply(context, args);
    } else {
      //console.log("start tx")
      rootEvent = event;
      try {
        var result = f.apply(context, args);
        //console.log("done with tx")
        flush();
      } finally {
        rootEvent = undefined;
        processAfters()
      }
      return result;
    }
  };

  var currentEventId = function() {
    return rootEvent ? rootEvent.id : undefined
  };

  var wrappedSubscribe = function(obs, sink) {
    var unsubd = false;
    var shouldUnsub = false;
    var doUnsub = function() {
      shouldUnsub = true;
      return shouldUnsub;
    };
    var unsub = function() {
      unsubd = true;
      return doUnsub();
    };
    doUnsub = obs.dispatcher.subscribe(function(event) {
      return afterTransaction(obs, function() {
        if (!unsubd) {
          var reply = sink(event);
          if (reply === Bacon.noMore) {
            return unsub();
          }
        }
      });
    });
    if (shouldUnsub) {
      doUnsub();
    }
    return unsub;
  };

  var hasWaiters = function() { return waiterObs.length > 0; };

  return { whenDoneWith, hasWaiters, inTransaction, currentEventId, wrappedSubscribe, afterTransaction };
}
)();
<commit_msg>correct check for whether processing afters in UpdateBarrier<commit_after>// build-dependencies: _

var UpdateBarrier = Bacon.UpdateBarrier = (function() {
  var rootEvent;
  var waiterObs = [];
  var waiters = {};
  var aftersStack = []
  var aftersStackHeight = 0
  var flushed = {}
  var processingAfters = false

  function toString() {
    return _.toString({rootEvent, processingAfters, waiterObs, waiters, aftersStack, aftersStackHeight, flushed})
  }

  function ensureStackHeight(h) {
    if (h <= aftersStackHeight) return
    if (!aftersStack[h-1]) {
      aftersStack[h-1]=[[],0]
    }
    aftersStackHeight = h
  }

  function afterTransaction(obs, f) {
    if (rootEvent || processingAfters) {
      ensureStackHeight(1)
      var stackIndexForThisObs = 0
      while (stackIndexForThisObs < aftersStackHeight - 1) {
        if (containsObs(obs, aftersStack[stackIndexForThisObs][0])) {
          // this observable is already being processed at this stack index -> use this index
          break;
        }
        stackIndexForThisObs++
      }
      var listFromStack = aftersStack[stackIndexForThisObs][0]
      listFromStack.push([obs, f]);
      if (!rootEvent) {
        processAfters() // wouldn't be called otherwise
      }
    } else {
      return f();
    }
  };

  function containsObs(obs, aftersList) {
    for (var i = 0; i < aftersList.length; i++) {
      if (aftersList[i][0].id == obs.id) return true
    }
    return false
  }

  function processAfters() {
    let stackSizeAtStart = aftersStackHeight
    if (!stackSizeAtStart) return
    let isRoot = !processingAfters
    processingAfters = true
    try {
      while (aftersStackHeight >= stackSizeAtStart) { // to prevent sinking to levels started by others
        var topOfStack = aftersStack[aftersStackHeight - 1]
        if (!topOfStack) throw new Error("Unexpected stack top: " + topOfStack)
        var [topAfters, index] = topOfStack
        if (index < topAfters.length) {
          var [obs, after] = topAfters[index];
          topOfStack[1]++ // increase index already here to indicate that this level is being processed
          ensureStackHeight(aftersStackHeight+1) // to ensure there's a new level for recursively added afters
          var callSuccess = false
          try {
            after()
            callSuccess = true
            while (aftersStackHeight > stackSizeAtStart && aftersStack[aftersStackHeight-1][0].length == 0) {
              aftersStackHeight--
            }
          } finally {
            if (!callSuccess) {
              aftersStack = []
              aftersStackHeight = 0 // reset state to prevent stale updates after error
            }
          }
        } else {
          topOfStack[0] = []
          topOfStack[1] = 0 // reset this level
          break
        }
      }
    } finally {
      if (isRoot) processingAfters = false
    }
  }

  function whenDoneWith(obs, f) {
    if (rootEvent) {
      var obsWaiters = waiters[obs.id];
      if (!(typeof obsWaiters !== "undefined" && obsWaiters !== null)) {
        obsWaiters = waiters[obs.id] = [f];
        return waiterObs.push(obs);
      } else {
        return obsWaiters.push(f);
      }
    } else {
      return f();
    }
  };

  function flush() {
    while (waiterObs.length > 0) {
      flushWaiters(0, true);
    }
    flushed = {}
  };

  function flushWaiters(index, deps) {
    var obs = waiterObs[index];
    var obsId = obs.id;
    var obsWaiters = waiters[obsId];
    waiterObs.splice(index, 1);
    delete waiters[obsId];
    if (deps && waiterObs.length > 0) {
      flushDepsOf(obs);
    }
    for (var i = 0, f; i < obsWaiters.length; i++) {
      f = obsWaiters[i];
      f();
    }
  };

  function flushDepsOf(obs) {
    if (flushed[obs.id]) return
    var deps = obs.internalDeps();
    for (var i = 0, dep; i < deps.length; i++) {
      dep = deps[i];
      flushDepsOf(dep);
      if (waiters[dep.id]) {
        var index = _.indexOf(waiterObs, dep);
        flushWaiters(index, false);
      }
    }
    flushed[obs.id] = true
  };

  function inTransaction(event, context, f, args) {
    if (rootEvent) {
      //console.log("in tx")
      return f.apply(context, args);
    } else {
      //console.log("start tx")
      rootEvent = event;
      try {
        var result = f.apply(context, args);
        //console.log("done with tx")
        flush();
      } finally {
        rootEvent = undefined;
        processAfters()
      }
      return result;
    }
  };

  function currentEventId() {
    return rootEvent ? rootEvent.id : undefined
  };

  function wrappedSubscribe(obs, sink) {
    var unsubd = false;
    var shouldUnsub = false;
    var doUnsub = function() {
      shouldUnsub = true;
      return shouldUnsub;
    };
    var unsub = function() {
      unsubd = true;
      return doUnsub();
    };
    doUnsub = obs.dispatcher.subscribe(function(event) {
      return afterTransaction(obs, function() {
        if (!unsubd) {
          var reply = sink(event);
          if (reply === Bacon.noMore) {
            return unsub();
          }
        }
      });
    });
    if (shouldUnsub) {
      doUnsub();
    }
    return unsub;
  };

  var hasWaiters = function() { return waiterObs.length > 0; };

  return { toString, whenDoneWith, hasWaiters, inTransaction, currentEventId, wrappedSubscribe, afterTransaction };
}
)();
<|endoftext|>


<commit_before><commit_msg>Fix startup syntax errors<commit_after><|endoftext|>


<commit_before><commit_msg>dajax<commit_after><|endoftext|>


<commit_before><commit_msg>Languages in "Language settings" should be non-translated.<commit_after><|endoftext|>


<commit_before><commit_msg>starting to create registration and some changes to the deployment<commit_after><|endoftext|>


<commit_before><commit_msg>Clean up global<commit_after><|endoftext|>


<commit_before><commit_msg>Fix #14<commit_after><|endoftext|>


<commit_before><commit_msg>Basic functionality implemented.<commit_after><|endoftext|>


<commit_before><commit_msg>Lazy socket connection.<commit_after><|endoftext|>


<commit_before><commit_msg>post event fix<commit_after><|endoftext|>