text: /**
   * @object Vector3
   * @author Matthew Wagerfield
   */
  FSS.Vector3 = {
    create: function(x, y, z) {
      var vector = new FSS.Array(3);
      this.set(vector, x, y, z);
      return vector;
    },
    clone: function(a) {
      var vector = this.create();
      this.copy(vector, a);
      return vector;
    },
    set: function(target, x, y, z) {
      target[0] = x || 0;
      target[1] = y || 0;
      target[2] = z || 0;
      return this;
    },
    setX: function(target, x) {
      target[0] = x || 0;
      return this;
    },
    setY: function(target, y) {
      target[1] = y || 0;
      return this;
    },
    setZ: function(target, z) {
      target[2] = z || 0;
      return this;
    },
    copy: function(target, a) {
      target[0] = a[0];
      target[1] = a[1];
      target[2] = a[2];
      return this;
    },
    add: function(target, a) {
      target[0] += a[0];
      target[1] += a[1];
      target[2] += a[2];
      return this;
    },
    addVectors: function(target, a, b) {
      target[0] = a[0] + b[0];
      target[1] = a[1] + b[1];
      target[2] = a[2] + b[2];
      return this;
    },
    addScalar: function(target, s) {
      target[0] += s;
      target[1] += s;
      target[2] += s;
      return this;
    },
    subtract: function(target, a) {
      target[0] -= a[0];
      target[1] -= a[1];
      target[2] -= a[2];
      return this;
    },
    subtractVectors: function(target, a, b) {
      target[0] = a[0] - b[0];
      target[1] = a[1] - b[1];
      target[2] = a[2] - b[2];
      return this;
    },
    subtractScalar: function(target, s) {
      target[0] -= s;
      target[1] -= s;
      target[2] -= s;
      return this;
    },
    multiply: function(target, a) {
      target[0] *= a[0];
      target[1] *= a[1];
      target[2] *= a[2];
      return this;
    },
    multiplyVectors: function(target, a, b) {
      target[0] = a[0] * b[0];
      target[1] = a[1] * b[1];
      target[2] = a[2] * b[2];
      return this;
    },
    multiplyScalar: function(target, s) {
      target[0] *= s;
      target[1] *= s;
      target[2] *= s;
      return this;
    },
    divide: function(target, a) {
      target[0] /= a[0];
      target[1] /= a[1];
      target[2] /= a[2];
      return this;
    },
    divideVectors: function(target, a, b) {
      target[0] = a[0] / b[0];
      target[1] = a[1] / b[1];
      target[2] = a[2] / b[2];
      return this;
    },
    divideScalar: function(target, s) {
      if (s !== 0) {
        target[0] /= s;
        target[1] /= s;
        target[2] /= s;
      } else {
        target[0] = 0;
        target[1] = 0;
        target[2] = 0;
      }
      return this;
    },
    cross: function(target, a) {
      var x = target[0];
      var y = target[1];
      var z = target[2];
      target[0] = y*a[2] - z*a[1];
      target[1] = z*a[0] - x*a[2];
      target[2] = x*a[1] - y*a[0];
      return this;
    },
    crossVectors: function(target, a, b) {
      target[0] = a[1]*b[2] - a[2]*b[1];
      target[1] = a[2]*b[0] - a[0]*b[2];
      target[2] = a[0]*b[1] - a[1]*b[0];
      return this;
    },
    min: function(target, value) {
      if (target[0] < value) { target[0] = value; }
      if (target[1] < value) { target[1] = value; }
      if (target[2] < value) { target[2] = value; }
      return this;
    },
    max: function(target, value) {
      if (target[0] > value) { target[0] = value; }
      if (target[1] > value) { target[1] = value; }
      if (target[2] > value) { target[2] = value; }
      return this;
    },
    clamp: function(target, min, max) {
      this.min(target, min);
      this.max(target, max);
      return this;
    },
    limit: function(target, min, max) {
      var length = this.length(target);
      if (min !== null && length < min) {
        this.setLength(target, min);
      } else if (max !== null && length > max) {
        this.setLength(target, max);
      }
      return this;
    },
    dot: function(a, b) {
      return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
    },
    normalise: function(target) {
      return this.divideScalar(target, this.length(target));
    },
    negate: function(target) {
      return this.multiplyScalar(target, -1);
    },
    distanceSquared: function(a, b) {
      var dx = a[0] - b[0];
      var dy = a[1] - b[1];
      var dz = a[2] - b[2];
      return dx*dx + dy*dy + dz*dz;
    },
    distance: function(a, b) {
      return Math.sqrt(this.distanceSquared(a, b));
    },
    lengthSquared: function(a) {
      return a[0]*a[0] + a[1]*a[1] + a[2]*a[2];
    },
    length: function(a) {
      return Math.sqrt(this.lengthSquared(a));
    },
    setLength: function(target, l) {
      var length = this.length(target);
      if (length !== 0 && l !== length) {
        this.multiplyScalar(target, l / length);
      }
      return this;
    }
  };
  