text:   /**
     * Contains all Parse API classes and functions.
     * @name Parse
     * @namespace
     *
     * Contains all Parse API classes and functions.
     */
  
  var Parse = require('./Parse').Parse;
  
    // Helpers
    // -------
  
    // Shared empty constructor function to aid in prototype-chain creation.
    var EmptyConstructor = function() {};
  
    
    // Helper function to correctly set up the prototype chain, for subclasses.
    // Similar to `goog.inherits`, but uses a hash of prototype properties and
    // class properties to be extended.
    var inherits = function(parent, protoProps, staticProps) {
      var child;
  
      // The constructor function for the new subclass is either defined by you
      // (the "constructor" property in your `extend` definition), or defaulted
      // by us to simply call the parent's constructor.
      if (protoProps && protoProps.hasOwnProperty('constructor')) {
        child = protoProps.constructor;
      } else {
        /** @ignore */
        child = function(){ parent.apply(this, arguments); };
      }
  
      // Inherit class (static) properties from parent.
      Parse._.extend(child, parent);
  
      // Set the prototype chain to inherit from `parent`, without calling
      // `parent`'s constructor function.
      EmptyConstructor.prototype = parent.prototype;
      child.prototype = new EmptyConstructor();
  
      // Add prototype properties (instance properties) to the subclass,
      // if supplied.
      if (protoProps) {
        Parse._.extend(child.prototype, protoProps);
      }
  
      // Add static properties to the constructor function, if supplied.
      if (staticProps) {
        Parse._.extend(child, staticProps);
      }
  
      // Correctly set child's `prototype.constructor`.
      child.prototype.constructor = child;
  
      // Set a convenience property in case the parent's prototype is
      // needed later.
      child.__super__ = parent.prototype;
  
      return child;
    };
  
    // Set the server for Parse to talk to.
    Parse.serverURL = "https://api.parse.com";
  
    // Check whether we are running in Node.js.
    if (typeof(process) !== "undefined" &&
        process.versions &&
        process.versions.node) {
      Parse._isNode = true;
    }
  
    /**
     * Call this method first to set up your authentication tokens for Parse.
     * You can get your keys from the Data Browser on parse.com.
     * @param {String} applicationId Your Parse Application ID.
     * @param {String} javaScriptKey Your Parse JavaScript Key.
     * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!)
     */
    Parse.initialize = function(applicationId, javaScriptKey, masterKey) {
      if (masterKey) {
        throw "Parse.initialize() was passed a Master Key, which is only " +
          "allowed from within Node.js.";
      }
      Parse._initialize(applicationId, javaScriptKey);
    };
  
    /**
     * Call this method first to set up master authentication tokens for Parse.
     * This method is for Parse's own private use.
     * @param {String} applicationId Your Parse Application ID.
     * @param {String} javaScriptKey Your Parse JavaScript Key.
     * @param {String} masterKey Your Parse Master Key.
     */
    Parse._initialize = function(applicationId, javaScriptKey, masterKey) {
      Parse.applicationId = applicationId;
      Parse.javaScriptKey = javaScriptKey;
      Parse.masterKey = masterKey;
      Parse._useMasterKey = false;
    };
  
    // If we're running in node.js, allow using the master key.
    if (Parse._isNode) {
      Parse.initialize = Parse._initialize;
  
      Parse.Cloud = Parse.Cloud || {};
      /**
       * Switches the Parse SDK to using the Master key.  The Master key grants
       * priveleged access to the data in Parse and can be used to bypass ACLs and
       * other restrictions that are applied to the client SDKs.
       * <p><strong><em>Available in Cloud Code and Node.js only.</em></strong>
       * </p>
       */
      Parse.Cloud.useMasterKey = function() {
        Parse._useMasterKey = true;
      };
    }
  
    /**
     * Returns prefix for localStorage keys used by this instance of Parse.
     * @param {String} path The relative suffix to append to it.
     *     null or undefined is treated as the empty string.
     * @return {String} The full key name.
     */
    Parse._getParsePath = function(path) {
      if (!Parse.applicationId) {
        throw "You need to call Parse.initialize before using Parse.";
      }
      if (!path) {
        path = "";
      }
      if (!Parse._.isString(path)) {
        throw "Tried to get a localStorage path that wasn't a String.";
      }
      if (path[0] === "/") {
        path = path.substring(1);
      }
      return "Parse/" + Parse.applicationId + "/" + path;
    };
  
    /**
     * Returns the unique string for this app on this machine.
     * Gets reset when localStorage is cleared.
     */
    Parse._installationId = null;
    Parse._getInstallationId = function() {
      // See if it's cached in RAM.
      if (Parse._installationId) {
        return Parse._installationId;
      }
  
      // Try to get it from localStorage.
      var path = Parse._getParsePath("installationId");
      Parse._installationId = Parse.localStorage.getItem(path);
  
      if (!Parse._installationId || Parse._installationId === "") {
        // It wasn't in localStorage, so create a new one.
        var hexOctet = function() {
          return Math.floor((1+Math.random())*0x10000).toString(16).substring(1);
        };
        Parse._installationId = (
          hexOctet() + hexOctet() + "-" +
          hexOctet() + "-" +
          hexOctet() + "-" +
          hexOctet() + "-" +
          hexOctet() + hexOctet() + hexOctet());
        Parse.localStorage.setItem(path, Parse._installationId);
      }
  
      return Parse._installationId;
    };
  
    Parse._parseDate = function(iso8601) {
      var regexp = new RegExp(
        "^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})" + "T" +
        "([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})" +
        "(.([0-9]+))?" + "Z$");
      var match = regexp.exec(iso8601);
      if (!match) {
        return null;
      }
  
      var year = match[1] || 0;
      var month = (match[2] || 1) - 1;
      var day = match[3] || 0;
      var hour = match[4] || 0;
      var minute = match[5] || 0;
      var second = match[6] || 0;
      var milli = match[8] || 0;
  
      return new Date(Date.UTC(year, month, day, hour, minute, second, milli));
    };
  
    Parse._ajaxIE8 = function(method, url, data) {
      var promise = new Parse.Promise();
      var xdr = new XDomainRequest();
      xdr.onload = function() {
        var response;
        try {
          response = JSON.parse(xdr.responseText);
        } catch (e) {
          promise.reject(e);
        }
        if (response) {
          promise.resolve(response);
        }
      };
      xdr.onerror = xdr.ontimeout = function() {
        // Let's fake a real error message.
        var fakeResponse = {
          responseText: JSON.stringify({
            code: Parse.Error.X_DOMAIN_REQUEST,
            error: "IE's XDomainRequest does not supply error info."
          })
        };
        promise.reject(fakeResponse);
      };
      xdr.onprogress = function() {};
      xdr.open(method, url);
      xdr.send(data);
      return promise;
    };
  
    Parse._useXDomainRequest = function() {
      if (typeof(XDomainRequest) !== "undefined") {
        // We're in IE 8+.
        if ('withCredentials' in new XMLHttpRequest()) {
          // We're in IE 10+.
          return false;
        }
        return true;
      }
      return false;
    };
  
    
    Parse._ajax = function(method, url, data, success, error) {
      var options = {
        success: success,
        error: error
      };
  
      if (Parse._useXDomainRequest()) {
        return Parse._ajaxIE8(method, url, data)._thenRunCallbacks(options);
      }
  
      var promise = new Parse.Promise();
      var handled = false;
  
      var xhr = new Parse.XMLHttpRequest();
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          if (handled) {
            return;
          }
          handled = true;
  
          if (xhr.status >= 200 && xhr.status < 300) {
            var response;
            try {
              response = JSON.parse(xhr.responseText);
            } catch (e) {
              promise.reject(e);
            }
            if (response) {
              promise.resolve(response, xhr.status, xhr);
            }
          } else {
            promise.reject(xhr);
          }
        }
      };
      xhr.open(method, url, true);
      xhr.setRequestHeader("Content-Type", "text/plain");  // avoid pre-flight.
      if (Parse._isNode) {
        // Add a special user agent just for request from node.js.
        xhr.setRequestHeader("User-Agent",
                             "Parse/" + Parse.VERSION +
                             " (NodeJS " + process.versions.node + ")");
      }
      xhr.send(data);
      return promise._thenRunCallbacks(options);
    };
  
    // A self-propagating extend function.
    Parse._extend = function(protoProps, classProps) {
      var child = inherits(this, protoProps, classProps);
      child.extend = this.extend;
      return child;
    };
  
    /**
     * Options:
     *   route: is classes, users, login, etc.
     *   objectId: null if there is no associated objectId.
     *   method: the http method for the REST API.
     *   dataObject: the payload as an object, or null if there is none.
     *   useMasterKey: overrides whether to use the master key if set.
     * @ignore
     */
    Parse._request = function(options) {
      var route = options.route;
      var className = options.className;
      var objectId = options.objectId;
      var method = options.method;
      var useMasterKey = options.useMasterKey;
      var sessionToken = options.sessionToken;
      var dataObject = options.data;
  
      if (!Parse.applicationId) {
        throw "You must specify your applicationId using Parse.initialize.";
      }
  
      if (!Parse.javaScriptKey && !Parse.masterKey) {
        throw "You must specify a key using Parse.initialize.";
      }
  
      
      if (!sessionToken) {
        // Use the current user session token if none was provided.
        var currentUser = Parse.User.current();
        if (currentUser && currentUser._sessionToken) {
          sessionToken = currentUser._sessionToken;
        }
      }
  
      
      if (route !== "batch" &&
          route !== "classes" &&
          route !== "events" &&
          route !== "files" &&
          route !== "functions" &&
          route !== "login" &&
          route !== "push" &&
          route !== "requestPasswordReset" &&
          route !== "rest_verify_analytics" &&
          route !== "users" &&
          route !== "jobs") {
        throw "Bad route: '" + route + "'.";
      }
  
      var url = Parse.serverURL;
      if (url.charAt(url.length - 1) !== "/") {
        url += "/";
      }
      url += "1/" + route;
      if (className) {
        url += "/" + className;
      }
      if (objectId) {
        url += "/" + objectId;
      }
  
      dataObject = Parse._.clone(dataObject || {});
      if (method !== "POST") {
        dataObject._method = method;
        method = "POST";
      }
  
      if (Parse._.isUndefined(useMasterKey)) {
        useMasterKey = Parse._useMasterKey;
      }
  
      dataObject._ApplicationId = Parse.applicationId;
      if (!useMasterKey) {
        dataObject._JavaScriptKey = Parse.javaScriptKey;
      } else {
        dataObject._MasterKey = Parse.masterKey;
      }
  
      dataObject._ClientVersion = Parse.VERSION;
      dataObject._InstallationId = Parse._getInstallationId();
      if (sessionToken) {
        dataObject._SessionToken = sessionToken;
      }
      var data = JSON.stringify(dataObject);
  
      return Parse._ajax(method, url, data).then(null, function(response) {
        // Transform the error into an instance of Parse.Error by trying to parse
        // the error string as JSON.
        var error;
        if (response && response.responseText) {
          try {
            var errorJSON = JSON.parse(response.responseText);
            error = new Parse.Error(errorJSON.code, errorJSON.error);
          } catch (e) {
            // If we fail to parse the error text, that's okay.
            error = new Parse.Error(
                Parse.Error.INVALID_JSON,
                "Received an error with invalid JSON from Parse: " +
                    response.responseText);
          }
        } else {
          error = new Parse.Error(
              Parse.Error.CONNECTION_FAILED,
              "XMLHttpRequest failed: " + JSON.stringify(response));
        }
        // By explicitly returning a rejected Promise, this will work with
        // either jQuery or Promises/A semantics.
        return Parse.Promise.error(error);
      });
    };
  
    // Helper function to get a value from a Backbone object as a property
    // or as a function.
    Parse._getValue = function(object, prop) {
      if (!(object && object[prop])) {
        return null;
      }
      return Parse._.isFunction(object[prop]) ? object[prop]() : object[prop];
    };
  
    /**
     * Converts a value in a Parse Object into the appropriate representation.
     * This is the JS equivalent of Java's Parse.maybeReferenceAndEncode(Object)
     * if seenObjects is falsey. Otherwise any Parse.Objects not in
     * seenObjects will be fully embedded rather than encoded
     * as a pointer.  This array will be used to prevent going into an infinite
     * loop because we have circular references.  If seenObjects
     * is set, then none of the Parse Objects that are serialized can be dirty.
     */
    Parse._encode = function(value, seenObjects, disallowObjects) {
      var _ = Parse._;
      if (value instanceof Parse.Object) {
        if (disallowObjects) {
          throw "Parse.Objects not allowed here";
        }
        if (!seenObjects || _.include(seenObjects, value) || !value._hasData) {
          return value._toPointer();
        }
        if (!value.dirty()) {
          seenObjects = seenObjects.concat(value);
          return Parse._encode(value._toFullJSON(seenObjects),
                               seenObjects,
                               disallowObjects);
        }
        throw "Tried to save an object with a pointer to a new, unsaved object.";
      }
      if (value instanceof Parse.ACL) {
        return value.toJSON();
      }
      if (_.isDate(value)) {
        return { "__type": "Date", "iso": value.toJSON() };
      }
      if (value instanceof Parse.GeoPoint) {
        return value.toJSON();
      }
      if (_.isArray(value)) {
        return _.map(value, function(x) {
          return Parse._encode(x, seenObjects, disallowObjects);
        });
      }
      if (_.isRegExp(value)) {
        return value.source;
      }
      if (value instanceof Parse.Relation) {
        return value.toJSON();
      }
      if (value instanceof Parse.Op) {
        return value.toJSON();
      }
      if (value instanceof Parse.File) {
        if (!value.url()) {
          throw "Tried to save an object containing an unsaved file.";
        }
        return {
          __type: "File",
          name: value.name(),
          url: value.url()
        };
      }
      if (_.isObject(value)) {
        var output = {};
        Parse._objectEach(value, function(v, k) {
          output[k] = Parse._encode(v, seenObjects, disallowObjects);
        });
        return output;
      }
      return value;
    };
  
    /**
     * The inverse function of Parse._encode.
     * TODO: make decode not mutate value.
     */
    Parse._decode = function(key, value) {
      var _ = Parse._;
      if (!_.isObject(value)) {
        return value;
      }
      if (_.isArray(value)) {
        Parse._arrayEach(value, function(v, k) {
          value[k] = Parse._decode(k, v);
        });
        return value;
      }
      if (value instanceof Parse.Object) {
        return value;
      }
      if (value instanceof Parse.File) {
        return value;
      }
      if (value instanceof Parse.Op) {
        return value;
      }
      if (value.__op) {
        return Parse.Op._decode(value);
      }
      if (value.__type === "Pointer") {
        var pointer = Parse.Object._create(value.className);
        pointer._finishFetch({ objectId: value.objectId }, false);
        return pointer;
      }
      if (value.__type === "Object") {
        // It's an Object included in a query result.
        var className = value.className;
        delete value.__type;
        delete value.className;
        var object = Parse.Object._create(className);
        object._finishFetch(value, true);
        return object;
      }
      if (value.__type === "Date") {
        return Parse._parseDate(value.iso);
      }
      if (value.__type === "GeoPoint") {
        return new Parse.GeoPoint({
          latitude: value.latitude,
          longitude: value.longitude
        });
      }
      if (key === "ACL") {
        if (value instanceof Parse.ACL) {
          return value;
        }
        return new Parse.ACL(value);
      }
      if (value.__type === "Relation") {
        var relation = new Parse.Relation(null, key);
        relation.targetClassName = value.className;
        return relation;
      }
      if (value.__type === "File") {
        var file = new Parse.File(value.name);
        file._url = value.url;
        return file;
      }
      Parse._objectEach(value, function(v, k) {
        value[k] = Parse._decode(k, v);
      });
      return value;
    };
  
    Parse._arrayEach = Parse._.each;
  
    /**
     * Does a deep traversal of every item in object, calling func on every one.
     * @param {Object} object The object or array to traverse deeply.
     * @param {Function} func The function to call for every item. It will
     *     be passed the item as an argument. If it returns a truthy value, that
     *     value will replace the item in its parent container.
     * @returns {} the result of calling func on the top-level object itself.
     */
    Parse._traverse = function(object, func, seen) {
      if (object instanceof Parse.Object) {
        seen = seen || [];
        if (Parse._.indexOf(seen, object) >= 0) {
          // We've already visited this object in this call.
          return;
        }
        seen.push(object);
        Parse._traverse(object.attributes, func, seen);
        return func(object);
      }
      if (object instanceof Parse.Relation || object instanceof Parse.File) {
        // Nothing needs to be done, but we don't want to recurse into the
        // object's parent infinitely, so we catch this case.
        return func(object);
      }
      if (Parse._.isArray(object)) {
        Parse._.each(object, function(child, index) {
          var newChild = Parse._traverse(child, func, seen);
          if (newChild) {
            object[index] = newChild;
          }
        });
        return func(object);
      }
      if (Parse._.isObject(object)) {
        Parse._each(object, function(child, key) {
          var newChild = Parse._traverse(child, func, seen);
          if (newChild) {
            object[key] = newChild;
          }
        });
        return func(object);
      }
      return func(object);
    };
  
    /**
     * This is like _.each, except:
     * * it doesn't work for so-called array-like objects,
     * * it does work for dictionaries with a "length" attribute.
     */
    Parse._objectEach = Parse._each = function(obj, callback) {
      var _ = Parse._;
      if (_.isObject(obj)) {
        _.each(_.keys(obj), function(key) {
          callback(obj[key], key);
        });
      } else {
        _.each(obj, callback);
      }
    };
  
    // Helper function to check null or undefined.
    Parse._isNullOrUndefined = function(x) {
      return Parse._.isNull(x) || Parse._.isUndefined(x);
    };
  