Backbone.sync = function(method, model, options) {

  // we need to make sure we initialize a store, in this case
  // we will just use a JS object.
  var cache = {};
  
  // The size will be primarily used to assign ids to newly 
  // created models. Each time a new model is created, the size 
  // will be incremented.
  var size  = 0;

  // since we need to create a store for the models/collections
  // we are actually going to invoke the outer function which will
  // return this function below as the Backbone.sync that will
  // actually be used.
  return function(method, model, options) {

    // create a new deferred object. standard sync returns the $.ajax
    // request, which internally returns a deferred. It's important to
    // do this so that people can chain on fetch using the standard .then/.fail
    // syntax, rather than just the success/error callbacks.
    var deferred = $.Deferred();
    
    // when creating a new model...
    if (method === "create") {

      // first assign it an id. The server would traditionally do this.
      model.id = size;
      // store it in our cache
      cache[model.id] = model;
      // make sure we increment the number of models we now have.
      size += 1;

      // if a success callback was provided, execute it.
      if (options.success) {
        options.success(model, model.toJSON(), options);
      }

      // resolve the deferred.
      deferred.resolve(model);

    // we are updating a model
    } else if (method === "update") {
      
      // as long as the model actually exists in our store
      if (cache[model.id]) {
        
        // overwrite what is currently in the store with this model.
        cache[model.id] = model;

        // if a success callback was provided, execute it.
        if (options.success) {
          options.success(model, model.toJSON(), options);
        }

        deferred.resolve(model);
      
      // if this model doesn't exist yet, we can't update it
      } else {
        
        if (options.error) {
          options.error(model, "Model not found");
        }
        deferred.reject(model);
      }

    // if we're trying to read a model...
    } else if (method === "read") {
      
      // as long as it exists
      if (cache[model.id]) {
        
        // if a success callback was provided, execute it.
        if (options.success) {
          options.success(model, cache[model.id].toJSON(), options);
        }
        
        // resolve 
        deferred.resolve(model);
      } else {
        if (options.error) {
          options.error(model, "Model not found");
        }
        deferred.reject(model);
      }
      
    // if we're deleting a model...
    } else if (method === "delete") {
      
      // first make sure it exists in the cache
      if (cache[model.id]) {
        
        // then remove it from the cache
        delete cache[model.id];
        
        // and trigger the success callback. Note we're passing an 
        // empty object as the second argument, because a deletion 
        // would result in an empty return from the server.
        if (options.success) {
          options.success(model, {}, options);
        }
        
        // resolve the deferred
        deferred.resolve(model);
        
      // otherwise, error that the model doesn't exist.
      } else {
        if (options.error) {
          options.error(model, "Model not found");
        }
        deferred.reject(model);
      }
    }

    return deferred.promise();  
  }
  
}();