text: /**
   * Cesium - https://github.com/AnalyticalGraphicsInc/cesium
   *
   * Copyright 2011-2017 Cesium Contributors
   *
   * 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.
   *
   * Columbus View (Pat. Pend.)
   *
   * Portions licensed separately.
   * See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md for full licensing details.
   */
  (function () {
  define('Core/defined',[],function() {
      'use strict';
  
      /**
       * @exports defined
       *
       * @param {*} value The object.
       * @returns {Boolean} Returns true if the object is defined, returns false otherwise.
       *
       * @example
       * if (Cesium.defined(positions)) {
       *      doSomething();
       * } else {
       *      doSomethingElse();
       * }
       */
      function defined(value) {
          return value !== undefined && value !== null;
      }
  
      return defined;
  });
  
  define('Core/freezeObject',[
          './defined'
      ], function(
          defined) {
      'use strict';
  
      /**
       * Freezes an object, using Object.freeze if available, otherwise returns
       * the object unchanged.  This function should be used in setup code to prevent
       * errors from completely halting JavaScript execution in legacy browsers.
       *
       * @private
       *
       * @exports freezeObject
       */
      var freezeObject = Object.freeze;
      if (!defined(freezeObject)) {
          freezeObject = function(o) {
              return o;
          };
      }
  
      return freezeObject;
  });
  
  define('Core/defaultValue',[
          './freezeObject'
      ], function(
          freezeObject) {
      'use strict';
  
      /**
       * Returns the first parameter if not undefined, otherwise the second parameter.
       * Useful for setting a default value for a parameter.
       *
       * @exports defaultValue
       *
       * @param {*} a
       * @param {*} b
       * @returns {*} Returns the first parameter if not undefined, otherwise the second parameter.
       *
       * @example
       * param = Cesium.defaultValue(param, 'default');
       */
      function defaultValue(a, b) {
          if (a !== undefined && a !== null) {
              return a;
          }
          return b;
      }
  
      /**
       * A frozen empty object that can be used as the default value for options passed as
       * an object literal.
       * @type {Object}
       */
      defaultValue.EMPTY_OBJECT = freezeObject({});
  
      return defaultValue;
  });
  
  define('Core/DeveloperError',[
          './defined'
      ], function(
          defined) {
      'use strict';
  
      /**
       * Constructs an exception object that is thrown due to a developer error, e.g., invalid argument,
       * argument out of range, etc.  This exception should only be thrown during development;
       * it usually indicates a bug in the calling code.  This exception should never be
       * caught; instead the calling code should strive not to generate it.
       * <br /><br />
       * On the other hand, a {@link RuntimeError} indicates an exception that may
       * be thrown at runtime, e.g., out of memory, that the calling code should be prepared
       * to catch.
       *
       * @alias DeveloperError
       * @constructor
       * @extends Error
       *
       * @param {String} [message] The error message for this exception.
       *
       * @see RuntimeError
       */
      function DeveloperError(message) {
          /**
           * 'DeveloperError' indicating that this exception was thrown due to a developer error.
           * @type {String}
           * @readonly
           */
          this.name = 'DeveloperError';
  
          /**
           * The explanation for why this exception was thrown.
           * @type {String}
           * @readonly
           */
          this.message = message;
  
          //Browsers such as IE don't have a stack property until you actually throw the error.
          var stack;
          try {
              throw new Error();
          } catch (e) {
              stack = e.stack;
          }
  
          /**
           * The stack trace of this exception, if available.
           * @type {String}
           * @readonly
           */
          this.stack = stack;
      }
  
      if (defined(Object.create)) {
          DeveloperError.prototype = Object.create(Error.prototype);
          DeveloperError.prototype.constructor = DeveloperError;
      }
  
      DeveloperError.prototype.toString = function() {
          var str = this.name + ': ' + this.message;
  
          if (defined(this.stack)) {
              str += '\n' + this.stack.toString();
          }
  
          return str;
      };
  
      /**
       * @private
       */
      DeveloperError.throwInstantiationError = function() {
          throw new DeveloperError('This function defines an interface and should not be called directly.');
      };
  
      return DeveloperError;
  });
  
  define('Core/defineProperties',[
          './defined'
      ], function(
          defined) {
      'use strict';
  
      var definePropertyWorks = (function() {
          try {
              return 'x' in Object.defineProperty({}, 'x', {});
          } catch (e) {
              return false;
          }
      })();
  
      /**
       * Defines properties on an object, using Object.defineProperties if available,
       * otherwise returns the object unchanged.  This function should be used in
       * setup code to prevent errors from completely halting JavaScript execution
       * in legacy browsers.
       *
       * @private
       *
       * @exports defineProperties
       */
      var defineProperties = Object.defineProperties;
      if (!definePropertyWorks || !defined(defineProperties)) {
          defineProperties = function(o) {
              return o;
          };
      }
  
      return defineProperties;
  });
  
  define('Core/Fullscreen',[
          './defined',
          './defineProperties'
      ], function(
          defined,
          defineProperties) {
      'use strict';
  
      var _supportsFullscreen;
      var _names = {
          requestFullscreen : undefined,
          exitFullscreen : undefined,
          fullscreenEnabled : undefined,
          fullscreenElement : undefined,
          fullscreenchange : undefined,
          fullscreenerror : undefined
      };
  
      /**
       * Browser-independent functions for working with the standard fullscreen API.
       *
       * @exports Fullscreen
       * @namespace
       *
       * @see {@link http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html|W3C Fullscreen Living Specification}
       */
      var Fullscreen = {};
  
      defineProperties(Fullscreen, {
          /**
           * The element that is currently fullscreen, if any.  To simply check if the
           * browser is in fullscreen mode or not, use {@link Fullscreen#fullscreen}.
           * @memberof Fullscreen
           * @type {Object}
           * @readonly
           */
          element : {
              get : function() {
                  if (!Fullscreen.supportsFullscreen()) {
                      return undefined;
                  }
  
                  return document[_names.fullscreenElement];
              }
          },
  
          /**
           * The name of the event on the document that is fired when fullscreen is
           * entered or exited.  This event name is intended for use with addEventListener.
           * In your event handler, to determine if the browser is in fullscreen mode or not,
           * use {@link Fullscreen#fullscreen}.
           * @memberof Fullscreen
           * @type {String}
           * @readonly
           */
          changeEventName : {
              get : function() {
                  if (!Fullscreen.supportsFullscreen()) {
                      return undefined;
                  }
  
                  return _names.fullscreenchange;
              }
          },
  
          /**
           * The name of the event that is fired when a fullscreen error
           * occurs.  This event name is intended for use with addEventListener.
           * @memberof Fullscreen
           * @type {String}
           * @readonly
           */
          errorEventName : {
              get : function() {
                  if (!Fullscreen.supportsFullscreen()) {
                      return undefined;
                  }
  
                  return _names.fullscreenerror;
              }
          },
  
          /**
           * Determine whether the browser will allow an element to be made fullscreen, or not.
           * For example, by default, iframes cannot go fullscreen unless the containing page
           * adds an "allowfullscreen" attribute (or prefixed equivalent).
           * @memberof Fullscreen
           * @type {Boolean}
           * @readonly
           */
          enabled : {
              get : function() {
                  if (!Fullscreen.supportsFullscreen()) {
                      return undefined;
                  }
  
                  return document[_names.fullscreenEnabled];
              }
          },
  
          /**
           * Determines if the browser is currently in fullscreen mode.
           * @memberof Fullscreen
           * @type {Boolean}
           * @readonly
           */
          fullscreen : {
              get : function() {
                  if (!Fullscreen.supportsFullscreen()) {
                      return undefined;
                  }
  
                  return Fullscreen.element !== null;
              }
          }
      });
  
      /**
       * Detects whether the browser supports the standard fullscreen API.
       *
       * @returns {Boolean} <code>true</code> if the browser supports the standard fullscreen API,
       * <code>false</code> otherwise.
       */
      Fullscreen.supportsFullscreen = function() {
          if (defined(_supportsFullscreen)) {
              return _supportsFullscreen;
          }
  
          _supportsFullscreen = false;
  
          var body = document.body;
          if (typeof body.requestFullscreen === 'function') {
              // go with the unprefixed, standard set of names
              _names.requestFullscreen = 'requestFullscreen';
              _names.exitFullscreen = 'exitFullscreen';
              _names.fullscreenEnabled = 'fullscreenEnabled';
              _names.fullscreenElement = 'fullscreenElement';
              _names.fullscreenchange = 'fullscreenchange';
              _names.fullscreenerror = 'fullscreenerror';
              _supportsFullscreen = true;
              return _supportsFullscreen;
          }
  
          //check for the correct combination of prefix plus the various names that browsers use
          var prefixes = ['webkit', 'moz', 'o', 'ms', 'khtml'];
          var name;
          for (var i = 0, len = prefixes.length; i < len; ++i) {
              var prefix = prefixes[i];
  
              // casing of Fullscreen differs across browsers
              name = prefix + 'RequestFullscreen';
              if (typeof body[name] === 'function') {
                  _names.requestFullscreen = name;
                  _supportsFullscreen = true;
              } else {
                  name = prefix + 'RequestFullScreen';
                  if (typeof body[name] === 'function') {
                      _names.requestFullscreen = name;
                      _supportsFullscreen = true;
                  }
              }
  
              // disagreement about whether it's "exit" as per spec, or "cancel"
              name = prefix + 'ExitFullscreen';
              if (typeof document[name] === 'function') {
                  _names.exitFullscreen = name;
              } else {
                  name = prefix + 'CancelFullScreen';
                  if (typeof document[name] === 'function') {
                      _names.exitFullscreen = name;
                  }
              }
  
              // casing of Fullscreen differs across browsers
              name = prefix + 'FullscreenEnabled';
              if (document[name] !== undefined) {
                  _names.fullscreenEnabled = name;
              } else {
                  name = prefix + 'FullScreenEnabled';
                  if (document[name] !== undefined) {
                      _names.fullscreenEnabled = name;
                  }
              }
  
              // casing of Fullscreen differs across browsers
              name = prefix + 'FullscreenElement';
              if (document[name] !== undefined) {
                  _names.fullscreenElement = name;
              } else {
                  name = prefix + 'FullScreenElement';
                  if (document[name] !== undefined) {
                      _names.fullscreenElement = name;
                  }
              }
  
              // thankfully, event names are all lowercase per spec
              name = prefix + 'fullscreenchange';
              // event names do not have 'on' in the front, but the property on the document does
              if (document['on' + name] !== undefined) {
                  //except on IE
                  if (prefix === 'ms') {
                      name = 'MSFullscreenChange';
                  }
                  _names.fullscreenchange = name;
              }
  
              name = prefix + 'fullscreenerror';
              if (document['on' + name] !== undefined) {
                  //except on IE
                  if (prefix === 'ms') {
                      name = 'MSFullscreenError';
                  }
                  _names.fullscreenerror = name;
              }
          }
  
          return _supportsFullscreen;
      };
  
      /**
       * Asynchronously requests the browser to enter fullscreen mode on the given element.
       * If fullscreen mode is not supported by the browser, does nothing.
       *
       * @param {Object} element The HTML element which will be placed into fullscreen mode.
       * @param {HMDVRDevice} [vrDevice] The VR device.
       *
       * @example
       * // Put the entire page into fullscreen.
       * Cesium.Fullscreen.requestFullscreen(document.body)
       *
       * // Place only the Cesium canvas into fullscreen.
       * Cesium.Fullscreen.requestFullscreen(scene.canvas)
       */
      Fullscreen.requestFullscreen = function(element, vrDevice) {
          if (!Fullscreen.supportsFullscreen()) {
              return;
          }
  
          element[_names.requestFullscreen]({ vrDisplay: vrDevice });
      };
  
      /**
       * Asynchronously exits fullscreen mode.  If the browser is not currently
       * in fullscreen, or if fullscreen mode is not supported by the browser, does nothing.
       */
      Fullscreen.exitFullscreen = function() {
          if (!Fullscreen.supportsFullscreen()) {
              return;
          }
  
          document[_names.exitFullscreen]();
      };
  
      return Fullscreen;
  });
  
  /**
    @license
    when.js - https://github.com/cujojs/when
  
    MIT License (c) copyright B Cavalier & J Hann
  
   * A lightweight CommonJS Promises/A and when() implementation
   * when is part of the cujo.js family of libraries (http://cujojs.com/)
   *
   * Licensed under the MIT License at:
   * http://www.opensource.org/licenses/mit-license.php
   *
   * @version 1.7.1
   */
  
  (function(define) { 'use strict';
  define('ThirdParty/when',[],function () {
  	var reduceArray, slice, undef;
  
  	//
  	// Public API
  	//
  
  	when.defer     = defer;     // Create a deferred
  	when.resolve   = resolve;   // Create a resolved promise
  	when.reject    = reject;    // Create a rejected promise
  
  	when.join      = join;      // Join 2 or more promises
  
  	when.all       = all;       // Resolve a list of promises
  	when.map       = map;       // Array.map() for promises
  	when.reduce    = reduce;    // Array.reduce() for promises
  
  	when.any       = any;       // One-winner race
  	when.some      = some;      // Multi-winner race
  
  	when.chain     = chain;     // Make a promise trigger another resolver
  
  	when.isPromise = isPromise; // Determine if a thing is a promise
  
  	/**
  	 * Register an observer for a promise or immediate value.
  	 *
  	 * @param {*} promiseOrValue
  	 * @param {function?} [onFulfilled] callback to be called when promiseOrValue is
  	 *   successfully fulfilled.  If promiseOrValue is an immediate value, callback
  	 *   will be invoked immediately.
  	 * @param {function?} [onRejected] callback to be called when promiseOrValue is
  	 *   rejected.
  	 * @param {function?} [onProgress] callback to be called when progress updates
  	 *   are issued for promiseOrValue.
  	 * @returns {Promise} a new {@link Promise} that will complete with the return
  	 *   value of callback or errback or the completion value of promiseOrValue if
  	 *   callback and/or errback is not supplied.
  	 */
  	function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
  		// Get a trusted promise for the input promiseOrValue, and then
  		// register promise handlers
  		return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
  	}
  
  	/**
  	 * Returns promiseOrValue if promiseOrValue is a {@link Promise}, a new Promise if
  	 * promiseOrValue is a foreign promise, or a new, already-fulfilled {@link Promise}
  	 * whose value is promiseOrValue if promiseOrValue is an immediate value.
  	 *
  	 * @param {*} promiseOrValue
  	 * @returns Guaranteed to return a trusted Promise.  If promiseOrValue is a when.js {@link Promise}
  	 *   returns promiseOrValue, otherwise, returns a new, already-resolved, when.js {@link Promise}
  	 *   whose resolution value is:
  	 *   * the resolution value of promiseOrValue if it's a foreign promise, or
  	 *   * promiseOrValue if it's a value
  	 */
  	function resolve(promiseOrValue) {
  		var promise, deferred;
  
  		if(promiseOrValue instanceof Promise) {
  			// It's a when.js promise, so we trust it
  			promise = promiseOrValue;
  
  		} else {
  			// It's not a when.js promise. See if it's a foreign promise or a value.
  			if(isPromise(promiseOrValue)) {
  				// It's a thenable, but we don't know where it came from, so don't trust
  				// its implementation entirely.  Introduce a trusted middleman when.js promise
  				deferred = defer();
  
  				// IMPORTANT: This is the only place when.js should ever call .then() on an
  				// untrusted promise. Don't expose the return value to the untrusted promise
  				promiseOrValue.then(
  					function(value)  { deferred.resolve(value); },
  					function(reason) { deferred.reject(reason); },
  					function(update) { deferred.progress(update); }
  				);
  
  				promise = deferred.promise;
  
  			} else {
  				// It's a value, not a promise.  Create a resolved promise for it.
  				promise = fulfilled(promiseOrValue);
  			}
  		}
  
  		return promise;
  	}
  
  	/**
  	 * Returns a rejected promise for the supplied promiseOrValue.  The returned
  	 * promise will be rejected with:
  	 * - promiseOrValue, if it is a value, or
  	 * - if promiseOrValue is a promise
  	 *   - promiseOrValue's value after it is fulfilled
  	 *   - promiseOrValue's reason after it is rejected
  	 * @param {*} promiseOrValue the rejected value of the returned {@link Promise}
  	 * @returns {Promise} rejected {@link Promise}
  	 */
  	function reject(promiseOrValue) {
  		return when(promiseOrValue, rejected);
  	}
  
  	/**
  	 * Trusted Promise constructor.  A Promise created from this constructor is
  	 * a trusted when.js promise.  Any other duck-typed promise is considered
  	 * untrusted.
  	 * @constructor
  	 * @name Promise
  	 */
  	function Promise(then) {
  		this.then = then;
  	}
  
  	Promise.prototype = {
  		/**
  		 * Register a callback that will be called when a promise is
  		 * fulfilled or rejected.  Optionally also register a progress handler.
  		 * Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress)
  		 * @param {function?} [onFulfilledOrRejected]
  		 * @param {function?} [onProgress]
  		 * @returns {Promise}
  		 */
  		always: function(onFulfilledOrRejected, onProgress) {
  			return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
  		},
  
  		/**
  		 * Register a rejection handler.  Shortcut for .then(undefined, onRejected)
  		 * @param {function?} onRejected
  		 * @returns {Promise}
  		 */
  		otherwise: function(onRejected) {
  			return this.then(undef, onRejected);
  		},
  
  		/**
  		 * Shortcut for .then(function() { return value; })
  		 * @param  {*} value
  		 * @returns {Promise} a promise that:
  		 *  - is fulfilled if value is not a promise, or
  		 *  - if value is a promise, will fulfill with its value, or reject
  		 *    with its reason.
  		 */
  		yield: function(value) {
  			return this.then(function() {
  				return value;
  			});
  		},
  
  		/**
  		 * Assumes that this promise will fulfill with an array, and arranges
  		 * for the onFulfilled to be called with the array as its argument list
  		 * i.e. onFulfilled.spread(undefined, array).
  		 * @param {function} onFulfilled function to receive spread arguments
  		 * @returns {Promise}
  		 */
  		spread: function(onFulfilled) {
  			return this.then(function(array) {
  				// array may contain promises, so resolve its contents.
  				return all(array, function(array) {
  					return onFulfilled.apply(undef, array);
  				});
  			});
  		}
  	};
  
  	/**
  	 * Create an already-resolved promise for the supplied value
  	 * @private
  	 *
  	 * @param {*} value
  	 * @returns {Promise} fulfilled promise
  	 */
  	function fulfilled(value) {
  		var p = new Promise(function(onFulfilled) {
  			// TODO: Promises/A+ check typeof onFulfilled
  			try {
  				return resolve(onFulfilled ? onFulfilled(value) : value);
  			} catch(e) {
  				return rejected(e);
  			}
  		});
  
  		return p;
  	}
  
  	/**
  	 * Create an already-rejected {@link Promise} with the supplied
  	 * rejection reason.
  	 * @private
  	 *
  	 * @param {*} reason
  	 * @returns {Promise} rejected promise
  	 */
  	function rejected(reason) {
  		var p = new Promise(function(_, onRejected) {
  			// TODO: Promises/A+ check typeof onRejected
  			try {
  				return onRejected ? resolve(onRejected(reason)) : rejected(reason);
  			} catch(e) {
  				return rejected(e);
  			}
  		});
  
  		return p;
  	}
  
  	/**
  	 * Creates a new, Deferred with fully isolated resolver and promise parts,
  	 * either or both of which may be given out safely to consumers.
  	 * The Deferred itself has the full API: resolve, reject, progress, and
  	 * then. The resolver has resolve, reject, and progress.  The promise
  	 * only has then.
  	 *
  	 * @returns {Deferred}
  	 */
  	function defer() {
  		var deferred, promise, handlers, progressHandlers,
  			_then, _progress, _resolve;
  
  		/**
  		 * The promise for the new deferred
  		 * @type {Promise}
  		 */
  		promise = new Promise(then);
  
  		/**
  		 * The full Deferred object, with {@link Promise} and {@link Resolver} parts
  		 * @class Deferred
  		 * @name Deferred
  		 */
  		deferred = {
  			then:     then, // DEPRECATED: use deferred.promise.then
  			resolve:  promiseResolve,
  			reject:   promiseReject,
  			// TODO: Consider renaming progress() to notify()
  			progress: promiseProgress,
  
  			promise:  promise,
  
  			resolver: {
  				resolve:  promiseResolve,
  				reject:   promiseReject,
  				progress: promiseProgress
  			}
  		};
  
  		handlers = [];
  		progressHandlers = [];
  
  		/**
  		 * Pre-resolution then() that adds the supplied callback, errback, and progback
  		 * functions to the registered listeners
  		 * @private
  		 *
  		 * @param {function?} [onFulfilled] resolution handler
  		 * @param {function?} [onRejected] rejection handler
  		 * @param {function?} [onProgress] progress handler
  		 */
  		_then = function(onFulfilled, onRejected, onProgress) {
  			// TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress
  			var deferred, progressHandler;
  
  			deferred = defer();
  
  			progressHandler = typeof onProgress === 'function'
  				? function(update) {
  					try {
  						// Allow progress handler to transform progress event
  						deferred.progress(onProgress(update));
  					} catch(e) {
  						// Use caught value as progress
  						deferred.progress(e);
  					}
  				}
  				: function(update) { deferred.progress(update); };
  
  			handlers.push(function(promise) {
  				promise.then(onFulfilled, onRejected)
  					.then(deferred.resolve, deferred.reject, progressHandler);
  			});
  
  			progressHandlers.push(progressHandler);
  
  			return deferred.promise;
  		};
  
  		/**
  		 * Issue a progress event, notifying all progress listeners
  		 * @private
  		 * @param {*} update progress event payload to pass to all listeners
  		 */
  		_progress = function(update) {
  			processQueue(progressHandlers, update);
  			return update;
  		};
  
  		/**
  		 * Transition from pre-resolution state to post-resolution state, notifying
  		 * all listeners of the resolution or rejection
  		 * @private
  		 * @param {*} value the value of this deferred
  		 */
  		_resolve = function(value) {
  			value = resolve(value);
  
  			// Replace _then with one that directly notifies with the result.
  			_then = value.then;
  			// Replace _resolve so that this Deferred can only be resolved once
  			_resolve = resolve;
  			// Make _progress a noop, to disallow progress for the resolved promise.
  			_progress = noop;
  
  			// Notify handlers
  			processQueue(handlers, value);
  
  			// Free progressHandlers array since we'll never issue progress events
  			progressHandlers = handlers = undef;
  
  			return value;
  		};
  
  		return deferred;
  
  		/**
  		 * Wrapper to allow _then to be replaced safely
  		 * @param {function?} [onFulfilled] resolution handler
  		 * @param {function?} [onRejected] rejection handler
  		 * @param {function?} [onProgress] progress handler
  		 * @returns {Promise} new promise
  		 */
  		function then(onFulfilled, onRejected, onProgress) {
  			// TODO: Promises/A+ check typeof onFulfilled, onRejected, onProgress
  			return _then(onFulfilled, onRejected, onProgress);
  		}
  
  		/**
  		 * Wrapper to allow _resolve to be replaced
  		 */
  		function promiseResolve(val) {
  			return _resolve(val);
  		}
  
  		/**
  		 * Wrapper to allow _reject to be replaced
  		 */
  		function promiseReject(err) {
  			return _resolve(rejected(err));
  		}
  
  		/**
  		 * Wrapper to allow _progress to be replaced
  		 */
  		function promiseProgress(update) {
  			return _progress(update);
  		}
  	}
  
  	/**
  	 * Determines if promiseOrValue is a promise or not.  Uses the feature
  	 * test from http://wiki.commonjs.org/wiki/Promises/A to determine if
  	 * promiseOrValue is a promise.
  	 *
  	 * @param {*} promiseOrValue anything
  	 * @returns {boolean} true if promiseOrValue is a {@link Promise}
  	 */
  	function isPromise(promiseOrValue) {
  		return promiseOrValue && typeof promiseOrValue.then === 'function';
  	}
  
  	/**
  	 * Initiates a competitive race, returning a promise that will resolve when
  	 * howMany of the supplied promisesOrValues have resolved, or will reject when
  	 * it becomes impossible for howMany to resolve, for example, when
  	 * (promisesOrValues.length - howMany) + 1 input promises reject.
  	 *
  	 * @param {Array} promisesOrValues array of anything, may contain a mix
  	 *      of promises and values
  	 * @param howMany {number} number of promisesOrValues to resolve
  	 * @param {function?} [onFulfilled] resolution handler
  	 * @param {function?} [onRejected] rejection handler
  	 * @param {function?} [onProgress] progress handler
  	 * @returns {Promise} promise that will resolve to an array of howMany values that
  	 * resolved first, or will reject with an array of (promisesOrValues.length - howMany) + 1
  	 * rejection reasons.
  	 */
  	function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) {
  
  		checkCallbacks(2, arguments);
  
  		return when(promisesOrValues, function(promisesOrValues) {
  
  			var toResolve, toReject, values, reasons, deferred, fulfillOne, rejectOne, progress, len, i;
  
  			len = promisesOrValues.length >>> 0;
  
  			toResolve = Math.max(0, Math.min(howMany, len));
  			values = [];
  
  			toReject = (len - toResolve) + 1;
  			reasons = [];
  
  			deferred = defer();
  
  			// No items in the input, resolve immediately
  			if (!toResolve) {
  				deferred.resolve(values);
  
  			} else {
  				progress = deferred.progress;
  
  				rejectOne = function(reason) {
  					reasons.push(reason);
  					if(!--toReject) {
  						fulfillOne = rejectOne = noop;
  						deferred.reject(reasons);
  					}
  				};
  
  				fulfillOne = function(val) {
  					// This orders the values based on promise resolution order
  					// Another strategy would be to use the original position of
  					// the corresponding promise.
  					values.push(val);
  
  					if (!--toResolve) {
  						fulfillOne = rejectOne = noop;
  						deferred.resolve(values);
  					}
  				};
  
  				for(i = 0; i < len; ++i) {
  					if(i in promisesOrValues) {
  						when(promisesOrValues[i], fulfiller, rejecter, progress);
  					}
  				}
  			}
  
  			return deferred.then(onFulfilled, onRejected, onProgress);
  
  			function rejecter(reason) {
  				rejectOne(reason);
  			}
  
  			function fulfiller(val) {
  				fulfillOne(val);
  			}
  
  		});
  	}
  
  	/**
  	 * Initiates a competitive race, returning a promise that will resolve when
  	 * any one of the supplied promisesOrValues has resolved or will reject when
  	 * *all* promisesOrValues have rejected.
  	 *
  	 * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
  	 *      of {@link Promise}s and values
  	 * @param {function?} [onFulfilled] resolution handler
  	 * @param {function?} [onRejected] rejection handler
  	 * @param {function?} [onProgress] progress handler
  	 * @returns {Promise} promise that will resolve to the value that resolved first, or
  	 * will reject with an array of all rejected inputs.
  	 */
  	function any(promisesOrValues, onFulfilled, onRejected, onProgress) {
  
  		function unwrapSingleResult(val) {
  			return onFulfilled ? onFulfilled(val[0]) : val[0];
  		}
  
  		return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress);
  	}
  
  	/**
  	 * Return a promise that will resolve only once all the supplied promisesOrValues
  	 * have resolved. The resolution value of the returned promise will be an array
  	 * containing the resolution values of each of the promisesOrValues.
  	 * @memberOf when
  	 *
  	 * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
  	 *      of {@link Promise}s and values
  	 * @param {function?} [onFulfilled] resolution handler
  	 * @param {function?} [onRejected] rejection handler
  	 * @param {function?} [onProgress] progress handler
  	 * @returns {Promise}
  	 */
  	function all(promisesOrValues, onFulfilled, onRejected, onProgress) {
  		checkCallbacks(1, arguments);
  		return map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress);
  	}
  
  	/**
  	 * Joins multiple promises into a single returned promise.
  	 * @returns {Promise} a promise that will fulfill when *all* the input promises
  	 * have fulfilled, or will reject when *any one* of the input promises rejects.
  	 */
  	function join(/* ...promises */) {
  		return map(arguments, identity);
  	}
  
  	/**
  	 * Traditional map function, similar to `Array.prototype.map()`, but allows
  	 * input to contain {@link Promise}s and/or values, and mapFunc may return
  	 * either a value or a {@link Promise}
  	 *
  	 * @param {Array|Promise} promise array of anything, may contain a mix
  	 *      of {@link Promise}s and values
  	 * @param {function} mapFunc mapping function mapFunc(value) which may return
  	 *      either a {@link Promise} or value
  	 * @returns {Promise} a {@link Promise} that will resolve to an array containing
  	 *      the mapped output values.
  	 */
  	function map(promise, mapFunc) {
  		return when(promise, function(array) {
  			var results, len, toResolve, resolve, i, d;
  
  			// Since we know the resulting length, we can preallocate the results
  			// array to avoid array expansions.
  			toResolve = len = array.length >>> 0;
  			results = [];
  			d = defer();
  
  			if(!toResolve) {
  				d.resolve(results);
  			} else {
  
  				resolve = function resolveOne(item, i) {
  					when(item, mapFunc).then(function(mapped) {
  						results[i] = mapped;
  
  						if(!--toResolve) {
  							d.resolve(results);
  						}
  					}, d.reject);
  				};
  
  				// Since mapFunc may be async, get all invocations of it into flight
  				for(i = 0; i < len; i++) {
  					if(i in array) {
  						resolve(array[i], i);
  					} else {
  						--toResolve;
  					}
  				}
  
  			}
  
  			return d.promise;
  
  		});
  	}
  
  	/**
  	 * Traditional reduce function, similar to `Array.prototype.reduce()`, but
  	 * input may contain promises and/or values, and reduceFunc
  	 * may return either a value or a promise, *and* initialValue may
  	 * be a promise for the starting value.
  	 *
  	 * @param {Array|Promise} promise array or promise for an array of anything,
  	 *      may contain a mix of promises and values.
  	 * @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total),
  	 *      where total is the total number of items being reduced, and will be the same
  	 *      in each call to reduceFunc.
  	 * @returns {Promise} that will resolve to the final reduced value
  	 */
  	function reduce(promise, reduceFunc /*, initialValue */) {
  		var args = slice.call(arguments, 1);
  
  		return when(promise, function(array) {
  			var total;
  
  			total = array.length;
  
  			// Wrap the supplied reduceFunc with one that handles promises and then
  			// delegates to the supplied.
  			args[0] = function (current, val, i) {
  				return when(current, function (c) {
  					return when(val, function (value) {
  						return reduceFunc(c, value, i, total);
  					});
  				});
  			};
  
  			return reduceArray.apply(array, args);
  		});
  	}
  
  	/**
  	 * Ensure that resolution of promiseOrValue will trigger resolver with the
  	 * value or reason of promiseOrValue, or instead with resolveValue if it is provided.
  	 *
  	 * @param promiseOrValue
  	 * @param {Object} resolver
  	 * @param {function} resolver.resolve
  	 * @param {function} resolver.reject
  	 * @param {*} [resolveValue]
  	 * @returns {Promise}
  	 */
  	function chain(promiseOrValue, resolver, resolveValue) {
  		var useResolveValue = arguments.length > 2;
  
  		return when(promiseOrValue,
  			function(val) {
  				val = useResolveValue ? resolveValue : val;
  				resolver.resolve(val);
  				return val;
  			},
  			function(reason) {
  				resolver.reject(reason);
  				return rejected(reason);
  			},
  			resolver.progress
  		);
  	}
  
  	//
  	// Utility functions
  	//
  
  	/**
  	 * Apply all functions in queue to value
  	 * @param {Array} queue array of functions to execute
  	 * @param {*} value argument passed to each function
  	 */
  	function processQueue(queue, value) {
  		var handler, i = 0;
  
  		while (handler = queue[i++]) {
  			handler(value);
  		}
  	}
  
  	/**
  	 * Helper that checks arrayOfCallbacks to ensure that each element is either
  	 * a function, or null or undefined.
  	 * @private
  	 * @param {number} start index at which to start checking items in arrayOfCallbacks
  	 * @param {Array} arrayOfCallbacks array to check
  	 * @throws {Error} if any element of arrayOfCallbacks is something other than
  	 * a functions, null, or undefined.
  	 */
  	function checkCallbacks(start, arrayOfCallbacks) {
  		// TODO: Promises/A+ update type checking and docs
  		var arg, i = arrayOfCallbacks.length;
  
  		while(i > start) {
  			arg = arrayOfCallbacks[--i];
  
  			if (arg != null && typeof arg != 'function') {
  				throw new Error('arg '+i+' must be a function');
  			}
  		}
  	}
  
  	/**
  	 * No-Op function used in method replacement
  	 * @private
  	 */
  	function noop() {}
  
  	slice = [].slice;
  
  	// ES5 reduce implementation if native not available
  	// See: http://es5.github.com/#x15.4.4.21 as there are many
  	// specifics and edge cases.
  	reduceArray = [].reduce ||
  		function(reduceFunc /*, initialValue */) {
  			/*jshint maxcomplexity: 7*/
  
  			// ES5 dictates that reduce.length === 1
  
  			// This implementation deviates from ES5 spec in the following ways:
  			// 1. It does not check if reduceFunc is a Callable
  
  			var arr, args, reduced, len, i;
  
  			i = 0;
  			// This generates a jshint warning, despite being valid
  			// "Missing 'new' prefix when invoking a constructor."
  			// See https://github.com/jshint/jshint/issues/392
  			arr = Object(this);
  			len = arr.length >>> 0;
  			args = arguments;
  
  			// If no initialValue, use first item of array (we know length !== 0 here)
  			// and adjust i to start at second item
  			if(args.length <= 1) {
  				// Skip to the first real element in the array
  				for(;;) {
  					if(i in arr) {
  						reduced = arr[i++];
  						break;
  					}
  
  					// If we reached the end of the array without finding any real
  					// elements, it's a TypeError
  					if(++i >= len) {
  						throw new TypeError();
  					}
  				}
  			} else {
  				// If initialValue provided, use it
  				reduced = args[1];
  			}
  
  			// Do the actual reduce
  			for(;i < len; ++i) {
  				// Skip holes
  				if(i in arr) {
  					reduced = reduceFunc(reduced, arr[i], i, arr);
  				}
  			}
  
  			return reduced;
  		};
  
  	function identity(x) {
  		return x;
  	}
  
  	return when;
  });
  })(typeof define == 'function' && define.amd
  	? define
  	: function (factory) { typeof exports === 'object'
  		? (module.exports = factory())
  		: (this.when      = factory());
  	}
  	// Boilerplate for AMD, Node, and browser global
  );
  
  define('Core/FeatureDetection',[
          './defaultValue',
          './defined',
          './defineProperties',
          './DeveloperError',
          './Fullscreen',
          '../ThirdParty/when'
      ], function(
          defaultValue,
          defined,
          defineProperties,
          DeveloperError,
          Fullscreen,
          when) {
      'use strict';
      /*global CanvasPixelArray*/
  
      var theNavigator;
      if (typeof navigator !== 'undefined') {
          theNavigator = navigator;
      } else {
          theNavigator = {};
      }
  
      function extractVersion(versionString) {
          var parts = versionString.split('.');
          for (var i = 0, len = parts.length; i < len; ++i) {
              parts[i] = parseInt(parts[i], 10);
          }
          return parts;
      }
  
      var isChromeResult;
      var chromeVersionResult;
      function isChrome() {
          if (!defined(isChromeResult)) {
              isChromeResult = false;
              // Edge contains Chrome in the user agent too
              if (!isEdge()) {
                  var fields = (/ Chrome\/([\.0-9]+)/).exec(theNavigator.userAgent);
                  if (fields !== null) {
                      isChromeResult = true;
                      chromeVersionResult = extractVersion(fields[1]);
                  }
              }
          }
  
          return isChromeResult;
      }
  
      function chromeVersion() {
          return isChrome() && chromeVersionResult;
      }
  
      var isSafariResult;
      var safariVersionResult;
      function isSafari() {
          if (!defined(isSafariResult)) {
              isSafariResult = false;
  
              // Chrome and Edge contain Safari in the user agent too
              if (!isChrome() && !isEdge() && (/ Safari\/[\.0-9]+/).test(theNavigator.userAgent)) {
                  var fields = (/ Version\/([\.0-9]+)/).exec(theNavigator.userAgent);
                  if (fields !== null) {
                      isSafariResult = true;
                      safariVersionResult = extractVersion(fields[1]);
                  }
              }
          }
  
          return isSafariResult;
      }
  
      function safariVersion() {
          return isSafari() && safariVersionResult;
      }
  
      var isWebkitResult;
      var webkitVersionResult;
      function isWebkit() {
          if (!defined(isWebkitResult)) {
              isWebkitResult = false;
  
              var fields = (/ AppleWebKit\/([\.0-9]+)(\+?)/).exec(theNavigator.userAgent);
              if (fields !== null) {
                  isWebkitResult = true;
                  webkitVersionResult = extractVersion(fields[1]);
                  webkitVersionResult.isNightly = !!fields[2];
              }
          }
  
          return isWebkitResult;
      }
  
      function webkitVersion() {
          return isWebkit() && webkitVersionResult;
      }
  
      var isInternetExplorerResult;
      var internetExplorerVersionResult;
      function isInternetExplorer() {
          if (!defined(isInternetExplorerResult)) {
              isInternetExplorerResult = false;
  
              var fields;
              if (theNavigator.appName === 'Microsoft Internet Explorer') {
                  fields = /MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(theNavigator.userAgent);
                  if (fields !== null) {
                      isInternetExplorerResult = true;
                      internetExplorerVersionResult = extractVersion(fields[1]);
                  }
              } else if (theNavigator.appName === 'Netscape') {
                  fields = /Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(theNavigator.userAgent);
                  if (fields !== null) {
                      isInternetExplorerResult = true;
                      internetExplorerVersionResult = extractVersion(fields[1]);
                  }
              }
          }
          return isInternetExplorerResult;
      }
  
      function internetExplorerVersion() {
          return isInternetExplorer() && internetExplorerVersionResult;
      }
  
      var isEdgeResult;
      var edgeVersionResult;
      function isEdge() {
          if (!defined(isEdgeResult)) {
              isEdgeResult = false;
              var fields = (/ Edge\/([\.0-9]+)/).exec(theNavigator.userAgent);
              if (fields !== null) {
                  isEdgeResult = true;
                  edgeVersionResult = extractVersion(fields[1]);
              }
          }
          return isEdgeResult;
      }
  
      function edgeVersion() {
          return isEdge() && edgeVersionResult;
      }
  
      var isFirefoxResult;
      var firefoxVersionResult;
      function isFirefox() {
          if (!defined(isFirefoxResult)) {
              isFirefoxResult = false;
  
              var fields = /Firefox\/([\.0-9]+)/.exec(theNavigator.userAgent);
              if (fields !== null) {
                  isFirefoxResult = true;
                  firefoxVersionResult = extractVersion(fields[1]);
              }
          }
          return isFirefoxResult;
      }
  
      var isWindowsResult;
      function isWindows() {
          if (!defined(isWindowsResult)) {
              isWindowsResult = /Windows/i.test(theNavigator.appVersion);
          }
          return isWindowsResult;
      }
  
      function firefoxVersion() {
          return isFirefox() && firefoxVersionResult;
      }
  
      var hasPointerEvents;
      function supportsPointerEvents() {
          if (!defined(hasPointerEvents)) {
              //While navigator.pointerEnabled is deprecated in the W3C specification
              //we still need to use it if it exists in order to support browsers
              //that rely on it, such as the Windows WebBrowser control which defines
              //PointerEvent but sets navigator.pointerEnabled to false.
  
              //Firefox disabled because of https://github.com/AnalyticalGraphicsInc/cesium/issues/6372
              hasPointerEvents = !isFirefox() && typeof PointerEvent !== 'undefined' && (!defined(theNavigator.pointerEnabled) || theNavigator.pointerEnabled);
          }
          return hasPointerEvents;
      }
  
      var imageRenderingValueResult;
      var supportsImageRenderingPixelatedResult;
      function supportsImageRenderingPixelated() {
          if (!defined(supportsImageRenderingPixelatedResult)) {
              var canvas = document.createElement('canvas');
              canvas.setAttribute('style',
                                  'image-rendering: -moz-crisp-edges;' +
                                  'image-rendering: pixelated;');
              //canvas.style.imageRendering will be undefined, null or an empty string on unsupported browsers.
              var tmp = canvas.style.imageRendering;
              supportsImageRenderingPixelatedResult = defined(tmp) && tmp !== '';
              if (supportsImageRenderingPixelatedResult) {
                  imageRenderingValueResult = tmp;
              }
          }
          return supportsImageRenderingPixelatedResult;
      }
  
      function imageRenderingValue() {
          return supportsImageRenderingPixelated() ? imageRenderingValueResult : undefined;
      }
  
      function supportsWebP() {
                  if (!supportsWebP.initialized) {
              throw new DeveloperError('You must call FeatureDetection.supportsWebP.initialize and wait for the promise to resolve before calling FeatureDetection.supportsWebP');
          }
                  return supportsWebP._result;
      }
      supportsWebP._promise = undefined;
      supportsWebP._result = undefined;
      supportsWebP.initialize = function() {
          // From https://developers.google.com/speed/webp/faq#how_can_i_detect_browser_support_for_webp
          if (defined(supportsWebP._promise)) {
              return supportsWebP._promise;
          }
  
          var supportsWebPDeferred = when.defer();
          supportsWebP._promise = supportsWebPDeferred.promise;
          if (isEdge()) {
              // Edge's WebP support with WebGL is incomplete.
              // See bug report: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/19221241/
              supportsWebP._result = false;
              supportsWebPDeferred.resolve(supportsWebP._result);
              return supportsWebPDeferred.promise;
          }
  
          var image = new Image();
          image.onload = function () {
              supportsWebP._result = (image.width > 0) && (image.height > 0);
              supportsWebPDeferred.resolve(supportsWebP._result);
          };
  
          image.onerror = function () {
              supportsWebP._result = false;
              supportsWebPDeferred.resolve(supportsWebP._result);
          };
  
          image.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA';
  
          return supportsWebPDeferred.promise;
      };
      defineProperties(supportsWebP, {
          initialized: {
              get: function() {
                  return defined(supportsWebP._result);
              }
          }
      });
  
      var typedArrayTypes = [];
      if (typeof ArrayBuffer !== 'undefined') {
          typedArrayTypes.push(Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array);
  
          if (typeof Uint8ClampedArray !== 'undefined') {
              typedArrayTypes.push(Uint8ClampedArray);
          }
  
          if (typeof CanvasPixelArray !== 'undefined') {
              typedArrayTypes.push(CanvasPixelArray);
          }
      }
  
      /**
       * A set of functions to detect whether the current browser supports
       * various features.
       *
       * @exports FeatureDetection
       */
      var FeatureDetection = {
          isChrome : isChrome,
          chromeVersion : chromeVersion,
          isSafari : isSafari,
          safariVersion : safariVersion,
          isWebkit : isWebkit,
          webkitVersion : webkitVersion,
          isInternetExplorer : isInternetExplorer,
          internetExplorerVersion : internetExplorerVersion,
          isEdge : isEdge,
          edgeVersion : edgeVersion,
          isFirefox : isFirefox,
          firefoxVersion : firefoxVersion,
          isWindows : isWindows,
          hardwareConcurrency : defaultValue(theNavigator.hardwareConcurrency, 3),
          supportsPointerEvents : supportsPointerEvents,
          supportsImageRenderingPixelated: supportsImageRenderingPixelated,
          supportsWebP: supportsWebP,
          imageRenderingValue: imageRenderingValue,
          typedArrayTypes: typedArrayTypes
      };
  
      /**
       * Detects whether the current browser supports the full screen standard.
       *
       * @returns {Boolean} true if the browser supports the full screen standard, false if not.
       *
       * @see Fullscreen
       * @see {@link http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html|W3C Fullscreen Living Specification}
       */
      FeatureDetection.supportsFullscreen = function() {
          return Fullscreen.supportsFullscreen();
      };
  
      /**
       * Detects whether the current browser supports typed arrays.
       *
       * @returns {Boolean} true if the browser supports typed arrays, false if not.
       *
       * @see {@link http://www.khronos.org/registry/typedarray/specs/latest/|Typed Array Specification}
       */
      FeatureDetection.supportsTypedArrays = function() {
          return typeof ArrayBuffer !== 'undefined';
      };
  
      /**
       * Detects whether the current browser supports Web Workers.
       *
       * @returns {Boolean} true if the browsers supports Web Workers, false if not.
       *
       * @see {@link http://www.w3.org/TR/workers/}
       */
      FeatureDetection.supportsWebWorkers = function() {
          return typeof Worker !== 'undefined';
      };
  
      /**
       * Detects whether the current browser supports Web Assembly.
       *
       * @returns {Boolean} true if the browsers supports Web Assembly, false if not.
       *
       * @see {@link https://developer.mozilla.org/en-US/docs/WebAssembly}
       */
      FeatureDetection.supportsWebAssembly = function() {
          return typeof WebAssembly !== 'undefined' && !FeatureDetection.isEdge();
      };
  
      return FeatureDetection;
  });
  
  define('Core/WebGLConstants',[
          './freezeObject'
      ], function(
          freezeObject) {
      'use strict';
  
      /**
       * Enum containing WebGL Constant values by name.
       * for use without an active WebGL context, or in cases where certain constants are unavailable using the WebGL context
       * (For example, in [Safari 9]{@link https://github.com/AnalyticalGraphicsInc/cesium/issues/2989}).
       *
       * These match the constants from the [WebGL 1.0]{@link https://www.khronos.org/registry/webgl/specs/latest/1.0/}
       * and [WebGL 2.0]{@link https://www.khronos.org/registry/webgl/specs/latest/2.0/}
       * specifications.
       *
       * @exports WebGLConstants
       */
      var WebGLConstants = {
          DEPTH_BUFFER_BIT : 0x00000100,
          STENCIL_BUFFER_BIT : 0x00000400,
          COLOR_BUFFER_BIT : 0x00004000,
          POINTS : 0x0000,
          LINES : 0x0001,
          LINE_LOOP : 0x0002,
          LINE_STRIP : 0x0003,
          TRIANGLES : 0x0004,
          TRIANGLE_STRIP : 0x0005,
          TRIANGLE_FAN : 0x0006,
          ZERO : 0,
          ONE : 1,
          SRC_COLOR : 0x0300,
          ONE_MINUS_SRC_COLOR : 0x0301,
          SRC_ALPHA : 0x0302,
          ONE_MINUS_SRC_ALPHA : 0x0303,
          DST_ALPHA : 0x0304,
          ONE_MINUS_DST_ALPHA : 0x0305,
          DST_COLOR : 0x0306,
          ONE_MINUS_DST_COLOR : 0x0307,
          SRC_ALPHA_SATURATE : 0x0308,
          FUNC_ADD : 0x8006,
          BLEND_EQUATION : 0x8009,
          BLEND_EQUATION_RGB : 0x8009, // same as BLEND_EQUATION
          BLEND_EQUATION_ALPHA : 0x883D,
          FUNC_SUBTRACT : 0x800A,
          FUNC_REVERSE_SUBTRACT : 0x800B,
          BLEND_DST_RGB : 0x80C8,
          BLEND_SRC_RGB : 0x80C9,
          BLEND_DST_ALPHA : 0x80CA,
          BLEND_SRC_ALPHA : 0x80CB,
          CONSTANT_COLOR : 0x8001,
          ONE_MINUS_CONSTANT_COLOR : 0x8002,
          CONSTANT_ALPHA : 0x8003,
          ONE_MINUS_CONSTANT_ALPHA : 0x8004,
          BLEND_COLOR : 0x8005,
          ARRAY_BUFFER : 0x8892,
          ELEMENT_ARRAY_BUFFER : 0x8893,
          ARRAY_BUFFER_BINDING : 0x8894,
          ELEMENT_ARRAY_BUFFER_BINDING : 0x8895,
          STREAM_DRAW : 0x88E0,
          STATIC_DRAW : 0x88E4,
          DYNAMIC_DRAW : 0x88E8,
          BUFFER_SIZE : 0x8764,
          BUFFER_USAGE : 0x8765,
          CURRENT_VERTEX_ATTRIB : 0x8626,
          FRONT : 0x0404,
          BACK : 0x0405,
          FRONT_AND_BACK : 0x0408,
          CULL_FACE : 0x0B44,
          BLEND : 0x0BE2,
          DITHER : 0x0BD0,
          STENCIL_TEST : 0x0B90,
          DEPTH_TEST : 0x0B71,
          SCISSOR_TEST : 0x0C11,
          POLYGON_OFFSET_FILL : 0x8037,
          SAMPLE_ALPHA_TO_COVERAGE : 0x809E,
          SAMPLE_COVERAGE : 0x80A0,
          NO_ERROR : 0,
          INVALID_ENUM : 0x0500,
          INVALID_VALUE : 0x0501,
          INVALID_OPERATION : 0x0502,
          OUT_OF_MEMORY : 0x0505,
          CW : 0x0900,
          CCW : 0x0901,
          LINE_WIDTH : 0x0B21,
          ALIASED_POINT_SIZE_RANGE : 0x846D,
          ALIASED_LINE_WIDTH_RANGE : 0x846E,
          CULL_FACE_MODE : 0x0B45,
          FRONT_FACE : 0x0B46,
          DEPTH_RANGE : 0x0B70,
          DEPTH_WRITEMASK : 0x0B72,
          DEPTH_CLEAR_VALUE : 0x0B73,
          DEPTH_FUNC : 0x0B74,
          STENCIL_CLEAR_VALUE : 0x0B91,
          STENCIL_FUNC : 0x0B92,
          STENCIL_FAIL : 0x0B94,
          STENCIL_PASS_DEPTH_FAIL : 0x0B95,
          STENCIL_PASS_DEPTH_PASS : 0x0B96,
          STENCIL_REF : 0x0B97,
          STENCIL_VALUE_MASK : 0x0B93,
          STENCIL_WRITEMASK : 0x0B98,
          STENCIL_BACK_FUNC : 0x8800,
          STENCIL_BACK_FAIL : 0x8801,
          STENCIL_BACK_PASS_DEPTH_FAIL : 0x8802,
          STENCIL_BACK_PASS_DEPTH_PASS : 0x8803,
          STENCIL_BACK_REF : 0x8CA3,
          STENCIL_BACK_VALUE_MASK : 0x8CA4,
          STENCIL_BACK_WRITEMASK : 0x8CA5,
          VIEWPORT : 0x0BA2,
          SCISSOR_BOX : 0x0C10,
          COLOR_CLEAR_VALUE : 0x0C22,
          COLOR_WRITEMASK : 0x0C23,
          UNPACK_ALIGNMENT : 0x0CF5,
          PACK_ALIGNMENT : 0x0D05,
          MAX_TEXTURE_SIZE : 0x0D33,
          MAX_VIEWPORT_DIMS : 0x0D3A,
          SUBPIXEL_BITS : 0x0D50,
          RED_BITS : 0x0D52,
          GREEN_BITS : 0x0D53,
          BLUE_BITS : 0x0D54,
          ALPHA_BITS : 0x0D55,
          DEPTH_BITS : 0x0D56,
          STENCIL_BITS : 0x0D57,
          POLYGON_OFFSET_UNITS : 0x2A00,
          POLYGON_OFFSET_FACTOR : 0x8038,
          TEXTURE_BINDING_2D : 0x8069,
          SAMPLE_BUFFERS : 0x80A8,
          SAMPLES : 0x80A9,
          SAMPLE_COVERAGE_VALUE : 0x80AA,
          SAMPLE_COVERAGE_INVERT : 0x80AB,
          COMPRESSED_TEXTURE_FORMATS : 0x86A3,
          DONT_CARE : 0x1100,
          FASTEST : 0x1101,
          NICEST : 0x1102,
          GENERATE_MIPMAP_HINT : 0x8192,
          BYTE : 0x1400,
          UNSIGNED_BYTE : 0x1401,
          SHORT : 0x1402,
          UNSIGNED_SHORT : 0x1403,
          INT : 0x1404,
          UNSIGNED_INT : 0x1405,
          FLOAT : 0x1406,
          DEPTH_COMPONENT : 0x1902,
          ALPHA : 0x1906,
          RGB : 0x1907,
          RGBA : 0x1908,
          LUMINANCE : 0x1909,
          LUMINANCE_ALPHA : 0x190A,
          UNSIGNED_SHORT_4_4_4_4 : 0x8033,
          UNSIGNED_SHORT_5_5_5_1 : 0x8034,
          UNSIGNED_SHORT_5_6_5 : 0x8363,
          FRAGMENT_SHADER : 0x8B30,
          VERTEX_SHADER : 0x8B31,
          MAX_VERTEX_ATTRIBS : 0x8869,
          MAX_VERTEX_UNIFORM_VECTORS : 0x8DFB,
          MAX_VARYING_VECTORS : 0x8DFC,
          MAX_COMBINED_TEXTURE_IMAGE_UNITS : 0x8B4D,
          MAX_VERTEX_TEXTURE_IMAGE_UNITS : 0x8B4C,
          MAX_TEXTURE_IMAGE_UNITS : 0x8872,
          MAX_FRAGMENT_UNIFORM_VECTORS : 0x8DFD,
          SHADER_TYPE : 0x8B4F,
          DELETE_STATUS : 0x8B80,
          LINK_STATUS : 0x8B82,
          VALIDATE_STATUS : 0x8B83,
          ATTACHED_SHADERS : 0x8B85,
          ACTIVE_UNIFORMS : 0x8B86,
          ACTIVE_ATTRIBUTES : 0x8B89,
          SHADING_LANGUAGE_VERSION : 0x8B8C,
          CURRENT_PROGRAM : 0x8B8D,
          NEVER : 0x0200,
          LESS : 0x0201,
          EQUAL : 0x0202,
          LEQUAL : 0x0203,
          GREATER : 0x0204,
          NOTEQUAL : 0x0205,
          GEQUAL : 0x0206,
          ALWAYS : 0x0207,
          KEEP : 0x1E00,
          REPLACE : 0x1E01,
          INCR : 0x1E02,
          DECR : 0x1E03,
          INVERT : 0x150A,
          INCR_WRAP : 0x8507,
          DECR_WRAP : 0x8508,
          VENDOR : 0x1F00,
          RENDERER : 0x1F01,
          VERSION : 0x1F02,
          NEAREST : 0x2600,
          LINEAR : 0x2601,
          NEAREST_MIPMAP_NEAREST : 0x2700,
          LINEAR_MIPMAP_NEAREST : 0x2701,
          NEAREST_MIPMAP_LINEAR : 0x2702,
          LINEAR_MIPMAP_LINEAR : 0x2703,
          TEXTURE_MAG_FILTER : 0x2800,
          TEXTURE_MIN_FILTER : 0x2801,
          TEXTURE_WRAP_S : 0x2802,
          TEXTURE_WRAP_T : 0x2803,
          TEXTURE_2D : 0x0DE1,
          TEXTURE : 0x1702,
          TEXTURE_CUBE_MAP : 0x8513,
          TEXTURE_BINDING_CUBE_MAP : 0x8514,
          TEXTURE_CUBE_MAP_POSITIVE_X : 0x8515,
          TEXTURE_CUBE_MAP_NEGATIVE_X : 0x8516,
          TEXTURE_CUBE_MAP_POSITIVE_Y : 0x8517,
          TEXTURE_CUBE_MAP_NEGATIVE_Y : 0x8518,
          TEXTURE_CUBE_MAP_POSITIVE_Z : 0x8519,
          TEXTURE_CUBE_MAP_NEGATIVE_Z : 0x851A,
          MAX_CUBE_MAP_TEXTURE_SIZE : 0x851C,
          TEXTURE0 : 0x84C0,
          TEXTURE1 : 0x84C1,
          TEXTURE2 : 0x84C2,
          TEXTURE3 : 0x84C3,
          TEXTURE4 : 0x84C4,
          TEXTURE5 : 0x84C5,
          TEXTURE6 : 0x84C6,
          TEXTURE7 : 0x84C7,
          TEXTURE8 : 0x84C8,
          TEXTURE9 : 0x84C9,
          TEXTURE10 : 0x84CA,
          TEXTURE11 : 0x84CB,
          TEXTURE12 : 0x84CC,
          TEXTURE13 : 0x84CD,
          TEXTURE14 : 0x84CE,
          TEXTURE15 : 0x84CF,
          TEXTURE16 : 0x84D0,
          TEXTURE17 : 0x84D1,
          TEXTURE18 : 0x84D2,
          TEXTURE19 : 0x84D3,
          TEXTURE20 : 0x84D4,
          TEXTURE21 : 0x84D5,
          TEXTURE22 : 0x84D6,
          TEXTURE23 : 0x84D7,
          TEXTURE24 : 0x84D8,
          TEXTURE25 : 0x84D9,
          TEXTURE26 : 0x84DA,
          TEXTURE27 : 0x84DB,
          TEXTURE28 : 0x84DC,
          TEXTURE29 : 0x84DD,
          TEXTURE30 : 0x84DE,
          TEXTURE31 : 0x84DF,
          ACTIVE_TEXTURE : 0x84E0,
          REPEAT : 0x2901,
          CLAMP_TO_EDGE : 0x812F,
          MIRRORED_REPEAT : 0x8370,
          FLOAT_VEC2 : 0x8B50,
          FLOAT_VEC3 : 0x8B51,
          FLOAT_VEC4 : 0x8B52,
          INT_VEC2 : 0x8B53,
          INT_VEC3 : 0x8B54,
          INT_VEC4 : 0x8B55,
          BOOL : 0x8B56,
          BOOL_VEC2 : 0x8B57,
          BOOL_VEC3 : 0x8B58,
          BOOL_VEC4 : 0x8B59,
          FLOAT_MAT2 : 0x8B5A,
          FLOAT_MAT3 : 0x8B5B,
          FLOAT_MAT4 : 0x8B5C,
          SAMPLER_2D : 0x8B5E,
          SAMPLER_CUBE : 0x8B60,
          VERTEX_ATTRIB_ARRAY_ENABLED : 0x8622,
          VERTEX_ATTRIB_ARRAY_SIZE : 0x8623,
          VERTEX_ATTRIB_ARRAY_STRIDE : 0x8624,
          VERTEX_ATTRIB_ARRAY_TYPE : 0x8625,
          VERTEX_ATTRIB_ARRAY_NORMALIZED : 0x886A,
          VERTEX_ATTRIB_ARRAY_POINTER : 0x8645,
          VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : 0x889F,
          IMPLEMENTATION_COLOR_READ_TYPE : 0x8B9A,
          IMPLEMENTATION_COLOR_READ_FORMAT : 0x8B9B,
          COMPILE_STATUS : 0x8B81,
          LOW_FLOAT : 0x8DF0,
          MEDIUM_FLOAT : 0x8DF1,
          HIGH_FLOAT : 0x8DF2,
          LOW_INT : 0x8DF3,
          MEDIUM_INT : 0x8DF4,
          HIGH_INT : 0x8DF5,
          FRAMEBUFFER : 0x8D40,
          RENDERBUFFER : 0x8D41,
          RGBA4 : 0x8056,
          RGB5_A1 : 0x8057,
          RGB565 : 0x8D62,
          DEPTH_COMPONENT16 : 0x81A5,
          STENCIL_INDEX : 0x1901,
          STENCIL_INDEX8 : 0x8D48,
          DEPTH_STENCIL : 0x84F9,
          RENDERBUFFER_WIDTH : 0x8D42,
          RENDERBUFFER_HEIGHT : 0x8D43,
          RENDERBUFFER_INTERNAL_FORMAT : 0x8D44,
          RENDERBUFFER_RED_SIZE : 0x8D50,
          RENDERBUFFER_GREEN_SIZE : 0x8D51,
          RENDERBUFFER_BLUE_SIZE : 0x8D52,
          RENDERBUFFER_ALPHA_SIZE : 0x8D53,
          RENDERBUFFER_DEPTH_SIZE : 0x8D54,
          RENDERBUFFER_STENCIL_SIZE : 0x8D55,
          FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE : 0x8CD0,
          FRAMEBUFFER_ATTACHMENT_OBJECT_NAME : 0x8CD1,
          FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL : 0x8CD2,
          FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE : 0x8CD3,
          COLOR_ATTACHMENT0 : 0x8CE0,
          DEPTH_ATTACHMENT : 0x8D00,
          STENCIL_ATTACHMENT : 0x8D20,
          DEPTH_STENCIL_ATTACHMENT : 0x821A,
          NONE : 0,
          FRAMEBUFFER_COMPLETE : 0x8CD5,
          FRAMEBUFFER_INCOMPLETE_ATTACHMENT : 0x8CD6,
          FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : 0x8CD7,
          FRAMEBUFFER_INCOMPLETE_DIMENSIONS : 0x8CD9,
          FRAMEBUFFER_UNSUPPORTED : 0x8CDD,
          FRAMEBUFFER_BINDING : 0x8CA6,
          RENDERBUFFER_BINDING : 0x8CA7,
          MAX_RENDERBUFFER_SIZE : 0x84E8,
          INVALID_FRAMEBUFFER_OPERATION : 0x0506,
          UNPACK_FLIP_Y_WEBGL : 0x9240,
          UNPACK_PREMULTIPLY_ALPHA_WEBGL : 0x9241,
          CONTEXT_LOST_WEBGL : 0x9242,
          UNPACK_COLORSPACE_CONVERSION_WEBGL : 0x9243,
          BROWSER_DEFAULT_WEBGL : 0x9244,
  
          // WEBGL_compressed_texture_s3tc
          COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0,
          COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1,
          COMPRESSED_RGBA_S3TC_DXT3_EXT : 0x83F2,
          COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3,
  
          // WEBGL_compressed_texture_pvrtc
          COMPRESSED_RGB_PVRTC_4BPPV1_IMG : 0x8C00,
          COMPRESSED_RGB_PVRTC_2BPPV1_IMG : 0x8C01,
          COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : 0x8C02,
          COMPRESSED_RGBA_PVRTC_2BPPV1_IMG : 0x8C03,
  
          // WEBGL_compressed_texture_etc1
          COMPRESSED_RGB_ETC1_WEBGL : 0x8D64,
  
          // EXT_color_buffer_half_float
          HALF_FLOAT_OES : 0x8D61,
  
          // Desktop OpenGL
          DOUBLE : 0x140A,
  
          // WebGL 2
          READ_BUFFER : 0x0C02,
          UNPACK_ROW_LENGTH : 0x0CF2,
          UNPACK_SKIP_ROWS : 0x0CF3,
          UNPACK_SKIP_PIXELS : 0x0CF4,
          PACK_ROW_LENGTH : 0x0D02,
          PACK_SKIP_ROWS : 0x0D03,
          PACK_SKIP_PIXELS : 0x0D04,
          COLOR : 0x1800,
          DEPTH : 0x1801,
          STENCIL : 0x1802,
          RED : 0x1903,
          RGB8 : 0x8051,
          RGBA8 : 0x8058,
          RGB10_A2 : 0x8059,
          TEXTURE_BINDING_3D : 0x806A,
          UNPACK_SKIP_IMAGES : 0x806D,
          UNPACK_IMAGE_HEIGHT : 0x806E,
          TEXTURE_3D : 0x806F,
          TEXTURE_WRAP_R : 0x8072,
          MAX_3D_TEXTURE_SIZE : 0x8073,
          UNSIGNED_INT_2_10_10_10_REV : 0x8368,
          MAX_ELEMENTS_VERTICES : 0x80E8,
          MAX_ELEMENTS_INDICES : 0x80E9,
          TEXTURE_MIN_LOD : 0x813A,
          TEXTURE_MAX_LOD : 0x813B,
          TEXTURE_BASE_LEVEL : 0x813C,
          TEXTURE_MAX_LEVEL : 0x813D,
          MIN : 0x8007,
          MAX : 0x8008,
          DEPTH_COMPONENT24 : 0x81A6,
          MAX_TEXTURE_LOD_BIAS : 0x84FD,
          TEXTURE_COMPARE_MODE : 0x884C,
          TEXTURE_COMPARE_FUNC : 0x884D,
          CURRENT_QUERY : 0x8865,
          QUERY_RESULT : 0x8866,
          QUERY_RESULT_AVAILABLE : 0x8867,
          STREAM_READ : 0x88E1,
          STREAM_COPY : 0x88E2,
          STATIC_READ : 0x88E5,
          STATIC_COPY : 0x88E6,
          DYNAMIC_READ : 0x88E9,
          DYNAMIC_COPY : 0x88EA,
          MAX_DRAW_BUFFERS : 0x8824,
          DRAW_BUFFER0 : 0x8825,
          DRAW_BUFFER1 : 0x8826,
          DRAW_BUFFER2 : 0x8827,
          DRAW_BUFFER3 : 0x8828,
          DRAW_BUFFER4 : 0x8829,
          DRAW_BUFFER5 : 0x882A,
          DRAW_BUFFER6 : 0x882B,
          DRAW_BUFFER7 : 0x882C,
          DRAW_BUFFER8 : 0x882D,
          DRAW_BUFFER9 : 0x882E,
          DRAW_BUFFER10 : 0x882F,
          DRAW_BUFFER11 : 0x8830,
          DRAW_BUFFER12 : 0x8831,
          DRAW_BUFFER13 : 0x8832,
          DRAW_BUFFER14 : 0x8833,
          DRAW_BUFFER15 : 0x8834,
          MAX_FRAGMENT_UNIFORM_COMPONENTS : 0x8B49,
          MAX_VERTEX_UNIFORM_COMPONENTS : 0x8B4A,
          SAMPLER_3D : 0x8B5F,
          SAMPLER_2D_SHADOW : 0x8B62,
          FRAGMENT_SHADER_DERIVATIVE_HINT : 0x8B8B,
          PIXEL_PACK_BUFFER : 0x88EB,
          PIXEL_UNPACK_BUFFER : 0x88EC,
          PIXEL_PACK_BUFFER_BINDING : 0x88ED,
          PIXEL_UNPACK_BUFFER_BINDING : 0x88EF,
          FLOAT_MAT2x3 : 0x8B65,
          FLOAT_MAT2x4 : 0x8B66,
          FLOAT_MAT3x2 : 0x8B67,
          FLOAT_MAT3x4 : 0x8B68,
          FLOAT_MAT4x2 : 0x8B69,
          FLOAT_MAT4x3 : 0x8B6A,
          SRGB : 0x8C40,
          SRGB8 : 0x8C41,
          SRGB8_ALPHA8 : 0x8C43,
          COMPARE_REF_TO_TEXTURE : 0x884E,
          RGBA32F : 0x8814,
          RGB32F : 0x8815,
          RGBA16F : 0x881A,
          RGB16F : 0x881B,
          VERTEX_ATTRIB_ARRAY_INTEGER : 0x88FD,
          MAX_ARRAY_TEXTURE_LAYERS : 0x88FF,
          MIN_PROGRAM_TEXEL_OFFSET : 0x8904,
          MAX_PROGRAM_TEXEL_OFFSET : 0x8905,
          MAX_VARYING_COMPONENTS : 0x8B4B,
          TEXTURE_2D_ARRAY : 0x8C1A,
          TEXTURE_BINDING_2D_ARRAY : 0x8C1D,
          R11F_G11F_B10F : 0x8C3A,
          UNSIGNED_INT_10F_11F_11F_REV : 0x8C3B,
          RGB9_E5 : 0x8C3D,
          UNSIGNED_INT_5_9_9_9_REV : 0x8C3E,
          TRANSFORM_FEEDBACK_BUFFER_MODE : 0x8C7F,
          MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS : 0x8C80,
          TRANSFORM_FEEDBACK_VARYINGS : 0x8C83,
          TRANSFORM_FEEDBACK_BUFFER_START : 0x8C84,
          TRANSFORM_FEEDBACK_BUFFER_SIZE : 0x8C85,
          TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN : 0x8C88,
          RASTERIZER_DISCARD : 0x8C89,
          MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS : 0x8C8A,
          MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS : 0x8C8B,
          INTERLEAVED_ATTRIBS : 0x8C8C,
          SEPARATE_ATTRIBS : 0x8C8D,
          TRANSFORM_FEEDBACK_BUFFER : 0x8C8E,
          TRANSFORM_FEEDBACK_BUFFER_BINDING : 0x8C8F,
          RGBA32UI : 0x8D70,
          RGB32UI : 0x8D71,
          RGBA16UI : 0x8D76,
          RGB16UI : 0x8D77,
          RGBA8UI : 0x8D7C,
          RGB8UI : 0x8D7D,
          RGBA32I : 0x8D82,
          RGB32I : 0x8D83,
          RGBA16I : 0x8D88,
          RGB16I : 0x8D89,
          RGBA8I : 0x8D8E,
          RGB8I : 0x8D8F,
          RED_INTEGER : 0x8D94,
          RGB_INTEGER : 0x8D98,
          RGBA_INTEGER : 0x8D99,
          SAMPLER_2D_ARRAY : 0x8DC1,
          SAMPLER_2D_ARRAY_SHADOW : 0x8DC4,
          SAMPLER_CUBE_SHADOW : 0x8DC5,
          UNSIGNED_INT_VEC2 : 0x8DC6,
          UNSIGNED_INT_VEC3 : 0x8DC7,
          UNSIGNED_INT_VEC4 : 0x8DC8,
          INT_SAMPLER_2D : 0x8DCA,
          INT_SAMPLER_3D : 0x8DCB,
          INT_SAMPLER_CUBE : 0x8DCC,
          INT_SAMPLER_2D_ARRAY : 0x8DCF,
          UNSIGNED_INT_SAMPLER_2D : 0x8DD2,
          UNSIGNED_INT_SAMPLER_3D : 0x8DD3,
          UNSIGNED_INT_SAMPLER_CUBE : 0x8DD4,
          UNSIGNED_INT_SAMPLER_2D_ARRAY : 0x8DD7,
          DEPTH_COMPONENT32F : 0x8CAC,
          DEPTH32F_STENCIL8 : 0x8CAD,
          FLOAT_32_UNSIGNED_INT_24_8_REV : 0x8DAD,
          FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING : 0x8210,
          FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE : 0x8211,
          FRAMEBUFFER_ATTACHMENT_RED_SIZE : 0x8212,
          FRAMEBUFFER_ATTACHMENT_GREEN_SIZE : 0x8213,
          FRAMEBUFFER_ATTACHMENT_BLUE_SIZE : 0x8214,
          FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE : 0x8215,
          FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE : 0x8216,
          FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE : 0x8217,
          FRAMEBUFFER_DEFAULT : 0x8218,
          UNSIGNED_INT_24_8 : 0x84FA,
          DEPTH24_STENCIL8 : 0x88F0,
          UNSIGNED_NORMALIZED : 0x8C17,
          DRAW_FRAMEBUFFER_BINDING : 0x8CA6, // Same as FRAMEBUFFER_BINDING
          READ_FRAMEBUFFER : 0x8CA8,
          DRAW_FRAMEBUFFER : 0x8CA9,
          READ_FRAMEBUFFER_BINDING : 0x8CAA,
          RENDERBUFFER_SAMPLES : 0x8CAB,
          FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER : 0x8CD4,
          MAX_COLOR_ATTACHMENTS : 0x8CDF,
          COLOR_ATTACHMENT1 : 0x8CE1,
          COLOR_ATTACHMENT2 : 0x8CE2,
          COLOR_ATTACHMENT3 : 0x8CE3,
          COLOR_ATTACHMENT4 : 0x8CE4,
          COLOR_ATTACHMENT5 : 0x8CE5,
          COLOR_ATTACHMENT6 : 0x8CE6,
          COLOR_ATTACHMENT7 : 0x8CE7,
          COLOR_ATTACHMENT8 : 0x8CE8,
          COLOR_ATTACHMENT9 : 0x8CE9,
          COLOR_ATTACHMENT10 : 0x8CEA,
          COLOR_ATTACHMENT11 : 0x8CEB,
          COLOR_ATTACHMENT12 : 0x8CEC,
          COLOR_ATTACHMENT13 : 0x8CED,
          COLOR_ATTACHMENT14 : 0x8CEE,
          COLOR_ATTACHMENT15 : 0x8CEF,
          FRAMEBUFFER_INCOMPLETE_MULTISAMPLE : 0x8D56,
          MAX_SAMPLES : 0x8D57,
          HALF_FLOAT : 0x140B,
          RG : 0x8227,
          RG_INTEGER : 0x8228,
          R8 : 0x8229,
          RG8 : 0x822B,
          R16F : 0x822D,
          R32F : 0x822E,
          RG16F : 0x822F,
          RG32F : 0x8230,
          R8I : 0x8231,
          R8UI : 0x8232,
          R16I : 0x8233,
          R16UI : 0x8234,
          R32I : 0x8235,
          R32UI : 0x8236,
          RG8I : 0x8237,
          RG8UI : 0x8238,
          RG16I : 0x8239,
          RG16UI : 0x823A,
          RG32I : 0x823B,
          RG32UI : 0x823C,
          VERTEX_ARRAY_BINDING : 0x85B5,
          R8_SNORM : 0x8F94,
          RG8_SNORM : 0x8F95,
          RGB8_SNORM : 0x8F96,
          RGBA8_SNORM : 0x8F97,
          SIGNED_NORMALIZED : 0x8F9C,
          COPY_READ_BUFFER : 0x8F36,
          COPY_WRITE_BUFFER : 0x8F37,
          COPY_READ_BUFFER_BINDING : 0x8F36, // Same as COPY_READ_BUFFER
          COPY_WRITE_BUFFER_BINDING : 0x8F37, // Same as COPY_WRITE_BUFFER
          UNIFORM_BUFFER : 0x8A11,
          UNIFORM_BUFFER_BINDING : 0x8A28,
          UNIFORM_BUFFER_START : 0x8A29,
          UNIFORM_BUFFER_SIZE : 0x8A2A,
          MAX_VERTEX_UNIFORM_BLOCKS : 0x8A2B,
          MAX_FRAGMENT_UNIFORM_BLOCKS : 0x8A2D,
          MAX_COMBINED_UNIFORM_BLOCKS : 0x8A2E,
          MAX_UNIFORM_BUFFER_BINDINGS : 0x8A2F,
          MAX_UNIFORM_BLOCK_SIZE : 0x8A30,
          MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS : 0x8A31,
          MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS : 0x8A33,
          UNIFORM_BUFFER_OFFSET_ALIGNMENT : 0x8A34,
          ACTIVE_UNIFORM_BLOCKS : 0x8A36,
          UNIFORM_TYPE : 0x8A37,
          UNIFORM_SIZE : 0x8A38,
          UNIFORM_BLOCK_INDEX : 0x8A3A,
          UNIFORM_OFFSET : 0x8A3B,
          UNIFORM_ARRAY_STRIDE : 0x8A3C,
          UNIFORM_MATRIX_STRIDE : 0x8A3D,
          UNIFORM_IS_ROW_MAJOR : 0x8A3E,
          UNIFORM_BLOCK_BINDING : 0x8A3F,
          UNIFORM_BLOCK_DATA_SIZE : 0x8A40,
          UNIFORM_BLOCK_ACTIVE_UNIFORMS : 0x8A42,
          UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES : 0x8A43,
          UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER : 0x8A44,
          UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER : 0x8A46,
          INVALID_INDEX : 0xFFFFFFFF,
          MAX_VERTEX_OUTPUT_COMPONENTS : 0x9122,
          MAX_FRAGMENT_INPUT_COMPONENTS : 0x9125,
          MAX_SERVER_WAIT_TIMEOUT : 0x9111,
          OBJECT_TYPE : 0x9112,
          SYNC_CONDITION : 0x9113,
          SYNC_STATUS : 0x9114,
          SYNC_FLAGS : 0x9115,
          SYNC_FENCE : 0x9116,
          SYNC_GPU_COMMANDS_COMPLETE : 0x9117,
          UNSIGNALED : 0x9118,
          SIGNALED : 0x9119,
          ALREADY_SIGNALED : 0x911A,
          TIMEOUT_EXPIRED : 0x911B,
          CONDITION_SATISFIED : 0x911C,
          WAIT_FAILED : 0x911D,
          SYNC_FLUSH_COMMANDS_BIT : 0x00000001,
          VERTEX_ATTRIB_ARRAY_DIVISOR : 0x88FE,
          ANY_SAMPLES_PASSED : 0x8C2F,
          ANY_SAMPLES_PASSED_CONSERVATIVE : 0x8D6A,
          SAMPLER_BINDING : 0x8919,
          RGB10_A2UI : 0x906F,
          INT_2_10_10_10_REV : 0x8D9F,
          TRANSFORM_FEEDBACK : 0x8E22,
          TRANSFORM_FEEDBACK_PAUSED : 0x8E23,
          TRANSFORM_FEEDBACK_ACTIVE : 0x8E24,
          TRANSFORM_FEEDBACK_BINDING : 0x8E25,
          COMPRESSED_R11_EAC : 0x9270,
          COMPRESSED_SIGNED_R11_EAC : 0x9271,
          COMPRESSED_RG11_EAC : 0x9272,
          COMPRESSED_SIGNED_RG11_EAC : 0x9273,
          COMPRESSED_RGB8_ETC2 : 0x9274,
          COMPRESSED_SRGB8_ETC2 : 0x9275,
          COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9276,
          COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9277,
          COMPRESSED_RGBA8_ETC2_EAC : 0x9278,
          COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : 0x9279,
          TEXTURE_IMMUTABLE_FORMAT : 0x912F,
          MAX_ELEMENT_INDEX : 0x8D6B,
          TEXTURE_IMMUTABLE_LEVELS : 0x82DF,
  
          // Extensions
          MAX_TEXTURE_MAX_ANISOTROPY_EXT : 0x84FF
      };
  
      return freezeObject(WebGLConstants);
  });
  
  define('Core/ComponentDatatype',[
          './defaultValue',
          './defined',
          './DeveloperError',
          './FeatureDetection',
          './freezeObject',
          './WebGLConstants'
      ], function(
          defaultValue,
          defined,
          DeveloperError,
          FeatureDetection,
          freezeObject,
          WebGLConstants) {
      'use strict';
  
      // Bail out if the browser doesn't support typed arrays, to prevent the setup function
      // from failing, since we won't be able to create a WebGL context anyway.
      if (!FeatureDetection.supportsTypedArrays()) {
          return {};
      }
  
      /**
       * WebGL component datatypes.  Components are intrinsics,
       * which form attributes, which form vertices.
       *
       * @exports ComponentDatatype
       */
      var ComponentDatatype = {
          /**
           * 8-bit signed byte corresponding to <code>gl.BYTE</code> and the type
           * of an element in <code>Int8Array</code>.
           *
           * @type {Number}
           * @constant
           */
          BYTE : WebGLConstants.BYTE,
  
          /**
           * 8-bit unsigned byte corresponding to <code>UNSIGNED_BYTE</code> and the type
           * of an element in <code>Uint8Array</code>.
           *
           * @type {Number}
           * @constant
           */
          UNSIGNED_BYTE : WebGLConstants.UNSIGNED_BYTE,
  
          /**
           * 16-bit signed short corresponding to <code>SHORT</code> and the type
           * of an element in <code>Int16Array</code>.
           *
           * @type {Number}
           * @constant
           */
          SHORT : WebGLConstants.SHORT,
  
          /**
           * 16-bit unsigned short corresponding to <code>UNSIGNED_SHORT</code> and the type
           * of an element in <code>Uint16Array</code>.
           *
           * @type {Number}
           * @constant
           */
          UNSIGNED_SHORT : WebGLConstants.UNSIGNED_SHORT,
  
          /**
           * 32-bit signed int corresponding to <code>INT</code> and the type
           * of an element in <code>Int32Array</code>.
           *
           * @memberOf ComponentDatatype
           *
           * @type {Number}
           * @constant
           */
          INT : WebGLConstants.INT,
  
          /**
           * 32-bit unsigned int corresponding to <code>UNSIGNED_INT</code> and the type
           * of an element in <code>Uint32Array</code>.
           *
           * @memberOf ComponentDatatype
           *
           * @type {Number}
           * @constant
           */
          UNSIGNED_INT : WebGLConstants.UNSIGNED_INT,
  
          /**
           * 32-bit floating-point corresponding to <code>FLOAT</code> and the type
           * of an element in <code>Float32Array</code>.
           *
           * @type {Number}
           * @constant
           */
          FLOAT : WebGLConstants.FLOAT,
  
          /**
           * 64-bit floating-point corresponding to <code>gl.DOUBLE</code> (in Desktop OpenGL;
           * this is not supported in WebGL, and is emulated in Cesium via {@link GeometryPipeline.encodeAttribute})
           * and the type of an element in <code>Float64Array</code>.
           *
           * @memberOf ComponentDatatype
           *
           * @type {Number}
           * @constant
           * @default 0x140A
           */
          DOUBLE : WebGLConstants.DOUBLE
      };
  
      /**
       * Returns the size, in bytes, of the corresponding datatype.
       *
       * @param {ComponentDatatype} componentDatatype The component datatype to get the size of.
       * @returns {Number} The size in bytes.
       *
       * @exception {DeveloperError} componentDatatype is not a valid value.
       *
       * @example
       * // Returns Int8Array.BYTES_PER_ELEMENT
       * var size = Cesium.ComponentDatatype.getSizeInBytes(Cesium.ComponentDatatype.BYTE);
       */
      ComponentDatatype.getSizeInBytes = function(componentDatatype){
                  if (!defined(componentDatatype)) {
              throw new DeveloperError('value is required.');
          }
          
          switch (componentDatatype) {
          case ComponentDatatype.BYTE:
              return Int8Array.BYTES_PER_ELEMENT;
          case ComponentDatatype.UNSIGNED_BYTE:
              return Uint8Array.BYTES_PER_ELEMENT;
          case ComponentDatatype.SHORT:
              return Int16Array.BYTES_PER_ELEMENT;
          case ComponentDatatype.UNSIGNED_SHORT:
              return Uint16Array.BYTES_PER_ELEMENT;
          case ComponentDatatype.INT:
              return Int32Array.BYTES_PER_ELEMENT;
          case ComponentDatatype.UNSIGNED_INT:
              return Uint32Array.BYTES_PER_ELEMENT;
          case ComponentDatatype.FLOAT:
              return Float32Array.BYTES_PER_ELEMENT;
          case ComponentDatatype.DOUBLE:
              return Float64Array.BYTES_PER_ELEMENT;
                  default:
              throw new DeveloperError('componentDatatype is not a valid value.');
                  }
      };
  
      /**
       * Gets the {@link ComponentDatatype} for the provided TypedArray instance.
       *
       * @param {TypedArray} array The typed array.
       * @returns {ComponentDatatype} The ComponentDatatype for the provided array, or undefined if the array is not a TypedArray.
       */
      ComponentDatatype.fromTypedArray = function(array) {
          if (array instanceof Int8Array) {
              return ComponentDatatype.BYTE;
          }
          if (array instanceof Uint8Array) {
              return ComponentDatatype.UNSIGNED_BYTE;
          }
          if (array instanceof Int16Array) {
              return ComponentDatatype.SHORT;
          }
          if (array instanceof Uint16Array) {
              return ComponentDatatype.UNSIGNED_SHORT;
          }
          if (array instanceof Int32Array) {
              return ComponentDatatype.INT;
          }
          if (array instanceof Uint32Array) {
              return ComponentDatatype.UNSIGNED_INT;
          }
          if (array instanceof Float32Array) {
              return ComponentDatatype.FLOAT;
          }
          if (array instanceof Float64Array) {
              return ComponentDatatype.DOUBLE;
          }
      };
  
      /**
       * Validates that the provided component datatype is a valid {@link ComponentDatatype}
       *
       * @param {ComponentDatatype} componentDatatype The component datatype to validate.
       * @returns {Boolean} <code>true</code> if the provided component datatype is a valid value; otherwise, <code>false</code>.
       *
       * @example
       * if (!Cesium.ComponentDatatype.validate(componentDatatype)) {
       *   throw new Cesium.DeveloperError('componentDatatype must be a valid value.');
       * }
       */
      ComponentDatatype.validate = function(componentDatatype) {
          return defined(componentDatatype) &&
                 (componentDatatype === ComponentDatatype.BYTE ||
                  componentDatatype === ComponentDatatype.UNSIGNED_BYTE ||
                  componentDatatype === ComponentDatatype.SHORT ||
                  componentDatatype === ComponentDatatype.UNSIGNED_SHORT ||
                  componentDatatype === ComponentDatatype.INT ||
                  componentDatatype === ComponentDatatype.UNSIGNED_INT ||
                  componentDatatype === ComponentDatatype.FLOAT ||
                  componentDatatype === ComponentDatatype.DOUBLE);
      };
  
      /**
       * Creates a typed array corresponding to component data type.
       *
       * @param {ComponentDatatype} componentDatatype The component data type.
       * @param {Number|Array} valuesOrLength The length of the array to create or an array.
       * @returns {Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} A typed array.
       *
       * @exception {DeveloperError} componentDatatype is not a valid value.
       *
       * @example
       * // creates a Float32Array with length of 100
       * var typedArray = Cesium.ComponentDatatype.createTypedArray(Cesium.ComponentDatatype.FLOAT, 100);
       */
      ComponentDatatype.createTypedArray = function(componentDatatype, valuesOrLength) {
                  if (!defined(componentDatatype)) {
              throw new DeveloperError('componentDatatype is required.');
          }
          if (!defined(valuesOrLength)) {
              throw new DeveloperError('valuesOrLength is required.');
          }
          
          switch (componentDatatype) {
          case ComponentDatatype.BYTE:
              return new Int8Array(valuesOrLength);
          case ComponentDatatype.UNSIGNED_BYTE:
              return new Uint8Array(valuesOrLength);
          case ComponentDatatype.SHORT:
              return new Int16Array(valuesOrLength);
          case ComponentDatatype.UNSIGNED_SHORT:
              return new Uint16Array(valuesOrLength);
          case ComponentDatatype.INT:
              return new Int32Array(valuesOrLength);
          case ComponentDatatype.UNSIGNED_INT:
              return new Uint32Array(valuesOrLength);
          case ComponentDatatype.FLOAT:
              return new Float32Array(valuesOrLength);
          case ComponentDatatype.DOUBLE:
              return new Float64Array(valuesOrLength);
                  default:
              throw new DeveloperError('componentDatatype is not a valid value.');
                  }
      };
  
      /**
       * Creates a typed view of an array of bytes.
       *
       * @param {ComponentDatatype} componentDatatype The type of the view to create.
       * @param {ArrayBuffer} buffer The buffer storage to use for the view.
       * @param {Number} [byteOffset] The offset, in bytes, to the first element in the view.
       * @param {Number} [length] The number of elements in the view.
       * @returns {Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} A typed array view of the buffer.
       *
       * @exception {DeveloperError} componentDatatype is not a valid value.
       */
      ComponentDatatype.createArrayBufferView = function(componentDatatype, buffer, byteOffset, length) {
                  if (!defined(componentDatatype)) {
              throw new DeveloperError('componentDatatype is required.');
          }
          if (!defined(buffer)) {
              throw new DeveloperError('buffer is required.');
          }
          
          byteOffset = defaultValue(byteOffset, 0);
          length = defaultValue(length, (buffer.byteLength - byteOffset) / ComponentDatatype.getSizeInBytes(componentDatatype));
  
          switch (componentDatatype) {
          case ComponentDatatype.BYTE:
              return new Int8Array(buffer, byteOffset, length);
          case ComponentDatatype.UNSIGNED_BYTE:
              return new Uint8Array(buffer, byteOffset, length);
          case ComponentDatatype.SHORT:
              return new Int16Array(buffer, byteOffset, length);
          case ComponentDatatype.UNSIGNED_SHORT:
              return new Uint16Array(buffer, byteOffset, length);
          case ComponentDatatype.INT:
              return new Int32Array(buffer, byteOffset, length);
          case ComponentDatatype.UNSIGNED_INT:
              return new Uint32Array(buffer, byteOffset, length);
          case ComponentDatatype.FLOAT:
              return new Float32Array(buffer, byteOffset, length);
          case ComponentDatatype.DOUBLE:
              return new Float64Array(buffer, byteOffset, length);
                  default:
              throw new DeveloperError('componentDatatype is not a valid value.');
                  }
      };
  
      /**
       * Get the ComponentDatatype from its name.
       *
       * @param {String} name The name of the ComponentDatatype.
       * @returns {ComponentDatatype} The ComponentDatatype.
       *
       * @exception {DeveloperError} name is not a valid value.
       */
      ComponentDatatype.fromName = function(name) {
          switch (name) {
              case 'BYTE':
                  return ComponentDatatype.BYTE;
              case 'UNSIGNED_BYTE':
                  return ComponentDatatype.UNSIGNED_BYTE;
              case 'SHORT':
                  return ComponentDatatype.SHORT;
              case 'UNSIGNED_SHORT':
                  return ComponentDatatype.UNSIGNED_SHORT;
              case 'INT':
                  return ComponentDatatype.INT;
              case 'UNSIGNED_INT':
                  return ComponentDatatype.UNSIGNED_INT;
              case 'FLOAT':
                  return ComponentDatatype.FLOAT;
              case 'DOUBLE':
                  return ComponentDatatype.DOUBLE;
                          default:
                  throw new DeveloperError('name is not a valid value.');
                      }
      };
  
      return freezeObject(ComponentDatatype);
  });
  
  /*
    I've wrapped Makoto Matsumoto and Takuji Nishimura's code in a namespace
    so it's better encapsulated. Now you can have multiple random number generators
    and they won't stomp all over eachother's state.
  
    If you want to use this as a substitute for Math.random(), use the random()
    method like so:
  
    var m = new MersenneTwister();
    var randomNumber = m.random();
  
    You can also call the other genrand_{foo}() methods on the instance.
  
    If you want to use a specific seed in order to get a repeatable random
    sequence, pass an integer into the constructor:
  
    var m = new MersenneTwister(123);
  
    and that will always produce the same random sequence.
  
    Sean McCullough (banksean@gmail.com)
  */
  
  /*
     A C-program for MT19937, with initialization improved 2002/1/26.
     Coded by Takuji Nishimura and Makoto Matsumoto.
  
     Before using, initialize the state by using init_genrand(seed)
     or init_by_array(init_key, key_length).
  */
  /**
  @license
  mersenne-twister.js - https://gist.github.com/banksean/300494
  
     Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
     All rights reserved.
  
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:
  
       1. Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
  
       2. Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
  
       3. The names of its contributors may not be used to endorse or promote
          products derived from this software without specific prior written
          permission.
  
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  /*
     Any feedback is very welcome.
     http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
     email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
  */
  define('ThirdParty/mersenne-twister',[],function() {
  var MersenneTwister = function(seed) {
    if (seed == undefined) {
      seed = new Date().getTime();
    }
    /* Period parameters */
    this.N = 624;
    this.M = 397;
    this.MATRIX_A = 0x9908b0df;   /* constant vector a */
    this.UPPER_MASK = 0x80000000; /* most significant w-r bits */
    this.LOWER_MASK = 0x7fffffff; /* least significant r bits */
  
    this.mt = new Array(this.N); /* the array for the state vector */
    this.mti=this.N+1; /* mti==N+1 means mt[N] is not initialized */
  
    this.init_genrand(seed);
  }
  
  /* initializes mt[N] with a seed */
  MersenneTwister.prototype.init_genrand = function(s) {
    this.mt[0] = s >>> 0;
    for (this.mti=1; this.mti<this.N; this.mti++) {
        var s = this.mt[this.mti-1] ^ (this.mt[this.mti-1] >>> 30);
     this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253)
    + this.mti;
        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
        /* In the previous versions, MSBs of the seed affect   */
        /* only MSBs of the array mt[].                        */
        /* 2002/01/09 modified by Makoto Matsumoto             */
        this.mt[this.mti] >>>= 0;
        /* for >32 bit machines */
    }
  }
  
  /* initialize by an array with array-length */
  /* init_key is the array for initializing keys */
  /* key_length is its length */
  /* slight change for C++, 2004/2/26 */
  //MersenneTwister.prototype.init_by_array = function(init_key, key_length) {
  //  var i, j, k;
  //  this.init_genrand(19650218);
  //  i=1; j=0;
  //  k = (this.N>key_length ? this.N : key_length);
  //  for (; k; k--) {
  //    var s = this.mt[i-1] ^ (this.mt[i-1] >>> 30)
  //    this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525)))
  //      + init_key[j] + j; /* non linear */
  //    this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
  //    i++; j++;
  //    if (i>=this.N) { this.mt[0] = this.mt[this.N-1]; i=1; }
  //    if (j>=key_length) j=0;
  //  }
  //  for (k=this.N-1; k; k--) {
  //    var s = this.mt[i-1] ^ (this.mt[i-1] >>> 30);
  //    this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941))
  //      - i; /* non linear */
  //    this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
  //    i++;
  //    if (i>=this.N) { this.mt[0] = this.mt[this.N-1]; i=1; }
  //  }
  //
  //  this.mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
  //}
  
  /* generates a random number on [0,0xffffffff]-interval */
  MersenneTwister.prototype.genrand_int32 = function() {
    var y;
    var mag01 = new Array(0x0, this.MATRIX_A);
    /* mag01[x] = x * MATRIX_A  for x=0,1 */
  
    if (this.mti >= this.N) { /* generate N words at one time */
      var kk;
  
      if (this.mti == this.N+1)   /* if init_genrand() has not been called, */
        this.init_genrand(5489); /* a default initial seed is used */
  
      for (kk=0;kk<this.N-this.M;kk++) {
        y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk+1]&this.LOWER_MASK);
        this.mt[kk] = this.mt[kk+this.M] ^ (y >>> 1) ^ mag01[y & 0x1];
      }
      for (;kk<this.N-1;kk++) {
        y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk+1]&this.LOWER_MASK);
        this.mt[kk] = this.mt[kk+(this.M-this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
      }
      y = (this.mt[this.N-1]&this.UPPER_MASK)|(this.mt[0]&this.LOWER_MASK);
      this.mt[this.N-1] = this.mt[this.M-1] ^ (y >>> 1) ^ mag01[y & 0x1];
  
      this.mti = 0;
    }
  
    y = this.mt[this.mti++];
  
    /* Tempering */
    y ^= (y >>> 11);
    y ^= (y << 7) & 0x9d2c5680;
    y ^= (y << 15) & 0xefc60000;
    y ^= (y >>> 18);
  
    return y >>> 0;
  }
  
  /* generates a random number on [0,0x7fffffff]-interval */
  //MersenneTwister.prototype.genrand_int31 = function() {
  //  return (this.genrand_int32()>>>1);
  //}
  
  /* generates a random number on [0,1]-real-interval */
  //MersenneTwister.prototype.genrand_real1 = function() {
  //  return this.genrand_int32()*(1.0/4294967295.0);
  //  /* divided by 2^32-1 */
  //}
  
  /* generates a random number on [0,1)-real-interval */
  MersenneTwister.prototype.random = function() {
    return this.genrand_int32()*(1.0/4294967296.0);
    /* divided by 2^32 */
  }
  
  /* generates a random number on (0,1)-real-interval */
  //MersenneTwister.prototype.genrand_real3 = function() {
  //  return (this.genrand_int32() + 0.5)*(1.0/4294967296.0);
  //  /* divided by 2^32 */
  //}
  
  /* generates a random number on [0,1) with 53-bit resolution*/
  //MersenneTwister.prototype.genrand_res53 = function() {
  //  var a=this.genrand_int32()>>>5, b=this.genrand_int32()>>>6;
  //  return(a*67108864.0+b)*(1.0/9007199254740992.0);
  //}
  
  /* These real versions are due to Isaku Wada, 2002/01/09 added */
  
  return MersenneTwister;
  });
  
  define('Core/Check',[
          './defined',
          './DeveloperError'
      ], function(
          defined,
          DeveloperError) {
      'use strict';
  
      /**
       * Contains functions for checking that supplied arguments are of a specified type
       * or meet specified conditions
       * @private
       */
      var Check = {};
  
      /**
       * Contains type checking functions, all using the typeof operator
       */
      Check.typeOf = {};
  
      function getUndefinedErrorMessage(name) {
          return name + ' is required, actual value was undefined';
      }
  
      function getFailedTypeErrorMessage(actual, expected, name) {
          return 'Expected ' + name + ' to be typeof ' + expected + ', actual typeof was ' + actual;
      }
  
      /**
       * Throws if test is not defined
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value that is to be checked
       * @exception {DeveloperError} test must be defined
       */
      Check.defined = function (name, test) {
          if (!defined(test)) {
              throw new DeveloperError(getUndefinedErrorMessage(name));
          }
      };
  
      /**
       * Throws if test is not typeof 'function'
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @exception {DeveloperError} test must be typeof 'function'
       */
      Check.typeOf.func = function (name, test) {
          if (typeof test !== 'function') {
              throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'function', name));
          }
      };
  
      /**
       * Throws if test is not typeof 'string'
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @exception {DeveloperError} test must be typeof 'string'
       */
      Check.typeOf.string = function (name, test) {
          if (typeof test !== 'string') {
              throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'string', name));
          }
      };
  
      /**
       * Throws if test is not typeof 'number'
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @exception {DeveloperError} test must be typeof 'number'
       */
      Check.typeOf.number = function (name, test) {
          if (typeof test !== 'number') {
              throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'number', name));
          }
      };
  
      /**
       * Throws if test is not typeof 'number' and less than limit
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @param {Number} limit The limit value to compare against
       * @exception {DeveloperError} test must be typeof 'number' and less than limit
       */
      Check.typeOf.number.lessThan = function (name, test, limit) {
          Check.typeOf.number(name, test);
          if (test >= limit) {
              throw new DeveloperError('Expected ' + name + ' to be less than ' + limit + ', actual value was ' + test);
          }
      };
  
      /**
       * Throws if test is not typeof 'number' and less than or equal to limit
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @param {Number} limit The limit value to compare against
       * @exception {DeveloperError} test must be typeof 'number' and less than or equal to limit
       */
      Check.typeOf.number.lessThanOrEquals = function (name, test, limit) {
          Check.typeOf.number(name, test);
          if (test > limit) {
              throw new DeveloperError('Expected ' + name + ' to be less than or equal to ' + limit + ', actual value was ' + test);
          }
      };
  
      /**
       * Throws if test is not typeof 'number' and greater than limit
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @param {Number} limit The limit value to compare against
       * @exception {DeveloperError} test must be typeof 'number' and greater than limit
       */
      Check.typeOf.number.greaterThan = function (name, test, limit) {
          Check.typeOf.number(name, test);
          if (test <= limit) {
              throw new DeveloperError('Expected ' + name + ' to be greater than ' + limit + ', actual value was ' + test);
          }
      };
  
      /**
       * Throws if test is not typeof 'number' and greater than or equal to limit
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @param {Number} limit The limit value to compare against
       * @exception {DeveloperError} test must be typeof 'number' and greater than or equal to limit
       */
      Check.typeOf.number.greaterThanOrEquals = function (name, test, limit) {
          Check.typeOf.number(name, test);
          if (test < limit) {
              throw new DeveloperError('Expected ' + name + ' to be greater than or equal to' + limit + ', actual value was ' + test);
          }
      };
  
      /**
       * Throws if test is not typeof 'object'
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @exception {DeveloperError} test must be typeof 'object'
       */
      Check.typeOf.object = function (name, test) {
          if (typeof test !== 'object') {
              throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'object', name));
          }
      };
  
      /**
       * Throws if test is not typeof 'boolean'
       *
       * @param {String} name The name of the variable being tested
       * @param {*} test The value to test
       * @exception {DeveloperError} test must be typeof 'boolean'
       */
      Check.typeOf.bool = function (name, test) {
          if (typeof test !== 'boolean') {
              throw new DeveloperError(getFailedTypeErrorMessage(typeof test, 'boolean', name));
          }
      };
  
      /**
       * Throws if test1 and test2 is not typeof 'number' and not equal in value
       *
       * @param {String} name1 The name of the first variable being tested
       * @param {String} name2 The name of the second variable being tested against
       * @param {*} test1 The value to test
       * @param {*} test2 The value to test against
       * @exception {DeveloperError} test1 and test2 should be type of 'number' and be equal in value
       */
      Check.typeOf.number.equals = function (name1, name2, test1, test2) {
          Check.typeOf.number(name1, test1);
          Check.typeOf.number(name2, test2);
          if (test1 !== test2) {
              throw new DeveloperError(name1 + ' must be equal to ' + name2 + ', the actual values are ' + test1 + ' and ' + test2);
          }
      };
  
      return Check;
  });
  
  define('Core/Math',[
          '../ThirdParty/mersenne-twister',
          './Check',
          './defaultValue',
          './defined',
          './DeveloperError'
      ], function(
          MersenneTwister,
          Check,
          defaultValue,
          defined,
          DeveloperError) {
      'use strict';
  
      /**
       * Math functions.
       *
       * @exports CesiumMath
       * @alias Math
       */
      var CesiumMath = {};
  
      /**
       * 0.1
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON1 = 0.1;
  
      /**
       * 0.01
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON2 = 0.01;
  
      /**
       * 0.001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON3 = 0.001;
  
      /**
       * 0.0001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON4 = 0.0001;
  
      /**
       * 0.00001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON5 = 0.00001;
  
      /**
       * 0.000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON6 = 0.000001;
  
      /**
       * 0.0000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON7 = 0.0000001;
  
      /**
       * 0.00000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON8 = 0.00000001;
  
      /**
       * 0.000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON9 = 0.000000001;
  
      /**
       * 0.0000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON10 = 0.0000000001;
  
      /**
       * 0.00000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON11 = 0.00000000001;
  
      /**
       * 0.000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON12 = 0.000000000001;
  
      /**
       * 0.0000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON13 = 0.0000000000001;
  
      /**
       * 0.00000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON14 = 0.00000000000001;
  
      /**
       * 0.000000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON15 = 0.000000000000001;
  
      /**
       * 0.0000000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON16 = 0.0000000000000001;
  
      /**
       * 0.00000000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON17 = 0.00000000000000001;
  
      /**
       * 0.000000000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON18 = 0.000000000000000001;
  
      /**
       * 0.0000000000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON19 = 0.0000000000000000001;
  
      /**
       * 0.00000000000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON20 = 0.00000000000000000001;
  
      /**
       * 0.000000000000000000001
       * @type {Number}
       * @constant
       */
      CesiumMath.EPSILON21 = 0.000000000000000000001;
  
      /**
       * The gravitational parameter of the Earth in meters cubed
       * per second squared as defined by the WGS84 model: 3.986004418e14
       * @type {Number}
       * @constant
       */
      CesiumMath.GRAVITATIONALPARAMETER = 3.986004418e14;
  
      /**
       * Radius of the sun in meters: 6.955e8
       * @type {Number}
       * @constant
       */
      CesiumMath.SOLAR_RADIUS = 6.955e8;
  
      /**
       * The mean radius of the moon, according to the "Report of the IAU/IAG Working Group on
       * Cartographic Coordinates and Rotational Elements of the Planets and satellites: 2000",
       * Celestial Mechanics 82: 83-110, 2002.
       * @type {Number}
       * @constant
       */
      CesiumMath.LUNAR_RADIUS = 1737400.0;
  
      /**
       * 64 * 1024
       * @type {Number}
       * @constant
       */
      CesiumMath.SIXTY_FOUR_KILOBYTES = 64 * 1024;
  
      /**
       * Returns the sign of the value; 1 if the value is positive, -1 if the value is
       * negative, or 0 if the value is 0.
       *
       * @function
       * @param {Number} value The value to return the sign of.
       * @returns {Number} The sign of value.
       */
      CesiumMath.sign = defaultValue(Math.sign, function sign(value) {
          value = +value; // coerce to number
          if (value === 0 || value !== value) {
              // zero or NaN
              return value;
          }
          return value > 0 ? 1 : -1;
      });
  
      /**
       * Returns 1.0 if the given value is positive or zero, and -1.0 if it is negative.
       * This is similar to {@link CesiumMath#sign} except that returns 1.0 instead of
       * 0.0 when the input value is 0.0.
       * @param {Number} value The value to return the sign of.
       * @returns {Number} The sign of value.
       */
      CesiumMath.signNotZero = function(value) {
          return value < 0.0 ? -1.0 : 1.0;
      };
  
      /**
       * Converts a scalar value in the range [-1.0, 1.0] to a SNORM in the range [0, rangeMaximum]
       * @param {Number} value The scalar value in the range [-1.0, 1.0]
       * @param {Number} [rangeMaximum=255] The maximum value in the mapped range, 255 by default.
       * @returns {Number} A SNORM value, where 0 maps to -1.0 and rangeMaximum maps to 1.0.
       *
       * @see CesiumMath.fromSNorm
       */
      CesiumMath.toSNorm = function(value, rangeMaximum) {
          rangeMaximum = defaultValue(rangeMaximum, 255);
          return Math.round((CesiumMath.clamp(value, -1.0, 1.0) * 0.5 + 0.5) * rangeMaximum);
      };
  
      /**
       * Converts a SNORM value in the range [0, rangeMaximum] to a scalar in the range [-1.0, 1.0].
       * @param {Number} value SNORM value in the range [0, rangeMaximum]
       * @param {Number} [rangeMaximum=255] The maximum value in the SNORM range, 255 by default.
       * @returns {Number} Scalar in the range [-1.0, 1.0].
       *
       * @see CesiumMath.toSNorm
       */
      CesiumMath.fromSNorm = function(value, rangeMaximum) {
          rangeMaximum = defaultValue(rangeMaximum, 255);
          return CesiumMath.clamp(value, 0.0, rangeMaximum) / rangeMaximum * 2.0 - 1.0;
      };
  
      /**
       * Converts a scalar value in the range [rangeMinimum, rangeMaximum] to a scalar in the range [0.0, 1.0]
       * @param {Number} value The scalar value in the range [rangeMinimum, rangeMaximum]
       * @param {Number} rangeMinimum The minimum value in the mapped range.
       * @param {Number} rangeMaximum The maximum value in the mapped range.
       * @returns {Number} A scalar value, where rangeMinimum maps to 0.0 and rangeMaximum maps to 1.0.
       */
      CesiumMath.normalize = function(value, rangeMinimum, rangeMaximum) {
          rangeMaximum = Math.max(rangeMaximum - rangeMinimum, 0.0);
          return rangeMaximum === 0.0 ? 0.0 : CesiumMath.clamp((value - rangeMinimum) / rangeMaximum, 0.0, 1.0);
      };
  
      /**
       * Returns the hyperbolic sine of a number.
       * The hyperbolic sine of <em>value</em> is defined to be
       * (<em>e<sup>x</sup>&nbsp;-&nbsp;e<sup>-x</sup></em>)/2.0
       * where <i>e</i> is Euler's number, approximately 2.71828183.
       *
       * <p>Special cases:
       *   <ul>
       *     <li>If the argument is NaN, then the result is NaN.</li>
       *
       *     <li>If the argument is infinite, then the result is an infinity
       *     with the same sign as the argument.</li>
       *
       *     <li>If the argument is zero, then the result is a zero with the
       *     same sign as the argument.</li>
       *   </ul>
       *</p>
       *
       * @function
       * @param {Number} value The number whose hyperbolic sine is to be returned.
       * @returns {Number} The hyperbolic sine of <code>value</code>.
       */
      CesiumMath.sinh = defaultValue(Math.sinh, function sinh(value) {
          return (Math.exp(value) - Math.exp(-value)) / 2.0;
      });
  
      /**
       * Returns the hyperbolic cosine of a number.
       * The hyperbolic cosine of <strong>value</strong> is defined to be
       * (<em>e<sup>x</sup>&nbsp;+&nbsp;e<sup>-x</sup></em>)/2.0
       * where <i>e</i> is Euler's number, approximately 2.71828183.
       *
       * <p>Special cases:
       *   <ul>
       *     <li>If the argument is NaN, then the result is NaN.</li>
       *
       *     <li>If the argument is infinite, then the result is positive infinity.</li>
       *
       *     <li>If the argument is zero, then the result is 1.0.</li>
       *   </ul>
       *</p>
       *
       * @function
       * @param {Number} value The number whose hyperbolic cosine is to be returned.
       * @returns {Number} The hyperbolic cosine of <code>value</code>.
       */
      CesiumMath.cosh = defaultValue(Math.cosh, function cosh(value) {
          return (Math.exp(value) + Math.exp(-value)) / 2.0;
      });
  
      /**
       * Computes the linear interpolation of two values.
       *
       * @param {Number} p The start value to interpolate.
       * @param {Number} q The end value to interpolate.
       * @param {Number} time The time of interpolation generally in the range <code>[0.0, 1.0]</code>.
       * @returns {Number} The linearly interpolated value.
       *
       * @example
       * var n = Cesium.Math.lerp(0.0, 2.0, 0.5); // returns 1.0
       */
      CesiumMath.lerp = function(p, q, time) {
          return ((1.0 - time) * p) + (time * q);
      };
  
      /**
       * pi
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.PI = Math.PI;
  
      /**
       * 1/pi
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.ONE_OVER_PI = 1.0 / Math.PI;
  
      /**
       * pi/2
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.PI_OVER_TWO = Math.PI / 2.0;
  
      /**
       * pi/3
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.PI_OVER_THREE = Math.PI / 3.0;
  
      /**
       * pi/4
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.PI_OVER_FOUR = Math.PI / 4.0;
  
      /**
       * pi/6
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.PI_OVER_SIX = Math.PI / 6.0;
  
      /**
       * 3pi/2
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.THREE_PI_OVER_TWO = 3.0 * Math.PI / 2.0;
  
      /**
       * 2pi
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.TWO_PI = 2.0 * Math.PI;
  
      /**
       * 1/2pi
       *
       * @type {Number}
       * @constant
       */
      CesiumMath.ONE_OVER_TWO_PI = 1.0 / (2.0 * Math.PI);
  
      /**
       * The number of radians in a degree.
       *
       * @type {Number}
       * @constant
       * @default Math.PI / 180.0
       */
      CesiumMath.RADIANS_PER_DEGREE = Math.PI / 180.0;
  
      /**
       * The number of degrees in a radian.
       *
       * @type {Number}
       * @constant
       * @default 180.0 / Math.PI
       */
      CesiumMath.DEGREES_PER_RADIAN = 180.0 / Math.PI;
  
      /**
       * The number of radians in an arc second.
       *
       * @type {Number}
       * @constant
       * @default {@link CesiumMath.RADIANS_PER_DEGREE} / 3600.0
       */
      CesiumMath.RADIANS_PER_ARCSECOND = CesiumMath.RADIANS_PER_DEGREE / 3600.0;
  
      /**
       * Converts degrees to radians.
       * @param {Number} degrees The angle to convert in degrees.
       * @returns {Number} The corresponding angle in radians.
       */
      CesiumMath.toRadians = function(degrees) {
                  if (!defined(degrees)) {
              throw new DeveloperError('degrees is required.');
          }
                  return degrees * CesiumMath.RADIANS_PER_DEGREE;
      };
  
      /**
       * Converts radians to degrees.
       * @param {Number} radians The angle to convert in radians.
       * @returns {Number} The corresponding angle in degrees.
       */
      CesiumMath.toDegrees = function(radians) {
                  if (!defined(radians)) {
              throw new DeveloperError('radians is required.');
          }
                  return radians * CesiumMath.DEGREES_PER_RADIAN;
      };
  
      /**
       * Converts a longitude value, in radians, to the range [<code>-Math.PI</code>, <code>Math.PI</code>).
       *
       * @param {Number} angle The longitude value, in radians, to convert to the range [<code>-Math.PI</code>, <code>Math.PI</code>).
       * @returns {Number} The equivalent longitude value in the range [<code>-Math.PI</code>, <code>Math.PI</code>).
       *
       * @example
       * // Convert 270 degrees to -90 degrees longitude
       * var longitude = Cesium.Math.convertLongitudeRange(Cesium.Math.toRadians(270.0));
       */
      CesiumMath.convertLongitudeRange = function(angle) {
                  if (!defined(angle)) {
              throw new DeveloperError('angle is required.');
          }
                  var twoPi = CesiumMath.TWO_PI;
  
          var simplified = angle - Math.floor(angle / twoPi) * twoPi;
  
          if (simplified < -Math.PI) {
              return simplified + twoPi;
          }
          if (simplified >= Math.PI) {
              return simplified - twoPi;
          }
  
          return simplified;
      };
  
      /**
       * Convenience function that clamps a latitude value, in radians, to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
       * Useful for sanitizing data before use in objects requiring correct range.
       *
       * @param {Number} angle The latitude value, in radians, to clamp to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
       * @returns {Number} The latitude value clamped to the range [<code>-Math.PI/2</code>, <code>Math.PI/2</code>).
       *
       * @example
       * // Clamp 108 degrees latitude to 90 degrees latitude
       * var latitude = Cesium.Math.clampToLatitudeRange(Cesium.Math.toRadians(108.0));
       */
      CesiumMath.clampToLatitudeRange = function(angle) {
                  if (!defined(angle)) {
              throw new DeveloperError('angle is required.');
          }
          
          return CesiumMath.clamp(angle, -1*CesiumMath.PI_OVER_TWO, CesiumMath.PI_OVER_TWO);
      };
  
      /**
       * Produces an angle in the range -Pi <= angle <= Pi which is equivalent to the provided angle.
       *
       * @param {Number} angle in radians
       * @returns {Number} The angle in the range [<code>-CesiumMath.PI</code>, <code>CesiumMath.PI</code>].
       */
      CesiumMath.negativePiToPi = function(angle) {
                  if (!defined(angle)) {
              throw new DeveloperError('angle is required.');
          }
                  return CesiumMath.zeroToTwoPi(angle + CesiumMath.PI) - CesiumMath.PI;
      };
  
      /**
       * Produces an angle in the range 0 <= angle <= 2Pi which is equivalent to the provided angle.
       *
       * @param {Number} angle in radians
       * @returns {Number} The angle in the range [0, <code>CesiumMath.TWO_PI</code>].
       */
      CesiumMath.zeroToTwoPi = function(angle) {
                  if (!defined(angle)) {
              throw new DeveloperError('angle is required.');
          }
                  var mod = CesiumMath.mod(angle, CesiumMath.TWO_PI);
          if (Math.abs(mod) < CesiumMath.EPSILON14 && Math.abs(angle) > CesiumMath.EPSILON14) {
              return CesiumMath.TWO_PI;
          }
          return mod;
      };
  
      /**
       * The modulo operation that also works for negative dividends.
       *
       * @param {Number} m The dividend.
       * @param {Number} n The divisor.
       * @returns {Number} The remainder.
       */
      CesiumMath.mod = function(m, n) {
                  if (!defined(m)) {
              throw new DeveloperError('m is required.');
          }
          if (!defined(n)) {
              throw new DeveloperError('n is required.');
          }
                  return ((m % n) + n) % n;
      };
  
      /**
       * Determines if two values are equal using an absolute or relative tolerance test. This is useful
       * to avoid problems due to roundoff error when comparing floating-point values directly. The values are
       * first compared using an absolute tolerance test. If that fails, a relative tolerance test is performed.
       * Use this test if you are unsure of the magnitudes of left and right.
       *
       * @param {Number} left The first value to compare.
       * @param {Number} right The other value to compare.
       * @param {Number} relativeEpsilon The maximum inclusive delta between <code>left</code> and <code>right</code> for the relative tolerance test.
       * @param {Number} [absoluteEpsilon=relativeEpsilon] The maximum inclusive delta between <code>left</code> and <code>right</code> for the absolute tolerance test.
       * @returns {Boolean} <code>true</code> if the values are equal within the epsilon; otherwise, <code>false</code>.
       *
       * @example
       * var a = Cesium.Math.equalsEpsilon(0.0, 0.01, Cesium.Math.EPSILON2); // true
       * var b = Cesium.Math.equalsEpsilon(0.0, 0.1, Cesium.Math.EPSILON2);  // false
       * var c = Cesium.Math.equalsEpsilon(3699175.1634344, 3699175.2, Cesium.Math.EPSILON7); // true
       * var d = Cesium.Math.equalsEpsilon(3699175.1634344, 3699175.2, Cesium.Math.EPSILON9); // false
       */
      CesiumMath.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) {
                  if (!defined(left)) {
              throw new DeveloperError('left is required.');
          }
          if (!defined(right)) {
              throw new DeveloperError('right is required.');
          }
          if (!defined(relativeEpsilon)) {
              throw new DeveloperError('relativeEpsilon is required.');
          }
                  absoluteEpsilon = defaultValue(absoluteEpsilon, relativeEpsilon);
          var absDiff = Math.abs(left - right);
          return absDiff <= absoluteEpsilon || absDiff <= relativeEpsilon * Math.max(Math.abs(left), Math.abs(right));
      };
  
      /**
       * Determines if the left value is less than the right value. If the two values are within
       * <code>absoluteEpsilon</code> of each other, they are considered equal and this function returns false.
       *
       * @param {Number} left The first number to compare.
       * @param {Number} right The second number to compare.
       * @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
       * @returns {Boolean} <code>true</code> if <code>left</code> is less than <code>right</code> by more than
       *          <code>absoluteEpsilon<code>. <code>false</code> if <code>left</code> is greater or if the two
       *          values are nearly equal.
       */
      CesiumMath.lessThan = function(left, right, absoluteEpsilon) {
                  if (!defined(left)) {
              throw new DeveloperError('first is required.');
          }
          if (!defined(right)) {
              throw new DeveloperError('second is required.');
          }
          if (!defined(absoluteEpsilon)) {
              throw new DeveloperError('relativeEpsilon is required.');
          }
                  return left - right < -absoluteEpsilon;
      };
  
      /**
       * Determines if the left value is less than or equal to the right value. If the two values are within
       * <code>absoluteEpsilon</code> of each other, they are considered equal and this function returns true.
       *
       * @param {Number} left The first number to compare.
       * @param {Number} right The second number to compare.
       * @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
       * @returns {Boolean} <code>true</code> if <code>left</code> is less than <code>right</code> or if the
       *          the values are nearly equal.
       */
      CesiumMath.lessThanOrEquals = function(left, right, absoluteEpsilon) {
                  if (!defined(left)) {
              throw new DeveloperError('first is required.');
          }
          if (!defined(right)) {
              throw new DeveloperError('second is required.');
          }
          if (!defined(absoluteEpsilon)) {
              throw new DeveloperError('relativeEpsilon is required.');
          }
                  return left - right < absoluteEpsilon;
      };
  
      /**
       * Determines if the left value is greater the right value. If the two values are within
       * <code>absoluteEpsilon</code> of each other, they are considered equal and this function returns false.
       *
       * @param {Number} left The first number to compare.
       * @param {Number} right The second number to compare.
       * @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
       * @returns {Boolean} <code>true</code> if <code>left</code> is greater than <code>right</code> by more than
       *          <code>absoluteEpsilon<code>. <code>false</code> if <code>left</code> is less or if the two
       *          values are nearly equal.
       */
      CesiumMath.greaterThan = function(left, right, absoluteEpsilon) {
                  if (!defined(left)) {
              throw new DeveloperError('first is required.');
          }
          if (!defined(right)) {
              throw new DeveloperError('second is required.');
          }
          if (!defined(absoluteEpsilon)) {
              throw new DeveloperError('relativeEpsilon is required.');
          }
                  return left - right > absoluteEpsilon;
      };
  
      /**
       * Determines if the left value is greater than or equal to the right value. If the two values are within
       * <code>absoluteEpsilon</code> of each other, they are considered equal and this function returns true.
       *
       * @param {Number} left The first number to compare.
       * @param {Number} right The second number to compare.
       * @param {Number} absoluteEpsilon The absolute epsilon to use in comparison.
       * @returns {Boolean} <code>true</code> if <code>left</code> is greater than <code>right</code> or if the
       *          the values are nearly equal.
       */
      CesiumMath.greaterThanOrEquals = function(left, right, absoluteEpsilon) {
                  if (!defined(left)) {
              throw new DeveloperError('first is required.');
          }
          if (!defined(right)) {
              throw new DeveloperError('second is required.');
          }
          if (!defined(absoluteEpsilon)) {
              throw new DeveloperError('relativeEpsilon is required.');
          }
                  return left - right > -absoluteEpsilon;
      };
  
      var factorials = [1];
  
      /**
       * Computes the factorial of the provided number.
       *
       * @param {Number} n The number whose factorial is to be computed.
       * @returns {Number} The factorial of the provided number or undefined if the number is less than 0.
       *
       * @exception {DeveloperError} A number greater than or equal to 0 is required.
       *
       *
       * @example
       * //Compute 7!, which is equal to 5040
       * var computedFactorial = Cesium.Math.factorial(7);
       *
       * @see {@link http://en.wikipedia.org/wiki/Factorial|Factorial on Wikipedia}
       */
      CesiumMath.factorial = function(n) {
                  if (typeof n !== 'number' || n < 0) {
              throw new DeveloperError('A number greater than or equal to 0 is required.');
          }
          
          var length = factorials.length;
          if (n >= length) {
              var sum = factorials[length - 1];
              for (var i = length; i <= n; i++) {
                  factorials.push(sum * i);
              }
          }
          return factorials[n];
      };
  
      /**
       * Increments a number with a wrapping to a minimum value if the number exceeds the maximum value.
       *
       * @param {Number} [n] The number to be incremented.
       * @param {Number} [maximumValue] The maximum incremented value before rolling over to the minimum value.
       * @param {Number} [minimumValue=0.0] The number reset to after the maximum value has been exceeded.
       * @returns {Number} The incremented number.
       *
       * @exception {DeveloperError} Maximum value must be greater than minimum value.
       *
       * @example
       * var n = Cesium.Math.incrementWrap(5, 10, 0); // returns 6
       * var n = Cesium.Math.incrementWrap(10, 10, 0); // returns 0
       */
      CesiumMath.incrementWrap = function(n, maximumValue, minimumValue) {
          minimumValue = defaultValue(minimumValue, 0.0);
  
                  if (!defined(n)) {
              throw new DeveloperError('n is required.');
          }
          if (maximumValue <= minimumValue) {
              throw new DeveloperError('maximumValue must be greater than minimumValue.');
          }
          
          ++n;
          if (n > maximumValue) {
              n = minimumValue;
          }
          return n;
      };
  
      /**
       * Determines if a positive integer is a power of two.
       *
       * @param {Number} n The positive integer to test.
       * @returns {Boolean} <code>true</code> if the number if a power of two; otherwise, <code>false</code>.
       *
       * @exception {DeveloperError} A number greater than or equal to 0 is required.
       *
       * @example
       * var t = Cesium.Math.isPowerOfTwo(16); // true
       * var f = Cesium.Math.isPowerOfTwo(20); // false
       */
      CesiumMath.isPowerOfTwo = function(n) {
                  if (typeof n !== 'number' || n < 0) {
              throw new DeveloperError('A number greater than or equal to 0 is required.');
          }
          
          return (n !== 0) && ((n & (n - 1)) === 0);
      };
  
      /**
       * Computes the next power-of-two integer greater than or equal to the provided positive integer.
       *
       * @param {Number} n The positive integer to test.
       * @returns {Number} The next power-of-two integer.
       *
       * @exception {DeveloperError} A number greater than or equal to 0 is required.
       *
       * @example
       * var n = Cesium.Math.nextPowerOfTwo(29); // 32
       * var m = Cesium.Math.nextPowerOfTwo(32); // 32
       */
      CesiumMath.nextPowerOfTwo = function(n) {
                  if (typeof n !== 'number' || n < 0) {
              throw new DeveloperError('A number greater than or equal to 0 is required.');
          }
          
          // From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
          --n;
          n |= n >> 1;
          n |= n >> 2;
          n |= n >> 4;
          n |= n >> 8;
          n |= n >> 16;
          ++n;
  
          return n;
      };
  
      /**
       * Constraint a value to lie between two values.
       *
       * @param {Number} value The value to constrain.
       * @param {Number} min The minimum value.
       * @param {Number} max The maximum value.
       * @returns {Number} The value clamped so that min <= value <= max.
       */
      CesiumMath.clamp = function(value, min, max) {
                  if (!defined(value)) {
              throw new DeveloperError('value is required');
          }
          if (!defined(min)) {
              throw new DeveloperError('min is required.');
          }
          if (!defined(max)) {
              throw new DeveloperError('max is required.');
          }
                  return value < min ? min : value > max ? max : value;
      };
  
      var randomNumberGenerator = new MersenneTwister();
  
      /**
       * Sets the seed used by the random number generator
       * in {@link CesiumMath#nextRandomNumber}.
       *
       * @param {Number} seed An integer used as the seed.
       */
      CesiumMath.setRandomNumberSeed = function(seed) {
                  if (!defined(seed)) {
              throw new DeveloperError('seed is required.');
          }
          
          randomNumberGenerator = new MersenneTwister(seed);
      };
  
      /**
       * Generates a random floating point number in the range of [0.0, 1.0)
       * using a Mersenne twister.
       *
       * @returns {Number} A random number in the range of [0.0, 1.0).
       *
       * @see CesiumMath.setRandomNumberSeed
       * @see {@link http://en.wikipedia.org/wiki/Mersenne_twister|Mersenne twister on Wikipedia}
       */
      CesiumMath.nextRandomNumber = function() {
          return randomNumberGenerator.random();
      };
  
      /**
       * Generates a random number between two numbers.
       *
       * @param {Number} min The minimum value.
       * @param {Number} max The maximum value.
       * @returns {Number} A random number between the min and max.
       */
      CesiumMath.randomBetween = function(min, max) {
          return CesiumMath.nextRandomNumber() * (max - min) + min;
      };
  
      /**
       * Computes <code>Math.acos(value)</code>, but first clamps <code>value</code> to the range [-1.0, 1.0]
       * so that the function will never return NaN.
       *
       * @param {Number} value The value for which to compute acos.
       * @returns {Number} The acos of the value if the value is in the range [-1.0, 1.0], or the acos of -1.0 or 1.0,
       *          whichever is closer, if the value is outside the range.
       */
      CesiumMath.acosClamped = function(value) {
                  if (!defined(value)) {
              throw new DeveloperError('value is required.');
          }
                  return Math.acos(CesiumMath.clamp(value, -1.0, 1.0));
      };
  
      /**
       * Computes <code>Math.asin(value)</code>, but first clamps <code>value</code> to the range [-1.0, 1.0]
       * so that the function will never return NaN.
       *
       * @param {Number} value The value for which to compute asin.
       * @returns {Number} The asin of the value if the value is in the range [-1.0, 1.0], or the asin of -1.0 or 1.0,
       *          whichever is closer, if the value is outside the range.
       */
      CesiumMath.asinClamped = function(value) {
                  if (!defined(value)) {
              throw new DeveloperError('value is required.');
          }
                  return Math.asin(CesiumMath.clamp(value, -1.0, 1.0));
      };
  
      /**
       * Finds the chord length between two points given the circle's radius and the angle between the points.
       *
       * @param {Number} angle The angle between the two points.
       * @param {Number} radius The radius of the circle.
       * @returns {Number} The chord length.
       */
      CesiumMath.chordLength = function(angle, radius) {
                  if (!defined(angle)) {
              throw new DeveloperError('angle is required.');
          }
          if (!defined(radius)) {
              throw new DeveloperError('radius is required.');
          }
                  return 2.0 * radius * Math.sin(angle * 0.5);
      };
  
      /**
       * Finds the logarithm of a number to a base.
       *
       * @param {Number} number The number.
       * @param {Number} base The base.
       * @returns {Number} The result.
       */
      CesiumMath.logBase = function(number, base) {
                  if (!defined(number)) {
              throw new DeveloperError('number is required.');
          }
          if (!defined(base)) {
              throw new DeveloperError('base is required.');
          }
                  return Math.log(number) / Math.log(base);
      };
  
      /**
       * Finds the cube root of a number.
       * Returns NaN if <code>number</code> is not provided.
       *
       * @function
       * @param {Number} [number] The number.
       * @returns {Number} The result.
       */
      CesiumMath.cbrt = defaultValue(Math.cbrt, function cbrt(number) {
          var result = Math.pow(Math.abs(number), 1.0 / 3.0);
          return number < 0.0 ? -result : result;
      });
  
      /**
       * Finds the base 2 logarithm of a number.
       *
       * @function
       * @param {Number} number The number.
       * @returns {Number} The result.
       */
      CesiumMath.log2 = defaultValue(Math.log2, function log2(number) {
          return Math.log(number) * Math.LOG2E;
      });
  
      /**
       * @private
       */
      CesiumMath.fog = function(distanceToCamera, density) {
          var scalar = distanceToCamera * density;
          return 1.0 - Math.exp(-(scalar * scalar));
      };
  
      /**
       * Computes a fast approximation of Atan for input in the range [-1, 1].
       *
       * Based on Michal Drobot's approximation from ShaderFastLibs,
       * which in turn is based on "Efficient approximations for the arctangent function,"
       * Rajan, S. Sichun Wang Inkol, R. Joyal, A., May 2006.
       * Adapted from ShaderFastLibs under MIT License.
       *
       * @param {Number} x An input number in the range [-1, 1]
       * @returns {Number} An approximation of atan(x)
       */
      CesiumMath.fastApproximateAtan = function(x) {
                  Check.typeOf.number('x', x);
          
          return x * (-0.1784 * Math.abs(x) - 0.0663 * x * x + 1.0301);
      };
  
      /**
       * Computes a fast approximation of Atan2(x, y) for arbitrary input scalars.
       *
       * Range reduction math based on nvidia's cg reference implementation: http://developer.download.nvidia.com/cg/atan2.html
       *
       * @param {Number} x An input number that isn't zero if y is zero.
       * @param {Number} y An input number that isn't zero if x is zero.
       * @returns {Number} An approximation of atan2(x, y)
       */
      CesiumMath.fastApproximateAtan2 = function(x, y) {
                  Check.typeOf.number('x', x);
          Check.typeOf.number('y', y);
          
          // atan approximations are usually only reliable over [-1, 1]
          // So reduce the range by flipping whether x or y is on top based on which is bigger.
          var opposite;
          var adjacent;
          var t = Math.abs(x); // t used as swap and atan result.
          opposite = Math.abs(y);
          adjacent = Math.max(t, opposite);
          opposite = Math.min(t, opposite);
  
          var oppositeOverAdjacent = opposite / adjacent;
                  if (isNaN(oppositeOverAdjacent)) {
              throw new DeveloperError('either x or y must be nonzero');
          }
                  t = CesiumMath.fastApproximateAtan(oppositeOverAdjacent);
  
          // Undo range reduction
          t = Math.abs(y) > Math.abs(x) ? CesiumMath.PI_OVER_TWO - t : t;
          t = x < 0.0 ?  CesiumMath.PI - t : t;
          t = y < 0.0 ? -t : t;
          return t;
      };
  
      return CesiumMath;
  });
  
  define('Core/IndexDatatype',[
          './defined',
          './DeveloperError',
          './freezeObject',
          './Math',
          './WebGLConstants'
      ], function(
          defined,
          DeveloperError,
          freezeObject,
          CesiumMath,
          WebGLConstants) {
      'use strict';
  
      /**
       * Constants for WebGL index datatypes.  These corresponds to the
       * <code>type</code> parameter of {@link http://www.khronos.org/opengles/sdk/docs/man/xhtml/glDrawElements.xml|drawElements}.
       *
       * @exports IndexDatatype
       */
      var IndexDatatype = {
          /**
           * 8-bit unsigned byte corresponding to <code>UNSIGNED_BYTE</code> and the type
           * of an element in <code>Uint8Array</code>.
           *
           * @type {Number}
           * @constant
           */
          UNSIGNED_BYTE : WebGLConstants.UNSIGNED_BYTE,
  
          /**
           * 16-bit unsigned short corresponding to <code>UNSIGNED_SHORT</code> and the type
           * of an element in <code>Uint16Array</code>.
           *
           * @type {Number}
           * @constant
           */
          UNSIGNED_SHORT : WebGLConstants.UNSIGNED_SHORT,
  
          /**
           * 32-bit unsigned int corresponding to <code>UNSIGNED_INT</code> and the type
           * of an element in <code>Uint32Array</code>.
           *
           * @type {Number}
           * @constant
           */
          UNSIGNED_INT : WebGLConstants.UNSIGNED_INT
      };
  
      /**
       * Returns the size, in bytes, of the corresponding datatype.
       *
       * @param {IndexDatatype} indexDatatype The index datatype to get the size of.
       * @returns {Number} The size in bytes.
       *
       * @example
       * // Returns 2
       * var size = Cesium.IndexDatatype.getSizeInBytes(Cesium.IndexDatatype.UNSIGNED_SHORT);
       */
      IndexDatatype.getSizeInBytes = function(indexDatatype) {
          switch(indexDatatype) {
              case IndexDatatype.UNSIGNED_BYTE:
                  return Uint8Array.BYTES_PER_ELEMENT;
              case IndexDatatype.UNSIGNED_SHORT:
                  return Uint16Array.BYTES_PER_ELEMENT;
              case IndexDatatype.UNSIGNED_INT:
                  return Uint32Array.BYTES_PER_ELEMENT;
          }
  
                  throw new DeveloperError('indexDatatype is required and must be a valid IndexDatatype constant.');
              };
  
      /**
       * Gets the datatype with a given size in bytes.
       *
       * @param {Number} sizeInBytes The size of a single index in bytes.
       * @returns {IndexDatatype} The index datatype with the given size.
       */
      IndexDatatype.fromSizeInBytes = function(sizeInBytes) {
          switch (sizeInBytes) {
              case 2:
                  return IndexDatatype.UNSIGNED_SHORT;
              case 4:
                  return IndexDatatype.UNSIGNED_INT;
              case 1:
                  return IndexDatatype.UNSIGNED_BYTE;
                          default:
                  throw new DeveloperError('Size in bytes cannot be mapped to an IndexDatatype');
                      }
      };
  
      /**
       * Validates that the provided index datatype is a valid {@link IndexDatatype}.
       *
       * @param {IndexDatatype} indexDatatype The index datatype to validate.
       * @returns {Boolean} <code>true</code> if the provided index datatype is a valid value; otherwise, <code>false</code>.
       *
       * @example
       * if (!Cesium.IndexDatatype.validate(indexDatatype)) {
       *   throw new Cesium.DeveloperError('indexDatatype must be a valid value.');
       * }
       */
      IndexDatatype.validate = function(indexDatatype) {
          return defined(indexDatatype) &&
                 (indexDatatype === IndexDatatype.UNSIGNED_BYTE ||
                  indexDatatype === IndexDatatype.UNSIGNED_SHORT ||
                  indexDatatype === IndexDatatype.UNSIGNED_INT);
      };
  
      /**
       * Creates a typed array that will store indices, using either <code><Uint16Array</code>
       * or <code>Uint32Array</code> depending on the number of vertices.
       *
       * @param {Number} numberOfVertices Number of vertices that the indices will reference.
       * @param {Number|Array} indicesLengthOrArray Passed through to the typed array constructor.
       * @returns {Uint16Array|Uint32Array} A <code>Uint16Array</code> or <code>Uint32Array</code> constructed with <code>indicesLengthOrArray</code>.
       *
       * @example
       * this.indices = Cesium.IndexDatatype.createTypedArray(positions.length / 3, numberOfIndices);
       */
      IndexDatatype.createTypedArray = function(numberOfVertices, indicesLengthOrArray) {
                  if (!defined(numberOfVertices)) {
              throw new DeveloperError('numberOfVertices is required.');
          }
          
          if (numberOfVertices >= CesiumMath.SIXTY_FOUR_KILOBYTES) {
              return new Uint32Array(indicesLengthOrArray);
          }
  
          return new Uint16Array(indicesLengthOrArray);
      };
  
      /**
       * Creates a typed array from a source array buffer.  The resulting typed array will store indices, using either <code><Uint16Array</code>
       * or <code>Uint32Array</code> depending on the number of vertices.
       *
       * @param {Number} numberOfVertices Number of vertices that the indices will reference.
       * @param {ArrayBuffer} sourceArray Passed through to the typed array constructor.
       * @param {Number} byteOffset Passed through to the typed array constructor.
       * @param {Number} length Passed through to the typed array constructor.
       * @returns {Uint16Array|Uint32Array} A <code>Uint16Array</code> or <code>Uint32Array</code> constructed with <code>sourceArray</code>, <code>byteOffset</code>, and <code>length</code>.
       *
       */
      IndexDatatype.createTypedArrayFromArrayBuffer = function(numberOfVertices, sourceArray, byteOffset, length) {
                  if (!defined(numberOfVertices)) {
              throw new DeveloperError('numberOfVertices is required.');
          }
          if (!defined(sourceArray)) {
              throw new DeveloperError('sourceArray is required.');
          }
          if (!defined(byteOffset)) {
              throw new DeveloperError('byteOffset is required.');
          }
          
          if (numberOfVertices >= CesiumMath.SIXTY_FOUR_KILOBYTES) {
              return new Uint32Array(sourceArray, byteOffset, length);
          }
  
          return new Uint16Array(sourceArray, byteOffset, length);
      };
  
      return freezeObject(IndexDatatype);
  });
  
  define('Core/RuntimeError',[
          './defined'
      ], function(
          defined) {
      'use strict';
  
      /**
       * Constructs an exception object that is thrown due to an error that can occur at runtime, e.g.,
       * out of memory, could not compile shader, etc.  If a function may throw this
       * exception, the calling code should be prepared to catch it.
       * <br /><br />
       * On the other hand, a {@link DeveloperError} indicates an exception due
       * to a developer error, e.g., invalid argument, that usually indicates a bug in the
       * calling code.
       *
       * @alias RuntimeError
       * @constructor
       * @extends Error
       *
       * @param {String} [message] The error message for this exception.
       *
       * @see DeveloperError
       */
      function RuntimeError(message) {
          /**
           * 'RuntimeError' indicating that this exception was thrown due to a runtime error.
           * @type {String}
           * @readonly
           */
          this.name = 'RuntimeError';
  
          /**
           * The explanation for why this exception was thrown.
           * @type {String}
           * @readonly
           */
          this.message = message;
  
          //Browsers such as IE don't have a stack property until you actually throw the error.
          var stack;
          try {
              throw new Error();
          } catch (e) {
              stack = e.stack;
          }
  
          /**
           * The stack trace of this exception, if available.
           * @type {String}
           * @readonly
           */
          this.stack = stack;
      }
  
      if (defined(Object.create)) {
          RuntimeError.prototype = Object.create(Error.prototype);
          RuntimeError.prototype.constructor = RuntimeError;
      }
  
      RuntimeError.prototype.toString = function() {
          var str = this.name + ': ' + this.message;
  
          if (defined(this.stack)) {
              str += '\n' + this.stack.toString();
          }
  
          return str;
      };
  
      return RuntimeError;
  });
  
  define('Core/formatError',[
          './defined'
      ], function(
          defined) {
      'use strict';
  
      /**
       * Formats an error object into a String.  If available, uses name, message, and stack
       * properties, otherwise, falls back on toString().
       *
       * @exports formatError
       *
       * @param {*} object The item to find in the array.
       * @returns {String} A string containing the formatted error.
       */
      function formatError(object) {
          var result;
  
          var name = object.name;
          var message = object.message;
          if (defined(name) && defined(message)) {
              result = name + ': ' + message;
          } else {
              result = object.toString();
          }
  
          var stack = object.stack;
          if (defined(stack)) {
              result += '\n' + stack;
          }
  
          return result;
      }
  
      return formatError;
  });
  
  define('Workers/createTaskProcessorWorker',[
          '../ThirdParty/when',
          '../Core/defaultValue',
          '../Core/defined',
          '../Core/formatError'
      ], function(
          when,
          defaultValue,
          defined,
          formatError) {
      'use strict';
  
      // createXXXGeometry functions may return Geometry or a Promise that resolves to Geometry
      // if the function requires access to ApproximateTerrainHeights.
      // For fully synchronous functions, just wrapping the function call in a `when` Promise doesn't
      // handle errors correctly, hence try-catch
      function callAndWrap(workerFunction, parameters, transferableObjects) {
          var resultOrPromise;
          try {
              resultOrPromise = workerFunction(parameters, transferableObjects);
              return resultOrPromise; // errors handled by Promise
          } catch (e) {
              return when.reject(e);
          }
      }
  
      /**
       * Creates an adapter function to allow a calculation function to operate as a Web Worker,
       * paired with TaskProcessor, to receive tasks and return results.
       *
       * @exports createTaskProcessorWorker
       *
       * @param {createTaskProcessorWorker~WorkerFunction} workerFunction The calculation function,
       *        which takes parameters and returns a result.
       * @returns {createTaskProcessorWorker~TaskProcessorWorkerFunction} A function that adapts the
       *          calculation function to work as a Web Worker onmessage listener with TaskProcessor.
       *
       *
       * @example
       * function doCalculation(parameters, transferableObjects) {
       *   // calculate some result using the inputs in parameters
       *   return result;
       * }
       *
       * return Cesium.createTaskProcessorWorker(doCalculation);
       * // the resulting function is compatible with TaskProcessor
       *
       * @see TaskProcessor
       * @see {@link http://www.w3.org/TR/workers/|Web Workers}
       * @see {@link http://www.w3.org/TR/html5/common-dom-interfaces.html#transferable-objects|Transferable objects}
       */
      function createTaskProcessorWorker(workerFunction) {
          var postMessage;
  
          return function(event) {
              /*global self*/
              var data = event.data;
  
              var transferableObjects = [];
              var responseMessage = {
                  id : data.id,
                  result : undefined,
                  error : undefined
              };
  
              return when(callAndWrap(workerFunction, data.parameters, transferableObjects))
                  .then(function(result) {
                      responseMessage.result = result;
                  })
                  .otherwise(function(e) {
                      if (e instanceof Error) {
                          // Errors can't be posted in a message, copy the properties
                          responseMessage.error = {
                              name : e.name,
                              message : e.message,
                              stack : e.stack
                          };
                      } else {
                          responseMessage.error = e;
                      }
                  })
                  .always(function() {
                      if (!defined(postMessage)) {
                          postMessage = defaultValue(self.webkitPostMessage, self.postMessage);
                      }
  
                      if (!data.canTransferArrayBuffer) {
                          transferableObjects.length = 0;
                      }
  
                      try {
                          postMessage(responseMessage, transferableObjects);
                      } catch (e) {
                          // something went wrong trying to post the message, post a simpler
                          // error that we can be sure will be cloneable
                          responseMessage.result = undefined;
                          responseMessage.error = 'postMessage failed with error: ' + formatError(e) + '\n  with responseMessage: ' + JSON.stringify(responseMessage);
                          postMessage(responseMessage);
                      }
                  });
          };
      }
  
      /**
       * A function that performs a calculation in a Web Worker.
       * @callback createTaskProcessorWorker~WorkerFunction
       *
       * @param {Object} parameters Parameters to the calculation.
       * @param {Array} transferableObjects An array that should be filled with references to objects inside
       *        the result that should be transferred back to the main document instead of copied.
       * @returns {Object} The result of the calculation.
       *
       * @example
       * function calculate(parameters, transferableObjects) {
       *   // perform whatever calculation is necessary.
       *   var typedArray = new Float32Array(0);
       *
       *   // typed arrays are transferable
       *   transferableObjects.push(typedArray)
       *
       *   return {
       *      typedArray : typedArray
       *   };
       * }
       */
  
      /**
       * A Web Worker message event handler function that handles the interaction with TaskProcessor,
       * specifically, task ID management and posting a response message containing the result.
       * @callback createTaskProcessorWorker~TaskProcessorWorkerFunction
       *
       * @param {Object} event The onmessage event object.
       */
  
      return createTaskProcessorWorker;
  });
  
  define('Workers/decodeDraco',[
          '../Core/ComponentDatatype',
          '../Core/defined',
          '../Core/IndexDatatype',
          '../Core/RuntimeError',
          './createTaskProcessorWorker'
      ], function(
          ComponentDatatype,
          defined,
          IndexDatatype,
          RuntimeError,
          createTaskProcessorWorker) {
      'use strict';
  
      var draco;
  
      function decodeIndexArray(dracoGeometry, dracoDecoder) {
          var numPoints = dracoGeometry.num_points();
          var numFaces = dracoGeometry.num_faces();
          var faceIndices = new draco.DracoInt32Array();
          var numIndices = numFaces * 3;
          var indexArray = IndexDatatype.createTypedArray(numPoints, numIndices);
  
          var offset = 0;
          for (var i = 0; i < numFaces; ++i) {
              dracoDecoder.GetFaceFromMesh(dracoGeometry, i, faceIndices);
  
              indexArray[offset + 0] = faceIndices.GetValue(0);
              indexArray[offset + 1] = faceIndices.GetValue(1);
              indexArray[offset + 2] = faceIndices.GetValue(2);
              offset += 3;
          }
  
          draco.destroy(faceIndices);
  
          return {
              typedArray : indexArray,
              numberOfIndices : numIndices
          };
      }
  
      function decodeQuantizedDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, quantization, vertexArrayLength) {
          var vertexArray;
          var attributeData;
          if (quantization.quantizationBits <= 8) {
              attributeData = new draco.DracoUInt8Array();
              vertexArray = new Uint8Array(vertexArrayLength);
              dracoDecoder.GetAttributeUInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
          } else {
              attributeData = new draco.DracoUInt16Array();
              vertexArray = new Uint16Array(vertexArrayLength);
              dracoDecoder.GetAttributeUInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
          }
  
          for (var i = 0; i < vertexArrayLength; ++i) {
              vertexArray[i] = attributeData.GetValue(i);
          }
  
          draco.destroy(attributeData);
          return vertexArray;
      }
  
      function decodeDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, vertexArrayLength) {
          var vertexArray;
          var attributeData;
  
          // Some attribute types are casted down to 32 bit since Draco only returns 32 bit values
          switch (dracoAttribute.data_type()) {
              case 1: case 11: // DT_INT8 or DT_BOOL
                  attributeData = new draco.DracoInt8Array();
                  vertexArray = new Int8Array(vertexArrayLength);
                  dracoDecoder.GetAttributeInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
                  break;
              case 2: // DT_UINT8
                  attributeData = new draco.DracoUInt8Array();
                  vertexArray = new Uint8Array(vertexArrayLength);
                  dracoDecoder.GetAttributeUInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
                  break;
              case 3: // DT_INT16
                  attributeData = new draco.DracoInt16Array();
                  vertexArray = new Int16Array(vertexArrayLength);
                  dracoDecoder.GetAttributeInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
                  break;
              case 4: // DT_UINT16
                  attributeData = new draco.DracoUInt16Array();
                  vertexArray = new Uint16Array(vertexArrayLength);
                  dracoDecoder.GetAttributeUInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
                  break;
              case 5: case 7: // DT_INT32 or DT_INT64
                  attributeData = new draco.DracoInt32Array();
                  vertexArray = new Int32Array(vertexArrayLength);
                  dracoDecoder.GetAttributeInt32ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
                  break;
              case 6: case 8: // DT_UINT32 or DT_UINT64
                  attributeData = new draco.DracoUInt32Array();
                  vertexArray = new Uint32Array(vertexArrayLength);
                  dracoDecoder.GetAttributeUInt32ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
                  break;
              case 9: case 10: // DT_FLOAT32 or DT_FLOAT64
                  attributeData = new draco.DracoFloat32Array();
                  vertexArray = new Float32Array(vertexArrayLength);
                  dracoDecoder.GetAttributeFloatForAllPoints(dracoGeometry, dracoAttribute, attributeData);
                  break;
          }
  
          for (var i = 0; i < vertexArrayLength; ++i) {
              vertexArray[i] = attributeData.GetValue(i);
          }
  
          draco.destroy(attributeData);
          return vertexArray;
      }
  
      function decodeAttribute(dracoGeometry, dracoDecoder, dracoAttribute) {
          var numPoints = dracoGeometry.num_points();
          var numComponents = dracoAttribute.num_components();
  
          var quantization;
          var transform = new draco.AttributeQuantizationTransform();
          if (transform.InitFromAttribute(dracoAttribute)) {
              var minValues = new Array(numComponents);
              for (var i = 0; i < numComponents; ++i) {
                  minValues[i] = transform.min_value(i);
              }
              quantization = {
                  quantizationBits : transform.quantization_bits(),
                  minValues : minValues,
                  range : transform.range(),
                  octEncoded : false
              };
          }
          draco.destroy(transform);
  
          transform = new draco.AttributeOctahedronTransform();
          if (transform.InitFromAttribute(dracoAttribute)) {
              quantization = {
                  quantizationBits : transform.quantization_bits(),
                  octEncoded : true
              };
          }
          draco.destroy(transform);
  
          var vertexArrayLength = numPoints * numComponents;
          var vertexArray;
          if (defined(quantization)) {
              vertexArray = decodeQuantizedDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, quantization, vertexArrayLength);
          } else {
              vertexArray = decodeDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, vertexArrayLength);
          }
  
          var componentDatatype = ComponentDatatype.fromTypedArray(vertexArray);
  
          return {
              array : vertexArray,
              data : {
                  componentsPerAttribute : numComponents,
                  componentDatatype : componentDatatype,
                  byteOffset : dracoAttribute.byte_offset(),
                  byteStride : ComponentDatatype.getSizeInBytes(componentDatatype) * numComponents,
                  normalized : dracoAttribute.normalized(),
                  quantization : quantization
              }
          };
      }
  
      function decodePointCloud(parameters) {
          var dracoDecoder = new draco.Decoder();
  
          if (parameters.dequantizeInShader) {
              dracoDecoder.SkipAttributeTransform(draco.POSITION);
              dracoDecoder.SkipAttributeTransform(draco.NORMAL);
          }
  
          var buffer = new draco.DecoderBuffer();
          buffer.Init(parameters.buffer, parameters.buffer.length);
  
          var geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
          if (geometryType !== draco.POINT_CLOUD) {
              throw new RuntimeError('Draco geometry type must be POINT_CLOUD.');
          }
  
          var dracoPointCloud = new draco.PointCloud();
          var decodingStatus = dracoDecoder.DecodeBufferToPointCloud(buffer, dracoPointCloud);
          if (!decodingStatus.ok() || dracoPointCloud.ptr === 0) {
              throw new RuntimeError('Error decoding draco point cloud: ' + decodingStatus.error_msg());
          }
  
          draco.destroy(buffer);
  
          var result = {};
  
          var properties = parameters.properties;
          for (var propertyName in properties) {
              if (properties.hasOwnProperty(propertyName)) {
                  var attributeId = properties[propertyName];
                  var dracoAttribute = dracoDecoder.GetAttributeByUniqueId(dracoPointCloud, attributeId);
                  result[propertyName] = decodeAttribute(dracoPointCloud, dracoDecoder, dracoAttribute);
              }
          }
  
          draco.destroy(dracoPointCloud);
          draco.destroy(dracoDecoder);
  
          return result;
      }
  
      function decodePrimitive(parameters) {
          var dracoDecoder = new draco.Decoder();
  
          // Skip all parameter types except generic
          var attributesToSkip = ['POSITION', 'NORMAL', 'COLOR', 'TEX_COORD'];
          if (parameters.dequantizeInShader) {
              for (var i = 0; i < attributesToSkip.length; ++i) {
                  dracoDecoder.SkipAttributeTransform(draco[attributesToSkip[i]]);
              }
          }
  
          var bufferView = parameters.bufferView;
          var buffer = new draco.DecoderBuffer();
          buffer.Init(parameters.array, bufferView.byteLength);
  
          var geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
          if (geometryType !== draco.TRIANGULAR_MESH) {
              throw new RuntimeError('Unsupported draco mesh geometry type.');
          }
  
          var dracoGeometry = new draco.Mesh();
          var decodingStatus = dracoDecoder.DecodeBufferToMesh(buffer, dracoGeometry);
          if (!decodingStatus.ok() || dracoGeometry.ptr === 0) {
              throw new RuntimeError('Error decoding draco mesh geometry: ' + decodingStatus.error_msg());
          }
  
          draco.destroy(buffer);
  
          var attributeData = {};
  
          var compressedAttributes = parameters.compressedAttributes;
          for (var attributeName in compressedAttributes) {
              if (compressedAttributes.hasOwnProperty(attributeName)) {
                  var compressedAttribute = compressedAttributes[attributeName];
                  var dracoAttribute = dracoDecoder.GetAttributeByUniqueId(dracoGeometry, compressedAttribute);
                  attributeData[attributeName] = decodeAttribute(dracoGeometry, dracoDecoder, dracoAttribute);
              }
          }
  
          var result = {
              indexArray : decodeIndexArray(dracoGeometry, dracoDecoder),
              attributeData : attributeData
          };
  
          draco.destroy(dracoGeometry);
          draco.destroy(dracoDecoder);
  
          return result;
      }
  
      function decode(parameters) {
          if (defined(parameters.primitive)) {
              return decodePrimitive(parameters);
          }
          return decodePointCloud(parameters);
      }
  
      function initWorker(dracoModule) {
          draco = dracoModule;
          self.onmessage = createTaskProcessorWorker(decode);
          self.postMessage(true);
      }
  
      function decodeDraco(event) {
          var data = event.data;
  
          // Expect the first message to be to load a web assembly module
          var wasmConfig = data.webAssemblyConfig;
          if (defined(wasmConfig)) {
              // Require and compile WebAssembly module, or use fallback if not supported
              return require([wasmConfig.modulePath], function(dracoModule) {
                  if (defined(wasmConfig.wasmBinaryFile)) {
                      if (!defined(dracoModule)) {
                          dracoModule = self.DracoDecoderModule;
                      }
  
                      dracoModule(wasmConfig).then(function (compiledModule) {
                          initWorker(compiledModule);
                      });
                  } else {
                      initWorker(dracoModule());
                  }
              });
          }
      }
  
      return decodeDraco;
  });
  
  }());