<commit_before>define(['md5'], function (SparkMD5, allowExtsMimes) {
    allowExtsMimes = JSON.parse('{$exts|raw}');
    return function (element, UploadedHandler, options) {
        /*! 定义初始化变量 */
        options = {element: $(element), exts: [], mimes: [], files: {}, cache: {}, loading: 0};
        options.count = {total: 0, uploaded: 0};
        options.type = options.element.data('type') || '';
        options.safe = options.element.data('safe') ? 1 : 0;
        options.types = options.type ? options.type.split(',') : [];
        options.field = options.element.data('field') || 'file';
        options.input = $('[name="_field_"]'.replace('_field_', options.field));
        options.uptype = options.safe ? 'local' : options.element.attr('data-uptype') || '';
        options.multiple = options.element.attr('data-multiple') > 0;
        /*! 文件的选择筛选 */
        for (var index in options.types) if (allowExtsMimes[options.types[index]]) {
            options.exts.push(options.types[index]), options.mimes.push(allowExtsMimes[options.types[index]]);
        }
        /*! 初始化上传组件 */
        options.uploader = layui.upload.render({
            auto: false, multiple: options.multiple, accept: 'file', elem: element,
            exts: options.exts.join('|'), acceptMime: options.mimes.join(','), choose: function (obj) {
                for (var index in options.files = obj.pushFile()) {
                    options.loading = $.msg.loading('上传进度 0%');
                    options.count.total++, options.files[index].index = index, options.cache[index] = options.files[index], delete options.files[index];
                    md5file(options.cache[index]).then(function (file) {
                        jQuery.ajax("{:url('@admin/api.upload/state')}", {
                            data: {xkey: file.xkey, uptype: options.uptype, safe: options.safe, name: file.name}, method: 'post', success: function (ret) {
                                file.xurl = ret.data.url;
                                if (parseInt(ret.code) === 404) {
                                    options.uploader.config.url = ret.data.server;
                                    options.uploader.config.data.key = ret.data.xkey;
                                    options.uploader.config.data.safe = ret.data.safe;
                                    options.uploader.config.data.uptype = ret.data.uptype;
                                    if (ret.data.uptype === 'qiniu') {
                                        options.uploader.config.data.token = ret.data.token;
                                    } else if (ret.data.uptype === 'alioss') {
                                        options.uploader.config.data.policy = ret.data.policy;
                                        options.uploader.config.data.signature = ret.data.signature;
                                        options.uploader.config.data.OSSAccessKeyId = ret.data.OSSAccessKeyId;
                                        options.uploader.config.data.success_action_status = 200;
                                        options.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
                                    }
                                    obj.upload(file.index, file);
                                } else if (parseInt(ret.code) === 200) {
                                    options.uploader.config.done({uploaded: true, url: file.xurl}, file.index);
                                } else {
                                    $.msg.tips(ret.info || ret.error.message || '文件上传出错！');
                                }
                            }
                        });
                    });
                }
            }, progress: function (n) {
                $('[data-upload-progress]').html(n + '%');
            }, done: function (ret, index, file) {
                if (++options.count.uploaded >= options.count.total) {
                    layer.close(options.loading);
                }
                if (typeof ret.code === 'number' && parseInt(ret.code) === 0) {
                    return $.msg.tips(ret.info || '文件上传失败！');
                }
                file = options.cache[index];
                if (typeof file.xurl !== 'string') return $.msg.tips('无效的文件对象！');
                if (typeof ret.uploaded === 'undefined' && typeof file.xurl === 'string') {
                    ret = {uploaded: true, url: file.xurl};
                }
                if (ret.uploaded) {
                    if (typeof UploadedHandler === 'function') {
                        UploadedHandler.call(options.element, ret.url, file);
                    } else {
                        options.input.val(ret.url).trigger('change');
                    }
                } else {
                    $.msg.tips(ret.info || ret.error.message || '文件上传出错！');
                }
            }, allDone: function () {
                $.msg.close(options.loading);
                options.element.html(options.element.data('html'));
            }
        });
    };

    function md5file(file) {
        var deferred = jQuery.Deferred();
        file.xext = file.name.indexOf('.') > -1 ? file.name.split('.').pop() : 'tmp';

        /*! 兼容不能计算文件 HASH 的情况 */
        if (!window.FileReader) return jQuery.when((function (date, chars) {
            date = new Date(), chars = 'abcdefhijkmnprstwxyz0123456789';
            this.xmd5 = '' + date.getFullYear() + (date.getMonth() + 1) + date.getDay() + date.getHours() + date.getMinutes() + date.getSeconds();
            while (this.xmd5.length < 32) this.xmd5 += chars.charAt(Math.floor(Math.random() * chars.length));
            return setFileXdata(file, this.xmd5), deferred.resolve(file, file.xmd5, file.xkey), deferred;
        }).call(this));

        /*! 读取文件并计算 HASH 值 */
        var spark = new SparkMD5.ArrayBuffer();
        var slice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
        file.chunk_idx = 0, file.chunk_size = 2097152, file.chunk_total = Math.ceil(this.size / this.chunk_size);
        return jQuery.when(loadNextChunk(file));

        function setFileXdata(file, xmd5) {
            file.xmd5 = xmd5;
            file.xkey = file.xmd5.substr(0, 2) + '/' + file.xmd5.substr(2, 30) + '.' + file.xext;
            delete file.chunk_idx, delete file.chunk_size, delete file.chunk_total;
            return file;
        }

        function loadNextChunk(file) {
            this.reader = new FileReader();
            this.reader.onload = function (e) {
                spark.append(e.target.result);
                if (++file.chunk_idx < file.chunk_total) {
                    loadNextChunk(file);
                } else {
                    setFileXdata(file, spark.end());
                    deferred.resolve(file, file.xmd5, file.xkey);
                }
            };
            this.reader.onerror = function () {
                deferred.reject();
            };
            this.start = file.chunk_idx * file.chunk_size;
            this.loaded = (this.start + file.chunk_size >= file.size) ? file.size : this.start + file.chunk_size;
            this.reader.readAsArrayBuffer(slice.call(file, this.start, this.loaded));
            return deferred.notify(file, (this.loaded / file.size * 100).toFixed(2)), deferred;
        }
    }
});<commit_msg>Update upload.js<commit_after>define(['md5'], function (SparkMD5, allowExtsMimes) {
    allowExtsMimes = JSON.parse('{$exts|raw}');
    return function (element, UploadedHandler, options) {
        /*! 定义初始化变量 */
        options = {element: $(element), exts: [], mimes: [], files: {}, cache: {}, loading: 0};
        options.count = {total: 0, uploaded: 0};
        options.type = options.element.data('type') || '';
        options.safe = options.element.data('safe') ? 1 : 0;
        options.types = options.type ? options.type.split(',') : [];
        options.field = options.element.data('field') || 'file';
        options.input = $('[name="_field_"]'.replace('_field_', options.field));
        options.uptype = options.safe ? 'local' : options.element.attr('data-uptype') || '';
        options.multiple = options.element.attr('data-multiple') > 0;
        /*! 文件的选择筛选 */
        for (var index in options.types) if (allowExtsMimes[options.types[index]]) {
            options.exts.push(options.types[index]), options.mimes.push(allowExtsMimes[options.types[index]]);
        }
        /*! 初始化上传组件 */
        options.uploader = layui.upload.render({
            auto: false, multiple: options.multiple, accept: 'file', elem: element,
            exts: options.exts.join('|'), acceptMime: options.mimes.join(','), choose: function (obj) {
                for (var index in options.files = obj.pushFile()) {
                    options.loading = $.msg.loading('上传进度 0%');
                    options.count.total++, options.files[index].index = index, options.cache[index] = options.files[index], delete options.files[index];
                    md5file(options.cache[index]).then(function (file) {
                        jQuery.ajax("{:url('admin/api.upload/state')}", {
                            data: {xkey: file.xkey, uptype: options.uptype, safe: options.safe, name: file.name}, method: 'post', success: function (ret) {
                                file.xurl = ret.data.url;
                                if (parseInt(ret.code) === 404) {
                                    options.uploader.config.url = ret.data.server;
                                    options.uploader.config.data.key = ret.data.xkey;
                                    options.uploader.config.data.safe = ret.data.safe;
                                    options.uploader.config.data.uptype = ret.data.uptype;
                                    if (ret.data.uptype === 'qiniu') {
                                        options.uploader.config.data.token = ret.data.token;
                                    } else if (ret.data.uptype === 'alioss') {
                                        options.uploader.config.data.policy = ret.data.policy;
                                        options.uploader.config.data.signature = ret.data.signature;
                                        options.uploader.config.data.OSSAccessKeyId = ret.data.OSSAccessKeyId;
                                        options.uploader.config.data.success_action_status = 200;
                                        options.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
                                    }
                                    obj.upload(file.index, file);
                                } else if (parseInt(ret.code) === 200) {
                                    options.uploader.config.done({uploaded: true, url: file.xurl}, file.index);
                                } else {
                                    $.msg.tips(ret.info || ret.error.message || '文件上传出错！');
                                }
                            }
                        });
                    });
                }
            }, progress: function (n) {
                $('[data-upload-progress]').html(n + '%');
            }, done: function (ret, index, file) {
                if (++options.count.uploaded >= options.count.total) {
                    layer.close(options.loading);
                }
                if (typeof ret.code === 'number' && parseInt(ret.code) === 0) {
                    return $.msg.tips(ret.info || '文件上传失败！');
                }
                file = options.cache[index];
                if (typeof file.xurl !== 'string') return $.msg.tips('无效的文件对象！');
                if (typeof ret.uploaded === 'undefined' && typeof file.xurl === 'string') {
                    ret = {uploaded: true, url: file.xurl};
                }
                if (ret.uploaded) {
                    if (typeof UploadedHandler === 'function') {
                        UploadedHandler.call(options.element, ret.url, file);
                    } else {
                        options.input.val(ret.url).trigger('change');
                    }
                } else {
                    $.msg.tips(ret.info || ret.error.message || '文件上传出错！');
                }
            }, allDone: function () {
                $.msg.close(options.loading);
                options.element.html(options.element.data('html'));
            }
        });
    };

    function md5file(file) {
        var deferred = jQuery.Deferred();
        file.xext = file.name.indexOf('.') > -1 ? file.name.split('.').pop() : 'tmp';

        /*! 兼容不能计算文件 HASH 的情况 */
        if (!window.FileReader) return jQuery.when((function (date, chars) {
            date = new Date(), chars = 'abcdefhijkmnprstwxyz0123456789';
            this.xmd5 = '' + date.getFullYear() + (date.getMonth() + 1) + date.getDay() + date.getHours() + date.getMinutes() + date.getSeconds();
            while (this.xmd5.length < 32) this.xmd5 += chars.charAt(Math.floor(Math.random() * chars.length));
            return setFileXdata(file, this.xmd5), deferred.resolve(file, file.xmd5, file.xkey), deferred;
        }).call(this));

        /*! 读取文件并计算 HASH 值 */
        var spark = new SparkMD5.ArrayBuffer();
        var slice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
        file.chunk_idx = 0, file.chunk_size = 2097152, file.chunk_total = Math.ceil(this.size / this.chunk_size);
        return jQuery.when(loadNextChunk(file));

        function setFileXdata(file, xmd5) {
            file.xmd5 = xmd5;
            file.xkey = file.xmd5.substr(0, 2) + '/' + file.xmd5.substr(2, 30) + '.' + file.xext;
            delete file.chunk_idx, delete file.chunk_size, delete file.chunk_total;
            return file;
        }

        function loadNextChunk(file) {
            this.reader = new FileReader();
            this.reader.onload = function (e) {
                spark.append(e.target.result);
                if (++file.chunk_idx < file.chunk_total) {
                    loadNextChunk(file);
                } else {
                    setFileXdata(file, spark.end());
                    deferred.resolve(file, file.xmd5, file.xkey);
                }
            };
            this.reader.onerror = function () {
                deferred.reject();
            };
            this.start = file.chunk_idx * file.chunk_size;
            this.loaded = (this.start + file.chunk_size >= file.size) ? file.size : this.start + file.chunk_size;
            this.reader.readAsArrayBuffer(slice.call(file, this.start, this.loaded));
            return deferred.notify(file, (this.loaded / file.size * 100).toFixed(2)), deferred;
        }
    }
});<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */

(function(scope) {

  // imports

  var log = window.logFlags || {};

  // magic words

  var OBSERVE_SUFFIX = 'Changed';

  // element api

  var empty = [];

  var updateRecord = {
    object: undefined,
    type: 'update',
    name: undefined,
    oldValue: undefined
  };

  var numberIsNaN = Number.isNaN || function(value) {
    return typeof value === 'number' && isNaN(value);
  }

  function areSameValue(left, right) {
    if (left === right)
      return left !== 0 || 1 / left === 1 / right;
    if (numberIsNaN(left) && numberIsNaN(right))
      return true;

    return left !== left && right !== right;
  }

  // capture A's value if B's value is null or undefined,
  // otherwise use B's value
  function resolveBindingValue(oldValue, value) {
    if (value === undefined && oldValue === null) {
      return value;
    }
    return (value === null || value === undefined) ? oldValue : value;
  }

  var properties = {
    createPropertyObserver: function() {
      var n$ = this._observeNames;
      if (n$ && n$.length) {
        var o = this._propertyObserver = new CompoundObserver(true);
        this.registerObserver(o);
        // TODO(sorvell): may not be kosher to access the value here (this[n]);
        // previously we looked at the descriptor on the prototype
        // this doesn't work for inheritance and not for accessors without
        // a value property
        for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
          o.addPath(this, n);
          this.observeArrayValue(n, this[n], null);
        }
      }
    },
    openPropertyObserver: function() {
      if (this._propertyObserver) {
        this._propertyObserver.open(this.notifyPropertyChanges, this);
      }
    },
    notifyPropertyChanges: function(newValues, oldValues, paths) {
      var name, method, called = {};
      for (var i in oldValues) {
        // note: paths is of form [object, path, object, path]
        name = paths[2 * i + 1];
        method = this.observe[name];
        if (method) {
          var ov = oldValues[i], nv = newValues[i];
          // observes the value if it is an array
          this.observeArrayValue(name, nv, ov);
          if (!called[method]) {
            // only invoke change method if one of ov or nv is not (undefined | null)
            if ((ov !== undefined && ov !== null) || (nv !== undefined && nv !== null)) {
              called[method] = true;
              // TODO(sorvell): call method with the set of values it's expecting;
              // e.g. 'foo bar': 'invalidate' expects the new and old values for
              // foo and bar. Currently we give only one of these and then
              // deliver all the arguments.
              this.invokeMethod(method, [ov, nv, arguments]);
            }
          }
        }
      }
    },
    deliverChanges: function() {
      if (this._propertyObserver) {
        this._propertyObserver.deliver();
      }
    },
    propertyChanged_: function(name, value, oldValue) {
      if (this.reflect[name]) {
        this.reflectPropertyToAttribute(name);
      }
    },
    observeArrayValue: function(name, value, old) {
      // we only care if there are registered side-effects
      var callbackName = this.observe[name];
      if (callbackName) {
        // if we are observing the previous value, stop
        if (Array.isArray(old)) {
          log.observe && console.log('[%s] observeArrayValue: unregister observer [%s]', this.localName, name);
          this.closeNamedObserver(name + '__array');
        }
        // if the new value is an array, being observing it
        if (Array.isArray(value)) {
          log.observe && console.log('[%s] observeArrayValue: register observer [%s]', this.localName, name, value);
          var observer = new ArrayObserver(value);
          observer.open(function(value, old) {
            this.invokeMethod(callbackName, [old]);
          }, this);
          this.registerNamedObserver(name + '__array', observer);
        }
      }
    },
    notify: function(name, value, oldValue) {
      var object = this;
      if (areSameValue(value, oldValue))
        return;

      this.propertyChanged_(name, value, oldValue);

      if (!Observer.hasObjectObserve)
        return;

      var notifier = this.notifier_;
      if (!notifier)
        notifier = this.notifier_ = Object.getNotifier(this);

      updateRecord.object = this;
      updateRecord.name = name;
      updateRecord.oldValue = oldValue;

      notifier.notify(updateRecord);
    },
    bindToAccessor: function(name, observable, resolveFn) {
      var privateName = name + '_';
      var privateObservable  = name + 'Observable_';

      this[privateObservable] = observable;
      var oldValue = this[privateName];

      var self = this;
      var value = observable.open(function(value, oldValue) {
        self[privateName] = value;
        self.notify(name, value, oldValue);
      });

      if (resolveFn && !areSameValue(oldValue, value)) {
        var resolvedValue = resolveFn(oldValue, value);
        if (!areSameValue(value, resolvedValue)) {
          value = resolvedValue;
          if (observable.setValue)
            observable.setValue(value);
        }
      }

      this[privateName] = value;
      this.notify(name, value, oldValue);

      this.registerObserver({
        close: function() {
          observable.close();
          self[privateObservable] = undefined;
        }
      });
    },
    createComputedProperties: function() {
      if (!this._computedNames) {
        return;
      }

      for (var i = 0; i < this._computedNames.length; i++) {
        var name = this._computedNames[i];
        var expressionText = this.computed[name];
        try {
          var expression = PolymerExpressions.getExpression(expressionText);
          var observable = expression.getBinding(this, this.element.syntax);
          this.bindToAccessor(name, observable);
        } catch (ex) {
          console.error('Failed to create computed property', ex);
        }
      }
    },
    bindProperty: function(property, observable, oneTime) {
      if (oneTime) {
        this[property] = observable;
        return;
      }
      this.bindToAccessor(property, observable, resolveBindingValue);
    },
    invokeMethod: function(method, args) {
      var fn = this[method] || method;
      if (typeof fn === 'function') {
        fn.apply(this, args);
      }
    },
    registerObserver: function(observer) {
      if (!this._observers) {
        this._observers = [observer];
        return;
      }

      this._observers.push(observer);
    },
    // observer array items are arrays of observers.
    closeObservers: function() {
      if (!this._observers) {
        return;
      }

      var observers = this._observers;
      for (var i = 0; i < observers.length; i++) {
        var observer = observers[i];
        if (observer && typeof observer.close == 'function') {
          observer.close();
        }
      }

      this._observers = [];
    },
    // bookkeeping observers for memory management
    registerNamedObserver: function(name, observer) {
      var o$ = this._namedObservers || (this._namedObservers = {});
      o$[name] = observer;
    },
    closeNamedObserver: function(name) {
      var o$ = this._namedObservers;
      if (o$ && o$[name]) {
        o$[name].close();
        o$[name] = null;
        return true;
      }
    },
    closeNamedObservers: function() {
      if (this._namedObservers) {
        for (var i in this._namedObservers) {
          this.closeNamedObserver(i);
        }
        this._namedObservers = {};
      }
    }
  };

  // logging
  var LOG_OBSERVE = '[%s] watching [%s]';
  var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]';
  var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]';

  // exports

  scope.api.instance.properties = properties;

})(Polymer);
<commit_msg>bindProperty must return an observer if possible.<commit_after>/*
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */

(function(scope) {

  // imports

  var log = window.logFlags || {};

  // magic words

  var OBSERVE_SUFFIX = 'Changed';

  // element api

  var empty = [];

  var updateRecord = {
    object: undefined,
    type: 'update',
    name: undefined,
    oldValue: undefined
  };

  var numberIsNaN = Number.isNaN || function(value) {
    return typeof value === 'number' && isNaN(value);
  }

  function areSameValue(left, right) {
    if (left === right)
      return left !== 0 || 1 / left === 1 / right;
    if (numberIsNaN(left) && numberIsNaN(right))
      return true;

    return left !== left && right !== right;
  }

  // capture A's value if B's value is null or undefined,
  // otherwise use B's value
  function resolveBindingValue(oldValue, value) {
    if (value === undefined && oldValue === null) {
      return value;
    }
    return (value === null || value === undefined) ? oldValue : value;
  }

  var properties = {
    createPropertyObserver: function() {
      var n$ = this._observeNames;
      if (n$ && n$.length) {
        var o = this._propertyObserver = new CompoundObserver(true);
        this.registerObserver(o);
        // TODO(sorvell): may not be kosher to access the value here (this[n]);
        // previously we looked at the descriptor on the prototype
        // this doesn't work for inheritance and not for accessors without
        // a value property
        for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
          o.addPath(this, n);
          this.observeArrayValue(n, this[n], null);
        }
      }
    },
    openPropertyObserver: function() {
      if (this._propertyObserver) {
        this._propertyObserver.open(this.notifyPropertyChanges, this);
      }
    },
    notifyPropertyChanges: function(newValues, oldValues, paths) {
      var name, method, called = {};
      for (var i in oldValues) {
        // note: paths is of form [object, path, object, path]
        name = paths[2 * i + 1];
        method = this.observe[name];
        if (method) {
          var ov = oldValues[i], nv = newValues[i];
          // observes the value if it is an array
          this.observeArrayValue(name, nv, ov);
          if (!called[method]) {
            // only invoke change method if one of ov or nv is not (undefined | null)
            if ((ov !== undefined && ov !== null) || (nv !== undefined && nv !== null)) {
              called[method] = true;
              // TODO(sorvell): call method with the set of values it's expecting;
              // e.g. 'foo bar': 'invalidate' expects the new and old values for
              // foo and bar. Currently we give only one of these and then
              // deliver all the arguments.
              this.invokeMethod(method, [ov, nv, arguments]);
            }
          }
        }
      }
    },
    deliverChanges: function() {
      if (this._propertyObserver) {
        this._propertyObserver.deliver();
      }
    },
    propertyChanged_: function(name, value, oldValue) {
      if (this.reflect[name]) {
        this.reflectPropertyToAttribute(name);
      }
    },
    observeArrayValue: function(name, value, old) {
      // we only care if there are registered side-effects
      var callbackName = this.observe[name];
      if (callbackName) {
        // if we are observing the previous value, stop
        if (Array.isArray(old)) {
          log.observe && console.log('[%s] observeArrayValue: unregister observer [%s]', this.localName, name);
          this.closeNamedObserver(name + '__array');
        }
        // if the new value is an array, being observing it
        if (Array.isArray(value)) {
          log.observe && console.log('[%s] observeArrayValue: register observer [%s]', this.localName, name, value);
          var observer = new ArrayObserver(value);
          observer.open(function(value, old) {
            this.invokeMethod(callbackName, [old]);
          }, this);
          this.registerNamedObserver(name + '__array', observer);
        }
      }
    },
    notify: function(name, value, oldValue) {
      var object = this;
      if (areSameValue(value, oldValue))
        return;

      this.propertyChanged_(name, value, oldValue);

      if (!Observer.hasObjectObserve)
        return;

      var notifier = this.notifier_;
      if (!notifier)
        notifier = this.notifier_ = Object.getNotifier(this);

      updateRecord.object = this;
      updateRecord.name = name;
      updateRecord.oldValue = oldValue;

      notifier.notify(updateRecord);
    },
    bindToAccessor: function(name, observable, resolveFn) {
      var privateName = name + '_';
      var privateObservable  = name + 'Observable_';

      this[privateObservable] = observable;
      var oldValue = this[privateName];

      var self = this;
      var value = observable.open(function(value, oldValue) {
        self[privateName] = value;
        self.notify(name, value, oldValue);
      });

      if (resolveFn && !areSameValue(oldValue, value)) {
        var resolvedValue = resolveFn(oldValue, value);
        if (!areSameValue(value, resolvedValue)) {
          value = resolvedValue;
          if (observable.setValue)
            observable.setValue(value);
        }
      }

      this[privateName] = value;
      this.notify(name, value, oldValue);

      var observer = {
        close: function() {
          observable.close();
          self[privateObservable] = undefined;
        }
      };
      this.registerObserver(observer);
      return observer;
    },
    createComputedProperties: function() {
      if (!this._computedNames) {
        return;
      }

      for (var i = 0; i < this._computedNames.length; i++) {
        var name = this._computedNames[i];
        var expressionText = this.computed[name];
        try {
          var expression = PolymerExpressions.getExpression(expressionText);
          var observable = expression.getBinding(this, this.element.syntax);
          this.bindToAccessor(name, observable);
        } catch (ex) {
          console.error('Failed to create computed property', ex);
        }
      }
    },
    bindProperty: function(property, observable, oneTime) {
      if (oneTime) {
        this[property] = observable;
        return;
      }
      return this.bindToAccessor(property, observable, resolveBindingValue);
    },
    invokeMethod: function(method, args) {
      var fn = this[method] || method;
      if (typeof fn === 'function') {
        fn.apply(this, args);
      }
    },
    registerObserver: function(observer) {
      if (!this._observers) {
        this._observers = [observer];
        return;
      }

      this._observers.push(observer);
    },
    // observer array items are arrays of observers.
    closeObservers: function() {
      if (!this._observers) {
        return;
      }

      var observers = this._observers;
      for (var i = 0; i < observers.length; i++) {
        var observer = observers[i];
        if (observer && typeof observer.close == 'function') {
          observer.close();
        }
      }

      this._observers = [];
    },
    // bookkeeping observers for memory management
    registerNamedObserver: function(name, observer) {
      var o$ = this._namedObservers || (this._namedObservers = {});
      o$[name] = observer;
    },
    closeNamedObserver: function(name) {
      var o$ = this._namedObservers;
      if (o$ && o$[name]) {
        o$[name].close();
        o$[name] = null;
        return true;
      }
    },
    closeNamedObservers: function() {
      if (this._namedObservers) {
        for (var i in this._namedObservers) {
          this.closeNamedObserver(i);
        }
        this._namedObservers = {};
      }
    }
  };

  // logging
  var LOG_OBSERVE = '[%s] watching [%s]';
  var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]';
  var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]';

  // exports

  scope.api.instance.properties = properties;

})(Polymer);
<|endoftext|>


<commit_before>import express from "express";
import bodyParser from "body-parser";
import cors from "cors";
import path from 'path';
import morgan from 'morgan';
import logger from './src/util/logger';
import fileUpload from 'express-fileupload';
import {graphqlHTTP} from 'express-graphql';
import {buildSchema} from 'graphql';
import rootResolver from './src/resolvers';
import fs from 'fs';
import dotenv from 'dotenv';
import {loadConfig} from './config';
import getAuthenticatedUser from './src/users/user.context';

import config from './config';

const envPath = path.resolve(process.cwd()+'/../', '.env');
logger.info('Loading .env from '+envPath);
dotenv.config({
  path: envPath
});
loadConfig();

const app = express();
var corsOptions = {
    methods: ['GET','PUT','POST','DELETE','PATCH','OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization']
  };
app.use(cors(corsOptions));

app.use(bodyParser.json({limit: '10mb'}));
app.use(bodyParser.urlencoded({ extended: true, limit: '10mb' }));

// Set up logging
app.use(morgan('dev',{
  stream: logger.stream,
  skip: function (req, res) {
    if ( req.originalUrl === '/api/health' ) {
        return true;
    } else {
        return false;
    }
}
}));

//configureAuthContext(app);

// Need to do this to get real request IP from proxy
app.set('trust proxy', true);

// Enable PUG template engine
app.set("view engine","pug");
app.set('views', path.join(__dirname, '/src/views'));
app.use('/api/static', express.static(path.join(__dirname, '/src/static')));
app.use(fileUpload({
  useTempFiles: true,
  tempFileDir: config.tmpDir,
  debug:false
}));

// Construct a schema, using GraphQL schema language
logger.info('Loading schema.graphql')
let schemaFile =  fs.readFileSync('schema.graphql','utf8')
let schema = buildSchema(schemaFile);

const graphqlMiddleware = graphqlHTTP((req, res) => {
    console.log("graphMiddleWare called");
    return new Promise((resolve, reject) => {

      const next = async (data, info = {}) => {
        const user = await getAuthenticatedUser(req);

        /**
         * GraphQL configuration goes here
         */
        resolve({
            schema: schema,
            rootValue: rootResolver,
            graphiql: true,
            context: { user }
        });
    };
    return next();
  });
});

app.use('/graphql',graphqlMiddleware);

//Index route
// app.get('/', (req, res) => {
//     res.send('Invalid endpoint!');
// });
app.use(express.static(path.join(__dirname, " ",'../front/build')));

// app.use('*', (req,res) => res.sendFile(path.resolve('front','build','index.html')));
app.use((req, res, next) => {
  res.sendFile(path.join(__dirname, "..", 'front','build','index.html'));
});

app.use(function(error,req,res,next){
  console.log("ERROR: "+error,error.stack);
  logger.error((error.status || 500)+' - '+error.message+' - '+req.originalUrl+' - '+req.method+' - '+req.ip+' - '+error.stack,);
  res.status(500).end();
});

app.listen(config.port, () => {

  logger.info("_________ .__  .__       __      __.__ __   .__ ");
  logger.info("\\_   ___ \\|  | |__| ____/  \\    /  \\__|  | _|__|");
  logger.info("/    \\  \\/|  | |  |/    \\   \\/\\/   /  |  |/ /  |");
  logger.info("\\     \\___|  |_|  |   |  \\        /|  |    <|  |");
  logger.info(" \\______  /____/__|___|  /\\__/\\  / |__|__|_ \\__|");
  logger.info("        \\/             \\/      \\/          \\/     ");

  logger.info('Server started on port '+config.port);
});
<commit_msg>chaning app.get method<commit_after>import express from "express";
import bodyParser from "body-parser";
import cors from "cors";
import path from 'path';
import morgan from 'morgan';
import logger from './src/util/logger';
import fileUpload from 'express-fileupload';
import {graphqlHTTP} from 'express-graphql';
import {buildSchema} from 'graphql';
import rootResolver from './src/resolvers';
import fs from 'fs';
import dotenv from 'dotenv';
import {loadConfig} from './config';
import getAuthenticatedUser from './src/users/user.context';

import config from './config';

const envPath = path.resolve(process.cwd()+'/../', '.env');
logger.info('Loading .env from '+envPath);
dotenv.config({
  path: envPath
});
loadConfig();

const app = express();
var corsOptions = {
    methods: ['GET','PUT','POST','DELETE','PATCH','OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization']
  };
app.use(cors(corsOptions));

app.use(bodyParser.json({limit: '10mb'}));
app.use(bodyParser.urlencoded({ extended: true, limit: '10mb' }));

// Set up logging
app.use(morgan('dev',{
  stream: logger.stream,
  skip: function (req, res) {
    if ( req.originalUrl === '/api/health' ) {
        return true;
    } else {
        return false;
    }
}
}));

//configureAuthContext(app);

// Need to do this to get real request IP from proxy
app.set('trust proxy', true);

// Enable PUG template engine
app.set("view engine","pug");
app.set('views', path.join(__dirname, '/src/views'));
app.use('/api/static', express.static(path.join(__dirname, '/src/static')));
app.use(fileUpload({
  useTempFiles: true,
  tempFileDir: config.tmpDir,
  debug:false
}));

// Construct a schema, using GraphQL schema language
logger.info('Loading schema.graphql')
let schemaFile =  fs.readFileSync('schema.graphql','utf8')
let schema = buildSchema(schemaFile);

const graphqlMiddleware = graphqlHTTP((req, res) => {
    console.log("graphMiddleWare called");
    return new Promise((resolve, reject) => {

      const next = async (data, info = {}) => {
        const user = await getAuthenticatedUser(req);

        /**
         * GraphQL configuration goes here
         */
        resolve({
            schema: schema,
            rootValue: rootResolver,
            graphiql: true,
            context: { user }
        });
    };
    return next();
  });
});

app.use('/graphql',graphqlMiddleware);

//Index route
// app.get('/', (req, res) => {
//     res.send('Invalid endpoint!');
// });
// app.use(express.static(path.join(__dirname, " ",'../front/build')));

const root = path.join(__dirname, " ",'../front/build');
app.use(express.static(root));
// app.use('*', (req,res) => res.sendFile(path.resolve('front','build','index.html')));
// app.use((req, res, next) => {
//   res.sendFile(path.join(__dirname, "..", 'front','build','index.html'));
// });
app.get("*", (req, res) => {
  res.sendFile('index.html', { root });
})

app.use(function(error,req,res,next){
  console.log("ERROR: "+error,error.stack);
  logger.error((error.status || 500)+' - '+error.message+' - '+req.originalUrl+' - '+req.method+' - '+req.ip+' - '+error.stack,);
  res.status(500).end();
});

app.listen(config.port, () => {

  logger.info("_________ .__  .__       __      __.__ __   .__ ");
  logger.info("\\_   ___ \\|  | |__| ____/  \\    /  \\__|  | _|__|");
  logger.info("/    \\  \\/|  | |  |/    \\   \\/\\/   /  |  |/ /  |");
  logger.info("\\     \\___|  |_|  |   |  \\        /|  |    <|  |");
  logger.info(" \\______  /____/__|___|  /\\__/\\  / |__|__|_ \\__|");
  logger.info("        \\/             \\/      \\/          \\/     ");

  logger.info('Server started on port '+config.port);
});
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var cwd = process.cwd()
var fs = require('fs')
var path = require('path')
var pem2jwk = require('pem-jwk').pem2jwk

/**
 * Keys
 */

var keys = {}
var privateKey, publicKey
var defaultPublicKeyFile = path.join(cwd, 'config', 'keys', 'public.pem')
var defaultPrivateKeyFile = path.join(cwd, 'config', 'keys', 'private.pem')

/**
 * Look for environment variables.
 */

if (process.env.ANVIL_CONNECT_PRIVATE_KEY) {
  privateKey = new Buffer(process.env.ANVIL_CONNECT_PRIVATE_KEY, 'base64').toString('ascii')
}

if (process.env.ANVIL_CONNECT_PUBLIC_KEY) {
  publicKey = new Buffer(process.env.ANVIL_CONNECT_PUBLIC_KEY, 'base64').toString('ascii')
}

/**
 * Try to read the key files. If they are available locally,
 * they should override the environment variables.
 */

try {
  privateKey = fs.readFileSync(defaultPrivateKeyFile).toString('ascii')
  publicKey = fs.readFileSync(defaultPublicKeyFile).toString('ascii')
} catch (err) {}

/**
 * Ensure the key pair has been loaded
 */

if (!privateKey || !publicKey) {
  console.log('Cannot load keypair')
  process.exit(1)
}

/**
 * Create JWK from public key
 */

var jwk = pem2jwk(publicKey)

/**
 * JWK Set
 */

var jwks = {
  keys: [{
    kty: jwk.kty,
    use: 'sig',
    alg: 'RS256',
    n: jwk.n,
    e: jwk.e
  }]
}

/**
 * Export
 */

keys.privateKey = privateKey
keys.publicKey = publicKey
keys.jwks = jwks
module.exports = keys
<commit_msg>feat(boot): generate token-signing keypair if missing on boot<commit_after>/**
 * Module dependencies
 */

var cwd = process.cwd()
var fs = require('fs')
var mkdirp = require('mkdirp')
var path = require('path')
var pem2jwk = require('pem-jwk').pem2jwk
var exec = require('child_process').execFileSync

/**
 * Paths and file names
 */

var keyDirectory = path.join(cwd, 'config', 'keys')
var defaultPublicKeyFile = path.join(keyDirectory, 'public.pem')
var defaultPrivateKeyFile = path.join(keyDirectory, 'private.pem')

/**
 * Load Keys
 */

function loadKeys () {
  var keys = null

  // Try to read the key files. If they are available locally,
  // they should override the environment variables.
  try {
    keys = {
      privateKey: fs.readFileSync(defaultPrivateKeyFile).toString('ascii'),
      publicKey: fs.readFileSync(defaultPublicKeyFile).toString('ascii')
    }
  } catch (err) {}

  return keys
}

/**
 * Try loading
 */

var keys = loadKeys()

/**
 * Generate keys if not present
 */

if (!keys) {

  try {
    mkdirp.sync(keyDirectory)

    exec('openssl', [
      'genrsa',
      '-out',
      defaultPrivateKeyFile,
      '4096'
    ])

    exec('openssl', [
      'rsa',
      '-pubout',
      '-in',
      defaultPrivateKeyFile,
      '-out',
      defaultPublicKeyFile
    ])

  } catch (e) {
    console.log(
      'Failed to generate keys using OpenSSL. Please ensure you have OpenSSL ' +
      'installed and configured on your system.'
    )
    process.exit(1)
  }

  // Try again
  keys = loadKeys()

  // If they still can't be loaded, kill the process
  if (!keys) {
    console.log(
      'Unable to read the token-signing key pair from ' + keyDirectory
    )
    process.exit(1)
  }
}

/**
 * Create JWK from public key
 */

var jwk = pem2jwk(keys.publicKey)

/**
 * JWK Set
 */

keys.jwks = {
  keys: [{
    kty: jwk.kty,
    use: 'sig',
    alg: 'RS256',
    n: jwk.n,
    e: jwk.e
  }]
}

/**
 * Export
 */

module.exports = keys
<|endoftext|>


<commit_before>(function InitLevels() {

// Exports

var Circular;
if ("Circular" in window) {
  Circular = window.Circular;
} else {
  Circular = window.Circular = {};
}
var levels = Circular.levels = [];

// Starting credits
levels.push({
  start: function start(engine) {
    var eltText = engine.showText("You have been trapped in the circularity");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      engine.addEventListener("textHidden", function onhidden() {
        engine.removeEventListener("textHidden", onhidden);
        engine.levelComplete(true);
      });
      engine.hideText();
    });
  },
  step: function step(engine) {
    // Nothing to do
  },
  toString: function toString() {
    return "Starting credits";
  }
});

// Level 1

levels.push({
  start: function start(engine) {
    engine.showText("To exit, bounce the particle towards the center");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      window.setTimeout(function () { engine.hideText(); }, 5000);
    });

    var ball = engine.addBall();
    ball.x = 0;
    ball.y = 15;
    ball.dx = 0;
    ball.dy = 1;

    var target = engine.addArea();
    target.x = 0;
    target.y = 0;
    target.radiusPixels = 10;
    target.strokeStyle = "green";

    var superHandleCollision = target.handleCollision;
    target.handleCollision = function handleCollision(ball) {
      if (superHandleCollision.call(this, ball)) {
        console.log("Level is complete");
        engine.levelComplete(true);
      }
    };

    engine.run(this);
  },
  step: function step(engine) {
    engine.step();
  },
  toString: function toString() {
    return "Tutorial";
  }
});

// Level 2: Obstacle course
levels.push({
  start: function start(engine, img) {
    engine.showText("Often, you will need to avoid obstacles");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      window.setTimeout(function () { engine.hideText(); }, 5000);
    });

    var ball = engine.addBall();
    ball.x = 0;
    ball.y = 50;
    ball.dx = 0;
    ball.dy = 1;

    var target = engine.addArea();
    target.x = 0;
    target.y = 0;
    target.radiusPixels = 10;
    target.strokeStyle = "green";

    var superHandleCollision = target.handleCollision;
    target.handleCollision = function handleCollision(ball) {
      if (superHandleCollision.call(this, ball)) {
        console.log("Level is complete");
        engine.levelComplete(true);
      }
    };

    var obstacles = [[0, 25], [0, -25], [25, 0], [-25, 0]];
    for (var i = 0; i < obstacles.length; ++i) {
      var obstacle = engine.addArea();
      var coor = obstacles[i];
      obstacle.x = coor[0];
      obstacle.y = coor[1];
      obstacle.radiusPixels = 5;
      obstacle.isBouncing = true;
      obstacle.strokeStyle = "white";
    }

    engine.run(this);
  },
  step: function step(engine) {
    engine.step();
  },
  toString: function toString() {
    return "Obstacle course";
  }
});

// Level 3: Moving obstacles
levels.push({
  obstacles: [],
  start: function start(engine) {
    engine.showText("They move, too");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      window.setTimeout(function () { engine.hideText(); }, 5000);
    });

    var ball = engine.addBall();
    ball.x = 0;
    ball.y = 50;
    ball.dx = 0;
    ball.dy = 1;

    var target = engine.addArea();
    target.x = 0;
    target.y = 0;
    target.radiusPixels = 10;
    target.strokeStyle = "green";

    var superHandleCollision = target.handleCollision;
    target.handleCollision = function handleCollision(ball) {
      if (superHandleCollision.call(this, ball)) {
        console.log("Level is complete");
        engine.levelComplete(true);
      }
    };

    var obstacles = [0, Math.PI/2, Math.PI, 3*Math.PI/2];
    for (var i = 0; i < obstacles.length; ++i) {
      var obstacle = engine.addArea();
      var angle = obstacles[i];
      obstacle.x = Math.cos(angle) * 25;
      obstacle.y = Math.sin(angle) * 25;
      obstacle.radiusPixels = 5;
      obstacle.isBouncing = true;
      obstacle.strokeStyle = "white";
      this.obstacles.push(obstacle);
    }

    engine.run(this);
  },
  step: function step(engine) {
    var now = Date.now();
    var previous = engine._previousFrameStamp;
    for (var i = 0; i < this.obstacles.length; ++i) {
      var angle = now / 1000 + i * Math.PI / 2;
      this.obstacles[i].x = Math.cos(angle) * 25;
      this.obstacles[i].y = Math.sin(angle) * 25;
    }
    engine.step();
  },
  toString: function toString() {
    return "Moving obstacles";
  }
});

// Level 4: Bricks
levels.push({
  start: function start(engine, img) {
    engine.showText("Clear a path");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      window.setTimeout(function () { engine.hideText(); }, 5000);
    });

    var ball = engine.addBall();
    ball.x = 0;
    ball.y = 50;
    ball.dx = .1;
    ball.dy = .9;

    var target = engine.addArea();
    target.x = 0;
    target.y = 0;
    target.radiusPixels = 10;
    target.strokeStyle = "green";

    var superHandleCollision = target.handleCollision;
    target.handleCollision = function handleCollision(ball) {
      if (superHandleCollision.call(this, ball)) {
        console.log("Level is complete");
        engine.levelComplete(true);
      }
    };

    var obstacle;
    var angle;
    var i;

    for (i = 0; i < 4; ++i) {
      obstacle = engine.addArea();
      angle = Math.PI * i / 2;
      obstacle.x = Math.cos(angle) * 10;
      obstacle.y = Math.sin(angle) * 10;
      obstacle.radiusPixels = 5;
      obstacle.isBouncing = true;
      obstacle.strokeStyle = "white";
      obstacle.isDestructible = true;
    }

    for (i = 0; i < 8; ++i) {
      obstacle = engine.addArea();
      angle = Math.PI * i / 4;
      obstacle.x = Math.cos(angle) * 25;
      obstacle.y = Math.sin(angle) * 25;
      obstacle.radiusPixels = 5;
      obstacle.isBouncing = true;
      obstacle.strokeStyle = "white";
      obstacle.isDestructible = true;
    }

    for (i = 0; i < 16; ++i) {
      obstacle = engine.addArea();
      angle = Math.PI * i / 8;
      obstacle.x = Math.cos(angle) * 40;
      obstacle.y = Math.sin(angle) * 40;
      obstacle.radiusPixels = 5;
      obstacle.isBouncing = true;
      obstacle.strokeStyle = "white";
      obstacle.isDestructible = true;
    }

    engine.run(this);
  },
  step: function step(engine) {
    engine.step();
  },
  toString: function toString() {
    return "The Wall";
  }
});

// Ending credits
levels.push({
  start: function start(engine) {
    engine.showText("Congratulations. You have escaped the circularity");
  },
  step: function step(engine) {
    // Do NOT call engine.step()
  },
  toString: function toString() {
    return "Ending credits";
  }
});

})();<commit_msg>[Refactor] Factorized level.js<commit_after>(function InitLevels() {

// Exports

var Circular;
if ("Circular" in window) {
  Circular = window.Circular;
} else {
  Circular = window.Circular = {};
}
var levels = Circular.levels = [];

var addTarget = function addTarget(engine) {
  var target = engine.addArea();
  target.x = 0;
  target.y = 0;
  target.radiusPixels = 10;
  target.strokeStyle = "green";

  var superHandleCollision = target.handleCollision;
  target.handleCollision = function handleCollision(ball) {
    if (superHandleCollision.call(this, ball)) {
      console.log("Level is complete");
      engine.levelComplete(true);
    }
  };
  return target;
};

var addObstacle = function addObstacle(engine, x, y) {
  var obstacle = engine.addArea();
  obstacle.x = x;
  obstacle.y = y;
  obstacle.radiusPixels = 5;
  obstacle.isBouncing = true;
  obstacle.strokeStyle = "white";
  return obstacle;
};

var addDestructible = function addDestructible(engine, x, y) {
  var obstacle = engine.addArea();
  obstacle.x = x;
  obstacle.y = y;
  obstacle.radiusPixels = 5;
  obstacle.isBouncing = true;
  obstacle.strokeStyle = "white";
  obstacle.isDestructible = true;
  return obstacle;
};

// Starting credits
levels.push({
  start: function start(engine) {
    var eltText = engine.showText("The circularity has pulled you in.");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      engine.addEventListener("textHidden", function onhidden() {
        engine.removeEventListener("textHidden", onhidden);
        engine.levelComplete(true);
      });
      engine.hideText();
    });
  },
  step: function step(engine) {
    // Nothing to do
  },
  toString: function toString() {
    return "Starting credits";
  }
});

// Level 1

levels.push({
  start: function start(engine) {
    engine.showText("To exit, bounce the particle towards the center.");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      window.setTimeout(function () { engine.hideText(); }, 5000);
    });

    var ball = engine.addBall();
    ball.x = 0;
    ball.y = 15;
    ball.dx = 0;
    ball.dy = 1;

    var target = addTarget(engine);
    engine.run(this);
  },
  step: function step(engine) {
    engine.step();
  },
  toString: function toString() {
    return "Tutorial";
  }
});

// Level 2: Obstacle course
levels.push({
  start: function start(engine, img) {
    engine.showText("Work around the particles.");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      window.setTimeout(function () { engine.hideText(); }, 5000);
    });

    var ball = engine.addBall();
    ball.x = 0;
    ball.y = 50;
    ball.dx = 0;
    ball.dy = 1;

    var target = addTarget(engine);

    var obstacles = [[0, 25], [0, -25], [25, 0], [-25, 0]];
    for (var i = 0; i < obstacles.length; ++i) {
      var coor = obstacles[i];
      var obstacle = addObstacle(engine, coor[0], coor[1]);
    }

    engine.run(this);
  },
  step: function step(engine) {
    engine.step();
  },
  toString: function toString() {
    return "Obstacle course";
  }
});

// Level 3: Moving obstacles
levels.push({
  obstacles: [],
  start: function start(engine) {
    engine.showText("They move, too");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      window.setTimeout(function () { engine.hideText(); }, 5000);
    });

    var ball = engine.addBall();
    ball.x = 0;
    ball.y = 50;
    ball.dx = 0;
    ball.dy = 1;

    var target = addTarget(engine);

    var superHandleCollision = target.handleCollision;
    target.handleCollision = function handleCollision(ball) {
      if (superHandleCollision.call(this, ball)) {
        console.log("Level is complete");
        engine.levelComplete(true);
      }
    };

    var obstacles = [0, Math.PI/2, Math.PI, 3*Math.PI/2];
    for (var i = 0; i < obstacles.length; ++i) {
      var angle = obstacles[i];
      var obstacle = addObstacle(engine,
        Math.cos(angle) * 25, Math.sin(angle) * 25);
      this.obstacles.push(obstacle);
    }

    engine.run(this);
  },
  step: function step(engine) {
    var now = Date.now();
    var previous = engine._previousFrameStamp;
    for (var i = 0; i < this.obstacles.length; ++i) {
      var angle = now / 1000 + i * Math.PI / 2;
      this.obstacles[i].x = Math.cos(angle) * 25;
      this.obstacles[i].y = Math.sin(angle) * 25;
    }
    engine.step();
  },
  toString: function toString() {
    return "Moving obstacles";
  }
});

// Level 4: Bricks
levels.push({
  start: function start(engine, img) {
    engine.showText("Clear a path");
    engine.addEventListener("textShown", function onshown() {
      engine.removeEventListener("textShown", onshown);
      window.setTimeout(function () { engine.hideText(); }, 5000);
    });

    var ball = engine.addBall();
    ball.x = 0;
    ball.y = 50;
    ball.dx = .1;
    ball.dy = .9;

    var target = addTarget(engine);

    var obstacle;
    var angle;
    var i;

    for (i = 0; i < 4; ++i) {
      angle = Math.PI * i / 2;
      obstacle = addDestructible(engine,
        Math.cos(angle) * 10,
        Math.sin(angle) * 10);
    }

    for (i = 0; i < 8; ++i) {
      angle = Math.PI * i / 4;
      obstacle = addDestructible(engine,
        Math.cos(angle) * 25,
        Math.sin(angle) * 25);
    }

    for (i = 0; i < 16; ++i) {
      angle = Math.PI * i / 8;
      obstacle = addDestructible(engine,
        Math.cos(angle) * 40,
        Math.sin(angle) * 40);
    }

    engine.run(this);
  },
  step: function step(engine) {
    engine.step();
  },
  toString: function toString() {
    return "The Wall";
  }
});

// Ending credits
levels.push({
  start: function start(engine) {
    engine.showText("Congratulations. You have escaped the circularity");
  },
  step: function step(engine) {
    // Do NOT call engine.step()
  },
  toString: function toString() {
    return "Ending credits";
  }
});

})();<|endoftext|>


<commit_before>// Externals
var trim_link, $, ga;

(function() {
  'use strict';

  // make <detail> tags toggleable
  var enableDetailsToggle = function(i, el){
    var root = $(el),
      summary = root.find('.link'),
      content = root.find('.reveal');

    root.on('click', function(){
      content.toggleClass('closed');
      root.toggleClass('opened');
    });
  };

  // on the Dashboard (/dashboard), only enable the Commission button if
  // the mandatory fields are filled out
  var setCommissionButtonStatus = function(form) {
    var enable = true;
    var button = form.find('.commission-button');
    form.find('select.required-for-commission,input.required-for-commission').each(function() {
      var value = $(this).val();
      var filled = (value !== "" && value !== null);
      enable = enable && filled;
    });
    if (enable) {
      button.removeAttr('disabled');
    } else {
      button.attr('disabled', 'disabled');
    }
  };

  // 3 functions below increment, decrement of change the number of New PQ's
  // on the filter box
  var incrementBadge = function(id_of_navpill) {
    changeBadgeBy(id_of_navpill,1);
  };

  var decrementBadge = function(id_of_navpill) {
    changeBadgeBy(id_of_navpill,-1);
  };

  var changeBadgeBy = function(id_of_navpill, val) {
    var $badge = $(id_of_navpill).children('a').children('span');
    var curval = parseInt($badge.text(),10);
    var nextval = curval+val;
    if (nextval < 0) {
      nextval = 0;
    }
    $badge.text(nextval);
  };

  //==========================================================================

  $(document).ready(function () {

    // set up any date pickers on the page
    $('.datetimepicker input').datetimepicker({validateOnBlur:false,
                                               scrollMonth: false,
                                               closeOnDateSelect:true,
                                               dayOfWeekStart: 1,
                                               format:'d/m/Y     H:i'});

    // set up any datetime pickers on the page
    $('.datepicker input').datetimepicker({timepicker: false,
                                           scrollInput: false,
                                           scrollMonth: false,
                                           validateOnBlur:false,
                                           closeOnDateSelect:true,
                                           dayOfWeekStart: 1,
                                           format:'d/m/Y'});

    // enable select2 drop-boxes on various select controls
    $('.minister-select').select2({width:'250px'});
    $('.multi-select-action-officers').select2({width:'250px'});
    $('.single-select-dropdown').select2({width:'250px', allowClear: true});

    // if the page has rejection details, make them collapsible
    // applies to /assignment and /watchlist/preview pages
    $('.details-reveal').each(enableDetailsToggle);

    // on /assignment, open the reject justification form when Reject is selected
    // and hide it when Accept is selected
    $('#allocation_response_response_action_accept').on('click', function (){
      $('#reason-textarea').addClass('hide');
    });
    $('#allocation_response_response_action_reject').on('click', function (){
      $('#reason-textarea').removeClass('hide');
    });

    // on the dashboard, enable the Commission button only if the required fields are non-empty
    $('.form-commission').each(function() {
     setCommissionButtonStatus($(this));
    });

    // commisioning a question and showing the success message on the dashboard page
    $(".form-commission")
      .on("ajax:success", function(){
        // if the question was successfully commission, then hide it and replace with
        // a success message
        var pqid = $(this).data('pqid');
        var uin  = $(this).parents('*[data-pquin]').data('pquin');
        $('#pq-frame-'+pqid).replaceWith('
'+ uin +' commissioned successfully <button class="close" data-dismiss="alert">×</button>
');
        // on the right-hand filter panel, increment the number of No Eesponse questions
        incrementBadge('#db-filter-alloc-pend');
        // and decrement the number of unallocated
        decrementBadge('#db-filter-unalloc');
      }).on("ajax:error", function(e, xhr) {
        console.log(xhr.responseText);
      }).on('change', function(e) {
       // when the form is modified, check if all the mandatory fields are set
       // so that the Commission button is enabled
       setCommissionButtonStatus($(e.currentTarget));
      });

    // when clicking a calendar icon, open the calendar to the left of it
    // and if empty populate it with the current time,
    // (unless it has class default-time, in which case set time to 10:00)
    $('span.fa-calendar').on('click', function () {
      var picker = $(this).prev('input'), now, nowString;
      if (picker.val() === '') {
        now = new Date();
        if (picker.parent('.datepicker').length) {
          nowString = now.toLocaleString().substring(0,10);
        } else {
          if (picker.parent('.datetimepicker').hasClass('default-time')) {
            now.setHours(10);
            now.setMinutes(0);
          }
          nowString = now.toLocaleString().substring(0,16).replace(' ', '     ');
        }
        picker.val(nowString);
      }

      picker.datetimepicker('show');
    });

    // on successful reminder sent, display the data received from the
    // ajax call
    $('.ao-reminder-link').on('ajax:success', function(e, data){
      $(this).after(data);
    });

    // set up the trim file upload control on the dashboard
    if ($('.trim_area').length) {
      trim_link.trimFileUpload();
    }

    // Form behaviour: checkbox and radio button CSS state changes
    $(".block-label").each(function() {
      // Add focus
      $(".block-label input").focus(function() {
          $("label[for='" + this.id + "']").addClass("add-focus");
      }).blur(function() {
          $("label").removeClass("add-focus");
      });
      // Add selected class
      $('input:checked').parent().addClass('selected');
    });

    // Form behaviour: add/remove selected class
    $('.block-label').find('input[type=radio], input[type=checkbox]').click(function() {
      $('input:not(:checked)').parent().removeClass('selected');
      $('input:checked').parent().addClass('selected');
      $('.toggle-content').hide();
      var target = $('input:checked').parent().attr('data-target');
      $('#'+target).show();
    });

    // throw a google analytics event on trim link upload from dashboard
    $('.form-add-trim-link').on('submit', function() {
      var pquin = $(this).parents('li').first().data('pquin');
      ga('send', 'event', 'trim upload from dashboard', 'submit', pquin.toString());
    });

    $('.progress-menu-form').on('submit', function() {
      var files_selected = $('#pq_trim_link_attributes_file').prop('files');
      if (files_selected.length) {
        ga('send', 'event', 'trim upload from details page', 'submit', $('h2').first().text());
      }
    });

  });

}());
<commit_msg>conflicts again<commit_after>// Externals
var trim_link, $, ga;

(function() {
  'use strict';

  // make <detail> tags toggleable
  var enableDetailsToggle = function(i, el){
    var root = $(el),
      content = root.next('.reveal');

    root.on('click', function(){
      content.toggleClass('closed');
      root.toggleClass('opened');
    });
  };

  // on the Dashboard (/dashboard), only enable the Commission button if
  // the mandatory fields are filled out
  var setCommissionButtonStatus = function(form) {
    var enable = true;
    var button = form.find('.commission-button');
    form.find('select.required-for-commission,input.required-for-commission').each(function() {
      var value = $(this).val();
      var filled = (value !== "" && value !== null);
      enable = enable && filled;
    });
    if (enable) {
      button.removeAttr('disabled');
    } else {
      button.attr('disabled', 'disabled');
    }
  };

  // 3 functions below increment, decrement of change the number of New PQ's
  // on the filter box
  var incrementBadge = function(id_of_navpill) {
    changeBadgeBy(id_of_navpill,1);
  };

  var decrementBadge = function(id_of_navpill) {
    changeBadgeBy(id_of_navpill,-1);
  };

  var changeBadgeBy = function(id_of_navpill, val) {
    var $badge = $(id_of_navpill).children('a').children('span');
    var curval = parseInt($badge.text(),10);
    var nextval = curval+val;
    if (nextval < 0) {
      nextval = 0;
    }
    $badge.text(nextval);
  };

  //==========================================================================

  $(document).ready(function () {

    // set up any date pickers on the page
    $('.datetimepicker input').datetimepicker({validateOnBlur:false,
                                               scrollMonth: false,
                                               closeOnDateSelect:true,
                                               dayOfWeekStart: 1,
                                               format:'d/m/Y     H:i'});

    // set up any datetime pickers on the page
    $('.datepicker input').datetimepicker({timepicker: false,
                                           scrollInput: false,
                                           scrollMonth: false,
                                           validateOnBlur:false,
                                           closeOnDateSelect:true,
                                           dayOfWeekStart: 1,
                                           format:'d/m/Y'});

    // enable select2 drop-boxes on various select controls
    $('.minister-select').select2({width:'250px'});
    $('.multi-select-action-officers').select2({width:'250px'});
    $('.single-select-dropdown').select2({width:'250px', allowClear: true});

    // if the page has rejection details, make them collapsible
    // applies to /assignment and /watchlist/preview pages
    $('.details-reveal').each(enableDetailsToggle);

    // on /assignment, open the reject justification form when Reject is selected
    // and hide it when Accept is selected
    $('#allocation_response_response_action_accept').on('click', function (){
      $('#reason-textarea').addClass('hide');
    });
    $('#allocation_response_response_action_reject').on('click', function (){
      $('#reason-textarea').removeClass('hide');
    });

    // on the dashboard, enable the Commission button only if the required fields are non-empty
    $('.form-commission').each(function() {
     setCommissionButtonStatus($(this));
    });

    // commisioning a question and showing the success message on the dashboard page
    $(".form-commission")
      .on("ajax:success", function(){
        // if the question was successfully commission, then hide it and replace with
        // a success message
        var pqid = $(this).data('pqid');
        var uin  = $(this).parents('*[data-pquin]').data('pquin');
        $('#pq-frame-'+pqid).replaceWith('
'+ uin +' commissioned successfully <button class="close" data-dismiss="alert">×</button>
');
        // on the right-hand filter panel, increment the number of No Eesponse questions
        incrementBadge('#db-filter-alloc-pend');
        // and decrement the number of unallocated
        decrementBadge('#db-filter-unalloc');
      }).on("ajax:error", function(e, xhr) {
        console.log(xhr.responseText);
      }).on('change', function(e) {
       // when the form is modified, check if all the mandatory fields are set
       // so that the Commission button is enabled
       setCommissionButtonStatus($(e.currentTarget));
      });

    // when clicking a calendar icon, open the calendar to the left of it
    // and if empty populate it with the current time,
    // (unless it has class default-time, in which case set time to 10:00)
    $('span.fa-calendar').on('click', function () {
      var picker = $(this).prev('input'), now, nowString;
      if (picker.val() === '') {
        now = new Date();
        if (picker.parent('.datepicker').length) {
          nowString = now.toLocaleString().substring(0,10);
        } else {
          if (picker.parent('.datetimepicker').hasClass('default-time')) {
            now.setHours(10);
            now.setMinutes(0);
          }
          nowString = now.toLocaleString().substring(0,16).replace(' ', '     ');
        }
        picker.val(nowString);
      }

      picker.datetimepicker('show');
    });

    // on successful reminder sent, display the data received from the
    // ajax call
    $('.ao-reminder-link').on('ajax:success', function(e, data){
      $(this).after(data);
    });

    // set up the trim file upload control on the dashboard
    if ($('.trim_area').length) {
      trim_link.trimFileUpload();
    }

    // Form behaviour: checkbox and radio button CSS state changes
    $(".block-label").each(function() {
      // Add focus
      $(".block-label input").focus(function() {
          $("label[for='" + this.id + "']").addClass("add-focus");
      }).blur(function() {
          $("label").removeClass("add-focus");
      });
      // Add selected class
      $('input:checked').parent().addClass('selected');
    });

    // Form behaviour: add/remove selected class
    $('.block-label').find('input[type=radio], input[type=checkbox]').click(function() {
      $('input:not(:checked)').parent().removeClass('selected');
      $('input:checked').parent().addClass('selected');
      $('.toggle-content').hide();
      var target = $('input:checked').parent().attr('data-target');
      $('#'+target).show();
    });

    // throw a google analytics event on trim link upload from dashboard
    $('.form-add-trim-link').on('submit', function() {
      var pquin = $(this).parents('li').first().data('pquin');
      ga('send', 'event', 'trim upload from dashboard', 'submit', pquin.toString());
    });

    $('.progress-menu-form').on('submit', function() {
      var files_selected = $('#pq_trim_link_attributes_file').prop('files');
      if (files_selected.length) {
        ga('send', 'event', 'trim upload from details page', 'submit', $('h2').first().text());
      }
    });

  });

}());
<|endoftext|>


<commit_before>//TODO: Comments
Minionette.Region = function(options) {
    options || (options = {});
    this.cid = _.uniqueId('subview');
    if (options.view) { this.view = options.view; }
    this._ensureView();
};

_.extend(Minionette.Region.prototype, Backbone.Events, {
    _View: Backbone.View.extend({
        tagName: 'span',
        attributes: function() {
            return {'data-cid': this.cid};
        }
    }),

    _ensureView: function() {
        this._view = (new this._View()).render();
        if (!this.view || !(this.view instanceof Backbone.View)) {
            this.view = this._view;
        }
        this._assignParent(this.view);
    },

    reset: function() {
        this.attach(this._view, true);
    },

    render: function() {
        return this.view.render();
    },

    attach: function(view, detach) {
        this._assignParent(view);

        this.view.$el.after(view.$el).detach();

        if (!detach) {
            this.view.remove();
        }
        this.view = view;

        return view;
    },

    remove: function() {
        var oldView = this.view;

        this.reset();
        oldView.remove();

        return oldView;
    },

    detach: function() {
        this._detachedView = this.view;
        this.reset();

        return this;
    },

    reattach: function($context) {
        $context = $context || Backbone.$(document.body);
        var viewSelector = '[data-cid=' + this.view.cid + ']',
            newView = this._detachedView;

        $context.find(viewSelector).replaceWith(newView.$el);

        delete this._detachedView;
        this.view = newView;

        return newView;
    },

    _removeView: function(view) {
        if (this.view === view) {
            this.reset();
        }
    },

    _assignParent: function(view) {
        view._parent = this;
    }
});
<commit_msg>Make Region extendable<commit_after>//TODO: Comments
Minionette.Region = function(options) {
    options || (options = {});
    this.cid = _.uniqueId('subview');
    if (options.view) { this.view = options.view; }
    this._ensureView();
};

Minionette.Region.extend = Backbone.View.extend;

_.extend(Minionette.Region.prototype, Backbone.Events, {
    _View: Backbone.View.extend({
        tagName: 'span',
        attributes: function() {
            return {'data-cid': this.cid};
        }
    }),

    _ensureView: function() {
        this._view = (new this._View()).render();
        if (!this.view || !(this.view instanceof Backbone.View)) {
            this.view = this._view;
        }
        this._assignParent(this.view);
    },

    reset: function() {
        this.attach(this._view, true);
    },

    render: function() {
        return this.view.render();
    },

    attach: function(view, detach) {
        this._assignParent(view);

        this.view.$el.after(view.$el).detach();

        if (!detach) {
            this.view.remove();
        }
        this.view = view;

        return view;
    },

    remove: function() {
        var oldView = this.view;

        this.reset();
        oldView.remove();

        return oldView;
    },

    detach: function() {
        this._detachedView = this.view;
        this.reset();

        return this;
    },

    reattach: function($context) {
        $context = $context || Backbone.$(document.body);
        var viewSelector = '[data-cid=' + this.view.cid + ']',
            newView = this._detachedView;

        $context.find(viewSelector).replaceWith(newView.$el);

        delete this._detachedView;
        this.view = newView;

        return newView;
    },

    _removeView: function(view) {
        if (this.view === view) {
            this.reset();
        }
    },

    _assignParent: function(view) {
        view._parent = this;
    }
});
<|endoftext|>


<commit_before>
/* This defines a function which turns off every light by removing the "on" class from the HTML elements.*/

var TERMS = document.getElementsByClassName("term");

function allOff() {
  for (var i=0; i<TERMS.length; i = i+1) {
    TERMS[i].classList.remove("on");
  }
}

/*var ID = document.getElementByID("program");

#function allOff() {
 # for (var i=0; i<ID.length; i = i+1) {
  #  ID[i].classList.remove("on");
  #}
#}/*
/* This defines a function which first turns off every light and then immediately turns one on.*/
function switchTerm(termNumber) {
  allOff();
  var term = TERMS[termNumber];
  term.classList.add("on");
}
console.log(TERMS);
<commit_msg>Update lights.js<commit_after>
/* This defines a function which turns off every light by removing the "on" class from the HTML elements.*/

var TERMS = document.getElementsByClassName("term");

function allOff() {
  for (var i=0; i<TERMS.length; i = i+1) {
    TERMS[i].classList.remove("on");
  }
}

/*var ID = document.getElementByID("program");

#function allOff() {
 # for (var i=0; i<ID.length; i = i+1) {
  #  ID[i].classList.remove("on");
  #}
#}/*
/* This defines a function which first turns off every light and then immediately turns one on.*/

function switchTerm(termNumber) {
  allOff();
  var term = TERMS[termNumber];
  term.classList.add("on");
}

/*function switchTerm(termName) {
  allOff();
  var term = TERMS[termName];
  term.classList.add("on");
}
*/

console.log(TERMS);
<|endoftext|>


<commit_before>'use strict';

app.service('exportService', ['constantService', function(constants){

                //for timing
                //var seconds = new Date().getTime() / 1000;

                var dataExport = {};

                dataExport.downloadCSV = function(volume){

                    volume.get(['records', 'containers']).then(function(data){
                        createCSV(data);

                    });

                };

                function createCSV(data){

                    console.log(constants.category);
                    console.log(constants.metric);

                    var payload = '';

                    var array = typeof data !== 'object' ? JSON.parse(data) : data;

                    var containers = array.containers;
                    var records = array.records;

                    var baseHeaders = [
                        'session id',
                        'session date'
                    ];

                    var headerIdx = makeHeaderIndex(records, constants.metric);
                    var headerRef = sortHeaderIdx(makeHeaderIndex(records, constants.metric)); //not used
                    var hRef = makeHeaderRef(headerRef);
                    var moreHeaders = makeHeadersText(headerRef);

                    console.log(hRef);

                    var header = baseHeaders.concat(moreHeaders).join(',');

                    console.log(containers);
                    console.log(records);

                    /*create CSV body data*/
                    var body = createCSVBody(containers, records, hRef, headerIdx);

                    payload = header + '\n' + body;

                    createPayload(payload);

                }

                function createCSVBody(containers, records, headerReference, headerIndex){

                  console.log(headerReference);

                  var headerCats = Object.keys(headerIndex);

                  var body = '';

                  for(var k in containers){
                    if(containers[k].top !== true && containers[k].records.length !== 0){ //exclude materials for now

                      var ssRow = [];

                      ssRow.push(containers[k].id);
                      ssRow.push(containers[k].date);

                      for(var l = 0; l < headerReference.length; l++ ){

                       var cellCat = headerReference[l].category;
                       var cellMet = headerReference[l].metric.toString();

                       //ssRow.push(cellCat + "|" + cellMet);

                       for (var j in containers[k].records){

                        var recID = containers[k].records[j].id;
                        if(records[recID].category === cellCat){
                          for(var m in records[recID].measures){
                           console.log(typeof(cellMet));
                           console.log(typeof(records[recID].measures[m]));
                            if (records[recID].measures[m] == cellMet){
                             ssRow.push(records[recID].measures[m]);
                             break;
                           } else {
                               ssRow.push('');
                               break;
                            } continue;
                         }

                        } else {
                            ssRow.push('');
                            break;
                        }

                       }
                       /*for(var j in containers[k].records){

                        var recID = containers[k].records[j].id;

                          //if (headerCats.indexOf('-800') !== -1){ //not preferred to check for this one exactly.

                          //  if(records[recID].category === -800){
                          //      ssRow.push('Pilot');
                          //    } else {
                          //      ssRow.push('');

                          //  }
                          //}

                          var recCat = records[recID].category;

                          if(recCat === cellCat){
                            for(var m in records[recID].measures){
                              if(records[recID].measures[m] === cellMet){
                               ssRow.push(records[recID].measures[cellMet]);
                             } else {

                              ssRow.push('');
                             }
                            }
                          } else {
                            ssRow.push('');
                          }

                        } */

                      }

                    body += ssRow.join(',') + '\n';
                  }
                }
                return body;
              }

              function createPayload(payload){

                    var filename = 'download.csv';
                    var uri = 'data:text/csv;charset=utf-8,' + encodeURI(payload);

                    var link = document.createElement('a');
                    link.href = uri;

                    link.style = "visibility:hidden";
                    link.download = filename;

                    document.body.appendChild(link);
                    link.click();
                    document.body.removeChild(link);

                    //var timenow = new Date().getTime() / 1000;
                    //var timeto = (timenow - seconds);

                    //console.log("That took: " + timeto + " seconds");
                }

                /*--------------object manipulation functions-----------------*/

                function getIndex(recObj){ //DELETEME
                  var index = [];
                  for(var k in recObj){
                    if(index.indexOf(k) === -1){
                      index.push(k);
                    }

                  }

                  return index.sort().reverse();

                }

                function makeHeaderRef(headerIndexArr){

                  var output = [];

                  headerIndexArr.forEach(function(item){

                  var catID = constants.category[item.category].id;

                  if(item.metrics.length < 1){ //this is not future proof, may want to visit the data model.
                    output.push({"category": catID, "metric": ''});
                  }

                  item.metrics.forEach(function(m){
                    var metID = constants.metric[m].id;

                    output.push({"category": catID, "metric": metID});
                  });

                  });

                  return output;

                }

                 function makeHeadersText(headerIndexArr){

                  var output = [];

                  headerIndexArr.forEach(function(item){

                    var catText = constants.category[item.category].name;

                    if(item.metrics.length < 1){ //this is not future proof, may want to visit the data model.
                      output.push(catText);
                    }

                    item.metrics.forEach(function(m){
                      var metText = constants.metric[m].name;

                      output.push(catText + ' ' + metText);
                    });

                  });

                  return output;

                }

                function makeHeaderIndex(recObj, metrics){
                    var tableObj = {};

                    for(var key in recObj){

                      var cat = recObj[key].category;

                      tableObj[cat] = {};

                      for(var i in recObj[key].measures){

                        tableObj[cat][i] = metrics[i].name;

                      }
                    }

                    return tableObj;

                }

                function sortHeaderIdx(headerIdx){

                  var newIdx = [];

                  var catKeysSorted = Object.keys(headerIdx).sort().reverse();

                  for(var v = 0; v < catKeysSorted.length; v++){

                    var metKeysSorted = Object.keys(headerIdx[catKeysSorted[v]]).sort().reverse();
                    var metricsArrSorted = [];

                    for(var m = 0; m < metKeysSorted.length; m++){

                      metricsArrSorted.push(metKeysSorted[m]);

                    }
                     newIdx.push({"category": catKeysSorted[v], "metrics": metricsArrSorted});
                  }

                  return newIdx;

                }

               return dataExport;
            }

    ]);
<commit_msg>saving progress<commit_after>'use strict';

app.service('exportService', ['constantService', function(constants){

                //for timing
                //var seconds = new Date().getTime() / 1000;

                var dataExport = {};

                dataExport.downloadCSV = function(volume){

                    volume.get(['records', 'containers']).then(function(data){
                        createCSV(data);

                    });

                };

                function createCSV(data){

                    console.log(constants.category);
                    console.log(constants.metric);

                    var payload = '';

                    var array = typeof data !== 'object' ? JSON.parse(data) : data;

                    var containers = array.containers;
                    var records = array.records;

                    var baseHeaders = [
                        'session id',
                        'session date'
                    ];

                    var headerIdx = makeHeaderIndex(records, constants.metric);
                    var headerRef = sortHeaderIdx(makeHeaderIndex(records, constants.metric)); //not used
                    var hRef = makeHeaderRef(headerRef);
                    var moreHeaders = makeHeadersText(headerRef);

                    console.log(hRef);

                    var header = baseHeaders.concat(moreHeaders).join(',');

                    console.log(containers);
                    console.log(records);

                    /*create CSV body data*/
                    var body = createCSVBody(containers, records, hRef, headerIdx);

                    payload = header + '\n' + body;

                    createPayload(payload);

                }

                function createCSVBody(containers, records, headerReference, headerIndex){

                  console.log(headerReference);

                  var headerCats = Object.keys(headerIndex);

                  var body = '';

                  for(var k in containers){
                    if(containers[k].top !== true && containers[k].records.length !== 0){ //exclude materials for now

                      var ssRow = [];

                      ssRow.push(containers[k].id);
                      ssRow.push(containers[k].date);

                      for(var l = 0; l < headerReference.length; l++ ){

                       var cellCat = headerReference[l].category;
                       var cellMet = headerReference[l].metric.toString();

                       for (var j in containers[k].records){

                        var recID = containers[k].records[j].id;
                        var recMetrics = Object.keys(records[recID].measures).sort().reverse();

                        if(records[recID].category === cellCat){

                             ssRow.push(records[recID].measures[cellMet]);
                             break;

                        } else {
                            ssRow.push(cellCat +'|'+ cellMet + '|' + recID);
                            break;
                        }

                       }
                       /*for(var j in containers[k].records){

                        var recID = containers[k].records[j].id;

                          //if (headerCats.indexOf('-800') !== -1){ //not preferred to check for this one exactly.

                          //  if(records[recID].category === -800){
                          //      ssRow.push('Pilot');
                          //    } else {
                          //      ssRow.push('');

                          //  }
                          //}

                          var recCat = records[recID].category;

                          if(recCat === cellCat){
                            for(var m in records[recID].measures){
                              if(records[recID].measures[m] === cellMet){
                               ssRow.push(records[recID].measures[cellMet]);
                             } else {

                              ssRow.push('');
                             }
                            }
                          } else {
                            ssRow.push('');
                          }

                        } */

                      }

                    body += ssRow.join(',') + '\n';
                  }
                }
                return body;
              }

              function createPayload(payload){

                    var filename = 'download.csv';
                    var uri = 'data:text/csv;charset=utf-8,' + encodeURI(payload);

                    var link = document.createElement('a');
                    link.href = uri;

                    link.style = "visibility:hidden";
                    link.download = filename;

                    document.body.appendChild(link);
                    link.click();
                    document.body.removeChild(link);

                    //var timenow = new Date().getTime() / 1000;
                    //var timeto = (timenow - seconds);

                    //console.log("That took: " + timeto + " seconds");
                }

                /*--------------object manipulation functions-----------------*/

                function getIndex(recObj){ //DELETEME
                  var index = [];
                  for(var k in recObj){
                    if(index.indexOf(k) === -1){
                      index.push(k);
                    }

                  }

                  return index.sort().reverse();

                }

                function makeHeaderRef(headerIndexArr){

                  var output = [];

                  headerIndexArr.forEach(function(item){

                  var catID = constants.category[item.category].id;

                  if(item.metrics.length < 1){ //this is not future proof, may want to visit the data model.
                    output.push({"category": catID, "metric": ''});
                  }

                  item.metrics.forEach(function(m){
                    var metID = constants.metric[m].id;

                    output.push({"category": catID, "metric": metID});
                  });

                  });

                  return output;

                }

                 function makeHeadersText(headerIndexArr){

                  var output = [];

                  headerIndexArr.forEach(function(item){

                    var catText = constants.category[item.category].name;

                    if(item.metrics.length < 1){ //this is not future proof, may want to visit the data model.
                      output.push(catText);
                    }

                    item.metrics.forEach(function(m){
                      var metText = constants.metric[m].name;

                      output.push(catText + ' ' + metText);
                    });

                  });

                  return output;

                }

                function makeHeaderIndex(recObj, metrics){
                    var tableObj = {};

                    for(var key in recObj){

                      var cat = recObj[key].category;

                      tableObj[cat] = {};

                      for(var i in recObj[key].measures){

                        tableObj[cat][i] = metrics[i].name;

                      }
                    }

                    return tableObj;

                }

                function sortHeaderIdx(headerIdx){

                  var newIdx = [];

                  var catKeysSorted = Object.keys(headerIdx).sort().reverse();

                  for(var v = 0; v < catKeysSorted.length; v++){

                    var metKeysSorted = Object.keys(headerIdx[catKeysSorted[v]]).sort().reverse();
                    var metricsArrSorted = [];

                    for(var m = 0; m < metKeysSorted.length; m++){

                      metricsArrSorted.push(metKeysSorted[m]);

                    }
                     newIdx.push({"category": catKeysSorted[v], "metrics": metricsArrSorted});
                  }

                  return newIdx;

                }

               return dataExport;
            }

    ]);
<|endoftext|>