<commit_before>(function(global) {

  /**
   * Class: RemoteStorage.IndexedDB
   *
   *
   * IndexedDB Interface
   * -------------------
   *
   * TODO rewrite, doesn't expose GPD anymore, it's in cachinglayer now
   *
   * This file exposes a get/put/delete interface, accessing data in an IndexedDB.
   *
   * There are multiple parts to this interface:
   *
   *   The RemoteStorage integration:
   *     - RemoteStorage.IndexedDB._rs_supported() determines if IndexedDB support
   *       is available. If it isn't, RemoteStorage won't initialize the feature.
   *     - RemoteStorage.IndexedDB._rs_init() initializes the feature. It returns
   *       a promise that is fulfilled as soon as the database has been opened and
   *       migrated.
   *
   *   The storage interface (RemoteStorage.IndexedDB object):
   *     - Usually this is accessible via "remoteStorage.local"
   *     - #get() takes a path and returns a promise.
   *     - #put() takes a path, body and contentType and also returns a promise.
   *     - #delete() takes a path and also returns a promise.
   *     - #on('change', ...) events, being fired whenever something changes in
   *       the storage. Change events roughly follow the StorageEvent pattern.
   *       They have "oldValue" and "newValue" properties, which can be used to
   *       distinguish create/update/delete operations and analyze changes in
   *       change handlers. In addition they carry a "origin" property, which
   *       is either "window", "local", or "remote". "remote" events are fired
   *       whenever a change comes in from RemoteStorage.Sync. In the future,
   *       "device" origin events will also be fired for changes happening in
   *       other windows on the same device.
   *
   *   The sync interface (also on RemoteStorage.IndexedDB object):
   *     - #getNodes([paths]) returns the requested nodes in a promise.
   *     - #setNodes(map) stores all the nodes given in the (path -> node) map.
   *
   */

  var RS = RemoteStorage;

  var DB_VERSION = 2;

  var DEFAULT_DB_NAME = 'remotestorage';
  var DEFAULT_DB;

  RS.IndexedDB = function(database) {
    this.db = database || DEFAULT_DB;

    if (!this.db) {
      RemoteStorage.log("Failed to open indexedDB");
      return undefined;
    }

    RS.cachingLayer(this);
    RS.eventHandling(this, 'change');

    this.getsRunning = 0;
    this.putsRunning = 0;
  };

  RS.IndexedDB.prototype = {
    getNodes: function(paths) {
      var promise = promising();
      var transaction = this.db.transaction(['nodes'], 'readonly');
      var nodes = transaction.objectStore('nodes');
      var retrievedNodes = {};
      var startTime = new Date().getTime();

      this.getsRunning++;

      for (var i=0; i<paths.length; i++) {
        (function(index) {
          var path = paths[index];
          nodes.get(path).onsuccess = function(evt) {
            retrievedNodes[path] = evt.target.result;
          };
        })(i);
      }

      transaction.oncomplete = function() {
        promise.fulfill(retrievedNodes);
        this.getsRunning--;
      }.bind(this);

      transaction.onerror = transaction.onabort = function() {
        promise.reject('get transaction error/abort');
        this.getsRunning--;
      }.bind(this);

      return promise;
    },

    setNodes: function(nodes) {
      var promise = promising();
      var transaction = this.db.transaction(['nodes'], 'readwrite');
      var nodesStore = transaction.objectStore('nodes');
      var startTime = new Date().getTime();

      this.putsRunning++;

      RemoteStorage.log('Starting put', nodes, this.putsRunning);

      for (var path in nodes) {
        var node = nodes[path];
        if(typeof(node) === 'object') {
          try {
            nodesStore.put(node);
          } catch(e) {
            RemoteStorage.log('Error while putting', node, e);
            throw e;
          }
        } else {
          try {
            nodesStore.delete(path);
          } catch(e) {
            RemoteStorage.log('Error while removing', nodesStore, node, e);
            throw e;
          }
        }
      }

      transaction.oncomplete = function() {
        promise.fulfill();
        this.putsRunning--;
        RemoteStorage.log('Finished put', nodes, this.putsRunning, (new Date().getTime() - startTime)+'ms');
      }.bind(this);

      transaction.onerror = function() {
        promise.reject('transaction error');
        this.putsRunning--;
      }.bind(this);

      transaction.onabort = function() {
        promise.reject('transaction abort');
        this.putsRunning--;
      }.bind(this);

      return promise;
    },

    reset: function(callback) {
      var dbName = this.db.name;
      var self = this;

      this.db.close();

      RS.IndexedDB.clean(this.db.name, function() {
        RS.IndexedDB.open(dbName, function(other) {
          // hacky!
          self.db = other.db;
          callback(self);
        });
      });
    },

    forAllNodes: function(cb) {
      var promise = promising();
      var transaction = this.db.transaction(['nodes'], 'readonly');
      var cursorReq = transaction.objectStore('nodes').openCursor();

      cursorReq.onsuccess = function(evt) {
        var cursor = evt.target.result;

        if (cursor) {
          cb(this.migrate(cursor.value));
          cursor.continue();
        } else {
          promise.fulfill();
        }
      }.bind(this);

      return promise;
    },

    closeDB: function() {
      this.db.close();
    }

  };

  RS.IndexedDB.open = function(name, callback) {
    var timer = setTimeout(function() {
      callback("timeout trying to open db");
    }, 10000);

    var req = indexedDB.open(name, DB_VERSION);

    req.onerror = function() {
      RemoteStorage.log('Opening DB failed', req);

      clearTimeout(timer);
      callback(req.error);
    };

    req.onupgradeneeded = function(event) {
      var db = req.result;

      RemoteStorage.log("[IndexedDB] Upgrade: from ", event.oldVersion, " to ", event.newVersion);

      if (event.oldVersion !== 1) {
        RemoteStorage.log("[IndexedDB] Creating object store: nodes");
        db.createObjectStore('nodes', { keyPath: 'path' });
      }

      RemoteStorage.log("[IndexedDB] Creating object store: changes");

      db.createObjectStore('changes', { keyPath: 'path' });
    };

    req.onsuccess = function() {
      clearTimeout(timer);
      callback(null, req.result);
    };
  };

  RS.IndexedDB.clean = function(databaseName, callback) {
    var req = indexedDB.deleteDatabase(databaseName);

    req.onsuccess = function() {
      RemoteStorage.log('Done removing DB');
      callback();
    };

    req.onerror = req.onabort = function(evt) {
      console.error('Failed to remove database "' + databaseName + '"', evt);
    };
  };

  RS.IndexedDB._rs_init = function(remoteStorage) {
    var promise = promising();

    RS.IndexedDB.open(DEFAULT_DB_NAME, function(err, db) {
      if (err) {
        promise.reject(err);
      } else {
        DEFAULT_DB = db;
        db.onerror = function() { remoteStorage._emit('error', err); };
        promise.fulfill();
      }
    });

    return promise;
  };

  RS.IndexedDB._rs_supported = function() {
    return ('indexedDB' in global);
  };

  RS.IndexedDB._rs_cleanup = function(remoteStorage) {
    var promise = promising();

    if (remoteStorage.local) {
      remoteStorage.local.closeDB();
    }

    RS.IndexedDB.clean(DEFAULT_DB_NAME, function() {
      promise.fulfill();
    });

    return promise;
  };

})(typeof(window) !== 'undefined' ? window : global);
<commit_msg>Fix IndexedDB feature detection (esp. FF priv mode, fixes #621)<commit_after>(function(global) {

  /**
   * Class: RemoteStorage.IndexedDB
   *
   *
   * IndexedDB Interface
   * -------------------
   *
   * TODO rewrite, doesn't expose GPD anymore, it's in cachinglayer now
   *
   * This file exposes a get/put/delete interface, accessing data in an IndexedDB.
   *
   * There are multiple parts to this interface:
   *
   *   The RemoteStorage integration:
   *     - RemoteStorage.IndexedDB._rs_supported() determines if IndexedDB support
   *       is available. If it isn't, RemoteStorage won't initialize the feature.
   *     - RemoteStorage.IndexedDB._rs_init() initializes the feature. It returns
   *       a promise that is fulfilled as soon as the database has been opened and
   *       migrated.
   *
   *   The storage interface (RemoteStorage.IndexedDB object):
   *     - Usually this is accessible via "remoteStorage.local"
   *     - #get() takes a path and returns a promise.
   *     - #put() takes a path, body and contentType and also returns a promise.
   *     - #delete() takes a path and also returns a promise.
   *     - #on('change', ...) events, being fired whenever something changes in
   *       the storage. Change events roughly follow the StorageEvent pattern.
   *       They have "oldValue" and "newValue" properties, which can be used to
   *       distinguish create/update/delete operations and analyze changes in
   *       change handlers. In addition they carry a "origin" property, which
   *       is either "window", "local", or "remote". "remote" events are fired
   *       whenever a change comes in from RemoteStorage.Sync. In the future,
   *       "device" origin events will also be fired for changes happening in
   *       other windows on the same device.
   *
   *   The sync interface (also on RemoteStorage.IndexedDB object):
   *     - #getNodes([paths]) returns the requested nodes in a promise.
   *     - #setNodes(map) stores all the nodes given in the (path -> node) map.
   *
   */

  var RS = RemoteStorage;

  var DB_VERSION = 2;

  var DEFAULT_DB_NAME = 'remotestorage';
  var DEFAULT_DB;

  RS.IndexedDB = function(database) {
    this.db = database || DEFAULT_DB;

    if (!this.db) {
      RemoteStorage.log("Failed to open indexedDB");
      return undefined;
    }

    RS.cachingLayer(this);
    RS.eventHandling(this, 'change');

    this.getsRunning = 0;
    this.putsRunning = 0;
  };

  RS.IndexedDB.prototype = {
    getNodes: function(paths) {
      var promise = promising();
      var transaction = this.db.transaction(['nodes'], 'readonly');
      var nodes = transaction.objectStore('nodes');
      var retrievedNodes = {};
      var startTime = new Date().getTime();

      this.getsRunning++;

      for (var i=0; i<paths.length; i++) {
        (function(index) {
          var path = paths[index];
          nodes.get(path).onsuccess = function(evt) {
            retrievedNodes[path] = evt.target.result;
          };
        })(i);
      }

      transaction.oncomplete = function() {
        promise.fulfill(retrievedNodes);
        this.getsRunning--;
      }.bind(this);

      transaction.onerror = transaction.onabort = function() {
        promise.reject('get transaction error/abort');
        this.getsRunning--;
      }.bind(this);

      return promise;
    },

    setNodes: function(nodes) {
      var promise = promising();
      var transaction = this.db.transaction(['nodes'], 'readwrite');
      var nodesStore = transaction.objectStore('nodes');
      var startTime = new Date().getTime();

      this.putsRunning++;

      RemoteStorage.log('Starting put', nodes, this.putsRunning);

      for (var path in nodes) {
        var node = nodes[path];
        if(typeof(node) === 'object') {
          try {
            nodesStore.put(node);
          } catch(e) {
            RemoteStorage.log('Error while putting', node, e);
            throw e;
          }
        } else {
          try {
            nodesStore.delete(path);
          } catch(e) {
            RemoteStorage.log('Error while removing', nodesStore, node, e);
            throw e;
          }
        }
      }

      transaction.oncomplete = function() {
        promise.fulfill();
        this.putsRunning--;
        RemoteStorage.log('Finished put', nodes, this.putsRunning, (new Date().getTime() - startTime)+'ms');
      }.bind(this);

      transaction.onerror = function() {
        promise.reject('transaction error');
        this.putsRunning--;
      }.bind(this);

      transaction.onabort = function() {
        promise.reject('transaction abort');
        this.putsRunning--;
      }.bind(this);

      return promise;
    },

    reset: function(callback) {
      var dbName = this.db.name;
      var self = this;

      this.db.close();

      RS.IndexedDB.clean(this.db.name, function() {
        RS.IndexedDB.open(dbName, function(other) {
          // hacky!
          self.db = other.db;
          callback(self);
        });
      });
    },

    forAllNodes: function(cb) {
      var promise = promising();
      var transaction = this.db.transaction(['nodes'], 'readonly');
      var cursorReq = transaction.objectStore('nodes').openCursor();

      cursorReq.onsuccess = function(evt) {
        var cursor = evt.target.result;

        if (cursor) {
          cb(this.migrate(cursor.value));
          cursor.continue();
        } else {
          promise.fulfill();
        }
      }.bind(this);

      return promise;
    },

    closeDB: function() {
      this.db.close();
    }

  };

  RS.IndexedDB.open = function(name, callback) {
    var timer = setTimeout(function() {
      callback("timeout trying to open db");
    }, 10000);

    var req = indexedDB.open(name, DB_VERSION);

    req.onerror = function() {
      RemoteStorage.log('Opening DB failed', req);

      clearTimeout(timer);
      callback(req.error);
    };

    req.onupgradeneeded = function(event) {
      var db = req.result;

      RemoteStorage.log("[IndexedDB] Upgrade: from ", event.oldVersion, " to ", event.newVersion);

      if (event.oldVersion !== 1) {
        RemoteStorage.log("[IndexedDB] Creating object store: nodes");
        db.createObjectStore('nodes', { keyPath: 'path' });
      }

      RemoteStorage.log("[IndexedDB] Creating object store: changes");

      db.createObjectStore('changes', { keyPath: 'path' });
    };

    req.onsuccess = function() {
      clearTimeout(timer);
      callback(null, req.result);
    };
  };

  RS.IndexedDB.clean = function(databaseName, callback) {
    var req = indexedDB.deleteDatabase(databaseName);

    req.onsuccess = function() {
      RemoteStorage.log('Done removing DB');
      callback();
    };

    req.onerror = req.onabort = function(evt) {
      console.error('Failed to remove database "' + databaseName + '"', evt);
    };
  };

  RS.IndexedDB._rs_init = function(remoteStorage) {
    var promise = promising();

    RS.IndexedDB.open(DEFAULT_DB_NAME, function(err, db) {
      if (err) {
        promise.reject(err);
      } else {
        DEFAULT_DB = db;
        db.onerror = function() { remoteStorage._emit('error', err); };
        promise.fulfill();
      }
    });

    return promise;
  };

  RS.IndexedDB._rs_supported = function() {
    var promise = promising();

    if ('indexedDB' in global) {
      try {
        var check = indexedDB.open("MyTestDatabase");
        check.onerror = function(event) {
          promise.reject();
        };
        check.onsuccess = function(event) {
          promise.fulfill();
        };
      } catch(e) {
        promise.reject();
      }
    } else {
      promise.reject();
    }

    return promise;
  };

  RS.IndexedDB._rs_cleanup = function(remoteStorage) {
    var promise = promising();

    if (remoteStorage.local) {
      remoteStorage.local.closeDB();
    }

    RS.IndexedDB.clean(DEFAULT_DB_NAME, function() {
      promise.fulfill();
    });

    return promise;
  };

})(typeof(window) !== 'undefined' ? window : global);
<|endoftext|>


<commit_before>var HealthChecker = (function(){
	var storeLifetime = 5 * 60 * 1000; //5 minutes
	var serverStatusInterval = 20000; //every 20 seconds
	var store = {};
	var queueSizeReached = {};
	var catLength = 50; //keep a rolling window of the last n items of each category
	var healthChecking = true;

	var addMeasureFunc = function(category,success,duration){
		if (!(category in store)){
			store[category] = timedQueue(storeLifetime);
		}
		var catStore = store[category];
		/*
		if (!(category in queueSizeReached)){
		 	if (catStore.length >= catLength){
				queueSizeReached[category] = true;
				catStore.shift();
			}
		} else {
			catStore.shift();
		}
		catStore.push({
			instant:new Date().getTime(),
			duration:duration,
			success:success
		});
		*/
		catStore.enqueue({
			instant:new Date().getTime(),
			duration:duration,
			success:success
		});
	};
	var check = function(){
		var clientStart = new Date().getTime();
		$.ajax( "/latency",{
			method:"GET",
			success:function(time){
				var serverWorkTime = parseInt(time);
				var totalTime = new Date().getTime() - clientStart;
				var latency = (totalTime - serverWorkTime) / 2;
				addMeasureFunc("serverResponse",true,serverWorkTime);
				addMeasureFunc("latency",true,latency);
				_.delay(check,serverStatusInterval);
			},
			dataType:"text",
			error:function(){
				addMeasure("latency",false,(new Date().getTime() - clientStart) / 2);
				_.delay(check,serverStatusInterval);
			}
		});
	};
	var resumeHealthCheckFunc = function(){
		healthChecking = true;
		_.delay(check,serverStatusInterval);
	};
	var pauseHealthCheckFunc = function(){
		healthChecking = false;
	};
	var describeHealthFunction = function(){
		return _.map(store,function(catStore,k){
			var v = catStore.items();
			var count = v.length;
			var durations = _.map(v,"duration");
			if (count > 0){
				return {
					name:k,
					count:count,
					max:_.max(durations),
					min:_.min(durations),
					average:_.mean(durations),
					successRate:_.countBy(v,"success")[true] / count
				};
			}
		});
	};
	$(function(){
		resumeHealthCheckFunc();
	});
	return {
		check:check,
		resumeHealthCheck:resumeHealthCheckFunc,
		pauseHealthCheck:pauseHealthCheckFunc,
		addMeasure:addMeasureFunc,
		getMeasures:function(){
			return _.mapValues(store,function(v){return v.items();});
		},
		describeHealth:describeHealthFunction
	}
})();

var serverResponse = function(responseObj){
	HealthChecker.addMeasure(responseObj.command,responseObj.success,responseObj.duration);
	if ("instant" in responseObj){
		var startTime = responseObj.instant;
		var totalTime = new Date().getTime() - startTime;
		var latency = (totalTime - responseObj.duration) / 2;
		HealthChecker.addMeasure("latency",responseObj.success,latency);
	}
}

var HealthCheckViewer = (function(){
	var refreshRate = 5000; //every 5 seconds
	var viewing = false;
	var healthCheckContainer = {};
	$("#healthCheckListing");
	var healthCheckItemTemplate = {};
	var charts = {};
	$(function(){
		healthCheckContainer = $("#healthCheckListing");
		healthCheckItemTemplate = $("#healthCheckListing").clone();
		healthCheckContainer.empty();
	});
	var pauseFunc = function(){
		viewing = false;
	};
	var resumeFunc = function(){
		var identity = _.uniqueId();
		viewing = identity;
		var checkData = HealthChecker.getMeasures();
		healthCheckContainer.html(_.map(checkData,function(category,categoryName){
			var rootElem = healthCheckItemTemplate.clone();
			rootElem.attr("id","healthCheck_"+categoryName);
			var canvas = $("<canvas />").addClass("healthCheckCanvas");
			_.defer(function(){
				var options = {
					title: {
						display: true,
						text: categoryName
					},
					scales: {
						yAxes: [
							{
								id:"durationAxis",
								type: "linear",
								stacked: true,
								display:true,
								position:"left",
								ticks: {
								},
								labels: {
									show: true
								}
							},
							{
								id:"errorAxis",
								type: "linear",
								stacked: true,
								display:true,
								position:"right",
								ticks: {
									beginAtZero:true,
									min:0,
									max:1,
									stepSize:1
								},
								labels: {
									show: true
								}
							}
						],
						xAxes: [{
							type: "linear",
							position: "bottom",
							ticks: {
								stepSize:1
							}
						}]
					},
					elements:{
						line: {
							fill: false
						},
						bar: {
							fill:true
						}
					},
					legend:{
						display:false
					}
				};
				successData = _.map(category,function(d){
					return {
						x:d.instant,
						y: "success" in d && d.success ? 0 : 1
					};
				});
				var data = {
					labels: _.map(category,"instant"),
					datasets:[
						{
							type:"line",
							label:"error",
							data:successData,
							fill:true,
							borderColor:"rgba(0,0,0,0.5)",//["red"],
							backgroundColor:"rgba(255,0,0,0.3)",
							borderWidth:1,
							pointRadius:0,
							yAxisID: "errorAxis"
						},
						{
							label:"duration",
							type:"line",
							data:_.map(category,function(sample){
								return {
									y:sample.duration,
									x:sample.instant
								}
							}),
							fill:false,
							pointRadius:0,
							borderColor:"rgba(0,0,0,1)",
							backgroundColor:"rgba(0,0,255,1)",
							borderWidth:1,
							yAxisID: "durationAxis"
						}

					]
				};
				var chartDesc = {
					type:"bar",
					data: data,
					options: options
				};
				var chart = new Chart(canvas[0].getContext("2d"),chartDesc);
				charts[categoryName] = chart;
			});
			rootElem.html(canvas);
			return rootElem;
		}));
		_.delay(updateView,refreshRate,identity);
	};
	var updateView = function(identity){
		if ("HealthChecker" in window && viewing == identity){
			var checkData = HealthChecker.getMeasures();
			_.forEach(checkData,function(category,categoryName){
				var chart = charts[categoryName];
				if (chart){
					chart.data.datasets[1].data = _.map(category,function(sample){
						return {
							y:sample.duration,
							x:sample.instant
						};
					});
					chart.data.datasets[0].data = _.map(category,function(sample){
						return {
							x:sample.instant,
							y: "success" in sample && sample.success ? 0 : 1
						};
					});
					chart.update();
				}
			});
			_.delay(updateView,refreshRate,identity);
		}
	};
	return {
		resume:resumeFunc,
		pause:pauseFunc
	};
})();
<commit_msg>reducing the storeLifetime to 1 minute, to reduce the impact of the healthChecker<commit_after>var HealthChecker = (function(){
	var storeLifetime = 1 * 60 * 1000; //1 minute
	var serverStatusInterval = 20000; //every 20 seconds
	var store = {};
	var queueSizeReached = {};
	var catLength = 50; //keep a rolling window of the last n items of each category
	var healthChecking = true;

	var addMeasureFunc = function(category,success,duration){
		if (!(category in store)){
			store[category] = timedQueue(storeLifetime);
		}
		var catStore = store[category];
		/*
		if (!(category in queueSizeReached)){
		 	if (catStore.length >= catLength){
				queueSizeReached[category] = true;
				catStore.shift();
			}
		} else {
			catStore.shift();
		}
		catStore.push({
			instant:new Date().getTime(),
			duration:duration,
			success:success
		});
		*/
		catStore.enqueue({
			instant:new Date().getTime(),
			duration:duration,
			success:success
		});
	};
	var check = function(){
		var clientStart = new Date().getTime();
		$.ajax( "/latency",{
			method:"GET",
			success:function(time){
				var serverWorkTime = parseInt(time);
				var totalTime = new Date().getTime() - clientStart;
				var latency = (totalTime - serverWorkTime) / 2;
				addMeasureFunc("serverResponse",true,serverWorkTime);
				addMeasureFunc("latency",true,latency);
				_.delay(check,serverStatusInterval);
			},
			dataType:"text",
			error:function(){
				addMeasure("latency",false,(new Date().getTime() - clientStart) / 2);
				_.delay(check,serverStatusInterval);
			}
		});
	};
	var resumeHealthCheckFunc = function(){
		healthChecking = true;
		_.delay(check,serverStatusInterval);
	};
	var pauseHealthCheckFunc = function(){
		healthChecking = false;
	};
	var describeHealthFunction = function(){
		return _.map(store,function(catStore,k){
			var v = catStore.items();
			var count = v.length;
			var durations = _.map(v,"duration");
			if (count > 0){
				return {
					name:k,
					count:count,
					max:_.max(durations),
					min:_.min(durations),
					average:_.mean(durations),
					successRate:_.countBy(v,"success")[true] / count
				};
			}
		});
	};
	$(function(){
		resumeHealthCheckFunc();
	});
	return {
		check:check,
		resumeHealthCheck:resumeHealthCheckFunc,
		pauseHealthCheck:pauseHealthCheckFunc,
		addMeasure:addMeasureFunc,
		getMeasures:function(){
			return _.mapValues(store,function(v){return v.items();});
		},
		describeHealth:describeHealthFunction
	}
})();

var serverResponse = function(responseObj){
	HealthChecker.addMeasure(responseObj.command,responseObj.success,responseObj.duration);
	if ("instant" in responseObj){
		var startTime = responseObj.instant;
		var totalTime = new Date().getTime() - startTime;
		var latency = (totalTime - responseObj.duration) / 2;
		HealthChecker.addMeasure("latency",responseObj.success,latency);
	}
}

var HealthCheckViewer = (function(){
	var refreshRate = 5000; //every 5 seconds
	var viewing = false;
	var healthCheckContainer = {};
	$("#healthCheckListing");
	var healthCheckItemTemplate = {};
	var charts = {};
	$(function(){
		healthCheckContainer = $("#healthCheckListing");
		healthCheckItemTemplate = $("#healthCheckListing").clone();
		healthCheckContainer.empty();
	});
	var pauseFunc = function(){
		viewing = false;
	};
	var resumeFunc = function(){
		var identity = _.uniqueId();
		viewing = identity;
		var checkData = HealthChecker.getMeasures();
		healthCheckContainer.html(_.map(checkData,function(category,categoryName){
			var rootElem = healthCheckItemTemplate.clone();
			rootElem.attr("id","healthCheck_"+categoryName);
			var canvas = $("<canvas />").addClass("healthCheckCanvas");
			_.defer(function(){
				var options = {
					title: {
						display: true,
						text: categoryName
					},
					scales: {
						yAxes: [
							{
								id:"durationAxis",
								type: "linear",
								stacked: true,
								display:true,
								position:"left",
								ticks: {
								},
								labels: {
									show: true
								}
							},
							{
								id:"errorAxis",
								type: "linear",
								stacked: true,
								display:true,
								position:"right",
								ticks: {
									beginAtZero:true,
									min:0,
									max:1,
									stepSize:1
								},
								labels: {
									show: true
								}
							}
						],
						xAxes: [{
							type: "linear",
							position: "bottom",
							ticks: {
								stepSize:1
							}
						}]
					},
					elements:{
						line: {
							fill: false
						},
						bar: {
							fill:true
						}
					},
					legend:{
						display:false
					}
				};
				successData = _.map(category,function(d){
					return {
						x:d.instant,
						y: "success" in d && d.success ? 0 : 1
					};
				});
				var data = {
					labels: _.map(category,"instant"),
					datasets:[
						{
							type:"line",
							label:"error",
							data:successData,
							fill:true,
							borderColor:"rgba(0,0,0,0.5)",//["red"],
							backgroundColor:"rgba(255,0,0,0.3)",
							borderWidth:1,
							pointRadius:0,
							yAxisID: "errorAxis"
						},
						{
							label:"duration",
							type:"line",
							data:_.map(category,function(sample){
								return {
									y:sample.duration,
									x:sample.instant
								}
							}),
							fill:false,
							pointRadius:0,
							borderColor:"rgba(0,0,0,1)",
							backgroundColor:"rgba(0,0,255,1)",
							borderWidth:1,
							yAxisID: "durationAxis"
						}

					]
				};
				var chartDesc = {
					type:"bar",
					data: data,
					options: options
				};
				var chart = new Chart(canvas[0].getContext("2d"),chartDesc);
				charts[categoryName] = chart;
			});
			rootElem.html(canvas);
			return rootElem;
		}));
		_.delay(updateView,refreshRate,identity);
	};
	var updateView = function(identity){
		if ("HealthChecker" in window && viewing == identity){
			var checkData = HealthChecker.getMeasures();
			_.forEach(checkData,function(category,categoryName){
				var chart = charts[categoryName];
				if (chart){
					chart.data.datasets[1].data = _.map(category,function(sample){
						return {
							y:sample.duration,
							x:sample.instant
						};
					});
					chart.data.datasets[0].data = _.map(category,function(sample){
						return {
							x:sample.instant,
							y: "success" in sample && sample.success ? 0 : 1
						};
					});
					chart.update();
				}
			});
			_.delay(updateView,refreshRate,identity);
		}
	};
	return {
		resume:resumeFunc,
		pause:pauseFunc
	};
})();
<|endoftext|>


<commit_before>import {metadata} from 'aurelia-metadata';
import {_emptyParameters} from './container';

/**
* Decorator: Directs the TypeScript transpiler to write-out type metadata for the decorated class.
*/
export function autoinject(potentialTarget?: any): any {
  let deco = function(target) {
    let previousInject = target.inject;
    let autoInject: any = metadata.getOwn(metadata.paramTypes, target) || _emptyParameters;
    if (!previousInject) {
      target.inject = autoInject;
    } else {
      for (let i = 0; i < autoInject.length; i++) {
        //check if previously injected.
        if (previousInject[i] && previousInject[i] !== autoInject[i]) {
          const prevIndex = previousInject.indexOf(autoInject[i]);
          if (prevIndex > -1) {
            previousInject.splice(prevIndex, 1);
          }
          previousInject.splice((prevIndex > -1 && prevIndex < i) ? i - 1 : i, 0, autoInject[i]);
        }
        //else add
        else if (!previousInject[i]) {
          previousInject[i] = autoInject[i];
        }
      }
    }
  };

  return potentialTarget ? deco(potentialTarget) : deco;
}

/**
* Decorator: Specifies the dependencies that should be injected by the DI Container into the decoratored class/function.
*/
export function inject(...rest: any[]): any {
  return function(target, key, descriptor) {
    // handle when used as a parameter
    if (typeof descriptor === 'number' && rest.length === 1) {
      let params = target.inject;
      if (typeof params === 'function') {
        throw new Error('Decorator inject cannot be used with "inject()".  Please use an array instead.');
      }
      if (!params) {
        params = metadata.getOwn(metadata.paramTypes, target).slice();
        target.inject = params;
      }
      params[descriptor] = rest[0];
      return;
    }
    // if it's true then we injecting rest into function and not Class constructor
    if (descriptor) {
      const fn = descriptor.value;
      fn.inject = rest;
    } else {
      target.inject = rest;
    }
  };
}
<commit_msg>#121<commit_after>import {metadata} from 'aurelia-metadata';
import {_emptyParameters} from './container';

/**
* Decorator: Directs the TypeScript transpiler to write-out type metadata for the decorated class.
*/
export function autoinject(potentialTarget?: any): any {
  let deco = function(target) {
    let previousInject = target.inject;
    let autoInject: any = metadata.getOwn(metadata.paramTypes, target) || _emptyParameters;
    if (!previousInject) {
      target.inject = autoInject;
    } else {
      for (let i = 0; i < autoInject.length; i++) {
        //check if previously injected.
        if (previousInject[i] && previousInject[i] !== autoInject[i]) {
          const prevIndex = previousInject.indexOf(autoInject[i]);
          if (prevIndex > -1) {
            previousInject.splice(prevIndex, 1);
          }
          previousInject.splice((prevIndex > -1 && prevIndex < i) ? i - 1 : i, 0, autoInject[i]);
        } else if (!previousInject[i]) {//else add
          previousInject[i] = autoInject[i];
        }
      }
    }
  };

  return potentialTarget ? deco(potentialTarget) : deco;
}

/**
* Decorator: Specifies the dependencies that should be injected by the DI Container into the decoratored class/function.
*/
export function inject(...rest: any[]): any {
  return function(target, key, descriptor) {
    // handle when used as a parameter
    if (typeof descriptor === 'number' && rest.length === 1) {
      let params = target.inject;
      if (typeof params === 'function') {
        throw new Error('Decorator inject cannot be used with "inject()".  Please use an array instead.');
      }
      if (!params) {
        params = metadata.getOwn(metadata.paramTypes, target).slice();
        target.inject = params;
      }
      params[descriptor] = rest[0];
      return;
    }
    // if it's true then we injecting rest into function and not Class constructor
    if (descriptor) {
      const fn = descriptor.value;
      fn.inject = rest;
    } else {
      target.inject = rest;
    }
  };
}
<|endoftext|>


<commit_before>'use strict';

module.exports = {
  listInstancesToStop,
  listInstancesToStart,
  tagInstances,
  untagInstances,
  stopInstances,
  startInstances,
};

const AWS = require('aws-sdk');

function listInstancesToStop() {
  const params = {
    Filters: [
      {
        Name: 'instance-state-name',
        Values: ['running']
      }
    ]
  };

  return listTargetInstances(params);
}

function listInstancesToStart() {
  const params = {
    Filters: [
      {
        Name: 'instance-state-name',
        Values: ['stopped']
      },
      {
        Name: 'tag-key',
        Values: ['stop:hammertime']
      }
    ]
  };

  return listTargetInstances(params);
}

function tagInstances(instanceIds) {
  const ec2 = new AWS.EC2();
  const params = {
    Resources: instanceIds,
    Tags: [
      {
        Key: 'stop:hammertime',
        Value: new Date().toISOString()
      }
    ]
  };

  return new Promise((resolve, reject) => {
    ec2.createTags(params)
      .promise()
      .then(data => { resolve(instanceIds) })
      .catch(err => { reject(err) });
  });
}

function untagInstances(instanceIds) {
  const ec2 = new AWS.EC2();
  const params = {
    Resources: instanceIds,
    Tags: [
      {
        Key: 'stop:hammertime'
      }
    ]
  };

  return new Promise((resolve, reject) => {
    ec2.deleteTags(params)
      .promise()
      .then(data => { resolve(instanceIds) })
      .catch(reject);
  });
}

function stopInstances(instanceIds) {
  const ec2 = new AWS.EC2();
  const params = { InstanceIds: instanceIds };

  return new Promise((resolve, reject) => {
    ec2.stopInstances(params)
      .promise()
      .then(data => { resolve(instanceIds) })
      .catch(reject);
  });
}

function startInstances(instanceIds) {
  return new Promise((resolve, reject) => {
    const ec2 = new AWS.EC2();
    const params = { InstanceIds: instanceIds };

    ec2.startInstances(params)
      .promise()
      .then(data => { resolve(instanceIds) })
      .catch(reject);
  });
}

function listTargetInstances(params) {
  return new Promise((resolve, reject) => {
    const ec2 = new AWS.EC2();
    ec2.describeInstances(params)
      .promise()
      .then(data => { resolve(filterInstances(data)) })
      .catch(reject);
  });
}

function filterInstances(data) {
  return data
          .Reservations
          .map(reservation => reservation.Instances)
          .reduce((prev, curr) => prev.concat(curr), [])
          .filter(validInstance)
          .map(instance => instance.InstanceId)
}

function validInstance(instance) {
  return !instance.Tags.some(tag => {
    return (tag.Key === 'aws:autoscaling:groupName' || tag.Key === 'hammertime:canttouchthis');
  });
}
<commit_msg>Lint instance.js<commit_after>const AWS = require('aws-sdk');

function validInstance(instance) {
  return !instance.Tags.some(tag => (tag.Key === 'aws:autoscaling:groupName' || tag.Key === 'hammertime:canttouchthis'));
}

function filterInstances(data) {
  return data
    .Reservations
    .map(reservation => reservation.Instances)
    .reduce((prev, curr) => prev.concat(curr), [])
    .filter(validInstance)
    .map(instance => instance.InstanceId);
}

function listTargetInstances(params) {
  return new Promise((resolve, reject) => {
    const ec2 = new AWS.EC2();
    ec2.describeInstances(params)
      .promise()
      .then(data => resolve(filterInstances(data)))
      .catch(reject);
  });
}

function listInstancesToStop() {
  const params = {
    Filters: [
      {
        Name: 'instance-state-name',
        Values: ['running'],
      },
    ],
  };

  return listTargetInstances(params);
}

function listInstancesToStart() {
  const params = {
    Filters: [
      {
        Name: 'instance-state-name',
        Values: ['stopped'],
      },
      {
        Name: 'tag-key',
        Values: ['stop:hammertime'],
      },
    ],
  };

  return listTargetInstances(params);
}

function tagInstances(instanceIds) {
  const ec2 = new AWS.EC2();
  const params = {
    Resources: instanceIds,
    Tags: [
      {
        Key: 'stop:hammertime',
        Value: new Date().toISOString(),
      },
    ],
  };

  return new Promise((resolve, reject) => {
    ec2.createTags(params)
      .promise()
      .then(() => resolve(instanceIds))
      .catch(err => reject(err));
  });
}

function untagInstances(instanceIds) {
  const ec2 = new AWS.EC2();
  const params = {
    Resources: instanceIds,
    Tags: [
      {
        Key: 'stop:hammertime',
      },
    ],
  };

  return new Promise((resolve, reject) => {
    ec2.deleteTags(params)
      .promise()
      .then(() => resolve(instanceIds))
      .catch(reject);
  });
}

function stopInstances(instanceIds) {
  const ec2 = new AWS.EC2();
  const params = { InstanceIds: instanceIds };

  return new Promise((resolve, reject) => {
    ec2.stopInstances(params)
      .promise()
      .then(() => resolve(instanceIds))
      .catch(reject);
  });
}

function startInstances(instanceIds) {
  return new Promise((resolve, reject) => {
    const ec2 = new AWS.EC2();
    const params = { InstanceIds: instanceIds };

    ec2.startInstances(params)
      .promise()
      .then(() => resolve(instanceIds))
      .catch(reject);
  });
}

module.exports = {
  listInstancesToStop,
  listInstancesToStart,
  tagInstances,
  untagInstances,
  stopInstances,
  startInstances,
};
<|endoftext|>


<commit_before>/**
 * Copyright 2014-2015 Green Energy Corp.
 *
 * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or more
 * contributor license agreements. See the NOTICE file distributed with this
 * work for additional information regarding copyright ownership. Green Energy
 * Corp licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 * Author: Flint O'Brien
 */

angular.module('greenbus.views.measurementValue', []).

  factory('gbMeasurementValueRest', ['rest', function( rest) {

    /**
     * Override measurements for a point.
     *
     * @param pointId Point ID to be overridden
     * @param value The new value as a string
     * @param valueType The type of the value to override. BOOL, INT, DOUBLE, STRING
     * @param success Success callback
     * @param failure Failure callback
     */
    function override( pointId, value, valueType, callee, success, failure) {

      var arg = {
            value: value,
            valueType: valueType
          },
          url = '/models/1/points/' + pointId + '/override'

      rest.post( url, arg, null, null,
        function( data) {
          success.call( callee, data)
        },
        function( ex, statusCode, headers, config){
          console.log( 'gbMeasurementValueRest ERROR overriding point with ID: ' + pointId + ' to value "' + value + '" with type: "' + valueType + '". Exception: ' + ex.exception + ' - ' + ex.message)
          failure.call( callee, pointId, ex, statusCode)
        }
      )

      return true
    }

    /**
     * Put a point NIS (Not In Service)
     *
     * @param pointId Point ID to be overridden
     */
    function nis( pointId, callee, success, failure) {

      var arg,
          url = '/models/1/points/' + pointId + '/nis'

      rest.post( url, arg, null, null,
        function( data) {
          success.call( callee, data)
        },
        function( ex, statusCode, headers, config){
          console.log( 'gbMeasurementValueRest ERROR setting NIS point with ID: ' + pointId + '. Exception: ' + ex.exception + ' - ' + ex.message)
          failure.call( callee, pointId, ex, statusCode)
        }
      )

      return true
    }

    /**
     * Remove a point's override or NIS (Not In Service)
     *
     * @param pointId Point ID to remove the override or NIS.
     */
    function remove( pointId, callee, success, failure, nisOrOverride) {

      var url = '/models/1/points/' + pointId + '/' + nisOrOverride

      rest.delete( url, null, null,
        function( data) {
          success.call( callee, data)
        },
        function( ex, statusCode, headers, config){
          console.log( 'gbMeasurementValueRest ERROR removing ' + nisOrOverride + ' on point with ID: ' + pointId + '. Exception: ' + ex.exception + ' - ' + ex.message)
          failure.call( callee, pointId, ex, statusCode)
        }
      )

      return true
    }

    function removeNis( pointId, callee, success, failure) { remove( pointId, callee, success, failure, 'nis')}
    function removeOverride( pointId, callee, success, failure) { remove( pointId, callee, success, failure, 'override')}

    /**
     * Public API
     */
    return {
      override: override,
      nis: nis,
      removeNis: removeNis,
      removeOverride: removeOverride
    }
  }]).

  controller( 'gbMeasurementValueController', ['$scope', 'gbMeasurementValueRest', '$timeout', function( $scope, gbMeasurementValueRest, $timeout) {
    var self = this

    // When editing === undefined, we are not editing the value. The value is a view only span.
    // When editing === {value: '', valueType: ''}, we are editing.
    //
    $scope.editing = undefined

    $scope.removeTooltip = undefined // Remove NIS, Remove Replace
    $scope.placeHolder = ''
    $scope.requestPending = undefined
    $scope.replyError = undefined

    function getValueTypeFromPointType() {
      if( ! $scope.model.pointType)
        return 'DOUBLE'

      switch( $scope.model.pointType) {
        case 'ANALOG': return 'DOUBLE'
        case 'STATUS': return 'BOOL'
        case 'COUNTER': return 'INT'
        default:
          return 'DOUBLE'
      }
    }
    function getValueType() {
      if( ! $scope.model.currentMeasurement)
        return getValueTypeFromPointType()

      var m = $scope.model.currentMeasurement
      if( ! m.type)
        return getValueTypeFromPointType()

      switch( m.type) {
        case 'DOUBLE': return m.type
        case 'INT': return m.type
        case 'STRING': return m.type
        case 'BOOL': return m.type
        default:
          return getValueTypeFromPointType()
      }
    }

    $scope.editStart = function() {
      if( $scope.editing)
        return

      $scope.editing = {
        value: $scope.model.currentMeasurement.value,
        valueType: getValueType()
      }
      $scope.removeTooltip = self.getRemoveTooltip()
    }

    function editEnd() {
      $scope.editing = undefined
      pendingEditEndCancel() // just in case
    }

    //self.configureInput = function() {
    //  var m = $scope.model.currentMeasurement
    //  switch( m.shortQuality) {
    //    case 'R':
    //      $scope.canRemove = true
    //      $scope.canNis = true
    //      $scope.removeTooltip = 'Remove replace'
    //      break
    //    case 'N':
    //      $scope.canRemove = true
    //      $scope.canNis = false
    //      $scope.removeTooltip = 'Remove NIS'
    //      break
    //    default:
    //      $scope.canRemove = false
    //      $scope.canNis = true
    //      $scope.removeTooltip = undefined
    //      break
    //  }
    //
    //  // set focus and select text
    //}

    self.getRemoveTooltip = function() {
      var m = $scope.model.currentMeasurement
      switch( m.shortQuality) {
        case 'R': return $scope.removeTooltip = 'Remove replace'
        case 'N': return $scope.removeTooltip = 'Remove NIS'
        default: return $scope.removeTooltip = undefined
      }
    }

    function beforeRequest( requestType ) {
      $scope.replyError = undefined
      $scope.requestPending = requestType
    }
    function afterRequestSuccessful( requestType ) {
      $scope.replyError = undefined
      $scope.requestPending = undefined
      editEnd()
    }
    function afterRequestFailure( pointId, ex, statusCode ) {
      $scope.replyError = '"Exception: ' + ex.exception + ' - ' + ex.message
      $scope.requestPending = undefined
    }

    // If user clicks one of our buttons (NIS, Override, or Remove), then the input gets a blur event.
    // We don't want to end the edit mode in this case. We set a timeout to see if someone
    // did, in fact, click a button (or tab and a button got focus). If not, then we go ahead with
    // ending edit mode.
    //
    function pendingEditEndStart() {
      if( ! $scope.editing)
        return
      $scope.pendingEditEndTimer = $timeout( function() {
        $scope.editing = undefined
        $scope.pendingEditEndTimer = undefined
      }, 300)
    }
    function pendingEditEndCancel() {
      if( $scope.pendingEditEndTimer) {
        $timeout.cancel( $scope.pendingEditEndTimer)
        $scope.pendingEditEndTimer = undefined
      }
    }

    $scope.nis = function() {
      pendingEditEndCancel()
      if( $scope.requestPending)
        return false

      var m = $scope.model.currentMeasurement
      if( m.shortQuality !== 'R' && m.shortQuality !== 'N') {
        beforeRequest( 'nis')
        gbMeasurementValueRest.nis($scope.model.id, this, afterRequestSuccessful, afterRequestFailure)
      }
    }
    $scope.override = function() {
      pendingEditEndCancel()
      if( $scope.requestPending)
        return false

      var m = $scope.model.currentMeasurement
      beforeRequest( 'override')
      gbMeasurementValueRest.override($scope.model.id, $scope.editing.value, $scope.editing.valueType, this, afterRequestSuccessful, afterRequestFailure)
    }
    $scope.remove = function() {
      pendingEditEndCancel()
      if( $scope.requestPending)
        return false

      var m = $scope.model.currentMeasurement
      beforeRequest( 'remove')
      gbMeasurementValueRest.remove($scope.model.id, this, afterRequestSuccessful, afterRequestFailure)
    }
    $scope.inputKeyDown = function($event) {
      if( $event.keyCode === 27) // escape key
        editEnd()
    }
    $scope.inputOnFocus = function() {
      pendingEditEndCancel()
    }
    $scope.buttonOnFocus = function() {
      pendingEditEndCancel()
    }

    $scope.inputOnBlur = function() {
      pendingEditEndStart()
    }
    $scope.buttonOnBlur = function() {
      pendingEditEndStart()
    }

  }]).

  directive( 'gbMeasurementValue', function(){
    return {
      restrict: 'E', // Element name
      // The template HTML will replace the directive.
      replace: true,
      scope: {
             model  : '=',
             notify: '&'
      },
      templateUrl: 'greenbus.views.template/measurementValue/measurementValue.html',
      controller: 'gbMeasurementValueController',
      link: function(scope, element, attrs, controller) {
        var focusedElement
        element.on('click', function () {
          console.log( 'gbMeasurementValue onClick')
          if ( ! scope.editing) {
            scope.editStart()
            scope.$digest()
            console.log( 'gbMeasurementValue onClick selecting input')
            var input = element.find( 'input')
            if( input && input.length > 0) {
              input[0].select()
              focusedElement = input[0];
            }
          }
        })
        element.on('blur', function () {
          focusedElement = null;
        })

        var selectItem = attrs.selectItem || 'selectItem'
        scope.$parent[selectItem] = controller.selectItem
        scope.$parent.uncheckItem = controller.uncheckItem
        controller.notifyParent = function( state) {
          scope.notify( {state: state})
        }
      }
    }
  }).

  filter('buttonDisabled', function() {
    return function(disabled, classes) {
      return disabled ? classes + ' disabled' : classes
    };
  })

<commit_msg>fix(measurementValue): Remove NIS and Replace works as expected.<commit_after>/**
 * Copyright 2014-2015 Green Energy Corp.
 *
 * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or more
 * contributor license agreements. See the NOTICE file distributed with this
 * work for additional information regarding copyright ownership. Green Energy
 * Corp licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 * Author: Flint O'Brien
 */

angular.module('greenbus.views.measurementValue', []).

  factory('gbMeasurementValueRest', ['rest', function( rest) {

    /**
     * Override measurements for a point.
     *
     * @param pointId Point ID to be overridden
     * @param value The new value as a string
     * @param valueType The type of the value to override. BOOL, INT, DOUBLE, STRING
     * @param success Success callback
     * @param failure Failure callback
     */
    function override( pointId, value, valueType, callee, success, failure) {

      var arg = {
            value: value,
            valueType: valueType
          },
          url = '/models/1/points/' + pointId + '/override'

      rest.post( url, arg, null, null,
        function( data) {
          success.call( callee, data)
        },
        function( ex, statusCode, headers, config){
          console.log( 'gbMeasurementValueRest ERROR overriding point with ID: ' + pointId + ' to value "' + value + '" with type: "' + valueType + '". Exception: ' + ex.exception + ' - ' + ex.message)
          failure.call( callee, pointId, ex, statusCode)
        }
      )

      return true
    }

    /**
     * Put a point NIS (Not In Service)
     *
     * @param pointId Point ID to be overridden
     */
    function nis( pointId, callee, success, failure) {

      var arg,
          url = '/models/1/points/' + pointId + '/nis'

      rest.post( url, arg, null, null,
        function( data) {
          success.call( callee, data)
        },
        function( ex, statusCode, headers, config){
          console.log( 'gbMeasurementValueRest ERROR setting NIS point with ID: ' + pointId + '. Exception: ' + ex.exception + ' - ' + ex.message)
          failure.call( callee, pointId, ex, statusCode)
        }
      )

      return true
    }

    /**
     * Remove a point's override or NIS (Not In Service)
     *
     * @param pointId Point ID to remove the override or NIS.
     */
    function remove( pointId, callee, success, failure, nisOrOverride) {

      var url = '/models/1/points/' + pointId + '/' + nisOrOverride

      rest.delete( url, null, null,
        function( data) {
          success.call( callee, data)
        },
        function( ex, statusCode, headers, config){
          console.log( 'gbMeasurementValueRest ERROR removing ' + nisOrOverride + ' on point with ID: ' + pointId + '. Exception: ' + ex.exception + ' - ' + ex.message)
          failure.call( callee, pointId, ex, statusCode)
        }
      )

      return true
    }

    function removeNis( pointId, callee, success, failure) { remove( pointId, callee, success, failure, 'nis')}
    function removeOverride( pointId, callee, success, failure) { remove( pointId, callee, success, failure, 'override')}

    /**
     * Public API
     */
    return {
      override: override,
      nis: nis,
      removeNis: removeNis,
      removeOverride: removeOverride
    }
  }]).

  controller( 'gbMeasurementValueController', ['$scope', 'gbMeasurementValueRest', '$timeout', function( $scope, gbMeasurementValueRest, $timeout) {
    var self = this

    // When editing === undefined, we are not editing the value. The value is a view only span.
    // When editing === {value: '', valueType: ''}, we are editing.
    //
    $scope.editing = undefined

    $scope.removeTooltip = undefined // Remove NIS, Remove Replace
    $scope.placeHolder = ''
    $scope.requestPending = undefined
    $scope.replyError = undefined

    function getValueTypeFromPointType() {
      if( ! $scope.model.pointType)
        return 'DOUBLE'

      switch( $scope.model.pointType) {
        case 'ANALOG': return 'DOUBLE'
        case 'STATUS': return 'BOOL'
        case 'COUNTER': return 'INT'
        default:
          return 'DOUBLE'
      }
    }
    function getValueType() {
      if( ! $scope.model.currentMeasurement)
        return getValueTypeFromPointType()

      var m = $scope.model.currentMeasurement
      if( ! m.type)
        return getValueTypeFromPointType()

      switch( m.type) {
        case 'DOUBLE': return m.type
        case 'INT': return m.type
        case 'STRING': return m.type
        case 'BOOL': return m.type
        default:
          return getValueTypeFromPointType()
      }
    }

    $scope.editStart = function() {
      if( $scope.editing)
        return

      $scope.editing = {
        value: $scope.model.currentMeasurement.value,
        valueType: getValueType()
      }
      $scope.removeTooltip = self.getRemoveTooltip()
    }

    function editEnd() {
      $scope.editing = undefined
      pendingEditEndCancel() // just in case
    }

    //self.configureInput = function() {
    //  var m = $scope.model.currentMeasurement
    //  switch( m.shortQuality) {
    //    case 'R':
    //      $scope.canRemove = true
    //      $scope.canNis = true
    //      $scope.removeTooltip = 'Remove replace'
    //      break
    //    case 'N':
    //      $scope.canRemove = true
    //      $scope.canNis = false
    //      $scope.removeTooltip = 'Remove NIS'
    //      break
    //    default:
    //      $scope.canRemove = false
    //      $scope.canNis = true
    //      $scope.removeTooltip = undefined
    //      break
    //  }
    //
    //  // set focus and select text
    //}

    self.getRemoveTooltip = function() {
      var m = $scope.model.currentMeasurement
      switch( m.shortQuality) {
        case 'R': return $scope.removeTooltip = 'Remove replace'
        case 'N': return $scope.removeTooltip = 'Remove NIS'
        default: return $scope.removeTooltip = undefined
      }
    }

    function beforeRequest( requestType ) {
      $scope.replyError = undefined
      $scope.requestPending = requestType
    }
    function afterRequestSuccessful( requestType ) {
      $scope.replyError = undefined
      $scope.requestPending = undefined
      editEnd()
    }
    function afterRequestFailure( pointId, ex, statusCode ) {
      $scope.replyError = '"Exception: ' + ex.exception + ' - ' + ex.message
      $scope.requestPending = undefined
    }

    // If user clicks one of our buttons (NIS, Override, or Remove), then the input gets a blur event.
    // We don't want to end the edit mode in this case. We set a timeout to see if someone
    // did, in fact, click a button (or tab and a button got focus). If not, then we go ahead with
    // ending edit mode.
    //
    function pendingEditEndStart() {
      if( ! $scope.editing)
        return
      $scope.pendingEditEndTimer = $timeout( function() {
        $scope.editing = undefined
        $scope.pendingEditEndTimer = undefined
      }, 300)
    }
    function pendingEditEndCancel() {
      if( $scope.pendingEditEndTimer) {
        $timeout.cancel( $scope.pendingEditEndTimer)
        $scope.pendingEditEndTimer = undefined
      }
    }

    $scope.nis = function() {
      pendingEditEndCancel()
      if( $scope.requestPending)
        return false

      var m = $scope.model.currentMeasurement
      if( m.shortQuality !== 'R' && m.shortQuality !== 'N') {
        beforeRequest( 'nis')
        gbMeasurementValueRest.nis($scope.model.id, this, afterRequestSuccessful, afterRequestFailure)
      }
    }
    $scope.override = function() {
      pendingEditEndCancel()
      if( $scope.requestPending)
        return false

      var m = $scope.model.currentMeasurement
      beforeRequest( 'override')
      gbMeasurementValueRest.override($scope.model.id, $scope.editing.value, $scope.editing.valueType, this, afterRequestSuccessful, afterRequestFailure)
    }
    $scope.remove = function() {
      pendingEditEndCancel()
      if( $scope.requestPending)
        return false

      var m = $scope.model.currentMeasurement
      beforeRequest( 'remove')
      if( m.shortQuality==='R')
        gbMeasurementValueRest.removeOverride($scope.model.id, this, afterRequestSuccessful, afterRequestFailure)
      else if( m.shortQuality==='N')
        gbMeasurementValueRest.removeNis($scope.model.id, this, afterRequestSuccessful, afterRequestFailure)
      else
        console.error( 'gbMeasurementValueController.remove measurement shortQuality must be R or N; but it is: "' + m.shortQuality + '"')
    }
    $scope.inputKeyDown = function($event) {
      if( $event.keyCode === 27) // escape key
        editEnd()
    }
    $scope.inputOnFocus = function() {
      pendingEditEndCancel()
    }
    $scope.buttonOnFocus = function() {
      pendingEditEndCancel()
    }

    $scope.inputOnBlur = function() {
      pendingEditEndStart()
    }
    $scope.buttonOnBlur = function() {
      pendingEditEndStart()
    }

  }]).

  directive( 'gbMeasurementValue', function(){
    return {
      restrict: 'E', // Element name
      // The template HTML will replace the directive.
      replace: true,
      scope: {
             model  : '=',
             notify: '&'
      },
      templateUrl: 'greenbus.views.template/measurementValue/measurementValue.html',
      controller: 'gbMeasurementValueController',
      link: function(scope, element, attrs, controller) {
        var focusedElement
        element.on('click', function () {
          console.log( 'gbMeasurementValue onClick')
          if ( ! scope.editing) {
            scope.editStart()
            scope.$digest()
            console.log( 'gbMeasurementValue onClick selecting input')
            var input = element.find( 'input')
            if( input && input.length > 0) {
              input[0].select()
              focusedElement = input[0];
            }
          }
        })
        element.on('blur', function () {
          focusedElement = null;
        })

        var selectItem = attrs.selectItem || 'selectItem'
        scope.$parent[selectItem] = controller.selectItem
        scope.$parent.uncheckItem = controller.uncheckItem
        controller.notifyParent = function( state) {
          scope.notify( {state: state})
        }
      }
    }
  }).

  filter('buttonDisabled', function() {
    return function(disabled, classes) {
      return disabled ? classes + ' disabled' : classes
    };
  })

<|endoftext|>


<commit_before>//declare our dependencies
let entries = require('object.entries'), //Invoke its "shim" method to shim Object.entries if it is unavailable or noncompliant{heroku}
	natural = require('natural');
	invertedIndexObj = {},
	invertedIndex = {},
	searchResults ={},
	index = [];

/**
  * Takes data from a json file an returns the JSON object
  * @param {string} filepath, {string} encoding
  * @returns {{}|*}
  */
let readJsonFile = (content)=>{
	let file;
	try{
		file = content;
	}
	catch(e){
		throw new Error('No such file or directory');
	}
	if (Object.keys(file).length === 0) {
		throw new Error('the file is empty');
	}
	try {
		//console.log(content)
		return JSON.parse(file);
	} catch (e) {
		throw new Error('invalid json file')
	}
}

/**
  * Takes a json filename and creates an Inverted Index
  * @param {string} filename
  * @returns {{}|*}
  */
let createIndex =  (content, filename)=>{
	let term = [];
	invertedIndex = {};
	//get json file content assign to index
	let index = readJsonFile(content);
	for(let i=0; i<index.length; i++){
		term = index[i];
		let terms = term.title + ' ' + term.text;
		//process text to remove repetition, special characters & (lower case)
		terms = processText(terms);
		for(let j = 0; j<terms.length; j++){
			if(!(terms[j] in invertedIndex))
			{
				invertedIndex[terms[j]] = [i];
			}
			else{
				if(!(i in invertedIndex[terms[j]]))
				{
					invertedIndex[terms[j]].push(i);
				}
			}
		}
	}
	//remove directory path
	filename = filename.split('/');
	//get filename
	filename = filename[filename.length-1];
	//assign filename key the inverted index object
	invertedIndexObj[filename] = invertedIndex;
	return invertedIndexObj;
};

/**
  * Takes text and processes to lowercase, remove dublicates & other characters
  * @param {string} text
  * @returns text
  */
let processText = (text)=>{
	let normalised = text.replace(/[.[,\]/#!$%\^&\*;:@{}=\-_`~()]/g, '').toLowerCase().split(' ');
	text = new Set(normalised);
	text = Array.from(text);
	return text;
};
/**
 * Normalizes Data
 * @param {terms} a word to normalize.
 * @returns string  - normalized word.
 */
let search = (term)=>{
	return natural.PorterStemmer.stem(term);
}
/**
 * Searches inverted index
 * @param {words} title - extended parameters.
 * @returns { } searchresults - Object of search results.
 */
let searchIndex = (...words)=>{
	let file = [],
		searchResults = {},
		termresults = {};

	terms = words.toString().split(',').join(' ');
	terms = processText(terms);
	for(let [key, value] of entries(invertedIndexObj)){
		termresults = {};
		for (term of terms){
			if(search(term) in value){
				termresults[search(term)] = value[search(term)];
			}
			else if(term in value ){
				termresults[term] = value[term];
			}
			searchResults[key] = termresults;
		}
	}
	if(words[0]===undefined | words[0]===null){
		return searchResults
	}
	else if(words[0].toString().match(/^.*json$/)){
		let file = words[0].toString().match(/^.*json$/)
		if(file in searchResults){
			let s = searchResults;
			searchResults = {};
			searchResults[file] = s[file];
		}
	}
	return searchResults;
};
/**
 * Returns Inverted index object.
 */
let getIndex =  ()=>{
	return invertedIndexObj;
};

//export values
exports.createIndex = createIndex;
exports.getIndex = getIndex;
exports.searchIndex = searchIndex;<commit_msg>Add logic to check json content format, if searchresult has no result,  and lint code - airbnb<commit_after>// declare our dependencies
const entries = require('object.entries');

const natural = require('natural');

class Index {
  constructor() {
    this.invertedIndexObj = { };
    this.invertedIndex = { };
  }
  /**
    * Takes data from a json file an returns the JSON object
    * @param {string} filepath, {string} encoding
    * @returns {{}|*}
    */
  readJsonFile(content) {
    this.file = content;
    if (Object.keys(this.file).length === 0) {
      throw new Error('the file is empty');
    }
    try {
      this.jsonContent = JSON.parse(this.file);
    } catch (e) {
      throw new Error('Invalid json file');
    }
    for (let i = 0; i < this.jsonContent.length; i += 1) {
      if (!('title' in this.jsonContent[i] && 'text' in this.jsonContent[i])) {
        throw new Error('Bad JSON format');
      }
    }
    return this.jsonContent;
  }

  /**
    * Takes a json filename and creates an Inverted Index
    * @param {string} filename
    * @returns {{}|*}
    */
  createIndex(content, filename) {
    let term = [];
    this.invertedIndex = {};
    // get json file content assign to index
    const index = this.readJsonFile(content);
    for (let i = 0; i < index.length; i += 1) {
      term = index[i];
      let terms = `${term.title} ${term.text}`;
      // process text to remove repetition, special characters & (lower case)
      terms = this.processText(terms);
      for (let j = 0; j < terms.length; j += 1) {
        if (!(terms[j] in this.invertedIndex)) {
          this.invertedIndex[terms[j]] = [i];
        } else if (!(i in this.invertedIndex[terms[j]])) {
          this.invertedIndex[terms[j]].push(i);
        }
      }
    }
    // assign filename key the inverted index object
    this.invertedIndexObj[filename] = this.invertedIndex;
    return this.invertedIndexObj;
  }
  /**
    * Takes text and processes to lowercase, remove dublicates & other characters
    * @param {string} text
    * @returns text
    */
  processText(text) {
    const normalised = text.replace(/[.[,\]/#!$%^&*;:@{}=\-_`~()]/g, '').toLowerCase().split(' ');
    let normalisedText = new Set(normalised);
    normalisedText = Array.from(normalisedText);
    return normalisedText;
  }
  /**
   * Normalizes Data
   * @param {terms} a word to normalize.
   * @returns string  - normalized word.
   */
  search(term) {
    return natural.PorterStemmer.stem(term);
  }
  /**
   * Searches inverted index
   * @param {words} title - extended parameters.
   * @returns { } searchresults - Object of search results.
   */
  searchIndex(...words) {
    let file = [];
    this.searchResults = {};
    let termresults = {};

    let terms = words.toString().split(',').join(' ');
    terms = this.processText(terms);
    for (const [key, value] of entries(this.invertedIndexObj)) {
      termresults = {};
      for (const term of terms) {
        if (this.search(term) in value) {
          termresults[this.search(term)] = value[this.search(term)];
        } else if (term in value) {
          termresults[term] = value[term];
        }
      }
      if (Object.keys(termresults).length === 0 && termresults.constructor === Object) {
        termresults.Results = `No records found for: ${terms.toString().split(',').join(' ')}`;
      }
      this.searchResults[key] = termresults;
    }
    if (words[0] === undefined || words[0] === null) {
      return this.searchResults;
    } else if (words[0].toString().match(/^.*json$/)) {
      file = words[0].toString().match(/^.*json$/);
      if (file in this.searchResults) {
        const s = this.searchResults;
        this.searchResults = {};
        this.searchResults[file] = s[file];
      }
    }
    return this.searchResults;
  }

  /**
   * Returns Inverted index object.
   */
  getIndex() {
    return this.invertedIndexObj;
  }
}

// export values
exports.Index = Index;
<|endoftext|>


<commit_before>function Index() {
  this.bks = [];
  this.indexes = {};
  var self = this;

  var index = [];
  var stop_words = ['a', 'about', ',', 'above', 'into', 'across', 'of', 'the',
    'to', 'in', 'and', 'the', 'an'
  ];

  this.fetchJson = function(filepath) {
    /* Fetch returns a promise
     * 1. Takes in a file path
     * 2. Uses fetch API to request for the json file
     * 3. Uses Json method to convert result to a javascript object
     */
    return fetch(filepath)
      .then(function(response) {
        //Converting raw data to json
        if (response.status === 200) {
          return response.json();
        } else {
          throw response;
        }
      }).then(function(jsonData) {
        //Returns a javascript object
        self.bks = jsonData;
        return self.bks;
      }).catch(function(err) {
        // Throw an error if promise is rejected
        throw err;
      });

  }

  this.createIndex = function(filepath) {
    // Javascript object from the Json file
    return this.fetchJson(filepath)
      .then(function(books) {
        /*
         * 1. Looping through the Javascript Object getting the index of each book object
         * 2. Looping through the book to get book content
         * 3. Reformat string to lowercase and removing stop words [ Split returns array]
         */
        books.forEach(function(book, i) {
          for (var key in book) {
            var bookContent = book[key]
              .toLowerCase()
              .split(' ')
              .filter(function(element) {
                return stop_words.indexOf(element) == -1;
              });
            // Loop through the book content array to get individual word
            bookContent.forEach(function(word) {

              var ok = false;
              // Checking if the index is empty
              if (index.length) {
                /* Executed on the second loop:
                 * 1. Looping through the index
                 * 2. Checking if word exists
                 * 3. Concatinating index if it is unique
                 */

                index.forEach(function(obj) {
                  if (obj.hasOwnProperty(word)) {
                    if (obj[word].indexOf(i) === -1) {
                      obj[word] = obj[word].concat(i);
                    }
                    ok = true;
                  }
                });
              }
              // Executed on the first loop
              if (!ok) {
                index = index.concat({
                  // Concat to a new empty Array
                  [word]: [].concat(i)
                });
              }
            });
          }
        });
        self.indexes = index;
        return self.indexes;
      }).catch(function(error) {
        return error;
      });
  }

  this.getIndex = function() {
    return this.indexes;
  }
  this.searchIndex = function() {
    var theIndex = this.getIndex();
    var results = [];
    // Checking if arguments have been passed
    if (arguments.length) {
      //  Format
      var format = function(word) {
        return word.toLowerCase().split(' ').filter(function(element) {
          return stop_words.indexOf(element) == -1;
        });
      };
      // Returning Index of search terms
      var search = function(oneWord) {
        found = false;
        if (theIndex && oneWord) {
          theIndex.forEach(function(value) {
            if (value.hasOwnProperty(oneWord)) {
              found = true;
              results = results.concat(value[oneWord]);
            }
          });
          if (!found) {
            results.push(-1);
          }
        }
      };
      /*
       * 1. Loop through the args to get each term
       * 2. Check the type of the term
       * 3. If a string
       * 4. Split the term in ' '
       * 5. Loop through the splitted terms
       * 6. Search for the term
       * 7. Else if array:
       * 8. loop through the array, toLowerCase() search
       */
      var args = Array.from(arguments);
      args.forEach(function(terms) {
        if (typeof terms === 'string') {
          //  Format word to remove stop word and rswitch to lowercase
          var newTerm = format(terms);

          for (var word in newTerm) {
            var findWord = newTerm[word].replace(/[.,?\s]/g, '');
            search(findWord);
          }
        } else if (Array.isArray(terms)) {
          // Loop through the array
          terms.forEach(function(element) {
            //  Format word to remove stop word and switch to lowercase
            element = format(element);
            // Search word
            element.forEach(function(oneWord) {
              search( oneWord);
            });
          });
        } else {
          // Invalid search term;
          return results = null;
        }
      });
      return results;
    } else {
      // You need to search for a term;
      return false;
    }
  }
};
<commit_msg>Standards: making changes according to standards<commit_after>function Index () {
  this.bks = [];
  this.indexes = {};
  var self = this;

  var index = [];
  var stop_words = ['a', 'about', ',', 'above', 'into', 'across', 'of', 'the',
    'to', 'in', 'and', 'the', 'an'
  ];

  this.fetchJson = function (filepath) {
    // Fetch returns a promise
    // 1. Takes in a file path
    // 2. Uses fetch API to request for the json file
    // 3. Uses Json method to convert result to a javascript object

    return fetch(filepath)
      .then(function (response) {
        // Converting raw data to json
        if (response.status === 200) {
          return response.json();
        } else {
          throw response;
        }
      }).then(function (jsonData) {
      // Returns a javascript object
      self.bks = jsonData;
      return self.bks;
    }).catch(function (err) {
      // Throw an error if promise is rejected
      throw err;
    });
  };

  this.createIndex = function (filepath) {
    // Javascript object from the Json file
    return this.fetchJson(filepath)
      .then(function (books) {
        // 1. Looping through the Javascript Object getting the index of each book object
        // 2. Looping through the book to get book content
        // 3. Reformat string to lowercase and removing stop words [ Split returns array]

        books.forEach(function (book, i) {
          for (var key in book) {
            var bookContent = book[key]
              .toLowerCase()
              .split(' ')
              .filter(function (element) {
                return stop_words.indexOf(element) === -1;
              });
            // Loop through the book content array to get individual word
            bookContent.forEach(function (word) {
              var ok = false;
              // Checking if the index is empty
              if (index.length) {
                // Executed on the second loop:
                // 1. Looping through the index
                // 2. Checking if word exists
                // 3. Concatinating index if it is unique

                index.forEach(function (obj) {
                  if (obj.hasOwnProperty(word)) {
                    if (obj[word].indexOf(i) === -1) {
                      obj[word] = obj[word].concat(i);
                    }
                    ok = true;
                  }
                });
              }
              // Executed on the first loop
              if (!ok) {
                index = index.concat({
                  // Concat to a new empty Array
                  [word]: [].concat(i)
                });
              }
            });
          }
        });
        self.indexes = index;
        return self.indexes;
      }).catch(function (error) {
      return error;
    });
  };

  this.getIndex = function () {
    return this.indexes;
  };

  this.searchIndex = function () {
    var theIndex = this.getIndex();
    var results = [];
    // Checking if arguments have been passed
    if (arguments.length) {
      //  Format
      var format = function (word) {
        return word.toLowerCase().split(' ').filter(function (element) {
          return stop_words.indexOf(element) === -1;
        });
      };
      // Returning Index of search terms
      var search = function (oneWord) {
        found = false;
        if (theIndex && oneWord) {
          theIndex.forEach(function (value) {
            if (value.hasOwnProperty(oneWord)) {
              found = true;
              results = results.concat(value[oneWord]);
            }
          });
          if (!found) {
            results.push(-1);
          }
        }
      };

      // 1. Loop through the args to get each term
      // 2. Check the type of the term
      // 3. If a string
      // 4. Split the term in ' '
      // 5. Loop through the splitted terms
      // 6. Search for the term
      // 7. Else if array:
      // 8. loop through the array, toLowerCase() search

      var args = Array.from(arguments);
      args.forEach(function (terms) {
        if (typeof terms === 'string') {
          //  Format word to remove stop word and rswitch to lowercase
          var newTerm = format(terms);

          for (var word in newTerm) {
            var findWord = newTerm[word].replace(/[.,?\s]/g, '');
            search(findWord);
          }
        } else if (Array.isArray(terms)) {
          // Loop through the array
          terms.forEach(function (element) {
            //  Format word to remove stop word and switch to lowercase
            element = format(element);
            // Search word
            element.forEach(function (oneWord) {
              search(oneWord);
            });
          });
        } else {
          // Invalid search term
          results = null;
        }
      });
      console.log(results);
      return results;
    } else {
      // You need to search for a term
      return false;
    }
  };
}
<|endoftext|>


<commit_before><commit_msg>create backup file and write less often<commit_after><|endoftext|>