<commit_before>/*
 * Copyright 2009 Google 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.
 */

jstestdriver.convertToJson = function(delegate) {
  var serialize = jstestdriver.parameterSerialize
  return function(url, data, callback, type) {
    delegate(url, serialize(data), callback, type);
  };
};

jstestdriver.parameterSerialize = function(data) {
  var modifiedData = {};
  for (var key in data) {
    modifiedData[key] = JSON.stringify(data[key]);
  }
  return modifiedData;
};

jstestdriver.bind = function(context, func) {
  function bound() {
    return func.apply(context, arguments);
  };
  bound.toString = function() {
    return "bound: " + context + " to: " + func;
  }
  return bound;
};

jstestdriver.extractId = function(url) {
  return url.match(/\/id\/(\d+)\//)[1];
};

jstestdriver.createPath = function(basePath, path) {
  var prefix = basePath.match(/^(.*)\/(slave|runner|bcr)\//)[1];
  return prefix + path;
};

jstestdriver.getBrowserFriendlyName = function() {
  if (jstestdriver.jQuery.browser.safari) {
    if (navigator.userAgent.indexOf('Chrome') != -1) {
      return 'Chrome';
    }
    return 'Safari';
  } else if (jstestdriver.jQuery.browser.opera) {
    return 'Opera';
  } else if (jstestdriver.jQuery.browser.msie) {
    return 'Internet Explorer';
  } else if (jstestdriver.jQuery.browser.mozilla) {
    if (navigator.userAgent.indexOf('Firefox') != -1) {
      return 'Firefox';
    }
    return 'Mozilla';
  }
};

jstestdriver.getBrowserFriendlyVersion = function() {
  if (jstestdriver.jQuery.browser.msie) {
    if (typeof XDomainRequest != 'undefined') {
      return '8.0';
    }
  } else if (jstestdriver.jQuery.browser.safari) {
    if (navigator.appVersion.indexOf('Chrome/') != -1) {
      return navigator.appVersion.match(/Chrome\/(.*)\s/)[1];
    }
  }
  return jstestdriver.jQuery.browser.version;
};

jstestdriver.trim = function(str) {
  return str.replace(/(^\s*)|(\s*$)/g,'');
};

/**
 * Renders an html string as a dom nodes.
 * @param {string} htmlString The string to be rendered as html.
 * @param {Document} owningDocument The window that should own the html.
 */
jstestdriver.toHtml = function(htmlString, owningDocument) {
  var fragment = owningDocument.createDocumentFragment();
  var wrapper = owningDocument.createElement('div');
  wrapper.innerHTML = jstestdriver.trim(jstestdriver.stripHtmlComments(htmlString));
  while(wrapper.firstChild) {
    fragment.appendChild(wrapper.firstChild);
  }
  var ret =  fragment.childNodes.length > 1 ? fragment : fragment.firstChild;
  return ret;
};

jstestdriver.stripHtmlComments = function(htmlString) {
  var stripped = [];
  function getCommentIndices(offset) {
    var start = htmlString.indexOf('<!--', offset);
    var stop = htmlString.indexOf('-->', offset) + '-->'.length;
    if (start == -1) {
      return null;
    }
    return {
      'start' : start,
      'stop' : stop
    };
  }
  var offset = 0;
  while(true) {
    var comment = getCommentIndices(offset);
    if (!comment) {
      stripped.push(htmlString.slice(offset));
      break;
    }
    var frag = htmlString.slice(offset, comment.start);
    stripped.push(frag);
    offset = comment.stop;
  }
  return stripped.join('');
}

/**
 * Appends html string to the body.
 * @param {string} htmlString The string to be rendered as html.
 * @param {Document} owningDocument The window that should own the html.
 */
jstestdriver.appendHtml = function(htmlString, owningDocument) {
  var node = jstestdriver.toHtml(htmlString, owningDocument);
  jstestdriver.jQuery(owningDocument.body).append(node);
};

/**
 * @return {Number} The ms since the epoch.
 */
jstestdriver.now = function() { return new Date().getTime();}

/**
 * Creates a wrapper for jQuery.ajax that make a synchronous post
 * @param {jQuery} jQuery
 * @return {function(url, data):null}
 */
jstestdriver.createSynchPost = function(jQuery) {
  return jstestdriver.convertToJson(function(url, data) {
    return jQuery.ajax({
      'async' : false,
      'data' : data,
      'type' : 'POST',
      'url' : url
    });
  });
};

jstestdriver.utils = {};

jstestdriver.utils.serializeObject = function(obj) {
  var out = [];
  jstestdriver.utils.serializeObjectToArray(obj, out);
  return out.join('');
};

jstestdriver.utils.serializeObjectToArray =
   function(obj, opt_out){
  var out = opt_out || out;
  if (obj instanceof Array) {
      out.push('[');
      var arr = /** @type {Array.<Object>} */
      obj;
      for ( var i = 0; i < arr.length; i++) {
        this.serializeObjectToArray(arr[i], out);
        if (i < arr.length - 1) {
          out.push(',');
        }
      }
      out.push(']');
    } else if (obj instanceof Error) {
      out.push('{');
      out.push('"message":');
      this.serializeObjectToArray(obj.message, out);
      this.serializePropertyOnObject('name', obj, out);
      this.serializePropertyOnObject('description', obj, out);
      this.serializePropertyOnObject('fileName', obj, out);
      this.serializePropertyOnObject('lineNumber', obj, out);
      this.serializePropertyOnObject('number', obj, out);
      this.serializePropertyOnObject('stack', obj, out);
      out.push('}');
    } else {
      out.push(jstestdriver.angular.toJson(obj));
    }
    return out;
  };

jstestdriver.utils.serializePropertyOnObject = function(name, obj, out) {
  if (name in obj) {
    out.push(',');
    out.push('"' + name + '":');
    this.serializeObjectToArray(obj[name], out);
  }
};

jstestdriver.log = function(message) {
  if (jstestdriver.runConfig && jstestdriver.runConfig.debug) {
      var basePath = top.location.toString();
      var id = parseInt(jstestdriver.extractId(basePath));
      var browserInfo =  new jstestdriver.BrowserInfo(id);
      var prefix = basePath.match(/^(.*)\/(slave|runner|bcr)\//)[1];
      var url = prefix + '/log';

      jstestdriver.log = function(message) {
        try {
          var stack = new Error().stack.split('\n');
          var smallStack = [];

          for (var i = 0; stack[i]; i++) {
            var end = stack[i].indexOf('(');
            if (end > -1) {
              smallStack.push(stack[i].substr(0,end).trim());
            }R
          }
          jstestdriver.jQuery.ajax({
            'async' : true,
            data : 'logs=' + jstestdriver.utils.serializeObject([{
              'source' : 'jstestdriver.browser_' + id,
              'message' : jstestdriver.utils.serializeObject(message),
              'stack' : jstestdriver.utils.serializeObject(encodeURI(smallStack.toString())),
              'browser' : browserInfo,
              'level' : 3
            }]),
            'type' : 'POST',
            'url' : url
          });
        } catch (e) {
          if (window.console && window.console.log) {
            window.console.log(message);
          }
        }
      }
      jstestdriver.log(message);
  }
};

<commit_msg>stop sending broken JSON to the server when there is an error - preventing the broken statck traces when debugging tests<commit_after>/*
 * Copyright 2009 Google 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.
 */

jstestdriver.convertToJson = function(delegate) {
  var serialize = jstestdriver.parameterSerialize
  return function(url, data, callback, type) {
    delegate(url, serialize(data), callback, type);
  };
};

jstestdriver.parameterSerialize = function(data) {
  var modifiedData = {};
  for (var key in data) {
    modifiedData[key] = JSON.stringify(data[key]);
  }
  return modifiedData;
};

jstestdriver.bind = function(context, func) {
  function bound() {
    return func.apply(context, arguments);
  };
  bound.toString = function() {
    return "bound: " + context + " to: " + func;
  }
  return bound;
};

jstestdriver.extractId = function(url) {
  return url.match(/\/id\/(\d+)\//)[1];
};

jstestdriver.createPath = function(basePath, path) {
  var prefix = basePath.match(/^(.*)\/(slave|runner|bcr)\//)[1];
  return prefix + path;
};

jstestdriver.getBrowserFriendlyName = function() {
  if (jstestdriver.jQuery.browser.safari) {
    if (navigator.userAgent.indexOf('Chrome') != -1) {
      return 'Chrome';
    }
    return 'Safari';
  } else if (jstestdriver.jQuery.browser.opera) {
    return 'Opera';
  } else if (jstestdriver.jQuery.browser.msie) {
    return 'Internet Explorer';
  } else if (jstestdriver.jQuery.browser.mozilla) {
    if (navigator.userAgent.indexOf('Firefox') != -1) {
      return 'Firefox';
    }
    return 'Mozilla';
  }
};

jstestdriver.getBrowserFriendlyVersion = function() {
  if (jstestdriver.jQuery.browser.msie) {
    if (typeof XDomainRequest != 'undefined') {
      return '8.0';
    }
  } else if (jstestdriver.jQuery.browser.safari) {
    if (navigator.appVersion.indexOf('Chrome/') != -1) {
      return navigator.appVersion.match(/Chrome\/(.*)\s/)[1];
    }
  }
  return jstestdriver.jQuery.browser.version;
};

jstestdriver.trim = function(str) {
  return str.replace(/(^\s*)|(\s*$)/g,'');
};

/**
 * Renders an html string as a dom nodes.
 * @param {string} htmlString The string to be rendered as html.
 * @param {Document} owningDocument The window that should own the html.
 */
jstestdriver.toHtml = function(htmlString, owningDocument) {
  var fragment = owningDocument.createDocumentFragment();
  var wrapper = owningDocument.createElement('div');
  wrapper.innerHTML = jstestdriver.trim(jstestdriver.stripHtmlComments(htmlString));
  while(wrapper.firstChild) {
    fragment.appendChild(wrapper.firstChild);
  }
  var ret =  fragment.childNodes.length > 1 ? fragment : fragment.firstChild;
  return ret;
};

jstestdriver.stripHtmlComments = function(htmlString) {
  var stripped = [];
  function getCommentIndices(offset) {
    var start = htmlString.indexOf('<!--', offset);
    var stop = htmlString.indexOf('-->', offset) + '-->'.length;
    if (start == -1) {
      return null;
    }
    return {
      'start' : start,
      'stop' : stop
    };
  }
  var offset = 0;
  while(true) {
    var comment = getCommentIndices(offset);
    if (!comment) {
      stripped.push(htmlString.slice(offset));
      break;
    }
    var frag = htmlString.slice(offset, comment.start);
    stripped.push(frag);
    offset = comment.stop;
  }
  return stripped.join('');
}

/**
 * Appends html string to the body.
 * @param {string} htmlString The string to be rendered as html.
 * @param {Document} owningDocument The window that should own the html.
 */
jstestdriver.appendHtml = function(htmlString, owningDocument) {
  var node = jstestdriver.toHtml(htmlString, owningDocument);
  jstestdriver.jQuery(owningDocument.body).append(node);
};

/**
 * @return {Number} The ms since the epoch.
 */
jstestdriver.now = function() { return new Date().getTime();}

/**
 * Creates a wrapper for jQuery.ajax that make a synchronous post
 * @param {jQuery} jQuery
 * @return {function(url, data):null}
 */
jstestdriver.createSynchPost = function(jQuery) {
  return jstestdriver.convertToJson(function(url, data) {
    return jQuery.ajax({
      'async' : false,
      'data' : data,
      'type' : 'POST',
      'url' : url
    });
  });
};

jstestdriver.utils = {};

jstestdriver.utils.serializeObject = function(obj) {
  var out = [];
  jstestdriver.utils.serializeObjectToArray(obj, out);
  return out.join('');
};

jstestdriver.utils.serializeObjectToArray =
   function(obj, opt_out){
  var out = opt_out || out;
  if (obj instanceof Array) {
      out.push('[');
      var arr = /** @type {Array.<Object>} */
      obj;
      for ( var i = 0; i < arr.length; i++) {
        this.serializeObjectToArray(arr[i], out);
        if (i < arr.length - 1) {
          out.push(',');
        }
      }
      out.push(']');
    } else if (obj instanceof Error) {
      out.push('{');
      out.push('"message":');
      this.serializeObjectToArray(obj.message, out);
      this.serializePropertyOnObject('name', obj, out);
      this.serializePropertyOnObject('description', obj, out);
      this.serializePropertyOnObject('fileName', obj, out);
      this.serializePropertyOnObject('lineNumber', obj, out);
      this.serializePropertyOnObject('number', obj, out);
      this.serializePropertyOnObject('stack', obj, out);
      out.push('}');
    } else {
      out.push(jstestdriver.angular.toJson(obj));
    }
    return out;
  };

jstestdriver.utils.serializePropertyOnObject = function(name, obj, out) {
  if ((obj[name] !== null) && (obj[name] !== undefined)) {
    out.push(',');
    out.push('"' + name + '":');
    this.serializeObjectToArray(obj[name], out);
  }
};

jstestdriver.log = function(message) {
  if (jstestdriver.runConfig && jstestdriver.runConfig.debug) {
      var basePath = top.location.toString();
      var id = parseInt(jstestdriver.extractId(basePath));
      var browserInfo =  new jstestdriver.BrowserInfo(id);
      var prefix = basePath.match(/^(.*)\/(slave|runner|bcr)\//)[1];
      var url = prefix + '/log';

      jstestdriver.log = function(message) {
        try {
          var stack = new Error().stack.split('\n');
          var smallStack = [];

          for (var i = 0; stack[i]; i++) {
            var end = stack[i].indexOf('(');
            if (end > -1) {
              smallStack.push(stack[i].substr(0,end).trim());
            }R
          }
          jstestdriver.jQuery.ajax({
            'async' : true,
            data : 'logs=' + jstestdriver.utils.serializeObject([{
              'source' : 'jstestdriver.browser_' + id,
              'message' : jstestdriver.utils.serializeObject(message),
              'stack' : jstestdriver.utils.serializeObject(encodeURI(smallStack.toString())),
              'browser' : browserInfo,
              'level' : 3
            }]),
            'type' : 'POST',
            'url' : url
          });
        } catch (e) {
          if (window.console && window.console.log) {
            window.console.log(message);
          }
        }
      }
      jstestdriver.log(message);
  }
};

<|endoftext|>


<commit_before>/*
password-validation 0.1.0
A UI lib handling password validation feedback
MIT
2014-05-09
*/
        var PasswordValidation;

PasswordValidation = (function() {
  function PasswordValidation(el, validations) {
    this.el = el;
    this.validations = validations;
  }

  PasswordValidation.prototype.validations = {
    length: 0,
    lowercase: false,
    uppercase: false,
    numbers: false,
    symbols: false,
    includes: [],
    excludes: []
  };

  PasswordValidation.prototype.matchers = {
    lowercase: /[a-z]/,
    uppercase: /[A-Z]/,
    numbers: /[0-9]/,
    symbols: /[^a-zA-Z\d\s]/
  };

  PasswordValidation.prototype.validate = function() {
    var errors, excludes_errors, includes_errors, value;
    value = this.el.value;
    errors = [];
    if (this.validations.length) {
      if (!(value.length >= this.validations.length)) {
        errors.push('length');
      }
    }
    _.each(this.matchers, (function(_this) {
      return function(regex, validation) {
        if (_this.validations[validation]) {
          if (!_this.defaultRegex(_this.validations[validation], regex).test(value)) {
            return errors.push(validation);
          }
        }
      };
    })(this));
    includes_errors = _.compact(_.map(this.validations.includes, function(requirement) {
      if (!_.contains(value, requirement)) {
        return requirement;
      }
    }));
    if (includes_errors.length) {
      errors.push({
        include: includes_errors
      });
    }
    excludes_errors = _.compact(_.map(this.validations.excludes, function(requirement) {
      if (_.contains(value, requirement)) {
        return requirement;
      }
    }));
    if (excludes_errors.length) {
      errors.push({
        exclude: excludes_errors
      });
    }
    if (errors.length) {
      return errors;
    }
  };

  PasswordValidation.prototype.defaultRegex = function(regex, fallback) {
    if (regex instanceof RegExp) {
      return regex;
    } else {
      return fallback;
    }
  };

  return PasswordValidation;

})();
<commit_msg>Add dist<commit_after>/*
password-validation 0.1.0
A UI lib handling password validation feedback
MIT
2014-05-09
*/
        var PasswordValidation;

PasswordValidation = (function() {
  function PasswordValidation(el, validations) {
    this.el = el;
    this.validations = validations;
  }

  PasswordValidation.prototype.validations = {
    length: 0,
    lowercase: false,
    uppercase: false,
    numbers: false,
    symbols: false,
    includes: [],
    excludes: []
  };

  PasswordValidation.prototype.matchers = {
    lowercase: /[a-z]/,
    uppercase: /[A-Z]/,
    numbers: /[0-9]/,
    symbols: /[^a-zA-Z\d\s]/
  };

  PasswordValidation.prototype.validate = function() {
    var errors, excludes_errors, includes_errors, value;
    value = this.el.value;
    errors = [];
    if (this.validations.length) {
      if (!(value.length >= this.validations.length)) {
        errors.push('length');
      }
    }
    _.each(this.matchers, (function(_this) {
      return function(regex, validation) {
        if (_this.validations[validation]) {
          if (!_this.defaultRegex(_this.validations[validation], regex).test(value)) {
            return errors.push(validation);
          }
        }
      };
    })(this));
    includes_errors = _.compact(_.map(this.validations.includes, function(requirement) {
      if (!_.contains(value, requirement)) {
        return requirement;
      }
    }));
    if (includes_errors.length) {
      errors.push({
        include: includes_errors
      });
    }
    excludes_errors = _.compact(_.map(this.validations.excludes, function(requirement) {
      if (_.contains(value, requirement)) {
        return requirement;
      }
    }));
    if (excludes_errors.length) {
      errors.push({
        exclude: excludes_errors
      });
    }
    return errors;
  };

  PasswordValidation.prototype.defaultRegex = function(regex, fallback) {
    if (regex instanceof RegExp) {
      return regex;
    } else {
      return fallback;
    }
  };

  return PasswordValidation;

})();
<|endoftext|>


<commit_before>var wxs3 = wxs3 || {};

(function (ns) {
    'use strict';

    //check WebGL
    if (!window.WebGLRenderingContext) {
        // the browser doesn't even know what WebGL is
        window.location = "http://get.webgl.org";
    }

    //utility func to convert dict of {key: "val", key2: "val2"} to key=val&key2=val2
    function urlformat(values) {
        var res = [], key;
        for (key in values) {
            if (values.hasOwnProperty(key)) {
                var value = values[key];
                res.push(key + '=' + value);
            }
        }
        return res.join('&');
    }

    var WCSTile = function (dim, tileNr, bounds) {
        this.dim = dim;
        this.tileNr = tileNr;
        this.bounds = bounds;
        this.loaded = false;
    };

    WCSTile.prototype.getWcsBbox = function () {
        return [
            parseInt(this.bounds.minx, 10),
            parseInt(this.bounds.miny - this.dim.proportionHeight, 10),
            parseInt(this.bounds.maxx + this.dim.proportionWidth, 10),
            parseInt(this.bounds.maxy, 10)
        ].join(',');
    };

    WCSTile.prototype.load = function (callback) {

        this.callback = callback;

        var params = {
            SERVICE: 'WCS',
            VERSION: '1.0.0',
            REQUEST: 'GetCoverage',
            FORMAT: 'XYZ',
            COVERAGE: this.dim.coverage,
            bbox: this.getWcsBbox(),
            CRS: this.dim.crs,
            RESPONSE_CRS: this.dim.crs,
            WIDTH: parseInt(this.dim.demWidth, 10),
            HEIGHT: parseInt(this.dim.demHeight, 10)
        };

        var url = this.dim.wcsUrl + '?' + urlformat(params);

        var demTileRequest = new XMLHttpRequest();
        demTileRequest.open('GET', url, true);

        var that = this;
        demTileRequest.onreadystatechange = function () {
            if (this.readyState === 4) {
                that.demTileLoaded(this.responseText);
            }
        };
        demTileRequest.send();

        //allows chaining
        return this;
    };

    WCSTile.prototype.createGeometry = function (xyzlines) {

        var geometry = new THREE.PlaneGeometry(
            this.bounds.maxx - this.bounds.minx,
            this.bounds.maxy - this.bounds.miny,
            (this.dim.demWidth - 1),
            (this.dim.demHeight - 1)
        );

        var i, length = geometry.vertices.length;
        for (i = 0; i < length; i = i + 1) {
            var line = xyzlines[i].split(' ');
            geometry.vertices[i].x = line[0];
            geometry.vertices[i].y = line[1];
            geometry.vertices[i].z = line[2] ;
        }
        return geometry;
    };

    WCSTile.prototype.getWmsBbox = function () {

        var lastIndex = this.geometry.vertices.length - 1;

        var firstVertex = this.geometry.vertices[0];
        var lastVertex = this.geometry.vertices[lastIndex];
        return [
            firstVertex.x,
            lastVertex.y,
            lastVertex.x,
            firstVertex.y
        ].join(',');
    };

    WCSTile.prototype.demTileLoaded = function (responseText) {
        this.geometry = this.createGeometry(responseText.split("\n"));

        this.plane = new THREE.Mesh(
            this.geometry,
            this.createMaterial()
        );
        this.plane.name = 'tile_' + this.tileNr;
        this.plane.scale.z=dim.zMult;
        this.loaded = true; //not used yet
        this.callback(this);
    };

    WCSTile.prototype.createMaterial = function () {
        var params = {
            service: 'wms',
            version: '1.3.0',
            request: 'getmap',
            crs: this.dim.crs,
            srs: this.dim.crs,
            WIDTH: this.dim.demWidth * this.dim.wmsMult,
            HEIGHT: this.dim.demHeight * this.dim.wmsMult,
            bbox: this.getWmsBbox(),
            layers: this.dim.wmsLayers,
            format: this.dim.wmsFormat + this.dim.wmsFormatMode
        };

        var material = new THREE.MeshPhongMaterial(
            {
                map: THREE.ImageUtils.loadTexture(
                    this.dim.wmsUrl + '?' + urlformat(params),
                    new THREE.UVMapping()
                )
            }
        );
        material.name = 'material_' + this.tileNr;
        return material;
    };

    ns.ThreeDMap = function (layers, dim) {

        this.dim = dim;
        this.camera = null;
        this.scene = null;
        this.renderer = null;
        this.controls = null;

        //TODO: these shpuld be moved to separate functions to improve
        //readability. I'm not quite certain how to name these functions
        if (dim.metersWidth > dim.metersHeight) {
            var widthHeightRatio = dim.metersWidth / dim.metersHeight;
            dim.demWidth = parseInt(widthHeightRatio * dim.demWidth, 10);
        } else if (dim.metersWidth < dim.metersHeight) {
            var heightWidthRatio = dim.metersHeight / dim.metersWidth;
            dim.demHeight = parseInt(heightWidthRatio * dim.demHeight, 10);
        }

        // mapunits between vertexes in x-dimension
        dim.proportionWidth = dim.metersWidth / dim.demWidth;

        // mapunits between vertexes in y-dimension
        dim.proportionHeight = dim.metersHeight / dim.demHeight;

        this.dim.wmsLayers = layers;

        this.createRenderer();
        this.createScene();
        this.createCamera();
        this.createControls();

        // Generate tiles and boundingboxes
        this.bbox2tiles(this.dim.getBounds());
        document.getElementById('webgl').appendChild(this.renderer.domElement);
    };

    ns.ThreeDMap.prototype.createRenderer = function () {
        this.renderer = new THREE.WebGLRenderer();
        this.renderer.setSize(this.dim.width, this.dim.height);
    };

    ns.ThreeDMap.prototype.createScene = function () {
        this.scene = new THREE.Scene();
        this.scene.add(new THREE.AmbientLight(0xeeeeee));
    };

    ns.ThreeDMap.prototype.createCamera = function () {
        var fov = 45;
        this.camera = new THREE.PerspectiveCamera(
            fov,
            this.dim.width / this.dim.height,
            0.1,
            50000
        );
        // Some trig to find height for camera
        var cameraHeight;
        if (this.dim.Z) {
            cameraHeight = this.dim.Z;
        } else {
            cameraHeight = (this.dim.metersHeight / 2) / Math.tan((fov / 2) * Math.PI / 180);
        }
        // Place camera in middle of bbox
        var centerX = (this.dim.minx + this.dim.maxx) / 2;
        var centerY = (this.dim.miny + this.dim.maxy) / 2;
        this.camera.position.set(centerX, centerY, cameraHeight);
    };

    ns.ThreeDMap.prototype.createControls = function () {
        this.controls = new THREE.TrackballControls(this.camera);
        // Point camera directly down
        var centerX = (this.dim.minx + this.dim.maxx) / 2;
        var centerY = (this.dim.miny + this.dim.maxy) / 2;
        this.controls.target = new THREE.Vector3(centerX, centerY, 0);
    };

    ns.ThreeDMap.prototype.render = function () {
        this.controls.update();
        window.requestAnimationFrame(this.render.bind(this));
        this.renderer.render(this.scene, this.camera);
    };

    ns.ThreeDMap.prototype.bbox2tiles = function (bounds) {
        //TODO: generic tilematrix-parsing
        // Proof of concept with 2 subdivision in each dimension:

        this.tiles = [];

        //0,0
        this.tiles.push(
            new WCSTile(this.dim, 'x0_y0', {
                minx: bounds.minx,
                miny: bounds.miny,
                maxx: (bounds.minx + bounds.maxx) / 2,
                maxy: (bounds.miny + bounds.maxy) / 2
            }).load(this.tileLoaded.bind(this))
        );

        //1,0
        this.tiles.push(
            new WCSTile(this.dim, 'x1_y0', {
                minx: (bounds.minx + bounds.maxx) / 2,
                miny: bounds.miny,
                maxx: bounds.maxx,
                maxy: (bounds.miny + bounds.maxy) / 2
            }).load(this.tileLoaded.bind(this))
        );

        //0,1
        this.tiles.push(
            new WCSTile(this.dim, 'x0_y1', {
                minx: bounds.minx,
                miny: (bounds.miny + bounds.maxy) / 2,
                maxx: (bounds.minx + bounds.maxx) / 2,
                maxy: bounds.maxy
            }).load(this.tileLoaded.bind(this))
        );

        //1,1
        this.tiles.push(
            new WCSTile(this.dim, 'x1_y1', {
                minx: (bounds.minx + bounds.maxx) / 2,
                miny: (bounds.miny + bounds.maxy) / 2,
                maxx: bounds.maxx,
                maxy: bounds.maxy
            }).load(this.tileLoaded.bind(this))
        );
    };

    ns.ThreeDMap.prototype.tileLoaded = function (tile) {
        this.scene.add(tile.plane);
        this.render();
    };

    // extraction for URL parameters
    function getQueryVariable(variable) {
        var pair, i;
        var query = window.location.search.substring(1);
        var vars = query.split("&");
        for (i = 0; i < vars.length; i = i + 1) {
            pair = vars[i].split("=");
            if (pair[0].toUpperCase() === variable) {
                return pair[1];
            }
        }
        return false;
    }

    ns.Dim = {
        width: window.innerWidth,
        height: window.innerHeight,
        demWidth: getQueryVariable("WIDTH") || 100,
        demHeight: getQueryVariable("HEIGHT") || 100,
        bbox: getQueryVariable("BBOX") || '161244,6831251,171526,6837409',
        metersWidth: 0,
        metersHeight: 0,
        minx: 0,
        maxx: 0,
        miny: 0,
        maxy: 0,
        getBounds: function () {
            return {
                minx: this.minx,
                miny: this.miny,
                maxx: this.maxx,
                maxy: this.maxy
            };
        },
        init: function () {
            var splitBbox = this.bbox.split(',');
            this.metersWidth = splitBbox[2] - splitBbox[0];
            this.metersHeight = splitBbox[3] - splitBbox[1];
            this.minx = parseInt(splitBbox[0], 10);
            this.maxx = parseInt(splitBbox[2], 10);
            this.miny = parseInt(splitBbox[1], 10);
            this.maxy = parseInt(splitBbox[3], 10);

            if (getQueryVariable("WMSFORMATMODE")) {
                this.wmsFormatMode = '; mode=' + getQueryVariable("WMSFORMATMODE");
            }
            return this;
        },
        crs: getQueryVariable("CRS") || getQueryVariable("SRS") || 'EPSG:32633',
        coverage: getQueryVariable("COVERAGE") || 'land_utm33_10m',
        wmsUrl: getQueryVariable("WMS") || 'http://openwms.statkart.no/skwms1/wms.topo2',
        wcsUrl: 'http://openwms.statkart.no/skwms1/wcs.dtm',
        wmsMult: getQueryVariable("WMSMULT") || 5,
        wmsFormat: getQueryVariable("WMSFORMAT") || "image/png",
        wmsFormatMode: "",
        zMult: getQueryVariable("ZMULT")||1,
        Z: getQueryVariable("Z") || null,
        proportionWidth: 0,
        proportionHeight: 0
    };

    var dim = ns.Dim.init();
    var wmsLayers = getQueryVariable("LAYERS") || layers;
    var threeDMap = new ns.ThreeDMap(wmsLayers, dim);

}(wxs3));<commit_msg>capabilities-parsing v1<commit_after>var wxs3 = wxs3 || {};

(function (ns) {
    'use strict';

    //check WebGL
    if (!window.WebGLRenderingContext) {
        // the browser doesn't even know what WebGL is
        window.location = "http://get.webgl.org";
    }

    //utility func to convert dict of {key: "val", key2: "val2"} to key=val&key2=val2
    function urlformat(values) {
        var res = [], key;
        for (key in values) {
            if (values.hasOwnProperty(key)) {
                var value = values[key];
                res.push(key + '=' + value);
            }
        }
        return res.join('&');
    }

    var WCSTile = function (dim, tileNr, bounds) {
        this.dim = dim;
        this.tileNr = tileNr;
        this.bounds = bounds;
        this.loaded = false;
    };

    WCSTile.prototype.getWcsBbox = function () {
        return [
            parseInt(this.bounds.minx, 10),
            parseInt(this.bounds.miny - this.dim.proportionHeight, 10),
            parseInt(this.bounds.maxx + this.dim.proportionWidth, 10),
            parseInt(this.bounds.maxy, 10)
        ].join(',');
    };

    WCSTile.prototype.load = function (callback) {

        this.callback = callback;

        var params = {
            SERVICE: 'WCS',
            VERSION: '1.0.0',
            REQUEST: 'GetCoverage',
            FORMAT: 'XYZ',
            COVERAGE: this.dim.coverage,
            bbox: this.getWcsBbox(),
            CRS: this.dim.crs,
            RESPONSE_CRS: this.dim.crs,
            WIDTH: parseInt(this.dim.demWidth, 10),
            HEIGHT: parseInt(this.dim.demHeight, 10)
        };

        var url = this.dim.wcsUrl + '?' + urlformat(params);

        var demTileRequest = new XMLHttpRequest();
        demTileRequest.open('GET', url, true);

        var that = this;
        demTileRequest.onreadystatechange = function () {
            if (this.readyState === 4) {
                that.demTileLoaded(this.responseText);
            }
        };
        demTileRequest.send();

        //allows chaining
        return this;
    };

    WCSTile.prototype.createGeometry = function (xyzlines) {

        var geometry = new THREE.PlaneGeometry(
            this.bounds.maxx - this.bounds.minx,
            this.bounds.maxy - this.bounds.miny,
            (this.dim.demWidth - 1),
            (this.dim.demHeight - 1)
        );

        var i, length = geometry.vertices.length;
        for (i = 0; i < length; i = i + 1) {
            var line = xyzlines[i].split(' ');
            geometry.vertices[i].x = line[0];
            geometry.vertices[i].y = line[1];
            geometry.vertices[i].z = line[2] ;
        }
        return geometry;
    };

    WCSTile.prototype.getWmsBbox = function () {

        var lastIndex = this.geometry.vertices.length - 1;

        var firstVertex = this.geometry.vertices[0];
        var lastVertex = this.geometry.vertices[lastIndex];
        return [
            firstVertex.x,
            lastVertex.y,
            lastVertex.x,
            firstVertex.y
        ].join(',');
    };

    WCSTile.prototype.demTileLoaded = function (responseText) {
        this.geometry = this.createGeometry(responseText.split("\n"));

        this.plane = new THREE.Mesh(
            this.geometry,
            this.createMaterial()
        );
        this.plane.name = 'tile_' + this.tileNr;
        this.plane.scale.z=dim.zMult;
        this.loaded = true; //not used yet
        this.callback(this);
    };

    WCSTile.prototype.createMaterial = function () {
        var params = {
            service: 'wms',
            version: '1.3.0',
            request: 'getmap',
            crs: this.dim.crs,
            srs: this.dim.crs,
            WIDTH: this.dim.demWidth * this.dim.wmsMult,
            HEIGHT: this.dim.demHeight * this.dim.wmsMult,
            bbox: this.getWmsBbox(),
            layers: this.dim.wmsLayers,
            format: this.dim.wmsFormat + this.dim.wmsFormatMode
        };

        var material = new THREE.MeshPhongMaterial(
            {
                map: THREE.ImageUtils.loadTexture(
                    this.dim.wmsUrl + '?' + urlformat(params),
                    new THREE.UVMapping()
                )
            }
        );
        material.name = 'material_' + this.tileNr;
        return material;
    };

    ns.ThreeDMap = function (layers, dim) {

        this.dim = dim;
        this.camera = null;
        this.scene = null;
        this.renderer = null;
        this.controls = null;

        //TODO: these shpuld be moved to separate functions to improve
        //readability. I'm not quite certain how to name these functions
        if (dim.metersWidth > dim.metersHeight) {
            var widthHeightRatio = dim.metersWidth / dim.metersHeight;
            dim.demWidth = parseInt(widthHeightRatio * dim.demWidth, 10);
        } else if (dim.metersWidth < dim.metersHeight) {
            var heightWidthRatio = dim.metersHeight / dim.metersWidth;
            dim.demHeight = parseInt(heightWidthRatio * dim.demHeight, 10);
        }

        // mapunits between vertexes in x-dimension
        dim.proportionWidth = dim.metersWidth / dim.demWidth;

        // mapunits between vertexes in y-dimension
        dim.proportionHeight = dim.metersHeight / dim.demHeight;

        this.dim.wmsLayers = layers;

        this.createRenderer();
        this.createScene();
        this.createCamera();
        this.createControls();

        // Generate tiles and boundingboxes
        this.bbox2tiles(this.dim.getBounds());
        document.getElementById('webgl').appendChild(this.renderer.domElement);
    };

    ns.ThreeDMap.prototype.createRenderer = function () {
        this.renderer = new THREE.WebGLRenderer();
        this.renderer.setSize(this.dim.width, this.dim.height);
    };

    ns.ThreeDMap.prototype.createScene = function () {
        this.scene = new THREE.Scene();
        this.scene.add(new THREE.AmbientLight(0xeeeeee));
    };

    ns.ThreeDMap.prototype.createCamera = function () {
        var fov = 45;
        this.camera = new THREE.PerspectiveCamera(
            fov,
            this.dim.width / this.dim.height,
            0.1,
            50000
        );
        // Some trig to find height for camera
        var cameraHeight;
        if (this.dim.Z) {
            cameraHeight = this.dim.Z;
        } else {
            cameraHeight = (this.dim.metersHeight / 2) / Math.tan((fov / 2) * Math.PI / 180);
        }
        // Place camera in middle of bbox
        var centerX = (this.dim.minx + this.dim.maxx) / 2;
        var centerY = (this.dim.miny + this.dim.maxy) / 2;
        this.camera.position.set(centerX, centerY, cameraHeight);
    };

    ns.ThreeDMap.prototype.createControls = function () {
        this.controls = new THREE.TrackballControls(this.camera);
        // Point camera directly down
        var centerX = (this.dim.minx + this.dim.maxx) / 2;
        var centerY = (this.dim.miny + this.dim.maxy) / 2;
        this.controls.target = new THREE.Vector3(centerX, centerY, 0);
    };

    ns.ThreeDMap.prototype.render = function () {
        this.controls.update();
        window.requestAnimationFrame(this.render.bind(this));
        this.renderer.render(this.scene, this.camera);
    };

    ns.ThreeDMap.prototype.bbox2tiles = function (bounds) {
        //TODO: generic tilematrix-parsing
        // Proof of concept with 2 subdivision in each dimension:

	var capabilitiesURL='http://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?Version=1.0.0&service=wmts&request=getcapabilities';
	var client = new XMLHttpRequest();
	var tileMatrixSet={};
	client.open('GET', capabilitiesURL);
	client.onreadystatechange = function() {
		if (this.readyState === 4) {
			// Start timing
			console.time('capabilities parsing');
			var capabilitiesText=client.responseText;
			var capabilitiesXml=txt2xml(capabilitiesText);
			tileMatrixSet=parseCapabilities(capabilitiesXml);
			console.log(tileMatrixSet);
            }
	}
	client.send();

        this.tiles = [];

        //0,0
        this.tiles.push(
            new WCSTile(this.dim, 'x0_y0', {
                minx: bounds.minx,
                miny: bounds.miny,
                maxx: (bounds.minx + bounds.maxx) / 2,
                maxy: (bounds.miny + bounds.maxy) / 2
            }).load(this.tileLoaded.bind(this))
        );

        //1,0
        this.tiles.push(
            new WCSTile(this.dim, 'x1_y0', {
                minx: (bounds.minx + bounds.maxx) / 2,
                miny: bounds.miny,
                maxx: bounds.maxx,
                maxy: (bounds.miny + bounds.maxy) / 2
            }).load(this.tileLoaded.bind(this))
        );

        //0,1
        this.tiles.push(
            new WCSTile(this.dim, 'x0_y1', {
                minx: bounds.minx,
                miny: (bounds.miny + bounds.maxy) / 2,
                maxx: (bounds.minx + bounds.maxx) / 2,
                maxy: bounds.maxy
            }).load(this.tileLoaded.bind(this))
        );

        //1,1
        this.tiles.push(
            new WCSTile(this.dim, 'x1_y1', {
                minx: (bounds.minx + bounds.maxx) / 2,
                miny: (bounds.miny + bounds.maxy) / 2,
                maxx: bounds.maxx,
                maxy: bounds.maxy
            }).load(this.tileLoaded.bind(this))
        );
    };

    ns.ThreeDMap.prototype.tileLoaded = function (tile) {
        this.scene.add(tile.plane);
        this.render();
    };

    // extraction for URL parameters
    function getQueryVariable(variable) {
        var pair, i;
        var query = window.location.search.substring(1);
        var vars = query.split("&");
        for (i = 0; i < vars.length; i = i + 1) {
            pair = vars[i].split("=");
            if (pair[0].toUpperCase() === variable) {
                return pair[1];
            }
        }
        return false;
    }

    ns.Dim = {
        width: window.innerWidth,
        height: window.innerHeight,
        demWidth: getQueryVariable("WIDTH") || 100,
        demHeight: getQueryVariable("HEIGHT") || 100,
        bbox: getQueryVariable("BBOX") || '161244,6831251,171526,6837409',
        metersWidth: 0,
        metersHeight: 0,
        minx: 0,
        maxx: 0,
        miny: 0,
        maxy: 0,
        getBounds: function () {
            return {
                minx: this.minx,
                miny: this.miny,
                maxx: this.maxx,
                maxy: this.maxy
            };
        },
        init: function () {
            var splitBbox = this.bbox.split(',');
            this.metersWidth = splitBbox[2] - splitBbox[0];
            this.metersHeight = splitBbox[3] - splitBbox[1];
            this.minx = parseInt(splitBbox[0], 10);
            this.maxx = parseInt(splitBbox[2], 10);
            this.miny = parseInt(splitBbox[1], 10);
            this.maxy = parseInt(splitBbox[3], 10);

            if (getQueryVariable("WMSFORMATMODE")) {
                this.wmsFormatMode = '; mode=' + getQueryVariable("WMSFORMATMODE");
            }
            return this;
        },
        crs: getQueryVariable("CRS") || getQueryVariable("SRS") || 'EPSG:32633',
        coverage: getQueryVariable("COVERAGE") || 'land_utm33_10m',
        wmsUrl: getQueryVariable("WMS") || 'http://openwms.statkart.no/skwms1/wms.topo2',
        wcsUrl: 'http://openwms.statkart.no/skwms1/wcs.dtm',
        wmsMult: getQueryVariable("WMSMULT") || 5,
        wmsFormat: getQueryVariable("WMSFORMAT") || "image/png",
        wmsFormatMode: "",
        zMult: getQueryVariable("ZMULT")||1,
        Z: getQueryVariable("Z") || null,
        proportionWidth: 0,
        proportionHeight: 0
    };

    var dim = ns.Dim.init();
    var wmsLayers = getQueryVariable("LAYERS") || layers;
    var threeDMap = new ns.ThreeDMap(wmsLayers, dim);

    function parseCapabilities(capabilitiesXml) {
	var tileMatrixSetDict=[];
	var layers=capabilitiesXml.getElementsByTagName("Layer");
	//TODO: This fetches tileMatrixes we don't need:
	var tileMatrixSets=capabilitiesXml.getElementsByTagName("TileMatrixSet");
	var layersCount=layers.length;
	// Iterate through all layers
	for (var layer=0; layer<layersCount; layer++) {
		//Check for layer specified
		//TODO: should be evaluated against wxs url-parameters
		if (layers[layer].getElementsByTagName('Identifier')[0].innerHTML=='topo2'){
			var activeLayer=layers[layer];
			var layerTileMatrixSets=activeLayer.getElementsByTagName('TileMatrixSetLink');
			var layerTileMatrixCount=layerTileMatrixSets.length;
			// Iterate through all tilematrixsets allowed for layer
			for (var layerTileMatrix=0; layerTileMatrix<layerTileMatrixCount; layerTileMatrix++){
				//Check for specified crs
				//TODO: should be evaluated against wxs url-parameters
				if (layerTileMatrixSets[layerTileMatrix].getElementsByTagName('TileMatrixSet')[0].innerHTML=='EPSG:32633'){
					//console.log(layerTileMatrixSets[layerTileMatrix].getElementsByTagName('TileMatrixSet')[0].innerHTML);
					var tileMatrixSetsCount=tileMatrixSets.length;
					// We've now verified that the specified layer supports the specified crs. Time to fetch the actual tilematrixset
					for (var tileMatrixSet=0; tileMatrixSet<tileMatrixSetsCount; tileMatrixSet++)
					{
						// Neccessary hack since we fetch too many tilematrixes
						if(tileMatrixSets[tileMatrixSet].getElementsByTagName('Identifier').length >0){
							//Check for specified crs
							if (tileMatrixSets[tileMatrixSet].getElementsByTagName('Identifier')[0].innerHTML=='EPSG:32633'){
								var tileMatrix=tileMatrixSets[tileMatrixSet].getElementsByTagName('TileMatrix');
								var tileMatrixCount=tileMatrix.length;
								// Iterate through all matrixes for crs
								for (var tileMatrixIndex=0;tileMatrixIndex<tileMatrixCount; tileMatrixIndex++){

									tileMatrixSetDict.push(
									{
									Identifier: tileMatrix[tileMatrixIndex].getElementsByTagName('Identifier')[0].innerHTML,
									ScaleDenominator: tileMatrix[tileMatrixIndex].getElementsByTagName('ScaleDenominator')[0].innerHTML,
									TopLeftCorner: tileMatrix[tileMatrixIndex].getElementsByTagName('TopLeftCorner')[0].innerHTML,
									TileWidth: tileMatrix[tileMatrixIndex].getElementsByTagName('TileWidth')[0].innerHTML,
									TileHeight: tileMatrix[tileMatrixIndex].getElementsByTagName('TileHeight')[0].innerHTML,
									MatrixWidth: tileMatrix[tileMatrixIndex].getElementsByTagName('MatrixWidth')[0].innerHTML,
									MatrixHeight: tileMatrix[tileMatrixIndex].getElementsByTagName('MatrixHeight')[0].innerHTML
									});
								}
								console.timeEnd('capabilities parsing');
							}
						}
					}
				}
			}
		}
	}
	return tileMatrixSetDict;
    }
    function txt2xml(xmltxt) {
	if(window.DOMParser){
	    // non i.e. browser
	    var xmlparser = new DOMParser();
	    var xmlDoc = xmlparser.parseFromString(xmltxt, "text/xml");
	}else{
	    // i.e. browser
	    var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
	    xmlDoc.async = false;
	    xmlDoc.loadXML(xmltxt);
}
return xmlDoc;
};
}(wxs3));
<|endoftext|>


<commit_before>(function(angular){
    'use strict';

    let musicianUrl = '/MLL/MusicianHomePageServlet';
    let searchUrl = '/MLL/SearchServlet/?searchTitle=';
    let deleteUrl = '/MLL/DeleteAssetServlet/?assetId=';
    let editUrl = '/MLL/UpdateSongMetaDataServlet';
    let addBandUrl = '/MLL/ProfileServlet';
    let getBandDetailsUrl = '/MLL/BandServlet/?bandId=';

    // State of the music upload form
    let musicForms = {
        currentId: 0,
        submitFormId: 3,
        data: [
            {title: 'Recording Information', isActive: true},
            {title: 'Song Ownership Information', isActive: false},
            {title: 'Recording Upload', isActive: false},
            {title: 'Summary', isActive: false}
        ]
    };

    // Information relevant to a piece of music
    let musicData = {
        fileInformation: {name: '', file: null},
        generalInformation: {
            title: '',
            artists: [
                {name: ''}
            ],
            beatRate: 0,
            primaryGenre: '',
            secondaryGenre: ''
        },
        ownershipInformation: {
            songwriters: [
                {
                    name: '',
                    primaryEmail: '',
                    primaryPhone: '',
                    secondaryPhone: '',
                    contribution: '',
                    ownershipPercent: 0,
                    musicianRole: ''
                }
            ],
            copyright: '',
            pubCompany: '',
            pro: ''
        },
        soundInformation: {
            soundOwners: [
                {
                    name: '',
                    primaryEmail: '',
                    primaryPhone: '',
                    secondaryPhone: '',
                    contribution: '',
                    ownershipPercent: 0,
                    musicianRole: ''
                }
            ]
        },
        serverInformation: {}
    };

    // Enumeration of the various types of contributions to a song
    let musicContributions = [
        'Lyrics',
        'Music',
        'Lyrics and Music'
    ];

    // The master contact information for a single band
    let bandData = {
        ownershipInformation: {
            bandName: '',
            songwriters: [{
                name: '',
                primaryEmail: '',
                primaryPhone: '',
                secondaryPhone: '',
                contribution: '',
                ownershipPercent: 0,
                musicianRole: ''
            }]
        }
    };

    // Enumeration of the different roles/positions in a band
    let musicianRoles = [
        'Vocals',
        'Guitar',
        'Bass',
        'Drums',
        'Keyboard',
        'Backup Vocals',
        'Percussion',
        'Brass',
        'Woodwinds',
        'Strings'
    ];

    angular
        .module('mllApp.home')
        .constant('musicianUrl', musicianUrl)
    	.constant('searchUrl', searchUrl)
    	.constant('deleteUrl', deleteUrl)
    	.constant('editUrl', editUrl)
    	.constant('addBandUrl', addBandUrl)
    	.constant('musicData', musicData)
    	.constant('bandData', bandData)
    	.constant('musicContributions', musicContributions)
    	.constant('musicianRoles', musicianRoles)
    	.constant('getBandDetailsUrl', getBandDetailsUrl)
    	.constant('musicForms', musicForms);
})(window.angular);<commit_msg>Add global vals for message bodies<commit_after>(function(angular){
    'use strict';

    let musicianUrl = '/MLL/MusicianHomePageServlet';
    let searchUrl = '/MLL/SearchServlet/?searchTitle=';
    let deleteUrl = '/MLL/DeleteAssetServlet/?assetId=';
    let editUrl = '/MLL/UpdateSongMetaDataServlet';
    let addBandUrl = '/MLL/ProfileServlet';
    let getBandDetailsUrl = '/MLL/BandServlet/?bandId=';

    // State of the music upload form
    let musicForms = {
        currentId: 0,
        submitFormId: 3,
        data: [
            {title: 'Recording Information', isActive: true},
            {title: 'Song Ownership Information', isActive: false},
            {title: 'Recording Upload', isActive: false},
            {title: 'Summary', isActive: false}
        ]
    };

    // Information relevant to a piece of music
    let musicData = {
        fileInformation: {name: '', file: null},
        generalInformation: {
            title: '',
            artists: [
                {name: ''}
            ],
            beatRate: 0,
            primaryGenre: '',
            secondaryGenre: ''
        },
        ownershipInformation: {
            songwriters: [
                {
                    name: '',
                    primaryEmail: '',
                    primaryPhone: '',
                    secondaryPhone: '',
                    contribution: '',
                    ownershipPercent: 0,
                    musicianRole: ''
                }
            ],
            copyright: '',
            pubCompany: '',
            pro: ''
        },
        soundInformation: {
            soundOwners: [
                {
                    name: '',
                    primaryEmail: '',
                    primaryPhone: '',
                    secondaryPhone: '',
                    contribution: '',
                    ownershipPercent: 0,
                    musicianRole: ''
                }
            ]
        },
        serverInformation: {}
    };

    // Enumeration of the various types of contributions to a song
    let musicContributions = [
        'Lyrics',
        'Music',
        'Lyrics and Music'
    ];

    // The master contact information for a single band
    let bandData = {
        ownershipInformation: {
            bandName: '',
            songwriters: [{
                name: '',
                primaryEmail: '',
                primaryPhone: '',
                secondaryPhone: '',
                contribution: '',
                ownershipPercent: 0,
                musicianRole: ''
            }]
        }
    };

    // Enumeration of the different roles/positions in a band
    let musicianRoles = [
        'Vocals',
        'Guitar',
        'Bass',
        'Drums',
        'Keyboard',
        'Backup Vocals',
        'Percussion',
        'Brass',
        'Woodwinds',
        'Strings'
    ];

    let arUserInvitationBody = `Dear A&R Student,

        Thanks for your interest in the ML-Lab. We are looking forward to building our library of great music and we’re very excited that you will help us by inviting independent artists to participate.

        Below you will see the blurb that will be automatically included in your invitation for musicians to participate in the ML-Lab. As you can see, you will need to add the musician’s name in the intro and your name in the signature. You can feel free to add more information to the message if you want to personalize your invitation.

Here’s some information about the ML-Lab:

• All musicians must be independent (i.e., not signed to a record label).
• All songs must be original to the musician (i.e., no covers)
• The musician retains all rights to their music.
• Music in the library will NOT be commercially exploited.
• The music in the library will be listened to, browsed, evaluated, categorized, sorted and shared with other NU students and faculty.
• Eventually, we want to place music in movies, television shows, video games and commercials, however, we’re not even close to launching the Licensing Program, so for now, we’re just trying to gather some great music into our library for NU students to work with.
• Before we actually launch the Music Licensing Program, we’ll ask the musicians if they want to be included.
• If musicians do decide to participate in the Music Licensing Program, they will be free to withdraw at any time.

Please contact Professor Herlihy at d.herlihy@neu.edu if you have any comments or questions.

Dear MUSICIAN NAME

        I would like to invite you to participate in an exciting new music project at Northeastern University, the first beta-test phase of the launch of NU’s Media Licensing Laboratory (ML-Lab).

        I am asking you to join this effort, and upload your music onto our ML-LAB Platform so we can create a prototype music library solely for educational and research purposes. This will be a great way to introduce your music to NU students.

        We are also anxious to get your feedback about your experience with the ML-LAB Platform, so I ask that you send any feedback and bug reports promptly through the feedback window so that we can use your input to improve the process.

        Our long term goal is to establish a student-run music licensing program so students can place great independent music in movies, television shows, video games and commercials. However, we’re not even close to launching the Licensing Program, so for now, we’re just trying to gather some great music into our library for NU students to work with.

        Before we actually launch the Music Licensing Program, we’ll ask you if you want to be included. Participation in the Music Licensing Program will be voluntary and non-exclusive and you will retain all rights in your music. If you do decide to participate in the Music Licensing Program, you will be free to withdraw at any time.

        Please click on the link below to participate in the ML-Lab and upload your music into our Library. Please let me know if you have any comments or questions and don’t forget to give us your feedback about your experience with the Platform.

Thanks,  A&R INVITER’S NAME`;

    let musicianInvitationBody = `Dear   MUSICIAN NAME

        I would like to invite you to participate in an exciting new music project at Northeastern University, the first beta-test phase of the launch of NU’s Media Licensing Laboratory (ML-Lab).

        I am asking you to join this effort, and upload your music onto our ML-LAB Platform so we can create a prototype music library solely for educational and research purposes. This will be a great way to introduce your music to NU students.

        We are also anxious to get your feedback about your experience with the ML-LAB Platform, so I ask that you send any feedback and bug reports promptly through the feedback window so that we can use your input to improve the process.

        Our long term goal is to establish a student-run music licensing program so students can place great independent music in movies, television shows, video games and commercials. However, we’re not even close to launching the Licensing Program, so for now, we’re just trying to gather some great music into our library for NU students to work with.

        Before we actually launch the Music Licensing Program, we’ll ask you if you want to be included. Participation in the Music Licensing Program will be voluntary and non-exclusive and you will retain all rights in your music. If you do decide to participate in the Music Licensing Program, you will be free to withdraw at any time.

        Please click on the link below to participate in the ML-Lab and upload your music into our Library. Please let me know if you have any comments or questions and don’t forget to give us your feedback about your experience with the Platform.

Thanks,  A&R INVITER’S NAME`;

    angular
        .module('mllApp.home')
        .constant('musicianUrl', musicianUrl)
    	.constant('searchUrl', searchUrl)
    	.constant('deleteUrl', deleteUrl)
    	.constant('editUrl', editUrl)
    	.constant('addBandUrl', addBandUrl)
    	.constant('musicData', musicData)
    	.constant('bandData', bandData)
    	.constant('musicContributions', musicContributions)
    	.constant('musicianRoles', musicianRoles)
    	.constant('getBandDetailsUrl', getBandDetailsUrl)
    	.constant('musicForms', musicForms)
        .constant('arUserInvitationBody', arUserInvitationBody)
        .constant('musicianInvitationBody', musicianInvitationBody);
})(window.angular);<|endoftext|>


<commit_before>// ## Globals
var argv         = require('minimist')(process.argv.slice(2));
var autoprefixer = require('gulp-autoprefixer');
var browserSync  = require('browser-sync').create();
var changed      = require('gulp-changed');
var concat       = require('gulp-concat');
var flatten      = require('gulp-flatten');
var gulp         = require('gulp');
var bless        = require('gulp-bless');
var gulpif       = require('gulp-if');
var imagemin     = require('gulp-imagemin');
var jshint       = require('gulp-jshint');
var lazypipe     = require('lazypipe');
var less         = require('gulp-less');
var merge        = require('merge-stream');
var minifyCss    = require('gulp-minify-css');
var plumber      = require('gulp-plumber');
var rev          = require('gulp-rev');
var runSequence  = require('run-sequence');
var sass         = require('gulp-sass');
var sourcemaps   = require('gulp-sourcemaps');
var uglify       = require('gulp-uglify');

// See https://github.com/austinpray/asset-builder
var manifest = require('asset-builder')('./assets/manifest.json');

// `path` - Paths to base asset directories. With trailing slashes.
// - `path.source` - Path to the source files. Default: `assets/`
// - `path.dist` - Path to the build directory. Default: `dist/`
var path = manifest.paths;

// `config` - Store arbitrary configuration values here.
var config = manifest.config || {};

// `globs` - These ultimately end up in their respective `gulp.src`.
// - `globs.js` - Array of asset-builder JS dependency objects. Example:
//   ```
//   {type: 'js', name: 'main.js', globs: []}
//   ```
// - `globs.css` - Array of asset-builder CSS dependency objects. Example:
//   ```
//   {type: 'css', name: 'main.css', globs: []}
//   ```
// - `globs.fonts` - Array of font path globs.
// - `globs.images` - Array of image path globs.
// - `globs.bower` - Array of all the main Bower files.
var globs = manifest.globs;

// `project` - paths to first-party assets.
// - `project.js` - Array of first-party JS assets.
// - `project.css` - Array of first-party CSS assets.
var project = manifest.getProjectGlobs();

// CLI options
var enabled = {
  // Enable static asset revisioning when `--production`
  rev: argv.production,
  // Disable source maps when `--production`
  maps: !argv.production,
  // Fail styles task on error when `--production`
  failStyleTask: argv.production,
  // Fail due to JSHint warnings only when `--production`
  failJSHint: argv.production,
  // Strip debug statments from javascript when `--production`
  stripJSDebug: argv.production,
  // Minify CSS, JS, and Images
  minify: !argv.fast,
  // Split minified css when '--production'
  split: argv.production
};

// Path to the compiled assets manifest in the dist directory
var revManifest = path.dist + 'assets.json';

// ## Reusable Pipelines
// See https://github.com/OverZealous/lazypipe

// ### CSS processing pipeline
// Example
// ```
// gulp.src(cssFiles)
//   .pipe(cssTasks('main.css')
//   .pipe(gulp.dest(path.dist + 'styles'))
// ```
var cssTasks = function(filename) {
  return lazypipe()
    .pipe(function() {
      return gulpif(!enabled.failStyleTask, plumber());
    })
    .pipe(function() {
      return gulpif(enabled.maps, sourcemaps.init());
    })
    .pipe(function() {
      return gulpif('*.less', less());
    })
    .pipe(function() {
      return gulpif('*.scss', sass({
        outputStyle: 'nested', // libsass doesn't support expanded yet
        precision: 10,
        includePaths: ['.'],
        errLogToConsole: !enabled.failStyleTask
      }));
    })
    .pipe(concat, filename)
    .pipe(autoprefixer, {
      browsers: [
        'last 2 versions',
        'ie 8',
        'ie 9',
        'android 2.3',
        'android 4',
        'opera 12'
      ]
    })
    .pipe(function() {
      return gulpif(enabled.minify, minifyCss({
        advanced: false,
        rebase: false
      }));
    })
    .pipe(function() {
      return gulpif(enabled.rev, rev());
    })
    .pipe(function() {
      return gulpif(enabled.maps, sourcemaps.write('.', {
        sourceRoot: 'assets/styles/'
      }));
    })();
};

// ### Bless
gulp.task('bless', function() {
  if(enabled.split) {
    return gulp.src(path.dist + 'styles/*.css')
    .pipe(bless())
     .pipe(gulp.dest(path.dist + 'styles'));
  }
});

// ### JS processing pipeline
// Example
// ```
// gulp.src(jsFiles)
//   .pipe(jsTasks('main.js')
//   .pipe(gulp.dest(path.dist + 'scripts'))
// ```
var jsTasks = function(filename) {
  return lazypipe()
    .pipe(function() {
      return gulpif(enabled.maps, sourcemaps.init());
    })
    .pipe(concat, filename)
    .pipe(function() {
      return gulpif(enabled.minify, uglify({
        compress: {
          'drop_debugger': enabled.stripJSDebug
        }
      }));
    })
    .pipe(function() {
      return gulpif(enabled.rev, rev());
    })
    .pipe(function() {
      return gulpif(enabled.maps, sourcemaps.write('.', {
        sourceRoot: 'assets/scripts/'
      }));
    })();
};

// ### Write to rev manifest
// If there are any revved files then write them to the rev manifest.
// See https://github.com/sindresorhus/gulp-rev
var writeToManifest = function(directory) {
  return lazypipe()
    .pipe(gulp.dest, path.dist + directory)
    .pipe(browserSync.stream, {match: '**/*.{js,css}'})
    .pipe(rev.manifest, revManifest, {
      base: path.dist,
      merge: true
    })
    .pipe(gulp.dest, path.dist)();
};

// ## Gulp tasks
// Run `gulp -T` for a task summary

// ### Styles
// `gulp styles` - Compiles, combines, and optimizes Bower CSS and project CSS.
// By default this task will only log a warning if a precompiler error is
// raised. If the `--production` flag is set: this task will fail outright.
gulp.task('styles', ['wiredep'], function() {
  var merged = merge();
  manifest.forEachDependency('css', function(dep) {
    var cssTasksInstance = cssTasks(dep.name);
    if (!enabled.failStyleTask) {
      cssTasksInstance.on('error', function(err) {
        console.error(err.message);
        this.emit('end');
      });
    }
    merged.add(gulp.src(dep.globs, {base: 'styles'})
      .pipe(cssTasksInstance));
  });
  return merged
    .pipe(writeToManifest('styles'));
});

// ### Scripts
// `gulp scripts` - Runs JSHint then compiles, combines, and optimizes Bower JS
// and project JS.
gulp.task('scripts', ['jshint'], function() {
  var merged = merge();
  manifest.forEachDependency('js', function(dep) {
    merged.add(
      gulp.src(dep.globs, {base: 'scripts'})
        .pipe(jsTasks(dep.name))
    );
  });
  return merged
    .pipe(writeToManifest('scripts'));
});

// ### Fonts
// `gulp fonts` - Grabs all the fonts and outputs them in a flattened directory
// structure. See: https://github.com/armed/gulp-flatten
gulp.task('fonts', function() {
  return gulp.src(globs.fonts)
    .pipe(flatten())
    .pipe(gulp.dest(path.dist + 'fonts'))
    .pipe(browserSync.stream());
});

// ### Images
// `gulp images` - Run lossless compression on all the images.
gulp.task('images', function() {
  return gulp.src(globs.images)
    .pipe(gulpif(enabled.minify, imagemin({
      progressive: true,
      interlaced: true,
      svgoPlugins: [{removeUnknownsAndDefaults: false}, {cleanupIDs: false}]
    })))
    .pipe(gulp.dest(path.dist + 'images'))
    .pipe(browserSync.stream());
});

// ### JSHint
// `gulp jshint` - Lints configuration JSON and project JS.
gulp.task('jshint', function() {
  return gulp.src([
    'bower.json', 'gulpfile.js'
  ].concat(project.js))
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'))
    .pipe(gulpif(enabled.failJSHint, jshint.reporter('fail')));
});

// ### Clean
// `gulp clean` - Deletes the build folder entirely.
gulp.task('clean', require('del').bind(null, [path.dist]));

// ### Watch
// `gulp watch` - Use BrowserSync to proxy your dev server and synchronize code
// changes across devices. Specify the hostname of your dev server at
// `manifest.config.devUrl`. When a modification is made to an asset, run the
// build step for that asset and inject the changes into the page.
// See: http://www.browsersync.io
gulp.task('watch', function() {
	var url = process.cwd();
	url = url.split('/');
	host = process.env.HOSTNAME;
	var finalurl = "http://" + url[4] + "." + url[2] + "." + host;
	browserSync.init({
		files: ['{lib,templates}/**/*.php', '*.php'],
		proxy: finalurl, snippetOptions: {
			whitelist: ['/wp-admin/admin-ajax.php'],
			blacklist: ['/wp-admin/**']
		},
		middleware: function (req, res, next) {
			res.setHeader('Access-Control-Allow-Origin', '*');
			next();
		}
	});
	gulp.watch([path.source + 'styles/**/*'], ['styles']);
	gulp.watch([path.source + 'scripts/**/*'], ['jshint', 'scripts']);
	gulp.watch([path.source + 'fonts/**/*'], ['fonts']);
	gulp.watch([path.source + 'images/**/*'], ['images']);
	gulp.watch(['bower.json', 'assets/manifest.json'], ['build']);
});

// ### Build
// `gulp build` - Run all the build tasks but don't clean up beforehand.
// Generally you should be running `gulp` instead of `gulp build`.
gulp.task('build', function(callback) {
  runSequence('styles',
  			  'bless',
              'scripts',
              ['fonts', 'images'],
              callback);
});

// ### Wiredep
// `gulp wiredep` - Automatically inject Less and Sass Bower dependencies. See
// https://github.com/taptapship/wiredep
gulp.task('wiredep', function() {
  var wiredep = require('wiredep').stream;
  return gulp.src(project.css)
    .pipe(wiredep())
    .pipe(changed(path.source + 'styles', {
      hasChanged: changed.compareSha1Digest
    }))
    .pipe(gulp.dest(path.source + 'styles'));
});

// ### Gulp
// `gulp` - Run a complete build. To compile for production run `gulp --production`.
gulp.task('default', ['clean'], function() {
  gulp.start('build');
});<commit_msg>removed unneeded less handling<commit_after>// ## Globals
var argv         = require('minimist')(process.argv.slice(2));
var autoprefixer = require('gulp-autoprefixer');
var browserSync  = require('browser-sync').create();
var changed      = require('gulp-changed');
var concat       = require('gulp-concat');
var flatten      = require('gulp-flatten');
var gulp         = require('gulp');
var bless        = require('gulp-bless');
var gulpif       = require('gulp-if');
var imagemin     = require('gulp-imagemin');
var jshint       = require('gulp-jshint');
var lazypipe     = require('lazypipe');
var merge        = require('merge-stream');
var minifyCss    = require('gulp-minify-css');
var plumber      = require('gulp-plumber');
var rev          = require('gulp-rev');
var runSequence  = require('run-sequence');
var sass         = require('gulp-sass');
var sourcemaps   = require('gulp-sourcemaps');
var uglify       = require('gulp-uglify');

// See https://github.com/austinpray/asset-builder
var manifest = require('asset-builder')('./assets/manifest.json');

// `path` - Paths to base asset directories. With trailing slashes.
// - `path.source` - Path to the source files. Default: `assets/`
// - `path.dist` - Path to the build directory. Default: `dist/`
var path = manifest.paths;

// `config` - Store arbitrary configuration values here.
var config = manifest.config || {};

// `globs` - These ultimately end up in their respective `gulp.src`.
// - `globs.js` - Array of asset-builder JS dependency objects. Example:
//   ```
//   {type: 'js', name: 'main.js', globs: []}
//   ```
// - `globs.css` - Array of asset-builder CSS dependency objects. Example:
//   ```
//   {type: 'css', name: 'main.css', globs: []}
//   ```
// - `globs.fonts` - Array of font path globs.
// - `globs.images` - Array of image path globs.
// - `globs.bower` - Array of all the main Bower files.
var globs = manifest.globs;

// `project` - paths to first-party assets.
// - `project.js` - Array of first-party JS assets.
// - `project.css` - Array of first-party CSS assets.
var project = manifest.getProjectGlobs();

// CLI options
var enabled = {
  // Enable static asset revisioning when `--production`
  rev: argv.production,
  // Disable source maps when `--production`
  maps: !argv.production,
  // Fail styles task on error when `--production`
  failStyleTask: argv.production,
  // Fail due to JSHint warnings only when `--production`
  failJSHint: argv.production,
  // Strip debug statments from javascript when `--production`
  stripJSDebug: argv.production,
  // Minify CSS, JS, and Images
  minify: !argv.fast,
  // Split minified css when '--production'
  split: argv.production
};

// Path to the compiled assets manifest in the dist directory
var revManifest = path.dist + 'assets.json';

// ## Reusable Pipelines
// See https://github.com/OverZealous/lazypipe

// ### CSS processing pipeline
// Example
// ```
// gulp.src(cssFiles)
//   .pipe(cssTasks('main.css')
//   .pipe(gulp.dest(path.dist + 'styles'))
// ```
var cssTasks = function(filename) {
  return lazypipe()
    .pipe(function() {
      return gulpif(!enabled.failStyleTask, plumber());
    })
    .pipe(function() {
      return gulpif(enabled.maps, sourcemaps.init());
    })
    .pipe(function() {
      return gulpif('*.scss', sass({
        outputStyle: 'nested', // libsass doesn't support expanded yet
        precision: 10,
        includePaths: ['.'],
        errLogToConsole: !enabled.failStyleTask
      }));
    })
    .pipe(concat, filename)
    .pipe(autoprefixer, {
      browsers: [
        'last 2 versions',
        'ie 8',
        'ie 9',
        'android 2.3',
        'android 4',
        'opera 12'
      ]
    })
    .pipe(function() {
      return gulpif(enabled.minify, minifyCss({
        advanced: false,
        rebase: false
      }));
    })
    .pipe(function() {
      return gulpif(enabled.rev, rev());
    })
    .pipe(function() {
      return gulpif(enabled.maps, sourcemaps.write('.', {
        sourceRoot: 'assets/styles/'
      }));
    })();
};

// ### Bless
gulp.task('bless', function() {
  if(enabled.split) {
    return gulp.src(path.dist + 'styles/*.css')
    .pipe(bless())
     .pipe(gulp.dest(path.dist + 'styles'));
  }
});

// ### JS processing pipeline
// Example
// ```
// gulp.src(jsFiles)
//   .pipe(jsTasks('main.js')
//   .pipe(gulp.dest(path.dist + 'scripts'))
// ```
var jsTasks = function(filename) {
  return lazypipe()
    .pipe(function() {
      return gulpif(enabled.maps, sourcemaps.init());
    })
    .pipe(concat, filename)
    .pipe(function() {
      return gulpif(enabled.minify, uglify({
        compress: {
          'drop_debugger': enabled.stripJSDebug
        }
      }));
    })
    .pipe(function() {
      return gulpif(enabled.rev, rev());
    })
    .pipe(function() {
      return gulpif(enabled.maps, sourcemaps.write('.', {
        sourceRoot: 'assets/scripts/'
      }));
    })();
};

// ### Write to rev manifest
// If there are any revved files then write them to the rev manifest.
// See https://github.com/sindresorhus/gulp-rev
var writeToManifest = function(directory) {
  return lazypipe()
    .pipe(gulp.dest, path.dist + directory)
    .pipe(browserSync.stream, {match: '**/*.{js,css}'})
    .pipe(rev.manifest, revManifest, {
      base: path.dist,
      merge: true
    })
    .pipe(gulp.dest, path.dist)();
};

// ## Gulp tasks
// Run `gulp -T` for a task summary

// ### Styles
// `gulp styles` - Compiles, combines, and optimizes Bower CSS and project CSS.
// By default this task will only log a warning if a precompiler error is
// raised. If the `--production` flag is set: this task will fail outright.
gulp.task('styles', ['wiredep'], function() {
  var merged = merge();
  manifest.forEachDependency('css', function(dep) {
    var cssTasksInstance = cssTasks(dep.name);
    if (!enabled.failStyleTask) {
      cssTasksInstance.on('error', function(err) {
        console.error(err.message);
        this.emit('end');
      });
    }
    merged.add(gulp.src(dep.globs, {base: 'styles'})
      .pipe(cssTasksInstance));
  });
  return merged
    .pipe(writeToManifest('styles'));
});

// ### Scripts
// `gulp scripts` - Runs JSHint then compiles, combines, and optimizes Bower JS
// and project JS.
gulp.task('scripts', ['jshint'], function() {
  var merged = merge();
  manifest.forEachDependency('js', function(dep) {
    merged.add(
      gulp.src(dep.globs, {base: 'scripts'})
        .pipe(jsTasks(dep.name))
    );
  });
  return merged
    .pipe(writeToManifest('scripts'));
});

// ### Fonts
// `gulp fonts` - Grabs all the fonts and outputs them in a flattened directory
// structure. See: https://github.com/armed/gulp-flatten
gulp.task('fonts', function() {
  return gulp.src(globs.fonts)
    .pipe(flatten())
    .pipe(gulp.dest(path.dist + 'fonts'))
    .pipe(browserSync.stream());
});

// ### Images
// `gulp images` - Run lossless compression on all the images.
gulp.task('images', function() {
  return gulp.src(globs.images)
    .pipe(gulpif(enabled.minify, imagemin({
      progressive: true,
      interlaced: true,
      svgoPlugins: [{removeUnknownsAndDefaults: false}, {cleanupIDs: false}]
    })))
    .pipe(gulp.dest(path.dist + 'images'))
    .pipe(browserSync.stream());
});

// ### JSHint
// `gulp jshint` - Lints configuration JSON and project JS.
gulp.task('jshint', function() {
  return gulp.src([
    'bower.json', 'gulpfile.js'
  ].concat(project.js))
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'))
    .pipe(gulpif(enabled.failJSHint, jshint.reporter('fail')));
});

// ### Clean
// `gulp clean` - Deletes the build folder entirely.
gulp.task('clean', require('del').bind(null, [path.dist]));

// ### Watch
// `gulp watch` - Use BrowserSync to proxy your dev server and synchronize code
// changes across devices. Specify the hostname of your dev server at
// `manifest.config.devUrl`. When a modification is made to an asset, run the
// build step for that asset and inject the changes into the page.
// See: http://www.browsersync.io
gulp.task('watch', function() {
	var url = process.cwd();
	url = url.split('/');
	host = process.env.HOSTNAME;
	var finalurl = "http://" + url[4] + "." + url[2] + "." + host;
	browserSync.init({
		files: ['{lib,templates}/**/*.php', '*.php'],
		proxy: finalurl, snippetOptions: {
			whitelist: ['/wp-admin/admin-ajax.php'],
			blacklist: ['/wp-admin/**']
		},
		middleware: function (req, res, next) {
			res.setHeader('Access-Control-Allow-Origin', '*');
			next();
		}
	});
	gulp.watch([path.source + 'styles/**/*'], ['styles']);
	gulp.watch([path.source + 'scripts/**/*'], ['jshint', 'scripts']);
	gulp.watch([path.source + 'fonts/**/*'], ['fonts']);
	gulp.watch([path.source + 'images/**/*'], ['images']);
	gulp.watch(['bower.json', 'assets/manifest.json'], ['build']);
});

// ### Build
// `gulp build` - Run all the build tasks but don't clean up beforehand.
// Generally you should be running `gulp` instead of `gulp build`.
gulp.task('build', function(callback) {
  runSequence('styles',
  			  'bless',
              'scripts',
              ['fonts', 'images'],
              callback);
});

// ### Wiredep
// `gulp wiredep` - Automatically inject Less and Sass Bower dependencies. See
// https://github.com/taptapship/wiredep
gulp.task('wiredep', function() {
  var wiredep = require('wiredep').stream;
  return gulp.src(project.css)
    .pipe(wiredep())
    .pipe(changed(path.source + 'styles', {
      hasChanged: changed.compareSha1Digest
    }))
    .pipe(gulp.dest(path.source + 'styles'));
});

// ### Gulp
// `gulp` - Run a complete build. To compile for production run `gulp --production`.
gulp.task('default', ['clean'], function() {
  gulp.start('build');
});<|endoftext|>


<commit_before>// NML VM
// Runs NML AST, stored in a MObject
// A VM would exist for each script/verb, and would be reset/replaced with a
// new VM when those scripts/verbs are updated/edited.

var async = require('async');

var OPERATORS          = require('./constants').OPERATORS;
var TYPE_COMPATIBILITY = require('./constants').TYPE_COMPATIBILITY;
var OP_ORDER           = require('./constants').OP_ORDER;

var VM = function(app, mobj, ast) {
  this._app = app;
  this.mobj = mobj; // MOO Object

  // Initialize the state
  this.state = {
    ast: ast,
    localVars: {},
    ip: [0] // Instruction pointer/path; this is an array as the AST is a tree with many levels
            // Example: [2, 4, 10] for the second object, then fourth, then tenth object
  }
}

VM.findIns = function(ip, ast) {
  // Find the instruction specified by instruction path IP
  if(ip.length <= 1) {
    return ast[ip[0]];
  } else {
    if(typeof(ast[ip[0]]) === 'object' && ast[ip[0]].block !== undefined) {
      return VM.findIns(ip.slice(1, ip.length), ast[ip[0]].block);
    } else {
      return ast; // Path not valid, just return the ast at it's current state
    }
  }
}

var err = function(str) {
  throw 'runtime error: ' + str;
}

// Resolve possible indirect values, like variables, properties, etc
// Async because it _might_ hit the DB
VM.prototype.resolveValue = function(value, callback) {
  if(typeof(value) !== 'object') return callback(null, value); // This is a direct value, just return it.
  if(value instanceof Array) { // Not arrays, expression groups. Arrays are {type: 'array', ...}
    // If the array has a single item, return that instead of the whole array
    // This helps collapse expressions for evalExpr
    if(value.length === 1) {
      return this.evalExpr(value[0], callback);
    }
    return this.evalExpr(value, callback);
  }
  switch(value.type) {
    case 'var': // Local variable, return it from our state.
      return callback(null, this.state.localVars[value.name]);
    case 'prop': // This is a property, fetch it from the object
      return this.mobj.getProp(value.name, callback);
    case 'objectIdAlias': // This is an object id alias, ask the app for what it means
      return callback(null, this._app.resolveObjIdAlias(value.value));
    default: // This may be an object like a virtual null, just pass it through
      return callback(null, value);
  }
}

// Evaluate simple expresisons, like 4 * 5
// Async because resolveValue _might_ hit the DB
VM.prototype.evalExpr = function(expr, finalCallback) {
  expr = expr.slice(); // Shallow copy expr, as we will be modifying it
  // First, if the second component is not an operator and the whole expression
  // has no JS objects/hashes, then just return the expression joined by space
  // UNLESS, the first component is a number
  if(OPERATORS[expr[1]] === undefined && typeof(expr[0]) !== 'number') {
    var noObjects = true;
    for(var obj of expr) { if(typeof(obj) === 'object') { noObjects = false; break; }}
    if(noObjects) return finalCallback(null, expr.join(' '));
  }

  var parseAllOps = function(opTypeIndex) {
    var nextOpType = function() {
      if(opTypeIndex + 1 >= OP_ORDER.length || expr.length < 2) {
        finalCallback(null, expr[0]); // The result should be the only thing remaining
                                      // in the expression.
      } else {
        parseAllOps(opTypeIndex + 1);
      }
    }.bind(this);
    var op = OP_ORDER[opTypeIndex];

    var nextOp = function() { // We shouldn't need an index of where to search
                              // for the next op if we delete the op and replace
                              // it with it's result
      var opIndex = expr.indexOf(op);
      if(opIndex === -1) return nextOpType(); // Find the next op type if there is no more of this op type
      async.map([expr[opIndex-1], expr[opIndex+1]], this.resolveValue.bind(this), function(err, results) {
        if(err) return finalCallback(err);
        // We have our resolved results in the results array, left = [0], right = [1]
        var left = results[0], right = results[1];
        // Check types
        if(TYPE_COMPATIBILITY[op] !== undefined && TYPE_COMPATIBILITY[op][typeof(right)].indexOf(typeof(left)) < 0) return finalCallback(new Error('type ' + typeof(left) + ' cannot be opped ' + op + ' with ' + typeof(right)));
        // Splice out the op and the right side from the expression
        expr.splice(opIndex, 2);
        // Set the opIndex - 1 (left side which is still intact) to the result
        expr[opIndex - 1] = OPERATORS[op](left, right);
        // Find the next op of this type
        nextOp();
      }.bind(this));
    }.bind(this);

    nextOp();
  }.bind(this);

  parseAllOps(0);
}

VM.prototype.stepOnce = function(callback) {
  // First find the Instruction
  var ins = VM.findIns(this.state.ip, this.state.ast); // _that was easy_

  // Finishes job by incrementing the IP accordingly
  var jobDone = function(err, results) {
    if(err) return callback(err);
    // If this is a branching instruction and we need to branch (results[0]),
    // branch instead of incrementing the IP
    if((ins.type === 'if' || ins.type === 'while') && results && ins.block.length > 0) {
      this.state.ip.push(0); // This simply bumps us into the next instruction to the right on the AST
      return callback();
    } else {
      // Otherwise, we need to decide what to do
      var progressIP = function() {
        // While we are at the end of the current block (if we are)
        while(this.state.ip.length > 1 &&
              this.state.ip.slice(-1)[0] ===
              VM.findIns(this.state.ip.slice(0, -1), this.state.ast).block.length - 1) {
          if(VM.findIns(this.state.ip.slice(0, -1), this.state.ast).type === 'while') {
            // Consider looping around
            // Reevaluate the condition and if it is true, go back to the top of
            // the loop (set ip[ip.length - 1] = 0)
            // Otherwise pop off the path from ip
            this.evalExpr(VM.findIns(this.state.ip.slice(0, -1), this.state.ast).expr, function(err, value) {
              if(err) return callback(err); // If we couldn't eval the expression, error
              if(value) {
                // Restart loop
                this.state.ip[this.state.ip.length - 1] = 0;
                return callback();
              } else {
                // Pop off the current state to return to where we were
                this.state.ip.pop(); // Pop off the current state

                return progressIP(); // This runs through the whole escape block loop again
              }
            }.bind(this));
            return;
          } else { // Probably an if statement, just pop off the stack
            this.state.ip.pop(); // Pop off the current state
          }
        }

        // Are we at the end of the script
        if(this.state.ip.length === 1 && this.state.ip[0] === this.state.ast.length - 1)
          return callback('endOfScript'); // Error with endOfScript

        // Carry on, increment by one
        this.state.ip[this.state.ip.length - 1]++;
        callback(); // Call the callback, everything is done
      }.bind(this);

      progressIP();
    }
  }.bind(this);

  switch(ins.type) {
    case 'while':
    case 'if':
      // while/if statement. Check if expression provided evaluates to true
      // and if so, callback with branch set to true
      this.evalExpr(ins.expr, function(err, value) {
        if(err) return jobDone(err); // If we couldn't eval the expression, error
        var out = false;
        if(value) out = true; // Evaluate the expression using JS's if evaluation
        return jobDone(null, out);
      });
      break;
    case 'assign':
      async.waterfall([
      function(c) { this.evalExpr(ins.src, c); }.bind(this),
      function(value, c) { // We have evaluated the right side of the assignment, set the value.
        if(ins.op === '=') {
          // Simple assignment
          if(ins.dst.type === 'var') {
            // Local variable, just set it here
            this.state.localVars[ins.dst.name] = value;
            c();
          } else if(ins.dst.type === 'prop') {
            // Object prop, set it and pass it the stepOnce callback.
            this.mobj.setProp(ins.dst.name, value, c);
          } else {
            c('unspecifiable error (cac96aa5-fade-4263-a56c-e4cd883447cc)');
          }
        } else {
          // Complex assignment, runs an expression.
          // We need to resolve the dst so we can type check
          this.resolveValue(ins.dst, function(err, currentValue) {
            if(TYPE_COMPATIBILITY[ins.op][typeof(value)].indexOf(typeof(currentValue)) < 0) return c('type ' + typeof(value) + ' cannot be opped ' + ins.op + ' with ' + typeof(currentValue));
            // It's all valid, do the assignment
            currentValue = OPERATORS[ins.op](currentValue, value);
            // Set currentValue back to where it came from
            if(ins.dst.type === 'prop') {
              this.mobj.setProp(ins.dst.name, currentValue, c);
            } else if(ins.dst.type === 'var') {
              this.state.localVars[ins.dst.name] = currentValue;
              return c();
            } else {
              return c('unspecifiable error (13041b5b-7392-400d-9623-44347db5f81e)');
            }
          }.bind(this));
        }
      }.bind(this)], jobDone);
      break;
    case 'verbcall':
      jobDone(); // TODO actually implement the verbcalls
      break;
  }
}

VM.prototype.step = function(times, callback) {
  async.times(times, function(i, next) {
    this.stepOnce(next);
  }.bind(this), callback);
}

module.exports = VM;
<commit_msg>array element indexing<commit_after>// NML VM
// Runs NML AST, stored in a MObject
// A VM would exist for each script/verb, and would be reset/replaced with a
// new VM when those scripts/verbs are updated/edited.

var async = require('async');

var OPERATORS          = require('./constants').OPERATORS;
var TYPE_COMPATIBILITY = require('./constants').TYPE_COMPATIBILITY;
var OP_ORDER           = require('./constants').OP_ORDER;

var VM = function(app, mobj, ast) {
  this._app = app;
  this.mobj = mobj; // MOO Object

  // Initialize the state
  this.state = {
    ast: ast,
    localVars: {},
    ip: [0] // Instruction pointer/path; this is an array as the AST is a tree with many levels
            // Example: [2, 4, 10] for the second object, then fourth, then tenth object
  }
}

VM.findIns = function(ip, ast) {
  // Find the instruction specified by instruction path IP
  if(ip.length <= 1) {
    return ast[ip[0]];
  } else {
    if(typeof(ast[ip[0]]) === 'object' && ast[ip[0]].block !== undefined) {
      return VM.findIns(ip.slice(1, ip.length), ast[ip[0]].block);
    } else {
      return ast; // Path not valid, just return the ast at it's current state
    }
  }
}

// NML type array
var traverseArray = function(arr, path) {
  if(path.length <= 1) {
    return arr.ctx[path[0] || 0];
  } else {
    return traverseArray(arr.ctx[path[0]], path.slice(1, path.length - 1));
  }
}

// Resolve possible indirect values, like variables, properties, etc
// Async because it _might_ hit the DB
VM.prototype.resolveValue = function(value, callback) {
  if(typeof(value) !== 'object') return callback(null, value); // This is a direct value, just return it.
  if(value instanceof Array) { // Not arrays, expression groups. Arrays are {type: 'array', ...}
    // If the array has a single item, return that instead of the whole array
    // This helps collapse expressions for evalExpr
    if(value.length === 1) return this.evalExpr(value[0], callback);
    return this.evalExpr(value, callback);
  }
  switch(value.type) {
    case 'var': // Local variable, return it from our state.
      // Return an element of the array if provided with an index
      if(value.ctx) {
        if(typeof(this.state.localVars[value.name]) !== 'object' || this.state.localVars[value.name].type !== 'array') return callback(new Error('attempted to index nonindexable local var'));
        return callback(null, traverseArray(this.state.localVars[value.name], value.ctx));
      }
      return callback(null, this.state.localVars[value.name]);
    case 'prop': // This is a property, fetch it from the object
      // Return an element of the array if provided with an index
      if(value.ctx) return this.mobj.getProp(value.name, function(err, val) {
        if(err) return callback(err);
        if(typeof(val) !== 'object' || val.type !== 'array') return callback(new Error('attempted to index nonindexable object prop'));
        return callback(null, traverseArray(val, value.ctx));
      });
      return this.mobj.getProp(value.name, callback);
    case 'objectIdAlias': // This is an object id alias, ask the app for what it means
      return callback(null, this._app.resolveObjIdAlias(value.value));
    default: // This may be an object like a virtual null, just pass it through
      return callback(null, value);
  }
}

// Evaluate simple expresisons, like 4 * 5
// Async because resolveValue _might_ hit the DB
VM.prototype.evalExpr = function(expr, finalCallback) {
  expr = expr.slice(); // Shallow copy expr, as we will be modifying it
  // First, if the second component is not an operator and the whole expression
  // has no JS objects/hashes, then just return the expression joined by space
  // UNLESS, the first component is a number
  if(OPERATORS[expr[1]] === undefined && typeof(expr[0]) !== 'number') {
    var noObjects = true;
    for(var obj of expr) { if(typeof(obj) === 'object') { noObjects = false; break; }}
    if(noObjects) return finalCallback(null, expr.join(' '));
  }

  var parseAllOps = function(opTypeIndex) {
    var nextOpType = function() {
      if(opTypeIndex + 1 >= OP_ORDER.length || expr.length < 2) {
        finalCallback(null, expr[0]); // The result should be the only thing remaining
                                      // in the expression.
      } else {
        parseAllOps(opTypeIndex + 1);
      }
    }.bind(this);
    var op = OP_ORDER[opTypeIndex];

    var nextOp = function() { // We shouldn't need an index of where to search
                              // for the next op if we delete the op and replace
                              // it with it's result
      var opIndex = expr.indexOf(op);
      if(opIndex === -1) return nextOpType(); // Find the next op type if there is no more of this op type
      async.map([expr[opIndex-1], expr[opIndex+1]], this.resolveValue.bind(this), function(err, results) {
        if(err) return finalCallback(err);
        // We have our resolved results in the results array, left = [0], right = [1]
        var left = results[0], right = results[1];
        // Check types
        if(TYPE_COMPATIBILITY[op] !== undefined && TYPE_COMPATIBILITY[op][typeof(right)].indexOf(typeof(left)) < 0) return finalCallback(new Error('type ' + typeof(left) + ' cannot be opped ' + op + ' with ' + typeof(right)));
        // Splice out the op and the right side from the expression
        expr.splice(opIndex, 2);
        // Set the opIndex - 1 (left side which is still intact) to the result
        expr[opIndex - 1] = OPERATORS[op](left, right);
        // Find the next op of this type
        nextOp();
      }.bind(this));
    }.bind(this);

    nextOp();
  }.bind(this);

  parseAllOps(0);
}

VM.prototype.stepOnce = function(callback) {
  // First find the Instruction
  var ins = VM.findIns(this.state.ip, this.state.ast); // _that was easy_

  // Finishes job by incrementing the IP accordingly
  var jobDone = function(err, results) {
    if(err) return callback(err);
    // If this is a branching instruction and we need to branch (results[0]),
    // branch instead of incrementing the IP
    if((ins.type === 'if' || ins.type === 'while') && results && ins.block.length > 0) {
      this.state.ip.push(0); // This simply bumps us into the next instruction to the right on the AST
      return callback();
    } else {
      // Otherwise, we need to decide what to do
      var progressIP = function() {
        // While we are at the end of the current block (if we are)
        while(this.state.ip.length > 1 &&
              this.state.ip.slice(-1)[0] ===
              VM.findIns(this.state.ip.slice(0, -1), this.state.ast).block.length - 1) {
          if(VM.findIns(this.state.ip.slice(0, -1), this.state.ast).type === 'while') {
            // Consider looping around
            // Reevaluate the condition and if it is true, go back to the top of
            // the loop (set ip[ip.length - 1] = 0)
            // Otherwise pop off the path from ip
            this.evalExpr(VM.findIns(this.state.ip.slice(0, -1), this.state.ast).expr, function(err, value) {
              if(err) return callback(err); // If we couldn't eval the expression, error
              if(value) {
                // Restart loop
                this.state.ip[this.state.ip.length - 1] = 0;
                return callback();
              } else {
                // Pop off the current state to return to where we were
                this.state.ip.pop(); // Pop off the current state

                return progressIP(); // This runs through the whole escape block loop again
              }
            }.bind(this));
            return;
          } else { // Probably an if statement, just pop off the stack
            this.state.ip.pop(); // Pop off the current state
          }
        }

        // Are we at the end of the script
        if(this.state.ip.length === 1 && this.state.ip[0] === this.state.ast.length - 1)
          return callback('endOfScript'); // Error with endOfScript

        // Carry on, increment by one
        this.state.ip[this.state.ip.length - 1]++;
        callback(); // Call the callback, everything is done
      }.bind(this);

      progressIP();
    }
  }.bind(this);

  switch(ins.type) {
    case 'while':
    case 'if':
      // while/if statement. Check if expression provided evaluates to true
      // and if so, callback with branch set to true
      this.evalExpr(ins.expr, function(err, value) {
        if(err) return jobDone(err); // If we couldn't eval the expression, error
        var out = false;
        if(value) out = true; // Evaluate the expression using JS's if evaluation
        return jobDone(null, out);
      });
      break;
    case 'assign':
      async.waterfall([
      function(c) { this.evalExpr(ins.src, c); }.bind(this),
      function(value, c) { // We have evaluated the right side of the assignment, set the value.
        if(ins.op === '=') {
          // Simple assignment
          if(ins.dst.type === 'var') {
            // Local variable, just set it here
            this.state.localVars[ins.dst.name] = value;
            c();
          } else if(ins.dst.type === 'prop') {
            // Object prop, set it and pass it the stepOnce callback.
            this.mobj.setProp(ins.dst.name, value, c);
          } else {
            c('unspecifiable error (cac96aa5-fade-4263-a56c-e4cd883447cc)');
          }
        } else {
          // Complex assignment, runs an expression.
          // We need to resolve the dst so we can type check
          this.resolveValue(ins.dst, function(err, currentValue) {
            if(TYPE_COMPATIBILITY[ins.op][typeof(value)].indexOf(typeof(currentValue)) < 0) return c('type ' + typeof(value) + ' cannot be opped ' + ins.op + ' with ' + typeof(currentValue));
            // It's all valid, do the assignment
            currentValue = OPERATORS[ins.op](currentValue, value);
            // Set currentValue back to where it came from
            if(ins.dst.type === 'prop') {
              this.mobj.setProp(ins.dst.name, currentValue, c);
            } else if(ins.dst.type === 'var') {
              this.state.localVars[ins.dst.name] = currentValue;
              return c();
            } else {
              return c('unspecifiable error (13041b5b-7392-400d-9623-44347db5f81e)');
            }
          }.bind(this));
        }
      }.bind(this)], jobDone);
      break;
    case 'verbcall':
      jobDone(); // TODO actually implement the verbcalls
      break;
  }
}

VM.prototype.step = function(times, callback) {
  async.times(times, function(i, next) {
    this.stepOnce(next);
  }.bind(this), callback);
}

module.exports = VM;
<|endoftext|>