<commit_before>var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');
var through = require('through');
var resumer = require('resumer');
var inspect = require('object-inspect');
var bind = require('function-bind');
var has = require('has');
var regexpTest = bind.call(Function.call, RegExp.prototype.test);
var yamlIndicators = /\:|\-|\?/;
var nextTick = typeof setImmediate !== 'undefined'
    ? setImmediate
    : process.nextTick
;

module.exports = Results;
inherits(Results, EventEmitter);

function Results () {
    if (!(this instanceof Results)) return new Results;
    this.count = 0;
    this.fail = 0;
    this.pass = 0;
    this._stream = through();
    this.tests = [];
    this._only = 0;
    this._nextIndex = 0;
}

Results.prototype.createStream = function (opts) {
    if (!opts) opts = {};
    var self = this;
    var output, testId = 0;
    if (opts.objectMode) {
        output = through();
        self.on('_push', function ontest (t, extra) {
            if (!extra) extra = {};
            var id = testId++;
            t.once('prerun', function () {
                var row = {
                    type: 'test',
                    name: t.name,
                    id: id
                };
                if (has(extra, 'parent')) {
                    row.parent = extra.parent;
                }
                output.queue(row);
            });
            t.on('test', function (st) {
                ontest(st, { parent: id });
            });
            t.on('result', function (res) {
                res.test = id;
                res.type = 'assert';
                output.queue(res);
            });
            t.on('end', function () {
                output.queue({ type: 'end', test: id });
            });
        });
        self.on('done', function () { output.queue(null) });
    }
    else {
        output = resumer();
        output.queue('TAP version 13\n');
        self._stream.pipe(output);
    }

    nextTick(function next() {
        var t;
        while (t = getNextScheduledTest(self)) {
            t.run();
            if (!t.ended) return t.once('end', function(){ nextTick(next); });
        }
        self.emit('done');
    });

    return output;
};

var onlyTestNumber = false; // TBD: temporary
var numbered = false;
Results.prototype.setNumbering = function (testNumber) { // TBD: temporary
    numbered = true;
    if (typeof testNumber === "number") {
        onlyTestNumber = testNumber;
    }
}

var nextTestNumber = 0; // TBD: temporary
Results.prototype.onPreTest = function (title, unscheduled) {
    if (onlyTestNumber !== false && nextTestNumber === 0) { // first run only
        if (onlyTestNumber === 0 || onlyTestNumber > this.tests.length) {
            exitWithError("test "+ onlyTestNumber +" not found");
        }
    }
    ++ nextTestNumber;
    if (numbered) {
        title = '['+ nextTestNumber +'] '+ title;
        if (onlyTestNumber) {
            if (nextTestNumber !== onlyTestNumber)
                title = null;
            else if (unscheduled)
                exitWithError("test "+ onlyTestNumber +" not scheduled to run");
        }
    }
    return title;
};

function exitWithError(message) { // TBD: temporary
    // should only call this method prior to running any tests
    console.log("*** %s ***\n", message);
    process.exit(1);
}

Results.prototype.push = function (t) {
    var self = this;
    self.tests.push(t);
    self._watch(t);
    self.emit('_push', t);
};

Results.prototype.only = function (t) {
    this._only = t;
};

Results.prototype._watch = function (t) {
    var self = this;
    var write = function (s) { self._stream.queue(s) };
    t.once('prerun', function () {
        write('# ' + t.name + '\n');
    });

    t.on('result', function (res) {
        if (typeof res === 'string') {
            write('# ' + res + '\n');
            return;
        }
        write(encodeResult(res, self.count + 1));
        self.count ++;

        if (res.ok) self.pass ++
        else self.fail ++
    });

    t.on('test', function (st) { self._watch(st) });
};

Results.prototype.close = function () {
    var self = this;
    if (self.closed) self._stream.emit('error', new Error('ALREADY CLOSED'));
    self.closed = true;
    var write = function (s) { self._stream.queue(s) };

    write('\n1..' + self.count + '\n');
    write('# tests ' + self.count + '\n');
    write('# pass  ' + self.pass + '\n');
    if (self.fail) write('# fail  ' + self.fail + '\n')
    else write('\n# ok\n')

    self._stream.queue(null);
};

function encodeResult (res, count) {
    var output = '';
    output += (res.ok ? 'ok ' : 'not ok ') + count;
    output += res.name ? ' ' + res.name.toString().replace(/\s+/g, ' ') : '';

    if (res.skip) output += ' # SKIP';
    else if (res.todo) output += ' # TODO';

    output += '\n';
    if (res.ok) return output;

    var outer = '  ';
    var inner = outer + '  ';
    output += outer + '---\n';
    output += inner + 'operator: ' + res.operator + '\n';

    if (has(res, 'expected') || has(res, 'actual')) {
        var ex = inspect(res.expected, {depth: res.objectPrintDepth});
        var ac = inspect(res.actual, {depth: res.objectPrintDepth});

        if (Math.max(ex.length, ac.length) > 65 || invalidYaml(ex) || invalidYaml(ac)) {
            output += inner + 'expected: |-\n' + inner + '  ' + ex + '\n';
            output += inner + 'actual: |-\n' + inner + '  ' + ac + '\n';
        }
        else {
            output += inner + 'expected: ' + ex + '\n';
            output += inner + 'actual:   ' + ac + '\n';
        }
    }
    if (res.at) {
        output += inner + 'at: ' + res.at + '\n';
    }
    if (res.operator === 'error' && res.actual && res.actual.stack) {
        var lines = String(res.actual.stack).split('\n');
        output += inner + 'stack: |-\n';
        for (var i = 0; i < lines.length; i++) {
            output += inner + '  ' + lines[i] + '\n';
        }
    }

    output += outer + '...\n';
    return output;
}

function getNextScheduledTest (results) {
    var t = getNextTest(results);
    var scheduled = false;

    while (t && !scheduled) {
        if (results._only) {
            scheduled = (t === results._only);
        }
        else {
            scheduled = (!!t._cb);
        }
        var name = results.onPreTest(t.name, !scheduled);
        if (name !== null) {
            t.name = name;
        }
        else {
            scheduled = false;
        }
        if (!scheduled) {
            // prevent t._end() from being called on tests not run
            results.tests.splice(-- results._nextIndex, 1);
            t = getNextTest(results);
        }
    }
    return t;
}

function getNextTest (results) {
    if (results._nextIndex >= results.tests.length) {
        return null;
    }
    return results.tests[results._nextIndex ++];
}

function invalidYaml (str) {
    return regexpTest(yamlIndicators, str);
}
<commit_msg>inited results._only to null<commit_after>var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');
var through = require('through');
var resumer = require('resumer');
var inspect = require('object-inspect');
var bind = require('function-bind');
var has = require('has');
var regexpTest = bind.call(Function.call, RegExp.prototype.test);
var yamlIndicators = /\:|\-|\?/;
var nextTick = typeof setImmediate !== 'undefined'
    ? setImmediate
    : process.nextTick
;

module.exports = Results;
inherits(Results, EventEmitter);

function Results () {
    if (!(this instanceof Results)) return new Results;
    this.count = 0;
    this.fail = 0;
    this.pass = 0;
    this._stream = through();
    this.tests = [];
    this._only = null;
    this._nextIndex = 0;
}

Results.prototype.createStream = function (opts) {
    if (!opts) opts = {};
    var self = this;
    var output, testId = 0;
    if (opts.objectMode) {
        output = through();
        self.on('_push', function ontest (t, extra) {
            if (!extra) extra = {};
            var id = testId++;
            t.once('prerun', function () {
                var row = {
                    type: 'test',
                    name: t.name,
                    id: id
                };
                if (has(extra, 'parent')) {
                    row.parent = extra.parent;
                }
                output.queue(row);
            });
            t.on('test', function (st) {
                ontest(st, { parent: id });
            });
            t.on('result', function (res) {
                res.test = id;
                res.type = 'assert';
                output.queue(res);
            });
            t.on('end', function () {
                output.queue({ type: 'end', test: id });
            });
        });
        self.on('done', function () { output.queue(null) });
    }
    else {
        output = resumer();
        output.queue('TAP version 13\n');
        self._stream.pipe(output);
    }

    nextTick(function next() {
        var t;
        while (t = getNextScheduledTest(self)) {
            t.run();
            if (!t.ended) return t.once('end', function(){ nextTick(next); });
        }
        self.emit('done');
    });

    return output;
};

var onlyTestNumber = false; // TBD: temporary
var numbered = false;
Results.prototype.setNumbering = function (testNumber) { // TBD: temporary
    numbered = true;
    if (typeof testNumber === "number") {
        onlyTestNumber = testNumber;
    }
}

var nextTestNumber = 0; // TBD: temporary
Results.prototype.onPreTest = function (title, unscheduled) {
    if (onlyTestNumber !== false && nextTestNumber === 0) { // first run only
        if (onlyTestNumber === 0 || onlyTestNumber > this.tests.length) {
            exitWithError("test "+ onlyTestNumber +" not found");
        }
    }
    ++ nextTestNumber;
    if (numbered) {
        title = '['+ nextTestNumber +'] '+ title;
        if (onlyTestNumber) {
            if (nextTestNumber !== onlyTestNumber)
                title = null;
            else if (unscheduled)
                exitWithError("test "+ onlyTestNumber +" not scheduled to run");
        }
    }
    return title;
};

function exitWithError(message) { // TBD: temporary
    // should only call this method prior to running any tests
    console.log("*** %s ***\n", message);
    process.exit(1);
}

Results.prototype.push = function (t) {
    var self = this;
    self.tests.push(t);
    self._watch(t);
    self.emit('_push', t);
};

Results.prototype.only = function (t) {
    this._only = t;
};

Results.prototype._watch = function (t) {
    var self = this;
    var write = function (s) { self._stream.queue(s) };
    t.once('prerun', function () {
        write('# ' + t.name + '\n');
    });

    t.on('result', function (res) {
        if (typeof res === 'string') {
            write('# ' + res + '\n');
            return;
        }
        write(encodeResult(res, self.count + 1));
        self.count ++;

        if (res.ok) self.pass ++
        else self.fail ++
    });

    t.on('test', function (st) { self._watch(st) });
};

Results.prototype.close = function () {
    var self = this;
    if (self.closed) self._stream.emit('error', new Error('ALREADY CLOSED'));
    self.closed = true;
    var write = function (s) { self._stream.queue(s) };

    write('\n1..' + self.count + '\n');
    write('# tests ' + self.count + '\n');
    write('# pass  ' + self.pass + '\n');
    if (self.fail) write('# fail  ' + self.fail + '\n')
    else write('\n# ok\n')

    self._stream.queue(null);
};

function encodeResult (res, count) {
    var output = '';
    output += (res.ok ? 'ok ' : 'not ok ') + count;
    output += res.name ? ' ' + res.name.toString().replace(/\s+/g, ' ') : '';

    if (res.skip) output += ' # SKIP';
    else if (res.todo) output += ' # TODO';

    output += '\n';
    if (res.ok) return output;

    var outer = '  ';
    var inner = outer + '  ';
    output += outer + '---\n';
    output += inner + 'operator: ' + res.operator + '\n';

    if (has(res, 'expected') || has(res, 'actual')) {
        var ex = inspect(res.expected, {depth: res.objectPrintDepth});
        var ac = inspect(res.actual, {depth: res.objectPrintDepth});

        if (Math.max(ex.length, ac.length) > 65 || invalidYaml(ex) || invalidYaml(ac)) {
            output += inner + 'expected: |-\n' + inner + '  ' + ex + '\n';
            output += inner + 'actual: |-\n' + inner + '  ' + ac + '\n';
        }
        else {
            output += inner + 'expected: ' + ex + '\n';
            output += inner + 'actual:   ' + ac + '\n';
        }
    }
    if (res.at) {
        output += inner + 'at: ' + res.at + '\n';
    }
    if (res.operator === 'error' && res.actual && res.actual.stack) {
        var lines = String(res.actual.stack).split('\n');
        output += inner + 'stack: |-\n';
        for (var i = 0; i < lines.length; i++) {
            output += inner + '  ' + lines[i] + '\n';
        }
    }

    output += outer + '...\n';
    return output;
}

function getNextScheduledTest (results) {
    var t = getNextTest(results);
    var scheduled = false;

    while (t && !scheduled) {
        if (results._only) {
            scheduled = (t === results._only);
        }
        else {
            scheduled = (!!t._cb);
        }
        var name = results.onPreTest(t.name, !scheduled);
        if (name !== null) {
            t.name = name;
        }
        else {
            scheduled = false;
        }
        if (!scheduled) {
            // prevent t._end() from being called on tests not run
            results.tests.splice(-- results._nextIndex, 1);
            t = getNextTest(results);
        }
    }
    return t;
}

function getNextTest (results) {
    if (results._nextIndex >= results.tests.length) {
        return null;
    }
    return results.tests[results._nextIndex ++];
}

function invalidYaml (str) {
    return regexpTest(yamlIndicators, str);
}
<|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 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')

    };
  }()) );

<commit_msg>[Fixes #132836311] Slider should ignore commas when interpreting number typed as value. (Or it should not display commas in values.) We elect not to display commas in slider values. This eliminates or greatly reduces the possibility that users will have sliders in their numeric values.<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().group('').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>(function () {
    'use strict';

    angular
        .module('app.core', [
            'ngMaterial',
            'ui.router',
            'firebase'
        ]);

})();
<commit_msg>Removed firebase dependency from app.core.<commit_after>(function () {
    'use strict';

    angular
        .module('app.core', [
            'ngMaterial',
            'ui.router'
        ]);

})();
<|endoftext|>


<commit_before>const _ = require('lodash/fp')
const Pdf417Parser = require('./compliance/parsepdf417')
const { utils: coinUtils } = require('@lamassu/coins')
const v4l2camera = require('v4l2camera')
const jpg = require('jpeg-turbo')
const manatee = require('manatee')
const supyo = require('@lamassu/supyo')
const jsQR = require('jsqr')

const selectedCamResolutions = {}

let configuration = null
let cancelFlag = false
let opened = false
let processing = false
let closing = false
let openedFromOutside = false
let openSettings = null

module.exports = {
  config,
  prepareForCapture,
  scanPairingCode,
  scanMainQR,
  scanPDF417,
  scanPhotoCard,
  takeFacephoto,
  cancel,
  isOpened,
  scanPK,
  hasCamera,
  takeFacePhotoTC
}

const maxCamResolutions = [
  {
    width: 2592,
    height: 1944
  }
]

const minCamResolutions = [
  {
    width: 1280,
    height: 1024
  },
  {
    width: 1280,
    height: 960
  },
  {
    width: 1280,
    height: 720
  },
  {
    width: 640,
    height: 480
  }
]

const maxCamResolutionQRCode = [
  {
    width: 640,
    height: 480
  }
]

const maxCamResolutionPhotoId = [
  {
    width: 1280,
    height: 720
  }
]

function setConfig (cam, mode) {
  const isQRCodeMode = mode === 'qr'
  const isPhotoIdMode = mode === 'photoId'

  var format = null
  const cachedRes = selectedCamResolutions[mode]
  if (!_.isNil(cachedRes)) return cachedRes

  const pixelRes = format => format.width * format.height
  const sortByPixelRes = _.orderBy(pixelRes, ['desc'])

  const isSuitableRes = res => {
    const currentRes = pixelRes(res)

    const gteCurrent = _.gte(currentRes)
    const lteCurrent = _.lte(currentRes)

    const isAboveMinAcceptableResolutions = _.compose(_.some(_.identity), _.map(gteCurrent), _.map(pixelRes))
    const isUnderMaxAcceptableResolutions = _.compose(_.some(_.identity), _.map(lteCurrent), _.map(pixelRes))

    return isUnderMaxAcceptableResolutions(isQRCodeMode ? maxCamResolutionQRCode : isPhotoIdMode ? maxCamResolutionPhotoId : maxCamResolutions) &&
     isAboveMinAcceptableResolutions(minCamResolutions)
  }

  const availableFormats = sortByPixelRes(cam.formats.filter(f => f.formatName === 'MJPG'))

  format = _.find(isSuitableRes, availableFormats)

  if (!format) throw new Error('Unsupported cam resolution!')

  selectedCamResolutions[mode] = format

  return format
}

function config (_configuration) {
  configuration = _configuration

  const licenses = _.get('scanner.manatee.license', configuration)
  manatee.register('qr', _.get('qr.name', licenses), _.get('qr.key', licenses))
  manatee.register('pdf417', _.get('pdf417.name', licenses), _.get('pdf417.key', licenses))
}

function cancel () {
  cancelFlag = true
}

function isOpened () {
  return opened
}

function hasCamera (mode) {
  const cameraConf = mode === 'facephoto' ? 'frontFacingCamera' : 'scanner'

  const device = _.get(`${cameraConf}.device`, configuration)

  if (!device) return false

  console.log('Camera device available: ' + device)
  try {
    new v4l2camera.Camera(device)
    return true
  } catch (err) {
    return false
  }
}
// resultCallback returns final scan result
// captureCallback returns result of a frame capture
function scan (mode, resultCallback, captureCallback) {
  if (!openedFromOutside && opened) {
    console.log("Camera is already open. Shouldn't happen.")
    return resultCallback(new Error('Camera open'))
  }

  const {
    cam,
    modeConfig,
    width,
    height
  } = _prepareForCapture(mode)

  var handle = setInterval(capture, 100)

  function capture () {
    if (cancelFlag) {
      if (opened && !closing && !processing) {
        closing = true
        clearInterval(handle)
        cam.stop(() => {
          processing = false
          opened = false
          closing = false
          openedFromOutside = false
          openSettings = null
          return resultCallback()
        })
      }

      return
    }

    if (processing) return
    processing = true

    cam.capture(function (success) {
      if (!success) {
        processing = false
        return
      }

      var frame = Buffer.from(cam.frameRaw())
      let greyscale = null

      try {
        greyscale = jpg.decompressSync(frame, { format: jpg.FORMAT_GRAY })
      } catch (err) {
        processing = false
        return
      }

      captureCallback(modeConfig, width, height, frame, greyscale.data, function (err, result) {
        if (!err && !result && !cancelFlag) {
          processing = false
          openedFromOutside = false
          openSettings = null
          return
        }

        clearInterval(handle)
        cam.stop(() => {
          processing = false
          opened = false
          openedFromOutside = false
          openSettings = null
          return resultCallback(err, result)
        })
      })
    })
  }
}

function scanQR (callback) {
  scan('qr', callback, function (modeConfig, width, height, frame, greyscale, _callback) {
    const rgba8 = jpg.decompressSync(frame, { format: jpg.FORMAT_RGBA8 })
    const r = jsQR(rgba8.data, rgba8.width, rgba8.height, { inversionAttempts: 'dontInvert' })
    if (!r) return _callback()
    _callback(null, r.data)
  })
}

function scanPDF417 (callback, idCardStillsCallback) {
  const photosTaken = {
    1: true,
    2: true,
    3: true,
    4: true,
    5: true
  }
  const timerInit = new Date().getTime()

  scan('photoId', callback, function (modeConfig, width, height, frame, greyscale, _callback) {

    var timeChecker = new Date().getTime()
    let secondsPassed = Math.floor((timeChecker - timerInit) / 1000)
    var result = manatee.scanPDF417(greyscale, width, height)
    if (!result) {
      if (photosTaken[secondsPassed]) {
        photosTaken[secondsPassed] = false
        idCardStillsCallback(frame)
      }
      return _callback(null, null)
    }
    var parsed = Pdf417Parser.parse(result)
    if (!parsed) {
      if (photosTaken[secondsPassed]) {
        photosTaken[secondsPassed] = false
        idCardStillsCallback(frame)
      }
      return _callback(null, null)
    }
    parsed.raw = result.toString()
    _callback(null, parsed)
  })
}

function scanPhoto (callback) {
  scan('photoId', callback, function (modeConfig, width, height, frame, greyscale, _callback) {
    const detected = supyo.detect(greyscale, width, height, {
      minSize: modeConfig.minFaceSize || 100,
      qualityThreshold: modeConfig.threshold || 20,
      verbose: false
    })

    if (!detected) return _callback(null, null)
    _callback(null, frame)
  })
}

function scanFacephoto (callback) {
  scan('facephoto', callback, function (modeConfig, width, height, frame, greyscale, _callback) {
    const detected = supyo.detect(greyscale, width, height, {
      minSize: modeConfig.minFaceSize || 100,
      qualityThreshold: modeConfig.threshold || 20,
      verbose: false
    })

    if (!detected) return _callback(null, null)
    _callback(null, frame)
  })
}

function scanFacephotoTC (callback) {
  scan('facephoto', callback, function (modeConfig, width, height, frame, greyscale, _callback) {
    _callback(null, frame)
  })
}

function scanPairingCode (callback) {
  scanQR((err, res) => {
    if (err) return callback(err)
    if (!res) return callback()
    return callback(null, res.toString())
  })
}

function scanMainQR (cryptoCode, callback) {
  scanQR(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    var resultStr = result.toString()
    console.log('DEBUG55: %s', resultStr)

    const network = 'main'
    try {
      callback(null, coinUtils.parseUrl(cryptoCode, network, resultStr))
    } catch (error) {
      callback(error)
    }
  })
}

function scanPK (callback) {
  scanQR(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    callback(null, result.toString())
  })
}

function scanPhotoCard (callback) {
  scanPhoto(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    callback(null, result)
  })
}

function takeFacephoto (callback) {
  scanFacephoto(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    callback(null, result)
  })
}

function takeFacePhotoTC (callback) {
  scanFacephotoTC(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    callback(null, result)
  })
}

function _prepareForCapture (mode) {
  if (opened) return openSettings
  // Pick correct camera
  const cameraConf = mode === 'facephoto' ? 'frontFacingCamera' : 'scanner'

  const device = _.get([cameraConf, 'device'], configuration)
  const modeConfig = _.get([cameraConf, mode], configuration)

  const cam = new v4l2camera.Camera(device)

  cancelFlag = false

  const format = setConfig(cam, mode)

  cam.configSet(format)

  console.log('Opening v4l2camera device: ' + device + ' with mode: ' + mode, format)

  const width = format.width
  const height = format.height

  cam.start()

  opened = true
  openSettings = {
    cam,
    modeConfig,
    width,
    height
  }
  return openSettings
}

function prepareForCapture (mode) {
  openedFromOutside = true
  _prepareForCapture(mode)
}
<commit_msg>fix: increase photo ID camera resolution<commit_after>const _ = require('lodash/fp')
const Pdf417Parser = require('./compliance/parsepdf417')
const { utils: coinUtils } = require('@lamassu/coins')
const v4l2camera = require('v4l2camera')
const jpg = require('jpeg-turbo')
const manatee = require('manatee')
const supyo = require('@lamassu/supyo')
const jsQR = require('jsqr')

const selectedCamResolutions = {}

let configuration = null
let cancelFlag = false
let opened = false
let processing = false
let closing = false
let openedFromOutside = false
let openSettings = null

module.exports = {
  config,
  prepareForCapture,
  scanPairingCode,
  scanMainQR,
  scanPDF417,
  scanPhotoCard,
  takeFacephoto,
  cancel,
  isOpened,
  scanPK,
  hasCamera,
  takeFacePhotoTC
}

const maxCamResolutions = [
  {
    width: 2592,
    height: 1944
  }
]

const minCamResolutions = [
  {
    width: 1280,
    height: 1024
  },
  {
    width: 1280,
    height: 960
  },
  {
    width: 1280,
    height: 720
  },
  {
    width: 640,
    height: 480
  }
]

const maxCamResolutionQRCode = [
  {
    width: 640,
    height: 480
  }
]

const maxCamResolutionPhotoId = [
  {
    width: 1280,
    height: 1024
  }
]

function setConfig (cam, mode) {
  const isQRCodeMode = mode === 'qr'
  const isPhotoIdMode = mode === 'photoId'

  var format = null
  const cachedRes = selectedCamResolutions[mode]
  if (!_.isNil(cachedRes)) return cachedRes

  const pixelRes = format => format.width * format.height
  const sortByPixelRes = _.orderBy(pixelRes, ['desc'])

  const isSuitableRes = res => {
    const currentRes = pixelRes(res)

    const gteCurrent = _.gte(currentRes)
    const lteCurrent = _.lte(currentRes)

    const isAboveMinAcceptableResolutions = _.compose(_.some(_.identity), _.map(gteCurrent), _.map(pixelRes))
    const isUnderMaxAcceptableResolutions = _.compose(_.some(_.identity), _.map(lteCurrent), _.map(pixelRes))

    return isUnderMaxAcceptableResolutions(isQRCodeMode ? maxCamResolutionQRCode : isPhotoIdMode ? maxCamResolutionPhotoId : maxCamResolutions) &&
     isAboveMinAcceptableResolutions(minCamResolutions)
  }

  const availableFormats = sortByPixelRes(cam.formats.filter(f => f.formatName === 'MJPG'))

  format = _.find(isSuitableRes, availableFormats)

  if (!format) throw new Error('Unsupported cam resolution!')

  selectedCamResolutions[mode] = format

  return format
}

function config (_configuration) {
  configuration = _configuration

  const licenses = _.get('scanner.manatee.license', configuration)
  manatee.register('qr', _.get('qr.name', licenses), _.get('qr.key', licenses))
  manatee.register('pdf417', _.get('pdf417.name', licenses), _.get('pdf417.key', licenses))
}

function cancel () {
  cancelFlag = true
}

function isOpened () {
  return opened
}

function hasCamera (mode) {
  const cameraConf = mode === 'facephoto' ? 'frontFacingCamera' : 'scanner'

  const device = _.get(`${cameraConf}.device`, configuration)

  if (!device) return false

  console.log('Camera device available: ' + device)
  try {
    new v4l2camera.Camera(device)
    return true
  } catch (err) {
    return false
  }
}
// resultCallback returns final scan result
// captureCallback returns result of a frame capture
function scan (mode, resultCallback, captureCallback) {
  if (!openedFromOutside && opened) {
    console.log("Camera is already open. Shouldn't happen.")
    return resultCallback(new Error('Camera open'))
  }

  const {
    cam,
    modeConfig,
    width,
    height
  } = _prepareForCapture(mode)

  var handle = setInterval(capture, 100)

  function capture () {
    if (cancelFlag) {
      if (opened && !closing && !processing) {
        closing = true
        clearInterval(handle)
        cam.stop(() => {
          processing = false
          opened = false
          closing = false
          openedFromOutside = false
          openSettings = null
          return resultCallback()
        })
      }

      return
    }

    if (processing) return
    processing = true

    cam.capture(function (success) {
      if (!success) {
        processing = false
        return
      }

      var frame = Buffer.from(cam.frameRaw())
      let greyscale = null

      try {
        greyscale = jpg.decompressSync(frame, { format: jpg.FORMAT_GRAY })
      } catch (err) {
        processing = false
        return
      }

      captureCallback(modeConfig, width, height, frame, greyscale.data, function (err, result) {
        if (!err && !result && !cancelFlag) {
          processing = false
          openedFromOutside = false
          openSettings = null
          return
        }

        clearInterval(handle)
        cam.stop(() => {
          processing = false
          opened = false
          openedFromOutside = false
          openSettings = null
          return resultCallback(err, result)
        })
      })
    })
  }
}

function scanQR (callback) {
  scan('qr', callback, function (modeConfig, width, height, frame, greyscale, _callback) {
    const rgba8 = jpg.decompressSync(frame, { format: jpg.FORMAT_RGBA8 })
    const r = jsQR(rgba8.data, rgba8.width, rgba8.height, { inversionAttempts: 'dontInvert' })
    if (!r) return _callback()
    _callback(null, r.data)
  })
}

function scanPDF417 (callback, idCardStillsCallback) {
  const photosTaken = {
    1: true,
    2: true,
    3: true,
    4: true,
    5: true
  }
  const timerInit = new Date().getTime()

  scan('photoId', callback, function (modeConfig, width, height, frame, greyscale, _callback) {

    var timeChecker = new Date().getTime()
    let secondsPassed = Math.floor((timeChecker - timerInit) / 1000)
    var result = manatee.scanPDF417(greyscale, width, height)
    if (!result) {
      if (photosTaken[secondsPassed]) {
        photosTaken[secondsPassed] = false
        idCardStillsCallback(frame)
      }
      return _callback(null, null)
    }
    var parsed = Pdf417Parser.parse(result)
    if (!parsed) {
      if (photosTaken[secondsPassed]) {
        photosTaken[secondsPassed] = false
        idCardStillsCallback(frame)
      }
      return _callback(null, null)
    }
    parsed.raw = result.toString()
    _callback(null, parsed)
  })
}

function scanPhoto (callback) {
  scan('photoId', callback, function (modeConfig, width, height, frame, greyscale, _callback) {
    const detected = supyo.detect(greyscale, width, height, {
      minSize: modeConfig.minFaceSize || 100,
      qualityThreshold: modeConfig.threshold || 20,
      verbose: false
    })

    if (!detected) return _callback(null, null)
    _callback(null, frame)
  })
}

function scanFacephoto (callback) {
  scan('facephoto', callback, function (modeConfig, width, height, frame, greyscale, _callback) {
    const detected = supyo.detect(greyscale, width, height, {
      minSize: modeConfig.minFaceSize || 100,
      qualityThreshold: modeConfig.threshold || 20,
      verbose: false
    })

    if (!detected) return _callback(null, null)
    _callback(null, frame)
  })
}

function scanFacephotoTC (callback) {
  scan('facephoto', callback, function (modeConfig, width, height, frame, greyscale, _callback) {
    _callback(null, frame)
  })
}

function scanPairingCode (callback) {
  scanQR((err, res) => {
    if (err) return callback(err)
    if (!res) return callback()
    return callback(null, res.toString())
  })
}

function scanMainQR (cryptoCode, callback) {
  scanQR(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    var resultStr = result.toString()
    console.log('DEBUG55: %s', resultStr)

    const network = 'main'
    try {
      callback(null, coinUtils.parseUrl(cryptoCode, network, resultStr))
    } catch (error) {
      callback(error)
    }
  })
}

function scanPK (callback) {
  scanQR(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    callback(null, result.toString())
  })
}

function scanPhotoCard (callback) {
  scanPhoto(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    callback(null, result)
  })
}

function takeFacephoto (callback) {
  scanFacephoto(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    callback(null, result)
  })
}

function takeFacePhotoTC (callback) {
  scanFacephotoTC(function (err, result) {
    if (err) return callback(err)
    if (!result) return callback(null, null)

    callback(null, result)
  })
}

function _prepareForCapture (mode) {
  if (opened) return openSettings
  // Pick correct camera
  const cameraConf = mode === 'facephoto' ? 'frontFacingCamera' : 'scanner'

  const device = _.get([cameraConf, 'device'], configuration)
  const modeConfig = _.get([cameraConf, mode], configuration)

  const cam = new v4l2camera.Camera(device)

  cancelFlag = false

  const format = setConfig(cam, mode)

  cam.configSet(format)

  console.log('Opening v4l2camera device: ' + device + ' with mode: ' + mode, format)

  const width = format.width
  const height = format.height

  cam.start()

  opened = true
  openSettings = {
    cam,
    modeConfig,
    width,
    height
  }
  return openSettings
}

function prepareForCapture (mode) {
  openedFromOutside = true
  _prepareForCapture(mode)
}
<|endoftext|>


<commit_before>// schlock.js
//
// Cheaply-made in-process lock broker
//
// Copyright 2012, StatusNet Inc.
//
// 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.

var SchlockDoc = function() {
    var readers    = 0,
        writers    = 0,
        readQueue  = [],
        writeQueue = [];

    var runNext = function() {

        var writer,
            reader;

        // XXX: assert(writers === 0);

        if (writeQueue.length > 0) {
            if (readers === 0) {
                writer = writeQueue.shift();
                writers++;
                process.nextTick(function() {
                    writer(null);
                });
            }
        } else {
            while (readQueue.length > 0) {
                reader = readQueue.shift();
                readers++;
                process.nextTick((function(runme) {
                    return function() {
                        runme(null);
                    };
                })(reader));
            }
        }
    };

    this.idle = function() {
        return (readers === 0 &&
                writers === 0 &&
                readQueue.length === 0 &&
                writeQueue.length === 0);
    };

    this.readLock = function(callback) {
        if (writers > 0 || writeQueue.length > 0) {
            readQueue.push(callback);
        } else {
            readers++;
            process.nextTick(function() {
                callback(null);
            });
        }
    };

    this.writeLock = function(callback) {
        if (writers > 0 || readers > 0 || writeQueue.length > 0) {
            writeQueue.push(callback);
        } else {
            writers++;
            process.nextTick(function() {
                callback(null);
            });
        }
    };

    this.readUnlock = function(callback) {

        if (readers > 0) {
            readers--;
        }

        runNext();

        process.nextTick(function() {
            callback(null);
        });
    };

    this.writeUnlock = function(callback) {

        if (writers > 0) {
            writers--;
        }

        runNext();

        process.nextTick(function() {
            callback(null);
        });
    };
};

var Schlock = function() {

    var that = this,
        docs = {};

    var getDoc = function(name) {

        if (!docs.hasOwnProperty(name)) {
            docs[name] = new SchlockDoc();
        }

        return docs[name];
    };

    var rmDoc = function(name) {
        docs[name] = null;
    };

    this.readLock = function(name, callback) {
        var sd = getDoc(name);
        sd.readLock(callback);
    };

    this.writeLock = function(name, callback) {
        var sd = getDoc(name);
        sd.writeLock(callback);
    };

    this.readUnlock = function(name, callback) {
        var sd = getDoc(name);
        sd.readUnlock(callback);
        if (sd.idle()) {
            rmDoc(name);
        }
    };

    this.writeUnlock = function(name, callback) {
        var sd = getDoc(name);
        sd.writeUnlock(callback);
        if (sd.idle()) {
            rmDoc(name);
        }
    };
};

module.exports = Schlock;
<commit_msg>Lift callback maker<commit_after>// schlock.js
//
// Cheaply-made in-process lock broker
//
// Copyright 2012, StatusNet Inc.
//
// 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.

var SchlockDoc = function() {
    var readers    = 0,
        writers    = 0,
        readQueue  = [],
        writeQueue = [];

    var runNext = function() {

        var writer,
            reader,
            runner = function(runme) {
                return function() {
                    runme(null);
                };
            };

        // XXX: assert(writers === 0);

        if (writeQueue.length > 0) {
            if (readers === 0) {
                writer = writeQueue.shift();
                writers++;
                process.nextTick(runner(writer));
            }
        } else {
            while (readQueue.length > 0) {
                reader = readQueue.shift();
                readers++;
                process.nextTick(runner(reader));
            }
        }
    };

    this.idle = function() {
        return (readers === 0 &&
                writers === 0 &&
                readQueue.length === 0 &&
                writeQueue.length === 0);
    };

    this.readLock = function(callback) {
        if (writers > 0 || writeQueue.length > 0) {
            readQueue.push(callback);
        } else {
            readers++;
            process.nextTick(function() {
                callback(null);
            });
        }
    };

    this.writeLock = function(callback) {
        if (writers > 0 || readers > 0 || writeQueue.length > 0) {
            writeQueue.push(callback);
        } else {
            writers++;
            process.nextTick(function() {
                callback(null);
            });
        }
    };

    this.readUnlock = function(callback) {

        if (readers > 0) {
            readers--;
        }

        runNext();

        process.nextTick(function() {
            callback(null);
        });
    };

    this.writeUnlock = function(callback) {

        if (writers > 0) {
            writers--;
        }

        runNext();

        process.nextTick(function() {
            callback(null);
        });
    };
};

var Schlock = function() {

    var that = this,
        docs = {};

    var getDoc = function(name) {

        if (!docs.hasOwnProperty(name)) {
            docs[name] = new SchlockDoc();
        }

        return docs[name];
    };

    var rmDoc = function(name) {
        docs[name] = null;
    };

    this.readLock = function(name, callback) {
        var sd = getDoc(name);
        sd.readLock(callback);
    };

    this.writeLock = function(name, callback) {
        var sd = getDoc(name);
        sd.writeLock(callback);
    };

    this.readUnlock = function(name, callback) {
        var sd = getDoc(name);
        sd.readUnlock(callback);
        if (sd.idle()) {
            rmDoc(name);
        }
    };

    this.writeUnlock = function(name, callback) {
        var sd = getDoc(name);
        sd.writeUnlock(callback);
        if (sd.idle()) {
            rmDoc(name);
        }
    };
};

module.exports = Schlock;
<|endoftext|>


<commit_before>'use strict';

var App = require('../app');
var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var NUSMods = require('../nusmods');
var _ = require('underscore');
var $ = require('jquery');
var config = require('../common/config');
var timify = require('../common/utils/timify');
var Promise = require('bluebird');

var navigationItem = App.request('addNavigationItem', {
  name: 'Venues',
  icon: 'location-arrow',
  url: '/venues'
});

var loadVenueInformation = function (callback) {
  Promise.all([
    NUSMods.getVenueInformation(config.semester),
    NUSMods.getVenues(config.semester)
  ]).then(function (response) {
    var venues = response[0];
    var venuesList = response[1];
    // TODO: Change key from classes to lessons for venues api
    _.each(venues, function (value, key) {
      _.each(value, function (day) {
        if (day.classes) {
          day.lessons = day.classes;
        }
      });
    });
    callback(venues, venuesList);
  });
};

var controller = {
  showVenueInformation: function (venueName) {
    navigationItem.select();

    if (!venueName) {
      // Set to empty string for the default page
      venueName = '';
    }

    loadVenueInformation(function (venues, venuesList) {
      var VenueInformationView = require('./views/VenueInformationView');
      var venuesModel = new Backbone.Model({
        selectedVenueName: venueName,
        venues: venues,
        venuesList: venuesList,
        selectedVenue: null
      });

      App.mainRegion.show(new VenueInformationView({model: venuesModel}));
    });
  },
  showVenueAvailability: function () {
    navigationItem.select();
    loadVenueInformation(function (venues, venuesList) {
      var VenueAvailabilityView = require('./views/VenueAvailabilityView');
      var venuesModel = new Backbone.Model({
        venues: venues,
        venuesList: venuesList
      });

      App.mainRegion.show(new VenueAvailabilityView({model: venuesModel}));
    });
  }
};

App.addInitializer(function () {
  new Marionette.AppRouter({
    controller: controller,
    appRoutes: {
      'venues': 'showVenueInformation',
      'venues(/:id)': 'showVenueInformation',
      'venueavailability': 'showVenueAvailability'
    }
  });
});

<commit_msg>Change venue nav icon<commit_after>'use strict';

var App = require('../app');
var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var NUSMods = require('../nusmods');
var _ = require('underscore');
var $ = require('jquery');
var config = require('../common/config');
var timify = require('../common/utils/timify');
var Promise = require('bluebird');

var navigationItem = App.request('addNavigationItem', {
  name: 'Venues',
  icon: 'building-o',
  url: '/venues'
});

var loadVenueInformation = function (callback) {
  Promise.all([
    NUSMods.getVenueInformation(config.semester),
    NUSMods.getVenues(config.semester)
  ]).then(function (response) {
    var venues = response[0];
    var venuesList = response[1];
    // TODO: Change key from classes to lessons for venues api
    _.each(venues, function (value, key) {
      _.each(value, function (day) {
        if (day.classes) {
          day.lessons = day.classes;
        }
      });
    });
    callback(venues, venuesList);
  });
};

var controller = {
  showVenueInformation: function (venueName) {
    navigationItem.select();

    if (!venueName) {
      // Set to empty string for the default page
      venueName = '';
    }

    loadVenueInformation(function (venues, venuesList) {
      var VenueInformationView = require('./views/VenueInformationView');
      var venuesModel = new Backbone.Model({
        selectedVenueName: venueName,
        venues: venues,
        venuesList: venuesList,
        selectedVenue: null
      });

      App.mainRegion.show(new VenueInformationView({model: venuesModel}));
    });
  },
  showVenueAvailability: function () {
    navigationItem.select();
    loadVenueInformation(function (venues, venuesList) {
      var VenueAvailabilityView = require('./views/VenueAvailabilityView');
      var venuesModel = new Backbone.Model({
        venues: venues,
        venuesList: venuesList
      });

      App.mainRegion.show(new VenueAvailabilityView({model: venuesModel}));
    });
  }
};

App.addInitializer(function () {
  new Marionette.AppRouter({
    controller: controller,
    appRoutes: {
      'venues': 'showVenueInformation',
      'venues(/:id)': 'showVenueInformation',
      'venueavailability': 'showVenueAvailability'
    }
  });
});

<|endoftext|>


<commit_before>'use strict';

import * as _ from 'lodash'
import {courseCache} from './db'
import buildQueryFromString from './queryStuff'

function getCourse(clbid) {
	let course = courseCache[clbid]

	if (!course) {
		console.warn('course retrieval failed for: ' + clbid)
	}

	return _.cloneDeep(course)
}

function getCourses(clbids) {
	// Takes a list of clbids, and returns a list of the course objects for
	// those clbids.
	return _.map(clbids, getCourse)
}

function deptNumToCrsid(deptNumString) {
	let result = _.find(courseCache.courses, {deptnum: deptNumString})
	if (result) {
		return result.crsid
	} else {
		console.warn('Course ' + deptNumString + ' was not found')
	}
}

function checkCoursesForDeptNum(courses, deptNumString) {
	var crsidsToCheckAgainst = _.chain(courses).pluck('crsid').uniq().value()

	let crsid = deptNumToCrsid(deptNumString)
	return _.contains(crsidsToCheckAgainst, crsid)
}

function checkCoursesFor(courses, filter) {
	return _.any(courses, filter)
}

////
// from queryCourses

// 'dept: Computer Science  dept: Asian Studies  name: Parallel  level: 300  year: $OR year:2013 year: 2014'
// { depts: [ '$AND', 'CSCI', 'ASIAN' ],
//   title: [ 'Parallel' ],
//   level: [ 300 ],
//   year: [ '$OR', 2013, 2014 ] }

// 'dept: ASIAN  Dept: Religion  title: "Japan*"  LEVEL: 200  year: 2014  semester: $OR  semester: 3  semester: 1'
// { depts: [ '$AND', 'ASIAN', 'REL' ],
//   title: [ '"Japan*"' ],
//   level: [ 200 ],
//   year: [ 2014 ],
//   semester: [ '$OR', 3, 1 ] }

// 'department: American Conversations  name: Independence  year: 2014  time: Tuesdays after 12'
// { depts: [ 'AMCON' ],
//   title: [ 'Independence' ],
//   year: [ 2014 ],
//   time: [ 'Tuesdays after 12' ] }

// 'ges: $AND  geneds: history of western culture gened: HBS  semester: Spring  year: 2014'
// { geneds: [ '$AND', 'HWC', 'HBS' ],
//   semester: [ 3 ],
//   year: [ 2014 ] }

function queryCourses(queryString) {
	let query = buildQueryFromString(queryString)
	console.log('query:', query)
	var results = _(courseCache)
		.filter(course => {
			let matches = _.map(query, (values, key) => {
				let AND = false;
				let OR = false;
				let substring = false;

				// values is either:
				// - a 1-long array
				// - an $AND query
				// - an $OR query
				// - one of the above, but substring

				if (values[0] === '$OR') {
					OR = true
				} else if (values[0] === '$AND') {
					AND = true
				}

				if (AND || OR) {
					values = _.tail(values);
				}

				if (_.contains(['title', 'name', 'description', 'notes'], key)) {
					substring = true;
				}

				let internalMatches = _.map(values, (val) => {
					// dept, gereqs, etc.
					if (_.isArray(course[key]) || substring) {
						return _.contains(course[key], val)
					}
					return course[key] === val;
				})

				return OR ? _.some(internalMatches) : _.all(internalMatches)
			})
			return _.all(matches)
		})
		.map(_.cloneDeep)
		.sortBy('title')
		.groupBy('term')
		.value()
	return results
}

export {
	getCourse,
	getCourses,
	queryCourses,

	deptNumToCrsid,
	checkCoursesForDeptNum,
	checkCoursesFor
}

window.courses = {
	getCourse, getCourses,
	queryCourses,

	deptNumToCrsid,
	checkCoursesForDeptNum,
	checkCoursesFor,
}
<commit_msg>Lower-case stuff when comparing to allow for case-insensetive searches<commit_after>'use strict';

import * as _ from 'lodash'
import {courseCache} from './db'
import buildQueryFromString from './queryStuff'

function getCourse(clbid) {
	let course = courseCache[clbid]

	if (!course) {
		console.warn('course retrieval failed for: ' + clbid)
	}

	return _.cloneDeep(course)
}

function getCourses(clbids) {
	// Takes a list of clbids, and returns a list of the course objects for
	// those clbids.
	return _.map(clbids, getCourse)
}

function deptNumToCrsid(deptNumString) {
	let result = _.find(courseCache.courses, {deptnum: deptNumString})
	if (result) {
		return result.crsid
	} else {
		console.warn('Course ' + deptNumString + ' was not found')
	}
}

function checkCoursesForDeptNum(courses, deptNumString) {
	var crsidsToCheckAgainst = _.chain(courses).pluck('crsid').uniq().value()

	let crsid = deptNumToCrsid(deptNumString)
	return _.contains(crsidsToCheckAgainst, crsid)
}

function checkCoursesFor(courses, filter) {
	return _.any(courses, filter)
}

////
// from queryCourses

// 'dept: Computer Science  dept: Asian Studies  name: Parallel  level: 300  year: $OR year:2013 year: 2014'
// { depts: [ '$AND', 'CSCI', 'ASIAN' ],
//   title: [ 'Parallel' ],
//   level: [ 300 ],
//   year: [ '$OR', 2013, 2014 ] }

// 'dept: ASIAN  Dept: Religion  title: "Japan*"  LEVEL: 200  year: 2014  semester: $OR  semester: 3  semester: 1'
// { depts: [ '$AND', 'ASIAN', 'REL' ],
//   title: [ '"Japan*"' ],
//   level: [ 200 ],
//   year: [ 2014 ],
//   semester: [ '$OR', 3, 1 ] }

// 'department: American Conversations  name: Independence  year: 2014  time: Tuesdays after 12'
// { depts: [ 'AMCON' ],
//   title: [ 'Independence' ],
//   year: [ 2014 ],
//   time: [ 'Tuesdays after 12' ] }

// 'ges: $AND  geneds: history of western culture gened: HBS  semester: Spring  year: 2014'
// { geneds: [ '$AND', 'HWC', 'HBS' ],
//   semester: [ 3 ],
//   year: [ 2014 ] }

function queryCourses(queryString) {
	let query = buildQueryFromString(queryString)
	console.log('query:', query)
	var results = _(courseCache)
		.filter(course => {
			let matches = _.map(query, (values, key) => {
				let AND = false;
				let OR = false;
				let substring = false;

				// values is either:
				// - a 1-long array
				// - an $AND query
				// - an $OR query
				// - one of the above, but substring

				if (values[0] === '$OR') {
					OR = true
				} else if (values[0] === '$AND') {
					AND = true
				}

				if (AND || OR) {
					values = _.tail(values);
				}

				if (_.contains(['title', 'name', 'description', 'notes'], key)) {
					substring = true;
				}

				let internalMatches = _.map(values, (val) => {
					// dept, gereqs, etc.
					if (_.isArray(course[key]) || substring) {
						return _.contains(course[key].toLowerCase(), val.toLowerCase())
					}
					return course[key] === val;
				})

				return OR ? _.some(internalMatches) : _.all(internalMatches)
			})
			return _.all(matches)
		})
		.map(_.cloneDeep)
		.sortBy('title')
		.groupBy('term')
		.value()
	return results
}

export {
	getCourse,
	getCourses,
	queryCourses,

	deptNumToCrsid,
	checkCoursesForDeptNum,
	checkCoursesFor
}

window.courses = {
	getCourse, getCourses,
	queryCourses,

	deptNumToCrsid,
	checkCoursesForDeptNum,
	checkCoursesFor,
}
<|endoftext|>


<commit_before>'use strict';

let JSZip = require('js/jszip.min'),
    paper = require('js/paper-core.min'),
    paperScope = require('js/PaperScopeManager'),
    licenses =  require('js/licenses');

const RESOLUTIONS = [
    { name: 'mdpi', factor: 1 },
    { name: 'hdpi', factor: 1.5 },
    { name: 'xhdpi', factor: 2 },
    { name: 'xxhdpi', factor: 3 },
    { name: 'xxxhdpi', factor: 4 }
];

/**
 * Creates a downloadable ZIP file.
 */
class ExportManager {

    /**
     * Creates + downloads the final ZIP file.
     */
    createAndDownloadZip() {
        let zip = new JSZip();
        let rootFolder = zip.folder('icons');

        // generate content
        this.createAndZipImages(rootFolder);
        this.createAndZipLicenses(rootFolder);

        // download
        if (JSZip.support.blob) {
            window.location = "data:application/zip;base64," + zip.generate({type:"base64"});
        } else {
            console.log('blob not supported');
            // TODO
        }
    }

    createAndZipImages(rootFolder) {
        let drawProject = paperScope.draw().project;
        for (let i = 0; i < 5; ++i) {
            let resolution = RESOLUTIONS[i];

            paperScope.activateExpo(i);
            let exportProject = paperScope.expo(i).project;

            // copy draw layer over to export canvas
            exportProject.clear();
            let layer = new paper.Layer();
            for (let j = 0; j < drawProject.layers[0].children.length; ++j) {
                layer.addChild(drawProject.layers[0].children[j].clone(false));
            }
            paperScope.expo(i).view.center = new paper.Point(24, 24); // center at icon center (which is 48 px big)
            paperScope.expo(i).view.zoom = resolution.factor;
            paperScope.expo(i).view.draw();

            // copy png
            let pngData = paperScope.expoCanvas(i)[0].toDataURL('image/png').split(',')[1];
            let pngFileName = 'icon.png';
            rootFolder.folder('mipmap-' + resolution.name).file(pngFileName, pngData, { base64: true });

            if (i !== 0) continue;

            // generate final svg
            let svg = exportProject.exportSVG({ asString: true });
            let svgData = btoa(svg);
            let svgFileName = 'icon.svg';
            rootFolder.file(svgFileName, svgData, { base64: true });
        }

        // reactivate draw scope
        paperScope.activateDraw();
    }

    createAndZipLicenses(rootFolder) {
        let licenseFolder = rootFolder.folder('LICENSE');
        licenseFolder.file('LICENSE.txt', licenses.LICENSE_GENERAL);
        licenseFolder.file('LICENSE.CC_BY_4_0.txt',  licenses.LICENSE_CC_BY_4);
    }

}

module.exports = new ExportManager();<commit_msg>Do not export shadow template<commit_after>'use strict';

let JSZip = require('js/jszip.min'),
    paper = require('js/paper-core.min'),
    paperScope = require('js/PaperScopeManager'),
    licenses =  require('js/licenses');

const RESOLUTIONS = [
    { name: 'mdpi', factor: 1 },
    { name: 'hdpi', factor: 1.5 },
    { name: 'xhdpi', factor: 2 },
    { name: 'xxhdpi', factor: 3 },
    { name: 'xxxhdpi', factor: 4 }
];

/**
 * Creates a downloadable ZIP file.
 */
class ExportManager {

    /**
     * Creates + downloads the final ZIP file.
     */
    createAndDownloadZip() {
        let zip = new JSZip();
        let rootFolder = zip.folder('icons');

        // generate content
        this.createAndZipImages(rootFolder);
        this.createAndZipLicenses(rootFolder);

        // download
        if (JSZip.support.blob) {
            window.location = "data:application/zip;base64," + zip.generate({type:"base64"});
        } else {
            console.log('blob not supported');
            // TODO
        }
    }

    createAndZipImages(rootFolder) {
        let drawProject = paperScope.draw().project;
        for (let i = 0; i < 5; ++i) {
            let resolution = RESOLUTIONS[i];

            paperScope.activateExpo(i);
            let exportProject = paperScope.expo(i).project;

            // copy draw layer over to export canvas
            exportProject.clear();
            let layer = new paper.Layer();
            for (let j = 0; j < drawProject.layers[0].children.length; ++j) {
                let child = drawProject.layers[0].children[j];
                if (!child.fillColor) continue;
                layer.addChild(child.clone(false));
            }
            paperScope.expo(i).view.center = new paper.Point(24, 24); // center at icon center (which is 48 px big)
            paperScope.expo(i).view.zoom = resolution.factor;
            paperScope.expo(i).view.draw();

            // copy png
            let pngData = paperScope.expoCanvas(i)[0].toDataURL('image/png').split(',')[1];
            let pngFileName = 'icon.png';
            rootFolder.folder('mipmap-' + resolution.name).file(pngFileName, pngData, { base64: true });

            if (i !== 0) continue;

            // generate final svg
            let svg = exportProject.exportSVG({ asString: true });
            let svgData = btoa(svg);
            let svgFileName = 'icon.svg';
            rootFolder.file(svgFileName, svgData, { base64: true });
        }

        // reactivate draw scope
        paperScope.activateDraw();
    }

    createAndZipLicenses(rootFolder) {
        let licenseFolder = rootFolder.folder('LICENSE');
        licenseFolder.file('LICENSE.txt', licenses.LICENSE_GENERAL);
        licenseFolder.file('LICENSE.CC_BY_4_0.txt',  licenses.LICENSE_CC_BY_4);
    }

}

module.exports = new ExportManager();<|endoftext|>


<commit_before>
define([
  'jquery',
  'underscore',
  'backbone',
  'collections/sidebar',
  'text!templates/sidebar.html',
  'text!templates/sidebar_nav.html'
], function ($, _, Backbone, SidebarCollection,
             SidebarTemplate, SidebarNavTemplate) {

  var SidebarView = Backbone.View.extend ({
    el: '#sidebar',

    initialize: function () {
      this.sidebarCollection = new SidebarCollection ();

      $("#left-navbar").html (_.template (SidebarNavTemplate));

      // register channels event
      var that = this;
      $("#channels a").click (function () { that.click (this); });
    },

    render: function () {

      var that = this;

      this.sidebarCollection.fetch ({

        success: function (entries) {

          $(that.el).append (_.template (SidebarTemplate,
                                         {entries: entries.toJSON ()}));

        }

      });
    },

    click: function (ev) {
      var channel = $(ev).attr ('href').match (/^#(hot)*(\/)*(.*?)$/, '')[3];

      if (channel == '')
        channel = 'gundem';

      this.sidebarCollection.channel = channel;
      this.sidebarCollection.reset ();
      $(this.el).html ('');
      this.render ();
    }

  });

  return SidebarView;

});
<commit_msg>add infinite scrollto sidebar<commit_after>
define([
  'jquery',
  'underscore',
  'backbone',
  'collections/sidebar',
  'text!templates/sidebar.html',
  'text!templates/sidebar_nav.html'
], function ($, _, Backbone, SidebarCollection,
             SidebarTemplate, SidebarNavTemplate) {

  var SidebarView = Backbone.View.extend ({
    el: '#sidebar',

    initialize: function () {
      this.sidebarCollection = new SidebarCollection ();

      $("#left-navbar").html (_.template (SidebarNavTemplate));

      // register channels event
      var that = this;
      $("#channels a").click (function () { that.click (this); });

      $("#sidebar-wrapper").on ('scroll', function () {
        that.checkScroll (this);
      });
    },

    render: function () {

      var that = this;

      this.isLoading = true;

      this.sidebarCollection.fetch ({

        success: function (entries) {

          $(that.el).append (_.template (SidebarTemplate,
                                         {entries: entries.toJSON ()}));

          that.isLoading = false;

        }

      });
    },

    click: function (ev) {
      var channel = $(ev).attr ('href').match (/^#(hot)*(\/)*(.*?)$/, '')[3];

      if (channel == '')
        channel = 'gundem';

      this.sidebarCollection.channel = channel;
      this.sidebarCollection.page = 1;
      this.sidebarCollection.reset ();
      $(this.el).html ('');
      this.render ();
    },

    checkScroll: function () {
      if (!this.isLoading &&
          !this.sidebarCollection.lastPage () &&
          $('#sidebar-wrapper').scrollTop () +
              $('#sidebar-wrapper').height () + 200 >
              this.el.scrollHeight) {
        this.sidebarCollection.page++;
        this.render ();
      }

    }

  });

  return SidebarView;

});
<|endoftext|>


<commit_before>gpf.require.define({
    Tile: "tile.js",
    dom: "../dom.js",
    config: "../../tmp/config.json"

}, function (require) {
    "use strict";

    var dom = require.dom,
        config = require.config;

    return gpf.define({
        $class: "Hosts",
        $extend: require.Tile,

        constructor: function () {
            this.$super("hosts", "Hosts");
            this._setGruntCommand("detectSelenium", "Detect selenium");
        },

        getDynamicContent: function () {
            return gpf.http.get("/fs/test/legacy")
                .then(function (response) {
                    if (404 === response.status) {
                        return [];
                    }
                    return JSON.parse(response.responseText);
                })
                .then(function (legacyFolderContent) {
                    return [
                        dom.label({for: "hostsVersion"}, "Version: "),
                        dom.select({id: "hostsVersion"}, [
                            dom.optgroup({label: "Current"}, [
                                dom.option({value: "Verbose"}, "source"),
                                dom.option({value: "Debug"}, "debug"),
                                dom.option({value: "Release"}, "release")
                            ]),
                            dom.optgroup({label: "Legacy"}, legacyFolderContent
                                .filter(function (name) {
                                    return name !== "legacy.json";
                                })
                                .map(function (name) {
                                    var version = name.substr(0, name.lastIndexOf("."));
                                    return dom.option({value: "Legacy:" + version}, version);
                                })
                            )
                        ]),
                        dom.ul({id: "hostsNames"}, Object.keys(config.browsers)
                            .concat(["node", "phantom", "nodewscript"])
                            .concat(["rhino"].filter(function (name) {
                                return config.host.java;
                            }))
                            .concat(["nashorn"].filter(function (name) {
                                return config.host.nashorn;
                            }))
                            .concat(["wscript"].filter(function (name) {
                                return config.host.wscript;
                            }))
                            .sort()
                            .map(function (name) {
                                return dom.li({id:"host-" + name, link:"env"}, name);
                            })
                        )
                    ];
                });
        }

    });

});
<commit_msg>Fixing linter issue (#183)<commit_after>gpf.require.define({
    Tile: "tile.js",
    dom: "../dom.js",
    config: "../../tmp/config.json"

}, function (require) {
    "use strict";

    var dom = require.dom,
        config = require.config;

    return gpf.define({
        $class: "Hosts",
        $extend: require.Tile,

        constructor: function () {
            this.$super("hosts", "Hosts");
            this._setGruntCommand("detectSelenium", "Detect selenium");
        },

        getDynamicContent: function () {
            return gpf.http.get("/fs/test/legacy")
                .then(function (response) {
                    if (404 === response.status) {
                        return [];
                    }
                    return JSON.parse(response.responseText);
                })
                .then(function (legacyFolderContent) {
                    return [
                        dom.label({"for": "hostsVersion"}, "Version: "),
                        dom.select({id: "hostsVersion"}, [
                            dom.optgroup({label: "Current"}, [
                                dom.option({value: "Verbose"}, "source"),
                                dom.option({value: "Debug"}, "debug"),
                                dom.option({value: "Release"}, "release")
                            ]),
                            dom.optgroup({label: "Legacy"}, legacyFolderContent
                                .filter(function (name) {
                                    return name !== "legacy.json";
                                })
                                .map(function (name) {
                                    var version = name.substr(0, name.lastIndexOf("."));
                                    return dom.option({value: "Legacy:" + version}, version);
                                })
                            )
                        ]),
                        dom.ul({id: "hostsNames"}, Object.keys(config.browsers)
                            .concat(["node", "phantom", "nodewscript"])
                            .concat(["rhino"].filter(function () {
                                return config.host.java;
                            }))
                            .concat(["nashorn"].filter(function () {
                                return config.host.nashorn;
                            }))
                            .concat(["wscript"].filter(function () {
                                return config.host.wscript;
                            }))
                            .sort()
                            .map(function (name) {
                                return dom.li({id: "host-" + name, link: "env"}, name);
                            })
                        )
                    ];
                });
        }

    });

});
<|endoftext|>


<commit_before>// TODO: Move Android permissions that are currently done natively in Java to here
// Exception is bluetooth as the library doesn't appear to handle Bluetooth on Android

// TODO: Permissions alert wrapper so don't lose the first iOS permission request

import Permissions from 'react-native-permissions';
import { Platform } from 'react-native';

export default function() {
    Permissions.request('photo');
    Permissions.request('camera');
    Permissions.request('microphone');
    if (Platform.OS !== 'ios') {
        Permissions.request('storage');
    }
};
<commit_msg>Permissions now uses promises to chain then<commit_after>// TODO: Move Android permissions that are currently done natively in Java to here
// Exception is bluetooth as the library doesn't appear to handle Bluetooth on Android

// TODO: Permissions alert wrapper so don't lose the first iOS permission request

import Permissions from 'react-native-permissions';
import { Platform } from 'react-native';

export default function() {
    Permissions.request('photo')
    .then(Permissions.request('camera'))
    .then(Permissions.request('microphone'))
    .then(() => {
        if (Platform.OS !== 'ios') {
            Permissions.request('storage');
        }
    });
};
<|endoftext|>


<commit_before>import { createHistory } from 'history';
import Auth0Lock from 'auth0-lock';
import { gotError } from './general';
import authVars from '../../auth0-variables';
import debugFactory from 'debug';

const debug = debugFactory( 'voyageur:actions' );
const history = createHistory();

function removeTokenFromUrl() {
  if ( ! window ) return;
  const newUrl = window.location.pathname;
  debug( 'replacing history location with', newUrl );
  history.replace( newUrl );
}

export function doAuth() {
  return function() {
    const lock = new Auth0Lock( authVars.AUTH0_CLIENT_ID, authVars.AUTH0_DOMAIN );
    lock.show( { authParams: { scope: 'openid role name email nickname' } } );
  }
}

export function parseAuthToken() {
  return function( dispatch, getState ) {
    const lock = new Auth0Lock( authVars.AUTH0_CLIENT_ID, authVars.AUTH0_DOMAIN );
    const idToken = getState().auth.token;
    const hash = ( window ? window.location.hash : '' );
    const authHash = lock.parseHash( hash );
    if ( ! idToken && authHash ) {
      if ( authHash.id_token ) {
        debug( 'parsed auth token from URL' );
        dispatch( gotAuthToken( authHash.id_token ) );
      }
      if ( authHash.error ) {
        debug( 'error parsing auth token from URL' );
        console.error( 'Error signing in', authHash );
      }
    }
    if ( authHash ) removeTokenFromUrl();
  }
}

export function gotAuthToken( token ) {
  return { type: 'AUTH_GOT_TOKEN', token };
}

export function getProfile() {
  return function( dispatch, getState ) {
    const lock = new Auth0Lock( authVars.AUTH0_CLIENT_ID, authVars.AUTH0_DOMAIN );
    lock.getProfile( getState().auth.token, ( err, profile ) => {
      if ( err ) return dispatch( gotError( err ) );
      dispatch( gotProfile( profile ) );
    } );
  }
}

export function gotProfile( allUserData ) {
  const { name, role } = allUserData;
  return { type: 'AUTH_GOT_USER', user: { name, role } };
}

export function logOut() {
  return { type: 'AUTH_LOG_OUT' };
}
<commit_msg>Add icon to login screen<commit_after>import { createHistory } from 'history';
import Auth0Lock from 'auth0-lock';
import { gotError } from './general';
import authVars from '../../auth0-variables';
import debugFactory from 'debug';

const debug = debugFactory( 'voyageur:actions' );
const history = createHistory();

function removeTokenFromUrl() {
  if ( ! window ) return;
  const newUrl = window.location.pathname;
  debug( 'replacing history location with', newUrl );
  history.replace( newUrl );
}

export function doAuth() {
  return function() {
    const lock = new Auth0Lock( authVars.AUTH0_CLIENT_ID, authVars.AUTH0_DOMAIN );
    lock.show( {
      icon: 'https://cldup.com/iu86nhnHUS.png',
      authParams: { scope: 'openid role name email nickname' }
    } );
  }
}

export function parseAuthToken() {
  return function( dispatch, getState ) {
    const lock = new Auth0Lock( authVars.AUTH0_CLIENT_ID, authVars.AUTH0_DOMAIN );
    const idToken = getState().auth.token;
    const hash = ( window ? window.location.hash : '' );
    const authHash = lock.parseHash( hash );
    if ( ! idToken && authHash ) {
      if ( authHash.id_token ) {
        debug( 'parsed auth token from URL' );
        dispatch( gotAuthToken( authHash.id_token ) );
      }
      if ( authHash.error ) {
        debug( 'error parsing auth token from URL' );
        console.error( 'Error signing in', authHash );
      }
    }
    if ( authHash ) removeTokenFromUrl();
  }
}

export function gotAuthToken( token ) {
  return { type: 'AUTH_GOT_TOKEN', token };
}

export function getProfile() {
  return function( dispatch, getState ) {
    const lock = new Auth0Lock( authVars.AUTH0_CLIENT_ID, authVars.AUTH0_DOMAIN );
    lock.getProfile( getState().auth.token, ( err, profile ) => {
      if ( err ) return dispatch( gotError( err ) );
      dispatch( gotProfile( profile ) );
    } );
  }
}

export function gotProfile( allUserData ) {
  const { name, role } = allUserData;
  return { type: 'AUTH_GOT_USER', user: { name, role } };
}

export function logOut() {
  return { type: 'AUTH_LOG_OUT' };
}
<|endoftext|>