<commit_before>var should   = require('should');
var helper   = require('../support/spec_helper');
var ORM      = require('../../');

describe("Model.find() chaining", function() {
	var db = null;
	var Person = null;

	var setup = function () {
		return function (done) {
			Person = db.define("person", {
				name    : String,
				surname : String,
				age     : Number
			});
			Person.hasMany("parents");

			ORM.singleton.clear(); // clear cache

			return helper.dropSync(Person, function () {
				Person.create([{
					name    : "John",
					surname : "Doe",
					age     : 18
				}, {
					name    : "Jane",
					surname : "Doe",
					age     : 20
				}, {
					name    : "Jane",
					surname : "Dean",
					age     : 18
				}], done);
			});
		};
	};

	before(function (done) {
		helper.connect(function (connection) {
			db = connection;

			return done();
		});
	});

	after(function () {
		return db.close();
	});

	describe(".limit(N)", function () {
		before(setup());

		it("should limit results to N items", function (done) {
			Person.find().limit(2).run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 2);

				return done();
			});
		});
	});

	describe(".skip(N)", function () {
		before(setup());

		it("should skip the first N results", function (done) {
			Person.find().skip(2).order("age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 1);
				instances[0].age.should.equal(20);

				return done();
			});
		});
	});

	describe(".offset(N)", function () {
		before(setup());

		it("should skip the first N results", function (done) {
			Person.find().offset(2).order("age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 1);
				instances[0].age.should.equal(20);

				return done();
			});
		});
	});

	describe(".order('property')", function () {
		before(setup());

		it("should order by that property ascending", function (done) {
			Person.find().order("age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].age.should.equal(18);
				instances[2].age.should.equal(20);

				return done();
			});
		});
	});

	describe(".order('-property')", function () {
		before(setup());

		it("should order by that property descending", function (done) {
			Person.find().order("-age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].age.should.equal(20);
				instances[2].age.should.equal(18);

				return done();
			});
		});
	});

	describe(".order('property', 'Z')", function () {
		before(setup());

		it("should order by that property descending", function (done) {
			Person.find().order("age", "Z").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].age.should.equal(20);
				instances[2].age.should.equal(18);

				return done();
			});
		});
	});

	describe(".only('property', ...)", function () {
		before(setup());

		it("should return only those properties, others null", function (done) {
			Person.find().only("age", "surname").order("-age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].should.have.property("age");
				instances[0].should.have.property("surname", "Doe");
				instances[0].should.have.property("name", null);

				return done();
			});
		});
	});

	describe(".only('property1', ...)", function () {
		before(setup());

		it("should return only those properties, others null", function (done) {
			Person.find().only([ "age", "surname" ]).order("-age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].should.have.property("age");
				instances[0].should.have.property("surname", "Doe");
				instances[0].should.have.property("name", null);

				return done();
			});
		});
	});

	describe(".count()", function () {
		before(setup());

		it("should return only the total number of results", function (done) {
			Person.find().count(function (err, count) {
				should.equal(err, null);
				count.should.equal(3);

				return done();
			});
		});
	});

	describe(".first()", function () {
		before(setup());

		it("should return only the first element", function (done) {
			Person.find().order("-age").first(function (err, JaneDoe) {
				should.equal(err, null);

				JaneDoe.name.should.equal("Jane");
				JaneDoe.surname.should.equal("Doe");
				JaneDoe.age.should.equal(20);

				return done();
			});
		});

		it("should return null if not found", function (done) {
			Person.find({ name: "Jack" }).first(function (err, Jack) {
				should.equal(err, null);
				should.equal(Jack, null);

				return done();
			});
		});
	});

	describe(".last()", function () {
		before(setup());

		it("should return only the last element", function (done) {
			Person.find().order("age").last(function (err, JaneDoe) {
				should.equal(err, null);

				JaneDoe.name.should.equal("Jane");
				JaneDoe.surname.should.equal("Doe");
				JaneDoe.age.should.equal(20);

				return done();
			});
		});

		it("should return null if not found", function (done) {
			Person.find({ name: "Jack" }).last(function (err, Jack) {
				should.equal(err, null);
				should.equal(Jack, null);

				return done();
			});
		});
	});

	describe(".find()", function () {
		before(setup());

		it("should not change find if no arguments", function (done) {
			Person.find().find().count(function (err, count) {
				should.equal(err, null);
				count.should.equal(3);

				return done();
			});
		});

		it("should restrict conditions if passed", function (done) {
			Person.find().find({ age: 18 }).count(function (err, count) {
				should.equal(err, null);
				count.should.equal(2);

				return done();
			});
		});

		it("should restrict conditions if passed and also be chainable", function (done) {
			Person.find().find({ age: 18 }).find({ name: "Jane" }).count(function (err, count) {
				should.equal(err, null);
				count.should.equal(1);

				return done();
			});
		});

		it("should return results if passed a callback as second argument", function (done) {
			Person.find().find({ age: 18 }, function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 2);

				return done();
			});
		});
	});

	describe(".each()", function () {
		before(setup());

		it("should return a ChainInstance", function (done) {
			var chain = Person.find().each();

			chain.filter.should.be.a("function");
			chain.sort.should.be.a("function");
			chain.count.should.be.a("function");

			return done();
		});
	});

	describe(".remove()", function () {
		before(setup());

		it("should have no problems if no results found", function (done) {
			Person.find({ age: 22 }).remove(function (err) {
				should.equal(err, null);

				Person.find().count(function (err, count) {
					should.equal(err, null);

					count.should.equal(3);

					return done();
				});
			});
		});

		it("should remove results and give feedback", function (done) {
			Person.find({ age: 20 }).remove(function (err) {
				should.equal(err, null);

				Person.find().count(function (err, count) {
					should.equal(err, null);

					count.should.equal(2);

					return done();
				});
			});
		});
	});

	describe(".each()", function () {
		before(setup());

		it("should return a ChainFind", function (done) {
			var chain = Person.find({ age: 22 }).each();

			chain.should.be.a("object");
			chain.filter.should.be.a("function");
			chain.sort.should.be.a("function");
			chain.count.should.be.a("function");
			chain.get.should.be.a("function");
			chain.save.should.be.a("function");

			return done();
		});

		describe(".count()", function () {
			it("should return the total filtered items", function (done) {
				Person.find().each().filter(function (person) {
					return (person.age > 18);
				}).count(function (count) {
					count.should.equal(1);

					return done();
				});
			});
		});

		describe(".sort()", function () {
			it("should return the items sorted using the sorted function", function (done) {
				Person.find().each().sort(function (first, second) {
					return (first.age < second.age);
				}).get(function (people) {
					should(Array.isArray(people));

					people.length.should.equal(3);
					people[0].age.should.equal(20);
					people[2].age.should.equal(18);

					return done();
				});
			});
		});

		describe(".save()", function () {
			it("should save items after changes", function (done) {
				Person.find({ surname: "Dean" }).each(function (person) {
					person.should.not.equal(45);
					person.age = 45;
				}).save(function () {
					Person.find({ surname: "Dean" }, function (err, people) {
						should(Array.isArray(people));

						people.length.should.equal(1);
						people[0].age.should.equal(45);

						return done();
					});
				});
			});
		});

		describe("if passing a callback", function () {
			it("should use it to .forEach()", function (done) {
				Person.find({ surname: "Dean" }).each(function (person) {
					person.fullName = person.name + " " + person.surname;
				}).get(function (people) {
					should(Array.isArray(people));

					people.length.should.equal(1);
					people[0].fullName = "Jane Dean";

					return done();
				});
			});
		});

		describe(".hasAccessor() for hasOne associations", function () {
			it("should be chainable", function (done) {
				Person.find({ name: "John" }, function (err, John) {
					should.equal(err, null);

					var Justin = new Person({
						name : "Justin",
						age  : 45
					});

					John[0].setParents([ Justin ], function (err) {
						should.equal(err, null);

						Person.find().hasParents(Justin.id).all(function (err, people) {
							should.equal(err, null);

							should(Array.isArray(people));

							people.length.should.equal(1);
							people[0].name.should.equal("John");

							return done();
						});
					});
				});
			});
		});
	});
});
<commit_msg>Fixes test typo in commit 2de728358704e50631e5ec68bba0fe4090357509<commit_after>var should   = require('should');
var helper   = require('../support/spec_helper');
var ORM      = require('../../');

describe("Model.find() chaining", function() {
	var db = null;
	var Person = null;

	var setup = function () {
		return function (done) {
			Person = db.define("person", {
				name    : String,
				surname : String,
				age     : Number
			});
			Person.hasMany("parents");

			ORM.singleton.clear(); // clear cache

			return helper.dropSync(Person, function () {
				Person.create([{
					name    : "John",
					surname : "Doe",
					age     : 18
				}, {
					name    : "Jane",
					surname : "Doe",
					age     : 20
				}, {
					name    : "Jane",
					surname : "Dean",
					age     : 18
				}], done);
			});
		};
	};

	before(function (done) {
		helper.connect(function (connection) {
			db = connection;

			return done();
		});
	});

	after(function () {
		return db.close();
	});

	describe(".limit(N)", function () {
		before(setup());

		it("should limit results to N items", function (done) {
			Person.find().limit(2).run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 2);

				return done();
			});
		});
	});

	describe(".skip(N)", function () {
		before(setup());

		it("should skip the first N results", function (done) {
			Person.find().skip(2).order("age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 1);
				instances[0].age.should.equal(20);

				return done();
			});
		});
	});

	describe(".offset(N)", function () {
		before(setup());

		it("should skip the first N results", function (done) {
			Person.find().offset(2).order("age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 1);
				instances[0].age.should.equal(20);

				return done();
			});
		});
	});

	describe(".order('property')", function () {
		before(setup());

		it("should order by that property ascending", function (done) {
			Person.find().order("age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].age.should.equal(18);
				instances[2].age.should.equal(20);

				return done();
			});
		});
	});

	describe(".order('-property')", function () {
		before(setup());

		it("should order by that property descending", function (done) {
			Person.find().order("-age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].age.should.equal(20);
				instances[2].age.should.equal(18);

				return done();
			});
		});
	});

	describe(".order('property', 'Z')", function () {
		before(setup());

		it("should order by that property descending", function (done) {
			Person.find().order("age", "Z").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].age.should.equal(20);
				instances[2].age.should.equal(18);

				return done();
			});
		});
	});

	describe(".only('property', ...)", function () {
		before(setup());

		it("should return only those properties, others null", function (done) {
			Person.find().only("age", "surname").order("-age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].should.have.property("age");
				instances[0].should.have.property("surname", "Doe");
				instances[0].should.have.property("name", null);

				return done();
			});
		});
	});

	describe(".only('property1', ...)", function () {
		before(setup());

		it("should return only those properties, others null", function (done) {
			Person.find().only([ "age", "surname" ]).order("-age").run(function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 3);
				instances[0].should.have.property("age");
				instances[0].should.have.property("surname", "Doe");
				instances[0].should.have.property("name", null);

				return done();
			});
		});
	});

	describe(".count()", function () {
		before(setup());

		it("should return only the total number of results", function (done) {
			Person.find().count(function (err, count) {
				should.equal(err, null);
				count.should.equal(3);

				return done();
			});
		});
	});

	describe(".first()", function () {
		before(setup());

		it("should return only the first element", function (done) {
			Person.find().order("-age").first(function (err, JaneDoe) {
				should.equal(err, null);

				JaneDoe.name.should.equal("Jane");
				JaneDoe.surname.should.equal("Doe");
				JaneDoe.age.should.equal(20);

				return done();
			});
		});

		it("should return null if not found", function (done) {
			Person.find({ name: "Jack" }).first(function (err, Jack) {
				should.equal(err, null);
				should.equal(Jack, null);

				return done();
			});
		});
	});

	describe(".last()", function () {
		before(setup());

		it("should return only the last element", function (done) {
			Person.find().order("age").last(function (err, JaneDoe) {
				should.equal(err, null);

				JaneDoe.name.should.equal("Jane");
				JaneDoe.surname.should.equal("Doe");
				JaneDoe.age.should.equal(20);

				return done();
			});
		});

		it("should return null if not found", function (done) {
			Person.find({ name: "Jack" }).last(function (err, Jack) {
				should.equal(err, null);
				should.equal(Jack, null);

				return done();
			});
		});
	});

	describe(".find()", function () {
		before(setup());

		it("should not change find if no arguments", function (done) {
			Person.find().find().count(function (err, count) {
				should.equal(err, null);
				count.should.equal(3);

				return done();
			});
		});

		it("should restrict conditions if passed", function (done) {
			Person.find().find({ age: 18 }).count(function (err, count) {
				should.equal(err, null);
				count.should.equal(2);

				return done();
			});
		});

		it("should restrict conditions if passed and also be chainable", function (done) {
			Person.find().find({ age: 18 }).find({ name: "Jane" }).count(function (err, count) {
				should.equal(err, null);
				count.should.equal(1);

				return done();
			});
		});

		it("should return results if passed a callback as second argument", function (done) {
			Person.find().find({ age: 18 }, function (err, instances) {
				should.equal(err, null);
				instances.should.have.property("length", 2);

				return done();
			});
		});
	});

	describe(".each()", function () {
		before(setup());

		it("should return a ChainInstance", function (done) {
			var chain = Person.find().each();

			chain.filter.should.be.a("function");
			chain.sort.should.be.a("function");
			chain.count.should.be.a("function");

			return done();
		});
	});

	describe(".remove()", function () {
		before(setup());

		it("should have no problems if no results found", function (done) {
			Person.find({ age: 22 }).remove(function (err) {
				should.equal(err, null);

				Person.find().count(function (err, count) {
					should.equal(err, null);

					count.should.equal(3);

					return done();
				});
			});
		});

		it("should remove results and give feedback", function (done) {
			Person.find({ age: 20 }).remove(function (err) {
				should.equal(err, null);

				Person.find().count(function (err, count) {
					should.equal(err, null);

					count.should.equal(2);

					return done();
				});
			});
		});
	});

	describe(".each()", function () {
		before(setup());

		it("should return a ChainFind", function (done) {
			var chain = Person.find({ age: 22 }).each();

			chain.should.be.a("object");
			chain.filter.should.be.a("function");
			chain.sort.should.be.a("function");
			chain.count.should.be.a("function");
			chain.get.should.be.a("function");
			chain.save.should.be.a("function");

			return done();
		});

		describe(".count()", function () {
			it("should return the total filtered items", function (done) {
				Person.find().each().filter(function (person) {
					return (person.age > 18);
				}).count(function (count) {
					count.should.equal(1);

					return done();
				});
			});
		});

		describe(".sort()", function () {
			it("should return the items sorted using the sorted function", function (done) {
				Person.find().each().sort(function (first, second) {
					return (first.age < second.age);
				}).get(function (people) {
					should(Array.isArray(people));

					people.length.should.equal(3);
					people[0].age.should.equal(20);
					people[2].age.should.equal(18);

					return done();
				});
			});
		});

		describe(".save()", function () {
			it("should save items after changes", function (done) {
				Person.find({ surname: "Dean" }).each(function (person) {
					person.age.should.not.equal(45);
					person.age = 45;
				}).save(function () {
					Person.find({ surname: "Dean" }, function (err, people) {
						should(Array.isArray(people));

						people.length.should.equal(1);
						people[0].age.should.equal(45);

						return done();
					});
				});
			});
		});

		describe("if passing a callback", function () {
			it("should use it to .forEach()", function (done) {
				Person.find({ surname: "Dean" }).each(function (person) {
					person.fullName = person.name + " " + person.surname;
				}).get(function (people) {
					should(Array.isArray(people));

					people.length.should.equal(1);
					people[0].fullName = "Jane Dean";

					return done();
				});
			});
		});

		describe(".hasAccessor() for hasOne associations", function () {
			it("should be chainable", function (done) {
				Person.find({ name: "John" }, function (err, John) {
					should.equal(err, null);

					var Justin = new Person({
						name : "Justin",
						age  : 45
					});

					John[0].setParents([ Justin ], function (err) {
						should.equal(err, null);

						Person.find().hasParents(Justin.id).all(function (err, people) {
							should.equal(err, null);

							should(Array.isArray(people));

							people.length.should.equal(1);
							people[0].name.should.equal("John");

							return done();
						});
					});
				});
			});
		});
	});
});
<|endoftext|>


<commit_before>// TODO: Exibir filtros só em  específicos

function testPatternAgainstValue(p, v) {
  // TODO: Aceitar expressões matemáticas nos filtros (<, >)
  return !v.includes(p);
}

function updateFilters () {
  // TODO: atualizar só o Filterable pai do elemento que disparou o evento
  $('.filterable').each(function() {

    // Cria array com os filtros.
    var patterns = $(this)
                      .find('.filterable-filter-row th input')
                      .map(function() {
                        return $(this).val();
                      }).toArray();

    // Itera por cada linha da tabela e testa se passa no filtro.
    $(this).find('tbody tr').each(function() {
      // Mostra a linha
      $(this).show();

      // Mapeia cada célula da linha para um elemento na array
      var values = $(this)
                      .children()
                      .map(function() {
                        return $(this).text();
                      });

      var patternValuePair = _.zip(patterns, values);
      var patternMatch = _.map(patternValuePair, testPatternAgainstValue);

      // Se algum filtro não passar....
      if (_.any(patternMatch)) {
        $(this).hide();
      }

    }); // $(this).find('tbody tr').each(function() {
  });
}

// A rotina seleciona todas as tabelas com .filterable.
// Cada tabela com filtros deve ter o
 bem especificado.
// Nós criaremos uma nova
 com class .filterable-filter-row
// dentro do
, e colocaremos uma  para cada coluna da tabela.
// Dentro de cada , colocaremos um <input> que será usado para os filtros.
function setupFilters () {
  $("table.filterable").each(function() {
    table = $(this);
    tableHead = table.find('thead');
    tableHead.append("

")
    tableHead.find('th').each(function() {
      $('<input></input>	')
        .appendTo(tableHead.find('.filterable-filter-row'))
        .change(function() {
          updateFilters();
        });
    });
  });
}

$(document).ready(setupFilters);
<commit_msg>Adds support for using filters only on given columns<commit_after>function testPatternAgainstValue(p, v) {
  return !v.includes(p);
}

function updateFilters () {
    console.log('updateFilters');

    $('table.ef').each(function(i, table) {
        var patterns = $(table).find('thead tr.ef-filter-row th').map(function (j, columnFilter) {
            if ($(columnFilter).hasClass('ef-column-filter')) {
                var inputBox = $(columnFilter).find('input');
                return inputBox.val();
            } else {
                return "";
            }
        }).toArray();

        $(table).find('tbody tr').each(function (j, row) {

            var values = $(row).find('td').map(function (k, cell) {
                return $(cell).text();
            }).toArray();

            patternsAndValues = _.zip(patterns, values);
            results = _.map(patternsAndValues, function (e) {
                return testPatternAgainstValue(e[0], e[1]);
            });

            if (_.any(results)) {
                $(row).hide();

            } else {
                $(row).show();
            }

        });

     });

}

function setupTable(t) {

    $(t).find('thead')
        .append("

");

    $(t).find('thead tr.ef-header th').each(function (i, elem) {
        if ($(elem).hasClass('ef-column')) {
            $(t).find('thead tr.ef-filter-row').append("<input class='ef-input'></input>	");
        } else {
            $(t).find('thead tr.ef-filter-row').append("	");
        }
    });

    $(".ef-input").change(function () {
       updateFilters();
    });
}

function setupFilters() {
    $("table.ef").each(function () {
        setupTable(this);
    });
}

$(document).ready(setupFilters);
<|endoftext|>


<commit_before><commit_msg>Javascript Addition<commit_after><|endoftext|>


<commit_before>import { registerWaiter, unregisterWaiter } from '@ember/test';
import { computed } from '@ember/object';
import { A } from '@ember/array';
import Service from '@ember/service';
import { DEBUG } from '@glimmer/env';
import Ember from 'ember';
import { task } from '../ember-scheduler';
import {
  microwait,
  rAF,
  afterRender,
  allSettled
} from '../concurrency-helpers';

const MotionService = Service.extend({
  init() {
    this._super();
    this._rendezvous = [];
    this._measurements = [];
    this._animators = A();
    this._orphanObserver = null;
    this._animationObservers = [];
    this._descendantObservers = [];
    this._ancestorObservers = new WeakMap();
  },

  // === Notification System ===

  // Ever animator should register and unregister itself so we know
  // when there are any animations running. Animators are required to
  // have:
  //    - an isAnimating property
  //    - beginStaticMeasurement and endStaticMeasurement methods
  register(animator) {
    this._animators.pushObject(animator);
    return this;
  },
  unregister(animator) {
    this._animators.removeObject(animator);
    return this;
  },

  // Register to receive any sprites that are orphaned by a destroyed
  // animator.
  observeOrphans(fn) {
    if (this._orphanObserver) {
      throw new Error("Only one animated-orphans component can be used at one time");
    }
    this._orphanObserver = fn;
    return this;
  },
  unobserveOrphans(fn) {
    if (this._orphanObserver === fn) {
      this._orphanObserver = null;
    }
    return this;
  },

  // Register to know when an animation is starting anywhere in the app.
  observeAnimations(fn) {
    this._animationObservers.push(fn);
    return this;
  },
  unobserveAnimations(fn) {
    let index = this._animationObservers.indexOf(fn);
    if (index !== -1) {
      this._animationObservers.splice(fn, 1);
    }
    return this;
  },

  // Register to know when an animation is starting within the
  // descendants of the given component
  observeDescendantAnimations(component, fn) {
    this._descendantObservers.push({ component, fn });
    return this;
  },
  unobserveDescendantAnimations(component, fn) {
    let index = this._descendantObservers.find(e => e.component === component && e.fn === fn);
    if (index !== -1) {
      this._descendantObservers.splice(fn, 1);
    }
    return this;
  },

  // Register to know when an animation is starting among the
  // ancestors of the given component. The fn will be told whether
  // component is going to be destroyed or not at the end of the
  // animation.
  observeAncestorAnimations(component, fn) {
    let id;
    for (let ancestorComponent of ancestorsOf(component)) {
      // when we find an animated list element, we save its ID
      if (ancestorComponent.isEmberAnimatedListElement) {
        id = ancestorComponent.get('child.id');
      } else if (id != null) {
        // if we found an ID on the last loop, now we've got the list
        // element's parent which is the actual animator.
        let observers = this._ancestorObservers.get(ancestorComponent);
        if (!observers) {
          this._ancestorObservers.set(ancestorComponent, observers = new Map());
        }
        observers.set(fn, id);
        id = null;
      }
    }
    return this;
  },
  unobserveAncestorAnimations(component, fn){
    for (let ancestorComponent of ancestorsOf(component)) {
      let observers = this._ancestorObservers.get(ancestorComponent);
      if (observers) {
        observers.delete(fn);
      }
    }
    return this;
  },

  // This is a publicly visible property you can use to know if any
  // animations are running. It's timing is deliberately not
  // synchronous, so that you can bind it into a template without
  // getting double-render errors.
  isAnimating: computed(function () {
    return this.get('isAnimatingSync');
  }),

  // Synchronously updated version of isAnimating. If you try to
  // depend on this in a template you will get double-render errors
  // (because the act of rendering can cause animations to begin).
  isAnimatingSync: computed('_animators.@each.isAnimating', function() {
    return this.get('_animators').any(animator => animator.get('isAnimating'));
  }),

  // Invalidation support for isAnimating
  _invalidateIsAnimating: task(function * () {
    yield rAF();
    this.notifyPropertyChange('isAnimating');
  }).observes('isAnimatingSync'),

  waitUntilIdle: task(function * () {
    // we are idle if we experience two frames in a row with nothing
    // animating.
    while (true) {
      yield rAF();
      if (!this.get('isAnimatingSync')) {
        yield rAF();
        if (!this.get('isAnimatingSync')) {
          return;
        }
      }
    }
  }),

  matchDestroyed(removed, transition, duration) {
    if (this._orphanObserver && transition && removed.length > 0) {
      // if these orphaned sprites may be capable of animating,
      // delegate them to the orphanObserver. It will do farMatching
      // for them.
      this._orphanObserver(removed, transition, duration);
    } else {
      // otherwise, we make them available for far matching but they
      // can't be animated.
      this.get('farMatch').perform(null, [], [], removed, true);
    }
  },

  farMatch: task(function * (runAnimationTask, inserted, kept, removed, longWait=false) {
    let matches = new Map();
    let mine = { inserted, kept, removed, matches, runAnimationTask, otherTasks: new Map() };
    this._rendezvous.push(mine);
    yield microwait();
    if (longWait) {
      // used by matchDestroyed because it gets called earlier in the
      // render cycle, so it needs to linger longer in order to
      // coincide with other farMatches.
      yield afterRender();
      yield microwait();
      yield microwait();
    }

    if (this.get('farMatch.concurrency') > 1) {
      this._rendezvous.forEach(target => {
        if (target === mine) { return; }
        performMatches(mine, target);
        performMatches(target, mine);
      });
    }
    this._rendezvous.splice(this._rendezvous.indexOf(mine), 1);
    return {
      farMatches: matches,
      matchingAnimatorsFinished: allSettled([...mine.otherTasks.keys()])
    };
  }),

  willAnimate({ task, duration, component, children }) {
    let message = { task, duration };

    // tell any of our ancestors who are observing their descendants
    let ancestors = [...ancestorsOf(component)];
    for (let { component: observingComponent, fn } of this._descendantObservers) {
      if (ancestors.indexOf(observingComponent) !== -1) {
        fn(message);
      }
    }

    // tell any of our descendants who are observing their ancestors
    let observers = this._ancestorObservers.get(component);
    if (observers) {
      for (let [fn, id] of observers.entries()) {
        let child = children.find(child => child.id === id);
        fn(child.state);
      }
    }

    // tell anybody who is listening for all animations
    for (let fn of this._animationObservers) {
      fn(message);
    }
  },

  staticMeasurement: function * (fn) {
    let measurement = { fn, resolved: false, value: null };
    this._measurements.push(measurement);
    try {
      // allow all concurrent animators to join in with our single
      // measurement step instead of having each trigger its own reflow.
      yield microwait();

      if (!measurement.resolved) {
        // we are the first concurrent task to wake up, so we do the
        // actual resolution for everyone.
        let animators = this.get('_animators');
        animators.forEach(animator => animator.beginStaticMeasurement());
        this._measurements.forEach(m => {
          try {
            m.value = m.fn();
          } catch(err) {
            setTimeout(function() { throw err; }, 0);
          }
          m.resolved = true;
        });
        animators.forEach(animator => animator.endStaticMeasurement());
      }
      return measurement.value;
    } finally {
      this._measurements.splice(this._measurements.indexOf(measurement), 1);
    }
  }

});

function performMatches(sink, source) {
  sink.inserted.concat(sink.kept).forEach(sprite => {
    let match = source.removed.find(
      mySprite =>
        sprite.owner.group == mySprite.owner.group &&
          sprite.owner.id === mySprite.owner.id
    );
    if (match) {
      sink.matches.set(sprite, match);
      sink.otherTasks.set(source.runAnimationTask, true);
      source.matches.set(match, sprite);
      source.otherTasks.set(sink.runAnimationTask, true);
    }
  });
}

function * ancestorsOf(component) {
  let pointer = component.parentView;
  while (pointer) {
    yield pointer;
    pointer = pointer.parentView;
  }
}

// This layer will cause everything inside to be stripped from prod builds via dead code elimination.
if (DEBUG) {

  // Then within non-production builds, this hooks into Ember's test
  // system but only when tests are actually running.
  if (Ember.testing) {

    let idleFrames = 0;
    const isIdle = function() {
      return idleFrames > 2;
    };

    MotionService.reopen({
      init() {
        this._super(...arguments);
        registerWaiter(isIdle);
        this.get('idlePoller').perform();
      },

      willDestroy() {
        unregisterWaiter(isIdle);
        this._super(...arguments);
      },

      idlePoller: task(function * () {
        while (true) {
          yield rAF();
          if (this.get('isAnimatingSync')) {
            idleFrames = 0;
          } else {
            idleFrames++;
          }
        }
      })
    });
  }
}

export default MotionService;
<commit_msg>our new animationsSettled supercedes the need for registerWaiter<commit_after>import { computed } from '@ember/object';
import { A } from '@ember/array';
import Service from '@ember/service';
import { task } from '../ember-scheduler';
import {
  microwait,
  rAF,
  afterRender,
  allSettled
} from '../concurrency-helpers';

const MotionService = Service.extend({
  init() {
    this._super();
    this._rendezvous = [];
    this._measurements = [];
    this._animators = A();
    this._orphanObserver = null;
    this._animationObservers = [];
    this._descendantObservers = [];
    this._ancestorObservers = new WeakMap();
  },

  // === Notification System ===

  // Ever animator should register and unregister itself so we know
  // when there are any animations running. Animators are required to
  // have:
  //    - an isAnimating property
  //    - beginStaticMeasurement and endStaticMeasurement methods
  register(animator) {
    this._animators.pushObject(animator);
    return this;
  },
  unregister(animator) {
    this._animators.removeObject(animator);
    return this;
  },

  // Register to receive any sprites that are orphaned by a destroyed
  // animator.
  observeOrphans(fn) {
    if (this._orphanObserver) {
      throw new Error("Only one animated-orphans component can be used at one time");
    }
    this._orphanObserver = fn;
    return this;
  },
  unobserveOrphans(fn) {
    if (this._orphanObserver === fn) {
      this._orphanObserver = null;
    }
    return this;
  },

  // Register to know when an animation is starting anywhere in the app.
  observeAnimations(fn) {
    this._animationObservers.push(fn);
    return this;
  },
  unobserveAnimations(fn) {
    let index = this._animationObservers.indexOf(fn);
    if (index !== -1) {
      this._animationObservers.splice(fn, 1);
    }
    return this;
  },

  // Register to know when an animation is starting within the
  // descendants of the given component
  observeDescendantAnimations(component, fn) {
    this._descendantObservers.push({ component, fn });
    return this;
  },
  unobserveDescendantAnimations(component, fn) {
    let index = this._descendantObservers.find(e => e.component === component && e.fn === fn);
    if (index !== -1) {
      this._descendantObservers.splice(fn, 1);
    }
    return this;
  },

  // Register to know when an animation is starting among the
  // ancestors of the given component. The fn will be told whether
  // component is going to be destroyed or not at the end of the
  // animation.
  observeAncestorAnimations(component, fn) {
    let id;
    for (let ancestorComponent of ancestorsOf(component)) {
      // when we find an animated list element, we save its ID
      if (ancestorComponent.isEmberAnimatedListElement) {
        id = ancestorComponent.get('child.id');
      } else if (id != null) {
        // if we found an ID on the last loop, now we've got the list
        // element's parent which is the actual animator.
        let observers = this._ancestorObservers.get(ancestorComponent);
        if (!observers) {
          this._ancestorObservers.set(ancestorComponent, observers = new Map());
        }
        observers.set(fn, id);
        id = null;
      }
    }
    return this;
  },
  unobserveAncestorAnimations(component, fn){
    for (let ancestorComponent of ancestorsOf(component)) {
      let observers = this._ancestorObservers.get(ancestorComponent);
      if (observers) {
        observers.delete(fn);
      }
    }
    return this;
  },

  // This is a publicly visible property you can use to know if any
  // animations are running. It's timing is deliberately not
  // synchronous, so that you can bind it into a template without
  // getting double-render errors.
  isAnimating: computed(function () {
    return this.get('isAnimatingSync');
  }),

  // Synchronously updated version of isAnimating. If you try to
  // depend on this in a template you will get double-render errors
  // (because the act of rendering can cause animations to begin).
  isAnimatingSync: computed('_animators.@each.isAnimating', function() {
    return this.get('_animators').any(animator => animator.get('isAnimating'));
  }),

  // Invalidation support for isAnimating
  _invalidateIsAnimating: task(function * () {
    yield rAF();
    this.notifyPropertyChange('isAnimating');
  }).observes('isAnimatingSync'),

  waitUntilIdle: task(function * () {
    // we are idle if we experience two frames in a row with nothing
    // animating.
    while (true) {
      yield rAF();
      if (!this.get('isAnimatingSync')) {
        yield rAF();
        if (!this.get('isAnimatingSync')) {
          return;
        }
      }
    }
  }),

  matchDestroyed(removed, transition, duration) {
    if (this._orphanObserver && transition && removed.length > 0) {
      // if these orphaned sprites may be capable of animating,
      // delegate them to the orphanObserver. It will do farMatching
      // for them.
      this._orphanObserver(removed, transition, duration);
    } else {
      // otherwise, we make them available for far matching but they
      // can't be animated.
      this.get('farMatch').perform(null, [], [], removed, true);
    }
  },

  farMatch: task(function * (runAnimationTask, inserted, kept, removed, longWait=false) {
    let matches = new Map();
    let mine = { inserted, kept, removed, matches, runAnimationTask, otherTasks: new Map() };
    this._rendezvous.push(mine);
    yield microwait();
    if (longWait) {
      // used by matchDestroyed because it gets called earlier in the
      // render cycle, so it needs to linger longer in order to
      // coincide with other farMatches.
      yield afterRender();
      yield microwait();
      yield microwait();
    }

    if (this.get('farMatch.concurrency') > 1) {
      this._rendezvous.forEach(target => {
        if (target === mine) { return; }
        performMatches(mine, target);
        performMatches(target, mine);
      });
    }
    this._rendezvous.splice(this._rendezvous.indexOf(mine), 1);
    return {
      farMatches: matches,
      matchingAnimatorsFinished: allSettled([...mine.otherTasks.keys()])
    };
  }),

  willAnimate({ task, duration, component, children }) {
    let message = { task, duration };

    // tell any of our ancestors who are observing their descendants
    let ancestors = [...ancestorsOf(component)];
    for (let { component: observingComponent, fn } of this._descendantObservers) {
      if (ancestors.indexOf(observingComponent) !== -1) {
        fn(message);
      }
    }

    // tell any of our descendants who are observing their ancestors
    let observers = this._ancestorObservers.get(component);
    if (observers) {
      for (let [fn, id] of observers.entries()) {
        let child = children.find(child => child.id === id);
        fn(child.state);
      }
    }

    // tell anybody who is listening for all animations
    for (let fn of this._animationObservers) {
      fn(message);
    }
  },

  staticMeasurement: function * (fn) {
    let measurement = { fn, resolved: false, value: null };
    this._measurements.push(measurement);
    try {
      // allow all concurrent animators to join in with our single
      // measurement step instead of having each trigger its own reflow.
      yield microwait();

      if (!measurement.resolved) {
        // we are the first concurrent task to wake up, so we do the
        // actual resolution for everyone.
        let animators = this.get('_animators');
        animators.forEach(animator => animator.beginStaticMeasurement());
        this._measurements.forEach(m => {
          try {
            m.value = m.fn();
          } catch(err) {
            setTimeout(function() { throw err; }, 0);
          }
          m.resolved = true;
        });
        animators.forEach(animator => animator.endStaticMeasurement());
      }
      return measurement.value;
    } finally {
      this._measurements.splice(this._measurements.indexOf(measurement), 1);
    }
  }

});

function performMatches(sink, source) {
  sink.inserted.concat(sink.kept).forEach(sprite => {
    let match = source.removed.find(
      mySprite =>
        sprite.owner.group == mySprite.owner.group &&
          sprite.owner.id === mySprite.owner.id
    );
    if (match) {
      sink.matches.set(sprite, match);
      sink.otherTasks.set(source.runAnimationTask, true);
      source.matches.set(match, sprite);
      source.otherTasks.set(sink.runAnimationTask, true);
    }
  });
}

function * ancestorsOf(component) {
  let pointer = component.parentView;
  while (pointer) {
    yield pointer;
    pointer = pointer.parentView;
  }
}

export default MotionService;
<|endoftext|>


<commit_before>const Pulse = require('./adt-pulse.js');
const mqtt = require('mqtt');
var config = require('/data/options.json');

var myAlarm = new Pulse(config.pulse_login.username, config.pulse_login.password);

// Use mqtt_url option if specified, otherwise build URL using host option
if (config.mqtt_url) {
   var client = new mqtt.connect(config.mqtt_url, config.mqtt_options);
}
else {
   var client = new mqtt.connect("mqtt://"+config.mqtt_host,config.mqtt_connect_options);
}

var alarm_state_topic = config.alarm_state_topic;
var alarm_command_topic = config.alarm_command_topic;
var zone_state_topic = config.zone_state_topic;
var smartthings_topic = config.smartthings_topic;
var smartthings = config.smartthings;

var alarm_last_state = "unknown";
var devices = {};

client.on('connect', function () {
  console.log("MQTT Sub to: "+alarm_command_topic);
  client.subscribe(alarm_command_topic)
  if (smartthings){
      client.subscribe(smartthings_topic+"/ADT Alarm System/alarm/state")
  }
});

client.on('message', function (topic, message) {
  console.log((new Date()).toLocaleString()+" Received Message:"+ topic + ":"+message);

  if (smartthings && topic==smartthings_topic+"/ADT Alarm System/alarm/state" && message.toString().includes("_push")){
      var toState=null;

      switch (message.toString()){
        case "off_push":
          toState="disarm";
          break;
        case "stay_push":
          toState="arm_home";
          break;
        case "away_push":
          toState="arm_away";
          break;
      }
      console.log((new Date()).toLocaleString()+" Pushing alarm state to Hass:"+toState);

      if (toState!=null){
        client.publish(alarm_command_topic, toState,{"retain":false});
      }
      return;
  }
  if (topic!=alarm_command_topic){
    return;
  }

  var msg = message.toString();
  var action;
  var prev_state="disarmed";

  if(alarm_last_state=="armed_home") prev_state = "stay";
  if(alarm_last_state=="armed_away") prev_state = "away";

  if (msg =="arm_home"){
      action= {'newstate':'stay','prev_state':prev_state};
  }
  else if (msg=="disarm") {
     action= {'newstate':'disarm','prev_state':prev_state};
  }
  else if (msg=="arm_away") {
    action = {'newstate':'away','prev_state':prev_state};
  }  else{ // I don't know this mode #5
      console.log((new Date()).toLocaleString()+" Unsupportated state requested:"+msg);
      return;
  }

  myAlarm.setAlarmState(action);
});

// Register Callbacks:
myAlarm.onDeviceUpdate(
    function(device) {
        console.log("Device callback"+ JSON.stringify(device));
    }
);

myAlarm.onStatusUpdate(
  function(device) {
      var mqtt_state = "unknown";
      var sm_alarm_value = "off";

      var status = device.status.toLowerCase();

      // smartthings bridge has no typical alarm device with stay|away|alarm|home status.
      // we'll re-use the "alarm" and map strobe|siren|both|off to stay|away|alarm|home
      // Sorry I'm too lazy to write my own smartthngs bridge for now.

      if (status.includes('disarmed')) {
          mqtt_state = "disarmed";
          sm_alarm_value = "off";
      }
      if (status.includes('armed stay')) {
          mqtt_state = "armed_home";
          sm_alarm_value = "strobe";
      }
      if (status.includes('armed away')) {
          mqtt_state = "armed_away";
          sm_alarm_value = "siren";
      }
      if (status.includes('alarm')) {
          mqtt_state = "triggered";
          sm_alarm_value = "both";
      }
      if (status.includes('arming')) {
          mqtt_state = "pending";
          sm_alarm_value = "siren"; // temporary
      }

      if (!mqtt_state.includes(alarm_last_state) && !mqtt_state.includes('unknown')) {
         console.log((new Date()).toLocaleString()+": Pushing alarm state: "+mqtt_state+" to "+alarm_state_topic);
         client.publish(alarm_state_topic, mqtt_state,{"retain":true});
         if (smartthings){
           var sm_alarm_topic = smartthings_topic+"/ADT Alarm System/alarm/cmd";
           console.log((new Date()).toLocaleString()+": Pushing alarm state to smartthings"+sm_alarm_topic);
           client.publish(sm_alarm_topic, sm_alarm_value,{"retain":false});
         }
		  alarm_last_state = mqtt_state;
      }
  }
);

myAlarm.onZoneUpdate(
  function(device) {

    var dev_zone_state_topic = zone_state_topic+"/"+device.name+"/state";
    //var devValue = JSON.stringify(device);
    var sm_dev_zone_state_topic;

    // smartthings bridge assumes actionable devices have a topic set with cmd
    // adt/zone/DEVICE_NAME/state needs to turn into
    // smartthings/DEVICE_NAME/door/cmd
    // or
    // smartthings/DEVICE_NAME/motion/cmd

    if (smartthings){
      var contactType = "door";
      var contactValue= (device.state == "devStatOK")? "closed":"open";

      if (device.tags.includes("motion")) {
        contactType="motion";
        contactValue = (device.states == "devStatOK")? "inactive":"active";
      }
       sm_dev_zone_state_topic=smartthings_topic+"/"+device.name+"/"+contactType+"/cmd";
    }

    if (devices[device.id]==null || device.timestamp > devices[device.id].timestamp) {
        client.publish(dev_zone_state_topic, device.state, {"retain":false});
        console.log((new Date()).toLocaleString()+": Pushing  "+dev_zone_state_topic+" to "+device.state);

        if (smartthings){
          client.publish(sm_dev_zone_state_topic, contactValue, {"retain":false});
          console.log((new Date()).toLocaleString()+": Pushing to smartthings: "+sm_dev_zone_state_topic+" to "+contactValue);
        }
	  }
      devices[device.id] = device;
  }
);

myAlarm.pulse();
<commit_msg>Update logging message to be more clear<commit_after>const Pulse = require('./adt-pulse.js');
const mqtt = require('mqtt');
var config = require('/data/options.json');

var myAlarm = new Pulse(config.pulse_login.username, config.pulse_login.password);

// Use mqtt_url option if specified, otherwise build URL using host option
if (config.mqtt_url) {
   var client = new mqtt.connect(config.mqtt_url, config.mqtt_options);
}
else {
   var client = new mqtt.connect("mqtt://"+config.mqtt_host,config.mqtt_connect_options);
}

var alarm_state_topic = config.alarm_state_topic;
var alarm_command_topic = config.alarm_command_topic;
var zone_state_topic = config.zone_state_topic;
var smartthings_topic = config.smartthings_topic;
var smartthings = config.smartthings;

var alarm_last_state = "unknown";
var devices = {};

client.on('connect', function () {
  console.log("MQTT Sub to: "+alarm_command_topic);
  client.subscribe(alarm_command_topic)
  if (smartthings){
      client.subscribe(smartthings_topic+"/ADT Alarm System/alarm/state")
  }
});

client.on('message', function (topic, message) {
  console.log((new Date()).toLocaleString()+" Received Message:"+ topic + ":"+message);

  if (smartthings && topic==smartthings_topic+"/ADT Alarm System/alarm/state" && message.toString().includes("_push")){
      var toState=null;

      switch (message.toString()){
        case "off_push":
          toState="disarm";
          break;
        case "stay_push":
          toState="arm_home";
          break;
        case "away_push":
          toState="arm_away";
          break;
      }
      console.log((new Date()).toLocaleString()+" Pushing alarm state to Hass:"+toState);

      if (toState!=null){
        client.publish(alarm_command_topic, toState,{"retain":false});
      }
      return;
  }
  if (topic!=alarm_command_topic){
    return;
  }

  var msg = message.toString();
  var action;
  var prev_state="disarmed";

  if(alarm_last_state=="armed_home") prev_state = "stay";
  if(alarm_last_state=="armed_away") prev_state = "away";

  if (msg =="arm_home"){
      action= {'newstate':'stay','prev_state':prev_state};
  }
  else if (msg=="disarm") {
     action= {'newstate':'disarm','prev_state':prev_state};
  }
  else if (msg=="arm_away") {
    action = {'newstate':'away','prev_state':prev_state};
  }  else{ // I don't know this mode #5
      console.log((new Date()).toLocaleString()+" Unsupportated state requested:"+msg);
      return;
  }

  myAlarm.setAlarmState(action);
});

// Register Callbacks:
myAlarm.onDeviceUpdate(
    function(device) {
        console.log("Device callback"+ JSON.stringify(device));
    }
);

myAlarm.onStatusUpdate(
  function(device) {
      var mqtt_state = "unknown";
      var sm_alarm_value = "off";

      var status = device.status.toLowerCase();

      // smartthings bridge has no typical alarm device with stay|away|alarm|home status.
      // we'll re-use the "alarm" and map strobe|siren|both|off to stay|away|alarm|home
      // Sorry I'm too lazy to write my own smartthngs bridge for now.

      if (status.includes('disarmed')) {
          mqtt_state = "disarmed";
          sm_alarm_value = "off";
      }
      if (status.includes('armed stay')) {
          mqtt_state = "armed_home";
          sm_alarm_value = "strobe";
      }
      if (status.includes('armed away')) {
          mqtt_state = "armed_away";
          sm_alarm_value = "siren";
      }
      if (status.includes('alarm')) {
          mqtt_state = "triggered";
          sm_alarm_value = "both";
      }
      if (status.includes('arming')) {
          mqtt_state = "pending";
          sm_alarm_value = "siren"; // temporary
      }

      if (!mqtt_state.includes(alarm_last_state) && !mqtt_state.includes('unknown')) {
         console.log((new Date()).toLocaleString()+": Pushing alarm state: "+mqtt_state+" to "+alarm_state_topic);
         client.publish(alarm_state_topic, mqtt_state,{"retain":true});
         if (smartthings){
           var sm_alarm_topic = smartthings_topic+"/ADT Alarm System/alarm/cmd";
           console.log((new Date()).toLocaleString()+": Pushing alarm state to smartthings"+sm_alarm_topic);
           client.publish(sm_alarm_topic, sm_alarm_value,{"retain":false});
         }
		  alarm_last_state = mqtt_state;
      }
  }
);

myAlarm.onZoneUpdate(
  function(device) {

    var dev_zone_state_topic = zone_state_topic+"/"+device.name+"/state";
    //var devValue = JSON.stringify(device);
    var sm_dev_zone_state_topic;

    // smartthings bridge assumes actionable devices have a topic set with cmd
    // adt/zone/DEVICE_NAME/state needs to turn into
    // smartthings/DEVICE_NAME/door/cmd
    // or
    // smartthings/DEVICE_NAME/motion/cmd

    if (smartthings){
      var contactType = "door";
      var contactValue= (device.state == "devStatOK")? "closed":"open";

      if (device.tags.includes("motion")) {
        contactType="motion";
        contactValue = (device.states == "devStatOK")? "inactive":"active";
      }
       sm_dev_zone_state_topic=smartthings_topic+"/"+device.name+"/"+contactType+"/cmd";
    }

    if (devices[device.id]==null || device.timestamp > devices[device.id].timestamp) {
        client.publish(dev_zone_state_topic, device.state, {"retain":false});
        console.log((new Date()).toLocaleString()+": Pushing device state: " + device.state+  " to topic " + dev_zone_state_topic);

        if (smartthings){
          client.publish(sm_dev_zone_state_topic, contactValue, {"retain":false});
          console.log((new Date()).toLocaleString()+": Pushing to smartthings: "+sm_dev_zone_state_topic+" to "+contactValue);
        }
	  }
      devices[device.id] = device;
  }
);

myAlarm.pulse();
<|endoftext|>


<commit_before>// satisfy ag-grid HTMLElement dependency
HTMLElement = typeof HTMLElement === 'undefined' ? function () {} : HTMLElement;
HTMLSelectElement = typeof HTMLSelectElement === 'undefined' ? function () {} : HTMLSelectElement;
HTMLInputElement = typeof HTMLInputElement === 'undefined' ? function () {} : HTMLInputElement;
HTMLButtonElement = typeof HTMLButtonElement === 'undefined' ? function () {} : HTMLButtonElement;

require('./node_modules/reflect-metadata');

var {AgGridNg2} = require('./dist/agGridNg2');
var {ComponentUtil} = require("ag-grid/main");

var missingProperties = [];
ComponentUtil.ALL_PROPERTIES.forEach((property) => {
    if (!Reflect.getOwnMetadata('propMetadata', AgGridNg2).hasOwnProperty(property)) {
        missingProperties.push(`Grid property ${property} does not exist on AgGridNg2`)
    }
});

var missingEvents = [];
ComponentUtil.EVENTS.forEach((event) => {
    if (!Reflect.getOwnMetadata('propMetadata', AgGridNg2).hasOwnProperty(event)) {
        missingEvents.push(`Grid event ${event} does not exist on AgGridNg2`)
    }
});

if(missingProperties.length || missingEvents.length) {
    console.error("*************************** BUILD FAILED ***************************");
    missingProperties.concat(missingEvents).forEach((message) => console.error(message));
    console.error("*************************** BUILD FAILED ***************************");

    throw("Build Properties Check Failed");
} else {
    console.info("*************************** BUILD OK ***************************");
}<commit_msg>Fix regression - internal reflect lib changes!<commit_after>// satisfy ag-grid HTMLElement dependency
HTMLElement = typeof HTMLElement === 'undefined' ? function () {} : HTMLElement;
HTMLSelectElement = typeof HTMLSelectElement === 'undefined' ? function () {} : HTMLSelectElement;
HTMLInputElement = typeof HTMLInputElement === 'undefined' ? function () {} : HTMLInputElement;
HTMLButtonElement = typeof HTMLButtonElement === 'undefined' ? function () {} : HTMLButtonElement;

var {AgGridNg2} = require('./dist/agGridNg2');
var {ComponentUtil} = require("ag-grid/main");

var missingProperties = [];
ComponentUtil.ALL_PROPERTIES.forEach((property) => {
    if (!AgGridNg2.propDecorators.hasOwnProperty(property)) {
        missingProperties.push(`Grid property ${property} does not exist on AgGridNg2`)
    }
});

var missingEvents = [];
ComponentUtil.EVENTS.forEach((event) => {
    if (!AgGridNg2.propDecorators.hasOwnProperty(event)) {
        missingEvents.push(`Grid event ${event} does not exist on AgGridNg2`)
    }
});

if(missingProperties.length || missingEvents.length) {
    console.error("*************************** BUILD FAILED ***************************");
    missingProperties.concat(missingEvents).forEach((message) => console.error(message));
    console.error("*************************** BUILD FAILED ***************************");

    throw("Build Properties Check Failed");
} else {
    console.info("*************************** BUILD OK ***************************");
}<|endoftext|>


<commit_before>var _ = require('lodash');
var ProjectUtils = require('./ProjectUtils');
var FormatUtils = require('./FormatUtils');

module.exports = {

  convertDateToUTC: function(date) {
    return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
  },

  /**
   * Takes a time object and returns a string representing the timeframe type (absolute or relative)
   * @param  {Object} time The time object
   * @return {String} The type of timeframe, 'absolute' or 'relative'
   */
   timeframeType: function(time) {
      if (_.isUndefined(time)) {
        return null;
      } else if (!_.isPlainObject(time)) {
        throw new Error('Invalid timeframe type: not a plain object.');
      } else if (_.has(time, 'start') || _.has(time, 'end')) {
        return 'absolute';
      } else if (_.has(time, 'relativity') && _.has(time, 'amount') && _.has(time, 'sub_timeframe')) {
        return 'relative';
      } else {
        throw new Error('Invalid timeframe type: invalid time value.');
      }
   },

  getTimezoneOffset: function(timezone) {
    var zone = _.find(ProjectUtils.getConstant('TIMEZONES'), { value: timezone });
    return zone ? zone.offset : '+00:00';
  },

  timeframeBuilders: {

    absolute: function(time) {
      if (time && time.start && time.end) {
        return {
          start: FormatUtils.formatISOTimeNoTimezone(time.start),
          end: FormatUtils.formatISOTimeNoTimezone(time.end)
        };
      }
    },

    relative: function(time) {
      if (time && time.relativity && time.amount && time.sub_timeframe) {
        return [time.relativity, time.amount, time.sub_timeframe].join('_');
      }
    }

  },

  getTimeframe: function(time) {
    var timeframeBuilder = module.exports.timeframeBuilders[module.exports.timeframeType(time)];
    if (typeof(timeframeBuilder) === 'undefined') return "";
    return timeframeBuilder(time);
  },

  getTimeParameters: function(timeframe, timezone) {
    return {
      timeframe: timeframe ? module.exports.getTimeframe(timeframe) : null,
      timezone: timezone || ProjectUtils.getConstant('DEFAULT_TIMEZONE')
    };
  },

  /**
   * Takes a URL encoded timerame string or object and returns a time object that looks how the Explorer store wants
   * it to
   * @param  {String} timeframe
   * @return {Object}
   * Return structure:
   * {
   *  time: {an Object, either containing a deconstructed absolute or relative timeframe}
   * }
   */
  unpackTimeframeParam: function(timeframe, timezone) {
    if (typeof timeframe === 'object') {
      return module.exports.unpackAbsoluteTimeframe(timeframe, timezone);
    } else if (typeof timeframe === 'string') {
      return module.exports.unpackRelativeTimeframe(timeframe, timezone);
    }
  },

  unpackAbsoluteTimeframe: function (timeframe, timezone) {
    var formattedValue = {
      time: {},
      timezone: null
    };

    if (!timezone || ProjectUtils.getConstant('TIMEZONES').indexOf(timezone) === -1) {
      formattedValue.timezone = 'UTC';
    } else {
      formattedValue.timezone = timezone;
    }

    var startVal = timeframe.start ? timeframe.start.substring(0, 19) : "";
    formattedValue.time.start = FormatUtils.formatISOTimeNoTimezone(module.exports.convertDateToUTC(new Date(startVal)));

    var endVal = timeframe.end ? timeframe.end.substring(0, 19) : "";
    formattedValue.time.end = FormatUtils.formatISOTimeNoTimezone(module.exports.convertDateToUTC(new Date(endVal)));

    return formattedValue;
  },

  unpackRelativeTimeframe: function (timeframe, timezone) {
    var split = timeframe.split('_');
    return {
      time: {
        relativity: split[0],
        amount: split[1],
        sub_timeframe: split[2]
      },
      timezone: timezone
    };
  }

}
<commit_msg>don’t convert date to UTC when unpacking, because timezone is stripped.<commit_after>var _ = require('lodash');
var ProjectUtils = require('./ProjectUtils');
var FormatUtils = require('./FormatUtils');

module.exports = {

  convertDateToUTC: function(date) {
    return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
  },

  /**
   * Takes a time object and returns a string representing the timeframe type (absolute or relative)
   * @param  {Object} time The time object
   * @return {String} The type of timeframe, 'absolute' or 'relative'
   */
   timeframeType: function(time) {
      if (_.isUndefined(time)) {
        return null;
      } else if (!_.isPlainObject(time)) {
        throw new Error('Invalid timeframe type: not a plain object.');
      } else if (_.has(time, 'start') || _.has(time, 'end')) {
        return 'absolute';
      } else if (_.has(time, 'relativity') && _.has(time, 'amount') && _.has(time, 'sub_timeframe')) {
        return 'relative';
      } else {
        throw new Error('Invalid timeframe type: invalid time value.');
      }
   },

  getTimezoneOffset: function(timezone) {
    var zone = _.find(ProjectUtils.getConstant('TIMEZONES'), { value: timezone });
    return zone ? zone.offset : '+00:00';
  },

  timeframeBuilders: {

    absolute: function(time) {
      if (time && time.start && time.end) {
        return {
          start: FormatUtils.formatISOTimeNoTimezone(time.start),
          end: FormatUtils.formatISOTimeNoTimezone(time.end)
        };
      }
    },

    relative: function(time) {
      if (time && time.relativity && time.amount && time.sub_timeframe) {
        return [time.relativity, time.amount, time.sub_timeframe].join('_');
      }
    }

  },

  getTimeframe: function(time) {
    var timeframeBuilder = module.exports.timeframeBuilders[module.exports.timeframeType(time)];
    if (typeof(timeframeBuilder) === 'undefined') return "";
    return timeframeBuilder(time);
  },

  getTimeParameters: function(timeframe, timezone) {
    return {
      timeframe: timeframe ? module.exports.getTimeframe(timeframe) : null,
      timezone: timezone || ProjectUtils.getConstant('DEFAULT_TIMEZONE')
    };
  },

  /**
   * Takes a URL encoded timerame string or object and returns a time object that looks how the Explorer store wants
   * it to
   * @param  {String} timeframe
   * @return {Object}
   * Return structure:
   * {
   *  time: {an Object, either containing a deconstructed absolute or relative timeframe}
   * }
   */
  unpackTimeframeParam: function(timeframe, timezone) {
    if (typeof timeframe === 'object') {
      return module.exports.unpackAbsoluteTimeframe(timeframe, timezone);
    } else if (typeof timeframe === 'string') {
      return module.exports.unpackRelativeTimeframe(timeframe, timezone);
    }
  },

  unpackAbsoluteTimeframe: function (timeframe, timezone) {
    var formattedValue = {
      time: {},
      timezone: null
    };

    if (!timezone || ProjectUtils.getConstant('TIMEZONES').indexOf(timezone) === -1) {
      formattedValue.timezone = 'UTC';
    } else {
      formattedValue.timezone = timezone;
    }

    var startVal = timeframe.start ? timeframe.start.substring(0, 19) : "";
    formattedValue.time.start = FormatUtils.formatISOTimeNoTimezone(new Date(startVal));

    var endVal = timeframe.end ? timeframe.end.substring(0, 19) : "";
    formattedValue.time.end = FormatUtils.formatISOTimeNoTimezone(new Date(endVal));

    return formattedValue;
  },

  unpackRelativeTimeframe: function (timeframe, timezone) {
    var split = timeframe.split('_');
    return {
      time: {
        relativity: split[0],
        amount: split[1],
        sub_timeframe: split[2]
      },
      timezone: timezone
    };
  }

}
<|endoftext|>


<commit_before>/*! Loop protect | (c) 2014 JS Bin | jsbin.mit-license.org */
/**
 * Protect against infinite loops.
 * Look for for, while and do loops, and insert a check function at the start of
 * the loop. If the check function is called many many times then it returns
 * true, preventing the loop from running again.
 */

if (typeof DEBUG === 'undefined') { DEBUG = true; } //jshint ignore:line

(function (root, factory) {
  'use strict';
  /*global define*/
  if (typeof define === 'function' && define.amd) {
    define(factory(root));
  } else if (typeof exports === 'object') {
    module.exports = factory(root);
  } else {
    root.loopProtect = factory(root);
  }
})(this, function loopProtectModule(root) {
  /*global DEBUG*/
  'use strict';
  var debug = null;

  // the standard loops - note that recursive is not supported
  var re = /\b(for|while|do)\b/g;
  var reSingle = /\b(for|while|do)\b/;
  var labelRe = /\b(?!default:)([a-z_]{1}\w+:)/i;
  var comments = /(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm;

  var loopProtect = rewriteLoops;

  // used in the loop detection
  loopProtect.counters = {};

  // expose debug info
  loopProtect.debug = function debugSwitch(state) {
    debug = state ? function () {
      console.log.apply(console, [].slice.apply(arguments));
    } : function () {};
  };

  loopProtect.debug(false); // off by default

  // the method - as this could be aliased to something else
  loopProtect.alias = 'loopProtect';

  function inMultilineComment(lineNum, lines) {
    if (lineNum === 0) {
      return false;
    }

    var j = lineNum;
    var closeCommentTags = 1; // let's assume we're inside a comment
    var closePos = -1;
    var openPos = -1;

    do {
      DEBUG && debug('looking backwards ' + lines[j]); // jshint ignore:line
      closePos = lines[j].indexOf('*/');
      openPos = lines[j].indexOf('/*');

      if (closePos !== -1) {
        closeCommentTags++;
      }

      //check for single line /* comment */ formatted comments.
      if (closePos === lines[j].length - 2 && openPos !== -1) {
        closeCommentTags--;
      }

      if (openPos !== -1) {
        closeCommentTags--;

        if (closeCommentTags === 0) {
          DEBUG && debug('- exit: part of a multiline comment'); // jshint ignore:line
          return true;
        }
      }
      j -= 1;
    } while (j >= 0);

    return false;
  }

  function inCommentOrString(index, line) {
    var character;
    while (--index > -1) {
      character = line.substr(index, 1);
      if (character === '"' || character === '\'' || character === '.') {
        // our loop keyword was actually either in a string or a property, so let's exit and ignore this line
        DEBUG && debug('- exit: matched inside a string or property key'); // jshint ignore:line
        return true;
      }
      if (character === '/' || character === '*') {
        // looks like a comment, go back one to confirm or not
        var prevCharacter = line.substr(index - 1, 1);
        if (prevCharacter === '/') {
          // we've found a comment, so let's exit and ignore this line
          DEBUG && debug('- exit: part of a comment'); // jshint ignore:line
          return true;
        }
      }
    }
    return false;
  }

  function directlyBeforeLoop(index, lineNum, lines) {
    reSingle.lastIndex = 0;
    labelRe.lastIndex = 0;
    var beforeLoop = false;

    var theRest = lines.slice(lineNum).join('\n').substr(index).replace(labelRe, '');
    theRest.replace(reSingle, function commentStripper(match, capture, i) {
      var target = theRest.substr(0, i).replace(comments, '').trim();
      DEBUG && debug('- directlyBeforeLoop: ' + target); // jshint ignore:line
      if (target.length === 0) {
        beforeLoop = true;
      }
      // strip comments out of the target, and if there's nothing else
      // it's a valid label...I hope!
    });

    return beforeLoop;
  }

  /**
   * Look for for, while and do loops, and inserts *just* at the start of the
   * loop, a check function.
   */
  function rewriteLoops(code, offset) {
    var recompiled = [];
    var lines = code.split('\n');
    var disableLoopProtection = false;
    var method = loopProtect.alias + '.protect';
    var ignore = {};
    var pushonly = {};
    var labelPostion = null;

    function insertReset(lineNum, line, matchPosition) {
      // recompile the line with the reset **just** before the actual loop
      // so that we insert in to the correct location (instead of possibly
      // outside the logic
      // wrap reset and loop in a block to avoid one line loop behind
      // `if (false)`, insert the open brace in this function, and the close
      // brace after loop close brace.
      return line.slice(0, matchPosition) + '{;' + method + '({ line: ' + lineNum + ', reset: true }); ' + line.slice(matchPosition);
    }

    if (!offset) {
      offset = 0;
    }

    lines.forEach(function eachLine(line, lineNum) {
      // reset our regexp each time.
      re.lastIndex = 0;
      labelRe.lastIndex = 0;

      if (disableLoopProtection) {
        return;
      }

      if (line.toLowerCase().indexOf('noprotect') !== -1) {
        disableLoopProtection = true;
      }

      var index = -1;
      var matchPosition = -1;
      var originalLineNum = lineNum;
      // +1 since we're humans and don't read lines numbers from zero
      var printLineNumber = lineNum - offset + 1;
      var character = '';
      // special case for `do` loops, as they're end with `while`
      var dofound = false;
      var findwhile = false;
      var terminator = false;
      var matches = line.match(re) || [];
      var match = matches.length ? matches[0] : '';
      var labelMatch = line.match(labelRe) || [];
      var openBrackets = 0;
      var openBraces = 0;
      var foundLoopEnd = false;

      if (labelMatch.length) {
        DEBUG && debug('- label match'); // jshint ignore:line
        index = line.indexOf(labelMatch[1]);
        if (!inCommentOrString(index, line)) {
          if (!inMultilineComment(lineNum, lines)) {
            if (directlyBeforeLoop(index, lineNum, lines)) {
              DEBUG && debug('- found a label: "' + labelMatch[0] + '"'); // jshint ignore:line
              labelPostion = lineNum;
            } else {
              DEBUG && debug('- ignored "label", false positive'); // jshint ignore:line
            }
          } else {
            DEBUG && debug('- ignored label in multline comment'); // jshint ignore:line
          }
        } else {
          DEBUG && debug('- ignored label in string or comment'); // jshint ignore:line
        }
      }

      if (ignore[lineNum]) {
        DEBUG && debug(' -exit: ignoring line ' + lineNum +': ' + line); // jshint ignore:line
        return;
      }

      if (pushonly[lineNum]) {
        DEBUG && debug('- exit: ignoring, but adding line ' + lineNum + ': ' + line); // jshint ignore:line
        recompiled.push(line);
        return;
      }

      // if there's more than one match, we just ignore this kind of loop
      // otherwise I'm going to be writing a full JavaScript lexer...and god
      // knows I've got better things to be doing.
      if (match && matches.length === 1 && line.indexOf('jsbin') === -1) {
        DEBUG && debug('match on ' + match + '\n'); // jshint ignore:line

        // there's a special case for protecting `do` loops, we need to first
        // prtect the `do`, but then ignore the closing `while` statement, so
        // we reset the search state for this special case.
        dofound = match === 'do';

        // make sure this is an actual loop command by searching backwards
        // to ensure it's not a string, comment or object property
        matchPosition = index = line.indexOf(match);

        // first we need to walk backwards to ensure that our match isn't part
        // of a string or part of a comment
        if (inCommentOrString(index, line)) {
          recompiled.push(line);
          return;
        }

        // it's quite possible we're in the middle of a multiline
        // comment, so we'll cycle up looking for an opening comment,
        // and if there's one (and not a closing `*/`), then we'll
        // ignore this line as a comment
        if (inMultilineComment(lineNum, lines)) {
          recompiled.push(line);
          return;
        }

        // now work our way forward to look for '{'
        index = line.indexOf(match) + match.length;

        if (index === line.length) {
          if (index === line.length && lineNum < (lines.length-1)) {
            // move to the next line
            DEBUG && debug('- moving to next line'); // jshint ignore:line
            recompiled.push(line);
            lineNum++;
            line = lines[lineNum];
            ignore[lineNum] = true;
            index = 0;
          }

        }

        while (index < line.length) {
          character = line.substr(index, 1);
          // DEBUG && debug(character, index); // jshint ignore:line

          if (character === '(') {
            openBrackets++;
          }

          if (character === ')') {
            openBrackets--;

            if (openBrackets === 0 && terminator === false) {
              terminator = index;
            }
          }

          if (character === '{') {
            openBraces++;
          }

          if (character === '}') {
            openBraces--;
          }

          if (openBrackets === 0 && (character === ';' || character === '{')) {
            // if we're a non-curlies loop, then convert to curlies to get our code inserted
            // add a close brace after loop to match the open brace before reset
            if (character === ';') {
              if (lineNum !== originalLineNum) {
                DEBUG && debug('- multiline inline loop'); // jshint ignore:line
                // affect the compiled line
                recompiled[originalLineNum] = recompiled[originalLineNum].substring(0, terminator + 1) + '{\nif (' + method + '({ line: ' + printLineNumber + ' })) break;\n' + recompiled[originalLineNum].substring(terminator + 1);
                line += '\n}}\n';
              } else {
                // simpler
                DEBUG && debug('- single line inline loop'); // jshint ignore:line
                line = line.substring(0, terminator + 1) + '{\nif (' + method + '({ line: ' + printLineNumber + ' })) break;\n' + line.substring(terminator + 1) + '\n}}\n';
              }
              foundLoopEnd = true;
            } else if (character === '{') {
              DEBUG && debug('- multiline with braces'); // jshint ignore:line
              var insert = ';\nif (' + method + '({ line: ' + printLineNumber + ' })) break;\n';
              line = line.substring(0, index + 1) + insert + line.substring(index + 1);

              index += insert.length;
            }

            // work out where to put the reset
            if (lineNum === originalLineNum && labelPostion === null) {
              DEBUG && debug('- simple reset insert'); // jshint ignore:line
              line = insertReset(printLineNumber, line, matchPosition);
              index += (';' + method + '({ line: ' + lineNum + ', reset: true }); ').length;
            } else {
              // insert the reset above the originalLineNum OR if this loop used
              // a label, we have to insert the reset *above* the label
              if (labelPostion === null) {
                DEBUG && debug('- reset inserted above original line'); // jshint ignore:line
                recompiled[originalLineNum] = insertReset(printLineNumber, recompiled[originalLineNum], matchPosition);
              } else {
                DEBUG && debug('- reset inserted above matched label on line ' + labelPostion); // jshint ignore:line
                if (recompiled[labelPostion] === undefined) {
                  labelPostion--;
                  matchPosition = 0;
                }
                recompiled[labelPostion] = insertReset(printLineNumber, recompiled[labelPostion], matchPosition);
                labelPostion = null;
              }
            }

            if (!dofound) {
              if (foundLoopEnd) {
                recompiled.push(line);
                return;
              }

              DEBUG && debug('searching for closing brace of loop for: ' + line); // jshint ignore:line
              while (line !== null) {
                character = line.substr(index, 1);

                DEBUG && debug(index, character, openBraces); // jshint ignore:line

                if (character === '{') {
                  openBraces++;
                }

                if (character === '}') {
                  openBraces--;
                  if (openBraces === 0) {
                    DEBUG && debug('outside of loop, add a close brace to: ' + line); // jshint ignore:line
                    line = line.substring(0, index+1) + '}' + line.substring(index+1);
                    recompiled.push(line);
                    ignore[lineNum] = true;
                    return;
                  }
                }

                index++;

                if (index >= line.length) {
                  recompiled.push(line);
                  ignore[lineNum] = true;
                  lineNum++;
                  line = lines[lineNum];
                  DEBUG && debug(line); // jshint ignore:line
                  index = 0;
                }
              }
              return;
            } else {
              DEBUG && debug('searching for closing `while` statement for: ' + line); // jshint ignore:line
              // cycle forward until we find the close brace, after which should
              // be our while statement to ignore
              findwhile = false;
              while (index < line.length) {
                character = line.substr(index, 1);

                if (character === '{') {
                  openBraces++;
                }

                if (character === '}') {
                  openBraces--;
                }

                if (openBraces === 0) {
                  findwhile = true;
                } else {
                  findwhile = false;
                }

                if (openBraces === 0) {
                  DEBUG && debug('outside of closure, looking for `while` statement: ' + line); // jshint ignore:line
                }

                if (findwhile && line.indexOf('while') !== -1) {
                  DEBUG && debug('- exit as we found `while`: ' + line); // jshint ignore:line
                  // TODO: handle while statement in multiple lines
                  line += '}';
                  recompiled.push(line);
                  ignore[lineNum] = true;
                  return;
                }

                index++;

                if (index === line.length && lineNum < (lines.length-1)) {
                  recompiled.push(line);
                  ignore[lineNum] = true;
                  lineNum++;
                  line = lines[lineNum];
                  DEBUG && debug(line); // jshint ignore:line
                  index = 0;
                }
              }
              return;
            }
          }

          index++;

          if (index === line.length && lineNum < (lines.length-1)) {
            // move to the next line
            DEBUG && debug('- moving to next line'); // jshint ignore:line
            recompiled.push(line);
            lineNum++;
            line = lines[lineNum];
            ignore[lineNum] = true;
            index = 0;
          }
        }
      } else {
        // else we're a regular line, and we shouldn't be touched
        DEBUG && debug('regular line ' + line); // jshint ignore:line
        recompiled.push(line);
      }
    });

    DEBUG && debug('---- source ----'); // jshint ignore:line
    DEBUG && debug(code); // jshint ignore:line
    DEBUG && debug('---- rewrite ---'); // jshint ignore:line
    DEBUG && debug(recompiled.join('\n')); // jshint ignore:line
    DEBUG && debug(''); // jshint ignore:line

    return disableLoopProtection ? code : recompiled.join('\n');
  }

  /**
   * Injected code in to user's code to **try** to protect against infinite
   * loops cropping up in the code, and killing the browser. Returns true
   * when the loops has been running for more than 100ms.
   */
  loopProtect.protect = function protect(state) {
    loopProtect.counters[state.line] = loopProtect.counters[state.line] || {};
    var line = loopProtect.counters[state.line];
    var now = (new Date()).getTime();

    if (state.reset) {
      line.time = now;
      line.hit = 0;
      line.last = 0;
    }

    line.hit++;
    if ((now - line.time) > 100) {//} && line.hit !== line.last+1) {
      // We've spent over 100ms on this loop... smells infinite.
      loopProtect.hit(state.line);
      // Returning true prevents the loop running again
      return true;
    }
    line.last++;
    return false;
  };

  loopProtect.hit = function hit(line) {
    var msg = 'Exiting potential infinite loop at line ' + line + '. To disable loop protection: add "// noprotect" to your code';
    if (root.proxyConsole) {
      root.proxyConsole.error(msg);
    } else {
      console.error(msg);
    }
  };

  loopProtect.reset = function reset() {
    // reset the counters
    loopProtect.counters = {};
  };

  return loopProtect;
});
<commit_msg>remove var 'DEBUG'; increase time check to 1000ms<commit_after>/*! Loop protect | (c) 2014 JS Bin | jsbin.mit-license.org */
/**
 * Protect against infinite loops.
 * Look for for, while and do loops, and insert a check function at the start of
 * the loop. If the check function is called many many times then it returns
 * true, preventing the loop from running again.
 */

(function (root, factory) {
  'use strict';
  /*global define*/
  if (typeof define === 'function' && define.amd) {
    define(factory(root));
  } else if (typeof exports === 'object') {
    module.exports = factory(root);
  } else {
    root.loopProtect = factory(root);
  }
})(this, function loopProtectModule(root) {
  /*global DEBUG*/
  'use strict';
  var debug = null;

  // the standard loops - note that recursive is not supported
  var re = /\b(for|while|do)\b/g;
  var reSingle = /\b(for|while|do)\b/;
  var labelRe = /\b(?!default:)([a-z_]{1}\w+:)/i;
  var comments = /(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm;

  var loopProtect = rewriteLoops;

  // used in the loop detection
  loopProtect.counters = {};

  // expose debug info
  loopProtect.debug = function debugSwitch(state) {
    debug = state ? function () {
      console.log.apply(console, [].slice.apply(arguments));
    } : function () {};
  };

  loopProtect.debug(false); // off by default

  // the method - as this could be aliased to something else
  loopProtect.alias = 'loopProtect';

  function inMultilineComment(lineNum, lines) {
    if (lineNum === 0) {
      return false;
    }

    var j = lineNum;
    var closeCommentTags = 1; // let's assume we're inside a comment
    var closePos = -1;
    var openPos = -1;

    do {
      debug('looking backwards ' + lines[j]); // jshint ignore:line
      closePos = lines[j].indexOf('*/');
      openPos = lines[j].indexOf('/*');

      if (closePos !== -1) {
        closeCommentTags++;
      }

      //check for single line /* comment */ formatted comments.
      if (closePos === lines[j].length - 2 && openPos !== -1) {
        closeCommentTags--;
      }

      if (openPos !== -1) {
        closeCommentTags--;

        if (closeCommentTags === 0) {
          debug('- exit: part of a multiline comment'); // jshint ignore:line
          return true;
        }
      }
      j -= 1;
    } while (j >= 0);

    return false;
  }

  function inCommentOrString(index, line) {
    var character;
    while (--index > -1) {
      character = line.substr(index, 1);
      if (character === '"' || character === '\'' || character === '.') {
        // our loop keyword was actually either in a string or a property, so let's exit and ignore this line
        debug('- exit: matched inside a string or property key'); // jshint ignore:line
        return true;
      }
      if (character === '/' || character === '*') {
        // looks like a comment, go back one to confirm or not
        var prevCharacter = line.substr(index - 1, 1);
        if (prevCharacter === '/') {
          // we've found a comment, so let's exit and ignore this line
          debug('- exit: part of a comment'); // jshint ignore:line
          return true;
        }
      }
    }
    return false;
  }

  function directlyBeforeLoop(index, lineNum, lines) {
    reSingle.lastIndex = 0;
    labelRe.lastIndex = 0;
    var beforeLoop = false;

    var theRest = lines.slice(lineNum).join('\n').substr(index).replace(labelRe, '');
    theRest.replace(reSingle, function commentStripper(match, capture, i) {
      var target = theRest.substr(0, i).replace(comments, '').trim();
      debug('- directlyBeforeLoop: ' + target); // jshint ignore:line
      if (target.length === 0) {
        beforeLoop = true;
      }
      // strip comments out of the target, and if there's nothing else
      // it's a valid label...I hope!
    });

    return beforeLoop;
  }

  /**
   * Look for for, while and do loops, and inserts *just* at the start of the
   * loop, a check function.
   */
  function rewriteLoops(code, offset) {
    var recompiled = [];
    var lines = code.split('\n');
    var disableLoopProtection = false;
    var method = loopProtect.alias + '.protect';
    var ignore = {};
    var pushonly = {};
    var labelPostion = null;

    function insertReset(lineNum, line, matchPosition) {
      // recompile the line with the reset **just** before the actual loop
      // so that we insert in to the correct location (instead of possibly
      // outside the logic
      // wrap reset and loop in a block to avoid one line loop behind
      // `if (false)`, insert the open brace in this function, and the close
      // brace after loop close brace.
      return line.slice(0, matchPosition) + '{;' + method + '({ line: ' + lineNum + ', reset: true }); ' + line.slice(matchPosition);
    }

    if (!offset) {
      offset = 0;
    }

    lines.forEach(function eachLine(line, lineNum) {
      // reset our regexp each time.
      re.lastIndex = 0;
      labelRe.lastIndex = 0;

      if (disableLoopProtection) {
        return;
      }

      if (line.toLowerCase().indexOf('noprotect') !== -1) {
        disableLoopProtection = true;
      }

      var index = -1;
      var matchPosition = -1;
      var originalLineNum = lineNum;
      // +1 since we're humans and don't read lines numbers from zero
      var printLineNumber = lineNum - offset + 1;
      var character = '';
      // special case for `do` loops, as they're end with `while`
      var dofound = false;
      var findwhile = false;
      var terminator = false;
      var matches = line.match(re) || [];
      var match = matches.length ? matches[0] : '';
      var labelMatch = line.match(labelRe) || [];
      var openBrackets = 0;
      var openBraces = 0;
      var foundLoopEnd = false;

      if (labelMatch.length) {
        debug('- label match'); // jshint ignore:line
        index = line.indexOf(labelMatch[1]);
        if (!inCommentOrString(index, line)) {
          if (!inMultilineComment(lineNum, lines)) {
            if (directlyBeforeLoop(index, lineNum, lines)) {
              debug('- found a label: "' + labelMatch[0] + '"'); // jshint ignore:line
              labelPostion = lineNum;
            } else {
              debug('- ignored "label", false positive'); // jshint ignore:line
            }
          } else {
            debug('- ignored label in multline comment'); // jshint ignore:line
          }
        } else {
          debug('- ignored label in string or comment'); // jshint ignore:line
        }
      }

      if (ignore[lineNum]) {
        debug(' -exit: ignoring line ' + lineNum +': ' + line); // jshint ignore:line
        return;
      }

      if (pushonly[lineNum]) {
        debug('- exit: ignoring, but adding line ' + lineNum + ': ' + line); // jshint ignore:line
        recompiled.push(line);
        return;
      }

      // if there's more than one match, we just ignore this kind of loop
      // otherwise I'm going to be writing a full JavaScript lexer...and god
      // knows I've got better things to be doing.
      if (match && matches.length === 1 && line.indexOf('jsbin') === -1) {
        debug('match on ' + match + '\n'); // jshint ignore:line

        // there's a special case for protecting `do` loops, we need to first
        // prtect the `do`, but then ignore the closing `while` statement, so
        // we reset the search state for this special case.
        dofound = match === 'do';

        // make sure this is an actual loop command by searching backwards
        // to ensure it's not a string, comment or object property
        matchPosition = index = line.indexOf(match);

        // first we need to walk backwards to ensure that our match isn't part
        // of a string or part of a comment
        if (inCommentOrString(index, line)) {
          recompiled.push(line);
          return;
        }

        // it's quite possible we're in the middle of a multiline
        // comment, so we'll cycle up looking for an opening comment,
        // and if there's one (and not a closing `*/`), then we'll
        // ignore this line as a comment
        if (inMultilineComment(lineNum, lines)) {
          recompiled.push(line);
          return;
        }

        // now work our way forward to look for '{'
        index = line.indexOf(match) + match.length;

        if (index === line.length) {
          if (index === line.length && lineNum < (lines.length-1)) {
            // move to the next line
            debug('- moving to next line'); // jshint ignore:line
            recompiled.push(line);
            lineNum++;
            line = lines[lineNum];
            ignore[lineNum] = true;
            index = 0;
          }

        }

        while (index < line.length) {
          character = line.substr(index, 1);
          // debug(character, index); // jshint ignore:line

          if (character === '(') {
            openBrackets++;
          }

          if (character === ')') {
            openBrackets--;

            if (openBrackets === 0 && terminator === false) {
              terminator = index;
            }
          }

          if (character === '{') {
            openBraces++;
          }

          if (character === '}') {
            openBraces--;
          }

          if (openBrackets === 0 && (character === ';' || character === '{')) {
            // if we're a non-curlies loop, then convert to curlies to get our code inserted
            // add a close brace after loop to match the open brace before reset
            if (character === ';') {
              if (lineNum !== originalLineNum) {
                debug('- multiline inline loop'); // jshint ignore:line
                // affect the compiled line
                recompiled[originalLineNum] = recompiled[originalLineNum].substring(0, terminator + 1) + '{\nif (' + method + '({ line: ' + printLineNumber + ' })) break;\n' + recompiled[originalLineNum].substring(terminator + 1);
                line += '\n}}\n';
              } else {
                // simpler
                debug('- single line inline loop'); // jshint ignore:line
                line = line.substring(0, terminator + 1) + '{\nif (' + method + '({ line: ' + printLineNumber + ' })) break;\n' + line.substring(terminator + 1) + '\n}}\n';
              }
              foundLoopEnd = true;
            } else if (character === '{') {
              debug('- multiline with braces'); // jshint ignore:line
              var insert = ';\nif (' + method + '({ line: ' + printLineNumber + ' })) break;\n';
              line = line.substring(0, index + 1) + insert + line.substring(index + 1);

              index += insert.length;
            }

            // work out where to put the reset
            if (lineNum === originalLineNum && labelPostion === null) {
              debug('- simple reset insert'); // jshint ignore:line
              line = insertReset(printLineNumber, line, matchPosition);
              index += (';' + method + '({ line: ' + lineNum + ', reset: true }); ').length;
            } else {
              // insert the reset above the originalLineNum OR if this loop used
              // a label, we have to insert the reset *above* the label
              if (labelPostion === null) {
                debug('- reset inserted above original line'); // jshint ignore:line
                recompiled[originalLineNum] = insertReset(printLineNumber, recompiled[originalLineNum], matchPosition);
              } else {
                debug('- reset inserted above matched label on line ' + labelPostion); // jshint ignore:line
                if (recompiled[labelPostion] === undefined) {
                  labelPostion--;
                  matchPosition = 0;
                }
                recompiled[labelPostion] = insertReset(printLineNumber, recompiled[labelPostion], matchPosition);
                labelPostion = null;
              }
            }

            if (!dofound) {
              if (foundLoopEnd) {
                recompiled.push(line);
                return;
              }

              debug('searching for closing brace of loop for: ' + line); // jshint ignore:line
              while (line !== null) {
                character = line.substr(index, 1);

                debug(index, character, openBraces); // jshint ignore:line

                if (character === '{') {
                  openBraces++;
                }

                if (character === '}') {
                  openBraces--;
                  if (openBraces === 0) {
                    debug('outside of loop, add a close brace to: ' + line); // jshint ignore:line
                    line = line.substring(0, index+1) + '}' + line.substring(index+1);
                    recompiled.push(line);
                    ignore[lineNum] = true;
                    return;
                  }
                }

                index++;

                if (index >= line.length) {
                  recompiled.push(line);
                  ignore[lineNum] = true;
                  lineNum++;
                  line = lines[lineNum];
                  debug(line); // jshint ignore:line
                  index = 0;
                }
              }
              return;
            } else {
              debug('searching for closing `while` statement for: ' + line); // jshint ignore:line
              // cycle forward until we find the close brace, after which should
              // be our while statement to ignore
              findwhile = false;
              while (index < line.length) {
                character = line.substr(index, 1);

                if (character === '{') {
                  openBraces++;
                }

                if (character === '}') {
                  openBraces--;
                }

                if (openBraces === 0) {
                  findwhile = true;
                } else {
                  findwhile = false;
                }

                if (openBraces === 0) {
                  debug('outside of closure, looking for `while` statement: ' + line); // jshint ignore:line
                }

                if (findwhile && line.indexOf('while') !== -1) {
                  debug('- exit as we found `while`: ' + line); // jshint ignore:line
                  // TODO: handle while statement in multiple lines
                  line += '}';
                  recompiled.push(line);
                  ignore[lineNum] = true;
                  return;
                }

                index++;

                if (index === line.length && lineNum < (lines.length-1)) {
                  recompiled.push(line);
                  ignore[lineNum] = true;
                  lineNum++;
                  line = lines[lineNum];
                  debug(line); // jshint ignore:line
                  index = 0;
                }
              }
              return;
            }
          }

          index++;

          if (index === line.length && lineNum < (lines.length-1)) {
            // move to the next line
            debug('- moving to next line'); // jshint ignore:line
            recompiled.push(line);
            lineNum++;
            line = lines[lineNum];
            ignore[lineNum] = true;
            index = 0;
          }
        }
      } else {
        // else we're a regular line, and we shouldn't be touched
        debug('regular line ' + line); // jshint ignore:line
        recompiled.push(line);
      }
    });

    debug('---- source ----'); // jshint ignore:line
    debug(code); // jshint ignore:line
    debug('---- rewrite ---'); // jshint ignore:line
    debug(recompiled.join('\n')); // jshint ignore:line
    debug(''); // jshint ignore:line

    return disableLoopProtection ? code : recompiled.join('\n');
  }

  /**
   * Injected code in to user's code to **try** to protect against infinite
   * loops cropping up in the code, and killing the browser. Returns true
   * when the loops has been running for more than 100ms.
   */
  loopProtect.protect = function protect(state) {
    loopProtect.counters[state.line] = loopProtect.counters[state.line] || {};
    var line = loopProtect.counters[state.line];
    var now = (new Date()).getTime();

    if (state.reset) {
      line.time = now;
      line.hit = 0;
      line.last = 0;
    }

    line.hit++;
    if ((now - line.time) > 1000) {//} && line.hit !== line.last+1) {
      // We've spent over 100ms on this loop... smells infinite.
      loopProtect.hit(state.line);
      // Returning true prevents the loop running again
      return true;
    }
    line.last++;
    return false;
  };

  loopProtect.hit = function hit(line) {
    var msg = 'Exiting potential infinite loop at line ' + line + '. To disable loop protection: add "// noprotect" to your code';
    if (root.proxyConsole) {
      root.proxyConsole.error(msg);
    } else {
      console.error(msg);
    }
  };

  loopProtect.reset = function reset() {
    // reset the counters
    loopProtect.counters = {};
  };

  return loopProtect;
});
<|endoftext|>