<commit_before>/*!
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

var assert = require('assert');
var async = require('async');
var BigQuery = require('@google-cloud/bigquery');
var exec = require('methmeth');
var extend = require('extend');
var format = require('string-format-obj');
var is = require('is');
var prop = require('propprop');
var PubSub = require('@google-cloud/pubsub');
var Storage = require('@google-cloud/storage');
var uuid = require('uuid');

var env = require('../../../system-test/env.js');
var Logging = require('../');

describe('Logging', function() {
  var TESTS_PREFIX = 'gcloud-logging-test';
  var WRITE_CONSISTENCY_DELAY_MS = 60000;

  var logging = new Logging(env);
  var bigQuery = new BigQuery(env);
  var pubsub = new PubSub(env);
  var storage = new Storage(env);

  // Create the possible destinations for sinks that we will create.
  var bucket = storage.bucket(generateName());
  var dataset = bigQuery.dataset(generateName().replace(/-/g, '_'));
  var topic = pubsub.topic(generateName());

  before(function(done) {
    async.parallel([
      bucket.create.bind(bucket),
      dataset.create.bind(dataset),
      topic.create.bind(topic)
    ], done);
  });

  after(function(done) {
    async.parallel([
      deleteBuckets,
      deleteDatasets,
      deleteTopics,
      deleteSinks
    ], done);

    function deleteBuckets(callback) {
      storage.getBuckets({
        prefix: TESTS_PREFIX
      }, function(err, buckets) {
        if (err) {
          done(err);
          return;
        }

        function deleteBucket(bucket, callback) {
          bucket.deleteFiles(function(err) {
            if (err) {
              callback(err);
              return;
            }

            bucket.delete(callback);
          });
        }

        async.each(buckets, deleteBucket, callback);
      });
    }

    function deleteDatasets(callback) {
      getAndDelete(bigQuery.getDatasets.bind(bigQuery), callback);
    }

    function deleteTopics(callback) {
      getAndDelete(pubsub.getTopics.bind(pubsub), callback);
    }

    function deleteSinks(callback) {
      getAndDelete(logging.getSinks.bind(logging), callback);
    }

    function getAndDelete(method, callback) {
      method(function(err, objects) {
        if (err) {
          callback(err);
          return;
        }

        objects = objects.filter(function(object) {
          return object.id.indexOf(TESTS_PREFIX) === 0;
        });

        async.each(objects, exec('delete'), callback);
      });
    }
  });

  describe('sinks', function() {
    it('should create a sink with a Bucket destination', function(done) {
      var sink = logging.sink(generateName());

      sink.create({
        destination: bucket
      }, function(err, sink, apiResponse) {
        assert.ifError(err);

        var destination = 'storage.googleapis.com/' + bucket.name;
        assert.strictEqual(apiResponse.destination, destination);

        done();
      });
    });

    it('should create a sink with a Dataset destination', function(done) {
      var sink = logging.sink(generateName());

      sink.create({
        destination: dataset
      }, function(err, sink, apiResponse) {
        assert.ifError(err);

        var destination = format('{baseUrl}/projects/{pId}/datasets/{dId}', {
          baseUrl: 'bigquery.googleapis.com',
          pId: dataset.parent.projectId,
          dId: dataset.id
        });

        assert.strictEqual(apiResponse.destination, destination);

        done();
      });
    });

    it('should create a sink with a Topic destination', function(done) {
      var sink = logging.sink(generateName());

      sink.create({
        destination: topic
      }, function(err, sink, apiResponse) {
        assert.ifError(err);

        var destination = 'pubsub.googleapis.com/' + topic.name;
        assert.strictEqual(apiResponse.destination, destination);

        done();
      });
    });

    describe('metadata', function() {
      var sink = logging.sink(generateName());
      var FILTER = 'severity = ALERT';

      before(function(done) {
        sink.create({
          destination: topic
        }, done);
      });

      it('should set metadata', function(done) {
        var metadata = {
          filter: FILTER
        };

        sink.setMetadata(metadata, function(err, apiResponse) {
          assert.ifError(err);
          assert.strictEqual(apiResponse.filter, FILTER);
          done();
        });
      });

      it('should set a filter', function(done) {
        sink.setFilter(FILTER, function(err, apiResponse) {
          assert.ifError(err);
          assert.strictEqual(apiResponse.filter, FILTER);
          done();
        });
      });
    });

    describe('listing sinks', function() {
      var sink = logging.sink(generateName());

      before(function(done) {
        sink.create({
          destination: topic
        }, done);
      });

      it('should list sinks', function(done) {
        logging.getSinks(function(err, sinks) {
          assert.ifError(err);
          assert(sinks.length > 0);
          done();
        });
      });

      it('should list sinks as a stream', function(done) {
        logging.getSinksStream({ pageSize: 1 })
          .on('error', done)
          .once('data', function() {
            this.end();
            done();
          });
      });

      it('should get metadata', function(done) {
        logging.getSinksStream({ pageSize: 1 })
          .on('error', done)
          .once('data', function(sink) {
            sink.getMetadata(function(err, metadata) {
              assert.ifError(err);
              assert.strictEqual(is.object(metadata), true);
              done();
            });
          });
      });
    });
  });

  describe('logs', function() {
    var log = logging.log('syslog');

    var logEntries = [
      // string data
      log.entry('log entry 1'),

      // object data
      log.entry({ delegate: 'my_username' }),

      // various data types
      log.entry({
        nonValue: null,
        boolValue: true,
        arrayValue: [ 1, 2, 3 ]
      }),

      // nested object data
      log.entry({
        nested: {
          delegate: 'my_username'
        }
      })
    ];

    var options = {
      resource: {
        type: 'gce_instance',
        labels: {
          zone: 'global',
          instance_id: '3'
        }
      }
    };

    it('should list log entries', function(done) {
      logging.getEntries({ pageSize: 1 }, function(err, entries) {
        assert.ifError(err);
        assert.strictEqual(entries.length, 1);
        done();
      });
    });

    it('should list log entries as a stream', function(done) {
      logging.getEntriesStream({ pageSize: 1 })
        .on('error', done)
        .once('data', function() {
          this.end();
          done();
        });
    });

    describe('log-specific entries', function() {
      before(function(done) {
        log.write(logEntries, options, done);
      });

      it('should list log entries', function(done) {
        log.getEntries({ pageSize: 1 }, function(err, entries) {
          assert.ifError(err);
          assert.strictEqual(entries.length, 1);
          done();
        });
      });

      it('should list log entries as a stream', function(done) {
        log.getEntriesStream({ pageSize: 1 })
          .on('error', done)
          .once('data', function() {
            this.end();
            done();
          });
      });
    });

    it('should write a single entry to a log', function(done) {
      log.write(logEntries[0], options, done);
    });

    it('should write multiple entries to a log', function(done) {
      log.write(logEntries, options, function(err) {
        assert.ifError(err);

        setTimeout(function() {
          log.getEntries({
            pageSize: logEntries.length
          }, function(err, entries) {
            assert.ifError(err);

            assert.deepEqual(entries.map(prop('data')).reverse(), [
              'log entry 1',
              {
                delegate: 'my_username'
              },
              {
                nonValue: null,
                boolValue: true,
                arrayValue: [ 1, 2, 3 ]
              },
              {
                nested: {
                  delegate: 'my_username'
                }
              }
            ]);

            done();
          });
        }, WRITE_CONSISTENCY_DELAY_MS);
      });
    });

    it('should preserve order of entries', function(done) {
      var entry1 = log.entry('1');

      setTimeout(function() {
        var entry2 = log.entry('2');
        var entry3 = log.entry({ timestamp: entry2.metadata.timestamp }, '3');

        // Re-arrange to confirm the timestamp is sent and honored.
        log.write([entry2, entry3, entry1], options, function(err) {
          assert.ifError(err);

          setTimeout(function() {
            log.getEntries({ pageSize: 3 }, function(err, entries) {
              assert.ifError(err);
              assert.deepEqual(entries.map(prop('data')), [ '3', '2', '1' ]);
              done();
            });
          }, WRITE_CONSISTENCY_DELAY_MS);
        });
      }, 1000);
    });

    it('should preserve order for sequential write calls', function(done) {
      var messages =  ['1', '2', '3', '4', '5'];

      messages.forEach(function(message) {
        log.write(log.entry(message));
      });

      setTimeout(function() {
        log.getEntries({ pageSize: messages.length }, function(err, entries) {
          assert.ifError(err);
          assert.deepEqual(entries.reverse().map(prop('data')), messages);
          done();
        });
      }, WRITE_CONSISTENCY_DELAY_MS);
    });

    it('should write an entry with primitive values', function(done) {
      var logEntry = log.entry({
        when: new Date(),
        matchUser: /username: (.+)/,
        matchUserError: new Error('No user found.'),
        shouldNotBeSaved: undefined
      });

      log.write(logEntry, options, function(err) {
        assert.ifError(err);

        setTimeout(function() {
          log.getEntries({ pageSize: 1 }, function(err, entries) {
            assert.ifError(err);

            var entry = entries[0];

            assert.deepEqual(entry.data, {
              when: logEntry.data.when.toString(),
              matchUser: logEntry.data.matchUser.toString(),
              matchUserError: logEntry.data.matchUserError.toString()
            });

            done();
          });
        }, WRITE_CONSISTENCY_DELAY_MS);
      });
    });

    it('should write a log with metadata', function(done) {
      var metadata = extend({}, options, {
        severity: 'DEBUG'
      });

      var data = {
        embeddedData: true
      };

      var logEntry = log.entry(metadata, data);

      log.write(logEntry, function(err) {
        assert.ifError(err);

        setTimeout(function() {
          log.getEntries({ pageSize: 1 }, function(err, entries) {
            assert.ifError(err);

            var entry = entries[0];

            assert.strictEqual(entry.metadata.severity, metadata.severity);
            assert.deepEqual(entry.data, data);

            done();
          });
        }, WRITE_CONSISTENCY_DELAY_MS);
      });
    });

    it('should set the default resource', function(done) {
      var text = 'entry-text';
      var entry = log.entry(text);

      log.write(entry, function(err) {
        assert.ifError(err);

        setTimeout(function() {
          log.getEntries({ pageSize: 1 }, function(err, entries) {
            assert.ifError(err);

            var entry = entries[0];

            assert.strictEqual(entry.data, text);
            assert.deepEqual(entry.metadata.resource, {
              type: 'global',
              labels: {
                project_id: logging.projectId
              }
            });

            done();
          });
        }, WRITE_CONSISTENCY_DELAY_MS);
      });
    });

    it('should write to a log with alert helper', function(done) {
      log.alert(logEntries, options, done);
    });

    it('should write to a log with critical helper', function(done) {
      log.critical(logEntries, options, done);
    });

    it('should write to a log with debug helper', function(done) {
      log.debug(logEntries, options, done);
    });

    it('should write to a log with emergency helper', function(done) {
      log.emergency(logEntries, options, done);
    });

    it('should write to a log with error helper', function(done) {
      log.error(logEntries, options, done);
    });

    it('should write to a log with info helper', function(done) {
      log.info(logEntries, options, done);
    });

    it('should write to a log with notice helper', function(done) {
      log.notice(logEntries, options, done);
    });

    it('should write to a log with warning helper', function(done) {
      log.warning(logEntries, options, done);
    });
  });

  function generateName() {
    return TESTS_PREFIX + uuid.v1();
  }
});
<commit_msg>logging: allow more time for write consistency<commit_after>/*!
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

var assert = require('assert');
var async = require('async');
var BigQuery = require('@google-cloud/bigquery');
var exec = require('methmeth');
var extend = require('extend');
var format = require('string-format-obj');
var is = require('is');
var prop = require('propprop');
var PubSub = require('@google-cloud/pubsub');
var Storage = require('@google-cloud/storage');
var uuid = require('uuid');

var env = require('../../../system-test/env.js');
var Logging = require('../');

describe('Logging', function() {
  var TESTS_PREFIX = 'gcloud-logging-test';
  var WRITE_CONSISTENCY_DELAY_MS = 90000;

  var logging = new Logging(env);
  var bigQuery = new BigQuery(env);
  var pubsub = new PubSub(env);
  var storage = new Storage(env);

  // Create the possible destinations for sinks that we will create.
  var bucket = storage.bucket(generateName());
  var dataset = bigQuery.dataset(generateName().replace(/-/g, '_'));
  var topic = pubsub.topic(generateName());

  before(function(done) {
    async.parallel([
      bucket.create.bind(bucket),
      dataset.create.bind(dataset),
      topic.create.bind(topic)
    ], done);
  });

  after(function(done) {
    async.parallel([
      deleteBuckets,
      deleteDatasets,
      deleteTopics,
      deleteSinks
    ], done);

    function deleteBuckets(callback) {
      storage.getBuckets({
        prefix: TESTS_PREFIX
      }, function(err, buckets) {
        if (err) {
          done(err);
          return;
        }

        function deleteBucket(bucket, callback) {
          bucket.deleteFiles(function(err) {
            if (err) {
              callback(err);
              return;
            }

            bucket.delete(callback);
          });
        }

        async.each(buckets, deleteBucket, callback);
      });
    }

    function deleteDatasets(callback) {
      getAndDelete(bigQuery.getDatasets.bind(bigQuery), callback);
    }

    function deleteTopics(callback) {
      getAndDelete(pubsub.getTopics.bind(pubsub), callback);
    }

    function deleteSinks(callback) {
      getAndDelete(logging.getSinks.bind(logging), callback);
    }

    function getAndDelete(method, callback) {
      method(function(err, objects) {
        if (err) {
          callback(err);
          return;
        }

        objects = objects.filter(function(object) {
          return object.id.indexOf(TESTS_PREFIX) === 0;
        });

        async.each(objects, exec('delete'), callback);
      });
    }
  });

  describe('sinks', function() {
    it('should create a sink with a Bucket destination', function(done) {
      var sink = logging.sink(generateName());

      sink.create({
        destination: bucket
      }, function(err, sink, apiResponse) {
        assert.ifError(err);

        var destination = 'storage.googleapis.com/' + bucket.name;
        assert.strictEqual(apiResponse.destination, destination);

        done();
      });
    });

    it('should create a sink with a Dataset destination', function(done) {
      var sink = logging.sink(generateName());

      sink.create({
        destination: dataset
      }, function(err, sink, apiResponse) {
        assert.ifError(err);

        var destination = format('{baseUrl}/projects/{pId}/datasets/{dId}', {
          baseUrl: 'bigquery.googleapis.com',
          pId: dataset.parent.projectId,
          dId: dataset.id
        });

        assert.strictEqual(apiResponse.destination, destination);

        done();
      });
    });

    it('should create a sink with a Topic destination', function(done) {
      var sink = logging.sink(generateName());

      sink.create({
        destination: topic
      }, function(err, sink, apiResponse) {
        assert.ifError(err);

        var destination = 'pubsub.googleapis.com/' + topic.name;
        assert.strictEqual(apiResponse.destination, destination);

        done();
      });
    });

    describe('metadata', function() {
      var sink = logging.sink(generateName());
      var FILTER = 'severity = ALERT';

      before(function(done) {
        sink.create({
          destination: topic
        }, done);
      });

      it('should set metadata', function(done) {
        var metadata = {
          filter: FILTER
        };

        sink.setMetadata(metadata, function(err, apiResponse) {
          assert.ifError(err);
          assert.strictEqual(apiResponse.filter, FILTER);
          done();
        });
      });

      it('should set a filter', function(done) {
        sink.setFilter(FILTER, function(err, apiResponse) {
          assert.ifError(err);
          assert.strictEqual(apiResponse.filter, FILTER);
          done();
        });
      });
    });

    describe('listing sinks', function() {
      var sink = logging.sink(generateName());

      before(function(done) {
        sink.create({
          destination: topic
        }, done);
      });

      it('should list sinks', function(done) {
        logging.getSinks(function(err, sinks) {
          assert.ifError(err);
          assert(sinks.length > 0);
          done();
        });
      });

      it('should list sinks as a stream', function(done) {
        logging.getSinksStream({ pageSize: 1 })
          .on('error', done)
          .once('data', function() {
            this.end();
            done();
          });
      });

      it('should get metadata', function(done) {
        logging.getSinksStream({ pageSize: 1 })
          .on('error', done)
          .once('data', function(sink) {
            sink.getMetadata(function(err, metadata) {
              assert.ifError(err);
              assert.strictEqual(is.object(metadata), true);
              done();
            });
          });
      });
    });
  });

  describe('logs', function() {
    var log = logging.log('syslog');

    var logEntries = [
      // string data
      log.entry('log entry 1'),

      // object data
      log.entry({ delegate: 'my_username' }),

      // various data types
      log.entry({
        nonValue: null,
        boolValue: true,
        arrayValue: [ 1, 2, 3 ]
      }),

      // nested object data
      log.entry({
        nested: {
          delegate: 'my_username'
        }
      })
    ];

    var options = {
      resource: {
        type: 'gce_instance',
        labels: {
          zone: 'global',
          instance_id: '3'
        }
      }
    };

    it('should list log entries', function(done) {
      logging.getEntries({ pageSize: 1 }, function(err, entries) {
        assert.ifError(err);
        assert.strictEqual(entries.length, 1);
        done();
      });
    });

    it('should list log entries as a stream', function(done) {
      logging.getEntriesStream({ pageSize: 1 })
        .on('error', done)
        .once('data', function() {
          this.end();
          done();
        });
    });

    describe('log-specific entries', function() {
      before(function(done) {
        log.write(logEntries, options, done);
      });

      it('should list log entries', function(done) {
        log.getEntries({ pageSize: 1 }, function(err, entries) {
          assert.ifError(err);
          assert.strictEqual(entries.length, 1);
          done();
        });
      });

      it('should list log entries as a stream', function(done) {
        log.getEntriesStream({ pageSize: 1 })
          .on('error', done)
          .once('data', function() {
            this.end();
            done();
          });
      });
    });

    it('should write a single entry to a log', function(done) {
      log.write(logEntries[0], options, done);
    });

    it('should write multiple entries to a log', function(done) {
      log.write(logEntries, options, function(err) {
        assert.ifError(err);

        setTimeout(function() {
          log.getEntries({
            pageSize: logEntries.length
          }, function(err, entries) {
            assert.ifError(err);

            assert.deepEqual(entries.map(prop('data')).reverse(), [
              'log entry 1',
              {
                delegate: 'my_username'
              },
              {
                nonValue: null,
                boolValue: true,
                arrayValue: [ 1, 2, 3 ]
              },
              {
                nested: {
                  delegate: 'my_username'
                }
              }
            ]);

            done();
          });
        }, WRITE_CONSISTENCY_DELAY_MS);
      });
    });

    it('should preserve order of entries', function(done) {
      var entry1 = log.entry('1');

      setTimeout(function() {
        var entry2 = log.entry('2');
        var entry3 = log.entry({ timestamp: entry2.metadata.timestamp }, '3');

        // Re-arrange to confirm the timestamp is sent and honored.
        log.write([entry2, entry3, entry1], options, function(err) {
          assert.ifError(err);

          setTimeout(function() {
            log.getEntries({ pageSize: 3 }, function(err, entries) {
              assert.ifError(err);
              assert.deepEqual(entries.map(prop('data')), [ '3', '2', '1' ]);
              done();
            });
          }, WRITE_CONSISTENCY_DELAY_MS);
        });
      }, 1000);
    });

    it('should preserve order for sequential write calls', function(done) {
      var messages =  ['1', '2', '3', '4', '5'];

      messages.forEach(function(message) {
        log.write(log.entry(message));
      });

      setTimeout(function() {
        log.getEntries({ pageSize: messages.length }, function(err, entries) {
          assert.ifError(err);
          assert.deepEqual(entries.reverse().map(prop('data')), messages);
          done();
        });
      }, WRITE_CONSISTENCY_DELAY_MS);
    });

    it('should write an entry with primitive values', function(done) {
      var logEntry = log.entry({
        when: new Date(),
        matchUser: /username: (.+)/,
        matchUserError: new Error('No user found.'),
        shouldNotBeSaved: undefined
      });

      log.write(logEntry, options, function(err) {
        assert.ifError(err);

        setTimeout(function() {
          log.getEntries({ pageSize: 1 }, function(err, entries) {
            assert.ifError(err);

            var entry = entries[0];

            assert.deepEqual(entry.data, {
              when: logEntry.data.when.toString(),
              matchUser: logEntry.data.matchUser.toString(),
              matchUserError: logEntry.data.matchUserError.toString()
            });

            done();
          });
        }, WRITE_CONSISTENCY_DELAY_MS);
      });
    });

    it('should write a log with metadata', function(done) {
      var metadata = extend({}, options, {
        severity: 'DEBUG'
      });

      var data = {
        embeddedData: true
      };

      var logEntry = log.entry(metadata, data);

      log.write(logEntry, function(err) {
        assert.ifError(err);

        setTimeout(function() {
          log.getEntries({ pageSize: 1 }, function(err, entries) {
            assert.ifError(err);

            var entry = entries[0];

            assert.strictEqual(entry.metadata.severity, metadata.severity);
            assert.deepEqual(entry.data, data);

            done();
          });
        }, WRITE_CONSISTENCY_DELAY_MS);
      });
    });

    it('should set the default resource', function(done) {
      var text = 'entry-text';
      var entry = log.entry(text);

      log.write(entry, function(err) {
        assert.ifError(err);

        setTimeout(function() {
          log.getEntries({ pageSize: 1 }, function(err, entries) {
            assert.ifError(err);

            var entry = entries[0];

            assert.strictEqual(entry.data, text);
            assert.deepEqual(entry.metadata.resource, {
              type: 'global',
              labels: {
                project_id: logging.projectId
              }
            });

            done();
          });
        }, WRITE_CONSISTENCY_DELAY_MS);
      });
    });

    it('should write to a log with alert helper', function(done) {
      log.alert(logEntries, options, done);
    });

    it('should write to a log with critical helper', function(done) {
      log.critical(logEntries, options, done);
    });

    it('should write to a log with debug helper', function(done) {
      log.debug(logEntries, options, done);
    });

    it('should write to a log with emergency helper', function(done) {
      log.emergency(logEntries, options, done);
    });

    it('should write to a log with error helper', function(done) {
      log.error(logEntries, options, done);
    });

    it('should write to a log with info helper', function(done) {
      log.info(logEntries, options, done);
    });

    it('should write to a log with notice helper', function(done) {
      log.notice(logEntries, options, done);
    });

    it('should write to a log with warning helper', function(done) {
      log.warning(logEntries, options, done);
    });
  });

  function generateName() {
    return TESTS_PREFIX + uuid.v1();
  }
});
<|endoftext|>


<commit_before>var lastLookup = [];
var lastSearch = [];
var bool = [true];
/*
 * Search the yelp api
 */
var searchYelp = function (term, near, category_filters, offset) {
  if (offset == undefined) {
    var opt_int = 0;
  } else {
    var opt_int = offset;
  }
  if (category_filters == undefined) {
    var opt_cat = "";
  } else {
    var opt_cat = category_filters;
  }
  alert($('#middle').size());
  if (near){
    alert('SEARCHING');
    searchQuery(term, near, opt_cat, opt_int);
  } else {
    if(bool[0]) {
      bool = [];
      bool.push(false);
      $('#middle').append('
' +
      '<button type="button" onclick="bool.pop(); bool.push(true);" class="close" data-dismiss="alert">×</button>'+
      'Warning! Please include the appropriate info in the appropriate fields.'+
      '
');
    }

  }

}

/*
 *
 */
var getBookmarks = function(term) {
  var bookmarks = searchFavorites(term);
  alert('bookmarks length: ' + bookmarks.length);
  browseFavorites(bookmarks);
}

/*
 * Browses Favorites
 */
var browseFavorites = function(data) {
  var current = $('.active1').text();
  alert("LOL: " + current);
  if (current != 'Lookup'){
    alert('PUSHING DATA');
    lastLookup.push(data);
    $('.active1').remove();
    $('.breadcrumb').append('
' + current + ' /
');
    $('.breadcrumb').append('
' + 'Lookup' +'
 ');
    history.pushState({}, 'Yelptastic- Browse Favorite', '#bookmarksearch');
  }
  $('.columnCenter').empty();

  browseBookmarks(data, 0);
}

/*
 * Displays the view for searching yelp.
 */

var addFavoritesView = function(data, total, opt_term, opt_location, opt_cat, opt_offset) {
  //$('.breadcrumbs').removeClass('.active');
  var current = $('.active1').text();
  $('.alert').remove();
  bool = [];
  bool.push(true);

  alert("LOL: " + current);
  lastSearch.push(data);
    lastSearch.push(total);
  lastSearch.push(opt_term);
  lastSearch.push(opt_location);
  lastSearch.push(opt_cat);
  lastSearch.push(opt_offset);
  if (current != 'Search'){
    $('.active1').remove();
    $('.breadcrumb').append('
' + current + ' /
');
    $('.breadcrumb').append('
' + 'Search' +'
 ');
    history.pushState({}, 'Yelptastic- Yelp Search', '#yelpsearch');
  }
  $('.columnLeft').empty();
  $('.columnCenter').empty();
  var allcategories = $.getJSON("scripts/categories.json", function(y){
  	  var x = y;
  	  parseYelpCategories(opt_term, opt_location, x);
  });
  addQuery(data, opt_offset, total, opt_term, opt_location, opt_cat);

}

/*
 * Takes in the results and appends them to the thumbnails grids
 */
var addQuery = function (results, opt_int, opt_total, opt_term, opt_location, opt_cat) {
  $('.columnCenter').empty();
  $thumbnailswrapper = $('

');
  var data = [];
    for (var i = 0; i < results.length; i ++) {
      $button = $('<button>Favorite</button>');
      if(results[i].image_url) {
        var image_url = results[i].image_url;
      } else {
        var image_url = 'http://s3-media3.ak.yelpcdn.com/assets/2/www/img/305e17fe6ed8/gfx/blank_biz_medium_sq.png';
      }
      data.push({
        name:results[i].name,
        image:image_url,
        quote:results[i].snippet_text,
        ratingImage:results[i].rating_img_url,
        button:'Favorite',
        object:JSON.stringify(results[i]),
        url:results[i].url,
        phonenumber:results[i].display_phone,
        n:i.toString(),
      });
  }
  var source = $('#results').html();
  var template = Handlebars.compile(source);
  var string = template(data);
  $thumbnailswrapper.append(string);
  if (opt_total > 20) {
    $buttonRow = $('

');

    if (opt_int >= 20) {
      $see_prev = $('<input type="button" value="Previous 20" name="nextButton">');
      $see_prev.click(function() {
        searchYelp(opt_term, opt_location, opt_cat, opt_int-20);
       });
     $buttonRow.append($see_prev);
    }
    if (opt_int + 20 <= opt_total) {
      alert('Running <')
       $see_all = $('<input type="button" value="Next 20" name="prevButton">');
       $see_all.click(function() {
          searchYelp(opt_term, opt_location, opt_cat, opt_int + 20);
       });
     $buttonRow.append($see_all);
    }
  $thumbnailswrapper.append($buttonRow);
  }
  $('.columnCenter').append($thumbnailswrapper);
  window.scroll();
}

/*
 * Takes in the results and appends them to the thumbnails grids
 */
var browseBookmarks = function (results, opt_int) {
  $('.columnCenter').empty();
  $thumbnailswrapper = $('

');
  $buttonRow = $('

');
  alert('Running browse bookmarks')
  var data = [];
  if (results.length >=20) {
    for (var i = opt_int; i < opt_int + 20; i ++) {
      if(results[i].image_url) {
        var image_url = results[i].image_url;
      } else {
        var image_url = 'http://s3-media3.ak.yelpcdn.com/assets/2/www/img/305e17fe6ed8/gfx/blank_biz_medium_sq.png';
      }
      $button = $('<button>Favorite</button>');
      data.push({
        name:results[i].name,
        image:image_url,
        quote:results[i].snippet_text,
        ratingImage:results[i].rating_img_url,
        tags:results[i].tags,
        url:results[i].url,
      });
    }
  } else {
    for (var i = opt_int; i < results.length; i ++) {
      if(results[i].image_url) {
        var image_url = results[i].image_url;
      } else {
        var image_url = 'http://s3-media3.ak.yelpcdn.com/assets/2/www/img/305e17fe6ed8/gfx/blank_biz_medium_sq.png';
      }
      $button = $('<button>Favorite</button>');
      alert(results[i].name);
      data.push({
        name:results[i].name,
        image:image_url,
        quote:results[i].snippet_text,
        ratingImage:results[i].rating_img_url,
        tags:results[i].tags,
        url:results[i].url,
      });
    }
  }
  var source = $('#browse').html();
  var template = Handlebars.compile(source);
  var string = template(data);
  $thumbnailswrapper.append(string);
  if (data.length >= 20) {
    if (opt_int >= 20) {
      $see_prev = $('<input type="button" value="Previous" name="nextButton">');
      $see_prev.click(function() {
        addQuery(results, opt_int-1);
       });
      $buttonRow.append($see_prev);
      }
    if (opt_int + 20 <= data.length) {
      alert('Running <')
       $see_all = $('<input type="button" value="Next" name="prevButton">');
       $see_all.click(function() {
          addQuery(results, opt_int + 20);
       });
      $buttonRow.append($see_all);
    }
  }

  $thumbnailswrapper.append($buttonRow);
  $('.columnCenter').append($thumbnailswrapper);
}
/*
 * Function to send the bookmarks to the backend
 */
var saveFavorite = function (jsonString, tags1, notes1) {
  var object1 = jsonString;
  alert("ADDED" + object1.name);
  saveBookmark(object1, tags1, notes1);
}

var parseYelpCategories = function (term, location, categories) {

	var categories_wrapper = '
';
	for (var i in categories)
	{
		var genCategory = i;
		var genCategoryTag = i;
		genCategoryTag = genCategoryTag.replace(/ /g, "_");
		genCategoryTag = genCategoryTag.replace(/&/g, "And");

    	categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '';
		categories_wrapper = categories_wrapper + genCategory;
        categories_wrapper = categories_wrapper + '';
        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';

        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';

	}

	categories_wrapper = categories_wrapper + "
";

}<commit_msg>first level categories on yelp search<commit_after>var lastLookup = [];
var lastSearch = [];
var bool = [true];
/*
 * Search the yelp api
 */
var searchYelp = function (term, near, category_filters, offset) {
  if (offset == undefined) {
    var opt_int = 0;
  } else {
    var opt_int = offset;
  }
  if (category_filters == undefined) {
    var opt_cat = "";
  } else {
    var opt_cat = category_filters;
  }
  alert($('#middle').size());
  if (near){
    alert('SEARCHING');
    searchQuery(term, near, opt_cat, opt_int);
  } else {
    if(bool[0]) {
      bool = [];
      bool.push(false);
      $('#middle').append('
' +
      '<button type="button" onclick="bool.pop(); bool.push(true);" class="close" data-dismiss="alert">×</button>'+
      'Warning! Please include the appropriate info in the appropriate fields.'+
      '
');
    }

  }

}

/*
 *
 */
var getBookmarks = function(term) {
  var bookmarks = searchFavorites(term);
  alert('bookmarks length: ' + bookmarks.length);
  browseFavorites(bookmarks);
}

/*
 * Browses Favorites
 */
var browseFavorites = function(data) {
  var current = $('.active1').text();
  alert("LOL: " + current);
  if (current != 'Lookup'){
    alert('PUSHING DATA');
    lastLookup.push(data);
    $('.active1').remove();
    $('.breadcrumb').append('
' + current + ' /
');
    $('.breadcrumb').append('
' + 'Lookup' +'
 ');
    history.pushState({}, 'Yelptastic- Browse Favorite', '#bookmarksearch');
  }
  $('.columnCenter').empty();

  browseBookmarks(data, 0);
}

/*
 * Displays the view for searching yelp.
 */

var addFavoritesView = function(data, total, opt_term, opt_location, opt_cat, opt_offset) {
  //$('.breadcrumbs').removeClass('.active');
  var current = $('.active1').text();
  $('.alert').remove();
  bool = [];
  bool.push(true);

  alert("LOL: " + current);
  lastSearch.push(data);
    lastSearch.push(total);
  lastSearch.push(opt_term);
  lastSearch.push(opt_location);
  lastSearch.push(opt_cat);
  lastSearch.push(opt_offset);
  if (current != 'Search'){
    $('.active1').remove();
    $('.breadcrumb').append('
' + current + ' /
');
    $('.breadcrumb').append('
' + 'Search' +'
 ');
    history.pushState({}, 'Yelptastic- Yelp Search', '#yelpsearch');
  }
  $('.columnLeft').empty();
  $('.columnCenter').empty();
  var allcategories = $.getJSON("scripts/categories.json", function(y){
  	  var x = y;
  	  parseYelpCategories(opt_term, opt_location, x);
  });
  addQuery(data, opt_offset, total, opt_term, opt_location, opt_cat);

}

/*
 * Takes in the results and appends them to the thumbnails grids
 */
var addQuery = function (results, opt_int, opt_total, opt_term, opt_location, opt_cat) {
  $('.columnCenter').empty();
  $thumbnailswrapper = $('

');
  var data = [];
    for (var i = 0; i < results.length; i ++) {
      $button = $('<button>Favorite</button>');
      if(results[i].image_url) {
        var image_url = results[i].image_url;
      } else {
        var image_url = 'http://s3-media3.ak.yelpcdn.com/assets/2/www/img/305e17fe6ed8/gfx/blank_biz_medium_sq.png';
      }
      data.push({
        name:results[i].name,
        image:image_url,
        quote:results[i].snippet_text,
        ratingImage:results[i].rating_img_url,
        button:'Favorite',
        object:JSON.stringify(results[i]),
        url:results[i].url,
        phonenumber:results[i].display_phone,
        n:i.toString(),
      });
  }
  var source = $('#results').html();
  var template = Handlebars.compile(source);
  var string = template(data);
  $thumbnailswrapper.append(string);
  if (opt_total > 20) {
    $buttonRow = $('

');

    if (opt_int >= 20) {
      $see_prev = $('<input type="button" value="Previous 20" name="nextButton">');
      $see_prev.click(function() {
        searchYelp(opt_term, opt_location, opt_cat, opt_int-20);
       });
     $buttonRow.append($see_prev);
    }
    if (opt_int + 20 <= opt_total) {
      alert('Running <')
       $see_all = $('<input type="button" value="Next 20" name="prevButton">');
       $see_all.click(function() {
          searchYelp(opt_term, opt_location, opt_cat, opt_int + 20);
       });
     $buttonRow.append($see_all);
    }
  $thumbnailswrapper.append($buttonRow);
  }
  $('.columnCenter').append($thumbnailswrapper);
  window.scroll();
}

/*
 * Takes in the results and appends them to the thumbnails grids
 */
var browseBookmarks = function (results, opt_int) {
  $('.columnCenter').empty();
  $thumbnailswrapper = $('

');
  $buttonRow = $('

');
  alert('Running browse bookmarks')
  var data = [];
  if (results.length >=20) {
    for (var i = opt_int; i < opt_int + 20; i ++) {
      if(results[i].image_url) {
        var image_url = results[i].image_url;
      } else {
        var image_url = 'http://s3-media3.ak.yelpcdn.com/assets/2/www/img/305e17fe6ed8/gfx/blank_biz_medium_sq.png';
      }
      $button = $('<button>Favorite</button>');
      data.push({
        name:results[i].name,
        image:image_url,
        quote:results[i].snippet_text,
        ratingImage:results[i].rating_img_url,
        tags:results[i].tags,
        url:results[i].url,
      });
    }
  } else {
    for (var i = opt_int; i < results.length; i ++) {
      if(results[i].image_url) {
        var image_url = results[i].image_url;
      } else {
        var image_url = 'http://s3-media3.ak.yelpcdn.com/assets/2/www/img/305e17fe6ed8/gfx/blank_biz_medium_sq.png';
      }
      $button = $('<button>Favorite</button>');
      alert(results[i].name);
      data.push({
        name:results[i].name,
        image:image_url,
        quote:results[i].snippet_text,
        ratingImage:results[i].rating_img_url,
        tags:results[i].tags,
        url:results[i].url,
      });
    }
  }
  var source = $('#browse').html();
  var template = Handlebars.compile(source);
  var string = template(data);
  $thumbnailswrapper.append(string);
  if (data.length >= 20) {
    if (opt_int >= 20) {
      $see_prev = $('<input type="button" value="Previous" name="nextButton">');
      $see_prev.click(function() {
        addQuery(results, opt_int-1);
       });
      $buttonRow.append($see_prev);
      }
    if (opt_int + 20 <= data.length) {
      alert('Running <')
       $see_all = $('<input type="button" value="Next" name="prevButton">');
       $see_all.click(function() {
          addQuery(results, opt_int + 20);
       });
      $buttonRow.append($see_all);
    }
  }

  $thumbnailswrapper.append($buttonRow);
  $('.columnCenter').append($thumbnailswrapper);
}
/*
 * Function to send the bookmarks to the backend
 */
var saveFavorite = function (jsonString, tags1, notes1) {
  var object1 = jsonString;
  alert("ADDED" + object1.name);
  saveBookmark(object1, tags1, notes1);
}

var parseYelpCategories = function (term, location, categories) {

	var categories_wrapper = '
';
	for (var i in categories)
	{
		var genCategory = i;
		var genCategoryTag = i;
		genCategoryTag = genCategoryTag.replace(/ /g, "_");
		genCategoryTag = genCategoryTag.replace(/&/g, "And");

    	categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '';
		categories_wrapper = categories_wrapper + genCategory;
        categories_wrapper = categories_wrapper + '';
        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';

        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';
        categories_wrapper = categories_wrapper + '
';

	}

	categories_wrapper = categories_wrapper + "
";

	$'.columnLeft'.append(categories_wrapper);
}<|endoftext|>


<commit_before>var debug = require('debug')('notification:rpc');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var when = require('when');
var whennode = require('when/node');

var PUSH_NOTIFICATION_CHANNEL_ID = 'cloud-push-notification';

function UserNotificationServiceFacet(service, name) {
  this.service = service;
  this.name = name;
}
util.inherits(UserNotificationServiceFacet, EventEmitter);

UserNotificationServiceFacet.prototype.initialise = function() {
  return this.service.facets('notificationService', 'amqp').spread(function (notificationService, amqp) {
    this._notificationService = notificationService;
    this._amqp = amqp;

    // bind to userspace MQTT (command bridge)
    var topic = ':userId.$cloud.device.:deviceId.channel.'+PUSH_NOTIFICATION_CHANNEL_ID;
    this._amqp.route(
      topic,
      {exchange:'amq.topic', queue: 'push_notification_device_bridge'},
      this._mapUserNotificationDisplayCommand.bind(this)
    );
  }.bind(this));
};

UserNotificationServiceFacet.prototype.getUserspaceRPCMethods = function(rpcBroker) {
  rpcBroker.register('notification.subscribe', this._subscribeRPC.bind(this));
  rpcBroker.register('notification.unsubscribe', this._unsubscribeRPC.bind(this));
};

UserNotificationServiceFacet.prototype._handleStandardSubscriptionRPC = function(remoteMethod, rpc, deviceId, subscriber) {
  if (typeof deviceId !== 'string') throw new rpc.JSONRPCError('deviceId must be a string');
  if (typeof subscriber !== 'object') throw new rpc.JSONRPCError('subscriber must be an object');

  if (typeof subscriber.platform !== 'string') throw new rpc.JSONRPCError('subscriber.platform must be a string');
  if (typeof subscriber.environment !== 'string') throw new rpc.JSONRPCError('subscriber.environment must be a string');
  if (typeof subscriber.token !== 'string') throw new rpc.JSONRPCError('subscriber.token must be a string');

  debug(remoteMethod, 'for user', rpc.userId, 'device', deviceId);

  var internalResponse = this._notificationService.call(
    'notification.' + remoteMethod,
    rpc.userId, // authenticated user ID (via mqtt-proxy)
    'device_' + deviceId, // any "topic" is really fine, they are prefixed by user
    {
      platform: subscriber.platform,
      environment: subscriber.environment,
      token: subscriber.token,
    }
  );

  return internalResponse.then(function(response) {
    return {
      success: response.success, // only share success with userspace, not ARN etc
    };
  });
};

UserNotificationServiceFacet.prototype._subscribeRPC = function(rpc, deviceId, subscriber) {
  return this._handleStandardSubscriptionRPC('subscribeDeviceToTopic', rpc, deviceId, subscriber).then(function(response) {
    var channelId = PUSH_NOTIFICATION_CHANNEL_ID;

    // when we have a success, we announce a channel for the device magically
    var announcement = {
      topic: '$device/' + deviceId + '/channel/' + channelId,
      schema: 'http://schema.ninjablocks.com/protocol/notification',
      supportedMethods: ['display'],
      supportedEvents: [],
      id: channelId,
      protocol: 'notification',
      deviceId: deviceId,
      lastState: null
    };

    var wrappedAnnounce = { jsonrpc: "2.0", params: [announcement] };

    var topic = rpc.userId+'.$cloud.device.'+deviceId+'.channel.'+channelId+'.event.announce';
    var payload = new Buffer(JSON.stringify(wrappedAnnounce));

    this._amqp.publish('amq.topic', topic, payload);

    return response;
  }.bind(this));
};

UserNotificationServiceFacet.prototype._unsubscribeRPC = function(rpc, deviceId, subscriber) {
  // FIXME: when a user unsubscribes, the device channel should be revoked.
  // currently no message exists for un-announcing channels.
  return this._handleStandardSubscriptionRPC('unsubscribeDeviceFromTopic', rpc, deviceId, subscriber);
};

UserNotificationServiceFacet.prototype._mapUserNotificationDisplayCommand = function(amqMsg) {
  // FIXME: support this without copy-paste via the userspace_rpc facet
  var userId = amqMsg.params.userId;
  var deviceId = amqMsg.params.deviceId;

  var response = when.try(function() {
    var message = JSON.parse(amqMsg.content.toString());
    var topic = 'device_' + deviceId;

    var pushText = message.params[0].title;

    var notifyResult = this._notificationService.call(
      'notification.sendNotificationToTopic',
      userId, // authenticated user ID (via mqtt-proxy)
      topic, // topic based on device id in topic (unsafe, but any topic is fine)
      {
        text: pushText,
      }
    );

    return notifyResult.then(function(response) {
      // success, valid json rpc to pass through
      return { jsonrpc: "2.0", result: { success: response.success }, id: message.id };
    }.bind(this), function(err) {
      // error, something broke in the parsing
      debug('error', err);
      return { jsonrpc: "2.0", error: { message: 'Internal Error', code: -32000}, id: message.id };
    }.bind(this));
  }.bind(this));

  return response.then(function(response) {
    // send back the response on the amq.topic
    var topic = userId+'.$cloud.device.'+deviceId+'.channel.'+PUSH_NOTIFICATION_CHANNEL_ID+'.reply';
    var payload = new Buffer(JSON.stringify(response));

    debug('reply', response);

    return this._amqp.publish('amq.topic', topic, payload);
  }.bind(this));
};

module.exports = UserNotificationServiceFacet;
<commit_msg>Send whole ninja notification payload to notification service.<commit_after>var debug = require('debug')('notification:rpc');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var when = require('when');
var whennode = require('when/node');

var PUSH_NOTIFICATION_CHANNEL_ID = 'cloud-push-notification';

function UserNotificationServiceFacet(service, name) {
  this.service = service;
  this.name = name;
}
util.inherits(UserNotificationServiceFacet, EventEmitter);

UserNotificationServiceFacet.prototype.initialise = function() {
  return this.service.facets('notificationService', 'amqp').spread(function (notificationService, amqp) {
    this._notificationService = notificationService;
    this._amqp = amqp;

    // bind to userspace MQTT (command bridge)
    var topic = ':userId.$cloud.device.:deviceId.channel.'+PUSH_NOTIFICATION_CHANNEL_ID;
    this._amqp.route(
      topic,
      {exchange:'amq.topic', queue: 'push_notification_device_bridge'},
      this._mapUserNotificationDisplayCommand.bind(this)
    );
  }.bind(this));
};

UserNotificationServiceFacet.prototype.getUserspaceRPCMethods = function(rpcBroker) {
  rpcBroker.register('notification.subscribe', this._subscribeRPC.bind(this));
  rpcBroker.register('notification.unsubscribe', this._unsubscribeRPC.bind(this));
};

UserNotificationServiceFacet.prototype._handleStandardSubscriptionRPC = function(remoteMethod, rpc, deviceId, subscriber) {
  if (typeof deviceId !== 'string') throw new rpc.JSONRPCError('deviceId must be a string');
  if (typeof subscriber !== 'object') throw new rpc.JSONRPCError('subscriber must be an object');

  if (typeof subscriber.platform !== 'string') throw new rpc.JSONRPCError('subscriber.platform must be a string');
  if (typeof subscriber.environment !== 'string') throw new rpc.JSONRPCError('subscriber.environment must be a string');
  if (typeof subscriber.token !== 'string') throw new rpc.JSONRPCError('subscriber.token must be a string');

  debug(remoteMethod, 'for user', rpc.userId, 'device', deviceId);

  var internalResponse = this._notificationService.call(
    'notification.' + remoteMethod,
    rpc.userId, // authenticated user ID (via mqtt-proxy)
    'device_' + deviceId, // any "topic" is really fine, they are prefixed by user
    {
      platform: subscriber.platform,
      environment: subscriber.environment,
      token: subscriber.token,
    }
  );

  return internalResponse.then(function(response) {
    return {
      success: response.success, // only share success with userspace, not ARN etc
    };
  });
};

UserNotificationServiceFacet.prototype._subscribeRPC = function(rpc, deviceId, subscriber) {
  return this._handleStandardSubscriptionRPC('subscribeDeviceToTopic', rpc, deviceId, subscriber).then(function(response) {
    var channelId = PUSH_NOTIFICATION_CHANNEL_ID;

    // when we have a success, we announce a channel for the device magically
    var announcement = {
      topic: '$device/' + deviceId + '/channel/' + channelId,
      schema: 'http://schema.ninjablocks.com/protocol/notification',
      supportedMethods: ['display'],
      supportedEvents: [],
      id: channelId,
      protocol: 'notification',
      deviceId: deviceId,
      lastState: null
    };

    var wrappedAnnounce = { jsonrpc: "2.0", params: [announcement] };

    var topic = rpc.userId+'.$cloud.device.'+deviceId+'.channel.'+channelId+'.event.announce';
    var payload = new Buffer(JSON.stringify(wrappedAnnounce));

    this._amqp.publish('amq.topic', topic, payload);

    return response;
  }.bind(this));
};

UserNotificationServiceFacet.prototype._unsubscribeRPC = function(rpc, deviceId, subscriber) {
  // FIXME: when a user unsubscribes, the device channel should be revoked.
  // currently no message exists for un-announcing channels.
  return this._handleStandardSubscriptionRPC('unsubscribeDeviceFromTopic', rpc, deviceId, subscriber);
};

UserNotificationServiceFacet.prototype._mapUserNotificationDisplayCommand = function(amqMsg) {
  // FIXME: support this without copy-paste via the userspace_rpc facet
  var userId = amqMsg.params.userId;
  var deviceId = amqMsg.params.deviceId;

  var response = when.try(function() {
    var message = JSON.parse(amqMsg.content.toString());
    var topic = 'device_' + deviceId;

    // var pushText = message.params[0].title;

    var notifyResult = this._notificationService.call(
      'notification.sendNotificationToTopic',
      userId, // authenticated user ID (via mqtt-proxy)
      topic, // topic based on device id in topic (unsafe, but any topic is fine)
      message.params[0] // send the whole ninja notification payload!
    );

    return notifyResult.then(function(response) {
      // success, valid json rpc to pass through
      return { jsonrpc: "2.0", result: { success: response.success }, id: message.id };
    }.bind(this), function(err) {
      // error, something broke in the parsing
      debug('error', err);
      return { jsonrpc: "2.0", error: { message: 'Internal Error', code: -32000}, id: message.id };
    }.bind(this));
  }.bind(this));

  return response.then(function(response) {
    // send back the response on the amq.topic
    var topic = userId+'.$cloud.device.'+deviceId+'.channel.'+PUSH_NOTIFICATION_CHANNEL_ID+'.reply';
    var payload = new Buffer(JSON.stringify(response));

    debug('reply', response);

    return this._amqp.publish('amq.topic', topic, payload);
  }.bind(this));
};

module.exports = UserNotificationServiceFacet;
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START functions_http_integration_test]
const assert = require('assert');
const execPromise = require('child-process-promise').exec;
const path = require('path');
const requestRetry = require('requestretry');
const uuid = require('uuid');

const PORT = process.env.PORT || 8080;
const BASE_URL = process.env.BASE_URL || `http://localhost:${PORT}`;
const cwd = path.join(__dirname, '..');

// [END functions_http_integration_test]

describe('functions_helloworld_http HTTP integration test', () => {
  // [START functions_http_integration_test]
  let ffProc;

  // Run the functions-framework instance to host functions locally
  before(() => {
    // exec's 'timeout' param won't kill children of "shim" /bin/sh process
    // Workaround: include "& sleep <TIMEOUT>; kill $!" in executed command
    ffProc = execPromise(
      `functions-framework --target=helloHttp --signature-type=http --port ${PORT} & sleep 2; kill $!`,
      {shell: true, cwd}
    );
  });

  after(async () => {
    // Wait for the functions framework to stop
    await ffProc;
  });

  it('helloHttp: should print a name', async () => {
    const name = uuid.v4();

    const response = await requestRetry({
      url: `${BASE_URL}/helloHttp`,
      method: 'POST',
      body: {name},
      retryDelay: 200,
      json: true,
    });

    assert.strictEqual(response.statusCode, 200);
    assert.strictEqual(response.body, `Hello ${name}!`);
  });
  // [END functions_http_integration_test]

  it('helloHttp: should print hello world', async () => {
    const response = await requestRetry({
      url: `${BASE_URL}/helloHttp`,
      method: 'POST',
      body: {},
      retryDelay: 200,
      json: true,
    });

    assert.strictEqual(response.statusCode, 200);
    assert.strictEqual(response.body, 'Hello World!');
  });
});
<commit_msg>chore(functions): remove BASE_URL env var (#2106)<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START functions_http_integration_test]
const assert = require('assert');
const execPromise = require('child-process-promise').exec;
const path = require('path');
const requestRetry = require('requestretry');
const uuid = require('uuid');

const PORT = process.env.PORT || 8080;
const BASE_URL = `http://localhost:${PORT}`;
const cwd = path.join(__dirname, '..');

// [END functions_http_integration_test]

describe('functions_helloworld_http HTTP integration test', () => {
  // [START functions_http_integration_test]
  let ffProc;

  // Run the functions-framework instance to host functions locally
  before(() => {
    // exec's 'timeout' param won't kill children of "shim" /bin/sh process
    // Workaround: include "& sleep <TIMEOUT>; kill $!" in executed command
    ffProc = execPromise(
      `functions-framework --target=helloHttp --signature-type=http --port ${PORT} & sleep 2; kill $!`,
      {shell: true, cwd}
    );
  });

  after(async () => {
    // Wait for the functions framework to stop
    await ffProc;
  });

  it('helloHttp: should print a name', async () => {
    const name = uuid.v4();

    const response = await requestRetry({
      url: `${BASE_URL}/helloHttp`,
      method: 'POST',
      body: {name},
      retryDelay: 200,
      json: true,
    });

    assert.strictEqual(response.statusCode, 200);
    assert.strictEqual(response.body, `Hello ${name}!`);
  });
  // [END functions_http_integration_test]

  it('helloHttp: should print hello world', async () => {
    const response = await requestRetry({
      url: `${BASE_URL}/helloHttp`,
      method: 'POST',
      body: {},
      retryDelay: 200,
      json: true,
    });

    assert.strictEqual(response.statusCode, 200);
    assert.strictEqual(response.body, 'Hello World!');
  });
});
<|endoftext|>


<commit_before>const koa = require('koa');
const path = require('path');
const Router = require('koa-router');
const rewrite = require('koa-rewrite');
const json = require('koa-json');
const fs = require('fs');
const { flatMap, forEach, filter, map } = require('lodash');
const etag = require('koa-etag');
const conditional = require('koa-conditional-get');

const app = koa();
const config = require('../config');

// Serve files if required
if (!config.server.apiOnly) {
    const staticCache = require('koa-static-cache');

    // Forward base path to index.html
    app.use(rewrite('/', '/index.html'));
    app.use(staticCache(path.join(__dirname, '../web'), {
        cacheControl: 'no-cache, no-store, must-revalidate',
        buffer: true,
        gzip: false
    }));
}

app.use(conditional());
app.use(etag());

app.use(json({ pretty: false, param: 'pretty' }));
app.use(rewrite('/api/sync', '/api/v1/sync')); // Legacy, before vx syntax

const apiFolder = path.join(__dirname, 'api');

const apiRoutes = map(
    filter(
        fs.readdirSync(apiFolder),
        name => fs.statSync(path.join(apiFolder, name)).isDirectory()
    ),
    name => {
        const imported = require(`./api/${name}`);

        return {
            name,
            setup: imported.setup,
            rewrites: imported.rewrites || []
        };
    }
);

// Run rewrites before adding routes
forEach(
    flatMap(
        apiRoutes,
        it => it.rewrites
    ),
    it => app.use(rewrite(it.from, it.to))
);

// Base API route
const apiRouter = new Router({
    prefix: '/api'
});

// Generic error catcher that renders as JSON
apiRouter.use(function * (next) {
    try {
        yield next;
    } catch (err) {
        this.status = err.status || 500;
        this.body = { error: err.message };
        this.app.emit('error', err, this);
    }
});

// Run the setup function for each version
forEach(
    apiRoutes,
    ({ name, setup }) => {
        // Create route for /v1 e.t.c.
        const router = new Router({ prefix: `/${name}` });
        setup(router);

        // Attach to parent API route
        apiRouter.use(router.routes()).use(router.allowedMethods());
    }
);

app.listen(config.server.port, () => console.log(`Server running on port ${config.server.port}`));
<commit_msg>add route path initial logging and readd the lost api router register<commit_after>const koa = require('koa');
const path = require('path');
const Router = require('koa-router');
const rewrite = require('koa-rewrite');
const json = require('koa-json');
const fs = require('fs');
const { flatMap, forEach, filter, map } = require('lodash');
const etag = require('koa-etag');
const conditional = require('koa-conditional-get');

const app = koa();
const config = require('../config');

// Serve files if required
if (!config.server.apiOnly) {
    const staticCache = require('koa-static-cache');

    // Forward base path to index.html
    app.use(rewrite('/', '/index.html'));
    app.use(staticCache(path.join(__dirname, '../web'), {
        cacheControl: 'no-cache, no-store, must-revalidate',
        buffer: true,
        gzip: false
    }));
}

app.use(conditional());
app.use(etag());

app.use(json({ pretty: false, param: 'pretty' }));
app.use(rewrite('/api/sync', '/api/v1/sync')); // Legacy, before vx syntax

const apiFolder = path.join(__dirname, 'api');

const apiRoutes = map(
    filter(
        fs.readdirSync(apiFolder),
        name => fs.statSync(path.join(apiFolder, name)).isDirectory()
    ),
    name => {
        const imported = require(`./api/${name}`);

        return {
            name,
            setup: imported.setup,
            rewrites: imported.rewrites || []
        };
    }
);

// Run rewrites before adding routes
forEach(
    flatMap(
        apiRoutes,
        it => it.rewrites
    ),
    it => {
        console.log(`Rewriting '${it.from}' to '${it.to}'`);
        app.use(rewrite(it.from, it.to))
    }
);

// Base API route
const apiRouter = new Router({
    prefix: '/api'
});

// Generic error catcher that renders as JSON
apiRouter.use(function * (next) {
    try {
        yield next;
    } catch (err) {
        this.status = err.status || 500;
        this.body = { error: err.message };
        this.app.emit('error', err, this);
    }
});

// Run the setup function for each version
forEach(
    apiRoutes,
    ({ name, setup }) => {
        // Create route for /v1 e.t.c.
        const router = new Router({ prefix: `/${name}` });
        setup(router);
        console.log(`Created API '${name}'`);
        router.stack.forEach(it => {
            console.log(`  ${it.methods.map(it => `[${it}]`)} - ${apiRouter.opts.prefix}${it.path}`);
        });

        // Attach to parent API route
        apiRouter.use(router.routes()).use(router.allowedMethods());
    }
);

app.use(apiRouter.routes()).use(apiRouter.allowedMethods());

app.listen(config.server.port, () => console.log(`Server running on port ${config.server.port}`));
<|endoftext|>


<commit_before>(function( factory ) {
	if (typeof define !== 'undefined' && define.amd) {
		define([], factory);
	} else if (typeof module !== 'undefined' && module.exports) {
		module.exports = factory();
	} else {
		window.scrollMonitor = factory();
	}
})(function() {

	var scrollTop = function() {
		return window.pageYOffset ||
			(document.documentElement && document.documentElement.scrollTop) ||
			document.body.scrollTop;
	};

	var exports = {};

	var watchers = [];

	var VISIBILITYCHANGE = 'visibilityChange';
	var ENTERVIEWPORT = 'enterViewport';
	var FULLYENTERVIEWPORT = 'fullyEnterViewport';
	var EXITVIEWPORT = 'exitViewport';
	var PARTIALLYEXITVIEWPORT = 'partiallyExitViewport';
	var LOCATIONCHANGE = 'locationChange';
	var STATECHANGE = 'stateChange';

	var eventTypes = [
		VISIBILITYCHANGE,
		ENTERVIEWPORT,
		FULLYENTERVIEWPORT,
		EXITVIEWPORT,
		PARTIALLYEXITVIEWPORT,
		LOCATIONCHANGE,
		STATECHANGE
	];

	var defaultOffsets = {top: 0, bottom: 0};

	var getViewportHeight = function() {
		return window.innerHeight || document.documentElement.clientHeight;
	};

	var getDocumentHeight = function() {
		// jQuery approach
		// whichever is greatest
		return Math.max(
			document.body.scrollHeight, document.documentElement.scrollHeight,
			document.body.offsetHeight, document.documentElement.offsetHeight,
			document.documentElement.clientHeight
		);
	};

	exports.viewportTop = null;
	exports.viewportBottom = null;
	exports.documentHeight = null;
	exports.viewportHeight = getViewportHeight();

	var previousDocumentHeight;
	var latestEvent;

	var calculateViewportI;
	function calculateViewport() {
		exports.viewportTop = scrollTop();
		exports.viewportBottom = exports.viewportTop + exports.viewportHeight;
		exports.documentHeight = getDocumentHeight();
		if (exports.documentHeight !== previousDocumentHeight) {
			calculateViewportI = watchers.length;
			while( calculateViewportI-- ) {
				watchers[calculateViewportI].recalculateLocation();
			}
			previousDocumentHeight = exports.documentHeight;
		}
	}

	function recalculateWatchLocationsAndTrigger() {
		exports.viewportHeight = getViewportHeight();
		calculateViewport();
		updateAndTriggerWatchers();
	}

	var recalculateAndTriggerTimer;
	function debouncedRecalcuateAndTrigger() {
		clearTimeout(recalculateAndTriggerTimer);
		recalculateAndTriggerTimer = setTimeout( recalculateWatchLocationsAndTrigger, 100 );
	}

	var updateAndTriggerWatchersI;
	function updateAndTriggerWatchers() {
		// update all watchers then trigger the events so one can rely on another being up to date.
		updateAndTriggerWatchersI = watchers.length;
		while( updateAndTriggerWatchersI-- ) {
			watchers[updateAndTriggerWatchersI].update();
		}

		updateAndTriggerWatchersI = watchers.length;
		while( updateAndTriggerWatchersI-- ) {
			watchers[updateAndTriggerWatchersI].triggerCallbacks();
		}

	}

	function ElementWatcher( watchItem, offsets ) {
		var self = this;

		this.watchItem = watchItem;

		if (!offsets) {
			this.offsets = defaultOffsets;
		} else if (offsets === +offsets) {
			this.offsets = {top: offsets, bottom: offsets};
		} else {
			this.offsets = {
				top: offsets.top || defaultOffsets.top,
				bottom: offsets.bottom || defaultOffsets.bottom
			};
		}

		this.callbacks = {}; // {callback: function, isOne: true }

		for (var i = 0, j = eventTypes.length; i < j; i++) {
			self.callbacks[eventTypes[i]] = [];
		}

		this.locked = false;

		var wasInViewport;
		var wasFullyInViewport;
		var wasAboveViewport;
		var wasBelowViewport;

		var listenerToTriggerListI;
		var listener;
		function triggerCallbackArray( listeners ) {
			if (listeners.length === 0) {
				return;
			}
			listenerToTriggerListI = listeners.length;
			while( listenerToTriggerListI-- ) {
				listener = listeners[listenerToTriggerListI];
				listener.callback.call( self, latestEvent );
				if (listener.isOne) {
					listeners.splice(listenerToTriggerListI, 1);
				}
			}
		}
		this.triggerCallbacks = function triggerCallbacks() {

			if (this.isInViewport && !wasInViewport) {
				triggerCallbackArray( this.callbacks[ENTERVIEWPORT] );
			}
			if (this.isFullyInViewport && !wasFullyInViewport) {
				triggerCallbackArray( this.callbacks[FULLYENTERVIEWPORT] );
			}

			if (this.isAboveViewport !== wasAboveViewport &&
				this.isBelowViewport !== wasBelowViewport) {

				triggerCallbackArray( this.callbacks[VISIBILITYCHANGE] );

				// if you skip completely past this element
				if (!wasFullyInViewport && !this.isFullyInViewport) {
					triggerCallbackArray( this.callbacks[FULLYENTERVIEWPORT] );
					triggerCallbackArray( this.callbacks[PARTIALLYEXITVIEWPORT] );
				}
				if (!wasInViewport && !this.isInViewport) {
					triggerCallbackArray( this.callbacks[ENTERVIEWPORT] );
					triggerCallbackArray( this.callbacks[EXITVIEWPORT] );
				}
			}

			if (!this.isFullyInViewport && wasFullyInViewport) {
				triggerCallbackArray( this.callbacks[PARTIALLYEXITVIEWPORT] );
			}
			if (!this.isInViewport && wasInViewport) {
				triggerCallbackArray( this.callbacks[EXITVIEWPORT] );
			}
			if (this.isInViewport !== wasInViewport) {
				triggerCallbackArray( this.callbacks[VISIBILITYCHANGE] );
			}
			switch( true ) {
				case wasInViewport !== this.isInViewport:
				case wasFullyInViewport !== this.isFullyInViewport:
				case wasAboveViewport !== this.isAboveViewport:
				case wasBelowViewport !== this.isBelowViewport:
					triggerCallbackArray( this.callbacks[STATECHANGE] );
			}

			wasInViewport = this.isInViewport;
			wasFullyInViewport = this.isFullyInViewport;
			wasAboveViewport = this.isAboveViewport;
			wasBelowViewport = this.isBelowViewport;

		};

		this.recalculateLocation = function() {
			if (this.locked) {
				return;
			}
			var previousTop = this.top;
			var previousBottom = this.bottom;
			if (this.watchItem.nodeName) { // a dom element
				var cachedDisplay = this.watchItem.style.display;
				if (cachedDisplay === 'none') {
					this.watchItem.style.display = '';
				}

				var boundingRect = this.watchItem.getBoundingClientRect();
				this.top = boundingRect.top + exports.viewportTop;
				this.bottom = boundingRect.bottom + exports.viewportTop;

				if (cachedDisplay === 'none') {
					this.watchItem.style.display = cachedDisplay;
				}

			} else if (this.watchItem === +this.watchItem) { // number
				if (this.watchItem > 0) {
					this.top = this.bottom = this.watchItem;
				} else {
					this.top = this.bottom = exports.documentHeight - this.watchItem;
				}

			} else { // an object with a top and bottom property
				this.top = this.watchItem.top;
				this.bottom = this.watchItem.bottom;
			}

			this.top -= this.offsets.top;
			this.bottom += this.offsets.bottom;
			this.height = this.bottom - this.top;

			if ( (previousTop !== undefined || previousBottom !== undefined) && (this.top !== previousTop || this.bottom !== previousBottom) ) {
				triggerCallbackArray( this.callbacks[LOCATIONCHANGE] );
			}
		};

		this.recalculateLocation();
		this.update();

		wasInViewport = this.isInViewport;
		wasFullyInViewport = this.isFullyInViewport;
		wasAboveViewport = this.isAboveViewport;
		wasBelowViewport = this.isBelowViewport;
	}

	ElementWatcher.prototype = {
		on: function( event, callback, isOne ) {

			// trigger the event if it applies to the element right now.
			switch( true ) {
				case event === VISIBILITYCHANGE && !this.isInViewport && this.isAboveViewport:
				case event === ENTERVIEWPORT && this.isInViewport:
				case event === FULLYENTERVIEWPORT && this.isFullyInViewport:
				case event === EXITVIEWPORT && this.isAboveViewport && !this.isInViewport:
				case event === PARTIALLYEXITVIEWPORT && this.isAboveViewport:
					callback.call( this, latestEvent );
					if (isOne) {
						return;
					}
			}

			if (this.callbacks[event]) {
				this.callbacks[event].push({callback: callback, isOne: isOne||false});
			} else {
				throw new Error('Tried to add a scroll monitor listener of type '+event+'. Your options are: '+eventTypes.join(', '));
			}
		},
		off: function( event, callback ) {
			if (this.callbacks[event]) {
				for (var i = 0, item; item = this.callbacks[event][i]; i++) {
					if (item.callback === callback) {
						this.callbacks[event].splice(i, 1);
						break;
					}
				}
			} else {
				throw new Error('Tried to remove a scroll monitor listener of type '+event+'. Your options are: '+eventTypes.join(', '));
			}
		},
		one: function( event, callback ) {
			this.on( event, callback, true);
		},
		recalculateSize: function() {
			this.height = this.watchItem.offsetHeight + this.offsets.top + this.offsets.bottom;
			this.bottom = this.top + this.height;
		},
		update: function() {
			this.isAboveViewport = this.top < exports.viewportTop;
			this.isBelowViewport = this.bottom > exports.viewportBottom;

			this.isInViewport = (this.top <= exports.viewportBottom && this.bottom >= exports.viewportTop);
			this.isFullyInViewport = (this.top >= exports.viewportTop && this.bottom <= exports.viewportBottom) ||
								 (this.isAboveViewport && this.isBelowViewport);

		},
		destroy: function() {
			var index = watchers.indexOf(this),
				self  = this;
			watchers.splice(index, 1);
			for (var i = 0, j = eventTypes.length; i < j; i++) {
				self.callbacks[eventTypes[i]].length = 0;
			}
		},
		// prevent recalculating the element location
		lock: function() {
			this.locked = true;
		},
		unlock: function() {
			this.locked = false;
		}
	};

	var eventHandlerFactory = function (type) {
		return function( callback, isOne ) {
			this.on.call(this, type, callback, isOne);
		};
	};

	for (var i = 0, j = eventTypes.length; i < j; i++) {
		var type =  eventTypes[i];
		ElementWatcher.prototype[type] = eventHandlerFactory(type);
	}

	try {
		calculateViewport();
	} catch (e) {
		try {
			window.$(calculateViewport);
		} catch (e) {
			throw new Error('If you must put scrollMonitor in the <head>, you must use jQuery.');
		}
	}

	function scrollMonitorListener(event) {
		latestEvent = event;
		calculateViewport();
		updateAndTriggerWatchers();
	}

	if (window.addEventListener) {
		window.addEventListener('scroll', scrollMonitorListener);
		window.addEventListener('resize', debouncedRecalcuateAndTrigger);
	} else {
		// Old IE support
		window.attachEvent('onscroll', scrollMonitorListener);
		window.attachEvent('onresize', debouncedRecalcuateAndTrigger);
	}

	exports.beget = exports.create = function( element, offsets ) {
		if (typeof element === 'string') {
			element = document.querySelector(element);
		} else if (element && element.length > 0) {
			element = element[0];
		}

		var watcher = new ElementWatcher( element, offsets );
		watchers.push(watcher);
		watcher.update();
		return watcher;
	};

	exports.update = function() {
		latestEvent = null;
		calculateViewport();
		updateAndTriggerWatchers();
	};
	exports.recalculateLocations = function() {
		exports.documentHeight = 0;
		exports.update();
	};

	return exports;
});
<commit_msg>Use jQuery property instead of $<commit_after>(function( factory ) {
	if (typeof define !== 'undefined' && define.amd) {
		define([], factory);
	} else if (typeof module !== 'undefined' && module.exports) {
		module.exports = factory();
	} else {
		window.scrollMonitor = factory();
	}
})(function() {

	var scrollTop = function() {
		return window.pageYOffset ||
			(document.documentElement && document.documentElement.scrollTop) ||
			document.body.scrollTop;
	};

	var exports = {};

	var watchers = [];

	var VISIBILITYCHANGE = 'visibilityChange';
	var ENTERVIEWPORT = 'enterViewport';
	var FULLYENTERVIEWPORT = 'fullyEnterViewport';
	var EXITVIEWPORT = 'exitViewport';
	var PARTIALLYEXITVIEWPORT = 'partiallyExitViewport';
	var LOCATIONCHANGE = 'locationChange';
	var STATECHANGE = 'stateChange';

	var eventTypes = [
		VISIBILITYCHANGE,
		ENTERVIEWPORT,
		FULLYENTERVIEWPORT,
		EXITVIEWPORT,
		PARTIALLYEXITVIEWPORT,
		LOCATIONCHANGE,
		STATECHANGE
	];

	var defaultOffsets = {top: 0, bottom: 0};

	var getViewportHeight = function() {
		return window.innerHeight || document.documentElement.clientHeight;
	};

	var getDocumentHeight = function() {
		// jQuery approach
		// whichever is greatest
		return Math.max(
			document.body.scrollHeight, document.documentElement.scrollHeight,
			document.body.offsetHeight, document.documentElement.offsetHeight,
			document.documentElement.clientHeight
		);
	};

	exports.viewportTop = null;
	exports.viewportBottom = null;
	exports.documentHeight = null;
	exports.viewportHeight = getViewportHeight();

	var previousDocumentHeight;
	var latestEvent;

	var calculateViewportI;
	function calculateViewport() {
		exports.viewportTop = scrollTop();
		exports.viewportBottom = exports.viewportTop + exports.viewportHeight;
		exports.documentHeight = getDocumentHeight();
		if (exports.documentHeight !== previousDocumentHeight) {
			calculateViewportI = watchers.length;
			while( calculateViewportI-- ) {
				watchers[calculateViewportI].recalculateLocation();
			}
			previousDocumentHeight = exports.documentHeight;
		}
	}

	function recalculateWatchLocationsAndTrigger() {
		exports.viewportHeight = getViewportHeight();
		calculateViewport();
		updateAndTriggerWatchers();
	}

	var recalculateAndTriggerTimer;
	function debouncedRecalcuateAndTrigger() {
		clearTimeout(recalculateAndTriggerTimer);
		recalculateAndTriggerTimer = setTimeout( recalculateWatchLocationsAndTrigger, 100 );
	}

	var updateAndTriggerWatchersI;
	function updateAndTriggerWatchers() {
		// update all watchers then trigger the events so one can rely on another being up to date.
		updateAndTriggerWatchersI = watchers.length;
		while( updateAndTriggerWatchersI-- ) {
			watchers[updateAndTriggerWatchersI].update();
		}

		updateAndTriggerWatchersI = watchers.length;
		while( updateAndTriggerWatchersI-- ) {
			watchers[updateAndTriggerWatchersI].triggerCallbacks();
		}

	}

	function ElementWatcher( watchItem, offsets ) {
		var self = this;

		this.watchItem = watchItem;

		if (!offsets) {
			this.offsets = defaultOffsets;
		} else if (offsets === +offsets) {
			this.offsets = {top: offsets, bottom: offsets};
		} else {
			this.offsets = {
				top: offsets.top || defaultOffsets.top,
				bottom: offsets.bottom || defaultOffsets.bottom
			};
		}

		this.callbacks = {}; // {callback: function, isOne: true }

		for (var i = 0, j = eventTypes.length; i < j; i++) {
			self.callbacks[eventTypes[i]] = [];
		}

		this.locked = false;

		var wasInViewport;
		var wasFullyInViewport;
		var wasAboveViewport;
		var wasBelowViewport;

		var listenerToTriggerListI;
		var listener;
		function triggerCallbackArray( listeners ) {
			if (listeners.length === 0) {
				return;
			}
			listenerToTriggerListI = listeners.length;
			while( listenerToTriggerListI-- ) {
				listener = listeners[listenerToTriggerListI];
				listener.callback.call( self, latestEvent );
				if (listener.isOne) {
					listeners.splice(listenerToTriggerListI, 1);
				}
			}
		}
		this.triggerCallbacks = function triggerCallbacks() {

			if (this.isInViewport && !wasInViewport) {
				triggerCallbackArray( this.callbacks[ENTERVIEWPORT] );
			}
			if (this.isFullyInViewport && !wasFullyInViewport) {
				triggerCallbackArray( this.callbacks[FULLYENTERVIEWPORT] );
			}

			if (this.isAboveViewport !== wasAboveViewport &&
				this.isBelowViewport !== wasBelowViewport) {

				triggerCallbackArray( this.callbacks[VISIBILITYCHANGE] );

				// if you skip completely past this element
				if (!wasFullyInViewport && !this.isFullyInViewport) {
					triggerCallbackArray( this.callbacks[FULLYENTERVIEWPORT] );
					triggerCallbackArray( this.callbacks[PARTIALLYEXITVIEWPORT] );
				}
				if (!wasInViewport && !this.isInViewport) {
					triggerCallbackArray( this.callbacks[ENTERVIEWPORT] );
					triggerCallbackArray( this.callbacks[EXITVIEWPORT] );
				}
			}

			if (!this.isFullyInViewport && wasFullyInViewport) {
				triggerCallbackArray( this.callbacks[PARTIALLYEXITVIEWPORT] );
			}
			if (!this.isInViewport && wasInViewport) {
				triggerCallbackArray( this.callbacks[EXITVIEWPORT] );
			}
			if (this.isInViewport !== wasInViewport) {
				triggerCallbackArray( this.callbacks[VISIBILITYCHANGE] );
			}
			switch( true ) {
				case wasInViewport !== this.isInViewport:
				case wasFullyInViewport !== this.isFullyInViewport:
				case wasAboveViewport !== this.isAboveViewport:
				case wasBelowViewport !== this.isBelowViewport:
					triggerCallbackArray( this.callbacks[STATECHANGE] );
			}

			wasInViewport = this.isInViewport;
			wasFullyInViewport = this.isFullyInViewport;
			wasAboveViewport = this.isAboveViewport;
			wasBelowViewport = this.isBelowViewport;

		};

		this.recalculateLocation = function() {
			if (this.locked) {
				return;
			}
			var previousTop = this.top;
			var previousBottom = this.bottom;
			if (this.watchItem.nodeName) { // a dom element
				var cachedDisplay = this.watchItem.style.display;
				if (cachedDisplay === 'none') {
					this.watchItem.style.display = '';
				}

				var boundingRect = this.watchItem.getBoundingClientRect();
				this.top = boundingRect.top + exports.viewportTop;
				this.bottom = boundingRect.bottom + exports.viewportTop;

				if (cachedDisplay === 'none') {
					this.watchItem.style.display = cachedDisplay;
				}

			} else if (this.watchItem === +this.watchItem) { // number
				if (this.watchItem > 0) {
					this.top = this.bottom = this.watchItem;
				} else {
					this.top = this.bottom = exports.documentHeight - this.watchItem;
				}

			} else { // an object with a top and bottom property
				this.top = this.watchItem.top;
				this.bottom = this.watchItem.bottom;
			}

			this.top -= this.offsets.top;
			this.bottom += this.offsets.bottom;
			this.height = this.bottom - this.top;

			if ( (previousTop !== undefined || previousBottom !== undefined) && (this.top !== previousTop || this.bottom !== previousBottom) ) {
				triggerCallbackArray( this.callbacks[LOCATIONCHANGE] );
			}
		};

		this.recalculateLocation();
		this.update();

		wasInViewport = this.isInViewport;
		wasFullyInViewport = this.isFullyInViewport;
		wasAboveViewport = this.isAboveViewport;
		wasBelowViewport = this.isBelowViewport;
	}

	ElementWatcher.prototype = {
		on: function( event, callback, isOne ) {

			// trigger the event if it applies to the element right now.
			switch( true ) {
				case event === VISIBILITYCHANGE && !this.isInViewport && this.isAboveViewport:
				case event === ENTERVIEWPORT && this.isInViewport:
				case event === FULLYENTERVIEWPORT && this.isFullyInViewport:
				case event === EXITVIEWPORT && this.isAboveViewport && !this.isInViewport:
				case event === PARTIALLYEXITVIEWPORT && this.isAboveViewport:
					callback.call( this, latestEvent );
					if (isOne) {
						return;
					}
			}

			if (this.callbacks[event]) {
				this.callbacks[event].push({callback: callback, isOne: isOne||false});
			} else {
				throw new Error('Tried to add a scroll monitor listener of type '+event+'. Your options are: '+eventTypes.join(', '));
			}
		},
		off: function( event, callback ) {
			if (this.callbacks[event]) {
				for (var i = 0, item; item = this.callbacks[event][i]; i++) {
					if (item.callback === callback) {
						this.callbacks[event].splice(i, 1);
						break;
					}
				}
			} else {
				throw new Error('Tried to remove a scroll monitor listener of type '+event+'. Your options are: '+eventTypes.join(', '));
			}
		},
		one: function( event, callback ) {
			this.on( event, callback, true);
		},
		recalculateSize: function() {
			this.height = this.watchItem.offsetHeight + this.offsets.top + this.offsets.bottom;
			this.bottom = this.top + this.height;
		},
		update: function() {
			this.isAboveViewport = this.top < exports.viewportTop;
			this.isBelowViewport = this.bottom > exports.viewportBottom;

			this.isInViewport = (this.top <= exports.viewportBottom && this.bottom >= exports.viewportTop);
			this.isFullyInViewport = (this.top >= exports.viewportTop && this.bottom <= exports.viewportBottom) ||
								 (this.isAboveViewport && this.isBelowViewport);

		},
		destroy: function() {
			var index = watchers.indexOf(this),
				self  = this;
			watchers.splice(index, 1);
			for (var i = 0, j = eventTypes.length; i < j; i++) {
				self.callbacks[eventTypes[i]].length = 0;
			}
		},
		// prevent recalculating the element location
		lock: function() {
			this.locked = true;
		},
		unlock: function() {
			this.locked = false;
		}
	};

	var eventHandlerFactory = function (type) {
		return function( callback, isOne ) {
			this.on.call(this, type, callback, isOne);
		};
	};

	for (var i = 0, j = eventTypes.length; i < j; i++) {
		var type =  eventTypes[i];
		ElementWatcher.prototype[type] = eventHandlerFactory(type);
	}

	try {
		calculateViewport();
	} catch (e) {
		try {
			window.jQuery(calculateViewport);
		} catch (e) {
			throw new Error('If you must put scrollMonitor in the <head>, you must use jQuery.');
		}
	}

	function scrollMonitorListener(event) {
		latestEvent = event;
		calculateViewport();
		updateAndTriggerWatchers();
	}

	if (window.addEventListener) {
		window.addEventListener('scroll', scrollMonitorListener);
		window.addEventListener('resize', debouncedRecalcuateAndTrigger);
	} else {
		// Old IE support
		window.attachEvent('onscroll', scrollMonitorListener);
		window.attachEvent('onresize', debouncedRecalcuateAndTrigger);
	}

	exports.beget = exports.create = function( element, offsets ) {
		if (typeof element === 'string') {
			element = document.querySelector(element);
		} else if (element && element.length > 0) {
			element = element[0];
		}

		var watcher = new ElementWatcher( element, offsets );
		watchers.push(watcher);
		watcher.update();
		return watcher;
	};

	exports.update = function() {
		latestEvent = null;
		calculateViewport();
		updateAndTriggerWatchers();
	};
	exports.recalculateLocations = function() {
		exports.documentHeight = 0;
		exports.update();
	};

	return exports;
});
<|endoftext|>


<commit_before>import { Menu, Tray as TrayIcon } from 'electron';
import { EventEmitter } from 'events';
import icon from './icon';
import i18n from '../i18n/index.js';

const getIconStyle = ({ badge: { title, count, showAlert }, status, showUserStatus }) => {
	const style = {
		template: process.platform === 'darwin',
		size: process.platform === 'win32' ? 16 : 24,
	};

	if (showUserStatus) {
		style.status = status;
	}

	if (process.platform !== 'darwin') {
		if (title === '•') {
			style.badgeText = '•';
		} else if (count > 0) {
			style.badgeText = count > 9 ? '9+' : String(count);
		} else if (showAlert) {
			style.badgeText = '!';
		}
	}

	return style;
};

const getIconTitle =
	({ badge: { title, count, showAlert } }) => ((showAlert && count > 0) ? title : null);

const getIconTooltip = ({ badge: { count } }) => i18n.pluralize('Message_count', count, count);

const createContextMenuTemplate = ({ isMainWindowVisible }, events) => ([
	{
		label: !isMainWindowVisible ? i18n.__('Show') : i18n.__('Hide'),
		click: () => events.emit('set-main-window-visibility', !isMainWindowVisible),
	},
	{
		label: i18n.__('Quit'),
		click: () => events.emit('quit'),
	},
]);

let trayIcon = null;

let state = {
	badge: {
		title: '',
		count: 0,
		showAlert: false,
	},
	status: 'online',
	isMainWindowVisible: true,
	showIcon: true,
	showUserStatus: true,
};

const instance = new (class Tray extends EventEmitter {});

const createIcon = (image) => {
	if (trayIcon) {
		return;
	}

	trayIcon = new TrayIcon(image);

	trayIcon.on('click', () => instance.emit('set-main-window-visibility', !state.isMainWindowVisible));
	trayIcon.on('right-click', (event, bounds) => trayIcon.popUpContextMenu(undefined, bounds));

	instance.emit('created');
};

const destroyIcon = () => {
	if (!trayIcon) {
		return;
	}

	trayIcon.destroy();
	instance.emit('destroyed');
	trayIcon = null;
};

const destroy = () => {
	instance.destroyIcon();
	instance.removeAllListeners();
};

const update = async() => {
	if (!state.showIcon) {
		destroyIcon();
		instance.emit('update');
		return;
	}

	const image = await icon.render(getIconStyle(state));

	if (!trayIcon) {
		createIcon(image);
	} else {
		trayIcon.setImage(image);
	}

	trayIcon.setToolTip(getIconTooltip(state));

	if (process.platform === 'darwin') {
		trayIcon.setTitle(getIconTitle(state));
	}

	const template = createContextMenuTemplate(state, instance);
	const menu = Menu.buildFromTemplate(template);
	trayIcon.setContextMenu(menu);
	instance.emit('update');
};

const setState = (partialState) => {
	state = {
		...state,
		...partialState,
	};
	update();
};

export default Object.assign(instance, {
	destroy,
	setState,
});
<commit_msg>Fix bug in tray module<commit_after>import { Menu, Tray as TrayIcon } from 'electron';
import { EventEmitter } from 'events';
import icon from './icon';
import i18n from '../i18n/index.js';

const getIconStyle = ({ badge: { title, count, showAlert }, status, showUserStatus }) => {
	const style = {
		template: process.platform === 'darwin',
		size: process.platform === 'win32' ? 16 : 24,
	};

	if (showUserStatus) {
		style.status = status;
	}

	if (process.platform !== 'darwin') {
		if (title === '•') {
			style.badgeText = '•';
		} else if (count > 0) {
			style.badgeText = count > 9 ? '9+' : String(count);
		} else if (showAlert) {
			style.badgeText = '!';
		}
	}

	return style;
};

const getIconTitle =
	({ badge: { title, count, showAlert } }) => ((showAlert && count > 0) ? title : null);

const getIconTooltip = ({ badge: { count } }) => i18n.pluralize('Message_count', count, count);

const createContextMenuTemplate = ({ isMainWindowVisible }, events) => ([
	{
		label: !isMainWindowVisible ? i18n.__('Show') : i18n.__('Hide'),
		click: () => events.emit('set-main-window-visibility', !isMainWindowVisible),
	},
	{
		label: i18n.__('Quit'),
		click: () => events.emit('quit'),
	},
]);

let trayIcon = null;

let state = {
	badge: {
		title: '',
		count: 0,
		showAlert: false,
	},
	status: 'online',
	isMainWindowVisible: true,
	showIcon: true,
	showUserStatus: true,
};

const instance = new (class Tray extends EventEmitter {});

const createIcon = (image) => {
	if (trayIcon) {
		return;
	}

	trayIcon = new TrayIcon(image);

	trayIcon.on('click', () => instance.emit('set-main-window-visibility', !state.isMainWindowVisible));
	trayIcon.on('right-click', (event, bounds) => trayIcon.popUpContextMenu(undefined, bounds));

	instance.emit('created');
};

const destroyIcon = () => {
	if (!trayIcon) {
		return;
	}

	trayIcon.destroy();
	instance.emit('destroyed');
	trayIcon = null;
};

const destroy = () => {
	destroyIcon();
	instance.removeAllListeners();
};

const update = async() => {
	if (!state.showIcon) {
		destroyIcon();
		instance.emit('update');
		return;
	}

	const image = await icon.render(getIconStyle(state));

	if (!trayIcon) {
		createIcon(image);
	} else {
		trayIcon.setImage(image);
	}

	trayIcon.setToolTip(getIconTooltip(state));

	if (process.platform === 'darwin') {
		trayIcon.setTitle(getIconTitle(state));
	}

	const template = createContextMenuTemplate(state, instance);
	const menu = Menu.buildFromTemplate(template);
	trayIcon.setContextMenu(menu);
	instance.emit('update');
};

const setState = (partialState) => {
	state = {
		...state,
		...partialState,
	};
	update();
};

export default Object.assign(instance, {
	destroy,
	setState,
});
<|endoftext|>


<commit_before>var generic = require("./generic"),
    cp = require("child_process"),
	path = require("path"),
    util = require("util"),
    _ = require('underscore');

function NodeunitHandler(cmd) {
	this.name = "NodeunitHandler";
	generic.apply(this, arguments);
}

util.inherits(NodeunitHandler, generic);

module.exports = NodeunitHandler;

NodeunitHandler.prototype.run = function(workingDir) {
  var env = _.extend(process.env, this.commandLine.envs);
  this.commandLine.cmd = path.join(__dirname, "..", "..", "test_suites","lib","node_modules","nodeunit","bin","nodeunit");

  // console.log("cmd: " + this.commandLine.cmd);
  // console.log("args (" + typeof this.commandLine.args + "): " + this.commandLine.args);

  var p = cp.spawn(this.commandLine.cmd, this.commandLine.args, {
    cwd: workingDir,
    env: env
  });

  p.stderr.on("data", _.bind(this.onErr, this));
  p.stdout.on("data", _.bind(this.onStd, this));
  p.on("exit", _.bind(this.onExit, this));
};

NodeunitHandler.prototype.output = '';
// NodeunitHandler.prototype.onStd = function (data) {
//   this.output += data;
//   console.log(data.toString());
// }
//
// NodeunitHandler.prototype.onErr = function(err, data) {
//   console.log(err.toString());
// };
//
// NodeunitHandler.prototype.onExit = function(code, sig) {
//   /*console.log('===');
//   console.log(this.output);
//   console.log('===');*/
//   console.log("complete", code <= 0, sig);
//   this.emit("complete", code <= 0, sig);
// };
<commit_msg>slave: use nodeunit binary located in slave's node_modules folder<commit_after>var generic = require("./generic"),
    cp = require("child_process"),
	path = require("path"),
    util = require("util"),
    _ = require('underscore');

function NodeunitHandler(cmd) {
	this.name = "NodeunitHandler";
	generic.apply(this, arguments);
}

util.inherits(NodeunitHandler, generic);

module.exports = NodeunitHandler;

NodeunitHandler.prototype.run = function(workingDir) {
  var env = _.extend(process.env, this.commandLine.envs);
  this.commandLine.cmd = path.join(
    __dirname, "..", "..", "node_modules","nodeunit","bin","nodeunit"
  );

  // console.log("cmd: " + this.commandLine.cmd);
  // console.log("args (" + typeof this.commandLine.args + "): " + this.commandLine.args);

  var p = cp.spawn(this.commandLine.cmd, this.commandLine.args, {
    cwd: workingDir,
    env: env
  });

  p.stderr.on("data", _.bind(this.onErr, this));
  p.stdout.on("data", _.bind(this.onStd, this));
  p.on("exit", _.bind(this.onExit, this));
};

NodeunitHandler.prototype.output = '';
// NodeunitHandler.prototype.onStd = function (data) {
//   this.output += data;
//   console.log(data.toString());
// }
//
// NodeunitHandler.prototype.onErr = function(err, data) {
//   console.log(err.toString());
// };
//
// NodeunitHandler.prototype.onExit = function(code, sig) {
//   /*console.log('===');
//   console.log(this.output);
//   console.log('===');*/
//   console.log("complete", code <= 0, sig);
//   this.emit("complete", code <= 0, sig);
// };
<|endoftext|>