<commit_before>/*!
 * Storage.js JavaScript Library v0.1.0
 * https://github.com/lcavadas/Storage.js
 *
 * Copyright 2012, Luís Serralheiro
 */

var storage = function (readyCallback, type) {

  var commons = {
    sequencialActionCallbackWrapper: function (values, callback, finalCallback) {
      var index = 0;
      var length = values.length;

      var _next = function () {
        if (index < length) {
          callback(values[index++]);
        } else {
          finalCallback();
        }
      };

      return {
        next: _next
      };
    },
    multipleActionCallbackWrapper: function (times, callback) {
      var values = [];

      return {
        countDown: function (value) {
          values.push(value);
          if (values.length === (times)) {
            callback(values);
          }
        }
      };
    }
  };

  var invokeReadyCallBack = function (database) {
    if (!database) {
      readyCallback();
    } else {
      readyCallback({
        set: function (entity, value, callback) {
          database.set(entity, value, callback);
        },
        setAll: function (entity, values, callback) {
          database.setAll(entity, values, callback);
        },
        get: function (entity, id, callback) {
          database.get(entity, id, callback);
        },
        getAll: function (entity, callback) {
          database.getAll(entity, callback);
        },
        remove: function (entity, id, callback) {
          database.remove(entity, id, callback);
        },
        removeAll: function (entity, callback) {
          database.removeAll(entity, callback);
        },
        ready: function (callback) {
          database.ready(callback);
        },
        close: database.close
      });
    }
  };

  switch (type) {
    case 'LocalStorage':
      storage.KeyValue(invokeReadyCallBack, commons);
      break;
    case 'SessionStorage':
      storage.KeyValue(invokeReadyCallBack, commons, true);
      break;
    case 'WebSQL':
      storage.WebSQL(invokeReadyCallBack, commons);
      break;
    case 'IndexedDB':
      storage.IndexedDB(invokeReadyCallBack, commons);
      break;
    default :
      //WebSQL
      if (window.openDatabase) {
        window.console.log("Using WebSQL");
        storage.WebSQL(invokeReadyCallBack, commons);
      } else if (window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB) {
        window.console.log("Using IndexedDB");
        storage.IndexedDB(invokeReadyCallBack, commons);
      } else {
        window.console.log("Using LocalStorage");
        //Fallback to localStorage
        storage.KeyValue(invokeReadyCallBack, commons);
      }
      break;
  }
};

// localStorage and sessionStorage wrapper
//      useSession: Indicates if sessionStorage is to be used (default is localStorage)
storage.KeyValue = function (ready, commons, useSession) {

  try {
    var kv = useSession ? sessionStorage : localStorage;
  } catch (e) {
    ready();
    return;
  }

  var _get = function (entity, id, callback) {
    var stored = JSON.parse(kv.getItem(entity));
    var length = stored ? stored.length : 0;

    for (var i = 0; i < length; i++) {
      if (stored[i].id === id) {
        callback(stored[i]);
        return;
      }
    }
    callback();
  };

  var _set = function (entity, value, callback) {
    var stored = JSON.parse(kv.getItem(entity)) || [];
    var updated = false;
    var length = stored.length;

    for (var i = 0; i < length; i++) {
      if (stored[i].id === value.id) {
        updated = true;
        stored[i] = value;
      }
    }
    if (!updated) {
      stored.push(value);
    }

    kv.setItem(entity, JSON.stringify(stored));

    callback();
  };

  var _remove = function (entity, id) {
    var stored = JSON.parse(kv.getItem(entity));
    var length = stored.length;

    for (var i = 0; i < length; i++) {
      if (stored[i].id === id) {
        stored.splice(i, 1);
        kv.setItem(entity, JSON.stringify(stored));
        return;
      }
    }
  };

  ready({
    set: _set,
    setAll: function (entity, values, callback) {
      var responseCallback = commons.multipleActionCallbackWrapper(values.length, callback);
      values.forEach(function (value) {
        _set(entity, value, responseCallback.countDown);
      });
    },
    get: _get,
    getAll: function (entity, callback) {
      var value = kv.getItem(entity);
      callback(value ? JSON.parse(value) : []);
    },
    remove: function (entity, id, callback) {
      _remove(entity, id);
      callback();
    },
    removeAll: function (entity, callback) {
      kv.removeItem(entity);
      callback();
    },
    close: function () {
      //There is nothing to do
    }
  });
};

storage.WebSQL = function (ready, commons) {
  var db;

  var _createTable = function (name, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          'CREATE TABLE if not exists ' + name + '(id TEXT NOT NULL, value TEXT, PRIMARY KEY(id));',
          [],
          callback,
          function (transaction, error) {
            window.console.log('Oops.  Error was ' + error.message + ' (Code ' + error.code + ')', error);
          }
        );
      }
    );
  };

  var _set = function (entity, value, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          'INSERT OR REPLACE into ' + entity + '(id, value) VALUES ( ?, ? );',
          [value.id, JSON.stringify(value)],
          function () {
            callback();
          },
          function (transaction, error) {
            //No such table
            if (error.code === 5) {
              window.console.log("WebSQL: going to create table " + entity);
              //create the table and try again
              _createTable(entity, function () {
                window.console.log("WebSQL: created table " + entity);
                _set(entity, value, callback);
              });
            } else {
              window.console.log('WebSQL Error: ' + error.message + ' (Code ' + error.code + ')', error);
              callback();
            }
          }
        );
      });
  };

  var _get = function (entity, id, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          "select value from " + entity + " where id=?;",
          [id],
          function (transaction, results) {
            callback(results.rows.length > 0 ? JSON.parse(results.rows.item(0).value) : undefined);
          },
          function (transaction, error) {
            //No such table
            if (error.code === 5) {
              callback();
            } else {
              window.console.log('WebSQL Error: ' + error.message + ' (Code ' + error.code + ')', error);
              callback();
            }
          }
        );
      }
    );
  };

  var _getAll = function (entity, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          "select value from " + entity,
          [],
          function (transaction, results) {
            var objectArray = [];
            var length = results.rows.length;
            for (var i = 0; i < length; i++) {
              objectArray.push(JSON.parse(results.rows.item(i).value));
            }
            callback(objectArray);
          },
          function (transaction, error) {
            //No such table
            if (error.code === 5) {
              callback([]);
            } else {
              window.console.log('WebSQL Error: ' + error.message + ' (Code ' + error.code + ')', error);
              callback();
            }
          }
        );
      }
    );
  };

  var _remove = function (entity, id, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          "delete from " + entity + " where id=?",
          [id],
          callback,
          function (transaction, error) {
            window.console.log('WebSQL Error: ' + error.message + ' (Code ' + error.code + ')', error);
            callback();
          }
        );
      }
    );
  };

  var _removeAll = function (entity, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          "drop table " + entity + "",
          [],
          callback,
          //table doesnt exist
          callback
        );
      }
    );
  };

  try {
    if (!window.openDatabase) {
      window.console.log('SQL Database not supported');
      ready();
    } else {
      var shortName = 'storage.js';
      var version = '1.0';
      var displayName = 'storage.js database';
      var maxSize = 65536; // in bytes
      db = openDatabase(shortName, version, displayName, maxSize);

      ready({
        set: _set,
        setAll: function (entity, values, callback) {
          var responseCallback = commons.multipleActionCallbackWrapper(values.length, callback);
          values.forEach(function (value) {
            _set(entity, value, responseCallback.countDown);
          });
        },
        get: _get,
        getAll: _getAll,
        remove: _remove,
        removeAll: _removeAll,
        close: function () {
          //There is nothing to do
        }
      });
    }
  } catch (e) {
    // Error handling code goes here.
    if (e === 2) {
      // Version number mismatch.
      window.console.log("Invalid database version.");
    } else {
      window.console.log("Unknown error " + e + ".");
    }
  }
};

storage.IndexedDB = function (ready, commons) {
  var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
  //var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.mozIDBTransaction || window.msIDBTransaction;
  var db;

  var _createObjectStore = function (entity, callback) {
    db.close();
    //IE fails with versions bigger that 9 digits and requires the type to be int (number fails with InvalidAccessError)
    var version = parseInt(Math.round(new Date().getTime() / 1000) % 1000000000);
    var versionRequest = indexedDB.open("storage_js", version);
    versionRequest.onupgradeneeded = function () {
      db = versionRequest.result;
      db.createObjectStore(entity, {keyPath: "id"});
    };
    versionRequest.onsuccess = function () {
      callback();
    };
  };

  var _set = function (entity, value, callback) {
    try {
      if (!db.objectStoreNames.contains(entity)) {
        window.console.log("IndexedDB: going to create objectStore " + entity);
        _createObjectStore(entity, function () {
          window.console.log("IndexedDB: created objectStore " + entity);
          _set(entity, value, callback);
        });
        return;
      }

      var transaction = db.transaction([entity], "readwrite");
      var objectStore = transaction.objectStore(entity);
      var request = objectStore.put(value);
      transaction.onerror = function (error) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      };
      request.onsuccess = function () {
        callback();
      };
      request.onerror = function (error) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      };
    } catch (error) {
      //error code 3 and 8 are not found on chrome and canary respectively
      if (error.code !== 3 && error.code !== 8) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
        callback();
      } else {
        window.console.log("IndexedDB: going to create objectStore " + entity);
        _createObjectStore(entity, function () {
          _set(entity, value, callback);
        });
      }
    }
  };

  var _get = function (entity, id, callback) {
    try {
      var transaction = db.transaction([entity], "readwrite");
      transaction.onerror = function (error) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      };

      var objectStore = transaction.objectStore(entity);
      objectStore.get(id).onsuccess = function (event) {
        callback(event.target.result);
      };
    } catch (error) {
      window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      callback();
    }
  };

  var _getAll = function (entity, callback) {
    try {
      var objectArray = [];
      var transaction = db.transaction([entity], "readwrite");
      transaction.onerror = function (error) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      };

      var objectStore = transaction.objectStore(entity);
      objectStore.openCursor().onsuccess = function (event) {
        var cursor = event.target.result;
        if (cursor) {
          objectArray.push(cursor.value);
          cursor.continue();
        }
        else {
          callback(objectArray);
        }
      };
    } catch (error) {
      callback([]);
    }
  };

  var _remove = function (entity, id, callback) {
    var transaction = db.transaction([entity], "readwrite");
    var objectStore = transaction.objectStore(entity);
    objectStore.delete(id).onsuccess = function () {
      callback();
    };
  };

  var _removeAll = function (entity, callback) {
    db.close();
    var request = indexedDB.open("storage_js", new Date().getTime());
    request.onupgradeneeded = function () {
      try {
        db = request.result;
        if (db.objectStoreNames.contains(entity)) {
          db.deleteObjectStore(entity);
        }
        callback();
      } catch (error) {
        //error code 3 and 8 are not found on chrome and canary respectively
        if (error.code !== 3 && error.code !== 8) {
          window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
        } else {
          callback();
        }
      }
    };
  };

  var _close = function () {
    db.close();
  };

  if (indexedDB) {
    // Now we can open our database
    var request = indexedDB.open("storage_js");
    request.onupgradeneeded = function () {
      window.console.log("UPGRADE NEEDED");
    };
    request.onsuccess = function () {
      db = request.result;
      ready({
        set: _set,
        setAll: function (entity, values, callback) {
          var seqWrapper = commons.sequencialActionCallbackWrapper(values, function (value) {
            _set(entity, value, seqWrapper.next);
          }, callback);
          seqWrapper.next();
        },
        get: _get,
        getAll: _getAll,
        remove: _remove,
        removeAll: _removeAll,
        close: _close
      });
    };
    request.onerror = function (event) {
      window.console.log("An error ocurred", event);
      ready();
    };
  } else {
    ready();
  }
};
window.storage = storage;
<commit_msg>Fixing for IE11<commit_after>/*!
 * Storage.js JavaScript Library v0.1.0
 * https://github.com/lcavadas/Storage.js
 *
 * Copyright 2012, Luís Serralheiro
 */

var storage = function (readyCallback, type) {

  var commons = {
    sequencialActionCallbackWrapper: function (values, callback, finalCallback) {
      var index = 0;
      var length = values.length;

      var _next = function () {
        if (index < length) {
          callback(values[index++]);
        } else {
          finalCallback();
        }
      };

      return {
        next: _next
      };
    },
    multipleActionCallbackWrapper: function (times, callback) {
      var values = [];

      return {
        countDown: function (value) {
          values.push(value);
          if (values.length === (times)) {
            callback(values);
          }
        }
      };
    }
  };

  var invokeReadyCallBack = function (database) {
    if (!database) {
      readyCallback();
    } else {
      readyCallback({
        set: function (entity, value, callback) {
          database.set(entity, value, callback);
        },
        setAll: function (entity, values, callback) {
          database.setAll(entity, values, callback);
        },
        get: function (entity, id, callback) {
          database.get(entity, id, callback);
        },
        getAll: function (entity, callback) {
          database.getAll(entity, callback);
        },
        remove: function (entity, id, callback) {
          database.remove(entity, id, callback);
        },
        removeAll: function (entity, callback) {
          database.removeAll(entity, callback);
        },
        ready: function (callback) {
          database.ready(callback);
        },
        close: database.close
      });
    }
  };

  switch (type) {
    case 'LocalStorage':
      storage.KeyValue(invokeReadyCallBack, commons);
      break;
    case 'SessionStorage':
      storage.KeyValue(invokeReadyCallBack, commons, true);
      break;
    case 'WebSQL':
      storage.WebSQL(invokeReadyCallBack, commons);
      break;
    case 'IndexedDB':
      storage.IndexedDB(invokeReadyCallBack, commons);
      break;
    default :
      //WebSQL
      if (window.openDatabase) {
        window.console.log("Using WebSQL");
        storage.WebSQL(invokeReadyCallBack, commons);
      } else if (window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB) {
        window.console.log("Using IndexedDB");
        storage.IndexedDB(invokeReadyCallBack, commons);
      } else {
        window.console.log("Using LocalStorage");
        //Fallback to localStorage
        storage.KeyValue(invokeReadyCallBack, commons);
      }
      break;
  }
};

// localStorage and sessionStorage wrapper
//      useSession: Indicates if sessionStorage is to be used (default is localStorage)
storage.KeyValue = function (ready, commons, useSession) {

  try {
    var kv = useSession ? sessionStorage : localStorage;
  } catch (e) {
    ready();
    return;
  }

  var _get = function (entity, id, callback) {
    var stored = JSON.parse(kv.getItem(entity));
    var length = stored ? stored.length : 0;

    for (var i = 0; i < length; i++) {
      if (stored[i].id === id) {
        callback(stored[i]);
        return;
      }
    }
    callback();
  };

  var _set = function (entity, value, callback) {
    var stored = JSON.parse(kv.getItem(entity)) || [];
    var updated = false;
    var length = stored.length;

    for (var i = 0; i < length; i++) {
      if (stored[i].id === value.id) {
        updated = true;
        stored[i] = value;
      }
    }
    if (!updated) {
      stored.push(value);
    }

    kv.setItem(entity, JSON.stringify(stored));

    callback();
  };

  var _remove = function (entity, id) {
    var stored = JSON.parse(kv.getItem(entity));
    var length = stored.length;

    for (var i = 0; i < length; i++) {
      if (stored[i].id === id) {
        stored.splice(i, 1);
        kv.setItem(entity, JSON.stringify(stored));
        return;
      }
    }
  };

  ready({
    set: _set,
    setAll: function (entity, values, callback) {
      var responseCallback = commons.multipleActionCallbackWrapper(values.length, callback);
      values.forEach(function (value) {
        _set(entity, value, responseCallback.countDown);
      });
    },
    get: _get,
    getAll: function (entity, callback) {
      var value = kv.getItem(entity);
      callback(value ? JSON.parse(value) : []);
    },
    remove: function (entity, id, callback) {
      _remove(entity, id);
      callback();
    },
    removeAll: function (entity, callback) {
      kv.removeItem(entity);
      callback();
    },
    close: function () {
      //There is nothing to do
    }
  });
};

storage.WebSQL = function (ready, commons) {
  var db;

  var _createTable = function (name, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          'CREATE TABLE if not exists ' + name + '(id TEXT NOT NULL, value TEXT, PRIMARY KEY(id));',
          [],
          callback,
          function (transaction, error) {
            window.console.log('Oops.  Error was ' + error.message + ' (Code ' + error.code + ')', error);
          }
        );
      }
    );
  };

  var _set = function (entity, value, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          'INSERT OR REPLACE into ' + entity + '(id, value) VALUES ( ?, ? );',
          [value.id, JSON.stringify(value)],
          function () {
            callback();
          },
          function (transaction, error) {
            //No such table
            if (error.code === 5) {
              window.console.log("WebSQL: going to create table " + entity);
              //create the table and try again
              _createTable(entity, function () {
                window.console.log("WebSQL: created table " + entity);
                _set(entity, value, callback);
              });
            } else {
              window.console.log('WebSQL Error: ' + error.message + ' (Code ' + error.code + ')', error);
              callback();
            }
          }
        );
      });
  };

  var _get = function (entity, id, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          "select value from " + entity + " where id=?;",
          [id],
          function (transaction, results) {
            callback(results.rows.length > 0 ? JSON.parse(results.rows.item(0).value) : undefined);
          },
          function (transaction, error) {
            //No such table
            if (error.code === 5) {
              callback();
            } else {
              window.console.log('WebSQL Error: ' + error.message + ' (Code ' + error.code + ')', error);
              callback();
            }
          }
        );
      }
    );
  };

  var _getAll = function (entity, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          "select value from " + entity,
          [],
          function (transaction, results) {
            var objectArray = [];
            var length = results.rows.length;
            for (var i = 0; i < length; i++) {
              objectArray.push(JSON.parse(results.rows.item(i).value));
            }
            callback(objectArray);
          },
          function (transaction, error) {
            //No such table
            if (error.code === 5) {
              callback([]);
            } else {
              window.console.log('WebSQL Error: ' + error.message + ' (Code ' + error.code + ')', error);
              callback();
            }
          }
        );
      }
    );
  };

  var _remove = function (entity, id, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          "delete from " + entity + " where id=?",
          [id],
          callback,
          function (transaction, error) {
            window.console.log('WebSQL Error: ' + error.message + ' (Code ' + error.code + ')', error);
            callback();
          }
        );
      }
    );
  };

  var _removeAll = function (entity, callback) {
    db.transaction(
      function (transaction) {
        transaction.executeSql(
          "drop table " + entity + "",
          [],
          callback,
          //table doesnt exist
          callback
        );
      }
    );
  };

  try {
    if (!window.openDatabase) {
      window.console.log('SQL Database not supported');
      ready();
    } else {
      var shortName = 'storage.js';
      var version = '1.0';
      var displayName = 'storage.js database';
      var maxSize = 65536; // in bytes
      db = openDatabase(shortName, version, displayName, maxSize);

      ready({
        set: _set,
        setAll: function (entity, values, callback) {
          var responseCallback = commons.multipleActionCallbackWrapper(values.length, callback);
          values.forEach(function (value) {
            _set(entity, value, responseCallback.countDown);
          });
        },
        get: _get,
        getAll: _getAll,
        remove: _remove,
        removeAll: _removeAll,
        close: function () {
          //There is nothing to do
        }
      });
    }
  } catch (e) {
    // Error handling code goes here.
    if (e === 2) {
      // Version number mismatch.
      window.console.log("Invalid database version.");
    } else {
      window.console.log("Unknown error " + e + ".");
    }
  }
};

storage.IndexedDB = function (ready, commons) {
  var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
  //var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.mozIDBTransaction || window.msIDBTransaction;
  var db;

  var _createObjectStore = function (entity, callback) {
    db.close();
    //IE fails with versions bigger that 9 digits and requires the type to be int (number fails with InvalidAccessError)
    var version = parseInt(Math.round(new Date().getTime() / 1000) % 1000000000);
    var versionRequest = indexedDB.open("storage_js", version);
    versionRequest.onupgradeneeded = function () {
      db = versionRequest.result;
      db.createObjectStore(entity, {keyPath: "id"});
    };
    versionRequest.onsuccess = function () {
      callback();
    };
  };

  var _set = function (entity, value, callback) {
    try {
      if (!db.objectStoreNames.contains(entity)) {
        window.console.log("IndexedDB: going to create objectStore " + entity);
        _createObjectStore(entity, function () {
          window.console.log("IndexedDB: created objectStore " + entity);
          _set(entity, value, callback);
        });
        return;
      }

      var transaction = db.transaction([entity], "readwrite");
      var objectStore = transaction.objectStore(entity);
      var request = objectStore.put(value);
      transaction.onerror = function (error) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      };
      request.onsuccess = function () {
        callback();
      };
      request.onerror = function (error) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      };
    } catch (error) {
      //error code 3 and 8 are not found on chrome and canary respectively
      if (error.code !== 3 && error.code !== 8) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
        callback();
      } else {
        window.console.log("IndexedDB: going to create objectStore " + entity);
        _createObjectStore(entity, function () {
          _set(entity, value, callback);
        });
      }
    }
  };

  var _get = function (entity, id, callback) {
    try {
      var transaction = db.transaction([entity], "readwrite");
      transaction.onerror = function (error) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      };

      var objectStore = transaction.objectStore(entity);
      objectStore.get(id).onsuccess = function (event) {
        callback(event.target.result);
      };
    } catch (error) {
      window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      callback();
    }
  };

  var _getAll = function (entity, callback) {
    try {
      var objectArray = [];
      var transaction = db.transaction([entity], "readwrite");
      transaction.onerror = function (error) {
        window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
      };

      var objectStore = transaction.objectStore(entity);
      objectStore.openCursor().onsuccess = function (event) {
        var cursor = event.target.result;
        if (cursor) {
          objectArray.push(cursor.value);
          cursor.continue();
        }
        else {
          callback(objectArray);
        }
      };
    } catch (error) {
      callback([]);
    }
  };

  var _remove = function (entity, id, callback) {
    var transaction = db.transaction([entity], "readwrite");
    var objectStore = transaction.objectStore(entity);
    objectStore.delete(id).onsuccess = function () {
      callback();
    };
  };

  var _removeAll = function (entity, callback) {
    db.close();
    var version = parseInt(Math.round(new Date().getTime() / 1000) % 1000000000);
    var request = indexedDB.open("storage_js", version);
    request.onupgradeneeded = function () {
      try {
        db = request.result;
        if (db.objectStoreNames.contains(entity)) {
          db.deleteObjectStore(entity);
        }
        callback();
      } catch (error) {
        //error code 3 and 8 are not found on chrome and canary respectively
        if (error.code !== 3 && error.code !== 8) {
          window.console.trace('IndexedDB Error: ' + error.message + ' (Code ' + error.code + ')', error);
        } else {
          callback();
        }
      }
    };
  };

  var _close = function () {
    db.close();
  };

  if (indexedDB) {
    // Now we can open our database
    var request = indexedDB.open("storage_js");
    request.onupgradeneeded = function () {
      window.console.log("UPGRADE NEEDED");
    };
    request.onsuccess = function () {
      db = request.result;
      ready({
        set: _set,
        setAll: function (entity, values, callback) {
          var seqWrapper = commons.sequencialActionCallbackWrapper(values, function (value) {
            _set(entity, value, seqWrapper.next);
          }, callback);
          seqWrapper.next();
        },
        get: _get,
        getAll: _getAll,
        remove: _remove,
        removeAll: _removeAll,
        close: _close
      });
    };
    request.onerror = function (event) {
      window.console.log("An error ocurred", event);
      ready();
    };
  } else {
    ready();
  }
};
window.storage = storage;
<|endoftext|>


<commit_before>import React from "react"
import Layout from "../components/layout"
import SEO from "../components/seo"
import Codepen from "react-codepen-embed";
import ProjectsImage from "../components/img/projectsImage"
import Projectsnav from "../components/projectsnav"
import * as frontendData from "../data/frontend.json";

class FrontEndPage extends React.Component {
      constructor(props) {
            super(props);

            this.state = {
                  pageNumber: 2
            }

      }

      increment = () => {
            this.setState({ pageNumber: this.state.pageNumber + 2 });
      }

      showAll = (size) => {
            this.setState({ pageNumber: size })
      }

      closeAll = () => {
            this.setState({ pageNumber: 2 })
      }

      render() {

            let incrementButton, showAllButton, closeAllButton;
            if (this.state.pageNumber < frontendData.length) {
                  incrementButton = <button className="button is-primary"
                        onClick={() => this.increment()}
                  >See more</button>;

                  showAllButton = <button className="button is-primary"
                        onClick={() => this.showAll(frontendData.length)}
                  >Show Everything</button>;
            }

            if (this.state.pageNumber >= frontendData.length) {
                  closeAllButton = <button className="button is-primary"
                        onClick={() => this.closeAll()}
                  >Close Everything</button>;
            }

            return (
                  <Layout navLocation="project">

                                          <Projectsnav project="frontend" />

<ProjectsImage />

100 Days of CSS

                                          {frontendData.slice(0, this.state.pageNumber).map(item => {
                                                return (

                                                            <Codepen
                                                                  hash={item.hash}
                                                                  user="mpakleung"
                                                                  defaultTab="result"
                                                                  loader={() =>
Loading...
}
                                                            />

                                                )
                                          })}

                                                {incrementButton}

                                                {showAllButton}
                                                {closeAllButton}

                        <SEO title="Projects" />
                  </Layout>
            )
      }
}

export default FrontEndPage;<commit_msg>fix netlify problem<commit_after>import React from "react"
import Layout from "../components/layout"
import SEO from "../components/seo"
import Codepen from "react-codepen-embed";
import ProjectsImage from "../components/img/projectsImage"
import Projectsnav from "../components/projectsnav"
import * as frontendData from "../data/frontend.json";

class FrontEndPage extends React.Component {
      constructor(props) {
            super(props);

            this.state = {
                  pageNumber: 2
            }

      }

      increment = () => {
            this.setState({ pageNumber: this.state.pageNumber + 2 });
      }

      showAll = (size) => {
            this.setState({ pageNumber: size })
      }

      closeAll = () => {
            this.setState({ pageNumber: 2 })
      }

      render() {

            let incrementButton, showAllButton, closeAllButton;
            if (this.state.pageNumber < frontendData.length) {
                  incrementButton = <button className="button is-primary"
                        onClick={() => this.increment()}
                  >See more</button>;

                  showAllButton = <button className="button is-primary"
                        onClick={() => this.showAll(frontendData.length)}
                  >Show Everything</button>;
            }

            if (this.state.pageNumber >= frontendData.length) {
                  closeAllButton = <button className="button is-primary"
                        onClick={() => this.closeAll()}
                  >Close Everything</button>;
            }

            return (
                  <Layout navLocation="project">

                                          <Projectsnav project="frontend" />

<ProjectsImage />

100 Days of CSS

                                          {frontendData.map(item => {
                                                return (

                                                            <Codepen
                                                                  hash={item.hash}
                                                                  user="mpakleung"
                                                                  defaultTab="result"
                                                                  loader={() =>
Loading...
}
                                                            />

                                                )
                                          })}

                                                {incrementButton}

                                                {showAllButton}
                                                {closeAllButton}

                        <SEO title="Projects" />
                  </Layout>
            )
      }
}

export default FrontEndPage;<|endoftext|>


<commit_before>/*
  Value type saving upon working with localStorage
*/

window.storage = new function() {

	var self = this;

	this.typesPrefix = 'LocalStorageTypes.';

	//TODO: Allow functions to be stored
	this.Types = {
		'string': 0,
		'number' : 1,
		'boolean' : 2,
		'date' : 3,
		'object' : 4,
	};

	/**
	* Saves the item at the key provided.
	* @param {string} key		Key identifying the value
	* @param {*} value			Value to be stored
	* @param {string=} type		Explicitly specified value type
	*/
	this.set = function (key, value, type) {

		type = typeof type !== 'undefined' ? type : typeof value;
		if (!self.Types.hasOwnProperty(type)) {
			throw new Error('Invalid value type.');
		}

		if (type === 'object') {
			value = JSON.stringify(value);
		}

		// Store value
		localStorage.setItem(key, value);

		// Store value type
		localStorage.setItem(self.typesPrefix + key, type);
	};

	/**
	* Returns the item identified by it's key.
	* @param {string} key		Key identifying the value
	* @return {*}
	*/
	this.get = function (key) {
		var valueString = localStorage.getItem(key);
		var type = localStorage.getItem(self.typesPrefix + key);

		if (valueString == null) {
			return null;
		}

		return parseString(valueString, type);
	};

	/**
	* Determines whether value stored with the specified key exists.
	* @param {string} key		Key identifying the value
	* @return {boolean}
	*/
	this.exists = function (key) {
		var recordString = localStorage.getItem(key);
		return recordString !== null;
	};

	/**
	* Removes the item identified by it's key.
	* @param {string} key		Key identifying the value
	*/
	this.remove = function (key) {
		localStorage.removeItem(key);
		localStorage.removeItem(self.typesPrefix + key);
	};

	/**
	* Removes all of the key value pairs.
	*/
	this.clear = function () {
		localStorage.clear();
	};

	var parseString = function (stringValue, type) {
		var value;

		if (!stringValue) {
			return stringValue;
		}

		switch (type) {
			case 'number':
				value = Number(stringValue);
				break;
			case 'boolean':
				value = Boolean(stringValue);
				break;
			case 'date':
				value = new Date(stringValue);
				break;
			case 'object':
				value = JSON.parse(stringValue);
				break;
			case 'string':
				value = stringValue;
				break;
			default:
				throw new Error('Invalid value type.');
		}

		return value;
	};

};
<commit_msg>Fixed type names and saving of Dates<commit_after>/*
  Value type saving upon working with localStorage
*/

storage = new function() {

	var self = this;

	this.typesPrefix = 'LocalStorageTypes.';

	this.Types = {
		String: 'string',
		Number : 'number',
		Boolean : 'boolean',
		Date : 'date',
		Object : 'object',
		Undefined: 'undefined',
	};

	this.allowedTypes = (function(){
		var result = [],
			i = 0;

		var keys =  Object.keys(self.Types);
		for(i; i < keys.length; i++) {
			result.push(self.Types[keys[i]]);
		}
		return result;
	})();

	/**
	* Saves the item at the key provided.
	* @param {string} key		Key identifying the value
	* @param {*} value		Value to be stored
	* @param {string=} type		Explicitly specified value type
	*/
	this.set = function (key, value, type) {

		type = typeof type !== 'undefined' ? type : typeof value;

		if (this.allowedTypes.indexOf(type) < 0) {
			throw new Error('Invalid value type.');
		}

		// Set Date type
		if (value && value.constructor.name == 'Date') {
			type = self.Types.Date;
		}

		if (type === 'object') {
			value = JSON.stringify(value);
		}

		// Store value
		localStorage.setItem(key, value);

		// Store value type
		localStorage.setItem(self.typesPrefix + key, type);
	};

	/**
	* Returns the item identified by it's key.
	* @param {string} key		Key identifying the value
	* @return {*}
	*/
	this.get = function (key) {
		var valueString, type;

		valueString = localStorage.getItem(key);
		type = localStorage.getItem(self.typesPrefix + key);

		if (valueString == null) {
			return null;
		}

		return parseString(valueString, type);
	};

	this.getType = function (key) {
		return localStorage.getItem(self.typesPrefix + key);
	}

	/**
	* Determines whether value stored with the specified key exists.
	* @param {string} key		Key identifying the value
	* @return {boolean}
	*/
	this.exists = function (key) {
		var recordString;

		recordString = localStorage.getItem(key);
		return recordString !== null;
	};

	/**
	* Removes the item identified by it's key.
	* @param {string} key		Key identifying the value
	*/
	this.remove = function (key) {
		localStorage.removeItem(key);
		localStorage.removeItem(self.typesPrefix + key);
	};

	/**
	* Removes all of the key value pairs.
	*/
	this.clear = function () {
		localStorage.clear();
	};

	var parseString = function (stringValue, type) {
		var value;

		if (stringValue === null || typeof stringValue === undefined) {
			return stringValue;
		}

		switch (type) {
			case self.Types.String:
				value = stringValue;
				break;
			case self.Types.Number:
				value = Number(stringValue);
				break;
			case self.Types.Boolean:
				value = Boolean(stringValue);
				break;
			case self.Types.Date:
				value = new Date(stringValue);
				break;
			case self.Types.Object:
				value = JSON.parse(stringValue);
				break;
			case self.Types.Undefined:
				value = undefined;
				break;
			default:
				throw new Error('Invalid value type.');
		}

		return value;
	};

};
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @author       Felipe Alfonso <@bitnenfer>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../../utils/Class');
var GetFastValue = require('../../../utils/object/GetFastValue');
var LightShaderSourceFS = require('../shaders/Light-frag.js');
var SinglePipeline = require('./SinglePipeline');
var WebGLPipeline = require('../WebGLPipeline');

var LIGHT_COUNT = 10;

/**
 * @classdesc
 *
 * The Light Pipeline is an extension of the Multi Pipeline and uses a custom shader
 * designed to handle forward diffused rendering of 2D lights in a Scene.
 *
 * The shader works in tandem with Light Game Objects, and optionally texture normal maps,
 * to provide an ambient illumination effect.
 *
 * If you wish to provide your own shader, you can use the `%LIGHT_COUNT%` declaration in the source,
 * and it will be automatically replaced at run-time with the total number of configured lights.
 *
 * The maximum number of lights can be set in the Render Config `maxLights` property and defaults to 10.
 *
 * Prior to Phaser v3.50 this pipeline was called the `ForwardDiffuseLightPipeline`.
 *
 * The fragment shader it uses can be found in `shaders/src/Light.frag`.
 * The vertex shader it uses can be found in `shaders/src/Multi.vert`.
 *
 * The default shader attributes for this pipeline are:
 *
 * `inPosition` (vec2, offset 0)
 * `inTexCoord` (vec2, offset 8)
 * `inTexId` (float, offset 16)
 * `inTintEffect` (float, offset 20)
 * `inTint` (vec4, offset 24, normalized)
 *
 * The default shader uniforms for this pipeline are:
 *
 * `uProjectionMatrix` (mat4)
 * `uViewMatrix` (mat4)
 * `uModelMatrix` (mat4)
 * `uMainSampler` (sampler2D)
 * `uNormSampler` (sampler2D)
 * `uCamera` (vec4)
 * `uResolution` (vec2)
 * `uAmbientLightColor` (vec3)
 * `uInverseRotationMatrix` (mat3)
 * `uLights` (Light struct)
 *
 * @class LightPipeline
 * @extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline
 * @memberof Phaser.Renderer.WebGL.Pipelines
 * @constructor
 * @since 3.50.0
 *
 * @param {Phaser.Types.Renderer.WebGL.WebGLPipelineConfig} config - The configuration options for this pipeline.
 */
var LightPipeline = new Class({

    Extends: SinglePipeline,

    initialize:

    function LightPipeline (config)
    {
        LIGHT_COUNT = config.game.renderer.config.maxLights;

        config.fragShader = GetFastValue(config, 'fragShader', LightShaderSourceFS).replace('%LIGHT_COUNT%', LIGHT_COUNT.toString());

        SinglePipeline.call(this, config);

        /**
         * Inverse rotation matrix for normal map rotations.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#inverseRotationMatrix
         * @type {Float32Array}
         * @private
         * @since 3.16.0
         */
        this.inverseRotationMatrix = new Float32Array([
            1, 0, 0,
            0, 1, 0,
            0, 0, 1
        ]);

        /**
         * Stores a default normal map, which is an object with a `glTexture` property that
         * maps to a 1x1 texture of the color #7f7fff created in the `boot` method.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#defaultNormalMap
         * @type {object}
         * @since 3.50.0
         */
        this.defaultNormalMap;

        /**
         * Stores the previous number of lights rendered.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#lightCount
         * @type {number}
         * @since 3.50.0
         */
        this.lightCount = 0;
    },

    /**
     * Called when the Game has fully booted and the Renderer has finished setting up.
     *
     * By this stage all Game level systems are now in place and you can perform any final
     * tasks that the pipeline may need that relied on game systems such as the Texture Manager.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#boot
     * @since 3.11.0
     */
    boot: function ()
    {
        WebGLPipeline.prototype.boot.call(this);

        var gl = this.gl;

        var tempTexture = gl.createTexture();

        gl.activeTexture(gl.TEXTURE0);

        gl.bindTexture(gl.TEXTURE_2D, tempTexture);

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([ 127, 127, 255, 255 ]));

        this.defaultNormalMap = { glTexture: tempTexture };
    },

    /**
     * Called every time a Game Object needs to use this pipeline.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.MultiPipeline#onBind
     * @since 3.0.0
     *
     * @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object that invoked this pipeline, if any.
     *
     * @return {this} This WebGLPipeline instance.
     */
    onBind: function ()
    {
        this.set1i('uMainSampler', 0);
        this.set1i('uNormSampler', 1);
        this.set2f('uResolution', this.width / 2, this.height / 2);
    },

    /**
     * This function sets all the needed resources for each camera pass.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#onRender
     * @ignore
     * @since 3.0.0
     *
     * @param {Phaser.Scene} scene - The Scene being rendered.
     * @param {Phaser.Cameras.Scene2D.Camera} camera - The Scene Camera being rendered with.
     */
    onRender: function (scene, camera)
    {
        var lightManager = scene.sys.lights;

        if (!lightManager || lightManager.lights.length <= 0 || !lightManager.active)
        {
            return;
        }

        var lights = lightManager.cull(camera);
        var lightCount = Math.min(lights.length, LIGHT_COUNT);

        if (lightCount === 0)
        {
            return;
        }

        var renderer = this.renderer;
        var cameraMatrix = camera.matrix;
        var point = { x: 0, y: 0 };
        var height = renderer.height;
        var i;

        //  Reset lights if we've a different total (probably not strict enough test)
        if (lightCount !== this.lightCount)
        {
            for (i = 0; i < LIGHT_COUNT; i++)
            {
                this.set1f('uLights[' + i + '].radius', 0);
            }

            this.lightCount = lightCount;
        }

        if (camera.dirty)
        {
            this.set4f('uCamera', camera.x, camera.y, camera.rotation, camera.zoom);
        }

        this.set3f('uAmbientLightColor', lightManager.ambientColor.r, lightManager.ambientColor.g, lightManager.ambientColor.b);

        for (i = 0; i < lightCount; i++)
        {
            var light = lights[i];
            var lightName = 'uLights[' + i + '].';

            cameraMatrix.transformPoint(light.x, light.y, point);

            this.set2f(lightName + 'position', point.x - (camera.scrollX * light.scrollFactorX * camera.zoom), height - (point.y - (camera.scrollY * light.scrollFactorY) * camera.zoom));

            if (light.dirty)
            {
                this.set3f(lightName + 'color', light.r, light.g, light.b);
                this.set1f(lightName + 'intensity', light.intensity);
                this.set1f(lightName + 'radius', light.radius);

                light.dirty = false;
            }
        }

        this.currentNormalMapRotation = null;
    },

    /**
     * Rotates the normal map vectors inversely by the given angle.
     * Only works in 2D space.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setNormalMapRotation
     * @since 3.16.0
     *
     * @param {number} rotation - The angle of rotation in radians.
     */
    setNormalMapRotation: function (rotation)
    {
        if (rotation !== this.currentNormalMapRotation || this.vertexCount === 0)
        {
            if (this.vertexCount > 0)
            {
                this.flush();
            }

            var inverseRotationMatrix = this.inverseRotationMatrix;

            if (rotation)
            {
                var rot = -rotation;
                var c = Math.cos(rot);
                var s = Math.sin(rot);

                inverseRotationMatrix[1] = s;
                inverseRotationMatrix[3] = -s;
                inverseRotationMatrix[0] = inverseRotationMatrix[4] = c;
            }
            else
            {
                inverseRotationMatrix[0] = inverseRotationMatrix[4] = 1;
                inverseRotationMatrix[1] = inverseRotationMatrix[3] = 0;
            }

            this.setMatrix3fv('uInverseRotationMatrix', false, inverseRotationMatrix);

            this.currentNormalMapRotation = rotation;
        }
    },

    /**
     * Assigns a texture to the current batch. If a different texture is already set it creates a new batch object.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setTexture2D
     * @ignore
     * @since 3.50.0
     *
     * @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch. If not given uses blankTexture.
     * @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object being rendered or added to the batch.
     */
    setTexture2D: function (texture, gameObject)
    {
        var renderer = this.renderer;

        if (texture === undefined) { texture = renderer.tempTextures[0]; }

        var normalTexture = this.getNormalMap(gameObject);

        if (renderer.isNewNormalMap())
        {
            this.flush();

            renderer.setTextureZero(texture);
            renderer.setNormalMap(normalTexture);
        }

        var rotation = (gameObject) ? gameObject.rotation : 0;

        this.setNormalMapRotation(rotation);

        this.currentUnit = 0;

        return 0;
    },

    /**
     * Custom pipelines can use this method in order to perform any required pre-batch tasks
     * for the given Game Object. It must return the texture unit the Game Object was assigned.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setGameObject
     * @ignore
     * @since 3.50.0
     *
     * @param {Phaser.GameObjects.GameObject} gameObject - The Game Object being rendered or added to the batch.
     * @param {Phaser.Textures.Frame} [frame] - Optional frame to use. Can override that of the Game Object.
     *
     * @return {number} The texture unit the Game Object has been assigned.
     */
    setGameObject: function (gameObject, frame)
    {
        if (frame === undefined) { frame = gameObject.frame; }

        var renderer = this.renderer;
        var texture = frame.glTexture;
        var normalTexture = this.getNormalMap(gameObject);

        if (renderer.isNewNormalMap())
        {
            this.flush();

            renderer.setTextureZero(texture);
            renderer.setNormalMap(normalTexture);
        }

        this.setNormalMapRotation(gameObject.rotation);

        this.currentUnit = 0;

        return 0;
    },

    /**
     * Returns the normal map WebGLTexture from the given Game Object.
     * If the Game Object doesn't have one, it returns the default normal map from this pipeline instead.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#getNormalMap
     * @since 3.50.0
     *
     * @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object to get the normal map from.
     *
     * @return {WebGLTexture} The normal map texture.
     */
    getNormalMap: function (gameObject)
    {
        var normalTexture;

        if (!gameObject)
        {
            normalTexture = this.defaultNormalMap;
        }
        else if (gameObject.displayTexture)
        {
            normalTexture = gameObject.displayTexture.dataSource[gameObject.displayFrame.sourceIndex];
        }
        else if (gameObject.texture)
        {
            normalTexture = gameObject.texture.dataSource[gameObject.frame.sourceIndex];
        }
        else if (gameObject.tileset)
        {
            if (Array.isArray(gameObject.tileset))
            {
                normalTexture = gameObject.tileset[0].image.dataSource[0];
            }
            else
            {
                normalTexture = gameObject.tileset.image.dataSource[0];
            }
        }

        if (!normalTexture)
        {
            normalTexture = this.defaultNormalMap;
        }

        return normalTexture.glTexture;
    }

});

LightPipeline.LIGHT_COUNT = LIGHT_COUNT;

module.exports = LightPipeline;
<commit_msg>Use `onActive` and reset textures, fixing all rendering issues<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @author       Felipe Alfonso <@bitnenfer>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../../utils/Class');
var GetFastValue = require('../../../utils/object/GetFastValue');
var LightShaderSourceFS = require('../shaders/Light-frag.js');
var MultiPipeline = require('./MultiPipeline');
var WebGLPipeline = require('../WebGLPipeline');

var LIGHT_COUNT = 10;

/**
 * @classdesc
 * The Light Pipeline is an extension of the Multi Pipeline and uses a custom shader
 * designed to handle forward diffused rendering of 2D lights in a Scene.
 *
 * The shader works in tandem with Light Game Objects, and optionally texture normal maps,
 * to provide an ambient illumination effect.
 *
 * If you wish to provide your own shader, you can use the `%LIGHT_COUNT%` declaration in the source,
 * and it will be automatically replaced at run-time with the total number of configured lights.
 *
 * The maximum number of lights can be set in the Render Config `maxLights` property and defaults to 10.
 *
 * Prior to Phaser v3.50 this pipeline was called the `ForwardDiffuseLightPipeline`.
 *
 * The fragment shader it uses can be found in `shaders/src/Light.frag`.
 * The vertex shader it uses can be found in `shaders/src/Multi.vert`.
 *
 * The default shader attributes for this pipeline are:
 *
 * `inPosition` (vec2, offset 0)
 * `inTexCoord` (vec2, offset 8)
 * `inTexId` (float, offset 16)
 * `inTintEffect` (float, offset 20)
 * `inTint` (vec4, offset 24, normalized)
 *
 * The default shader uniforms for this pipeline are:
 *
 * `uProjectionMatrix` (mat4)
 * `uViewMatrix` (mat4)
 * `uModelMatrix` (mat4)
 * `uMainSampler` (sampler2D)
 * `uNormSampler` (sampler2D)
 * `uCamera` (vec4)
 * `uResolution` (vec2)
 * `uAmbientLightColor` (vec3)
 * `uInverseRotationMatrix` (mat3)
 * `uLights` (Light struct)
 *
 * @class LightPipeline
 * @extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline
 * @memberof Phaser.Renderer.WebGL.Pipelines
 * @constructor
 * @since 3.50.0
 *
 * @param {Phaser.Types.Renderer.WebGL.WebGLPipelineConfig} config - The configuration options for this pipeline.
 */
var LightPipeline = new Class({

    Extends: MultiPipeline,

    initialize:

    function LightPipeline (config)
    {
        LIGHT_COUNT = config.game.renderer.config.maxLights;

        config.fragShader = GetFastValue(config, 'fragShader', LightShaderSourceFS).replace('%LIGHT_COUNT%', LIGHT_COUNT.toString());

        MultiPipeline.call(this, config);

        /**
         * Inverse rotation matrix for normal map rotations.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#inverseRotationMatrix
         * @type {Float32Array}
         * @private
         * @since 3.16.0
         */
        this.inverseRotationMatrix = new Float32Array([
            1, 0, 0,
            0, 1, 0,
            0, 0, 1
        ]);

        /**
         * Stores a default normal map, which is an object with a `glTexture` property that
         * maps to a 1x1 texture of the color #7f7fff created in the `boot` method.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#defaultNormalMap
         * @type {object}
         * @since 3.50.0
         */
        this.defaultNormalMap;

        /**
         * Stores the previous number of lights rendered.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#lightCount
         * @type {number}
         * @since 3.50.0
         */
        this.lightCount = 0;
    },

    /**
     * Called when the Game has fully booted and the Renderer has finished setting up.
     *
     * By this stage all Game level systems are now in place and you can perform any final
     * tasks that the pipeline may need that relied on game systems such as the Texture Manager.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#boot
     * @since 3.11.0
     */
    boot: function ()
    {
        WebGLPipeline.prototype.boot.call(this);

        var gl = this.gl;

        var tempTexture = gl.createTexture();

        gl.activeTexture(gl.TEXTURE0);

        gl.bindTexture(gl.TEXTURE_2D, tempTexture);

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([ 127, 127, 255, 255 ]));

        this.defaultNormalMap = { glTexture: tempTexture };
    },

    onActive: function ()
    {
        this.renderer.resetTextures();

        this.set1i('uMainSampler', 0);
        this.set1i('uNormSampler', 1);
        this.set2f('uResolution', this.width / 2, this.height / 2);
    },

    /**
     * This function sets all the needed resources for each camera pass.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#onRender
     * @ignore
     * @since 3.0.0
     *
     * @param {Phaser.Scene} scene - The Scene being rendered.
     * @param {Phaser.Cameras.Scene2D.Camera} camera - The Scene Camera being rendered with.
     */
    onRender: function (scene, camera)
    {
        var lightManager = scene.sys.lights;

        if (!lightManager || lightManager.lights.length <= 0 || !lightManager.active)
        {
            return;
        }

        var lights = lightManager.cull(camera);
        var lightCount = Math.min(lights.length, LIGHT_COUNT);

        if (lightCount === 0)
        {
            return;
        }

        var renderer = this.renderer;
        var cameraMatrix = camera.matrix;
        var point = { x: 0, y: 0 };
        var height = renderer.height;
        var i;

        //  Reset lights if we've a different total (probably not strict enough test)
        if (lightCount !== this.lightCount)
        {
            for (i = 0; i < LIGHT_COUNT; i++)
            {
                this.set1f('uLights[' + i + '].radius', 0);
            }

            this.lightCount = lightCount;
        }

        if (camera.dirty)
        {
            this.set4f('uCamera', camera.x, camera.y, camera.rotation, camera.zoom);
        }

        this.set3f('uAmbientLightColor', lightManager.ambientColor.r, lightManager.ambientColor.g, lightManager.ambientColor.b);

        for (i = 0; i < lightCount; i++)
        {
            var light = lights[i];
            var lightName = 'uLights[' + i + '].';

            cameraMatrix.transformPoint(light.x, light.y, point);

            this.set2f(lightName + 'position', point.x - (camera.scrollX * light.scrollFactorX * camera.zoom), height - (point.y - (camera.scrollY * light.scrollFactorY) * camera.zoom));

            if (light.dirty)
            {
                this.set3f(lightName + 'color', light.r, light.g, light.b);
                this.set1f(lightName + 'intensity', light.intensity);
                this.set1f(lightName + 'radius', light.radius);

                light.dirty = false;
            }
        }

        this.currentNormalMapRotation = null;
    },

    /**
     * Rotates the normal map vectors inversely by the given angle.
     * Only works in 2D space.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setNormalMapRotation
     * @since 3.16.0
     *
     * @param {number} rotation - The angle of rotation in radians.
     */
    setNormalMapRotation: function (rotation)
    {
        if (rotation !== this.currentNormalMapRotation || this.vertexCount === 0)
        {
            if (this.vertexCount > 0)
            {
                this.flush();
            }

            var inverseRotationMatrix = this.inverseRotationMatrix;

            if (rotation)
            {
                var rot = -rotation;
                var c = Math.cos(rot);
                var s = Math.sin(rot);

                inverseRotationMatrix[1] = s;
                inverseRotationMatrix[3] = -s;
                inverseRotationMatrix[0] = inverseRotationMatrix[4] = c;
            }
            else
            {
                inverseRotationMatrix[0] = inverseRotationMatrix[4] = 1;
                inverseRotationMatrix[1] = inverseRotationMatrix[3] = 0;
            }

            this.setMatrix3fv('uInverseRotationMatrix', false, inverseRotationMatrix);

            this.currentNormalMapRotation = rotation;
        }
    },

    /**
     * Assigns a texture to the current batch. If a different texture is already set it creates a new batch object.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setTexture2D
     * @ignore
     * @since 3.50.0
     *
     * @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch. If not given uses blankTexture.
     * @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object being rendered or added to the batch.
     */
    setTexture2D: function (texture, gameObject)
    {
        var renderer = this.renderer;

        if (texture === undefined) { texture = renderer.tempTextures[0]; }

        var normalTexture = this.getNormalMap(gameObject);

        if (renderer.isNewNormalMap())
        {
            this.flush();

            renderer.setTextureZero(texture);
            renderer.setNormalMap(normalTexture);
        }

        var rotation = (gameObject) ? gameObject.rotation : 0;

        this.setNormalMapRotation(rotation);

        this.currentUnit = 0;

        return 0;
    },

    /**
     * Custom pipelines can use this method in order to perform any required pre-batch tasks
     * for the given Game Object. It must return the texture unit the Game Object was assigned.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setGameObject
     * @ignore
     * @since 3.50.0
     *
     * @param {Phaser.GameObjects.GameObject} gameObject - The Game Object being rendered or added to the batch.
     * @param {Phaser.Textures.Frame} [frame] - Optional frame to use. Can override that of the Game Object.
     *
     * @return {number} The texture unit the Game Object has been assigned.
     */
    setGameObject: function (gameObject, frame)
    {
        if (frame === undefined) { frame = gameObject.frame; }

        var renderer = this.renderer;
        var texture = frame.glTexture;
        var normalTexture = this.getNormalMap(gameObject);

        if (renderer.isNewNormalMap())
        {
            this.flush();

            renderer.setTextureZero(texture);
            renderer.setNormalMap(normalTexture);
        }

        this.setNormalMapRotation(gameObject.rotation);

        this.currentUnit = 0;

        return 0;
    },

    /**
     * Returns the normal map WebGLTexture from the given Game Object.
     * If the Game Object doesn't have one, it returns the default normal map from this pipeline instead.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#getNormalMap
     * @since 3.50.0
     *
     * @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object to get the normal map from.
     *
     * @return {WebGLTexture} The normal map texture.
     */
    getNormalMap: function (gameObject)
    {
        var normalTexture;

        if (!gameObject)
        {
            normalTexture = this.defaultNormalMap;
        }
        else if (gameObject.displayTexture)
        {
            normalTexture = gameObject.displayTexture.dataSource[gameObject.displayFrame.sourceIndex];
        }
        else if (gameObject.texture)
        {
            normalTexture = gameObject.texture.dataSource[gameObject.frame.sourceIndex];
        }
        else if (gameObject.tileset)
        {
            if (Array.isArray(gameObject.tileset))
            {
                normalTexture = gameObject.tileset[0].image.dataSource[0];
            }
            else
            {
                normalTexture = gameObject.tileset.image.dataSource[0];
            }
        }

        if (!normalTexture)
        {
            normalTexture = this.defaultNormalMap;
        }

        return normalTexture.glTexture;
    }

});

LightPipeline.LIGHT_COUNT = LIGHT_COUNT;

module.exports = LightPipeline;
<|endoftext|>


<commit_before>_gaq.push(['_trackPageview']);

// If awaiting activation
var waiting = true;

// If trusted exit, for exit confirmation
var trustedExit = false;

// Used to fade out subtitles after calculated duration
var subtitleVanishTimer = false;

// Holder object for audio files to test mp3 duration
var subtitleMp3;

// If auto-focus on window to capture key events or not
var autoFocus = 0;

// Critical Animation
var critAnim = false;

// Idle time check
/*
  variables explanation:
  longestIdleTime - high score of idle time
  idleTimer       - timer ID for interval function of idleFunction
  idleTimeout     - timer ID for unsafe idle time marker
  idleFunction    - function that indicates the way of the idle counter
*/
localStorage.longestIdleTime = Math.max(localStorage.longestIdleTime || 0,1800000);
var
	lastRequestMark = Date.now(),
	idleTimer,
	idleTimeout,
	idleFunction;

// Show game screens
function ActivateGame(){
	waiting = false;
	$(".box-wrap").css("background", "#fff");
	$(".box-wait").hide();
	$(".game-swf").remove();
	$(".box-game")
		.prepend("")
		.find(".game-swf")
		.attr("src", "http://www.dmm.com/netgame/social/-/gadgets/=/app_id=854854/")
		.end()
		.show();
	idleTimer = setInterval(idleFunction,1000);
	if(ConfigManager.alert_idle_counter) {
		$(".game-idle-timer").trigger("refresh-tick");
	}
}

$(document).on("ready", function(){
	// Initialize data managers
	ConfigManager.load();
	KC3Master.init();
	RemodelDb.init();
	KC3Meta.init("../../../../data/");
	KC3Meta.loadQuotes();
	KC3QuestManager.load();
	KC3Database.init();
	KC3Translation.execute();

	// Apply interface configs
	$(".box-wrap").css("margin-top", ConfigManager.api_margin+"px");
	if(ConfigManager.api_bg_image === ""){
		$("body").css("background", ConfigManager.api_bg_color);
	}else{
		$("body").css("background-image", "url("+ConfigManager.api_bg_image+")");
		$("body").css("background-color", ConfigManager.api_bg_color);
		$("body").css("background-size", ConfigManager.api_bg_size);
		$("body").css("background-position", ConfigManager.api_bg_position);
		$("body").css("background-repeat", "no-repeat");
	}

	if(ConfigManager.api_subtitles){
		$(".overlay_subtitles").css("font-family", ConfigManager.subtitle_font);
		$(".overlay_subtitles").css("font-size", ConfigManager.subtitle_size);
		if(ConfigManager.subtitle_bold){
			$(".overlay_subtitles").css("font-weight", "bold");
		}
	}

	$(".box-wait").show();

	// Quick Play
	$(".play_btn").on('click', function(){
		ActivateGame();
	});

	// Disable Quick Play (must panel)
	if(ConfigManager.api_mustPanel) {
		$(".play_btn")
			.off('click')
			.text(KC3Meta.term("APIWaitToggle"))
			.css('color','#f00')
			.css('width','40%');
	}

	// Configure Refresh Toggle (using $(".game-refresh").trigger("click") is possible)
	$(".game-refresh").on("click",function(){
		switch($(this).text()) {
			case("01"):
				$(".game-swf").attr("src","about:blank").attr("src",localStorage.absoluteswf);
				$(this).text("05");
				break;
			default:
				$(this).text(($(this).text()-1).toDigits(2));
				break;
		}
	});

	// Configure Idle Timer
	/*
	  unsafe-tick  : remove the safe marker of API idle time
	  refresh-tick : reset the timer and set the idle time as safe zone
	*/
	$(".game-idle-timer").on("unsafe-tick",function(){
		$(".game-idle-timer").removeClass("safe-timer");
	}).on("refresh-tick",function(){
		clearTimeout(idleTimeout);
		$(".game-idle-timer").addClass("safe-timer");
		idleTimeout = setTimeout(function(){
			$(".game-idle-timer").trigger("unsafe-tick");
		},localStorage.longestIdleTime);
	});
	idleFunction = function(){
		if(ConfigManager.alert_idle_counter) {
			$(".game-idle-timer").text(String(Math.floor((Date.now() - lastRequestMark) / 1000)).toHHMMSS());
		} else {
			$(".game-idle-timer").text(String(NaN).toHHMMSS());
			clearInterval(idleTimer);
		}
	};

	// Enable Refresh Toggle
	if(ConfigManager.api_directRefresh) {
		$(".game-refresh").css("display","flex");
	}
	// Show Idle Counter
	if(ConfigManager.alert_idle_counter > 1) {
		$(".game-idle-timer").show();
	}

	// Exit confirmation
	window.onbeforeunload = function(){
		ConfigManager.load();
		// added waiting condition should be ignored
		if(ConfigManager.api_askExit==1 && !trustedExit && !waiting){
			trustedExit = true;
			setTimeout(function(){ trustedExit = false; }, 100);
			return KC3Meta.term("UnwantedExitDMM");
		}
	};

	setInterval(function(){
		if(autoFocus===0){
			window.focus();
			$(".focus_regain").hide();
		}else{
			$(".focus_regain").show();
			$(".focus_val").css("width", (800*(autoFocus/20))+"px");
			autoFocus--;
		}
	}, 1000);

});

$(document).on("keydown", function(event){
	switch(event.keyCode) {
		// F7: Toggle keyboard focus
		case(118):
			autoFocus = 20;
			return false;

		// F9: Screenshot
		case(120):
			(new KCScreenshot()).start("Auto", $(".box-wrap"));
			return false;

		// F10: Clear overlays
		case(121):
			interactions.clearOverlays({}, {}, function(){});
			return false;

		// Other else
		default:
		break;
	}
});

/* Invokable actions
-----------------------------------*/
var interactions = {

	// Panel is opened, activate the game
	activateGame :function(request, sender, response){
		if(waiting){
			ActivateGame();
			response({success:true});
		}else{
			response({success:false});
		}
	},

	// Cat Bomb Detection -> Enforced
	catBomb :function(request, sender, response){
		try{
			switch(ConfigManager.api_directRefresh) {
				case 0:
					throw new Error("");
				case 1:
					$(".game-refresh").text((0).toDigits(2)).css('right','0px');
					break;
				default:
					// TODO : Forced API Link Refresh
					$(".game-refresh").text((0).toDigits(2)).trigger('bomb-exploded');
					break;
			}
			response({success:true});
		}catch(e){
			console.error(e);
		}finally{
			response({success:false});
		}
	},

	// Request OK Marker
	goodResponses :function(request, sender, response){
		if(request.tcp_status === 200 && request.api_status === 1) {
			localStorage.longestIdleTime = Math.max(localStorage.longestIdleTime,Date.now() - lastRequestMark);
			lastRequestMark = Date.now();
			$(".game-idle-timer").trigger("refresh-tick");
			clearInterval(idleTimer);
			idleTimer = setInterval(idleFunction,1000);
			idleFunction();
		} else {
			clearInterval(idleTimer);
			clearTimeout(idleTimeout);
			$(".game-idle-timer").trigger("unsafe-tick");
			console.error("API Link cease to functioning anymore after",String(Math.floor((Date.now() - lastRequestMark)/1000)).toHHMMSS(),"idle time");
		}
	},

	// Quest page is opened, show overlays
	questOverlay :function(request, sender, response){
		//Only skip overlay generation if neither of the overlay features is enabled.
		if(!ConfigManager.api_translation && !ConfigManager.api_tracking){ response({success:false}); return true; }

		KC3QuestManager.load();
		$.each(request.questlist, function( index, QuestRaw ){
			// console.log("showing quest",QuestRaw);
			if( QuestRaw !=- 1 ){
				var QuestBox = $("#factory .ol_quest_exist").clone().appendTo(".overlay_quests");

				// Get quest data
				var QuestData = KC3QuestManager.get( QuestRaw.api_no );

				// Show meta, title and description
				if( typeof QuestData.meta().available != "undefined" ){

					if (ConfigManager.api_translation){
						$(".name", QuestBox).text( QuestData.meta().name );
						$(".desc", QuestBox).text( QuestData.meta().desc );
					}else{
						$(".content", QuestBox).css({opacity: 0});
					}

					if(ConfigManager.api_tracking){
						$(".tracking", QuestBox).html( QuestData.outputHtml() );
					}else{
						$(".tracking", QuestBox).hide();
					}

					// Special Bw1 case multiple requirements
					if( QuestRaw.api_no == 214 ){
						$(".tracking", QuestBox).addClass("small");
					}
				}else{
					QuestBox.css({ visibility: "hidden" });
				}
			}
		});
		response({success:true});
	},

	// Quest Progress Notification
	questProgress :function(request, sender, response){

		response({success:true});
	},

	// In-game record screen translation
	recordOverlay :function(request, sender, response){
		// app.Dom.applyRecordOverlay(request.record);
		response({success:true});
	},

	// Remove HTML overlays
	clearOverlays :function(request, sender, response){
		// console.log("clearing overlays");
		// app.Dom.clearOverlays();
		$(".overlay_quests").html("");
		$(".overlay_record").hide();
		response({success:true});
	},

	// Screenshot triggered, capture the visible tab
	screenshot :function(request, sender, response){
		// ~Please rewrite the screenshot script
		(new KCScreenshot()).start(request.playerName, $(".box-wrap"));
		response({success:true});
	},

	// Fit screen
	fitScreen :function(request, sender, response){
		// Get browser zoon level for the page
		chrome.tabs.getZoom(null, function(ZoomFactor){
			// Resize the window
			chrome.windows.getCurrent(function(wind){
				chrome.windows.update(wind.id, {
					width: Math.ceil(800*ZoomFactor) + (wind.width- Math.ceil($(window).width()*ZoomFactor) ),
					height: Math.ceil(480*ZoomFactor) + (wind.height- Math.ceil($(window).height()*ZoomFactor) )
				});
			});
		});
	},

	// Taiha Alert Start
	taihaAlertStart :function(request, sender, response){
		$(".box-wrap").addClass("critical");

		if(critAnim){ clearInterval(critAnim); }
		critAnim = setInterval(function() {
			$(".taiha_red").toggleClass("anim2");
		}, 500);

		$(".taiha_blood").show();
		$(".taiha_red").show();
	},

	// Taiha Alert Stop
	taihaAlertStop :function(request, sender, response){
		$(".box-wrap").removeClass("critical");
		if(critAnim){ clearInterval(critAnim); }
		$(".taiha_blood").hide();
		$(".taiha_red").hide();
	},

	// Show subtitles
	subtitle :function(request, sender, response){
		if(!ConfigManager.api_subtitles) return true;

		console.log("subtitle", request);

		// Get subtitle text
		var subtitleText = false;
		var quoteIdentifier = "";
		var quoteVoiceNum = request.voiceNum;
		switch(request.voicetype){
			case "titlecall":
				quoteIdentifier = "titlecall_"+request.filename;
				break;
			case "npc":
				quoteIdentifier = "npc";
				break;
			default:
				quoteIdentifier = request.shipID;
				break;
		}
		subtitleText = KC3Meta.quote( quoteIdentifier, quoteVoiceNum );

		// hide first to fading will stop
		$(".overlay_subtitles").stop(true, true);
		$(".overlay_subtitles").hide();

		// If subtitle removal timer is ongoing, reset
		if(subtitleVanishTimer){
			clearTimeout(subtitleVanishTimer);
		}

		// If subtitles available for the voice
		if(subtitleText){
			$(".overlay_subtitles").html(subtitleText);
			$(".overlay_subtitles").show();
			subtitleVanishTimer = setTimeout(function(){
				subtitleVanishTimer = false;
				$(".overlay_subtitles").fadeOut(2000);
			}, (2000+ ($(".overlay_subtitles").text().length*50)) );
		}
	},

	// Dummy action
	dummy :function(request, sender, response){

	}
};

/* Listen to messaging triggers
-----------------------------------*/
chrome.runtime.onMessage.addListener(function(request, sender, response){
	// If request is for this script
	if((request.identifier||"") == "kc3_gamescreen"){
		// If action requested is supported
		if(typeof interactions[request.action] !== "undefined"){
			// Execute the action
			interactions[request.action](request, sender, response);
			return true;
		}
	}
});
<commit_msg>Sync vanishing timing of subtitles feature to dmm.js<commit_after>_gaq.push(['_trackPageview']);

// If awaiting activation
var waiting = true;

// If trusted exit, for exit confirmation
var trustedExit = false;

// Used to fade out subtitles after calculated duration
var subtitleVanishTimer = false;
var subtitleVanishBaseMillis;
var subtitleVanishExtraMillisPerChar;

// Holder object for audio files to test mp3 duration
var subtitleMp3;

// If auto-focus on window to capture key events or not
var autoFocus = 0;

// Critical Animation
var critAnim = false;

// Idle time check
/*
  variables explanation:
  longestIdleTime - high score of idle time
  idleTimer       - timer ID for interval function of idleFunction
  idleTimeout     - timer ID for unsafe idle time marker
  idleFunction    - function that indicates the way of the idle counter
*/
localStorage.longestIdleTime = Math.max(localStorage.longestIdleTime || 0,1800000);
var
	lastRequestMark = Date.now(),
	idleTimer,
	idleTimeout,
	idleFunction;

// Show game screens
function ActivateGame(){
	waiting = false;
	$(".box-wrap").css("background", "#fff");
	$(".box-wait").hide();
	$(".game-swf").remove();
	$(".box-game")
		.prepend("")
		.find(".game-swf")
		.attr("src", "http://www.dmm.com/netgame/social/-/gadgets/=/app_id=854854/")
		.end()
		.show();
	idleTimer = setInterval(idleFunction,1000);
	if(ConfigManager.alert_idle_counter) {
		$(".game-idle-timer").trigger("refresh-tick");
	}
}

$(document).on("ready", function(){
	// Initialize data managers
	ConfigManager.load();
	KC3Master.init();
	RemodelDb.init();
	KC3Meta.init("../../../../data/");
	KC3Meta.loadQuotes();
	KC3QuestManager.load();
	KC3Database.init();
	KC3Translation.execute();

	// Apply interface configs
	$(".box-wrap").css("margin-top", ConfigManager.api_margin+"px");
	if(ConfigManager.api_bg_image === ""){
		$("body").css("background", ConfigManager.api_bg_color);
	}else{
		$("body").css("background-image", "url("+ConfigManager.api_bg_image+")");
		$("body").css("background-color", ConfigManager.api_bg_color);
		$("body").css("background-size", ConfigManager.api_bg_size);
		$("body").css("background-position", ConfigManager.api_bg_position);
		$("body").css("background-repeat", "no-repeat");
	}

	if(ConfigManager.api_subtitles){
		$(".overlay_subtitles").css("font-family", ConfigManager.subtitle_font);
		$(".overlay_subtitles").css("font-size", ConfigManager.subtitle_size);
		if(ConfigManager.subtitle_bold){
			$(".overlay_subtitles").css("font-weight", "bold");
		}
	}

	$(".box-wait").show();

	// Quick Play
	$(".play_btn").on('click', function(){
		ActivateGame();
	});

	// Disable Quick Play (must panel)
	if(ConfigManager.api_mustPanel) {
		$(".play_btn")
			.off('click')
			.text(KC3Meta.term("APIWaitToggle"))
			.css('color','#f00')
			.css('width','40%');
	}

	// Configure Refresh Toggle (using $(".game-refresh").trigger("click") is possible)
	$(".game-refresh").on("click",function(){
		switch($(this).text()) {
			case("01"):
				$(".game-swf").attr("src","about:blank").attr("src",localStorage.absoluteswf);
				$(this).text("05");
				break;
			default:
				$(this).text(($(this).text()-1).toDigits(2));
				break;
		}
	});

	// Configure Idle Timer
	/*
	  unsafe-tick  : remove the safe marker of API idle time
	  refresh-tick : reset the timer and set the idle time as safe zone
	*/
	$(".game-idle-timer").on("unsafe-tick",function(){
		$(".game-idle-timer").removeClass("safe-timer");
	}).on("refresh-tick",function(){
		clearTimeout(idleTimeout);
		$(".game-idle-timer").addClass("safe-timer");
		idleTimeout = setTimeout(function(){
			$(".game-idle-timer").trigger("unsafe-tick");
		},localStorage.longestIdleTime);
	});
	idleFunction = function(){
		if(ConfigManager.alert_idle_counter) {
			$(".game-idle-timer").text(String(Math.floor((Date.now() - lastRequestMark) / 1000)).toHHMMSS());
		} else {
			$(".game-idle-timer").text(String(NaN).toHHMMSS());
			clearInterval(idleTimer);
		}
	};

	// Enable Refresh Toggle
	if(ConfigManager.api_directRefresh) {
		$(".game-refresh").css("display","flex");
	}
	// Show Idle Counter
	if(ConfigManager.alert_idle_counter > 1) {
		$(".game-idle-timer").show();
	}

	// Exit confirmation
	window.onbeforeunload = function(){
		ConfigManager.load();
		// added waiting condition should be ignored
		if(ConfigManager.api_askExit==1 && !trustedExit && !waiting){
			trustedExit = true;
			setTimeout(function(){ trustedExit = false; }, 100);
			return KC3Meta.term("UnwantedExitDMM");
		}
	};

	setInterval(function(){
		if(autoFocus===0){
			window.focus();
			$(".focus_regain").hide();
		}else{
			$(".focus_regain").show();
			$(".focus_val").css("width", (800*(autoFocus/20))+"px");
			autoFocus--;
		}
	}, 1000);

});

$(document).on("keydown", function(event){
	switch(event.keyCode) {
		// F7: Toggle keyboard focus
		case(118):
			autoFocus = 20;
			return false;

		// F9: Screenshot
		case(120):
			(new KCScreenshot()).start("Auto", $(".box-wrap"));
			return false;

		// F10: Clear overlays
		case(121):
			interactions.clearOverlays({}, {}, function(){});
			return false;

		// Other else
		default:
		break;
	}
});

/* Invokable actions
-----------------------------------*/
var interactions = {

	// Panel is opened, activate the game
	activateGame :function(request, sender, response){
		if(waiting){
			ActivateGame();
			response({success:true});
		}else{
			response({success:false});
		}
	},

	// Cat Bomb Detection -> Enforced
	catBomb :function(request, sender, response){
		try{
			switch(ConfigManager.api_directRefresh) {
				case 0:
					throw new Error("");
				case 1:
					$(".game-refresh").text((0).toDigits(2)).css('right','0px');
					break;
				default:
					// TODO : Forced API Link Refresh
					$(".game-refresh").text((0).toDigits(2)).trigger('bomb-exploded');
					break;
			}
			response({success:true});
		}catch(e){
			console.error(e);
		}finally{
			response({success:false});
		}
	},

	// Request OK Marker
	goodResponses :function(request, sender, response){
		if(request.tcp_status === 200 && request.api_status === 1) {
			localStorage.longestIdleTime = Math.max(localStorage.longestIdleTime,Date.now() - lastRequestMark);
			lastRequestMark = Date.now();
			$(".game-idle-timer").trigger("refresh-tick");
			clearInterval(idleTimer);
			idleTimer = setInterval(idleFunction,1000);
			idleFunction();
		} else {
			clearInterval(idleTimer);
			clearTimeout(idleTimeout);
			$(".game-idle-timer").trigger("unsafe-tick");
			console.error("API Link cease to functioning anymore after",String(Math.floor((Date.now() - lastRequestMark)/1000)).toHHMMSS(),"idle time");
		}
	},

	// Quest page is opened, show overlays
	questOverlay :function(request, sender, response){
		//Only skip overlay generation if neither of the overlay features is enabled.
		if(!ConfigManager.api_translation && !ConfigManager.api_tracking){ response({success:false}); return true; }

		KC3QuestManager.load();
		$.each(request.questlist, function( index, QuestRaw ){
			// console.log("showing quest",QuestRaw);
			if( QuestRaw !=- 1 ){
				var QuestBox = $("#factory .ol_quest_exist").clone().appendTo(".overlay_quests");

				// Get quest data
				var QuestData = KC3QuestManager.get( QuestRaw.api_no );

				// Show meta, title and description
				if( typeof QuestData.meta().available != "undefined" ){

					if (ConfigManager.api_translation){
						$(".name", QuestBox).text( QuestData.meta().name );
						$(".desc", QuestBox).text( QuestData.meta().desc );
					}else{
						$(".content", QuestBox).css({opacity: 0});
					}

					if(ConfigManager.api_tracking){
						$(".tracking", QuestBox).html( QuestData.outputHtml() );
					}else{
						$(".tracking", QuestBox).hide();
					}

					// Special Bw1 case multiple requirements
					if( QuestRaw.api_no == 214 ){
						$(".tracking", QuestBox).addClass("small");
					}
				}else{
					QuestBox.css({ visibility: "hidden" });
				}
			}
		});
		response({success:true});
	},

	// Quest Progress Notification
	questProgress :function(request, sender, response){

		response({success:true});
	},

	// In-game record screen translation
	recordOverlay :function(request, sender, response){
		// app.Dom.applyRecordOverlay(request.record);
		response({success:true});
	},

	// Remove HTML overlays
	clearOverlays :function(request, sender, response){
		// console.log("clearing overlays");
		// app.Dom.clearOverlays();
		$(".overlay_quests").html("");
		$(".overlay_record").hide();
		response({success:true});
	},

	// Screenshot triggered, capture the visible tab
	screenshot :function(request, sender, response){
		// ~Please rewrite the screenshot script
		(new KCScreenshot()).start(request.playerName, $(".box-wrap"));
		response({success:true});
	},

	// Fit screen
	fitScreen :function(request, sender, response){
		// Get browser zoon level for the page
		chrome.tabs.getZoom(null, function(ZoomFactor){
			// Resize the window
			chrome.windows.getCurrent(function(wind){
				chrome.windows.update(wind.id, {
					width: Math.ceil(800*ZoomFactor) + (wind.width- Math.ceil($(window).width()*ZoomFactor) ),
					height: Math.ceil(480*ZoomFactor) + (wind.height- Math.ceil($(window).height()*ZoomFactor) )
				});
			});
		});
	},

	// Taiha Alert Start
	taihaAlertStart :function(request, sender, response){
		$(".box-wrap").addClass("critical");

		if(critAnim){ clearInterval(critAnim); }
		critAnim = setInterval(function() {
			$(".taiha_red").toggleClass("anim2");
		}, 500);

		$(".taiha_blood").show();
		$(".taiha_red").show();
	},

	// Taiha Alert Stop
	taihaAlertStop :function(request, sender, response){
		$(".box-wrap").removeClass("critical");
		if(critAnim){ clearInterval(critAnim); }
		$(".taiha_blood").hide();
		$(".taiha_red").hide();
	},

	// Show subtitles
	subtitle :function(request, sender, response){
		if(!ConfigManager.api_subtitles) return true;

		console.debug("subtitle", request);

		// Get subtitle text
		var subtitleText = false;
		var quoteIdentifier = "";
		var quoteVoiceNum = request.voiceNum;
		switch(request.voicetype){
			case "titlecall":
				quoteIdentifier = "titlecall_"+request.filename;
				break;
			case "npc":
				quoteIdentifier = "npc";
				break;
			default:
				quoteIdentifier = request.shipID;
				break;
		}
		subtitleText = KC3Meta.quote( quoteIdentifier, quoteVoiceNum );

		// hide first to fading will stop
		$(".overlay_subtitles").stop(true, true);
		$(".overlay_subtitles").hide();

		// If subtitle removal timer is ongoing, reset
		if(subtitleVanishTimer){
			clearTimeout(subtitleVanishTimer);
		}
		// Lazy init timing parameters
		if(!subtitleVanishBaseMillis){
			subtitleVanishBaseMillis = Number(KC3Meta.quote("timing", "baseMillisVoiceLine")) || 2000;
		}
		if(!subtitleVanishExtraMillisPerChar){
			subtitleVanishExtraMillisPerChar = Number(KC3Meta.quote("timing", "extraMillisPerChar")) || 50;
		}

		// If subtitles available for the voice
		if(subtitleText){
			$(".overlay_subtitles").html(subtitleText);
			$(".overlay_subtitles").show();
			var millis = subtitleVanishBaseMillis +
				(subtitleVanishExtraMillisPerChar * $(".overlay_subtitles").text().length);
			console.debug("vanish after", millis, "ms");
			subtitleVanishTimer = setTimeout(function(){
				subtitleVanishTimer = false;
				$(".overlay_subtitles").fadeOut(2000);
			}, millis);
		}
	},

	// Dummy action
	dummy :function(request, sender, response){

	}
};

/* Listen to messaging triggers
-----------------------------------*/
chrome.runtime.onMessage.addListener(function(request, sender, response){
	// If request is for this script
	if((request.identifier||"") == "kc3_gamescreen"){
		// If action requested is supported
		if(typeof interactions[request.action] !== "undefined"){
			// Execute the action
			interactions[request.action](request, sender, response);
			return true;
		}
	}
});
<|endoftext|>


<commit_before>var assert = require('assert'),
    _ = require('lodash');

describe('Association Interface', function() {

  describe('n:m association :: .find().populate([WHERE])', function() {

    /////////////////////////////////////////////////////
    // TEST SETUP
    ////////////////////////////////////////////////////

    var driverRecord;

    before(function(done) {
      Associations.Driver.create({ name: 'manymany find where'}, function(err, driver) {
        if(err) return done(err);

        driverRecord = driver;

        var taxis = [];
        for(var i=0; i<4; i++) {
          driverRecord.taxis.add({ medallion: i });
        }

        driverRecord.save(function(err) {
          if(err) return done(err);
          done();
        });
      });
    });

    /////////////////////////////////////////////////////
    // TEST METHODS
    ////////////////////////////////////////////////////

    it('should return only taxis with medallions less than 2', function(done) {
      Associations.Driver.find({ name: 'manymany find where' })
      .populate('taxis', { medallion: { '<': 2 }})
      .exec(function(err, drivers) {
        assert(!err, err);

        assert(Array.isArray(drivers));
        assert(drivers.length === 1);
        assert(Array.isArray(drivers[0].taxis));
        assert(drivers[0].taxis.length === 2, 'Expected first driver to have 2 taxis, but got '+drivers[0].taxis.length+', see?\n'+require('util').inspect(drivers[0]) );

        done();
      });
    });

    it('should return taxis using skip and limit', function(done) {
      Associations.Driver.find({ name: 'manymany find where' })
      .populate('taxis', { skip: 1, limit: 2 })
      .exec(function(err, drivers) {
        assert(!err, err);

        assert(Array.isArray(drivers));
        assert(drivers.length === 1);

        assert(Array.isArray(drivers[0].taxis));

        assert(drivers[0].taxis.length === 2, 'Expected first driver to have 2 taxis, but got '+drivers[0].taxis.length+', see?\n'+require('util').inspect(drivers[0]));
        console.log(drivers);
        /*
        assert.equal(drivers[0].taxis[0].medallion, 1, 'Expected first driver\'s first taxi to have medallion===1, but heres what I got for the first driver: '+require('util').inspect(drivers[0], false, null));
        assert.equal(drivers[0].taxis[1].medallion, 2, 'Expected first driver\'s second taxi to have medallion===2, but heres what I got for the first driver: '+require('util').inspect(drivers[0], false, null));
        */

        done();
      });
    });

  });
});
<commit_msg>remove log statement<commit_after>var assert = require('assert'),
    _ = require('lodash');

describe('Association Interface', function() {

  describe('n:m association :: .find().populate([WHERE])', function() {

    /////////////////////////////////////////////////////
    // TEST SETUP
    ////////////////////////////////////////////////////

    var driverRecord;

    before(function(done) {
      Associations.Driver.create({ name: 'manymany find where'}, function(err, driver) {
        if(err) return done(err);

        driverRecord = driver;

        var taxis = [];
        for(var i=0; i<4; i++) {
          driverRecord.taxis.add({ medallion: i });
        }

        driverRecord.save(function(err) {
          if(err) return done(err);
          done();
        });
      });
    });

    /////////////////////////////////////////////////////
    // TEST METHODS
    ////////////////////////////////////////////////////

    it('should return only taxis with medallions less than 2', function(done) {
      Associations.Driver.find({ name: 'manymany find where' })
      .populate('taxis', { medallion: { '<': 2 }})
      .exec(function(err, drivers) {
        assert(!err, err);

        assert(Array.isArray(drivers));
        assert(drivers.length === 1);
        assert(Array.isArray(drivers[0].taxis));
        assert(drivers[0].taxis.length === 2, 'Expected first driver to have 2 taxis, but got '+drivers[0].taxis.length+', see?\n'+require('util').inspect(drivers[0]) );

        done();
      });
    });

    it('should return taxis using skip and limit', function(done) {
      Associations.Driver.find({ name: 'manymany find where' })
      .populate('taxis', { skip: 1, limit: 2 })
      .exec(function(err, drivers) {
        assert(!err, err);

        assert(Array.isArray(drivers));
        assert(drivers.length === 1);

        assert(Array.isArray(drivers[0].taxis));

        assert(drivers[0].taxis.length === 2, 'Expected first driver to have 2 taxis, but got '+drivers[0].taxis.length+', see?\n'+require('util').inspect(drivers[0]));
        /*
        assert.equal(drivers[0].taxis[0].medallion, 1, 'Expected first driver\'s first taxi to have medallion===1, but heres what I got for the first driver: '+require('util').inspect(drivers[0], false, null));
        assert.equal(drivers[0].taxis[1].medallion, 2, 'Expected first driver\'s second taxi to have medallion===2, but heres what I got for the first driver: '+require('util').inspect(drivers[0], false, null));
        */

        done();
      });
    });

  });
});
<|endoftext|>