<commit_before>(function ($) {
  "use strict";

  addAnswersToSessionStorage();

  $('.carousel').carousel({
    indicators: true,
    shift: 100
  });

  function addAnswersToSessionStorage(){
    var personality = [];
    var hobbies = [];

    [
      "strange",
      "happy",
      "angry",
      "fun",
      "boring",
      "kind",
      "sad"
    ].forEach(emotion => {
      var node = document.getElementById(emotion);
      addClassToNode(node, 'pop');
      addClickEventArray('personality', node, emotion, personality);
    });

    [
      "sad-emoji",
      "happy-emoji",
      "indifferent-emoji"
    ].forEach(emoji => {
      var node = document.getElementsByClassName(emoji)[0];
      addClickEventSingle('feelings', node, emoji.match(/^[a-z]+/));
    });

    [
      "name",
      "age"
    ].forEach(inputField => {
      var node = document.getElementsByClassName(inputField)[0];
      addKeyupEvent(inputField, node);
    });

    [
      "football",
      "tennis",
      "gymnastics",
      "dance",
      "drawing",
      "photography",
      "cooking",
      "gardening",
      "puzzles",
      "camping",
      "fishing",
      "walking",
      "gymnastics-mobile",
      "photography-mobile",
      "walking-mobile",
      "puzzles-mobile"
    ].forEach(hobby => {
      var node = document.getElementsByClassName(hobby)[0];
      addClassToNode(node, 'js-chosen');
      addClickEventArray('hobbies', node, hobby, hobbies);
    });

    [
      "sleep__range",
      "friends__range",
      "school__range"
    ].forEach(range => {
      if (document.getElementsByClassName(range)[0]){
        var node = document.getElementsByClassName(range)[0];
        if (range === "sleep__range") {
          addOnInputToElement( node, sleepingLion );
        } else {
          addOnInputToElement( node, emojiSprite );
        }
      }
    });

    function addKeyupEvent(key, element){
      if(!element){ return; }
      element.addEventListener("keyup", function(){
        addSingleValueToStorage(key, element.value);
      });
    }

    function addClickEventSingle(key, element, value){
      if(!element){ return; }
      element.addEventListener("click", function(){
        addSingleValueToStorage(key, value);
      });
    }

    function addClickEventArray(key, element, value, array){
      if(!element){ return; }
      element.addEventListener("click", function(){
        addValueToArray(key, value, array);
      });
    }

    function addValueToArray(key, value, array){
      array.push(value);
      addArrayToStorage(key, array);
    }

    function addSingleValueToStorage(key, value){
      sessionStorage.setItem(key, value);
    }

    // JSON.stringify() is used here as session storage only supports strings
    function addArrayToStorage(key, array){
      sessionStorage.setItem(key, JSON.stringify(array));
    }
  }

  // Adds a class to node
  function addClassToNode(node, className){
    if (!node){ return; }
    node.addEventListener("click", function(){
      node.classList.add(className);
    });
  }

  function addOnInputToElement(element, func){
    element.oninput = function(){ func() }
  }

  function sleepingLion(){
    var value = document.getElementsByClassName("sleep__range")[0].value;
    var element = document.getElementsByClassName("sleep__sleeping-lion")[0];
    changeBackgroundPosition(element, value, -332)
  }

  function changeBackgroundPosition(element, value, illustrationSize){
    element.style.backgroundPosition = parseInt(value) * illustrationSize + "px";
  }

  function addOnInputToElement(element, func){
    element.oninput = function(){ func() }
  }

  function emojiSprite(){
    var value = document.getElementsByClassName("range")[0].value;
    var element = document.getElementsByClassName("friends__emoji-sprite")[0];
    changeBackgroundPosition(element, value, -180)
  }

  function changeBackgroundPosition(element, value, illustrationSize){
    element.style.backgroundPosition = parseInt(value) * illustrationSize + "px";
  }
})(jQuery);
<commit_msg>Update function showing sprites - query DOM only once<commit_after>(function ($) {
  "use strict";

  addAnswersToSessionStorage();

  $('.carousel').carousel({
    indicators: true,
    shift: 100
  });

  function addAnswersToSessionStorage(){
    var personality = [];
    var hobbies = [];

    [
      "strange",
      "happy",
      "angry",
      "fun",
      "boring",
      "kind",
      "sad"
    ].forEach(emotion => {
      var node = document.getElementById(emotion);
      addClassToNode(node, 'pop');
      addClickEventArray('personality', node, emotion, personality);
    });

    [
      "sad-emoji",
      "happy-emoji",
      "indifferent-emoji"
    ].forEach(emoji => {
      var node = document.getElementsByClassName(emoji)[0];
      addClickEventSingle('feelings', node, emoji.match(/^[a-z]+/));
    });

    [
      "name",
      "age"
    ].forEach(inputField => {
      var node = document.getElementsByClassName(inputField)[0];
      addKeyupEvent(inputField, node);
    });

    [
      "football",
      "tennis",
      "gymnastics",
      "dance",
      "drawing",
      "photography",
      "cooking",
      "gardening",
      "puzzles",
      "camping",
      "fishing",
      "walking",
      "gymnastics-mobile",
      "photography-mobile",
      "walking-mobile",
      "puzzles-mobile"
    ].forEach(hobby => {
      var node = document.getElementsByClassName(hobby)[0];
      addClassToNode(node, 'js-chosen');
      addClickEventArray('hobbies', node, hobby, hobbies);
    });

    [
      "sleep__range",
      "friends__range",
      "school__range"
    ].forEach(range => {
      var node = document.getElementsByClassName(range)[0];
      if (node) {
        if (range === "sleep__range") {
          addOnInputToElement( node, sleepingLion );
        } else {
          addOnInputToElement( node, emojiSprite );
        }
      }
    });

    function addKeyupEvent(key, element){
      if(!element){ return; }
      element.addEventListener("keyup", function(){
        addSingleValueToStorage(key, element.value);
      });
    }

    function addClickEventSingle(key, element, value){
      if(!element){ return; }
      element.addEventListener("click", function(){
        addSingleValueToStorage(key, value);
      });
    }

    function addClickEventArray(key, element, value, array){
      if(!element){ return; }
      element.addEventListener("click", function(){
        addValueToArray(key, value, array);
      });
    }

    function addValueToArray(key, value, array){
      array.push(value);
      addArrayToStorage(key, array);
    }

    function addSingleValueToStorage(key, value){
      sessionStorage.setItem(key, value);
    }

    // JSON.stringify() is used here as session storage only supports strings
    function addArrayToStorage(key, array){
      sessionStorage.setItem(key, JSON.stringify(array));
    }
  }

  // Adds a class to node
  function addClassToNode(node, className){
    if (!node){ return; }
    node.addEventListener("click", function(){
      node.classList.add(className);
    });
  }

  function addOnInputToElement(element, func){
    element.oninput = function(){ func() }
  }

  function sleepingLion(){
    var value = document.getElementsByClassName("sleep__range")[0].value;
    var element = document.getElementsByClassName("sleep__sleeping-lion")[0];
    changeBackgroundPosition(element, value, -332)
  }

  function changeBackgroundPosition(element, value, illustrationSize){
    element.style.backgroundPosition = parseInt(value) * illustrationSize + "px";
  }

  function addOnInputToElement(element, func){
    element.oninput = function(){ func() }
  }

  function emojiSprite(){
    var value = document.getElementsByClassName("range")[0].value;
    var element = document.getElementsByClassName("friends__emoji-sprite")[0];
    changeBackgroundPosition(element, value, -180)
  }

  function changeBackgroundPosition(element, value, illustrationSize){
    element.style.backgroundPosition = parseInt(value) * illustrationSize + "px";
  }
})(jQuery);
<|endoftext|>


<commit_before><commit_msg>Extra check for mp<commit_after><|endoftext|>


<commit_before>var noop = {value: function() {}};

function dispatch() {
  for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
    if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
    _[t] = [];
  }
  return new Dispatch(_);
}

function Dispatch(_) {
  this._ = _;
}

function parseTypenames(typenames, types) {
  return typenames.trim().split(/^|\s+/).map(function(t) {
    var name = "", i = t.indexOf(".");
    if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
    if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
    return {type: t, name: name};
  });
}

Dispatch.prototype = dispatch.prototype = {
  constructor: Dispatch,
  on: function(typename, callback) {
    var _ = this._,
        T = parseTypenames(typename + "", _),
        t,
        i = -1,
        n = T.length;

    // If no callback was specified, return the callback of the given type and name.
    if (arguments.length < 2) {
      while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
      return;
    }

    // If a type was specified, set the callback for the given type and name.
    // Otherwise, if a null callback was specified, remove callbacks of the given name.
    if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
    while (++i < n) {
      if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
      else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
    }

    return this;
  },
  copy: function() {
    var copy = {}, _ = this._;
    for (var t in _) copy[t] = _[t].slice();
    return new Dispatch(copy);
  },
  call: function(type, that) {
    if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n; i < n; ++i) args[i] = arguments[i + 2];
    this.apply(type, that, args);
  },
  apply: function(type, that, args) {
    if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
    for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
  }
};

function get(type, name) {
  for (var i = 0, n = type.length, c; i < n; ++i) {
    if ((c = type[i]).name === name) {
      return c.value;
    }
  }
}

function set(type, name, callback) {
  for (var i = 0, n = type.length; i < n; ++i) {
    if (type[i].name === name) {
      type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
      break;
    }
  }
  if (callback != null) type.push({name: name, value: callback});
  return type;
}

export default dispatch;
<commit_msg>Workaround Safari optimizer bug.<commit_after>var noop = {value: function() {}};

function dispatch() {
  for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
    if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
    _[t] = [];
  }
  return new Dispatch(_);
}

function Dispatch(_) {
  this._ = _;
}

function parseTypenames(typenames, types) {
  return typenames.trim().split(/^|\s+/).map(function(t) {
    var name = "", i = t.indexOf(".");
    if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
    if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
    return {type: t, name: name};
  });
}

Dispatch.prototype = dispatch.prototype = {
  constructor: Dispatch,
  on: function(typename, callback) {
    var _ = this._,
        T = parseTypenames(typename + "", _),
        t,
        i = -1,
        n = T.length;

    // If no callback was specified, return the callback of the given type and name.
    if (arguments.length < 2) {
      while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
      return;
    }

    // If a type was specified, set the callback for the given type and name.
    // Otherwise, if a null callback was specified, remove callbacks of the given name.
    if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
    while (++i < n) {
      if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
      else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
    }

    return this;
  },
  copy: function() {
    var copy = {}, _ = this._;
    for (var t in _) copy[t] = _[t].slice();
    return new Dispatch(copy);
  },
  call: function(type, that) {
    if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
    if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
    for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
  },
  apply: function(type, that, args) {
    if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
    for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
  }
};

function get(type, name) {
  for (var i = 0, n = type.length, c; i < n; ++i) {
    if ((c = type[i]).name === name) {
      return c.value;
    }
  }
}

function set(type, name, callback) {
  for (var i = 0, n = type.length; i < n; ++i) {
    if (type[i].name === name) {
      type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
      break;
    }
  }
  if (callback != null) type.push({name: name, value: callback});
  return type;
}

export default dispatch;
<|endoftext|>


<commit_before>// ==========================================================================
//                            DG.SliderView
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. 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.
// ==========================================================================

/** @class  DG.SliderView - The top level view for a slider

 @extends DG.View
 */
DG.SliderView = SC.View.extend(
  /** @scope DG.SliderView.prototype */
  (function() {
    var kWidth = 30,
        kThumbHeight = 36,
        kAxisHeight = 20,
        kButtonHeight = 18,
        kButtonWidth = 20,
        kGap = 5,
        tMouseDownInfo,
        tDraggingThumb = false;

    return {
      backgroundColor: "white",

      /**
       The model on which this view is based.
       @property { DG.SliderModel }
       */
      model: null,

      /**
       The model on which this view is based.
       @property { DG.CellLinearAxisView }
       */
      axisView: null,

      /**
       Subview that displays draggable thumb.
       @property { SC.ImageView }
       */
      thumbView: null,

      /**
       Subview that displays slider name and value.
       @property { SC.IconButton }
       */
      startButton: null,

      /**
       Subview that displays slider name and value.
       @property { SC.LabelView }
       */
      valueView: null,

      /**
       Set to true when user editing of valueView begins
       @property {Boolean}
       */
      userEdit: false,

      /**
       Stores the value of the slider before a mousedrag begins
       @property { Number }
       */
      _previousValue: 0,

      /**
       My model's value if there is one.
       @property { Number }
       */
      value: function() {
        return this.getPath('model.value');
      }.property('model').cacheable(),

      valueDidChange: function() {
        this.notifyPropertyChange('value');
      }.observes('*model.value'),

      /**
       The name of my model's global value
       @property { String }
       */
      name: function() {
        return this.getPath('model.name');
      }.property('model').cacheable(),

      nameDidChange: function() {
        this.notifyPropertyChange('name');
      }.observes('*model.name'),

      /**
       The screen coordinate of the model value.
       @property { Number }
       */
      thumbCoord: function() {
        var tValue = this.get('value'),
            tAxisView = this.get('axisView');
        return (SC.none( tValue) || SC.none( tAxisView)) ? null : tAxisView.dataToCoordinate( tValue);
      }.property('value'),

      thumbCoordDidChange: function() {
        this.notifyPropertyChange('thumbCoord');
      }.observes('*axisView.model.lowerBound', '*axisView.model.upperBound'),

      init: function() {
        // Notice that we are explicitly creating and laying out our subviews. This is because
        // when we tried doing it through childViews (the usual way), something about the dependencies
        // wouldn't work. (Might be worth figuring out.)
        sc_super();
        DG.assert( !SC.none( this.get( 'model' ) ) );

        this.set( 'axisView', DG.CellLinearAxisView.create(
          { layout: { bottom: 0, height: kAxisHeight }, orientation: 'horizontal', isDropTarget: false } ) );
        this.appendChild( this.axisView );
        this.setPath( 'axisView.model', this.getPath( 'model.axis' ) );

        this._previousValue = this.getPath('model.value');

        this.set('thumbView',
            DG.IconButton.create( {
              layout: { bottom: kAxisHeight, width: kWidth, height: kThumbHeight },
              iconExtent: { width: kWidth, height: kThumbHeight },
              iconClass: 'thumb-icon',
              classNames: 'display-styles'.w(),
              toolTip: 'DG.SliderView.thumbView.toolTip', // "Start/stop animation"
              localize: true,
              touchPriority: true,
              mouseDown: function() { return NO; }
            }));
        this.appendChild( this.thumbView );

        this.set('startButton',

          DG.IconButton.create( {
            layout: {top: kGap + 2, left: 2, width: kButtonWidth + 2, height: kButtonHeight + 2},
            iconExtent: { width: kButtonWidth, height: kButtonHeight },
            classNames: 'display-styles'.w(),
            target: this,
            action: 'toggleAnimation',
            toolTip: 'DG.SliderView.startButton.toolTip', // "Start/stop animation"
            localize: true
          }));

        this.appendChild( this.startButton );

        this.set('valueView',
          SC.LabelView.create(DG.MouseAndTouchView, {
            layout: { left: kButtonWidth + kGap, top: 3, bottom: kAxisHeight + 16 },
            classNames: 'slider-label'.w(),
            isEditable: true,
            exampleNode: null,
            inlineEditorWillBeginEditing: function( iEditor, iValue, iEditable) {
              sc_super();
              var tFrame = this.get('frame'),
                  kXGap = 4, kYGap = 5,
                  tOrigin = DG.ViewUtilities.viewToWindowCoordinates( { x: kXGap - 2, y: kYGap - 7 }, this);

              this.parentView.set('userEdit', true);

              // SC 1.10 introduced a new inline editor model in which
              // an 'exampleNode' is used to adjust inline editor style.
              var exampleNode = this.get('exampleNode');
              if(!exampleNode) {
                var parentNode = this.getPath('parentView.layer');
                exampleNode = this.get('layer').cloneNode(false);
                exampleNode.id = exampleNode.id + "-clone";
                exampleNode.style.visibility = 'hidden';
                parentNode.appendChild(exampleNode);
                this.set('exampleNode', exampleNode);
              }
              exampleNode.style.left = 0 + 'px';
              exampleNode.style.top = 9 + 'px';

              iEditor.set({ exampleElement: exampleNode,
                            exampleFrame: { x: tOrigin.x, y: tOrigin.y,
                                            width: tFrame.width - 2 * kXGap,
                                            height: tFrame.height - 2 * kYGap }});
            },
            doIt: function() {
              this.beginEditing();
            }
        }));
        this.appendChild( this.valueView );
      },

      _destroy: function () {
        var controller = this.get('controller');
        if( controller)
          controller.stopAnimation();
        this.model.destroy(); // so that it can unlink observers
      },

      willDestroy: function() {
        console.log('SliderView.willDestroy');
        this._destroy;
        sc_super();
      },

      destroy: function () {
        console.log('SliderView.destroy');
        this._destroy;
        sc_super();
      },

      viewDidResize: function() {
        sc_super();
        this.positionThumb();
      },

      /**
       * Use the value to position the thumbView.
       */
      positionThumb: function() {
        var tCoord = this.get('thumbCoord');
        if( DG.isFinite( tCoord)) {
          var thumbView = this.get('thumbView');
          if( thumbView)
            thumbView.adjust('left', tCoord + 0.5 - kWidth / 2);
        }
      }.observes('thumbCoord'),

      /**
       * Use the value to position the thumbView.
       */
      updateValueView: function() {
        var tAxis = this.get('axisView'),
            tDelta = tAxis.coordinateToData( 1) - tAxis.coordinateToData( 0),
            tLogDelta = Math.log( tDelta) / Math.LN10,
            tMaxDecimals = Math.ceil( -tLogDelta),
            tModel = this.get('model'),
            tName = SC.none( tModel) ? '' : tModel.get('name'),
            tNumber = SC.none( tModel) ? '' : DG.Format.number().fractionDigits( 0, tMaxDecimals)( tModel.get('value'));

        this.setPath('valueView.value', tName + ' = ' + tNumber);
      }.observes('thumbCoord', 'name'),

      mouseDown: function( iEvent) {
        DG.globalEditorLock.commitCurrentEdit();
        var tThumbFrame = this.getPath('thumbView.frame');
        tMouseDownInfo = {
          pagePoint: { x: iEvent.pageX, y: iEvent.pageY },
          viewPoint: DG.ViewUtilities.windowToViewCoordinates( { x: iEvent.pageX, y: iEvent.pageY }, this),
          thumbCoord: this.get('thumbCoord')
        };
        if( DG.ViewUtilities.ptInRect( tMouseDownInfo.viewPoint, tThumbFrame)) {
          this._previousValue = this.getPath('model.value');
          tDraggingThumb = true;
          return YES;  // We handled it
        }
        else
          // Let other event handling proceed - especially double-click
          return NO;
      },

      mouseDragged: function( iEvent) {
        if( tDraggingThumb) {
          var tDelta = iEvent.pageX - tMouseDownInfo.pagePoint.x,
              tNewCoord = tMouseDownInfo.thumbCoord + tDelta,
              tNewValue = this.get('axisView').coordinateToData( tNewCoord);
          this.setPath('model.value', tNewValue);
        }
      },

      mouseUp: function() {
        if( tDraggingThumb) {
          var this_ = this;
          DG.UndoHistory.execute(DG.Command.create({
            name: 'slider.change',
            undoString: 'DG.Undo.slider.change',
            redoString: 'DG.Redo.slider.change',
            log: "sliderThumbDrag: { \"name\": \"%@\", \"newValue\": %@ }".fmt(this_.getPath('model.name'), this_.getPath('model.value')),
            _componentId: this_.getPath('controller.model.id'),
            _controller: function() {
              return DG.currDocumentController().componentControllersMap[this._componentId];
            },
            _view: function() {
              return this._controller().get('sliderView');
            },
            _newValue: this_.getPath('model.value'),
            _prevValue: this_._previousValue,
            execute: function() {
              this._view().get('model').encompassValue();
              if (this._newValue === this._prevValue) {
                this.causedChange = false;
              }
            },
            undo: function() {
              var view = this._view();
              view.setPath('model.value', this._prevValue);
              view.get('model').encompassValue();
            },
            redo: function() {
              var view = this._view();
              view.setPath('model.value', this._newValue);
              view.get('model').encompassValue();
            }
          }));
        }
        tDraggingThumb = false;
      },

      touchStart: function(evt){
        return this.mouseDown(evt);
      },
      touchEnd: function(evt){
        return this.mouseUp(evt);
      },
      touchesDragged: function( evt, touches) {
        return this.mouseDragged( evt);
      },

      toggleAnimation: function() {
        var controller = this.get('controller');
        if( controller)
          controller.toggleAnimation();
      },

      /**
       * Updates the start button appearance
       */
      isAnimatingDidChange: function() {
        var startButton = this.get('startButton');
        if( !this.getPath('controller.isAnimating')) {
          startButton.set('iconClass', 'play-icon');
        }
        else {
          startButton.set('iconClass', 'pause-icon');
        }
      }.observes('*controller.isAnimating'),

      /**
       * Parses the user-edited contents of valueView. If it can identify a variable name and value,
       * the global value name and value will be set accordingly.
       */
      valueViewWasEdited: function() {
        // regular expression for matching 'variable = value'
        // TODO: Do better with white space
        // TODO: Handle scientific notation? Thousands separators? Internationalization?
        var kMatchExp = /^\s*([a-zA-Z_][\w]*)\s*=\s*([+\-]?[0-9.]+)/,
            tResult, tNewValue, tNewName;
        // We only want to parse the expression if the user actually edited it
        if( this.get('userEdit')) {
          var tNewString = this.getPath('valueView.value');
          tNewString = tNewString.replace('\u2212', '-');
          this.set('userEdit', false);
          tResult = kMatchExp.exec( tNewString);
          DG.logUser("sliderEdit: { expression: '%@', result: %@ }",
                                      tNewString, !SC.none( tResult) ? "success" : "failure");
          if( !SC.none( tResult)) {
            tNewValue = parseFloat( tResult[ 2]);
            tNewName = tResult[ 1];
            this.setPathIfChanged('model.value', tNewValue);
            this.setPathIfChanged('model.name', tNewName);
            this.get('model').encompassValue();
          }
          else
            this.updateValueView();
        }
      }.observes('.valueView.value')

    };
  }()) );

<commit_msg>[Fixes #132374697] Prevent slider axis from changing when user drags the slider thumb In mouseDragged, we prevent the slider from being dragged beyond the ends of the slider axis.<commit_after>// ==========================================================================
//                            DG.SliderView
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. 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.
// ==========================================================================

/** @class  DG.SliderView - The top level view for a slider

 @extends DG.View
 */
DG.SliderView = SC.View.extend(
  /** @scope DG.SliderView.prototype */
  (function() {
    var kWidth = 30,
        kThumbHeight = 36,
        kAxisHeight = 20,
        kButtonHeight = 18,
        kButtonWidth = 20,
        kGap = 5,
        tMouseDownInfo,
        tDraggingThumb = false;

    return {
      backgroundColor: "white",

      /**
       The model on which this view is based.
       @property { DG.SliderModel }
       */
      model: null,

      /**
       The model on which this view is based.
       @property { DG.CellLinearAxisView }
       */
      axisView: null,

      /**
       Subview that displays draggable thumb.
       @property { SC.ImageView }
       */
      thumbView: null,

      /**
       Subview that displays slider name and value.
       @property { SC.IconButton }
       */
      startButton: null,

      /**
       Subview that displays slider name and value.
       @property { SC.LabelView }
       */
      valueView: null,

      /**
       Set to true when user editing of valueView begins
       @property {Boolean}
       */
      userEdit: false,

      /**
       Stores the value of the slider before a mousedrag begins
       @property { Number }
       */
      _previousValue: 0,

      /**
       My model's value if there is one.
       @property { Number }
       */
      value: function() {
        return this.getPath('model.value');
      }.property('model').cacheable(),

      valueDidChange: function() {
        this.notifyPropertyChange('value');
      }.observes('*model.value'),

      /**
       The name of my model's global value
       @property { String }
       */
      name: function() {
        return this.getPath('model.name');
      }.property('model').cacheable(),

      nameDidChange: function() {
        this.notifyPropertyChange('name');
      }.observes('*model.name'),

      /**
       The screen coordinate of the model value.
       @property { Number }
       */
      thumbCoord: function() {
        var tValue = this.get('value'),
            tAxisView = this.get('axisView');
        return (SC.none( tValue) || SC.none( tAxisView)) ? null : tAxisView.dataToCoordinate( tValue);
      }.property('value'),

      thumbCoordDidChange: function() {
        this.notifyPropertyChange('thumbCoord');
      }.observes('*axisView.model.lowerBound', '*axisView.model.upperBound'),

      init: function() {
        // Notice that we are explicitly creating and laying out our subviews. This is because
        // when we tried doing it through childViews (the usual way), something about the dependencies
        // wouldn't work. (Might be worth figuring out.)
        sc_super();
        DG.assert( !SC.none( this.get( 'model' ) ) );

        this.set( 'axisView', DG.CellLinearAxisView.create(
          { layout: { bottom: 0, height: kAxisHeight }, orientation: 'horizontal', isDropTarget: false } ) );
        this.appendChild( this.axisView );
        this.setPath( 'axisView.model', this.getPath( 'model.axis' ) );

        this._previousValue = this.getPath('model.value');

        this.set('thumbView',
            DG.IconButton.create( {
              layout: { bottom: kAxisHeight, width: kWidth, height: kThumbHeight },
              iconExtent: { width: kWidth, height: kThumbHeight },
              iconClass: 'thumb-icon',
              classNames: 'display-styles'.w(),
              toolTip: 'DG.SliderView.thumbView.toolTip', // "Start/stop animation"
              localize: true,
              touchPriority: true,
              mouseDown: function() { return NO; }
            }));
        this.appendChild( this.thumbView );

        this.set('startButton',

          DG.IconButton.create( {
            layout: {top: kGap + 2, left: 2, width: kButtonWidth + 2, height: kButtonHeight + 2},
            iconExtent: { width: kButtonWidth, height: kButtonHeight },
            classNames: 'display-styles'.w(),
            target: this,
            action: 'toggleAnimation',
            toolTip: 'DG.SliderView.startButton.toolTip', // "Start/stop animation"
            localize: true
          }));

        this.appendChild( this.startButton );

        this.set('valueView',
          SC.LabelView.create(DG.MouseAndTouchView, {
            layout: { left: kButtonWidth + kGap, top: 3, bottom: kAxisHeight + 16 },
            classNames: 'slider-label'.w(),
            isEditable: true,
            exampleNode: null,
            inlineEditorWillBeginEditing: function( iEditor, iValue, iEditable) {
              sc_super();
              var tFrame = this.get('frame'),
                  kXGap = 4, kYGap = 5,
                  tOrigin = DG.ViewUtilities.viewToWindowCoordinates( { x: kXGap - 2, y: kYGap - 7 }, this);

              this.parentView.set('userEdit', true);

              // SC 1.10 introduced a new inline editor model in which
              // an 'exampleNode' is used to adjust inline editor style.
              var exampleNode = this.get('exampleNode');
              if(!exampleNode) {
                var parentNode = this.getPath('parentView.layer');
                exampleNode = this.get('layer').cloneNode(false);
                exampleNode.id = exampleNode.id + "-clone";
                exampleNode.style.visibility = 'hidden';
                parentNode.appendChild(exampleNode);
                this.set('exampleNode', exampleNode);
              }
              exampleNode.style.left = 0 + 'px';
              exampleNode.style.top = 9 + 'px';

              iEditor.set({ exampleElement: exampleNode,
                            exampleFrame: { x: tOrigin.x, y: tOrigin.y,
                                            width: tFrame.width - 2 * kXGap,
                                            height: tFrame.height - 2 * kYGap }});
            },
            doIt: function() {
              this.beginEditing();
            }
        }));
        this.appendChild( this.valueView );
      },

      _destroy: function () {
        var controller = this.get('controller');
        if( controller)
          controller.stopAnimation();
        this.model.destroy(); // so that it can unlink observers
      },

      willDestroy: function() {
        console.log('SliderView.willDestroy');
        this._destroy;
        sc_super();
      },

      destroy: function () {
        console.log('SliderView.destroy');
        this._destroy;
        sc_super();
      },

      viewDidResize: function() {
        sc_super();
        this.positionThumb();
      },

      /**
       * Use the value to position the thumbView.
       */
      positionThumb: function() {
        var tCoord = this.get('thumbCoord');
        if( DG.isFinite( tCoord)) {
          var thumbView = this.get('thumbView');
          if( thumbView)
            thumbView.adjust('left', tCoord + 0.5 - kWidth / 2);
        }
      }.observes('thumbCoord'),

      /**
       * Use the value to position the thumbView.
       */
      updateValueView: function() {
        var tAxis = this.get('axisView'),
            tDelta = tAxis.coordinateToData( 1) - tAxis.coordinateToData( 0),
            tLogDelta = Math.log( tDelta) / Math.LN10,
            tMaxDecimals = Math.ceil( -tLogDelta),
            tModel = this.get('model'),
            tName = SC.none( tModel) ? '' : tModel.get('name'),
            tNumber = SC.none( tModel) ? '' : DG.Format.number().fractionDigits( 0, tMaxDecimals)( tModel.get('value'));

        this.setPath('valueView.value', tName + ' = ' + tNumber);
      }.observes('thumbCoord', 'name'),

      mouseDown: function( iEvent) {
        DG.globalEditorLock.commitCurrentEdit();
        var tThumbFrame = this.getPath('thumbView.frame');
        tMouseDownInfo = {
          pagePoint: { x: iEvent.pageX, y: iEvent.pageY },
          viewPoint: DG.ViewUtilities.windowToViewCoordinates( { x: iEvent.pageX, y: iEvent.pageY }, this),
          thumbCoord: this.get('thumbCoord')
        };
        if( DG.ViewUtilities.ptInRect( tMouseDownInfo.viewPoint, tThumbFrame)) {
          this._previousValue = this.getPath('model.value');
          tDraggingThumb = true;
          return YES;  // We handled it
        }
        else
          // Let other event handling proceed - especially double-click
          return NO;
      },

      mouseDragged: function( iEvent) {
        if( tDraggingThumb) {
          var tPixelMax = this.getPath('axisView.pixelMax'),
              tPixelMin = this.getPath('axisView.pixelMin'),
              tDelta = iEvent.pageX - tMouseDownInfo.pagePoint.x,
              tNewCoord = tMouseDownInfo.thumbCoord + tDelta,
              tNewValue;
          tNewCoord = Math.min( Math.max( tNewCoord, tPixelMin), tPixelMax);
          tNewValue = this.get('axisView').coordinateToData( tNewCoord);
          this.setPath('model.value', tNewValue);
        }
      },

      mouseUp: function() {
        if( tDraggingThumb) {
          var this_ = this;
          DG.UndoHistory.execute(DG.Command.create({
            name: 'slider.change',
            undoString: 'DG.Undo.slider.change',
            redoString: 'DG.Redo.slider.change',
            log: "sliderThumbDrag: { \"name\": \"%@\", \"newValue\": %@ }".fmt(this_.getPath('model.name'), this_.getPath('model.value')),
            _componentId: this_.getPath('controller.model.id'),
            _controller: function() {
              return DG.currDocumentController().componentControllersMap[this._componentId];
            },
            _view: function() {
              return this._controller().get('sliderView');
            },
            _newValue: this_.getPath('model.value'),
            _prevValue: this_._previousValue,
            execute: function() {
              this._view().get('model').encompassValue();
              if (this._newValue === this._prevValue) {
                this.causedChange = false;
              }
            },
            undo: function() {
              var view = this._view();
              view.setPath('model.value', this._prevValue);
              view.get('model').encompassValue();
            },
            redo: function() {
              var view = this._view();
              view.setPath('model.value', this._newValue);
              view.get('model').encompassValue();
            }
          }));
        }
        tDraggingThumb = false;
      },

      touchStart: function(evt){
        return this.mouseDown(evt);
      },
      touchEnd: function(evt){
        return this.mouseUp(evt);
      },
      touchesDragged: function( evt, touches) {
        return this.mouseDragged( evt);
      },

      toggleAnimation: function() {
        var controller = this.get('controller');
        if( controller)
          controller.toggleAnimation();
      },

      /**
       * Updates the start button appearance
       */
      isAnimatingDidChange: function() {
        var startButton = this.get('startButton');
        if( !this.getPath('controller.isAnimating')) {
          startButton.set('iconClass', 'play-icon');
        }
        else {
          startButton.set('iconClass', 'pause-icon');
        }
      }.observes('*controller.isAnimating'),

      /**
       * Parses the user-edited contents of valueView. If it can identify a variable name and value,
       * the global value name and value will be set accordingly.
       */
      valueViewWasEdited: function() {
        // regular expression for matching 'variable = value'
        // TODO: Do better with white space
        // TODO: Handle scientific notation? Thousands separators? Internationalization?
        var kMatchExp = /^\s*([a-zA-Z_][\w]*)\s*=\s*([+\-]?[0-9.]+)/,
            tResult, tNewValue, tNewName;
        // We only want to parse the expression if the user actually edited it
        if( this.get('userEdit')) {
          var tNewString = this.getPath('valueView.value');
          tNewString = tNewString.replace('\u2212', '-');
          this.set('userEdit', false);
          tResult = kMatchExp.exec( tNewString);
          DG.logUser("sliderEdit: { expression: '%@', result: %@ }",
                                      tNewString, !SC.none( tResult) ? "success" : "failure");
          if( !SC.none( tResult)) {
            tNewValue = parseFloat( tResult[ 2]);
            tNewName = tResult[ 1];
            this.setPathIfChanged('model.value', tNewValue);
            this.setPathIfChanged('model.name', tNewName);
            this.get('model').encompassValue();
          }
          else
            this.updateValueView();
        }
      }.observes('.valueView.value')

    };
  }()) );

<|endoftext|>


<commit_before>define([
	'jquery',
	'backbone',
	'marionette',
	'appbar/appbar.model',
	'appbar/appbar.view',
	'welcome/welcome.view',
	'app.primary.view'
], function ($, Backbone, Marionette, AppBarModel, AppBarView, WelcomeView, AppPrimaryView) {
	'use strict';

	var AppView = Marionette.LayoutView.extend({
		el: 'body',

		regions: {
			appbar : '#top',
			main : '#primary'
		initialize: function () {
			var self = this;

			this.stack = this.model.get('modalStack');
			this.radio = Backbone.Wreqr.radio.channel('global');

			this.showChildView('appbar', new AppBarView({ model: new AppBarModel() }) );

			this.renderMainView();

			win.on('focus', function () {
				win.blur();
				if(self.stack && self.stack.length > 0) {
					self.stack.at(self.stack.length - 1).focus();
				}
				return false;
			});

			this.radio.vent.on('application:reload', this.forceCloseModals.bind(this));
			win.on('close', this.forceCloseModals.bind(this));
		},

		render: function () {

			return this;
		},

		renderMainView: function () {
			var self = this;
			if(this.main && this.main.currentView)
				this.getRegion('main').reset();

			if(this.model.get('accounts').length === 0) {
				this.radio.commands.setHandler('welcome:complete', function () {
					self.renderMainView();
				});
				this.showChildView('main', new WelcomeView({model : this.model}) );
			} else {
				// TODO
				this.showChildView('main', new AppPrimaryView({
					model : this.model,
					collection: this.model.get('mailboxes')}
				));
			}
		},

		setDeveloperMode: function () {
			this.appbar.currentView.model.set('isDebug', true);
			return this;
		},

		forceCloseModals: function () {
			while(this.stack.length) {
				this.stack.pop().forceClose();
			}
		}
	});

	return AppView;
});<commit_msg>Fix missing brace<commit_after>define([
	'jquery',
	'backbone',
	'marionette',
	'appbar/appbar.model',
	'appbar/appbar.view',
	'welcome/welcome.view',
	'app.primary.view'
], function ($, Backbone, Marionette, AppBarModel, AppBarView, WelcomeView, AppPrimaryView) {
	'use strict';

	var AppView = Marionette.LayoutView.extend({
		el: 'body',

		regions: {
			appbar : '#top',
			main : '#primary'
		},

		initialize: function () {
			var self = this;

			this.stack = this.model.get('modalStack');
			this.radio = Backbone.Wreqr.radio.channel('global');

			this.showChildView('appbar', new AppBarView({ model: new AppBarModel() }) );

			this.renderMainView();

			win.on('focus', function () {
				win.blur();
				if(self.stack && self.stack.length > 0) {
					self.stack.at(self.stack.length - 1).focus();
				}
				return false;
			});

			this.radio.vent.on('application:reload', this.forceCloseModals.bind(this));
			win.on('close', this.forceCloseModals.bind(this));
		},

		render: function () {

			return this;
		},

		renderMainView: function () {
			var self = this;
			if(this.main && this.main.currentView)
				this.getRegion('main').reset();

			if(this.model.get('accounts').length === 0) {
				this.radio.commands.setHandler('welcome:complete', function () {
					self.renderMainView();
				});
				this.showChildView('main', new WelcomeView({model : this.model}) );
			} else {
				// TODO
				this.showChildView('main', new AppPrimaryView({
					model : this.model,
					collection: this.model.get('mailboxes')}
				));
			}
		},

		setDeveloperMode: function () {
			this.appbar.currentView.model.set('isDebug', true);
			return this;
		},

		forceCloseModals: function () {
			while(this.stack.length) {
				this.stack.pop().forceClose();
			}
		}
	});

	return AppView;
});<|endoftext|>


<commit_before>/**
 * Base application
 * @module arpen/app/base
 */
const debug = require('debug')('arpen:app');
const fs = require('fs-ext');
const path = require('path');
const merge = require('merge');
const WError = require('verror').WError;
const Filer = require('../services/filer.js');

/**
 * Logger to use when 'logger' service is not available
 */
class AppLogger {
    error(...args) {
        console.error(...args);
    }
}

/**
 * Base application class
 */
class App {
    /**
     * Create app
     * @param {string} basePath             Base path
     * @param {object} argv                 Minimist object
     */
    constructor(basePath, argv) {
        debug('Constructing the app');
        this.basePath = basePath;
        this.argv = argv;
        this._initialized = null;
        this._running = null;
        this._container = new Map();
        this.registerInstance(this, 'app');
    }

    /**
     * Register an instance of a service
     * @param {*} instance                  Instance
     * @param {string} name                 Name
     * @return {string}                     Returns name of the service
     */
    registerInstance(instance, name) {
        if (!name)
            throw new Error('No name provided for an instance');

        debug(`Registering instance '${name}'`);
        let service = this._initService(name);
        delete service.class;
        service.instance = instance;

        return name;
    }

    /**
     * Register class function as a service
     * @param {function} classFunc          Class function
     * @return {string}                     Returns name of the service
     */
    registerClass(classFunc) {
        let name = classFunc.provides;
        if (!name)
            throw new Error('No name provided for a class');

        debug(`Registering class '${name}'`);
        let service = this._initService(name);
        service.class = classFunc;
        delete service.instance;

        return name;
    }

    /**
     * Get instance of a service
     * @param {string} name                 Service name
     * @param {...*} extra                  Optional extra arguments to the constructor
     * @return {object}                     Returns instance
     */
    get(name, ...extra) {
        if (!name)
            throw new Error('No service name provided');

        debug(`Retrieving service '${name}'`);
        return this._resolveService(name, extra, new Map());
    }

    /**
     * Search registered services
     * @param {RegExp} re                   Service name RegExp
     * @return {string[]}                   Returns array of matching service names
     */
    search(re) {
        debug(`Searching for services ${re}`);
        let result = [];
        for (let name of this._container.keys()) {
            if (re.test(name))
                result.push(name);
        }
        return result;
    }

    /**
     * Debug output
     * @param {...*} messages                           Messages
     */
    debug(...messages) {
        if (!(!!process.env.DEBUG))
            return Promise.resolve();

        return this._output(process.stderr, messages);
    }

    /**
     * Info output
     * @param {...*} messages                           Messages
     */
    info(...messages) {
        return this._output(process.stdout, messages);
    }

    /**
     * Error output
     * @param {...*} messages                           Messages
     */
    error(...messages) {
        return this._output(process.stderr, messages);
    }

    /**
     * Run the app. This method will simply call .init() and then .start().
     * @param {...*} args                               Descendant-specific arguments
     */
    run(...args) {
        this.init(...args)
            .then(() => {
                return this.start(...args);
            })
            .catch(error => {
                let logger;
                try {
                    logger = this.get('logger');
                    logger.error(new WError(error, 'App.run() failed'));
                } catch (ignore) {
                    logger = new AppLogger();
                    logger.error('App.run() failed:', error.message);
                }
                process.exit(1);
            });
    }

    /**
     * Initialize the app
     * @return {Promise}
     */
    init() {
        if (this._initialized)
            return Promise.resolve();

        debug('Initializing the app');
        return new Promise((resolve, reject) => {
                if (this._initialized === false)
                    return reject(new Error('Application is in process of initialization'));

                this._initialized = false;
                resolve();
            })
            .then(() => {
                return this._initConfig();
            })
            .then(() => {
                return this._initSources();
            })
            .then(() => {
                return this._initLogger();
            })
            .then(() => {
                return this._initModules();
            })
            .then(() => {
                this._initialized = true;
            });
    }

    /**
     * Start the app
     * @return {Promise}
     */
    start() {
        return new Promise((resolve, reject) => {
            if (this._running !== null)
                return reject(new Error('Application is already started'));

            this._running = false;
            resolve();
        });
    }

    /**
     * Load the configuration
     * @return {Promise}
     */
    _initConfig() {
        let config, modules = [];
        debug('Loading application configuration');
        return Promise.all([
                this.constructor._require(path.join(this.basePath, 'config', 'global.js')),
                this.constructor._require(path.join(this.basePath, 'config', 'local.js'), {}),
            ])
            .then(([globalConf, localConf]) => {
                if (typeof globalConf != 'object')
                    throw new Error('Global config is not an object');
                if (typeof localConf!= 'object')
                    throw new Error('Local config is not an object');

                config = merge.recursive(true, globalConf, localConf);
                config.base_path = this.basePath;
                config.get = function (key) {
                    return key.split('.').reduce((prev, cur) => {
                        if (!prev)
                            return prev;
                        return prev[cur];
                    }, this);
                };
                this.registerInstance(config, 'config');

                if (!config.autoload)
                    config.autoload = [];
                else if (!Array.isArray(config.autoload))
                    throw new Error('Config.autoload is not an array');

                if (!config.modules)
                    config.modules = [];
                else if (!Array.isArray(config.modules))
                    throw new Error('Config.modules is not an array');

                return config.modules.reduce(
                    (prev, cur) => {
                        return prev.then(() => {
                                debug(`Loading module ${cur} configuration`);
                                return Promise.all([
                                    this.constructor._require(
                                        path.join(this.basePath, 'modules', cur, 'config', 'global.js'),
                                        { autoload: [] }
                                    ),
                                    this.constructor._require(
                                        path.join(this.basePath, 'modules', cur, 'config', 'local.js'),
                                        {}
                                    )
                                ])
                                .then(([globalConf, localConf]) => {
                                    if (typeof globalConf != 'object')
                                        throw new Error(`Global config is not an object (module: ${cur})`);
                                    if (typeof localConf!= 'object')
                                        throw new Error(`Local config is not an object (module: ${cur})`);

                                    let moduleConfig = merge.recursive(true, globalConf, localConf);
                                    moduleConfig.name = cur;

                                    if (!moduleConfig.autoload)
                                        moduleConfig.autoload = [];
                                    else if (!Array.isArray(moduleConfig.autoload))
                                        throw new Error(`Config.autoload is not an array (module: ${cur})`);

                                    modules.push(moduleConfig);
                                });
                        });
                    },
                    Promise.resolve()
                );
            })
            .then(() => {
                config.modules = modules;
            });
    }

    /**
     * Load the source files
     * @return {Promise}
     */
    _initSources() {
        let config = this.get('config');
        let filer = new Filer();
        debug('Loading application sources');
        return config.autoload.reduce(
                (prev, cur) => {
                    return prev.then(() => {
                        let file = cur;
                        if (cur[0] == '!')
                            file = path.join(this.basePath, 'node_modules', 'arpen', cur.slice(1));
                        else if (cur[0] != '/')
                            file = path.join(this.basePath, cur);
                        return filer.process(
                            file,
                            filename => {
                                return this.constructor._require(filename)
                                    .then(obj => {
                                        if (!obj.provides)
                                            return;

                                        try {
                                            this.registerClass(obj);
                                        } catch (error) {
                                            throw new WError(error, `Registering ${filename}`);
                                        }
                                    });
                            }
                        );
                    });
                },
                Promise.resolve()
            )
            .then(() => {
                return config.modules.reduce(
                    (prevModule, curModule) => {
                        return prevModule.then(() => {
                            debug(`Loading module ${curModule.name} sources`);
                            return curModule.autoload.reduce(
                                (prevLoad, curLoad) => {
                                    return prevLoad.then(() => {
                                        let file = curLoad;
                                        if (curLoad[0] == '!')
                                            file = path.join(this.basePath, 'node_modules', 'arpen', curLoad.slice(1));
                                        else if (curLoad[0] != '/')
                                            file = path.join(this.basePath, 'modules', curModule.name, curLoad);
                                        return filer.process(
                                            file,
                                            filename => {
                                                return this.constructor._require(filename)
                                                    .then(obj => {
                                                        try {
                                                            this.registerClass(obj);
                                                        } catch (error) {
                                                            throw new WError(error, `Registering ${filename}`);
                                                        }
                                                    });
                                            }
                                        );
                                    });
                                },
                                Promise.resolve()
                            );
                        });
                    },
                    Promise.resolve()
                );
            });
    }

    /**
     * Create log streams
     * @return {Promise}
     */
    _initLogger() {
        return new Promise((resolve, reject) => {
            try {
                let config = this.get('config');
                if (!config.logs)
                    return resolve();

                let logger = this.get('logger');
                for (let log of Object.keys(config.logs)) {
                    let info = Object.assign({}, config.logs[log]);
                    let name = info.name;
                    delete info.name;
                    let level = info.level || 'info';
                    delete info.level;
                    let isDefault = info.default || false;
                    delete info.default;
                    logger.setLogStream(name, level, isDefault, info);
                }
                resolve();
            } catch (error) {
                console.log(error);
                reject(new WError(error, 'App._initLogger()'));
            }
        });
    }

    /**
     * Start modules
     * @return {Promise}
     */
    _initModules() {
        let modules = new Map();
        this.registerInstance(modules, 'modules');

        return this.search(/^modules\.[^.]+$/).reduce(
            (prev, cur) => {
                let _module = this.get(cur);
                modules.set(cur, _module);

                return prev.then(() => {
                    debug(`Bootstrapping module '${cur}'`);
                    let result = _module.bootstrap();
                    if (result === null || typeof result != 'object' || typeof result.then != 'function')
                        throw new Error(`Module '${cur}' bootstrap() did not return a Promise`);
                    return result;
                });
            },
            Promise.resolve()
        );
    }

    /**
     * Returns item of the service container, adding new one if it does not exist yet
     * @param {string} name                 Name of the service
     * @return {object}                     Returns service object
     */
    _initService(name) {
        if (name[name.length - 1] == '?')
            throw new Error(`Invalid service name: ${name}`);

        let service;
        if (this._container.has(name)) {
            service = this._container.get(name);
        } else {
            service = {};
            this._container.set(name, service);
        }
        return service;
    }

    /**
     * Resolve dependencies and return an instance of a service
     * @param {string} name                 Service name
     * @param {Array} extra                 Extra constructor arguments
     * @param {Map} request                 Resolved dependencies
     * @return {object}                     Returns instance of the service
     */
    _resolveService(name, extra, request) {
        let mustExist = true;
        if (name[name.length - 1] == '?') {
            name = name.slice(0, -1);
            mustExist = false;
        }

        if (!this._container.has(name)) {
            if (mustExist)
                throw new Error(`No service was found: ${name}`);
            return undefined;
        }

        let service = this._container.get(name);
        if (!service.class)
            return service.instance;

        let instance;
        if (request.has(name)) { // already resolved
            instance = request.get(name);
        } else {
            request.set(name, null); // mark as visited but not resolved yet
            switch (service.class.lifecycle || 'perRequest') {
                case 'perRequest':
                    instance = this._instantiateClass(service.class, extra, request);
                    request.set(name, instance);
                    break;
                case 'unique':
                    instance = this._instantiateClass(service.class, extra, request);
                    request.delete(name);
                    break;
                case 'singleton':
                    if (service.instance) {
                        instance = service.instance;
                    } else {
                        instance = this._instantiateClass(service.class, extra, request);
                        service.instance = instance;
                    }
                    request.set(name, instance);
                    break;
                default:
                    throw new Error(`Service '${name}' has invalid lifecycle: ${service.class.lifecycle}`);
            }
        }

        if (!instance)
            throw new Error(`Cyclic dependency while resolving '${name}'`);

        return instance;
    }

    /**
     * Instantiate given service class
     * @param {function} classFunc          Class function
     * @param {Array} extra                 Extra constructor arguments
     * @param {Map} request                 Resolved dependencies
     * @return {object}                     Returns instance of the class
     */
    _instantiateClass(classFunc, extra, request) {
        let args = [];
        for (let arg of classFunc.requires || [])
            args.push(this._resolveService(arg, [], request));
        args = args.concat(extra);
        return new classFunc(...args);
    }

    /**
     * Print output
     * @param {*} stream                    Stream for output
     * @param {Array} messages              Messages
     */
    _output(stream, messages) {
        return new Promise((resolve, reject) => {
            let output = messages.join(' ');
            if (!output.length)
                return resolve();

            let onError = error => {
                reject(error);
            };

            stream.once('error', onError);
            stream.write(output, () => {
                stream.removeListener('error', onError);
                resolve();
            })
        });
    }

    /**
     * Load js file
     * @param {string} filename             Path of the file
     * @param {*} [defaultObject]           If specified this will be returned if file could not be loaded
     * @return {Promise}                    Resolves to the exported object
     */
    static _require(filename, defaultObject) {
        return new Promise((resolve, reject) => {
                try {
                    resolve(require(filename));
                } catch (err) {
                    if (typeof defaultObject == 'undefined')
                        reject(new WError(err, `Could not load ${filename}`));
                    else
                        resolve(defaultObject);
                }
            });
    }
}

module.exports = App;<commit_msg>Start/stop program handling<commit_after>/**
 * Base application
 * @module arpen/app/base
 */
const debug = require('debug')('arpen:app');
const fs = require('fs-ext');
const path = require('path');
const merge = require('merge');
const WError = require('verror').WError;
const Filer = require('../services/filer.js');

/**
 * Logger to use when 'logger' service is not available
 */
class AppLogger {
    error(...args) {
        console.error(...args);
    }
}

/**
 * Base application class
 */
class App {
    /**
     * Create app
     * @param {string} basePath             Base path
     * @param {object} argv                 Minimist object
     */
    constructor(basePath, argv) {
        debug('Constructing the app');
        this.basePath = basePath;
        this.argv = argv;
        this._initialized = null;
        this._running = null;
        this._container = new Map();
        this.registerInstance(this, 'app');
    }

    /**
     * Graceful shutdown timeout
     * @type {number}
     */
    static get gracefulTimeout() {
        return 10 * 1000; // ms
    }

    /**
     * Register an instance of a service
     * @param {*} instance                  Instance
     * @param {string} name                 Name
     * @return {string}                     Returns name of the service
     */
    registerInstance(instance, name) {
        if (!name)
            throw new Error('No name provided for an instance');

        debug(`Registering instance '${name}'`);
        let service = this._initService(name);
        delete service.class;
        service.instance = instance;

        return name;
    }

    /**
     * Register class function as a service
     * @param {function} classFunc          Class function
     * @return {string}                     Returns name of the service
     */
    registerClass(classFunc) {
        let name = classFunc.provides;
        if (!name)
            throw new Error('No name provided for a class');

        debug(`Registering class '${name}'`);
        let service = this._initService(name);
        service.class = classFunc;
        delete service.instance;

        return name;
    }

    /**
     * Get instance of a service
     * @param {string} name                 Service name
     * @param {...*} extra                  Optional extra arguments to the constructor
     * @return {object}                     Returns instance
     */
    get(name, ...extra) {
        if (!name)
            throw new Error('No service name provided');

        debug(`Retrieving service '${name}'`);
        return this._resolveService(name, extra, new Map());
    }

    /**
     * Search registered services
     * @param {RegExp} re                   Service name RegExp
     * @return {string[]}                   Returns array of matching service names
     */
    search(re) {
        debug(`Searching for services ${re}`);
        let result = [];
        for (let name of this._container.keys()) {
            if (re.test(name))
                result.push(name);
        }
        return result;
    }

    /**
     * Debug output
     * @param {...*} messages                           Messages
     */
    debug(...messages) {
        if (!(!!process.env.DEBUG))
            return Promise.resolve();

        return this._output(process.stderr, messages);
    }

    /**
     * Info output
     * @param {...*} messages                           Messages
     */
    info(...messages) {
        return this._output(process.stdout, messages);
    }

    /**
     * Error output
     * @param {...*} messages                           Messages
     */
    error(...messages) {
        return this._output(process.stderr, messages);
    }

    /**
     * Run the app. This method will simply call .init() and then .start().
     * @param {...*} args                               Descendant-specific arguments
     */
    run(...args) {
        this.init(...args)
            .then(() => {
                return this.start(...args);
            })
            .catch(error => {
                let logger;
                try {
                    logger = this.get('logger');
                    logger.error(new WError(error, 'App.run() failed'));
                } catch (ignore) {
                    logger = new AppLogger();
                    logger.error('App.run() failed:', error.message);
                }
                process.exit(1);
            });
    }

    /**
     * Initialize the app
     * @return {Promise}
     */
    init() {
        if (this._initialized)
            return Promise.resolve();

        debug('Initializing the app');
        let onExit = signal => {
            try {
                let logger = this.get('logger');
                if (!logger)
                    throw new Error('No logger');

                logger.info(`Terminating due to ${signal} signal`, () => { process.exit(0); });
                setTimeout(() => { process.exit(0); }, this.constructor.gracefulTimeout);
            } catch (error) {
                process.exit(0);
            }
        };
        process.on('SIGINT', () => { onExit('SIGINT'); });
        process.on('SIGTERM', () => { onExit('SIGTERM'); });
        process.on('SIGHUP', () => { /* ignore */ });

        return new Promise((resolve, reject) => {
                if (this._initialized === false)
                    return reject(new Error('Application is in process of initialization'));

                this._initialized = false;
                resolve();
            })
            .then(() => {
                return this._initConfig();
            })
            .then(() => {
                return this._initSources();
            })
            .then(() => {
                return this._initLogger();
            })
            .then(() => {
                return this._initModules();
            })
            .then(() => {
                this._initialized = true;
            });
    }

    /**
     * Start the app
     * @return {Promise}
     */
    start() {
        return new Promise((resolve, reject) => {
            if (this._running !== null)
                return reject(new Error('Application is already started'));

            this._running = false;
            resolve();
        });
    }

    /**
     * Load the configuration
     * @return {Promise}
     */
    _initConfig() {
        let config, modules = [];
        debug('Loading application configuration');
        return Promise.all([
                this.constructor._require(path.join(this.basePath, 'config', 'global.js')),
                this.constructor._require(path.join(this.basePath, 'config', 'local.js'), {}),
            ])
            .then(([globalConf, localConf]) => {
                if (typeof globalConf != 'object')
                    throw new Error('Global config is not an object');
                if (typeof localConf!= 'object')
                    throw new Error('Local config is not an object');

                config = merge.recursive(true, globalConf, localConf);
                config.base_path = this.basePath;
                config.get = function (key) {
                    return key.split('.').reduce((prev, cur) => {
                        if (!prev)
                            return prev;
                        return prev[cur];
                    }, this);
                };
                this.registerInstance(config, 'config');

                if (!config.autoload)
                    config.autoload = [];
                else if (!Array.isArray(config.autoload))
                    throw new Error('Config.autoload is not an array');

                if (!config.modules)
                    config.modules = [];
                else if (!Array.isArray(config.modules))
                    throw new Error('Config.modules is not an array');

                return config.modules.reduce(
                    (prev, cur) => {
                        return prev.then(() => {
                                debug(`Loading module ${cur} configuration`);
                                return Promise.all([
                                    this.constructor._require(
                                        path.join(this.basePath, 'modules', cur, 'config', 'global.js'),
                                        { autoload: [] }
                                    ),
                                    this.constructor._require(
                                        path.join(this.basePath, 'modules', cur, 'config', 'local.js'),
                                        {}
                                    )
                                ])
                                .then(([globalConf, localConf]) => {
                                    if (typeof globalConf != 'object')
                                        throw new Error(`Global config is not an object (module: ${cur})`);
                                    if (typeof localConf!= 'object')
                                        throw new Error(`Local config is not an object (module: ${cur})`);

                                    let moduleConfig = merge.recursive(true, globalConf, localConf);
                                    moduleConfig.name = cur;

                                    if (!moduleConfig.autoload)
                                        moduleConfig.autoload = [];
                                    else if (!Array.isArray(moduleConfig.autoload))
                                        throw new Error(`Config.autoload is not an array (module: ${cur})`);

                                    modules.push(moduleConfig);
                                });
                        });
                    },
                    Promise.resolve()
                );
            })
            .then(() => {
                config.modules = modules;
            });
    }

    /**
     * Load the source files
     * @return {Promise}
     */
    _initSources() {
        let config = this.get('config');
        let filer = new Filer();
        debug('Loading application sources');
        return config.autoload.reduce(
                (prev, cur) => {
                    return prev.then(() => {
                        let file = cur;
                        if (cur[0] == '!')
                            file = path.join(this.basePath, 'node_modules', 'arpen', cur.slice(1));
                        else if (cur[0] != '/')
                            file = path.join(this.basePath, cur);
                        return filer.process(
                            file,
                            filename => {
                                return this.constructor._require(filename)
                                    .then(obj => {
                                        if (!obj.provides)
                                            return;

                                        try {
                                            this.registerClass(obj);
                                        } catch (error) {
                                            throw new WError(error, `Registering ${filename}`);
                                        }
                                    });
                            }
                        );
                    });
                },
                Promise.resolve()
            )
            .then(() => {
                return config.modules.reduce(
                    (prevModule, curModule) => {
                        return prevModule.then(() => {
                            debug(`Loading module ${curModule.name} sources`);
                            return curModule.autoload.reduce(
                                (prevLoad, curLoad) => {
                                    return prevLoad.then(() => {
                                        let file = curLoad;
                                        if (curLoad[0] == '!')
                                            file = path.join(this.basePath, 'node_modules', 'arpen', curLoad.slice(1));
                                        else if (curLoad[0] != '/')
                                            file = path.join(this.basePath, 'modules', curModule.name, curLoad);
                                        return filer.process(
                                            file,
                                            filename => {
                                                return this.constructor._require(filename)
                                                    .then(obj => {
                                                        try {
                                                            this.registerClass(obj);
                                                        } catch (error) {
                                                            throw new WError(error, `Registering ${filename}`);
                                                        }
                                                    });
                                            }
                                        );
                                    });
                                },
                                Promise.resolve()
                            );
                        });
                    },
                    Promise.resolve()
                );
            });
    }

    /**
     * Create log streams
     * @return {Promise}
     */
    _initLogger() {
        let config, logger;
        return new Promise((resolve, reject) => {
                try {
                    config = this.get('config');
                    if (!config.logs)
                        return resolve();

                    logger = this.get('logger');
                    for (let log of Object.keys(config.logs)) {
                        let info = Object.assign({}, config.logs[log]);
                        let name = info.name;
                        delete info.name;
                        let level = info.level || 'info';
                        delete info.level;
                        let isDefault = info.default || false;
                        delete info.default;
                        logger.setLogStream(name, level, isDefault, info);
                    }
                    resolve();
                } catch (error) {
                    console.log(error);
                    reject(new WError(error, 'App._initLogger()'));
                }
            })
            .then(() => {
                let filer = this.get('filer');
                return filer.lockRead(path.join(config.base_path, 'package.json'));
            })
            .then(packageInfo => {
                let json;
                try {
                    json = JSON.parse(packageInfo);
                } catch (error) {
                    json = { name: 'program' };
                }
                logger.info(`Starting ${json.name}` + (json.version ? ' v' + json.version : ''));
            });
    }

    /**
     * Start modules
     * @return {Promise}
     */
    _initModules() {
        let modules = new Map();
        this.registerInstance(modules, 'modules');

        return this.search(/^modules\.[^.]+$/).reduce(
            (prev, cur) => {
                let _module = this.get(cur);
                modules.set(cur, _module);

                return prev.then(() => {
                    debug(`Bootstrapping module '${cur}'`);
                    let result = _module.bootstrap();
                    if (result === null || typeof result != 'object' || typeof result.then != 'function')
                        throw new Error(`Module '${cur}' bootstrap() did not return a Promise`);
                    return result;
                });
            },
            Promise.resolve()
        );
    }

    /**
     * Returns item of the service container, adding new one if it does not exist yet
     * @param {string} name                 Name of the service
     * @return {object}                     Returns service object
     */
    _initService(name) {
        if (name[name.length - 1] == '?')
            throw new Error(`Invalid service name: ${name}`);

        let service;
        if (this._container.has(name)) {
            service = this._container.get(name);
        } else {
            service = {};
            this._container.set(name, service);
        }
        return service;
    }

    /**
     * Resolve dependencies and return an instance of a service
     * @param {string} name                 Service name
     * @param {Array} extra                 Extra constructor arguments
     * @param {Map} request                 Resolved dependencies
     * @return {object}                     Returns instance of the service
     */
    _resolveService(name, extra, request) {
        let mustExist = true;
        if (name[name.length - 1] == '?') {
            name = name.slice(0, -1);
            mustExist = false;
        }

        if (!this._container.has(name)) {
            if (mustExist)
                throw new Error(`No service was found: ${name}`);
            return undefined;
        }

        let service = this._container.get(name);
        if (!service.class)
            return service.instance;

        let instance;
        if (request.has(name)) { // already resolved
            instance = request.get(name);
        } else {
            request.set(name, null); // mark as visited but not resolved yet
            switch (service.class.lifecycle || 'perRequest') {
                case 'perRequest':
                    instance = this._instantiateClass(service.class, extra, request);
                    request.set(name, instance);
                    break;
                case 'unique':
                    instance = this._instantiateClass(service.class, extra, request);
                    request.delete(name);
                    break;
                case 'singleton':
                    if (service.instance) {
                        instance = service.instance;
                    } else {
                        instance = this._instantiateClass(service.class, extra, request);
                        service.instance = instance;
                    }
                    request.set(name, instance);
                    break;
                default:
                    throw new Error(`Service '${name}' has invalid lifecycle: ${service.class.lifecycle}`);
            }
        }

        if (!instance)
            throw new Error(`Cyclic dependency while resolving '${name}'`);

        return instance;
    }

    /**
     * Instantiate given service class
     * @param {function} classFunc          Class function
     * @param {Array} extra                 Extra constructor arguments
     * @param {Map} request                 Resolved dependencies
     * @return {object}                     Returns instance of the class
     */
    _instantiateClass(classFunc, extra, request) {
        let args = [];
        for (let arg of classFunc.requires || [])
            args.push(this._resolveService(arg, [], request));
        args = args.concat(extra);
        return new classFunc(...args);
    }

    /**
     * Print output
     * @param {*} stream                    Stream for output
     * @param {Array} messages              Messages
     */
    _output(stream, messages) {
        return new Promise((resolve, reject) => {
            let output = messages.join(' ');
            if (!output.length)
                return resolve();

            let onError = error => {
                reject(error);
            };

            stream.once('error', onError);
            stream.write(output, () => {
                stream.removeListener('error', onError);
                resolve();
            })
        });
    }

    /**
     * Load js file
     * @param {string} filename             Path of the file
     * @param {*} [defaultObject]           If specified this will be returned if file could not be loaded
     * @return {Promise}                    Resolves to the exported object
     */
    static _require(filename, defaultObject) {
        return new Promise((resolve, reject) => {
                try {
                    resolve(require(filename));
                } catch (err) {
                    if (typeof defaultObject == 'undefined')
                        reject(new WError(err, `Could not load ${filename}`));
                    else
                        resolve(defaultObject);
                }
            });
    }
}

module.exports = App;<|endoftext|>


<commit_before>var kue = require('kue'),
    redis = require('redis'),
    url = require('url'),
    config = require('../config'),
    lynx = require('lynx');

var statsDClient = null;

module.exports = {
    setRedisServer: function() {
        var port = config.BootstrapHtml.redis_port || process.env.REDISTOGO_URL || 6379,
            host = config.BootstrapHtml.redis_host;

        kue.redis.createClient = function() {
            var client = redis.createClient(port, host);
            console.log('Redis client created at', host, 'port', port)
            return client;
        };
    },

    getStatsClient: function() {
        if (statsDClient) {
            return statsDClient;
        }

        var host = config.BootstrapHtml.statsd_host.split('//')[1].split(':');
        var serverUrl = host[0];
        var serverPort = host[1];

        var scope = ['stats', config.environment.type, 'bshtml'].join('.');
        statsDClient = new lynx(serverUrl, serverPort, {
            scope: scope
        });
        console.log('StatsD client created at', serverUrl, serverPort);
        return statsDClient;
    }
};
<commit_msg>Remove 'stats' prefix from scope in lynx<commit_after>var kue = require('kue'),
    redis = require('redis'),
    url = require('url'),
    config = require('../config'),
    lynx = require('lynx');

var statsDClient = null;

module.exports = {
    setRedisServer: function() {
        var port = config.BootstrapHtml.redis_port || process.env.REDISTOGO_URL || 6379,
            host = config.BootstrapHtml.redis_host;

        kue.redis.createClient = function() {
            var client = redis.createClient(port, host);
            console.log('Redis client created at', host, 'port', port)
            return client;
        };
    },

    getStatsClient: function() {
        if (statsDClient) {
            return statsDClient;
        }

        var host = config.BootstrapHtml.statsd_host.split('//')[1].split(':');
        var serverUrl = host[0];
        var serverPort = host[1];

        var scope = [config.environment.type, 'bshtml'].join('.');
        statsDClient = new lynx(serverUrl, serverPort, {
            scope: scope
        });
        console.log('StatsD client created at', serverUrl, serverPort);
        return statsDClient;
    }
};
<|endoftext|>


<commit_before>// Wrapper for the THREE.js library

/*
	Template originally taken from Three.js "tutorials by example" by Lee Stemkoski,
  though it has been though many changes now.
 */

(function () {

  X = {}

  // library-global
  var keyboard = X.keyboard = new KeyboardState();
  var clock = X.clock = new THREE.Clock();
  X.fps = null;

  X.init = function () {

    var gui = X.gui = new GUI();

  	// SCENE
  	var scene = X.scene = new THREE.Scene();

  	// CAMERA
  	var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
  	var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;

  	camera = X.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
  	scene.add(camera);
  	camera.position.set(0,150,400);
  	camera.lookAt(scene.position);

  	if ( Detector.webgl )
  		renderer = X.renderer = new THREE.WebGLRenderer( {antialias:false, alpha: true } );
  	else
  		renderer = X.renderer = new THREE.CanvasRenderer();
  	renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
  	container = document.getElementById( 'ThreeJS' );
  	container.appendChild( renderer.domElement );
    // EVENTS
    THREEx.WindowResize(renderer, camera);
  //  THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
  	// CONTROLS
  	controls = new THREE.OrbitControls( camera, renderer.domElement );
  	// STATS

  	stats = new Stats();
  	stats.domElement.style.position = 'absolute';
  	stats.domElement.style.bottom = '0px';
  	stats.domElement.style.zIndex = 100;
  	container.appendChild( stats.domElement );

    X.main()
    // The controller

    X.gui.folder("Camera",function() {
      this.add(X, 'fps', { Slow: 1, Slower: 10, "Full Speed": null } );
      this.add(camera, 'fov').listen().onChange(function(value) {
        camera.updateProjectionMatrix()
      })
      this.folder('position',function() {
        this.add(camera.position, 'x').listen();
        this.add(camera.position, 'y').listen();
        this.add(camera.position, 'z').listen();
      })
      return true;
    })

  }

  X.animate = function ()
  {
    if (X.fps == null) {
      requestAnimationFrame( X.animate );
    } else {
      setTimeout(function () { requestAnimationFrame( X.animate ) },1000 / X.fps)
    }
  	X.render();
  	X.update();
  }

  X.render = function ()
  {
  	X.renderer.render( X.scene, X.camera );
  }

  X.update = function()
  {
//    console.log("X.update")
    X.keyboard.update()

  	if ( X.keyboard.pressed("Z") )
  	{
      console.log("z pressed")
  		// do something
  	}

  	controls.update();
  	stats.update();
  }

  // Should be called
  var surfaceCache = {};

  // Public function: adds a cardboard 'card' to the world
  X.card = function (args) {
      //    console.log(args,surfaceCache)
    var src = args.src || "";
    if (surfaceCache[src] || false) {
      var floorMaterial = surfaceCache[src];
    } else {
    	var floorTexture = new THREE.ImageUtils.loadTexture( src );
    	var floorMaterial = new THREE.MeshBasicMaterial( {
		        side: THREE.DoubleSide /* both sides of this mesh are drawn */
      });
      floorMaterial.transparent = true;
      floorMaterial.depthWrite = false // Artifacts also disappear when seting depthTest to false
      floorMaterial.map = floorTexture
      floorMaterial.needsUpdate = true // This is needed
	    surfaceCache[src] = floorMaterial;
    }
    var size   = args.size   || new THREE.Vector2(100,100)
    var anchor = args.anchor || new THREE.Vector2(size.x * 0.5, size.y * 0.5)

    // We always create an anchor, and fasten our surface to this anchor.
    var center = new THREE.Object3D();
    var floorGeometry = new THREE.PlaneGeometry(size.x,size.y);
    var floor = new THREE.Mesh(floorGeometry, floorMaterial);

    console.log("anchor size",anchor,size)

    console.log((0.5 * size.x) - anchor.x ,- (0.5 * size.y) + anchor.y,0);
    floor.position.set((0.5 * size.x) - anchor.x ,-(0.5 * size.y) + anchor.y,0);
    center.add(floor);

    var sphere = new THREE.SphereGeometry( 5, 4, 4 );
    var material = new THREE.MeshBasicMaterial( { color: 0x000000} );
    mesh = new THREE.Mesh( sphere, material );
    center.add(mesh);

    center.card = floor
    return center;
  }

  // To override with building the scene.
  X.main      = function () {}
  X.animation = function () {}

})();
<commit_msg>Fixing to work with updated THREE library.<commit_after>// Wrapper for the THREE.js library

/*
	Template originally taken from Three.js "tutorials by example" by Lee Stemkoski,
  though it has been though many changes now.
 */

(function () {

  X = {}

  // library-global
  var keyboard = X.keyboard = new KeyboardState();
  var clock = X.clock = new THREE.Clock();
  X.fps = null;

  X.init = function () {

    var gui = X.gui = new GUI();

  	// SCENE
  	var scene = X.scene = new THREE.Scene();

  	// CAMERA
  	var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
  	var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;

  	camera = X.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
  	scene.add(camera);
  	camera.position.set(0,150,400);
  	camera.lookAt(scene.position);

  	if ( Detector.webgl )
  		renderer = X.renderer = new THREE.WebGLRenderer( {antialias:true, alpha: true } );
  	else
  		renderer = X.renderer = new THREE.CanvasRenderer();
  	renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
  	container = document.getElementById( 'ThreeJS' );
  	container.appendChild( renderer.domElement );
    // EVENTS
    THREEx.WindowResize(renderer, camera);
  //  THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
  	// CONTROLS
  	controls = new THREE.OrbitControls( camera, renderer.domElement );
  	// STATS

  	stats = new Stats();
  	stats.domElement.style.position = 'absolute';
  	stats.domElement.style.bottom = '0px';
  	stats.domElement.style.zIndex = 100;
  	container.appendChild( stats.domElement );

    X.main()
    // The controller

    X.gui.folder("Camera",function() {
      this.add(X, 'fps', { Slow: 1, Slower: 10, "Full Speed": null } );
      this.add(camera, 'fov').listen().onChange(function(value) {
        camera.updateProjectionMatrix()
      })
      this.folder('position',function() {
        this.add(camera.position, 'x').listen();
        this.add(camera.position, 'y').listen();
        this.add(camera.position, 'z').listen();
      })
      return true;
    })

  }

  X.animate = function ()
  {
    if (X.fps == null) {
      requestAnimationFrame( X.animate );
    } else {
      setTimeout(function () { requestAnimationFrame( X.animate ) },1000 / X.fps)
    }
  	X.render();
  	X.update();
  }

  X.render = function ()
  {
  	X.renderer.render( X.scene, X.camera );
  }

  X.update = function()
  {
//    console.log("X.update")
    X.keyboard.update()

  	if ( X.keyboard.pressed("Z") )
  	{
      console.log("z pressed")
  		// do something
  	}

  	controls.update();
  	stats.update();
  }

  // Should be called
  var surfaceCache = {};

  // Public function: adds a cardboard 'card' to the world
  X.card = function (args) {
      //    console.log(args,surfaceCache)
    var src = args.src || "";
    var size   = args.size   || new THREE.Vector2(100,100)
    var anchor = args.anchor || new THREE.Vector2(size.x * 0.5, size.y * 0.5)
    if (surfaceCache[src] || false) {
      var floorMaterial = surfaceCache[src];
    } else {
    	var floorTexture = new THREE.ImageUtils.loadTexture( src );
      // This is needed for non-POT images
      floorTexture.minFilter = THREE.LinearFilter
    	var floorMaterial = new THREE.MeshBasicMaterial( {
		        side: THREE.DoubleSide /* both sides of this mesh are drawn */
      });
      floorMaterial.transparent = true;
      floorMaterial.depthWrite = false // Artifacts also disappear when seting depthTest to false
      floorMaterial.map = floorTexture
      floorMaterial.needsUpdate = true // This is needed
	    surfaceCache[src] = floorMaterial;
    }

    // We always create an anchor, and fasten our surface to this anchor.
    var center = new THREE.Object3D();
    var floorGeometry = new THREE.PlaneGeometry(size.x,size.y);
    var floor = new THREE.Mesh(floorGeometry, floorMaterial);

    console.log("anchor size",anchor,size)

    console.log((0.5 * size.x) - anchor.x ,- (0.5 * size.y) + anchor.y,0);
    floor.position.set((0.5 * size.x) - anchor.x ,-(0.5 * size.y) + anchor.y,0);
    center.add(floor);

    var sphere = new THREE.SphereGeometry( 5, 4, 4 );
    var material = new THREE.MeshBasicMaterial( { color: 0x000000} );
    mesh = new THREE.Mesh( sphere, material );
    center.add(mesh);

    center.card = floor
    return center;
  }

  // To override with building the scene.
  X.main      = function () {}
  X.animation = function () {}

})();
<|endoftext|>