docs: function(original, delta, atPath) {
      var pathStack = (atPath=="/")? "" : atPath;
      var modifications = {};
      
      var oType = this.objectType(original);
      var dType = this.objectType(delta);
      var oIsSimple = (oType != "object" && oType != "array");
      var dIsSimple = (dType != "object" && dType != "array");
      
      // Escale
      if(this.eq(original, delta)) {
        // Items are equivalent
        return modifications;
      } 
      else if(oIsSimple && dIsSimple) {
        // Compare simple -> simple
        var m = this.modificationSymbol(delta, original);
        if(m) modifications[atPath] = [m, original, delta];
      }
      
      
      if(!dIsSimple) {
        // New value is complex - we'll run all subkeys against the keys on the original, if they exist
        for(var dK in delta) {
          // For each key, get modifications for this tree level and merge.
          var dMods = this.compare(((oIsSimple)? undefined : original[dK]), delta[dK], pathStack+"/"+dK);
          for(mK in dMods) {
            modifications[mK] = dMods[mK];
          }
        }
      }
      
      if(!oIsSimple) {
        // Original value is complex - we'll run all subkeys against keys on the delta, if they exist
        // All keys in complex are nullified recursively
        for(var oK in original) {
          var oMods = this.compare(original[oK], ((dIsSimple)? undefined : delta[oK]), pathStack+"/"+oK);
          for(var mK in oMods) {
            modifications[mK] = oMods[mK];
          }
        }
      }
      
      // Register working path as modified if we got this far and didn't register anything for the mod path.
      if(!modifications[atPath]) {
        var mSym = this.modificationSymbol(delta, original);
        if(mSym) modifications[atPath] = [mSym, original, delta];
      }
  
      return modifications;
    }