text:
// Copyright 2012 YDN Authors. All Rights Reserved.
//
// 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.

/**
 * @fileoverview IndexedDB request executor.
 *
 * @author kyawtun@yathit.com (Kyaw Tun)
 */

goog.provide('ydn.db.crud.req.IndexedDb');
goog.require('goog.async.DeferredList');
goog.require('goog.userAgent');
goog.require('ydn.db.crud.req.IRequestExecutor');
goog.require('ydn.db.crud.req.RequestExecutor');
goog.require('ydn.debug.error.InvalidOperationException');
goog.require('ydn.error');
goog.require('ydn.json');

/**
 * Create a new IDB request executor.
 * @param {string} dbname database name.
 * @param {!ydn.db.schema.Database} schema schema.
 * @constructor
 * @extends {ydn.db.crud.req.RequestExecutor}
 * @implements {ydn.db.crud.req.IRequestExecutor}
 * @struct
 */
ydn.db.crud.req.IndexedDb = function(dbname, schema) {
  goog.base(this, dbname, schema);
};
goog.inherits(ydn.db.crud.req.IndexedDb, ydn.db.crud.req.RequestExecutor);

/**
 * @protected
 * @type {goog.debug.Logger} logger.
 */
ydn.db.crud.req.IndexedDb.prototype.logger =
    goog.log.getLogger('ydn.db.crud.req.IndexedDb');

/**
 *
 * @const {boolean} turn on debug flag to dump debug objects.
 */
ydn.db.crud.req.IndexedDb.DEBUG = false; // always false here.

/**
 * Large number of requests can cause memory hog without increasing performance.
 * @const
 * @type {number} Maximum number of requests created per transaction.
 */
ydn.db.crud.req.IndexedDb.REQ_PER_TX = 10;

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.countStores = function(req, stores) {

  var me = this;
  var out = [];

  var count_store = function(i) {
    var table = stores[i];
    var store = req.getTx().objectStore(table);
    var request = store.count();
    request.onsuccess = function(event) {
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log(event);
      }
      out[i] = event.target.result;
      i++;
      if (i == stores.length) {
        req.setDbValue(out);
      } else {
        count_store(i);
      }

    };
    request.onerror = function(event) {
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log(event);
      }
      event.preventDefault();
      req.setDbValue(request.error, true);
    };
  };

  if (stores.length == 0) {
    req.setDbValue([]);
  } else {
    count_store(0);
  }

};

/**
 * Put objects and return list of key inserted.
 * @param {ydn.db.Request} rq request.
 * @param {boolean} is_replace true if `put`, otherwise `add`.
 * @param {boolean} is_single true if result take only the first result.
 * @param {string} store_name store name.
 * @param {!Array.<!Object>} objs object to put.
 * @param {!Array.<IDBKey>=} opt_keys optional out-of-line keys.
 */
ydn.db.crud.req.IndexedDb.prototype.insertObjects = function(rq, is_replace,
    is_single, store_name, objs, opt_keys) {

  var results = [];
  var result_count = 0;
  var has_error = false;

  var me = this;
  var mth = is_replace ? 'put' : 'add';
  var ob_store = rq.getTx().objectStore(store_name);
  var msg = rq.getLabel() + ' ' + mth + ' ' + objs.length + ' objects' +
      ' to store "' + store_name + '"';
  goog.log.finest(this.logger, msg);

  var put = function(i) {

    if (!goog.isDefAndNotNull(objs[i])) {
      goog.log.finest(me.logger, 'empty object at ' + i + ' of ' + objs.length);
      result_count++;
      if (result_count == objs.length) {
        rq.setDbValue(results, has_error);
      } else {
        var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX;
        if (next < objs.length) {
          put(next);
        }
      }
    }

    var request;

    var obj = objs[i];
    // window.console.log(obj);
    if (opt_keys && goog.isDefAndNotNull(opt_keys[i])) {
      if (is_replace) {
        request = ob_store.put(obj, opt_keys[i]);
      } else {
        request = ob_store.add(obj, opt_keys[i]);
      }
    } else {
      if (is_replace) {
        request = ob_store.put(obj);
      } else {
        request = ob_store.add(obj);
      }
    }

    request.onsuccess = function(event) {
      result_count++;
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([store_name, event, i]);
      }
      results[i] = event.target.result;
      if (result_count == objs.length) {
        rq.setDbValue(is_single ? results[0] : results, has_error);
      } else {
        var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX;
        if (next < objs.length) {
          put(next);
        }
      }
    };

    request.onerror = function(event) {
      result_count++;
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([store_name, event, i]);
      }
      var error = request.error;
      goog.log.finest(me.logger, rq.getLabel() + mth + ' request to "' + store_name +
          '" cause ' + error.name + ' for object "' +
          ydn.json.toShortString(objs[i]) + '" at index ' +
          i + ' of ' + objs.length + ' objects.');
      // accessing request.error can cause InvalidStateError,
      // although it is not possible here since request has already done flag.
      // http://www.w3.org/TR/IndexedDB/#widl-IDBRequest-error
      results[i] = error;
      has_error = true;
      event.preventDefault(); // not abort the transaction.
      if (result_count == objs.length) {
        rq.setDbValue(is_single ? results[0] : results, has_error);
      } else {
        var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX;
        if (next < objs.length) {
          put(next);
        }
      }
    };

  };

  if (objs.length > 0) {
    // send parallel requests
    for (var i = 0; i < ydn.db.crud.req.IndexedDb.REQ_PER_TX &&
        i < objs.length; i++) {
      put(i);
    }
  } else {
    rq.setDbValue([]);
  }
};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.putByKeys = function(rq, objs,
                                                         keys) {

  var results = [];
  var result_count = 0;
  var has_error = false;

  var out = function() {
    rq.setDbValue(results, has_error);
  };

  var me = this;

  var msg = rq.getLabel() + ' putByKeys: of ' + objs.length + ' objects';
  goog.log.finest(this.logger, msg);

  var put = function(i) {
    /**
     * @type {!ydn.db.Key}
     */
    var key = keys[i];
    var store_name = key.getStoreName();
    var store = rq.getTx().objectStore(store_name);

    var request;

    if (goog.isNull(store.keyPath)) {
      request = store.put(objs[i], key.getId());
    } else {
      request = store.put(objs[i]);
    }

    request.onsuccess = function(event) {
      result_count++;
      //if (ydn.db.crud.req.IndexedDb.DEBUG) {
      //  goog.global.console.log([store_name, event]);
      //}
      results[i] = event.target.result;
      if (result_count == objs.length) {
        out();
      } else {
        var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX;
        if (next < objs.length) {
          put(next);
        }
      }
    };

    request.onerror = function(event) {
      result_count++;
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([store_name, event]);
      }
      var name = event.name;
      if (goog.DEBUG) {
        goog.log.warning(me.logger, 'request result ' + name +
            ' error when put keys to "' + store_name + '" for object "' +
            ydn.json.toShortString(objs[i]) + '" at index ' +
            i + ' of ' + objs.length + ' objects.');
      }
      results[i] = request.error;
      has_error = true;
      event.preventDefault();
      if (result_count == objs.length) {
        out();
      } else {
        var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX;
        if (next < objs.length) {
          put(next);
        }
      }
    };

  };

  if (objs.length > 0) {
    // send parallel requests
    for (var i = 0; i < ydn.db.crud.req.IndexedDb.REQ_PER_TX &&
        i < objs.length; i++) {
      put(i);
    }
  } else {
    out();
  }
};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.putData = function(tx, tx_no, df,
    store_name, data, delimiter) {
  var me = this;
  var store = this.schema.getStore(store_name);
  var objectStore = tx.objectStore(store_name);
  var results = [];
  var prev_pos = data.indexOf('\n');
  var fields = data.substr(0, prev_pos).split(delimiter);
  var types = [];
  for (var j = 0; j < fields.length; j++) {
    var index = store.getIndex(fields[j]);
    if (index) {
      types[j] = index.getType();
    } else if (fields[j] == store.getKeyPath()) {
      types[j] = store.getType();
    }
  }
  prev_pos++;

  var msg = tx_no + ' Loading data ' + ' of ' + fields.length +
      '-fields record to ' + store_name;
  goog.log.finest(this.logger, msg);

  var put = function() {

    var obj = {};
    var next_pos = data.indexOf('\n', prev_pos);
    var done = false;
    var text;
    if (next_pos == -1) {
      done = true;
      text = data.substring(prev_pos);
    } else {
      text = data.substring(prev_pos, next_pos);
      prev_pos = next_pos + 1;
    }

    var values = text.split(delimiter);
    for (var j = 0; j < fields.length; j++) {
      var value = values[j];
      if (types[j]) {
        if (types[j] == ydn.db.schema.DataType.TEXT) {
          value = goog.string.stripQuotes(value, '"');
        } else if (types[j] == ydn.db.schema.DataType.INTEGER) {
          value = parseInt(value, 10);
        } else if (types[j] == ydn.db.schema.DataType.NUMERIC) {
          value = parseFloat(value);
        }
      }
      obj[fields[j]] = value;
    }

    //console.log([text, obj]);

    var request = objectStore.put(obj);

    request.onsuccess = function(event) {

      //if (ydn.db.crud.req.IndexedDb.DEBUG) {
      //  goog.global.console.log([store_name, event]);
      //}
      results.push(event.target.result);
      if (done) {
        df(results);
      } else {
        put();
      }
    };

    request.onerror = function(event) {

      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([store_name, event]);
      }
      if (goog.DEBUG && event.name == 'DataError') {
        // give useful info.
        event = new ydn.db.InvalidKeyException(store + ': ' +
            text.substring(0, 70));
      }
      event.preventDefault();
      df(request.error, true);
      // abort transaction ?
    };

  };

  put();
};

/**
* @inheritDoc
*/
ydn.db.crud.req.IndexedDb.prototype.removeById = function(req,
                                                          store_name, key) {

  var me = this;
  var store = req.getTx().objectStore(store_name);
  var msg = req.getLabel() + ' clearById: ' + store_name + ' ' + key;
  goog.log.finest(this.logger, msg);

  var request = store.openCursor(ydn.db.IDBKeyRange.only(key));
  request.onsuccess = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log([store_name, key, event]);
    }
    var cursor = event.target.result;
    if (cursor) {
      var r = cursor['delete']();
      r.onsuccess = function(e) {
        req.setDbValue(1);
      };
      r.onerror = function(e) {
        req.setDbValue(r.error, true);
      };
    } else {
      req.setDbValue(0);
    }
  };
  request.onerror = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log([store_name, key, event]);
    }
    event.preventDefault();
    req.setDbValue(request.error, true);
  };

};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.removeByKeys = function(req, keys) {

  var me = this;
  var count = 0;
  var store_name, store, key;
  var msg = req.getLabel() + ' removeByKeys: ' + keys.length + ' keys';
  goog.log.finest(this.logger, msg);
  var errors = [];

  var removeAt = function(i) {
    i++;
    if (i >= keys.length) {
      var has_failed = errors.length > 0;
      if (has_failed) {
        req.setDbValue(errors, true);
      } else {
        req.setDbValue(count);
      }
      return;
    }

    if (keys[i].getStoreName() != store_name) {
      store_name = keys[i].getStoreName();
      store = req.getTx().objectStore(store_name);
    }

    var request = store.openCursor(IDBKeyRange.only(keys[i].getId()));
    request.onsuccess = function(event) {
      var cursor = event.target.result;
      if (cursor) {
        var r = cursor['delete']();
        r.onsuccess = function(e) {
          count++;
          removeAt(i);
        };
        r.onerror = function(event) {
          event.preventDefault();
          errors[i] = r.error;
          removeAt(i);
        };
      } else {
        removeAt(i);
      }
    };
    request.onerror = function(event) {
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([store_name, key, event]);
      }
      event.preventDefault();
      req.setDbValue(request.error, true);
    };

  };

  removeAt(-1);

};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.removeByKeyRange = function(
    req, store_name, key_range) {

  var me = this;
  var store = req.getTx().objectStore(store_name);
  var request = store.count(key_range);
  var msg = req.getLabel() + ' clearByKeyRange: ' + store_name + ' ' +
      key_range;
  goog.log.finest(this.logger, msg);
  request.onsuccess = function(event) {
    var n = event.target.result;
    var r = store['delete'](key_range);
    r.onsuccess = function() {
      req.setDbValue(n);
    };
    r.onerror = function(e) {
      req.setDbValue(r.error, true);
    };
  };
  request.onerror = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log([store_name, key_range, event]);
    }
    event.preventDefault();
    req.setDbValue(request.error, true);
  };

};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.clearByKeyRange = function(
    req, store_name, key_range) {

  var me = this;
  var store = req.getTx().objectStore(store_name);

  var msg = req.getLabel() + ' ' + store_name + ' ' + key_range;
  goog.log.finest(this.logger, msg);

  var r = store['delete'](key_range);
  r.onsuccess = function(event) {
    req.setDbValue(undefined);
  };
  r.onerror = function(event) {
    event.preventDefault();
    req.setDbValue(r.error, true);
  };

};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.removeByIndexKeyRange = function(
    req, store_name, index_name, key_range) {

  var me = this;
  var store = req.getTx().objectStore(store_name);
  var index = store.index(index_name);
  var msg = req.getLabel() + ' clearByIndexKeyRange: ' + store_name + ':' +
      index_name + ' ' + key_range;
  goog.log.finest(this.logger, msg);
  var errors = [];
  // var request = index.openKeyCursor(key_range);
  // theoritically key cursor should be able to delete the record, but
  // according to IndexedDB API spec, it is not.
  // if this cursor was created using openKeyCursor a DOMException of type
  // InvalidStateError is thrown.
  var request = index.openCursor(key_range);
  var n = 0;
  request.onsuccess = function(event) {
    var cursor = event.target.result;
    if (cursor) {
      //console.log(cursor);
      var r = cursor['delete']();
      r.onsuccess = function() {
        n++;
        cursor['continue']();
      };
      r.onerror = function(event) {
        errors.push(r.error);
        event.preventDefault();
        cursor['continue']();
      };
    } else {
      var has_failed = errors.length > 0;
      if (has_failed) {
        req.setDbValue(errors, true);
      } else {
        req.setDbValue(n);
      }
    }

  };
  request.onerror = function(event) {
    event.preventDefault();
    req.setDbValue(request.error, true);
  };

};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.clearByStores = function(req, store_names) {

  var me = this;
  var n_todo = store_names.length;
  var n_done = 0;
  var msg = req.getLabel() + ' clearByStores: ' + store_names;
  goog.log.finest(this.logger, msg);
  for (var i = 0; i < n_todo; i++) {
    var store_name = store_names[i];
    var store = req.getTx().objectStore(store_name);
    var request = store.clear();
    request.onsuccess = function(event) {
      n_done++;
      // if (ydn.db.crud.req.IndexedDb.DEBUG) {
      //   goog.global.console.log([n_done, event]);
      // }
      if (n_done == n_todo) {
        req.setDbValue(n_done);
      }
    };
    request.onerror = function(event) {
      n_done++;
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([n_done, event]);
      }
      event.preventDefault();
      if (n_done == n_todo) {
        req.setDbValue(request.error, true);
      }
    };
  }
};

/**
* @inheritDoc
*/
ydn.db.crud.req.IndexedDb.prototype.getById = function(req, store_name, id) {

  var me = this;
  var msg = req.getLabel() + store_name + ':' + id;
  goog.log.finest(this.logger, msg);
  var store = req.getTx().objectStore(store_name);

  var request = store.get(id);

  request.onsuccess = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log([store_name, id, event]);
    }
    goog.log.finest(me.logger,  req.getLabel() + ' record ' + id +
        (goog.isDefAndNotNull(event.target.result) ? ' ' : ' not ') +
        ' exists.');
    // check for decode blob, since chrome does not support blob
    var BASE64_MARKER = ';base64,';
    var s = event.target.result;
    if (!store.keyPath && store.indexNames.length == 0 &&
        goog.userAgent.WEBKIT && goog.isString(s) &&
        s.indexOf(BASE64_MARKER) >= 0) {
      if (s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') {
        s = s.substr(1, s.length - 2);
      }
      var parts = s.split(BASE64_MARKER);
      var contentType = parts[0].split(':')[1];
      var raw = window.atob(parts[1]);
      var rawLength = raw.length;

      var uInt8Array = new Uint8Array(rawLength);

      for (var i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
      }

      var blob = new Blob([uInt8Array.buffer], {type: contentType});
      req.setDbValue(blob);
    } else {
      req.setDbValue(event.target.result);
    }
  };

  request.onerror = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log([store_name, id, event]);
    }
    //goog.log.warning(me.logger, 'Error retrieving ' + id + ' in ' + store_name + ' ' +
    // event.message);
    event.preventDefault();
    req.setDbValue(request.error, true);
  };
};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.listByIds = function(req,
                                                         store_name, ids) {
  var me = this;

  var results = [];
  results.length = ids.length;
  var result_count = 0;
  var store = req.getTx().objectStore(store_name);
  var n = ids.length;
  var msg = req.getLabel() + ' ' + store_name + ':' + n + ' ids';
  goog.log.finest(this.logger, msg);

  var get = function(i) {

    if (!goog.isDefAndNotNull(ids[i])) {
      // should we just throw error ?
      result_count++;
      results[i] = undefined;
      if (result_count == n) {
        req.setDbValue(results);
      } else {
        var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX;
        if (next < n) {
          get(next);
        }
      }
    }

    var request;
//    try {
    // console.log(tx_no + ': ' + store_name + ' ' + i + ' ' + ids[i])
    request = store.get(ids[i]);
//    } catch (e) {
//      if (ydn.db.crud.req.IndexedDb.DEBUG) {
//        goog.global.console.log([store_name, i, ids[i], e]);
//        if (e.name == 'DataError') {
//          // http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-get-
//          // IDBRequest-any-key
//          throw new ydn.db.InvalidKeyException(ids[i]);
//        } else {
//          throw e;
//        }
//      }
//    }
    request.onsuccess = (function(event) {
      result_count++;
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([store_name, ids, i, event]);
      }
      results[i] = event.target.result;
      if (result_count == n) {
        req.setDbValue(results);
      } else {
        var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX;
        if (next < n) {
          get(next);
        }
      }
    });

    request.onerror = function(event) {
      result_count++;
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([store_name, ids, i, event]);
      }
      event.preventDefault();
      req.setDbValue(request.error, true);
    };

  };

  if (n > 0) {
    // send parallel requests
    for (var i = 0; i < ydn.db.crud.req.IndexedDb.REQ_PER_TX && i < n; i++) {
      get(i);
    }
  } else {
    req.setDbValue([]);
  }
};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.listByKeys = function(req, keys) {
  var me = this;

  var results = [];
  results.length = keys.length;
  var result_count = 0;
  var msg = req.getLabel() + ' ' + keys.length + ' ids';
  goog.log.finest(this.logger, msg);

  var getKey = function(i) {
    /**
     * @type {!ydn.db.Key}
     */
    var key = keys[i];
    /**
     * @type {IDBObjectStore}
     */
    var store = req.getTx().objectStore(key.getStoreName());
    var request = store.get(key.getId());

    request.onsuccess = function(event) {
      result_count++;
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log(event);
      }
      results[i] = event.target.result;
      if (result_count == keys.length) {
        req.setDbValue(results);
      } else {
        var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX;
        if (next < keys.length) {
          getKey(next);
        }
      }
    };

    request.onerror = function(event) {
      result_count++;
      if (ydn.db.crud.req.IndexedDb.DEBUG) {
        goog.global.console.log([keys, event]);
      }
      event.preventDefault();
      req.setDbValue(request.error, true);
    };

  };

  if (keys.length > 0) {
    // send parallel requests
    for (var i = 0; i < ydn.db.crud.req.IndexedDb.REQ_PER_TX && i < keys.length;
         i++) {
      getKey(i);
    }
  } else {
    req.setDbValue([]);
  }
};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.countKeyRange = function(req,
    table, keyRange, index_name, unique) {

  if (goog.DEBUG && !!index_name && !!unique) {
    throw new ydn.debug.error.InvalidOperationException(
        'unique count not available in IndexedDB');
  }

  var me = this;
  var store = req.getTx().objectStore(table);
  var msg = req.getLabel() + ' ' + table +
      (index_name ? ':' + index_name : '') +
      (keyRange ? ':' + ydn.json.stringify(keyRange) : '');
  goog.log.finest(this.logger, msg);
  var request;
  if (goog.isDefAndNotNull(index_name)) {
    var index = store.index(index_name);
    if (goog.isDefAndNotNull(keyRange)) {
      request = index.count(keyRange);
    } else {
      request = index.count();
    }
  } else {
    if (goog.isDefAndNotNull(keyRange)) {
      request = store.count(keyRange);
    } else {
      request = store.count();
    }
  }

  request.onsuccess = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log(event);
    }
    req.setDbValue(event.target.result);
  };
  request.onerror = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log(event);
    }
    event.preventDefault();
    req.setDbValue(request.error, true);
  };

};

/**
 * @define {boolean} use getAll and getKeyAll if available.
 */
ydn.db.crud.req.IndexedDb.USE_ALL_QUERY = true;

/**
 * Use getAll query.
 * @param {ydn.db.Request} req
 * @param {IDBIndex|IDBObjectStore} index
 * @param {IDBKeyRange} kr
 * @param {number} limit
 * @private
 */
ydn.db.crud.req.IndexedDb.prototype.getAll_ = function(req, index, kr, limit) {
  var request = index['getAll'](kr, limit);
  request.onsuccess = function(event) {
    req.setDbValue(event.target.result);
  };
  request.onerror = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log(event);
    }
    event.preventDefault();
    req.setDbValue(request.error, true);
  };
};

/**
 * Use getAll query.
 * @param {ydn.db.Request} req
 * @param {IDBIndex|IDBObjectStore} index
 * @param {IDBKeyRange} kr
 * @param {number} limit
 * @private
 */
ydn.db.crud.req.IndexedDb.prototype.getAllKeys_ = function(req, index, kr, limit) {
  var request = index['getAllKeys'](kr, limit);
  request.onsuccess = function(event) {
    req.setDbValue(event.target.result);
  };
  request.onerror = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log(event);
    }
    event.preventDefault();
    req.setDbValue(request.error, true);
  };
};

/**
 * @inheritDoc
 */
ydn.db.crud.req.IndexedDb.prototype.list = function(req, type,
    store_name, index, key_range, limit, offset, reverse, unique,
    opt_position) {
  var results = [];
  var store = req.getTx().objectStore(store_name);
  var dir = ydn.db.base.getDirection(reverse, unique);
  var msg = req.getLabel() + ' ' + type + ' ' + store_name +
      (index ? ':' + index : '') +
      (key_range ? ydn.json.stringify(key_range) : '');
  if (reverse) {
    msg += ' reverse';
  }
  if (unique) {
    msg += ' unique';
  }
  if (!!opt_position && goog.isDef(opt_position[0])) {
    // start position is given, cursor must open after this position.
    var open = index ? !(goog.isDef(opt_position[1])) : true;
    var s_key = /** @type {IDBKey} */ (opt_position[0]);
    var lower = /** @type {IDBKey|undefined} */ (key_range ?
        key_range.lower : undefined);
    var upper = /** @type {IDBKey|undefined} */ (key_range ?
        key_range.upper : undefined);
    var lowerOpen = key_range ? !!key_range.lowerOpen : false;
    var upperOpen = key_range ? !!key_range.upperOpen : false;
    var kr = reverse ?
        new ydn.db.KeyRange(lower, s_key, lowerOpen, open) :
        new ydn.db.KeyRange(s_key, upper, open, upperOpen);
    key_range = kr.toIDBKeyRange();
    msg += ' starting from ' +
        ydn.json.stringify(/** @type {Object} */ (opt_position[0]));
    if (goog.isDef(opt_position[1])) {
      msg += ', ' + ydn.json.stringify(/** @type {Object} */ (opt_position[1]));
    }
  }
  goog.log.finest(this.logger, msg);
  var request;
  if (type == ydn.db.base.QueryMethod.LIST_KEY ||
      type == ydn.db.base.QueryMethod.LIST_PRIMARY_KEY ||
      type == ydn.db.base.QueryMethod.LIST_KEYS) {
    // key query
    if (index) {
      var store_index = store.index(index);
      if (ydn.db.crud.req.IndexedDb.USE_ALL_QUERY && type == ydn.db.base.QueryMethod.LIST_PRIMARY_KEY &&
          store_index['getAllKeys'] && !unique && !offset && !reverse && !opt_position) {
        this.getAllKeys_(req, store_index, key_range, limit);
        return;
      }
      request = store_index.openKeyCursor(key_range, dir);
    } else {
      // NOTE: key cursor for object is not available as of IndexedDB API v1.
      if (ydn.db.crud.req.IndexedDb.USE_ALL_QUERY && type == ydn.db.base.QueryMethod.LIST_PRIMARY_KEY &&
          store['getAllKeys'] && !unique && !offset && !reverse &&
          !opt_position) {
        this.getAllKeys_(req, store, key_range, limit);
        return;
      }
      request = store.openCursor(key_range, dir);
    }
  } else {
    // value query
    if (index) {
      var store_index = store.index(index);
      if (ydn.db.crud.req.IndexedDb.USE_ALL_QUERY && store_index['getAll'] && !unique && !offset && !reverse &&
          !opt_position) {
        this.getAll_(req, store_index, key_range, limit);
        return;
      }
      request = store_index.openCursor(key_range, dir);
    } else {
      if (ydn.db.crud.req.IndexedDb.USE_ALL_QUERY && store['getAll'] && !unique && !offset && !reverse &&
          !opt_position) {
        this.getAll_(req, store, key_range, limit);
        return;
      }
      request = store.openCursor(key_range, dir);
    }
  }

  var cued = false;
  request.onsuccess = function(event) {
    /**
     *
     * @type {IDBCursorWithValue}
     */
    var cursor = event.target.result;
    if (cursor) {
      if (!cued) {
        if (offset > 0) {
          // if offset is defined, position will be ignored.
          cued = true;
          cursor.advance(offset);
          return;
        } else if (!!opt_position && !!index && goog.isDef(opt_position[0])) {
          if (goog.isDef(opt_position[1])) {
            var cmp = ydn.db.base.indexedDb.cmp(cursor.key, opt_position[0]);
            var dir = reverse ? -1 : 1;
            if (cmp == 0) {
              var cmp2 = ydn.db.base.indexedDb.cmp(
                  cursor.primaryKey, opt_position[1]);
              // console.log('continue ' + cmp2 + ' ' +
              //    cursor.key + ', ' + cursor.primaryKey);
              if (cmp2 == 0) {
                cued = true;
                // console.log('cued by primary key');
                cursor['continue'](); // skip current key
                return;
              } else if (cmp2 == dir) {
                // console.log('cued by primary key passed over');
                cued = true;
              } else {
                // console.log('continue cueing');
                cursor['continue']();
                return;
              }
            } else {
              // console.log('cued by key ' + cursor.key + ' passed over');
              cued = true;
            }
          } else {
            // console.log('cued by key passed over without primary key');
            cued = true;
          }
        } else {
          cued = true;
        }
      }
      // push to result list
      if (type == ydn.db.base.QueryMethod.LIST_KEY) {
        results.push(cursor.key);
      } else if (type == ydn.db.base.QueryMethod.LIST_PRIMARY_KEY) {
        results.push(cursor.primaryKey);
      } else if (type ==
          ydn.db.base.QueryMethod.LIST_KEYS) {
        var obj = {};
        if (index) {
          obj[index] = cursor.key;
        }
        if (store.keyPath) {
          obj[store.keyPath] = cursor.primaryKey;
        } else {
          obj[ydn.db.base.SQLITE_SPECIAL_COLUNM_NAME] = cursor.primaryKey;
        }
        results.push(obj);
      } else if (type ==
          ydn.db.base.QueryMethod.LIST_VALUE) {
        results.push(cursor.value);
      } else {
        results.push([cursor.key, cursor.primaryKey, cursor.value]);
      }
      // continue
      if (results.length < limit) {
        cursor['continue']();
      } else {
        if (opt_position) {
          opt_position[0] = ydn.db.Key.clone(cursor.key);
          opt_position[1] =
              ydn.db.Key.clone(/** @type {IDBKey} */ (cursor.primaryKey));
        }
        // console.log(req + ' by limit', results);
        req.setDbValue(results);
      }
    } else {
      if (opt_position) {
        opt_position[0] = undefined;
        opt_position[1] = undefined;
      }
      // console.log(req + ' by cursor', results);
      req.setDbValue(results);
    }
  };
  request.onerror = function(event) {
    if (ydn.db.crud.req.IndexedDb.DEBUG) {
      goog.global.console.log([store_name, event]);
    }
    event.preventDefault();
    req.setDbValue(request.error, true);
  };
};


text:
/*
* base-test.js: Test that should be common to all providers.
*
* (C) 2012 Charlie Robbins, Ken Perkins, Ross Kukulinski & the Contributors.
*
*/

var fs = require('fs'),
    Buffer = require('buffer').Buffer,
    assert = require('../../helpers/assert'),
    helpers = require('../../helpers'),
    should = require('should'),
    util = require('util'),
    async = require('async'),
    hock = require('hock'),
    http = require('http'),
    urlJoin = require('url-join'),
    request = require('request'),
    through = require('through2'),
    providers = require('../../configs/providers.json'),
    Container = require('../../../lib/pkgcloud/core/storage/container').Container,
    File = require('../../../lib/pkgcloud/core/storage/file').File,
    mock = !!process.env.MOCK,
    pkgcloud = require('../../../lib/pkgcloud'),
    fillerama = fs.readFileSync(helpers.fixturePath('fillerama.txt'), 'utf8');

// Declaring variables for helper functions defined later
var setupCreateContainerMock, setupGetContainersMock, setupUploadStreamMock,
    setupDownloadStreamMock, setupGetFileMock, setupGetFilesMock,
    setupRemoveFileMock, setupDestroyContainerMock, setupGetContainers2Mock;

providers.filter(function (provider) {
  return !!helpers.pkgcloud.providers[provider].storage;
}).forEach(function (provider) {
  describe('pkgcloud/common/storage/base [' + provider + ']', function () {

    var config = null;

    if (!mock && provider === 'google') {
      config = {
        keyFilename: process.env.GCLOUD_KEYFILE,
        projectId: process.env.GCLOUD_PROJECT_ID
      };
    }

    var client = helpers.createClient(provider, 'storage', config),
      context = {},
      authServer, server,
      authHockInstance, hockInstance;

    before(function (done) {

      if (!mock) {
        return done();
      }

      hockInstance = hock.createHock({ throwOnUnmatched: false });
      authHockInstance = hock.createHock();

      server = http.createServer(hockInstance.handler);
      authServer = http.createServer(authHockInstance.handler);

      // setup a filtering path for aws
      hockInstance.filteringPathRegEx(/https:\/\/[\w\-\.]*s3-us-west-2\.amazonaws\.com([\w\-\.\_0-9\/]*)/g, '$1');

      async.parallel([
        function (next) {
          server.listen(12345, next);
        },
        function (next) {
          authServer.listen(12346, next);
        }
      ], done);
    });

    it('the createContainer() method should return newly created container', function(done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupCreateContainerMock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      client.createContainer('pkgcloud-test-container', function(err, container) {
        should.not.exist(err);
        should.exist(container);
        container.should.be.instanceOf(Container);

        context.container = container;

        authHockInstance && authHockInstance.done();
        hockInstance && hockInstance.done();
        done();

      });
    });

    it('the getContainers() method should return newly created container', function (done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupGetContainersMock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      client.getContainers(function (err, containers) {
        should.not.exist(err);
        should.exist(containers);
        containers.should.be.an.Array;

        containers.forEach(function(container) {
          container.should.be.instanceOf(Container);
        });

        // TODO Name check
        hockInstance && hockInstance.done();
        done();

      });
    });

    it('the upload() method with container and filename should succeed', function (done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupUploadStreamMock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      var stream = client.upload({
        container: context.container,
        remote: 'test-file.txt',
        headers: {'x-amz-acl': 'public-read'}
      });

      stream.on('error', function(err, response) {
        should.not.exist(err);
        should.not.exist(response);
        done();
      });

      stream.on('success', function(file) {
        authHockInstance && authHockInstance.done();
        hockInstance && hockInstance.done();
        file.should.be.an.instanceof(File);

        context.file = {
          name: 'test-file.txt',
          size: Buffer.byteLength(fillerama)
        };

        done();
      });

      var file = fs.createReadStream(helpers.fixturePath('fillerama.txt'));
      file.pipe(stream);
    });

    it('the download() method with container and filename should succeed', function (done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupDownloadStreamMock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      var stream = client.download({
        container: context.container,
        remote: context.file.name
      });

      context.fileContents = '';

      stream.on('data', function (data) {
        context.fileContents += data;
      });

      stream.on('end', function() {
        context.fileContents.should.equal(fillerama);
        hockInstance && hockInstance.done();
        done();
      });
    });

    it('the getFile() method with container and filename should succeed', function (done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupGetFileMock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      client.getFile(context.container, context.file.name, function (err, file) {
          should.not.exist(err);
          should.exist(file);

          file.name.should.equal(context.file.name);
          file.size.should.equal(context.file.size);

          hockInstance && hockInstance.done();
          done();
        });
    });

    it('the getFiles() method with container should succeed', function (done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupGetFilesMock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      client.getFiles(context.container, null, function (err, files) {
        should.not.exist(err);
        should.exist(files);

        files.should.be.an.Array;

        files.forEach(function(file) {
          file.should.be.instanceOf(File);
        });

        // TODO look for context.file in array

        hockInstance && hockInstance.done();
        done();
      });
    });

    it('the removeFile() method with container and filename should succeed', function (done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupRemoveFileMock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      client.removeFile(context.container, context.file.name, function (err, ok) {
        should.not.exist(err);
        should.exist(ok);

        hockInstance && hockInstance.done();
        done();
      });
    });

    it('the upload() method with large file should succeed', function (done) {

      if (mock) {
        return done();
        // TODO mock these out
      }

      var stream = client.upload({
        container: context.container,
        remote: 'bigfile.raw'
      }, function (err, ok) {
        should.not.exist(err);
        should.exist(ok);

        context.file = {
          name: 'bigfile.raw',
          size: fs.readFileSync(helpers.fixturePath('bigfile.raw')).length
        };

        done();
      });

      var file = fs.createReadStream(helpers.fixturePath('bigfile.raw'));
      file.pipe(stream);
    });

    it('the download() method with large file should succeed', function (done) {

      if (mock) {
        return done();
        // TODO mock these out
      }

      var stream = client.download({
        container: context.container,
        remote: context.file.name
      }, function (err, file) {

        should.not.exist(err);
        should.exist(file);
        file.should.be.instanceOf(File);

        file.name.should.equal(context.file.name);
        file.size.should.equal(context.fileContentsSize);

        context.fileContents = Buffer.concat(context.fileContents,
          file.size);

        // Compare byte by byte
        var original = fs.readFileSync(helpers.fixturePath('bigfile.raw'));
        for (var i = 0; i < file.size; i++) {
          assert.equal(context.fileContents[i], original[i]);
        }

        done();
      });

      context.fileContents = [];
      context.fileContentsSize = 0;
      stream.on('data', function (data) {
        context.fileContents.push(data);
        context.fileContentsSize += data.length;
      });
      stream.end();
    });

    it('the destroyContainer() method with container should succeed', function (done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupDestroyContainerMock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      client.destroyContainer(context.container, function (err, ok) {
        should.not.exist(err);
        should.exist(ok);

        hockInstance && hockInstance.done();
        done();
      });
    });

    it('the getContainers() method should succeed', function (done) {

      if (mock) {
        if (provider === 'joyent') {
          // TODO figure out why joyent was disabled in vows based tests
          return done();
        }

        setupGetContainers2Mock(provider, client, {
          server: hockInstance,
          authServer: authHockInstance
        });
      }

      client.getContainers(function (err, ok) {
        should.not.exist(err);
        should.exist(ok);

        hockInstance && hockInstance.done();
        done();
      });
    });

    after(function (done) {
      if (!mock) {
        return done();
      }

      async.parallel([
        function (next) {
          server.close(next);
        },
        function (next) {
          authServer.close(next);
        }
      ], done);
    });
  });
});

setupCreateContainerMock = function (provider, client, servers) {
  if (provider === 'rackspace') {
    servers.authServer
      .post('/v2.0/tokens', {
        auth: {
          'RAX-KSKEY:apiKeyCredentials': {
            username: 'MOCK-USERNAME',
            apiKey: 'MOCK-API-KEY'
          }
        }
      })
      .reply(200, helpers.getRackspaceAuthResponse());

    servers.server
      .defaultReplyHeaders(helpers.rackspaceResponseHeaders())
      .put('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(201);
  }
  else if (provider === 'openstack') {
    servers.authServer
      .post('/v2.0/tokens', {
        auth: {
          passwordCredentials: {
            username: 'MOCK-USERNAME',
            password: 'MOCK-PASSWORD'
          }
        }
      }, {'User-Agent': util.format('nodejs-pkgcloud/%s', pkgcloud.version)})
      .reply(200, helpers._getOpenstackStandardResponse('../fixtures/openstack/initialToken.json'))
      .get('/v2.0/tenants', {'User-Agent': util.format('nodejs-pkgcloud/%s', pkgcloud.version)})
      .replyWithFile(200, __dirname + '/../../fixtures/openstack/tenantId.json')
      .post('/v2.0/tokens', {
        auth: {
          passwordCredentials: {
            username: 'MOCK-USERNAME',
            password: 'MOCK-PASSWORD'
          },
          tenantId: '72e90ecb69c44d0296072ea39e537041'
        }
      }, {'User-Agent': util.format('nodejs-pkgcloud/%s', pkgcloud.version)})
      .reply(200, helpers.getOpenstackAuthResponse());

    servers.server
      .put('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(201);
  }
  else if (provider === 'amazon') {
    servers.server
      .put('/', '<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LocationConstraint>us-west-2</LocationConstraint></CreateBucketConfiguration>')
      .reply(200);
  }
  else if (provider === 'azure') {

    // Override the clients getUrl method as it tries to prefix the container name onto the request
    client._getUrl = function (options) {
      options = options || {};

      return urlJoin('http://localhost:12345/',
        (typeof options === 'string'
          ? options
          : options.path));
    };

    servers.server
      .put('/pkgcloud-test-container?restype=container')
      .reply(201, '', helpers.azureResponseHeaders());
  }
  else if (provider === 'google') {
    servers.server
      .post('/storage/v1/b?project=test-project', {
        name: 'pkgcloud-test-container'
      })
      .replyWithFile(200, __dirname + '/../../fixtures/google/create-bucket.json');

    client.storage.connection_.createAuthorizedReq = function (reqOpts, callback) {
      reqOpts.uri = reqOpts.uri.replace(/.*\.com/, 'http://localhost:12345');
      callback(null, reqOpts);
    };

    client.storage.connection_.req = function (reqOpts, callback) {
      reqOpts.uri = reqOpts.uri.replace(/.*\.com/, 'http://localhost:12345');
      client.storage.connection_.requester(reqOpts, callback);
    };

    client.storage.connection_.requester = function (reqOpts, callback) {
      if (reqOpts.qs && reqOpts.qs.uploadType === 'multipart') {
        var stream = through();
        stream.on('finish', function () {
          fs.readFile(__dirname + '/../../fixtures/google/create-file.json', function(err, file) {
            if (err) {
              return stream.emit('error', err);
            }
            stream.emit('complete', { body: JSON.parse(file) });
          });
        });
        return stream;
      }

      return request(reqOpts, callback);
    };
  }
  else if (provider === 'hp') {
    servers.authServer
      .post('/v2.0/tokens', {
        auth: {
          apiAccessKeyCredentials: {
            accessKey: 'MOCK-USERNAME',
            secretKey: 'MOCK-API-KEY'
          }
        }
      }, {'User-Agent': util.format('nodejs-pkgcloud/%s', pkgcloud.version)})
      .reply(200, helpers._getOpenstackStandardResponse('../fixtures/hp/initialToken.json'))
      .get('/v2.0/tenants', {'User-Agent': util.format('nodejs-pkgcloud/%s', pkgcloud.version)})
      .replyWithFile(200, __dirname + '/../../fixtures/hp/tenantId.json')
      .post('/v2.0/tokens', {
        auth: {
          apiAccessKeyCredentials: {
            accessKey: 'MOCK-USERNAME',
            secretKey: 'MOCK-API-KEY'
          },
          tenantId: '5ACED3DC3AA740ABAA41711243CC6949'
        }
      }, {'User-Agent': util.format('nodejs-pkgcloud/%s', pkgcloud.version)})
      .reply(200, helpers.gethpAuthResponse());

    servers.server
      .put('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(201);
  }
};

setupGetContainersMock = function (provider, client, servers) {
  if (provider === 'rackspace' || provider === 'openstack') {
    servers.server
      .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00?format=json')
      .reply(200, helpers.loadFixture('rackspace/postContainers.json'));
  }
  else if (provider === 'amazon') {
    servers.server
      .get('/')
      .reply(200, helpers.loadFixture('amazon/list-buckets.xml'));
  }
  else if (provider === 'azure') {
    servers.server
      .get('/?comp=list')
      .reply(200, helpers.loadFixture('azure/list-containers.xml'),helpers.azureResponseHeaders());
  }
  else if (provider === 'google') {
    servers.server
      .get('/storage/v1/b?project=test-project')
      .replyWithFile(200, __dirname + '/../../fixtures/google/get-buckets.json');
  }
  else if (provider === 'hp') {
    servers.server
      .get('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00?format=json')
      .reply(200, helpers.loadFixture('hp/postContainers.json'));
  }
};

setupUploadStreamMock = function (provider, client, servers) {
  if (provider === 'rackspace' || provider === 'openstack') {
    servers.server
      .put('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt', fillerama)
      .reply(200)
      .head('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt?format=json')
      .reply(200, '', { 'content-length': fillerama.length + 2 });
  }
  else if (provider === 'amazon') {
    servers.server
      .post('/test-file.txt?uploads')
      .reply(200, '<?xml version="1.0" encoding="UTF-8"?>\n<InitiateMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Bucket>pkgcloud-test-container</Bucket><Key>test-file.txt</Key><UploadId>U4vzbMZVEkBOyxMPHMCu7nRSUw.eNLeqK0oYOPA6BeeiDSu6OTjrsMkkTsOFav3qCpgvIJluGWe_Yi.ypTVxEg--</UploadId></InitiateMultipartUploadResult>', {})
      .put('/test-file.txt?partNumber=1&uploadId=U4vzbMZVEkBOyxMPHMCu7nRSUw.eNLeqK0oYOPA6BeeiDSu6OTjrsMkkTsOFav3qCpgvIJluGWe_Yi.ypTVxEg--', fillerama)
      .reply(200, '<?xml version="1.0" encoding="UTF-8"?>\n\n<CompleteMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Location>https://pkgcloud-test-container.s3.amazonaws.com/test-file.txt</Location><Bucket>pkgcloud-test-container</Bucket><Key>test-file.txt</Key><ETag>"b2286fe4aac65809a1b7a053d07fc99f-1"</ETag></CompleteMultipartUploadResult>')
      .post('/test-file.txt?uploadId=U4vzbMZVEkBOyxMPHMCu7nRSUw.eNLeqK0oYOPA6BeeiDSu6OTjrsMkkTsOFav3qCpgvIJluGWe_Yi.ypTVxEg--', '<CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Part><ETag>"b2286fe4aac65809a1b7a053d07fc99f-1"</ETag><PartNumber>1</PartNumber></Part></CompleteMultipartUpload>')
      .reply(200);

  }
  else if (provider === 'azure') {
    servers.server
      .put('/pkgcloud-test-container/test-file.txt?comp=block&blockid=block000000000000000', fillerama)
      .reply(201, '', helpers.azureResponseHeaders({'content-md5': 'mw0KEVFFwT8SgYGK3Cu8vg=='}))
      .put('/pkgcloud-test-container/test-file.txt?comp=blocklist', '<?xml version="1.0" encoding="utf-8"?><BlockList><Latest>block000000000000000</Latest></BlockList>')
      .reply(201, '', helpers.azureResponseHeaders({'content-md5': 'VuFw1xub9CF3KoozbZ3kZw=='}))
      .get('/pkgcloud-test-container/test-file.txt')
      .reply(200, '', helpers.azureGetFileResponseHeaders({'content-length': fillerama.length + 2, 'content-type': 'text/plain'}));
  }
  else if (provider === 'hp') {
    servers.server
      .put('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt', fillerama)
      .reply(200)
      .head('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt?format=json')
      .reply(200, '', { 'content-length': fillerama.length + 2 });
  }
};

setupDownloadStreamMock = function (provider, client, servers) {
  if (provider === 'rackspace' || provider === 'openstack') {
    servers.server
      .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt')
      .reply(200, fillerama, { 'content-length': fillerama.length + 2});
  }
  else if (provider === 'amazon') {
    servers.server
      .get('/test-file.txt')
      .reply(200, fillerama, { 'content-length': fillerama.length + 2 });
  }
  else if (provider === 'azure') {
    servers.server
      .get('/pkgcloud-test-container/test-file.txt')
      .reply(200, fillerama, helpers.azureGetFileResponseHeaders({'content-length': fillerama.length + 2,'content-type': 'text/plain'}));
  }
  else if (provider === 'google') {
    servers.server
      .get('/storage/v1/b/pkgcloud-test-container/o/test-file.txt')
      .reply(200, { mediaLink: 'http://localhost:12345/mediaLink' })
      .get('/mediaLink')
      .reply(200, fillerama);
  }
  else if (provider === 'hp') {
    servers.server
      .get('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt')
      .reply(200, fillerama, { 'content-length': fillerama.length + 2});
  }
};

setupGetFileMock = function (provider, client, servers) {
  if (provider === 'rackspace' || provider === 'openstack') {
    servers.server
      .head('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt?format=json')
      .reply(200, '', { 'content-length': fillerama.length + 2 });
  }
  else if (provider === 'amazon') {
    servers.server
      .head('/test-file.txt')
      .reply(200, '', { 'content-length': fillerama.length + 2 });
  }
  else if (provider === 'azure') {
    servers.server
      .get('/pkgcloud-test-container/test-file.txt')
      .reply(200, '', helpers.azureGetFileResponseHeaders({'content-length': fillerama.length + 2, 'content-type': 'text/plain'}));
  }
  else if (provider === 'google') {
    servers.server
      .get('/storage/v1/b/pkgcloud-test-container/o/test-file.txt')
      .replyWithFile(200, __dirname + '/../../fixtures/google/get-file.json');
  }
  else if (provider === 'hp') {
    servers.server
      .head('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt?format=json')
      .reply(200, '', { 'content-length': fillerama.length + 2 });
  }
};

setupGetFilesMock = function (provider, client, servers) {
  if (provider === 'rackspace' || provider === 'openstack') {
    servers.server
      .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container?format=json')
      .reply(200, [{
        bytes: fillerama.length,
        name: 'test-file.txt',
        content_type: 'text/plain'
      }]);
  }
  else if (provider === 'amazon') {
    servers.server
      .get('/')
      .reply(200, helpers.loadFixture('amazon/list-bucket-files.xml'));
  }
  else if (provider === 'azure') {
    servers.server
      .get('/pkgcloud-test-container?restype=container&comp=list')
      .reply(200, helpers.loadFixture('azure/list-container-files.xml'), helpers.azureResponseHeaders({'content-type': 'application/xml'}));
  }
  else if (provider === 'google') {
    servers.server
      .get('/storage/v1/b/pkgcloud-test-container/o')
      .replyWithFile(200, __dirname + '/../../fixtures/google/get-files.json');
  }
  else if (provider === 'hp') {
    servers.server
      .get('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container?format=json')
      .reply(200, [{
        bytes: fillerama.length,
        name: 'test-file.txt',
        content_type: 'text/plain'
      }]);
  }
};

setupRemoveFileMock = function (provider, client, servers) {
  if (provider === 'rackspace' || provider === 'openstack') {
    servers.server
      .delete('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt')
      .reply(204, '');
  }
  else if (provider === 'amazon') {
    servers.server
      .delete('/test-file.txt')
      .reply(204);
  }
  else if (provider === 'azure') {
    servers.server
      .delete('/pkgcloud-test-container/test-file.txt')
      .reply(202, '', helpers.azureDeleteResponseHeaders());
  }
  else if (provider === 'google') {
    servers.server
      .delete('/storage/v1/b/pkgcloud-test-container/o/test-file.txt')
      .reply(204, {});
  }
  else if (provider === 'hp') {
    servers.server
      .delete('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt')
      .reply(204, '');
  }
};

setupDestroyContainerMock = function (provider, client, servers) {
  if (provider === 'openstack') {
    servers.server
      .head('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(200, {}, {
        'x-container-object-count': 1,
        'x-container-bytes-used': fillerama.length
      })
      .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container?format=json&limit=1001')
      .reply(200, [
        {
          bytes: fillerama.length,
          name: 'test-file.txt',
          content_type: 'text/plain'
        }
      ])
      .delete('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt')
      .reply(204, '')
      .delete('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(204);
  }
  else if (provider === 'rackspace') {
    servers.server
      .head('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(200, {}, {
        'x-container-object-count': 1,
        'x-container-bytes-used': fillerama.length
      })
      .head('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(200, {}, {
        'x-container-object-count': 1,
        'x-container-bytes-used': fillerama.length
      })
      .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container?format=json&limit=1001')
      .reply(200, [
        {
          bytes: fillerama.length,
          name: 'test-file.txt',
          content_type: 'text/plain'
        }
      ])
      .delete('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt')
      .reply(204, '')
      .delete('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(204);
  }
  else if (provider === 'amazon') {
    servers.server
      .get('/')
      .reply(200, helpers.loadFixture('amazon/list-bucket-files.xml'), {})
      .delete('/')
      .reply(204)
      .delete('/test-file.txt')
      .reply(204);
  }
  else if (provider === 'azure') {
    servers.server
      .delete('/pkgcloud-test-container?restype=container')
      .reply(202, '', helpers.azureDeleteResponseHeaders());
  }
  else if (provider === 'google') {
    servers.server
      .get('/storage/v1/b/pkgcloud-test-container/o')
      .replyWithFile(200, __dirname + '/../../fixtures/google/get-files.json')
      .delete('/storage/v1/b/pkgcloud-test-container/o/test-file.txt')
      .reply(204, {})
      .delete('/storage/v1/b/pkgcloud-test-container')
      .reply(204, {});
  }
  else if (provider === 'hp') {
    servers.server
      .head('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(200, {}, {
        'x-container-object-count': 1,
        'x-container-bytes-used': fillerama.length
      })
      .get('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container?format=json&limit=1001')
      .reply(200, [
        {
          bytes: fillerama.length,
          name: 'test-file.txt',
          content_type: 'text/plain'
        }
      ])
      .delete('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container/test-file.txt')
      .reply(204, '')
      .delete('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00/pkgcloud-test-container')
      .reply(204);
  }
};

setupGetContainers2Mock = function (provider, client, servers) {
  if (provider === 'rackspace' || provider === 'openstack') {
    servers.server
      .get('/v1/MossoCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00?format=json')
      .reply(200, helpers.loadFixture('rackspace/preContainers.json'));
  }
  else if (provider === 'amazon') {
    servers.server
      .get('/')
      .reply(200, helpers.loadFixture('amazon/list-buckets2.xml'));
  }
  else if (provider === 'azure') {
    servers.server
      .get('/?comp=list')
      .reply(200, helpers.loadFixture('azure/list-containers2.xml'), helpers.azureResponseHeaders());
  }
  else if (provider === 'google') {
    servers.server
      .get('/storage/v1/b?project=test-project')
      .replyWithFile(200, __dirname + '/../../fixtures/google/get-buckets.json');
  }
  else if (provider === 'hp') {
    servers.server
      .get('/v1/HPCloudFS_00aa00aa-aa00-aa00-aa00-aa00aa00aa00?format=json')
      .reply(200, helpers.loadFixture('hp/preContainers.json'));
  }
};

redpajama_set_name: RedPajamaGithub


text:
package com.gs.obevo.maven;

import com.gs.obevo.util.inputreader.Credential;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;

@Mojo(name = "test", defaultPhase = LifecyclePhase.TEST)
public class DeployBuildTestMojo extends AbstractDeployMojo {
    public void execute() throws MojoExecutionException {
        if (this.cleanFirst == null) {
            this.setCleanFirst(true);
        }
        this.setNoPrompt(true);
        Credential credential = this.getCredential();
        if (credential == null || !credential.isAuthenticationMethodProvided()) {
            throw new MojoExecutionException("Credential must be provided with authentication mode: " + credential);
        }

        this.setAllChangesets(true);

        this.validateIsPopulated(this.getSourcePath(), "sourcePath");
        super.execute();
    }
}


text:
: ${DOMAIN:=$HOSTNAME}; : ${DB_ENV_PASS:="$DB_ENV_MARIADB_PASS"};: ${UID:=80};
DB_NAME=${DOMAIN//./_};SHOP=shop-$DOMAIN;SHOP_PATH=/data/www/$SHOP

export TZ=$TIMEZONE
ln -sf /usr/share/zoneinfo/$TIMEZONE /etc/localtime

if [[ ! -d /data/conf/nginx/hosts.d/$DOMAIN.conf || "$OVERRIDDEN" == "TRUE" ]]; then
cat > /data/conf/nginx/hosts.d/$DOMAIN.conf <<EOF
server {
      listen      80;
      server_name $DOMAIN;
      root        $SHOP_PATH;
      index       index.php index.html;
      include     /etc/nginx/conf.d/default-*.conf;
      include     /data/conf/nginx/conf.d/default-*.conf;
      include     /etc/nginx/conf.d/php-wordpress.conf;

}
EOF
fi

if [[ ! -d $SHOP_PATH || "$OVERRIDDEN" == "TRUE" ]]; then
    rm -rf $SHOP_PATH
    mv /wordpress $SHOP_PATH
fi
if $(sudo -u www -i -- /usr/local/bin/wp core is-installed --path=$SHOP_PATH --allow-root); then INSTALLED=TRUE; else INSTALLED=FALSE; fi
if [[ "$INSTALLED" == "FALSE" || "$OVERRIDDEN" == "TRUE" ]]; then
    cd $SHOP_PATH

    echo "--- Generate wordpress config---"
    sudo -u www -i -- /usr/local/bin/wp core config \
        --dbname=$DB_NAME \
        --dbuser=$DB_ENV_USER \
        --dbpass=$DB_ENV_PASS \
        --dbhost=db \
        --locale=$LOCALE \
        --path=$SHOP_PATH

    echo "--- Reset wordpress database  ---"
    sudo -u www -i -- /usr/local/bin/wp db reset --yes --path=$SHOP_PATH

    echo "--- Installing wordpress ---"
    sudo -u www -i -- /usr/local/bin/wp core install \
        --url=http://$DOMAIN \
        --title=$TITLE \
        --admin_user=admin \
        --admin_password=$ADMIN_PASSWORD \
        --admin_email=$ADMIN_EMAIL \
        --path=$SHOP_PATH
    sudo -u www -i -- /usr/local/bin/wp plugin install nginx-helper --activate --path=$SHOP_PATH
    sudo -u www -i -- /usr/local/bin/wp plugin install w3-total-cache --activate --path=$SHOP_PATH
#    /usr/local/bin/wp option update home 'http://$DOMAIN' --allow-root
#    /usr/local/bin/wp option update siteurl 'http://$DOMAIN' --allow-root
#    /usr/local/bin/wp option update admin_email  '$ADMIN_EMAIL' --allow-root
#    /usr/local/bin/wp option update admin_password '$ADMIN_PASSWORD' --allow-root
#    /usr/local/bin/wp user update $ADMIN_EMAIL --display_name=admin --user_pass=$ADMIN_PASSWORD
#    /usr/local/bin/wp option update blogname '$TITLE' --allow-root
#    echo "--- Clean up ---"

    echo "--- Completed ---"
fi


text:
/**
 * General purpose types for language sources support.
 */
@Incubating
package org.gradle.language.base.sources;

import org.gradle.api.Incubating;


text:
using System;
using System.Windows.Forms;

namespace Palaso.UI.WindowsForms.WritingSystems.WSIdentifiers
{
	public partial class NothingSpecialView : UserControl, ISelectableIdentifierOptions
	{
		private readonly WritingSystemSetupModel _model;

		public NothingSpecialView(WritingSystemSetupModel model)
		{
			_model = model;
			InitializeComponent();
		}

		public string ChoiceName
		{
			get { return "None"; }
		}

		#region Implementation of ISelectableIdentifierOptions

		public void Selected()
		{
			if (_model != null)
			{
				_model.IdentifierNothingSelected();
			}
		}

		public void MoveDataFromViewToModel()
		{
			//do nothing
		}

		public void UnwireBeforeClosing()
		{
			//do nothing
		}

		#endregion
	}
}


text:
<link rel="stylesheet" href="/css/bootstrap.min.css">

<!-- IE Support -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->

<link rel="stylesheet" href="/css/style.css">


text:
require File.dirname(__FILE__) + '/spec_helper.rb'

describe "Given existing remote resources" do

  before(:each) do
    User.delete_all
    stub_resource 1, :email => "joeremote@foo.bar"
    stub_resource 2, :email => "jane_remote@foo.bar"
  end

  describe "a user" do

    it "should return cached attributes" do
      User.should respond_to(:cached_attributes)
      User.cached_attributes.should include(:email)
    end

    it "should return changed remotes since yesterday" do
      user_1, user_2 = mock(:user), mock(:user)
      time = 1.day.ago
      User::Remote.should_receive(:find).with(:all,{:from => :updated, :params=>{:since=>time.to_s, :last_record_id=>nil}}).once.and_return([user_1, user_2])

      User.should respond_to(:updated_remotes)
      User.updated_remotes(:since => time.to_s).should include(user_1, user_2)
    end

    it "should find last synchronization" do
      times = []
      3.downto(1) do |i|
        HasRemote::Synchronization.create!(:model_name => 'User', :last_record_updated_at => i.days.ago, :last_record_id => i)
      end
      User.should respond_to(:last_synchronization)
      sync = User.last_synchronization
      sync.last_record_updated_at.to_s.should == 1.day.ago.to_s
      sync.last_record_id.should == 1
    end

    it "should not delegate cached remote attributes" do
      user = User.create! :remote_id => 1
      User::Remote.should_not_receive(:find)
      user.email.should == "joeremote@foo.bar"
    end

    it "should update its cached remote attributes on save" do
      user = User.create! :remote_id => 1
      user[:email].should == "joeremote@foo.bar"
      user.update_attributes(:remote_id => 2)
      user[:email].should == "jane_remote@foo.bar"
    end

    it "should not update its cached remote attributes if skip_update_cache is true" do
      user = User.create! :remote_id => 1, :skip_update_cache => true
      user[:email].should == nil
    end

  end

  describe "synchronization" do

    describe "for the User model" do

      describe "with updated and deleted remotes" do

        before(:each) do
          @yesterday = 1.day.ago
          @user_1, @user_2 = User.create!(:remote_id => 1), User.create!(:remote_id => 2)

          resources = [
            mock(:user, :id => 1, :email => "altered@foo.bar", :updated_at => 2.days.ago, :deleted_at => nil),
            mock(:user, :id => 2, :email => "deleted@foo.bar", :updated_at => 2.days.ago, :deleted_at => 2.days.ago),
            mock(:user, :id => 3, :email => "new-deleted@foo.bar", :updated_at => 2.days.ago, :deleted_at => 2.days.ago),
            mock(:user, :id => 4, :email => "new@foo.bar", :updated_at => @yesterday),
          ]
          User.stub!(:updated_remotes).and_return(resources)

          lambda { User.synchronize! }.should change(HasRemote::Synchronization, :count).by(1)
        end

        it "should keep track of the last synchronized record" do
          sync = HasRemote::Synchronization.for("User").last

          sync.last_record_updated_at.should == @yesterday
          sync.last_record_id.should == 4
        end

        it "should update changed users" do
          @user_1.reload[:email].should == "altered@foo.bar"
        end

        it "should destroy deleted users" do
          User.exists?(@user_2).should be_false
        end

        it "should create added users" do
          User.exists?(:remote_id => 4).should be_true
        end

        it "should not create deleted users" do
          User.exists?(:remote_id => 3).should be_false
        end
      end

      describe "that fails" do

        before(:each) do

          @failure = lambda {
            user_1, user_2 = User.create!(:remote_id => 1), User.create!(:remote_id => 2)

            yesterday = DateTime.parse 1.day.ago.to_s

            resources = [
              mock(:user, :id => 1, :email => "changed@foo.bar", :updated_at => yesterday),
              mock(:user, :id => 2, :email => "altered@foo.bar", :updated_at => 2.days.ago)
            ]

            User.stub!(:updated_remotes).and_return(resources)

            resources.last.should_receive(:send).and_raise "All hell breaks loose" # Raise when attr is read from resource 2.

            User.synchronize!
          }
        end

        it "should do it silently" do
          @failure.should_not raise_error
        end

        it "should not create a synchronization record" do
          @failure.should_not change(HasRemote::Synchronization, :count)
        end

      end

    end

    describe "for a single user" do

      it "should update the user" do
        user = User.create! :remote_id => 1
        user[:email].should == "joeremote@foo.bar"

        stub_resource 1, :email => "changed@foo.bar"

        user.update_cached_attributes!
        user[:email].should == "changed@foo.bar"
      end

    end

  end

  describe "synchronizing new cheeses" do
    before do
      resources = [
        mock(:cheese, :id => 1, :name => "Brie", :updated_at => Date.yesterday)
      ]
      Cheese.stub!(:updated_remotes).and_return(resources)
      lambda{ Cheese.synchronize! }.should change(Cheese, :count).from(0).to(1)
    end

    after { Cheese.delete_all }

    it "should populate the local 'maturity' attribute with its default database value" do
      Cheese.first.maturity.should == 5
    end

    it "should populate the local 'smell' attribute with the value set inside of a before_validation callback" do
      Cheese.first.smell.should == 5 * 10
    end

  end

end

def stub_resource(id, attrs)
  resource = mock(:user, {:id => id}.merge(attrs))
  User::Remote.stub!(:find).with(id).and_return(resource)
  resource
end


text:
'use strict';

const DOM = require('../../util/dom');
const util = require('../../util/util');
const window = require('../../util/window');

const inertiaLinearity = 0.25,
    inertiaEasing = util.bezier(0, 0, inertiaLinearity, 1),
    inertiaMaxSpeed = 180, // deg/s
    inertiaDeceleration = 720; // deg/s^2

/**
 * The `DragRotateHandler` allows the user to rotate the map by clicking and
 * dragging the cursor while holding the right mouse button or `ctrl` key.
 *
 * @param {Map} map The Mapbox GL JS map to add the handler to.
 * @param {Object} [options]
 * @param {number} [options.bearingSnap] The threshold, measured in degrees, that determines when the map's
 *   bearing (rotation) will snap to north.
 * @param {bool} [options.pitchWithRotate=true] Control the map pitch in addition to the bearing
 */
class DragRotateHandler {
    constructor(map, options) {
        this._map = map;
        this._el = map.getCanvasContainer();
        this._bearingSnap = options.bearingSnap;
        this._pitchWithRotate = options.pitchWithRotate !== false;

        util.bindAll([
            '_onDown',
            '_onMove',
            '_onUp'
        ], this);

    }

    /**
     * Returns a Boolean indicating whether the "drag to rotate" interaction is enabled.
     *
     * @returns {boolean} `true` if the "drag to rotate" interaction is enabled.
     */
    isEnabled() {
        return !!this._enabled;
    }

    /**
     * Returns a Boolean indicating whether the "drag to rotate" interaction is active, i.e. currently being used.
     *
     * @returns {boolean} `true` if the "drag to rotate" interaction is active.
     */
    isActive() {
        return !!this._active;
    }

    /**
     * Enables the "drag to rotate" interaction.
     *
     * @example
     * map.dragRotate.enable();
     */
    enable() {
        if (this.isEnabled()) return;
        this._el.addEventListener('mousedown', this._onDown);
        this._enabled = true;
    }

    /**
     * Disables the "drag to rotate" interaction.
     *
     * @example
     * map.dragRotate.disable();
     */
    disable() {
        if (!this.isEnabled()) return;
        this._el.removeEventListener('mousedown', this._onDown);
        this._enabled = false;
    }

    _onDown(e) {
        if (this._ignoreEvent(e)) return;
        if (this.isActive()) return;

        window.document.addEventListener('mousemove', this._onMove);
        window.document.addEventListener('mouseup', this._onUp);
        /* Deactivate DragRotate when the window looses focus. Otherwise if a mouseup occurs when the window isn't in focus, DragRotate will still be active even though the mouse is no longer pressed. */
        window.addEventListener('blur', this._onUp);

        this._active = false;
        this._inertia = [[Date.now(), this._map.getBearing()]];
        this._startPos = this._pos = DOM.mousePos(this._el, e);
        this._center = this._map.transform.centerPoint;  // Center of rotation

        e.preventDefault();
    }

    _onMove(e) {
        if (this._ignoreEvent(e)) return;

        if (!this.isActive()) {
            this._active = true;
            this._map.moving = true;
            this._fireEvent('rotatestart', e);
            this._fireEvent('movestart', e);
        }

        const map = this._map;
        map.stop();

        const p1 = this._pos,
            p2 = DOM.mousePos(this._el, e),
            bearingDiff = (p1.x - p2.x) * 0.8,
            pitchDiff = (p1.y - p2.y) * -0.5,
            bearing = map.getBearing() - bearingDiff,
            pitch = map.getPitch() - pitchDiff,
            inertia = this._inertia,
            last = inertia[inertia.length - 1];

        this._drainInertiaBuffer();
        inertia.push([Date.now(), map._normalizeBearing(bearing, last[1])]);

        map.transform.bearing = bearing;
        if (this._pitchWithRotate) map.transform.pitch = pitch;

        this._fireEvent('rotate', e);
        this._fireEvent('move', e);

        this._pos = p2;
    }

    _onUp(e) {
        if (this._ignoreEvent(e)) return;
        window.document.removeEventListener('mousemove', this._onMove);
        window.document.removeEventListener('mouseup', this._onUp);
        window.removeEventListener('blur', this._onUp);

        if (!this.isActive()) return;

        this._active = false;
        this._fireEvent('rotateend', e);
        this._drainInertiaBuffer();

        const map = this._map,
            mapBearing = map.getBearing(),
            inertia = this._inertia;

        const finish = () => {
            if (Math.abs(mapBearing) < this._bearingSnap) {
                map.resetNorth({noMoveStart: true}, { originalEvent: e });
            } else {
                this._map.moving = false;
                this._fireEvent('moveend', e);
            }
        };

        if (inertia.length < 2) {
            finish();
            return;
        }

        const first = inertia[0],
            last = inertia[inertia.length - 1],
            previous = inertia[inertia.length - 2];
        let bearing = map._normalizeBearing(mapBearing, previous[1]);
        const flingDiff = last[1] - first[1],
            sign = flingDiff < 0 ? -1 : 1,
            flingDuration = (last[0] - first[0]) / 1000;

        if (flingDiff === 0 || flingDuration === 0) {
            finish();
            return;
        }

        let speed = Math.abs(flingDiff * (inertiaLinearity / flingDuration));  // deg/s
        if (speed > inertiaMaxSpeed) {
            speed = inertiaMaxSpeed;
        }

        const duration = speed / (inertiaDeceleration * inertiaLinearity),
            offset = sign * speed * (duration / 2);

        bearing += offset;

        if (Math.abs(map._normalizeBearing(bearing, 0)) < this._bearingSnap) {
            bearing = map._normalizeBearing(0, bearing);
        }

        map.rotateTo(bearing, {
            duration: duration * 1000,
            easing: inertiaEasing,
            noMoveStart: true
        }, { originalEvent: e });
    }

    _fireEvent(type, e) {
        return this._map.fire(type, { originalEvent: e });
    }

    _ignoreEvent(e) {
        const map = this._map;

        if (map.boxZoom && map.boxZoom.isActive()) return true;
        if (map.dragPan && map.dragPan.isActive()) return true;
        if (e.touches) {
            return (e.touches.length > 1);
        } else {
            const buttons = (e.ctrlKey ? 1 : 2),  // ? ctrl+left button : right button
                button = (e.ctrlKey ? 0 : 2);   // ? ctrl+left button : right button
            let eventButton = e.button;
            if (typeof InstallTrigger !== 'undefined' && e.button === 2 && e.ctrlKey &&
                window.navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
                // Fix for https://github.com/mapbox/mapbox-gl-js/issues/3131:
                // Firefox (detected by InstallTrigger) on Mac determines e.button = 2 when
                // using Control + left click
                eventButton = 0;
            }
            return (e.type === 'mousemove' ? e.buttons & buttons === 0 : !this.isActive() && eventButton !== button);
        }
    }

    _drainInertiaBuffer() {
        const inertia = this._inertia,
            now = Date.now(),
            cutoff = 160;   //msec

        while (inertia.length > 0 && now - inertia[0][0] > cutoff)
            inertia.shift();
    }
}

module.exports = DragRotateHandler;

/**
 * Fired when a "drag to rotate" interaction starts. See [`DragRotateHandler`](#DragRotateHandler).
 *
 * @event rotatestart
 * @memberof Map
 * @instance
 * @property {MapMouseEvent | MapTouchEvent} data
 */

/**
 * Fired repeatedly during a "drag to rotate" interaction. See [`DragRotateHandler`](#DragRotateHandler).
 *
 * @event rotate
 * @memberof Map
 * @instance
 * @property {MapMouseEvent | MapTouchEvent} data
 */

/**
 * Fired when a "drag to rotate" interaction ends. See [`DragRotateHandler`](#DragRotateHandler).
 *
 * @event rotateend
 * @memberof Map
 * @instance
 * @property {MapMouseEvent | MapTouchEvent} data
 */


text:
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>W28900_text</title>
        <link rel="stylesheet" type="text/css" href="style.css" />

                «

    <p class="styleSans1.0000<enum PANGO_WEIGHT_NORMAL of type PangoWeight><enum PANGO_STYLE_NORMAL of type PangoStyle>">

    <p class="styleSans12.0000<enum PANGO_WEIGHT_NORMAL of type PangoWeight><enum PANGO_STYLE_NORMAL of type PangoStyle>">1. Allan Wehrman, the surface owner of the Surface Lands described above. have entered into a Surface Use License and Damage Agreement with Mountain Divide. LLC. This agreement was entered into by me and Mountain Divide. LLC. for the purpose of allowing Mountain Divide, LLC. to use the Surface Lands for the drilling for. capturing, producing. and selling oil and gas from
wells located on the Surface Lands. Such right includes but is not limited to the burial of drill cuttings resulting from operations on the Surface Lands.
IN WITNESS HEREOF. 1. Allan Wehrman, the surface owner. hereto signed this ; day of June. 2014.

    <p class="styleSans5.0000<enum PANGO_WEIGHT_NORMAL of type PangoWeight><enum PANGO_STYLE_NORMAL of type PangoStyle>">

    <p class="styleSans15.0000<enum PANGO_WEIGHT_NORMAL of type PangoWeight><enum PANGO_STYLE_NORMAL of type PangoStyle>">Subscribed and swom to before me. in 22,15, g County, in the State of (year/4 94:67)?on this /_'7day ofJune, 2014.
SHIRLEY M. BINDE Notary Public
State of North Dakota _ My Commission Expires Aug. 15. 2018 W
(SEA) Notary Public, Druxé County. M 22-

    <p class="styleSans4.0000<enum PANGO_WEIGHT_NORMAL of type PangoWeight><enum PANGO_STYLE_NORMAL of type PangoStyle>">IQ