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

/**
 * @fileoverview Renderer for {@link goog.ui.SubMenu}s.
 *
 */

goog.provide('goog.ui.SubMenuRenderer');

goog.require('goog.a11y.aria');
goog.require('goog.a11y.aria.State');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.style');
goog.require('goog.ui.Menu');
goog.require('goog.ui.MenuItemRenderer');

goog.forwardDeclare('goog.ui.SubMenu');

/**
 * Default renderer for {@link goog.ui.SubMenu}s.  Each item has the following
 * structure:
 *
 *

 *      ...(menuitem content)...
 *

 *        ... (submenu content) ...
 *

 *

 *
 * @constructor
 * @extends {goog.ui.MenuItemRenderer}
 * @final
 */
goog.ui.SubMenuRenderer = function() {
  goog.ui.MenuItemRenderer.call(this);
};
goog.inherits(goog.ui.SubMenuRenderer, goog.ui.MenuItemRenderer);
goog.addSingletonGetter(goog.ui.SubMenuRenderer);

/**
 * Default CSS class to be applied to the root element of components rendered
 * by this renderer.
 * @type {string}
 */
goog.ui.SubMenuRenderer.CSS_CLASS = goog.getCssName('goog-submenu');

/**
 * The CSS class for submenus that displays the submenu arrow.
 * @type {string}
 * @private
 */
goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_ =
    goog.getCssName('goog-submenu-arrow');

/**
 * Overrides {@link goog.ui.MenuItemRenderer#createDom} by adding
 * the additional class 'goog-submenu' to the created element,
 * and passes the element to {@link goog.ui.SubMenuItemRenderer#addArrow_}
 * to add an child element that can be styled to show an arrow.
 * @param {goog.ui.Control} control goog.ui.SubMenu to render.
 * @return {!Element} Root element for the item.
 * @override
 */
goog.ui.SubMenuRenderer.prototype.createDom = function(control) {
  var subMenu = /** @type {goog.ui.SubMenu} */ (control);
  var element =
      goog.ui.SubMenuRenderer.superClass_.createDom.call(this, subMenu);
  goog.asserts.assert(element);
  goog.dom.classlist.add(element, goog.ui.SubMenuRenderer.CSS_CLASS);
  this.addArrow_(subMenu, element);
  return element;
};

/**
 * Overrides {@link goog.ui.MenuItemRenderer#decorate} by adding
 * the additional class 'goog-submenu' to the decorated element,
 * and passing the element to {@link goog.ui.SubMenuItemRenderer#addArrow_}
 * to add a child element that can be styled to show an arrow.
 * Also searches the element for a child with the class goog-menu. If a
 * matching child element is found, creates a goog.ui.Menu, uses it to
 * decorate the child element, and passes that menu to subMenu.setMenu.
 * @param {goog.ui.Control} control goog.ui.SubMenu to render.
 * @param {Element} element Element to decorate.
 * @return {!Element} Root element for the item.
 * @override
 */
goog.ui.SubMenuRenderer.prototype.decorate = function(control, element) {
  var subMenu = /** @type {goog.ui.SubMenu} */ (control);
  element =
      goog.ui.SubMenuRenderer.superClass_.decorate.call(this, subMenu, element);
  goog.asserts.assert(element);
  goog.dom.classlist.add(element, goog.ui.SubMenuRenderer.CSS_CLASS);
  this.addArrow_(subMenu, element);

  // Search for a child menu and decorate it.
  var childMenuEls = goog.dom.getElementsByTagNameAndClass(
      goog.dom.TagName.DIV, goog.getCssName('goog-menu'), element);
  if (childMenuEls.length) {
    var childMenu = new goog.ui.Menu(subMenu.getDomHelper());
    var childMenuEl = childMenuEls[0];
    // Hide the menu element before attaching it to the document body; see
    // bug 1089244.
    goog.style.setElementShown(childMenuEl, false);
    subMenu.getDomHelper().getDocument().body.appendChild(childMenuEl);
    childMenu.decorate(childMenuEl);
    subMenu.setMenu(childMenu, true);
  }
  return element;
};

/**
 * Takes a menu item's root element, and sets its content to the given text
 * caption or DOM structure.  Overrides the superclass immplementation by
 * making sure that the submenu arrow structure is preserved.
 * @param {Element} element The item's root element.
 * @param {goog.ui.ControlContent} content Text caption or DOM structure to be
 *     set as the item's content.
 * @override
 */
goog.ui.SubMenuRenderer.prototype.setContent = function(element, content) {
  // Save the submenu arrow element, if present.
  var contentElement = this.getContentElement(element);
  var arrowElement = contentElement && contentElement.lastChild;
  goog.ui.SubMenuRenderer.superClass_.setContent.call(this, element, content);
  // If the arrowElement was there, is no longer there, and really was an arrow,
  // reappend it.
  if (arrowElement && contentElement.lastChild != arrowElement &&
      goog.dom.classlist.contains(
          /** @type {!Element} */ (arrowElement),
          goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_)) {
    contentElement.appendChild(arrowElement);
  }
};

/**
 * Overrides {@link goog.ui.MenuItemRenderer#initializeDom} to tweak
 * the DOM structure for the span.goog-submenu-arrow element
 * depending on the text direction (LTR or RTL). When the SubMenu is RTL
 * the arrow will be given the additional class of goog-submenu-arrow-rtl,
 * and the arrow will be moved up to be the first child in the SubMenu's
 * element. Otherwise the arrow will have the class goog-submenu-arrow-ltr,
 * and be kept as the last child of the SubMenu's element.
 * @param {goog.ui.Control} control goog.ui.SubMenu whose DOM is to be
 *     initialized as it enters the document.
 * @override
 */
goog.ui.SubMenuRenderer.prototype.initializeDom = function(control) {
  var subMenu = /** @type {goog.ui.SubMenu} */ (control);
  goog.ui.SubMenuRenderer.superClass_.initializeDom.call(this, subMenu);
  var element = subMenu.getContentElement();
  var arrow = subMenu.getDomHelper().getElementsByTagNameAndClass(
      goog.dom.TagName.SPAN, goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_,
      element)[0];
  goog.ui.SubMenuRenderer.setArrowTextContent_(subMenu, arrow);
  if (arrow != element.lastChild) {
    element.appendChild(arrow);
  }
  var subMenuElement = subMenu.getElement();
  goog.asserts.assert(
      subMenuElement, 'The sub menu DOM element cannot be null.');
  goog.a11y.aria.setState(
      subMenuElement, goog.a11y.aria.State.HASPOPUP, 'true');
};

/**
 * Appends a child node with the class goog.getCssName('goog-submenu-arrow') or
 * 'goog-submenu-arrow-rtl' which can be styled to show an arrow.
 * @param {goog.ui.SubMenu} subMenu SubMenu to render.
 * @param {Element} element Element to decorate.
 * @private
 */
goog.ui.SubMenuRenderer.prototype.addArrow_ = function(subMenu, element) {
  var arrow = subMenu.getDomHelper().createDom(goog.dom.TagName.SPAN);
  arrow.className = goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_;
  goog.ui.SubMenuRenderer.setArrowTextContent_(subMenu, arrow);
  this.getContentElement(element).appendChild(arrow);
};

/**
 * The unicode char for a left arrow.
 * @type {string}
 * @private
 */
goog.ui.SubMenuRenderer.LEFT_ARROW_ = '\u25C4';

/**
 * The unicode char for a right arrow.
 * @type {string}
 * @private
 */
goog.ui.SubMenuRenderer.RIGHT_ARROW_ = '\u25BA';

/**
 * Set the text content of an arrow.
 * @param {goog.ui.SubMenu} subMenu The sub menu that owns the arrow.
 * @param {Element} arrow The arrow element.
 * @private
 */
goog.ui.SubMenuRenderer.setArrowTextContent_ = function(subMenu, arrow) {
  // Fix arrow rtl
  var leftArrow = goog.ui.SubMenuRenderer.LEFT_ARROW_;
  var rightArrow = goog.ui.SubMenuRenderer.RIGHT_ARROW_;

  goog.asserts.assert(arrow);

  if (subMenu.isRightToLeft()) {
    goog.dom.classlist.add(arrow, goog.getCssName('goog-submenu-arrow-rtl'));
    // Unicode character - Black left-pointing pointer iff aligned to end.
    goog.dom.setTextContent(
        arrow, subMenu.isAlignedToEnd() ? leftArrow : rightArrow);
  } else {
    goog.dom.classlist.remove(arrow, goog.getCssName('goog-submenu-arrow-rtl'));
    // Unicode character - Black right-pointing pointer iff aligned to end.
    goog.dom.setTextContent(
        arrow, subMenu.isAlignedToEnd() ? rightArrow : leftArrow);
  }
};
<commit_msg>Remove the final declaration from the SubMenuRenderer. A new HalfHoverSubMenuRenderer will be created for a submenu that opens only on hover on the side containing the arrow (see cl/205391966).<commit_after>// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Renderer for {@link goog.ui.SubMenu}s.
 *
 */

goog.provide('goog.ui.SubMenuRenderer');

goog.require('goog.a11y.aria');
goog.require('goog.a11y.aria.State');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.style');
goog.require('goog.ui.Menu');
goog.require('goog.ui.MenuItemRenderer');

goog.forwardDeclare('goog.ui.SubMenu');

/**
 * Default renderer for {@link goog.ui.SubMenu}s.  Each item has the following
 * structure:
 *
 *

 *      ...(menuitem content)...
 *

 *        ... (submenu content) ...
 *

 *

 *
 * @constructor
 * @extends {goog.ui.MenuItemRenderer}
 */
goog.ui.SubMenuRenderer = function() {
  goog.ui.MenuItemRenderer.call(this);
};
goog.inherits(goog.ui.SubMenuRenderer, goog.ui.MenuItemRenderer);
goog.addSingletonGetter(goog.ui.SubMenuRenderer);

/**
 * Default CSS class to be applied to the root element of components rendered
 * by this renderer.
 * @type {string}
 */
goog.ui.SubMenuRenderer.CSS_CLASS = goog.getCssName('goog-submenu');

/**
 * The CSS class for submenus that displays the submenu arrow.
 * @type {string}
 * @private
 */
goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_ =
    goog.getCssName('goog-submenu-arrow');

/**
 * Overrides {@link goog.ui.MenuItemRenderer#createDom} by adding
 * the additional class 'goog-submenu' to the created element,
 * and passes the element to {@link goog.ui.SubMenuItemRenderer#addArrow_}
 * to add an child element that can be styled to show an arrow.
 * @param {goog.ui.Control} control goog.ui.SubMenu to render.
 * @return {!Element} Root element for the item.
 * @override
 */
goog.ui.SubMenuRenderer.prototype.createDom = function(control) {
  var subMenu = /** @type {goog.ui.SubMenu} */ (control);
  var element =
      goog.ui.SubMenuRenderer.superClass_.createDom.call(this, subMenu);
  goog.asserts.assert(element);
  goog.dom.classlist.add(element, goog.ui.SubMenuRenderer.CSS_CLASS);
  this.addArrow_(subMenu, element);
  return element;
};

/**
 * Overrides {@link goog.ui.MenuItemRenderer#decorate} by adding
 * the additional class 'goog-submenu' to the decorated element,
 * and passing the element to {@link goog.ui.SubMenuItemRenderer#addArrow_}
 * to add a child element that can be styled to show an arrow.
 * Also searches the element for a child with the class goog-menu. If a
 * matching child element is found, creates a goog.ui.Menu, uses it to
 * decorate the child element, and passes that menu to subMenu.setMenu.
 * @param {goog.ui.Control} control goog.ui.SubMenu to render.
 * @param {Element} element Element to decorate.
 * @return {!Element} Root element for the item.
 * @override
 */
goog.ui.SubMenuRenderer.prototype.decorate = function(control, element) {
  var subMenu = /** @type {goog.ui.SubMenu} */ (control);
  element =
      goog.ui.SubMenuRenderer.superClass_.decorate.call(this, subMenu, element);
  goog.asserts.assert(element);
  goog.dom.classlist.add(element, goog.ui.SubMenuRenderer.CSS_CLASS);
  this.addArrow_(subMenu, element);

  // Search for a child menu and decorate it.
  var childMenuEls = goog.dom.getElementsByTagNameAndClass(
      goog.dom.TagName.DIV, goog.getCssName('goog-menu'), element);
  if (childMenuEls.length) {
    var childMenu = new goog.ui.Menu(subMenu.getDomHelper());
    var childMenuEl = childMenuEls[0];
    // Hide the menu element before attaching it to the document body; see
    // bug 1089244.
    goog.style.setElementShown(childMenuEl, false);
    subMenu.getDomHelper().getDocument().body.appendChild(childMenuEl);
    childMenu.decorate(childMenuEl);
    subMenu.setMenu(childMenu, true);
  }
  return element;
};

/**
 * Takes a menu item's root element, and sets its content to the given text
 * caption or DOM structure.  Overrides the superclass immplementation by
 * making sure that the submenu arrow structure is preserved.
 * @param {Element} element The item's root element.
 * @param {goog.ui.ControlContent} content Text caption or DOM structure to be
 *     set as the item's content.
 * @override
 */
goog.ui.SubMenuRenderer.prototype.setContent = function(element, content) {
  // Save the submenu arrow element, if present.
  var contentElement = this.getContentElement(element);
  var arrowElement = contentElement && contentElement.lastChild;
  goog.ui.SubMenuRenderer.superClass_.setContent.call(this, element, content);
  // If the arrowElement was there, is no longer there, and really was an arrow,
  // reappend it.
  if (arrowElement && contentElement.lastChild != arrowElement &&
      goog.dom.classlist.contains(
          /** @type {!Element} */ (arrowElement),
          goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_)) {
    contentElement.appendChild(arrowElement);
  }
};

/**
 * Overrides {@link goog.ui.MenuItemRenderer#initializeDom} to tweak
 * the DOM structure for the span.goog-submenu-arrow element
 * depending on the text direction (LTR or RTL). When the SubMenu is RTL
 * the arrow will be given the additional class of goog-submenu-arrow-rtl,
 * and the arrow will be moved up to be the first child in the SubMenu's
 * element. Otherwise the arrow will have the class goog-submenu-arrow-ltr,
 * and be kept as the last child of the SubMenu's element.
 * @param {goog.ui.Control} control goog.ui.SubMenu whose DOM is to be
 *     initialized as it enters the document.
 * @override
 */
goog.ui.SubMenuRenderer.prototype.initializeDom = function(control) {
  var subMenu = /** @type {goog.ui.SubMenu} */ (control);
  goog.ui.SubMenuRenderer.superClass_.initializeDom.call(this, subMenu);
  var element = subMenu.getContentElement();
  var arrow = subMenu.getDomHelper().getElementsByTagNameAndClass(
      goog.dom.TagName.SPAN, goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_,
      element)[0];
  goog.ui.SubMenuRenderer.setArrowTextContent_(subMenu, arrow);
  if (arrow != element.lastChild) {
    element.appendChild(arrow);
  }
  var subMenuElement = subMenu.getElement();
  goog.asserts.assert(
      subMenuElement, 'The sub menu DOM element cannot be null.');
  goog.a11y.aria.setState(
      subMenuElement, goog.a11y.aria.State.HASPOPUP, 'true');
};

/**
 * Appends a child node with the class goog.getCssName('goog-submenu-arrow') or
 * 'goog-submenu-arrow-rtl' which can be styled to show an arrow.
 * @param {goog.ui.SubMenu} subMenu SubMenu to render.
 * @param {Element} element Element to decorate.
 * @private
 */
goog.ui.SubMenuRenderer.prototype.addArrow_ = function(subMenu, element) {
  var arrow = subMenu.getDomHelper().createDom(goog.dom.TagName.SPAN);
  arrow.className = goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_;
  goog.ui.SubMenuRenderer.setArrowTextContent_(subMenu, arrow);
  this.getContentElement(element).appendChild(arrow);
};

/**
 * The unicode char for a left arrow.
 * @type {string}
 * @private
 */
goog.ui.SubMenuRenderer.LEFT_ARROW_ = '\u25C4';

/**
 * The unicode char for a right arrow.
 * @type {string}
 * @private
 */
goog.ui.SubMenuRenderer.RIGHT_ARROW_ = '\u25BA';

/**
 * Set the text content of an arrow.
 * @param {goog.ui.SubMenu} subMenu The sub menu that owns the arrow.
 * @param {Element} arrow The arrow element.
 * @private
 */
goog.ui.SubMenuRenderer.setArrowTextContent_ = function(subMenu, arrow) {
  // Fix arrow rtl
  var leftArrow = goog.ui.SubMenuRenderer.LEFT_ARROW_;
  var rightArrow = goog.ui.SubMenuRenderer.RIGHT_ARROW_;

  goog.asserts.assert(arrow);

  if (subMenu.isRightToLeft()) {
    goog.dom.classlist.add(arrow, goog.getCssName('goog-submenu-arrow-rtl'));
    // Unicode character - Black left-pointing pointer iff aligned to end.
    goog.dom.setTextContent(
        arrow, subMenu.isAlignedToEnd() ? leftArrow : rightArrow);
  } else {
    goog.dom.classlist.remove(arrow, goog.getCssName('goog-submenu-arrow-rtl'));
    // Unicode character - Black right-pointing pointer iff aligned to end.
    goog.dom.setTextContent(
        arrow, subMenu.isAlignedToEnd() ? rightArrow : leftArrow);
  }
};
<|endoftext|>


<commit_before>import { RecurrenceParser, DateObj } from 'recurrence-parser'
import { Conductor, DeviceType, TriggerType } from 'timeline-state-resolver'
import Store from '../renderer/store/index'
import { MediaScanner } from './media'
import { Resolver } from 'superfly-timeline'

const conductor = new Conductor()
const scanner = new MediaScanner()
const parser = new RecurrenceParser(name => scanner.getMediaDuration(name), name => scanner.getFolderContents(name), null, () => null)

conductor.on('error', (...err) => console.log(...err))
// conductor.on('debug', (...info) => console.log(...info))

conductor.init()
  .then(() => {
    conductor.mapping = {
      'bg': {
        device: DeviceType.CASPARCG,
        deviceId: 'ccg',
        channel: 1,
        layer: 10
      },
      'PLAYOUT': {
        device: DeviceType.CASPARCG,
        deviceId: 'ccg',
        channel: 1,
        layer: 20
      }
    }
  })
  .then(() => {
    return conductor.addDevice('ccg', { type: DeviceType.CASPARCG, options: { host: '127.0.0.1', port: 5250, useScheduling: false } })
  })
  .then(() => {
    createTimeline()
    scanner.on('changed', () => createTimeline())
    Store.watch(state => state.playoutSchedule, () => createTimeline())
    Store.watch(state => state.settings.decklinkInput, () => createTimeline())
  })

let timeout = setTimeout(() => createTimeline(), 0)

function createTimeline () {
  const tls = []
  let time = Date.now() - 6 * 3600 * 1000 // 6 hrs ago
  let stopCondition = Date.now() + 18 * 3600 * 1000 // 18 hrs ahead

  parser.schedule = JSON.parse(JSON.stringify(Store.state.playoutSchedule))

  while (time < stopCondition) {
    const tl = parser.getNextTimeline(new DateObj(time))
    tls.push(tl)
    time = tl.end + 1
  }

  const decklink = (volume, start, end) => {
    const tlObj = {
      id: `bg_decklink_${volume ? 'unmute' : 'mute'}_${start}`,
      LLayer: 'bg',
      trigger: {
        type: TriggerType.TIME_ABSOLUTE,
        value: start
      },
      duration: end ? end - start : 0,
      content: {
        type: 'input',
        attributes: {
          device: Number(Store.state.settings.decklinkInput)
        },
        mixer: {
          volume: volume ? 1 : 0,
          inTransition: {
            duration: 250
          }
        }
      }
    }

    return tlObj
  }

  const timeline = []
  let last = Date.now()
  for (const tl of tls) {
    timeline.push(decklink(true, last, tl.start))
    timeline.push(decklink(false, tl.start, tl.end))

    const bg = []
    for (let i = 0; i < tl.timeline.length; i++) { // make bg objects
      const obj = JSON.parse(JSON.stringify(tl.timeline[i]))
      obj.id += '_bg'
      obj.originalLLayer = obj.LLayer
      obj.LLayer += '_BG'
      obj.isBackground = true
      if (i === 0) {
        obj.trigger = {
          type: TriggerType.TIME_RELATIVE,
          value: `#${tl.timeline[0].id} - 2000`
        }
        obj.duration = 2000
      } else {
        obj.trigger = {
          type: TriggerType.LOGICAL,
          value: `#${tl.timeline[i - 1].id}`
        }
        obj.duration = 0
      }
      bg.push(obj)
    }

    timeline.push(...tl.timeline)
    timeline.push(...bg)

    for (const obj of tl.timeline) {
      if (obj.content.muted && obj.duration > 500) {
        const dl = {
          id: 'bg_decklink_' + obj.id,
          LLayer: 'bg',
          trigger: {
            type: TriggerType.TIME_RELATIVE,
            value: `#${obj.id}.start`
          },
          duration: obj.duration,
          priority: 1,
          content: {
            type: 'input',
            attributes: {
              device: 1
            },
            mixer: {
              volume: 1,
              inTransition: {
                duration: 250
              }
            }
          }
        }
        timeline.push(dl)
      }
    }
    last = tl.end
  }
  timeline.push(decklink(true, last))

  conductor.timeline = timeline
  clearTimeout(timeout)
  timeout = setTimeout(() => createTimeline(), 12 * 3600 * 1000) // re-parse in 12 hours
}

setInterval(() => {
  const update = {}

  if (!conductor.timeline) return

  const tl = Resolver.getState(conductor.timeline, Date.now())

  const curLayer = tl.LLayers['PLAYOUT'] || tl.LLayers['bg']

  if (curLayer.LLayer === 'bg' && Store.state.playoutState.nowPlaying !== 'Nothing') {
    update.nowPlaying = 'Nothing'
  } else if (curLayer.LLayer === 'PLAYOUT' && curLayer.content.attributes.file !== Store.state.playoutState.nowPlaying) {
    update.nowPlaying = curLayer.content.attributes.file
  }
  if (curLayer.resolved.endTime !== Store.state.playoutState.nextUpTime) {
    update.nextUpTime = curLayer.resolved.endTime
  }
  if (curLayer.resolved.startTime !== Store.state.playoutState.startTime) {
    update.startTime = curLayer.resolved.startTime
  }

  const nextTl = Resolver.getState(conductor.timeline, curLayer.resolved.endTime)
  if (nextTl.LLayers['PLAYOUT']) {
    if (nextTl.LLayers['PLAYOUT'].content.attributes.file !== Store.state.playoutState.nextUp) {
      update.nextUp = nextTl.LLayers['PLAYOUT'].content.attributes.file
    }
  } else {
    if (Store.state.playoutState.nextUp !== 'Nothing') {
      update.nextUp = 'Nothing'
    }
  }

  if (Object.keys(update).length > 0) Store.dispatch('updatePlayoutState', update)
}, 200)
<commit_msg>fix: don't run parser on empty schedule<commit_after>import { RecurrenceParser, DateObj } from 'recurrence-parser'
import { Conductor, DeviceType, TriggerType } from 'timeline-state-resolver'
import Store from '../renderer/store/index'
import { MediaScanner } from './media'
import { Resolver } from 'superfly-timeline'

const conductor = new Conductor()
const scanner = new MediaScanner()
const parser = new RecurrenceParser(name => scanner.getMediaDuration(name), name => scanner.getFolderContents(name), null, () => null)

conductor.on('error', (...err) => console.log(...err))
// conductor.on('debug', (...info) => console.log(...info))

conductor.init()
  .then(() => {
    conductor.mapping = {
      'bg': {
        device: DeviceType.CASPARCG,
        deviceId: 'ccg',
        channel: 1,
        layer: 10
      },
      'PLAYOUT': {
        device: DeviceType.CASPARCG,
        deviceId: 'ccg',
        channel: 1,
        layer: 20
      }
    }
  })
  .then(() => {
    return conductor.addDevice('ccg', { type: DeviceType.CASPARCG, options: { host: '127.0.0.1', port: 5250, useScheduling: false } })
  })
  .then(() => {
    createTimeline()
    scanner.on('changed', () => createTimeline())
    Store.watch(state => state.playoutSchedule, () => createTimeline())
    Store.watch(state => state.settings.decklinkInput, () => createTimeline())
  })

let timeout = setTimeout(() => createTimeline(), 0)

function createTimeline () {
  if (Store.state.playoutSchedule.length === 0) {
    clearTimeout(timeout)
    timeout = setTimeout(() => createTimeline(), 12 * 3600 * 1000) // re-parse in 12 hours
    return
  }
  const tls = []
  let time = Date.now() - 6 * 3600 * 1000 // 6 hrs ago
  let stopCondition = Date.now() + 18 * 3600 * 1000 // 18 hrs ahead

  parser.schedule = JSON.parse(JSON.stringify(Store.state.playoutSchedule))

  while (time < stopCondition) {
    const tl = parser.getNextTimeline(new DateObj(time))
    tls.push(tl)
    time = tl.end + 1
  }

  const decklink = (volume, start, end) => {
    const tlObj = {
      id: `bg_decklink_${volume ? 'unmute' : 'mute'}_${start}`,
      LLayer: 'bg',
      trigger: {
        type: TriggerType.TIME_ABSOLUTE,
        value: start
      },
      duration: end ? end - start : 0,
      content: {
        type: 'input',
        attributes: {
          device: Number(Store.state.settings.decklinkInput)
        },
        mixer: {
          volume: volume ? 1 : 0,
          inTransition: {
            duration: 250
          }
        }
      }
    }

    return tlObj
  }

  const timeline = []
  let last = Date.now()
  for (const tl of tls) {
    timeline.push(decklink(true, last, tl.start))
    timeline.push(decklink(false, tl.start, tl.end))

    const bg = []
    for (let i = 0; i < tl.timeline.length; i++) { // make bg objects
      const obj = JSON.parse(JSON.stringify(tl.timeline[i]))
      obj.id += '_bg'
      obj.originalLLayer = obj.LLayer
      obj.LLayer += '_BG'
      obj.isBackground = true
      if (i === 0) {
        obj.trigger = {
          type: TriggerType.TIME_RELATIVE,
          value: `#${tl.timeline[0].id} - 2000`
        }
        obj.duration = 2000
      } else {
        obj.trigger = {
          type: TriggerType.LOGICAL,
          value: `#${tl.timeline[i - 1].id}`
        }
        obj.duration = 0
      }
      bg.push(obj)
    }

    timeline.push(...tl.timeline)
    timeline.push(...bg)

    for (const obj of tl.timeline) {
      if (obj.content.muted && obj.duration > 500) {
        const dl = {
          id: 'bg_decklink_' + obj.id,
          LLayer: 'bg',
          trigger: {
            type: TriggerType.TIME_RELATIVE,
            value: `#${obj.id}.start`
          },
          duration: obj.duration,
          priority: 1,
          content: {
            type: 'input',
            attributes: {
              device: 1
            },
            mixer: {
              volume: 1,
              inTransition: {
                duration: 250
              }
            }
          }
        }
        timeline.push(dl)
      }
    }
    last = tl.end
  }
  timeline.push(decklink(true, last))

  conductor.timeline = timeline
  clearTimeout(timeout)
  timeout = setTimeout(() => createTimeline(), 12 * 3600 * 1000) // re-parse in 12 hours
}

setInterval(() => {
  const update = {}

  if (!conductor.timeline || conductor.timeline.length === 0) return

  const tl = Resolver.getState(conductor.timeline, Date.now())

  const curLayer = tl.LLayers['PLAYOUT'] || tl.LLayers['bg']

  if (curLayer.LLayer === 'bg' && Store.state.playoutState.nowPlaying !== 'Nothing') {
    update.nowPlaying = 'Nothing'
  } else if (curLayer.LLayer === 'PLAYOUT' && curLayer.content.attributes.file !== Store.state.playoutState.nowPlaying) {
    update.nowPlaying = curLayer.content.attributes.file
  }
  if (curLayer.resolved.endTime !== Store.state.playoutState.nextUpTime) {
    update.nextUpTime = curLayer.resolved.endTime
  }
  if (curLayer.resolved.startTime !== Store.state.playoutState.startTime) {
    update.startTime = curLayer.resolved.startTime
  }

  const nextTl = Resolver.getState(conductor.timeline, curLayer.resolved.endTime)
  if (nextTl.LLayers['PLAYOUT']) {
    if (nextTl.LLayers['PLAYOUT'].content.attributes.file !== Store.state.playoutState.nextUp) {
      update.nextUp = nextTl.LLayers['PLAYOUT'].content.attributes.file
    }
  } else {
    if (Store.state.playoutState.nextUp !== 'Nothing') {
      update.nextUp = 'Nothing'
    }
  }

  if (Object.keys(update).length > 0) Store.dispatch('updatePlayoutState', update)
}, 200)
<|endoftext|>


<commit_before>/*!
    Copyright (C) 2013 Google Inc., authors, and contributors <see AUTHORS file>
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
    Created By: dan@reciprocitylabs.com
    Maintained By: dan@reciprocitylabs.com
*/

(function(can) {

  var _mustache_path,
      overdue_compute;

  overdue_compute = can.compute(function(val) {
    if (this.attr("status") === "Verified") {
      return "";
    }
    var date = moment(this.attr("end_date"));
    if(date && date.isBefore(new Date())){
      return "overdue";
    }
    return "";
  });

  _mustache_path = GGRC.mustache_path + "/cycles";
  can.Model.Cacheable("CMS.Models.Cycle", {
    root_object: "cycle",
    root_collection: "cycles",
    category: "workflow",
    findAll: "GET /api/cycles",
    findOne: "GET /api/cycles/{id}",
    create: "POST /api/cycles",
    update: "PUT /api/cycles/{id}",
    destroy: "DELETE /api/cycles/{id}",

    attributes: {
      workflow: "CMS.Models.Workflow.stub",
      cycle_task_groups: "CMS.Models.CycleTaskGroup.stubs",
      modified_by: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub"
    },

    tree_view_options: {
      show_view: _mustache_path + "/tree.mustache",
      //footer_view: _mustache_path + "/tree_footer.mustache",
      draw_children: true,
      child_options: [
        {
          model: "CycleTaskGroup",
          mapping: "cycle_task_groups",
          allow_creating: false
        }
      ]
    },
    init: function(){
      var that = this;
      this._super.apply(this, arguments);
      this.bind("created", function(ev, instance) {
        if (instance instanceof that) {
          if (instance.workflow.reify().selfLink) {
            instance.workflow.reify().refresh();
          }
        }
      });
    }
  }, {});

  _mustache_path = GGRC.mustache_path + "/cycle_task_entries";
  can.Model.Cacheable("CMS.Models.CycleTaskEntry", {
    root_object: "cycle_task_entry",
    root_collection: "cycle_task_entries",
    category: "workflow",
    findAll: "GET /api/cycle_task_entries",
    findOne: "GET /api/cycle_task_entries/{id}",
    create: "POST /api/cycle_task_entries",
    update: "PUT /api/cycle_task_entries/{id}",
    destroy: "DELETE /api/cycle_task_entries/{id}",

    attributes: {
      cycle_task_group_object_task: "CMS.Models.CycleTaskGroupObjectTask.stub",
      modified_by: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub",
      documents : "CMS.Models.Document.stubs",
    },

    tree_view_options: {
      show_view: _mustache_path + "/tree.mustache",
      footer_view: _mustache_path + "/tree_footer.mustache",
      child_options: [{
        //0: Documents
        model: "Document",
        mapping: "documents",
        show_view: _mustache_path + "/documents.mustache",
        footer_view: _mustache_path + "/documents_footer.mustache"
      }],
    }
  }, {});

  _mustache_path = GGRC.mustache_path + "/cycle_task_groups";
  can.Model.Cacheable("CMS.Models.CycleTaskGroup", {
    root_object: "cycle_task_group",
    root_collection: "cycle_task_groups",
    category: "workflow",
    findAll: "GET /api/cycle_task_groups",
    findOne: "GET /api/cycle_task_groups/{id}",
    create: "POST /api/cycle_task_groups",
    update: "PUT /api/cycle_task_groups/{id}",
    destroy: "DELETE /api/cycle_task_groups/{id}",

    attributes: {
      cycle: "CMS.Models.Cycle.stub",
      task_group: "CMS.Models.TaskGroup.stub",
      cycle_task_group_objects: "CMS.Models.CycleTaskGroupObject.stubs",
      modified_by: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub"
    },

    tree_view_options: {
      show_view: _mustache_path + "/tree.mustache",
      //footer_view: _mustache_path + "/tree_footer.mustache",
      draw_children: true,
      child_options: [
        {
          model: "CycleTaskGroupObject",
          mapping: "cycle_task_group_objects",
          allow_creating: false
        }
      ]
    }
  }, {
    overdue: overdue_compute,
  });

  _mustache_path = GGRC.mustache_path + "/cycle_task_group_objects";
  can.Model.Cacheable("CMS.Models.CycleTaskGroupObject", {
    root_object: "cycle_task_group_object",
    root_collection: "cycle_task_group_objects",
    category: "workflow",
    findAll: "GET /api/cycle_task_group_objects",
    findOne: "GET /api/cycle_task_group_objects/{id}",
    create: "POST /api/cycle_task_group_objects",
    update: "PUT /api/cycle_task_group_objects/{id}",
    destroy: "DELETE /api/cycle_task_group_objects/{id}",

    attributes: {
      cycle_task_group: "CMS.Models.CycleTaskGroup.stub",
      task_group_object: "CMS.Models.TaskGroupObject.stub",
      cycle_task_group_object_tasks:
        "CMS.Models.CycleTaskGroupObjectTask.stubs",
      modified_by: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub"
    },

    tree_view_options: {
      show_view: _mustache_path + "/tree.mustache",
      //footer_view: _mustache_path + "/tree_footer.mustache",
      draw_children: true,
      child_options: [
        {
          model: "CycleTaskGroupObjectTask",
          mapping: "cycle_task_group_object_tasks",
          allow_creating: false
        }
      ]
    },

    init: function() {
      var that = this;
      this._super.apply(this, arguments);
      this.bind("updated", function(ev, instance) {
        if (instance instanceof that) {
          if (instance.cycle_task_group.reify().selfLink) {
            instance.cycle_task_group.reify().refresh();
          }
        }
      });
    }
  }, {
    overdue: overdue_compute
  });

  _mustache_path = GGRC.mustache_path + "/cycle_task_group_object_tasks";
  can.Model.Cacheable("CMS.Models.CycleTaskGroupObjectTask", {
    root_object: "cycle_task_group_object_task",
    root_collection: "cycle_task_group_object_tasks",
    category: "workflow",
    findAll: "GET /api/cycle_task_group_object_tasks",
    findOne: "GET /api/cycle_task_group_object_tasks/{id}",
    create: "POST /api/cycle_task_group_object_tasks",
    update: "PUT /api/cycle_task_group_object_tasks/{id}",
    destroy: "DELETE /api/cycle_task_group_object_tasks/{id}",

    attributes: {
      cycle_task_group_object: "CMS.Models.CycleTaskGroupObject.stub",
      task_group_task: "CMS.Models.TaskGroupTask.stub",
      cycle_task_entries: "CMS.Models.CycleTaskEntry.stubs",
      modified_by: "CMS.Models.Person.stub",
      contact: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub"
    },

    tree_view_options: {
      sort_property: 'sort_index',
      show_view: _mustache_path + "/tree.mustache",
      draw_children: true,
      child_options: [
        {
          model: "CycleTaskEntry",
          mapping: "cycle_task_entries",
          allow_creating: true
        }
      ]
    },

    init: function() {
      var that = this;
      this._super.apply(this, arguments);
      this.bind("updated", function(ev, instance) {
        if (instance instanceof that) {
          if (instance.cycle_task_group_object.reify().selfLink) {
            instance.cycle_task_group_object.reify().refresh();
          }
        }
      });
    }
  }, {
    overdue: overdue_compute,
  });

})(window.can);
<commit_msg>Refreshing cycle objects<commit_after>/*!
    Copyright (C) 2013 Google Inc., authors, and contributors <see AUTHORS file>
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
    Created By: dan@reciprocitylabs.com
    Maintained By: dan@reciprocitylabs.com
*/

(function(can) {

  var _mustache_path,
      overdue_compute,
      refresh_attr,
      refresh_attr_wrap;

  overdue_compute = can.compute(function(val) {
    if (this.attr("status") === "Verified") {
      return "";
    }
    var date = moment(this.attr("end_date"));
    if(date && date.isBefore(new Date())){
      return "overdue";
    }
    return "";
  });

  refresh_attr = function(instance, attr){
    if (instance.attr(attr).reify().selfLink) {
      instance.attr(attr).reify().refresh();
    }
  };

  refresh_attr_wrap = function(attr){
    return function(ev, instance) {
      if (instance instanceof this) {
        refresh_attr(instance, attr);
      }
    };
  };

  _mustache_path = GGRC.mustache_path + "/cycles";
  can.Model.Cacheable("CMS.Models.Cycle", {
    root_object: "cycle",
    root_collection: "cycles",
    category: "workflow",
    findAll: "GET /api/cycles",
    findOne: "GET /api/cycles/{id}",
    create: "POST /api/cycles",
    update: "PUT /api/cycles/{id}",
    destroy: "DELETE /api/cycles/{id}",

    attributes: {
      workflow: "CMS.Models.Workflow.stub",
      cycle_task_groups: "CMS.Models.CycleTaskGroup.stubs",
      modified_by: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub"
    },

    tree_view_options: {
      show_view: _mustache_path + "/tree.mustache",
      //footer_view: _mustache_path + "/tree_footer.mustache",
      draw_children: true,
      child_options: [
        {
          model: "CycleTaskGroup",
          mapping: "cycle_task_groups",
          allow_creating: false
        }
      ]
    },
    init: function(){
      var that = this;
      this._super.apply(this, arguments);
      this.bind("created", refresh_attr_wrap('workflow').bind(this));
    }
  }, {});

  _mustache_path = GGRC.mustache_path + "/cycle_task_entries";
  can.Model.Cacheable("CMS.Models.CycleTaskEntry", {
    root_object: "cycle_task_entry",
    root_collection: "cycle_task_entries",
    category: "workflow",
    findAll: "GET /api/cycle_task_entries",
    findOne: "GET /api/cycle_task_entries/{id}",
    create: "POST /api/cycle_task_entries",
    update: "PUT /api/cycle_task_entries/{id}",
    destroy: "DELETE /api/cycle_task_entries/{id}",

    attributes: {
      cycle_task_group_object_task: "CMS.Models.CycleTaskGroupObjectTask.stub",
      modified_by: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub",
      documents : "CMS.Models.Document.stubs",
    },

    tree_view_options: {
      show_view: _mustache_path + "/tree.mustache",
      footer_view: _mustache_path + "/tree_footer.mustache",
      child_options: [{
        //0: Documents
        model: "Document",
        mapping: "documents",
        show_view: _mustache_path + "/documents.mustache",
        footer_view: _mustache_path + "/documents_footer.mustache"
      }],
    },
    init: function(){
      this._super.apply(this, arguments);
      this.bind("created",
        refresh_attr_wrap("cycle_task_group_object_task").bind(this));
    }
  }, {});

  _mustache_path = GGRC.mustache_path + "/cycle_task_groups";
  can.Model.Cacheable("CMS.Models.CycleTaskGroup", {
    root_object: "cycle_task_group",
    root_collection: "cycle_task_groups",
    category: "workflow",
    findAll: "GET /api/cycle_task_groups",
    findOne: "GET /api/cycle_task_groups/{id}",
    create: "POST /api/cycle_task_groups",
    update: "PUT /api/cycle_task_groups/{id}",
    destroy: "DELETE /api/cycle_task_groups/{id}",

    attributes: {
      cycle: "CMS.Models.Cycle.stub",
      task_group: "CMS.Models.TaskGroup.stub",
      cycle_task_group_objects: "CMS.Models.CycleTaskGroupObject.stubs",
      modified_by: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub"
    },

    tree_view_options: {
      show_view: _mustache_path + "/tree.mustache",
      //footer_view: _mustache_path + "/tree_footer.mustache",
      draw_children: true,
      child_options: [
        {
          model: "CycleTaskGroupObject",
          mapping: "cycle_task_group_objects",
          allow_creating: false
        }
      ]
    }
  }, {
    overdue: overdue_compute,
  });

  _mustache_path = GGRC.mustache_path + "/cycle_task_group_objects";
  can.Model.Cacheable("CMS.Models.CycleTaskGroupObject", {
    root_object: "cycle_task_group_object",
    root_collection: "cycle_task_group_objects",
    category: "workflow",
    findAll: "GET /api/cycle_task_group_objects",
    findOne: "GET /api/cycle_task_group_objects/{id}",
    create: "POST /api/cycle_task_group_objects",
    update: "PUT /api/cycle_task_group_objects/{id}",
    destroy: "DELETE /api/cycle_task_group_objects/{id}",

    attributes: {
      cycle_task_group: "CMS.Models.CycleTaskGroup.stub",
      task_group_object: "CMS.Models.TaskGroupObject.stub",
      cycle_task_group_object_tasks:
        "CMS.Models.CycleTaskGroupObjectTask.stubs",
      modified_by: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub"
    },

    tree_view_options: {
      show_view: _mustache_path + "/tree.mustache",
      //footer_view: _mustache_path + "/tree_footer.mustache",
      draw_children: true,
      child_options: [
        {
          model: "CycleTaskGroupObjectTask",
          mapping: "cycle_task_group_object_tasks",
          allow_creating: false
        }
      ]
    },

    init: function() {
      this._super.apply(this, arguments);
      this.bind("updated", refresh_attr_wrap("cycle_task_group").bind(this));
    }
  }, {
    overdue: overdue_compute
  });

  _mustache_path = GGRC.mustache_path + "/cycle_task_group_object_tasks";
  can.Model.Cacheable("CMS.Models.CycleTaskGroupObjectTask", {
    root_object: "cycle_task_group_object_task",
    root_collection: "cycle_task_group_object_tasks",
    category: "workflow",
    findAll: "GET /api/cycle_task_group_object_tasks",
    findOne: "GET /api/cycle_task_group_object_tasks/{id}",
    create: "POST /api/cycle_task_group_object_tasks",
    update: "PUT /api/cycle_task_group_object_tasks/{id}",
    destroy: "DELETE /api/cycle_task_group_object_tasks/{id}",

    attributes: {
      cycle_task_group_object: "CMS.Models.CycleTaskGroupObject.stub",
      task_group_task: "CMS.Models.TaskGroupTask.stub",
      cycle_task_entries: "CMS.Models.CycleTaskEntry.stubs",
      modified_by: "CMS.Models.Person.stub",
      contact: "CMS.Models.Person.stub",
      context: "CMS.Models.Context.stub"
    },

    tree_view_options: {
      sort_property: 'sort_index',
      show_view: _mustache_path + "/tree.mustache",
      draw_children: true,
      child_options: [
        {
          model: "CycleTaskEntry",
          mapping: "cycle_task_entries",
          allow_creating: true
        }
      ]
    },

    init: function() {
      var that = this;
      this._super.apply(this, arguments);

      this.bind("updated", function(ev, instance) {
        if (instance instanceof that) {
          var object = instance.cycle_task_group_object.reify();
          if (object.selfLink) {
            object.refresh();
            refresh_attr(object, "cycle_task_group");
          }
        }
      });
    }
  }, {
    overdue: overdue_compute,
  });

})(window.can);
<|endoftext|>


<commit_before>const q = require('q')
const EventEmitter = require('events').EventEmitter
const { MongoClient, ObjectId } = require('mongodb')
const Redis = require('redis')
const fs = require('fs')

module.exports = function (config) {
  Object.assign(exports, config.common.storage)
  return function storageConnect () {
    if (exports._connected) {
      return q.when()
    }

    let uri = `mongodb://${config.mongo.host}:${config.mongo.port}/${config.mongo.database}`
    delete config.mongo.host
    delete config.mongo.port
    delete config.mongo.database

    let redis = Redis.createClient(config.redis)
    let pub = Redis.createClient(config.redis)
    let sub = Redis.createClient(config.redis)

    let mongo = q.ninvoke(MongoClient, 'connect', uri, Object.assign({ promiseLibrary: Promise }, config.mongo))
      .then(db => {
        function wrapCollection (collection, cname) {
          let wrap = {}
          function keyToId (obj) {
            let idRegex = /^[a-f0-9]{24}$/
            if (obj instanceof Array) return obj.map(keyToId)
            if (obj._id && obj._id.$in) {
              return Object.assign({}, obj, {
                _id: {
                  $in: obj._id.$in.map(i => {
                    if (typeof i === 'string' && i.match(idRegex)) {
                      i = new ObjectId(i)
                    }
                    return i
                  })
                }
              })
            }
            if (typeof obj._id === 'string' && obj._id.match(idRegex)) {
              return Object.assign({}, obj, { _id: new ObjectId(obj._id) })
            }
            return obj
          }
          function idToKey (obj) {
            if (obj instanceof Array) return obj.map(idToKey)
            if (obj && obj._id) {
              obj._id = obj._id.toString()
            }
            return obj
          }
          ;['find', 'findOne', 'findEx', 'by', 'count', 'ensureIndex', 'remove', 'insert', 'update'].forEach(method => {
            wrap[method] = (...a) => {
              try {
                let orig = a[0]
                if (typeof a[0] === 'object') {
                  a[0] = keyToId(a[0])
                }
                if (method === 'update') {
                  a[2] = a[2] || {}
                  if (a[2].multi !== false) a[2].multi = true
                }
                let ex = method === 'findEx'
                if (ex) method = 'find'
                let chain = collection[method](...a)
                if (method === 'insert') {
                  chain = chain.then((n) => Object.assign(orig, n))
                }
                if (method === 'update') {
                  chain = chain.then((n) => Object.assign(n, { modified: n.result.nModified }))
                }
                if (ex) {
                  let opts = a[1]
                  if (opts.sort) {
                    chain = chain.sort(opts.sort)
                  }
                  if (opts.offset) {
                    chain = chain.offset(opts.offset)
                  }
                  if (opts.limit) {
                    chain = chain.limit(opts.limit)
                  }
                }
                if (method === 'find') {
                  chain = q.ninvoke(chain, 'toArray')
                }
                return chain.then(idToKey)
                  .catch(e => {
                    console.error('DBERR', e, ex)
                    console.log('DBERR', e.stack)
                  })
              } catch (e) {
                console.error('DBERR', e)
                console.log('DBERR', e.stack)
                return Promise.reject(e)
              }
            }
          })

          wrap.drop = (...a) => {
            return q.ninvoke(collection, 'drop', ...a).catch(e => q.resolve())
          }
          wrap.clear = wrap.drop
          wrap.removeWhere = wrap.remove
          wrap.by = (_id) => wrap.find({ _id })
          wrap.bulk = function (bulk, cb) {
            let batch = collection.initializeUnorderedBulkOp()
            try {
              bulk.forEach(i => {
                if (i.op === 'insert') {
                  return batch.insert(i.data)
                }
                let q = { _id: (i.id && i.id.length === 24) ? new ObjectId(i.id + '') : i.id }
                if (i.op === 'update') {
                  return batch.find(q).update({ $set: i.$set })
                }
                if (i.op === 'remove') {
                  return batch.find(q).remove()
                }
                if (i.op === 'inc') {
                  return batch.find(q).update({$inc: { [i.key]: i.amount }})
                }
                console.error('UNKNOWN BULK!', i)
              })
              return q.ninvoke(batch, 'execute')
            } catch (e) {
              if (cb) cb(e.message)
              console.error(e)
              return q.reject(e.message)
            }
          }
          return wrap
        }
        config.common.dbCollections.forEach(i => {
          let collection = db.collection(i)
          let indexes = config.common.dbIndexes[i]
          if (indexes) {
            for (let k in indexes) {
              collection.ensureIndex({ [k]: indexes[k] })
            }
          }
          exports.db[i] = wrapCollection(collection, i)
        })
      })

    Object.assign(exports.pubsub, {
      ee: new EventEmitter(),
      subscribed: {},
      publish (channel, data) {
        pub.publish(channel, data)
        return q.when()
      },
      subscribe (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.on(channel, cb)
        return q.when()
      },
      once (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.once(channel, cb)
        return q.when()
      }
    })
    sub.on('message', (channel, message) => {
      exports.pubsub.ee.emit(channel, message)
    })
    sub.on('pmessage', (pattern, channel, message) => {
      exports.pubsub.ee.emit(channel, message)
      exports.pubsub.ee.emit(pattern, channel, message)
    })

    Object.assign(exports.env, {
      get: q.nbind(redis.get, redis),
      mget: q.nbind(redis.mget, redis),
      set: q.nbind(redis.set, redis),
      setex: q.nbind(redis.setex, redis),
      expire: q.nbind(redis.expire, redis),
      ttl: q.nbind(redis.ttl, redis),
      del: q.nbind(redis.del, redis),
      hmget: q.nbind(redis.hmget, redis),
      hmset: q.nbind(redis.hmset, redis),
      hget: q.nbind(redis.hget, redis),
      hset: q.nbind(redis.hset, redis),
      hgetall: q.nbind(redis.hgetall, redis),
      incr: q.nbind(redis.incr, redis),
      flushall: q.nbind(redis.flushall, redis)
    })

    exports._connected = true
    exports.resetAllData = () => q.when() // Temp dummy

    Object.assign(exports.queue, require('./queue'))
    exports.queue.wrap(redis, exports.pubsub)

    let oget = exports.env.get
    exports.env.get = function (...a) {
      return oget(...a).catch(() => exports.env.hgetall(...a))
    }

    exports.resetAllData = () => {
      return exports.importDB(`${__dirname}/../../db.original.json`)
    }

    return mongo
  }
}

exports.importDB = function importDB (path = './db.json') {
  let { db, env } = exports
  console.log('Importing DB')
  try {
    let olddb = JSON.parse(fs.readFileSync(path).toString())
    let ps = olddb.collections.map(oldcol => {
      let name = oldcol.name
      console.log('Collection', name)
      if (name === 'env') {
        return env.flushall().then(() => {
          let p = oldcol.data.map(row => {
            let ps = []
            for (let k in row.data) {
              let v = row.data[k]
              ps.push(env.set(k, typeof v === 'object' ? JSON.stringify(v) : v))
            }
            return Promise.all(ps)
          })
          return Promise.all(p)
        })
      } else {
        return db[name].drop().then(() => Promise.all(oldcol.data.map(row => {
          delete row.meta
          delete row.$loki
          return db[name].insert(row)
        })))
      }
    })
    ps.push(db.users.update({ _id: '2' }, { _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }, { upsert: true }))
    ps.push(db.users.update({ _id: '3' }, { _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }, { upsert: true }))
    return Promise.all(ps)
      .then(() => console.log('Import complete. Restart the server for best results.'))
      .catch(e => importFail(e))
  } catch (e) {
    return importFail(e)
  }
}

function importFail (e) {
  let { db, env } = exports
  let ps = []
  ps.push(db.users.insert({ _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(db.users.insert({ _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(env.set('gameTime', 1))
  return Promise.resolve()
    .then(() => console.log('An error occured importing existing db, initializing blank server'))
    .then(() => console.error(e))
    .then(() => Promise.all(ps))
    .then(() => console.log('Server initialzed. Remember to generate rooms.'))
    .catch(err => console.error(err))
}
<commit_msg>Fixed missing resetAllData()<commit_after>const q = require('q')
const EventEmitter = require('events').EventEmitter
const { MongoClient, ObjectId } = require('mongodb')
const Redis = require('redis')
const fs = require('fs')

module.exports = function (config) {
  Object.assign(exports, config.common.storage)
  return function storageConnect () {
    if (exports._connected) {
      return q.when()
    }

    let uri = `mongodb://${config.mongo.host}:${config.mongo.port}/${config.mongo.database}`
    delete config.mongo.host
    delete config.mongo.port
    delete config.mongo.database

    let redis = Redis.createClient(config.redis)
    let pub = Redis.createClient(config.redis)
    let sub = Redis.createClient(config.redis)

    let mongo = q.ninvoke(MongoClient, 'connect', uri, Object.assign({ promiseLibrary: Promise }, config.mongo))
      .then(db => {
        function wrapCollection (collection, cname) {
          let wrap = {}
          function keyToId (obj) {
            let idRegex = /^[a-f0-9]{24}$/
            if (obj instanceof Array) return obj.map(keyToId)
            if (obj._id && obj._id.$in) {
              return Object.assign({}, obj, {
                _id: {
                  $in: obj._id.$in.map(i => {
                    if (typeof i === 'string' && i.match(idRegex)) {
                      i = new ObjectId(i)
                    }
                    return i
                  })
                }
              })
            }
            if (typeof obj._id === 'string' && obj._id.match(idRegex)) {
              return Object.assign({}, obj, { _id: new ObjectId(obj._id) })
            }
            return obj
          }
          function idToKey (obj) {
            if (obj instanceof Array) return obj.map(idToKey)
            if (obj && obj._id) {
              obj._id = obj._id.toString()
            }
            return obj
          }
          ;['find', 'findOne', 'findEx', 'by', 'count', 'ensureIndex', 'remove', 'insert', 'update'].forEach(method => {
            wrap[method] = (...a) => {
              try {
                let orig = a[0]
                if (typeof a[0] === 'object') {
                  a[0] = keyToId(a[0])
                }
                if (method === 'update') {
                  a[2] = a[2] || {}
                  if (a[2].multi !== false) a[2].multi = true
                }
                let ex = method === 'findEx'
                if (ex) method = 'find'
                let chain = collection[method](...a)
                if (method === 'insert') {
                  chain = chain.then((n) => Object.assign(orig, n))
                }
                if (method === 'update') {
                  chain = chain.then((n) => Object.assign(n, { modified: n.result.nModified }))
                }
                if (ex) {
                  let opts = a[1]
                  if (opts.sort) {
                    chain = chain.sort(opts.sort)
                  }
                  if (opts.offset) {
                    chain = chain.offset(opts.offset)
                  }
                  if (opts.limit) {
                    chain = chain.limit(opts.limit)
                  }
                }
                if (method === 'find') {
                  chain = q.ninvoke(chain, 'toArray')
                }
                return chain.then(idToKey)
                  .catch(e => {
                    console.error('DBERR', e, ex)
                    console.log('DBERR', e.stack)
                  })
              } catch (e) {
                console.error('DBERR', e)
                console.log('DBERR', e.stack)
                return Promise.reject(e)
              }
            }
          })

          wrap.drop = (...a) => {
            return q.ninvoke(collection, 'drop', ...a).catch(e => q.resolve())
          }
          wrap.clear = wrap.drop
          wrap.removeWhere = wrap.remove
          wrap.by = (_id) => wrap.find({ _id })
          wrap.bulk = function (bulk, cb) {
            let batch = collection.initializeUnorderedBulkOp()
            try {
              bulk.forEach(i => {
                if (i.op === 'insert') {
                  return batch.insert(i.data)
                }
                let q = { _id: (i.id && i.id.length === 24) ? new ObjectId(i.id + '') : i.id }
                if (i.op === 'update') {
                  return batch.find(q).update({ $set: i.$set })
                }
                if (i.op === 'remove') {
                  return batch.find(q).remove()
                }
                if (i.op === 'inc') {
                  return batch.find(q).update({$inc: { [i.key]: i.amount }})
                }
                console.error('UNKNOWN BULK!', i)
              })
              return q.ninvoke(batch, 'execute')
            } catch (e) {
              if (cb) cb(e.message)
              console.error(e)
              return q.reject(e.message)
            }
          }
          return wrap
        }
        config.common.dbCollections.forEach(i => {
          let collection = db.collection(i)
          let indexes = config.common.dbIndexes[i]
          if (indexes) {
            for (let k in indexes) {
              collection.ensureIndex({ [k]: indexes[k] })
            }
          }
          exports.db[i] = wrapCollection(collection, i)
        })
      })

    Object.assign(exports.pubsub, {
      ee: new EventEmitter(),
      subscribed: {},
      publish (channel, data) {
        pub.publish(channel, data)
        return q.when()
      },
      subscribe (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.on(channel, cb)
        return q.when()
      },
      once (channel, cb) {
        if (!this.subscribed[channel]) {
          if (channel.match(/[?*]/)) { sub.psubscribe(channel) } else { sub.subscribe(channel) }
          this.subscribed[channel] = true
        }
        this.ee.once(channel, cb)
        return q.when()
      }
    })
    sub.on('message', (channel, message) => {
      exports.pubsub.ee.emit(channel, message)
    })
    sub.on('pmessage', (pattern, channel, message) => {
      exports.pubsub.ee.emit(channel, message)
      exports.pubsub.ee.emit(pattern, channel, message)
    })

    Object.assign(exports.env, {
      get: q.nbind(redis.get, redis),
      mget: q.nbind(redis.mget, redis),
      set: q.nbind(redis.set, redis),
      setex: q.nbind(redis.setex, redis),
      expire: q.nbind(redis.expire, redis),
      ttl: q.nbind(redis.ttl, redis),
      del: q.nbind(redis.del, redis),
      hmget: q.nbind(redis.hmget, redis),
      hmset: q.nbind(redis.hmset, redis),
      hget: q.nbind(redis.hget, redis),
      hset: q.nbind(redis.hset, redis),
      hgetall: q.nbind(redis.hgetall, redis),
      incr: q.nbind(redis.incr, redis),
      flushall: q.nbind(redis.flushall, redis)
    })

    exports._connected = true
    exports.resetAllData = () => q.when() // Temp dummy

    Object.assign(exports.queue, require('./queue'))
    exports.queue.wrap(redis, exports.pubsub)

    let oget = exports.env.get
    exports.env.get = function (...a) {
      return oget(...a).catch(() => exports.env.hgetall(...a))
    }

    exports.resetAllData = () => {
      return exports.importDB(`${__dirname}/../../db.original.json`)
    }
    Object.assign(config.common.storage, exports)
    return mongo
  }
}

exports.importDB = function importDB (path = './db.json') {
  let { db, env } = exports
  console.log('Importing DB')
  try {
    let olddb = JSON.parse(fs.readFileSync(path).toString())
    let ps = olddb.collections.map(oldcol => {
      let name = oldcol.name
      console.log('Collection', name)
      if (name === 'env') {
        return env.flushall().then(() => {
          let p = oldcol.data.map(row => {
            let ps = []
            for (let k in row.data) {
              let v = row.data[k]
              ps.push(env.set(k, typeof v === 'object' ? JSON.stringify(v) : v))
            }
            return Promise.all(ps)
          })
          return Promise.all(p)
        })
      } else {
        return db[name].drop().then(() => Promise.all(oldcol.data.map(row => {
          delete row.meta
          delete row.$loki
          return db[name].insert(row)
        })))
      }
    })
    ps.push(db.users.update({ _id: '2' }, { $set: { _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    ps.push(db.users.update({ _id: '3' }, { $set: { _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 } }, { upsert: true }))
    return Promise.all(ps)
      .then(() => console.log('Import complete. Restart the server for best results.'))
      .catch(e => importFail(e))
  } catch (e) {
    return importFail(e)
  }
}

function importFail (e) {
  let { db, env } = exports
  let ps = []
  ps.push(db.users.insert({ _id: '2', username: 'Invader', usernameLower: 'invader', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(db.users.insert({ _id: '3', username: 'Source Keeper', usernameLower: 'source keeper', cpu: 100, cpuAvailable: 10000, gcl: 13966610.2, active: 0 }))
  ps.push(env.set('gameTime', 1))
  return Promise.resolve()
    .then(() => console.log('An error occured importing existing db, initializing blank server'))
    .then(() => console.error(e))
    .then(() => Promise.all(ps))
    .then(() => console.log('Server initialzed. Remember to generate rooms.'))
    .catch(err => console.error(err))
}
<|endoftext|>


<commit_before>import { Vector3 } from './Vector3';

/**
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author bhouston / http://clara.io
 * @author tschw
 */

function Matrix3() {

	this.elements = [

		1, 0, 0,
		0, 1, 0,
		0, 0, 1

	];

	if ( arguments.length > 0 ) {

		console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );

	}

}

Object.assign( Matrix3.prototype, {

	isMatrix3: true,

	set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {

		var te = this.elements;

		te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
		te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
		te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;

		return this;

	},

	identity: function () {

		this.set(

			1, 0, 0,
			0, 1, 0,
			0, 0, 1

		);

		return this;

	},

	clone: function () {

		return new this.constructor().fromArray( this.elements );

	},

	copy: function ( m ) {

		var te = this.elements;
		var me = m.elements;

		te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
		te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
		te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];

		return this;

	},

	setFromMatrix4: function ( m ) {

		var me = m.elements;

		this.set(

			me[ 0 ], me[ 4 ], me[  8 ],
			me[ 1 ], me[ 5 ], me[  9 ],
			me[ 2 ], me[ 6 ], me[ 10 ]

		);

		return this;

	},

	applyToBufferAttribute: function () {

		var v1 = new Vector3();

		return function applyToBufferAttribute( attribute ) {

			for ( var i = 0, l = attribute.count; i < l; i ++ ) {

				v1.x = attribute.getX( i );
				v1.y = attribute.getY( i );
				v1.z = attribute.getZ( i );

				v1.applyMatrix3( this );

				attribute.setXYZ( i, v1.x, v1.y, v1.z );

			}

			return attribute;

		};

	}(),

	multiply: function ( m ) {

		return this.multiplyMatrices( this, m );

	},

	premultiply: function ( m ) {

		return this.multiplyMatrices( m, this );

	},

	multiplyMatrices: function ( a, b ) {

		var ae = a.elements;
		var be = b.elements;
		var te = this.elements;

		var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
		var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
		var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];

		var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
		var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
		var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];

		te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
		te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
		te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;

		te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
		te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
		te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;

		te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
		te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
		te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;

		return this;

	},

	multiplyScalar: function ( s ) {

		var te = this.elements;

		te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
		te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
		te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;

		return this;

	},

	determinant: function () {

		var te = this.elements;

		var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
			d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
			g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];

		return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;

	},

	getInverse: function ( matrix, throwOnDegenerate ) {

		if ( matrix && matrix.isMatrix4 ) {

			console.error( "THREE.Matrix3: .getInverse no longer takes a Matrix4 argument." );

		}

		var me = matrix.elements,
			te = this.elements,

			n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
			n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
			n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],

			t11 = n33 * n22 - n32 * n23,
			t12 = n32 * n13 - n33 * n12,
			t13 = n23 * n12 - n22 * n13,

			det = n11 * t11 + n21 * t12 + n31 * t13;

		if ( det === 0 ) {

			var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";

			if ( throwOnDegenerate === true ) {

				throw new Error( msg );

			} else {

				console.warn( msg );

			}

			return this.identity();

		}

		var detInv = 1 / det;

		te[ 0 ] = t11 * detInv;
		te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
		te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;

		te[ 3 ] = t12 * detInv;
		te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
		te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;

		te[ 6 ] = t13 * detInv;
		te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
		te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;

		return this;

	},

	transpose: function () {

		var tmp, m = this.elements;

		tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
		tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
		tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;

		return this;

	},

	getNormalMatrix: function ( matrix4 ) {

		return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();

	},

	transposeIntoArray: function ( r ) {

		var m = this.elements;

		r[ 0 ] = m[ 0 ];
		r[ 1 ] = m[ 3 ];
		r[ 2 ] = m[ 6 ];
		r[ 3 ] = m[ 1 ];
		r[ 4 ] = m[ 4 ];
		r[ 5 ] = m[ 7 ];
		r[ 6 ] = m[ 2 ];
		r[ 7 ] = m[ 5 ];
		r[ 8 ] = m[ 8 ];

		return this;

	},

	equals: function ( matrix ) {

		var te = this.elements;
		var me = matrix.elements;

		for ( var i = 0; i < 9; i ++ ) {

			if ( te[ i ] !== me[ i ] ) return false;

		}

		return true;

	},

	fromArray: function ( array, offset ) {

		if ( offset === undefined ) offset = 0;

		for ( var i = 0; i < 9; i ++ ) {

			this.elements[ i ] = array[ i + offset ];

		}

		return this;

	},

	toArray: function ( array, offset ) {

		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;

		var te = this.elements;

		array[ offset ] = te[ 0 ];
		array[ offset + 1 ] = te[ 1 ];
		array[ offset + 2 ] = te[ 2 ];

		array[ offset + 3 ] = te[ 3 ];
		array[ offset + 4 ] = te[ 4 ];
		array[ offset + 5 ] = te[ 5 ];

		array[ offset + 6 ] = te[ 6 ];
		array[ offset + 7 ] = te[ 7 ];
		array[ offset + 8 ] = te[ 8 ];

		return array;

	}

} );

export { Matrix3 };
<commit_msg>add ()  to error message<commit_after>import { Vector3 } from './Vector3';

/**
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author bhouston / http://clara.io
 * @author tschw
 */

function Matrix3() {

	this.elements = [

		1, 0, 0,
		0, 1, 0,
		0, 0, 1

	];

	if ( arguments.length > 0 ) {

		console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );

	}

}

Object.assign( Matrix3.prototype, {

	isMatrix3: true,

	set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {

		var te = this.elements;

		te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
		te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
		te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;

		return this;

	},

	identity: function () {

		this.set(

			1, 0, 0,
			0, 1, 0,
			0, 0, 1

		);

		return this;

	},

	clone: function () {

		return new this.constructor().fromArray( this.elements );

	},

	copy: function ( m ) {

		var te = this.elements;
		var me = m.elements;

		te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
		te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
		te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];

		return this;

	},

	setFromMatrix4: function ( m ) {

		var me = m.elements;

		this.set(

			me[ 0 ], me[ 4 ], me[  8 ],
			me[ 1 ], me[ 5 ], me[  9 ],
			me[ 2 ], me[ 6 ], me[ 10 ]

		);

		return this;

	},

	applyToBufferAttribute: function () {

		var v1 = new Vector3();

		return function applyToBufferAttribute( attribute ) {

			for ( var i = 0, l = attribute.count; i < l; i ++ ) {

				v1.x = attribute.getX( i );
				v1.y = attribute.getY( i );
				v1.z = attribute.getZ( i );

				v1.applyMatrix3( this );

				attribute.setXYZ( i, v1.x, v1.y, v1.z );

			}

			return attribute;

		};

	}(),

	multiply: function ( m ) {

		return this.multiplyMatrices( this, m );

	},

	premultiply: function ( m ) {

		return this.multiplyMatrices( m, this );

	},

	multiplyMatrices: function ( a, b ) {

		var ae = a.elements;
		var be = b.elements;
		var te = this.elements;

		var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
		var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
		var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];

		var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
		var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
		var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];

		te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
		te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
		te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;

		te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
		te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
		te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;

		te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
		te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
		te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;

		return this;

	},

	multiplyScalar: function ( s ) {

		var te = this.elements;

		te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
		te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
		te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;

		return this;

	},

	determinant: function () {

		var te = this.elements;

		var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
			d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
			g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];

		return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;

	},

	getInverse: function ( matrix, throwOnDegenerate ) {

		if ( matrix && matrix.isMatrix4 ) {

			console.error( "THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument." );

		}

		var me = matrix.elements,
			te = this.elements,

			n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
			n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
			n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],

			t11 = n33 * n22 - n32 * n23,
			t12 = n32 * n13 - n33 * n12,
			t13 = n23 * n12 - n22 * n13,

			det = n11 * t11 + n21 * t12 + n31 * t13;

		if ( det === 0 ) {

			var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";

			if ( throwOnDegenerate === true ) {

				throw new Error( msg );

			} else {

				console.warn( msg );

			}

			return this.identity();

		}

		var detInv = 1 / det;

		te[ 0 ] = t11 * detInv;
		te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
		te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;

		te[ 3 ] = t12 * detInv;
		te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
		te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;

		te[ 6 ] = t13 * detInv;
		te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
		te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;

		return this;

	},

	transpose: function () {

		var tmp, m = this.elements;

		tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
		tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
		tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;

		return this;

	},

	getNormalMatrix: function ( matrix4 ) {

		return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();

	},

	transposeIntoArray: function ( r ) {

		var m = this.elements;

		r[ 0 ] = m[ 0 ];
		r[ 1 ] = m[ 3 ];
		r[ 2 ] = m[ 6 ];
		r[ 3 ] = m[ 1 ];
		r[ 4 ] = m[ 4 ];
		r[ 5 ] = m[ 7 ];
		r[ 6 ] = m[ 2 ];
		r[ 7 ] = m[ 5 ];
		r[ 8 ] = m[ 8 ];

		return this;

	},

	equals: function ( matrix ) {

		var te = this.elements;
		var me = matrix.elements;

		for ( var i = 0; i < 9; i ++ ) {

			if ( te[ i ] !== me[ i ] ) return false;

		}

		return true;

	},

	fromArray: function ( array, offset ) {

		if ( offset === undefined ) offset = 0;

		for ( var i = 0; i < 9; i ++ ) {

			this.elements[ i ] = array[ i + offset ];

		}

		return this;

	},

	toArray: function ( array, offset ) {

		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;

		var te = this.elements;

		array[ offset ] = te[ 0 ];
		array[ offset + 1 ] = te[ 1 ];
		array[ offset + 2 ] = te[ 2 ];

		array[ offset + 3 ] = te[ 3 ];
		array[ offset + 4 ] = te[ 4 ];
		array[ offset + 5 ] = te[ 5 ];

		array[ offset + 6 ] = te[ 6 ];
		array[ offset + 7 ] = te[ 7 ];
		array[ offset + 8 ] = te[ 8 ];

		return array;

	}

} );

export { Matrix3 };
<|endoftext|>


<commit_before>'use babel';
import Exec from './exec';

export default class Preproc {

  constructor() {
    this.options = [];
  }

  /**
   * Define o caminho a pré-processar
   */
  setPath(path) {
    this.path = path;
  }

  /**
   * Adiciona opções
   */
  addOptions(options) {
    this.options = this.options.concat(options);
  }

  /**
   * Retorna os argumentos command-line para pré-processar
   */
  getCmdArgs() {
    return ['preproc.bat', '-dc=f:\\fontes\\'].concat(this.options).concat([this.path]);
  }

  /**
   * Executa o pré-processador
   */
  exec() {
    return new Promise((resolve) => {
       new Exec().exec(this.getCmdArgs(), (process) => {
         resolve();
       });
     });
  }

}
<commit_msg>Linter passa a considerar o WC na hora de executar o préprocessador<commit_after>'use babel';
import Exec from './exec';
import WcVersao from './wc-versao';

export default class Preproc {

  constructor() {
    this.options = [];
  }

  /**
   * Define o caminho a pré-processar
   */
  setPath(path) {
    this.path = path;
  }

  /**
   * Adiciona opções
   */
  addOptions(options) {
    this.options = this.options.concat(options);
  }

  /**
   * Retorna os argumentos command-line para pré-processar
   */
  getCmdArgs() {
    return ['preproc.bat'].concat(this.options).concat([this.path]);
  }

  /**
   * Executa o pré-processador
   */
  exec() {
    return new Promise((resolve) => {
      new WcVersao().currentWc().then((wc) => {
        new Exec().exec(this.getCmdArgs().concat(this.getWcParams(wc)), (process) => {
          resolve();
        });
      });
    });
  }

  /**
   * Retorna os parâmetros do WC
   */
  getWcParams(wc) {
    return ['-dc=f:\\fontes\\;f:\\siger\\wc\\des\\'+wc+'\\fon\\'];
  }

}
<|endoftext|>


<commit_before>#lang "js";
var fs = require("fs");
var path = require("path");
var pkg = require('../package.json');
var sweet = require("./sweet.js");
var syn = require("./syntax.js");

var argv = require("optimist")
    .usage("Usage: sjs [options] path/to/file.js")
    .alias('v', 'version')
    .describe('v', 'Output version info')
    .boolean('version')
    .alias('o', 'output')
    .describe('o', 'write out compiled files')
    .boolean('output')
    .alias('w', 'watch')
    .describe('w', 'watch a file')
    .boolean('watch')
    .alias('t', 'tokens')
    .describe('t', 'just emit the expanded tokens without parsing an AST')
    .alias('a', 'ast')
    .describe('a', 'just emit the expanded AST')
    .alias('p', 'no-parse')
    .describe('p', 'print out the expanded result but do not run through the parser (or apply hygienic renamings)')
    .boolean("no-parse")
    .alias('s', 'stdin')
    .describe('s', 'read from stdin')
    .boolean('stdin')
    .alias('c', 'sourcemap')
    .describe('c', 'generate a sourcemap')
    .boolean("sourcemap")
    .alias('n', 'num-expands')
    .describe('n', 'the maximum number of expands to perform')
    .alias('h', 'step-hygiene')
    .describe('h', 'display hygienic renames when stepping with "--num-expands"')
    .alias('r', 'readable-names')
    .describe('r', 'remove as many hygienic renames as possible (ES5 code only!)')
    .boolean('readable-names')
    .describe('format-indent', 'number of spaces for indentation')
    .alias('l', 'load-readtable')
    .describe('load-readtable', 'readtable module to install')
    .argv;

exports.run = function() {
    if (argv.version){
        return console.log("Sweet.js version: " + pkg.version);
    }
    var infile = argv._[0];
    var writeToDisk = argv.output;
    var watch = argv.watch;
    var tokens = argv.tokens;
    var ast = argv.ast;
    var sourcemap = argv.sourcemap;
    var noparse = argv['no-parse'];
    var numexpands = argv['num-expands'];
    var displayHygiene = argv['step-hygiene'];
    var readableNames = argv['readable-names'];
    var formatIndent = parseInt(argv['format-indent'], 10);
    var readtableModules = argv['load-readtable'];
    if (formatIndent !== formatIndent) {
        formatIndent = 4;
    }

    var file;
    if (infile) {
        file = fs.readFileSync(infile, "utf8");
    } else if (argv.stdin) {
        file = fs.readFileSync("/dev/stdin", "utf8");
    } else if (argv._.length === 0) {
        console.log(require("optimist").help());
        return;
    }

    var cwd = process.cwd();

    if(readtableModules) {
        readtableModules = (Array.isArray(readtableModules) ?
                            readtableModules :
                            [readtableModules]);

        readtableModules.forEach(function(mod) {
            sweet.setReadtable(mod);
        });
    }

    var options = {
        filename: infile,
        compileSuffix: ".jsc",
        ast: ast,
        sourceMap: sourcemap,
        readableNames: readableNames,
        escodegen: {
            format: {
                indent: {
                    style: Array(formatIndent + 1).join(' ')
                }
            }
        }
    };

    function doCompile() {
        var result = sweet.compile(file, options);
        result.forEach(function(res) {
            var outfile = res.path + options.compileSuffix;
            var mapfile = res.path + ".map";
            console.log("compiling: " + outfile);
            if (sourcemap) {
                fs.writeFileSync(outfile, res.code + "\n//# sourceMappingURL=" + mapfile, "utf8");
                fs.writeFileSync(mapfile, res.sourceMap, "utf8");
            } else {
                fs.writeFileSync(outfile, res.code, "utf8");
            }
        });
    }

    if (watch && writeToDisk) {
        fs.watch(infile, function(){
            file = fs.readFileSync(infile, "utf8");
            try {
                doCompile();
            } catch (e) {
                console.log(e);
            }
        });
    } else if (writeToDisk) {
        doCompile();
    } else if (tokens) {
        console.log(sweet.expand(file, modules, { maxExpands: numexpands }));
    } else if (ast) {
        console.log(JSON.stringify(sweet.compile(file, options), null, formatIndent));
    } else if (noparse) {
        var expanded = sweet.expand(file, modules, { maxExpands: numexpands });
        var unparsedString = syn.prettyPrint(expanded, displayHygiene);
        console.log(unparsedString);
    } else {
        options.maxExpands = numexpands;
        var result = sweet.compile(file, options);
        result.forEach(function(res) {
            console.log("file: " + res.path);
            console.log(res.code + "\n");
        });
    }
};
<commit_msg>-o now allows you to compile to a directory<commit_after>#lang "js";
var fs = require("fs");
var path = require("path");
var pkg = require('../package.json');
var sweet = require("./sweet.js");
var syn = require("./syntax.js");

var argv = require("optimist")
    .usage("Usage: sjs [options] path/to/file.js")
    .alias('v', 'version')
    .describe('v', 'Output version info')
    .boolean('version')
    .alias('o', 'output')
    .describe('o', 'write out compiled files')
    .alias('w', 'watch')
    .describe('w', 'watch a file')
    .boolean('watch')
    .alias('t', 'tokens')
    .describe('t', 'just emit the expanded tokens without parsing an AST')
    .alias('a', 'ast')
    .describe('a', 'just emit the expanded AST')
    .alias('p', 'no-parse')
    .describe('p', 'print out the expanded result but do not run through the parser (or apply hygienic renamings)')
    .boolean("no-parse")
    .alias('s', 'stdin')
    .describe('s', 'read from stdin')
    .boolean('stdin')
    .alias('c', 'sourcemap')
    .describe('c', 'generate a sourcemap')
    .boolean("sourcemap")
    .alias('n', 'num-expands')
    .describe('n', 'the maximum number of expands to perform')
    .alias('h', 'step-hygiene')
    .describe('h', 'display hygienic renames when stepping with "--num-expands"')
    .alias('r', 'readable-names')
    .describe('r', 'remove as many hygienic renames as possible (ES5 code only!)')
    .boolean('readable-names')
    .describe('format-indent', 'number of spaces for indentation')
    .alias('l', 'load-readtable')
    .describe('load-readtable', 'readtable module to install')
    .argv;

exports.run = function() {
    if (argv.version){
        return console.log("Sweet.js version: " + pkg.version);
    }
    var infile = argv._[0];
    var writeToDisk = argv.output;
    var watch = argv.watch;
    var tokens = argv.tokens;
    var ast = argv.ast;
    var sourcemap = argv.sourcemap;
    var noparse = argv['no-parse'];
    var numexpands = argv['num-expands'];
    var displayHygiene = argv['step-hygiene'];
    var readableNames = argv['readable-names'];
    var formatIndent = parseInt(argv['format-indent'], 10);
    var readtableModules = argv['load-readtable'];
    if (formatIndent !== formatIndent) {
        formatIndent = 4;
    }

    var file;
    if (infile) {
        file = fs.readFileSync(infile, "utf8");
    } else if (argv.stdin) {
        file = fs.readFileSync("/dev/stdin", "utf8");
    } else if (argv._.length === 0) {
        console.log(require("optimist").help());
        return;
    }

    var cwd = process.cwd();

    if(readtableModules) {
        readtableModules = (Array.isArray(readtableModules) ?
                            readtableModules :
                            [readtableModules]);

        readtableModules.forEach(function(mod) {
            sweet.setReadtable(mod);
        });
    }

    var options = {
        filename: infile,
        compileSuffix: ".jsc",
        ast: ast,
        sourceMap: sourcemap,
        readableNames: readableNames,
        escodegen: {
            format: {
                indent: {
                    style: Array(formatIndent + 1).join(' ')
                }
            }
        }
    };

    function doCompile() {
        var result = sweet.compile(file, options);
        result.forEach(function(res) {
            var filename = path.basename(res.path);
            var dirname = path.dirname(res.path);
            var relativeDir = path.relative(dirname, writeToDisk);

            var outfile = path.resolve(dirname, relativeDir, filename + options.compileSuffix);
            var mapfile = path.resolve(dirname, relativeDir, filename + ".map");

            console.log("compiling: " + outfile);
            if (sourcemap) {
                fs.writeFileSync(outfile, res.code + "\n//# sourceMappingURL=" + mapfile, "utf8");
                fs.writeFileSync(mapfile, res.sourceMap, "utf8");
            } else {
                fs.writeFileSync(outfile, res.code, "utf8");
            }
        });
    }

    if (watch && writeToDisk) {
        fs.watch(infile, function(){
            file = fs.readFileSync(infile, "utf8");
            try {
                doCompile();
            } catch (e) {
                console.log(e);
            }
        });
    } else if (writeToDisk) {
        doCompile();
    } else if (tokens) {
        console.log(sweet.expand(file, modules, { maxExpands: numexpands }));
    } else if (ast) {
        console.log(JSON.stringify(sweet.compile(file, options), null, formatIndent));
    } else if (noparse) {
        var expanded = sweet.expand(file, modules, { maxExpands: numexpands });
        var unparsedString = syn.prettyPrint(expanded, displayHygiene);
        console.log(unparsedString);
    } else {
        options.maxExpands = numexpands;
        var result = sweet.compile(file, options);
        result.forEach(function(res) {
            console.log("file: " + res.path);
            console.log(res.code + "\n");
        });
    }
};
<|endoftext|>


<commit_before>/*
 * Copyright 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
 * Please see distribution for license.
 */
$.register_module({
    name: 'og.views.config_blocks.Scenario',
    dependencies: ['og.common.util.ui.Form'],
    obj: function () {
        var Block = og.common.util.ui.Block;
        var Scenario = function (config) {
            var block = this, id = og.common.id('scenario'), form = config.form, data = config.data,
                index = config.index, extras = {id : id},
                template = '<select class="og-scenario-select" id="'
                + index + '"><option value="">Please select...</option></select>';
            form.Block.call(block, {
                extras: extras,
                module: 'og.views.forms.view-definition-scenario_tash',
                children: [
                    new form.Block({content: template})
                ]
            });
            form.on('form:load', function () {
                og.api.rest.configs.get({type: 'ScenarioDefinition'}).pipe(function (result) {
                    $('.og-scenario-select').append('<optgroup label="Scenario Definition"></optgroup>');
                    result.data.data.map(function (datum) { // search results
                        var fields = datum.split('|');
                        $('.og-scenario-select optgroup[label="Scenario Definition"]').append(
                            $('<option></option>').val(fields[0]).html(fields[1])
                                .attr('selected', fields[0] === data)
                        );
                    });
                });
                og.api.rest.configs.get({type: 'ScenarioDslScript'}).pipe(function (result) {
                    $('.og-scenario-select').append('<optgroup label="Scenario DSL Script"></optgroup>');
                    result.data.data.map(function (datum) { // search results
                        var fields = datum.split('|');
                        $('.og-scenario-select optgroup[label="Scenario DSL Script"]').append(
                            $('<option></option>').val(fields[0]).html(fields[1])
                                .attr('selected', fields[0] === data)
                        );
                    });
                });
            });
        };
        Scenario.prototype = new Block(); // inherit Block prototype
        return Scenario;
    }
});<commit_msg>[GUI-326] ensure populating dropdown is public<commit_after>/*
 * Copyright 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
 * Please see distribution for license.
 */
$.register_module({
    name: 'og.views.config_blocks.Scenario',
    dependencies: ['og.common.util.ui.Form'],
    obj: function () {
        var Block = og.common.util.ui.Block, data, constructor = this;
        var Scenario = function (config) {
            var block = this, id = og.common.id('scenario'), form = config.form,
                index = config.index, extras = {id : id},
                template = '<select class="og-scenario-select" id="'
                + index + '"><option value="">Please select...</option></select>';
            data = config.data;
            form.Block.call(block, {
                extras: extras,
                module: 'og.views.forms.view-definition-scenario_tash',
                children: [
                    new form.Block({content: template})
                ]
            });
            form.on('form:load', function () {
                constructor.content();
            });
        };
        constructor.content = function () {
            og.api.rest.configs.get({type: 'ScenarioDefinition'}).pipe(function (result) {
                $('.og-scenario-select').append('<optgroup label="Scenario Definition"></optgroup>');
                result.data.data.map(function (datum) { // search results
                    var fields = datum.split('|');
                    $('.og-scenario-select optgroup[label="Scenario Definition"]').append(
                        $('<option></option>').val(fields[0]).html(fields[1])
                            .attr('selected', fields[0] === data)
                    );
                });
            });
            og.api.rest.configs.get({type: 'ScenarioDslScript'}).pipe(function (result) {
                $('.og-scenario-select').append('<optgroup label="Scenario DSL Script"></optgroup>');
                result.data.data.map(function (datum) { // search results
                    var fields = datum.split('|');
                    $('.og-scenario-select optgroup[label="Scenario DSL Script"]').append(
                        $('<option></option>').val(fields[0]).html(fields[1])
                            .attr('selected', fields[0] === data)
                    );
                });
            });
        };
        Scenario.prototype = new Block(); // inherit Block prototype
        return Scenario;
    }
});<|endoftext|>