<commit_before>/* global describe, it*/
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai'),
  assert = chai.assert,
  expect = chai.expect,
  should = chai.should(),
  ksm = require('kronos-service-manager'),
  ServiceConsul = require('../service.js');

describe('consul service', function () {
  this.timeout(30000);
  it("create", () =>
    ksm.manager([{}, {
      name: "consul",
      port: 4713
    }], [ServiceConsul, require('kronos-service-health-check'), require('kronos-service-koa')]).then(
      manager => {
        const cs = manager.services.registry;

        assert.equal(cs.name, "registry");

        return cs.start().then(f => {
          assert.equal(cs.state, "running");
          assert.deepEqual(cs.tags, []);

          cs.registerService('myService', {
            url: cs.listener.url + "/somepath"
          }).then(() => {
            const us = cs.serviceURLs('myService');

            assert.equal(us, cs.listener.url + "/somepath");

            setInterval(() =>
              us.next().value.then(u => {
                assert.equal(us, cs.listener.url + "/somepath");
                console.log(`myService: ${u}`);
              }),
              1000);

            setTimeout(() => {
                cs.unregisterService('myService').then(() => {
                  assert.ok("unregistered");

                  const us = cs.serviceURLs('myService');
                  console.log(`after: ${us}`);
                });
              },
              5000);
          }).catch(console.log);

          return new Promise((f, r) =>
            setTimeout(f, 20000));
        });
      })
  );
});
<commit_msg>test: assert service url<commit_after>/* global describe, it*/
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai'),
  assert = chai.assert,
  expect = chai.expect,
  should = chai.should(),
  ksm = require('kronos-service-manager'),
  ServiceConsul = require('../service.js');

describe('consul service', function () {
  this.timeout(30000);
  it("create", () =>
    ksm.manager([{}, {
      name: "consul",
      port: 4713
    }], [ServiceConsul, require('kronos-service-health-check'), require('kronos-service-koa')]).then(
      manager => {
        const cs = manager.services.registry;

        assert.equal(cs.name, "registry");

        return cs.start().then(f => {
          assert.equal(cs.state, "running");
          assert.deepEqual(cs.tags, []);

          cs.registerService('myService', {
            url: cs.listener.url + "/somepath"
          }).then(() => {
            const us = cs.serviceURLs('myService');

            assert.equal(us, cs.listener.url + "/somepath");

            setInterval(() =>
              us.next().value.then(u => {
                assert.equal(u, cs.listener.url + "/somepath");
                console.log(`myService: ${u}`);
              }),
              1000);

            setTimeout(() => {
                cs.unregisterService('myService').then(() => {
                  assert.ok("unregistered");

                  const us = cs.serviceURLs('myService');
                  console.log(`after: ${us}`);
                });
              },
              5000);
          }).catch(console.log);

          return new Promise((f, r) =>
            setTimeout(f, 20000));
        });
      })
  );
});
<|endoftext|>


<commit_before>var app = {
  debug: true,
  log: function (a, b, c, d, e, f, g, h, i) {
    if (app.debug) {
      cobalt.log(a, b, c, d, e, f, g, h, i);
    }
  },
  touchTimer: null,
  touch: function (selector, touchHandler, allowDefault) {
    var preventDefault = allowDefault ? false : true;
    var elem = $(selector)
    var touchup = function () {
      elem.removeClass('touched');
    };
    var touching = function (e) {
      if (!elem.hasClass('touched')) {
        elem.addClass('touched');
        clearTimeout(app.touchTimer);
        app.touchTimer = setTimeout(touchup, 1000);
        touchHandler.apply([this, e]);
      }
      if (preventDefault)
        return false;
    };
    elem.unbind('tap').on('tap', touching);
    elem.unbind('click').on('click', touching);
  },
  start: function () {
    app.page = $.extend(true, {}, app.super, app.page);
    $('body').addClass(app.page.name);
    if (window.templates) {
      $.each(app.page.templates, function (key, item) {
        templates.templates.push(item);
      });
      templates.init();
      templates.addAsPartials(app.page.partials);
    }

    cobalt.init();

    if (cobalt.debugInBrowser) {
      setTimeout(app.page.events.onAppStarted, 200);
      setTimeout(app.page.events.onPageShown, 250);
    }
  },
  /*
   'super' is the default/parent controller for all pages.
   When defining a page you can use only a subset of functions and values.
   This "heritage" is recursive so you can mix some templates here and in the children page
   In a page you can also redefine a function and call app.super.myFunction if needed.
   */
  super: {
    name: 'default',
    templates: [],
    partials: [],
    config: function (data) {
    },
    init: function (data) {
      app.log('page created', app.page.name, data);
      app.page.reset(data);
    },
    refresh: function (data, callback) {
      app.log('page refresh', app.page.name, data);
    },
    events: {
      "onPageShown": function (data) {
        if (!app.pageAlreadyShown) {
          app.page.config(data);
          app.page.init(data);
          app.pageAlreadyShown = true;
        } else {
          app.page.refresh(data);
        }
      }
    }
  }
};
<commit_msg>fix for cobalt1.0<commit_after>var app = {
  debug: true,
  log: function (a, b, c, d, e, f, g, h, i) {
    if (app.debug) {
      cobalt.log(a, b, c, d, e, f, g, h, i);
    }
  },
  touchTimer: null,
  touch: function (selector, touchHandler, allowDefault) {
    var preventDefault = allowDefault ? false : true;
    var elem = $(selector)
    var touchup = function () {
      elem.removeClass('touched');
    };
    var touching = function (e) {
      if (!elem.hasClass('touched')) {
        elem.addClass('touched');
        clearTimeout(app.touchTimer);
        app.touchTimer = setTimeout(touchup, 1000);
        touchHandler.apply([this, e]);
      }
      if (preventDefault)
        return false;
    };
    elem.unbind('tap').on('tap', touching);
    elem.unbind('click').on('click', touching);
  },
  start: function () {
    app.page = $.extend(true, {}, app.super, app.page);
    $('body').addClass(app.page.name);
    if (window.templates) {
      $.each(app.page.templates, function (key, item) {
        templates.templates.push(item);
      });
      templates.init();
      templates.addAsPartials(app.page.partials);
    }

    cobalt.init();

    cobalt.subscribe("cobalt:onPageShown", function(data){
      if (!app.pageAlreadyShown) {
        app.page.config(data);
        app.page.init(data);
        app.pageAlreadyShown = true;
      } else {
        app.page.refresh(data);
      }
    });

    if (cobalt.debugInBrowser) {
      setTimeout(cobalt.private.pubsub.handlers['cobalt.onAppStarted'], 200);
      setTimeout(cobalt.private.pubsub.handlers['cobalt.onPageShown'], 250);
    }
  },
  /*
   'super' is the default/parent controller for all pages.
   When defining a page you can use only a subset of functions and values.
   This "heritage" is recursive so you can mix some templates here and in the children page
   In a page you can also redefine a function and call app.super.myFunction if needed.
   */
  super: {
    name: 'default',
    templates: [],
    partials: [],
    config: function (data) {
    },
    init: function (data) {
      app.log('page created', app.page.name, data);
      app.page.reset(data);
    },
    refresh: function (data, callback) {
      app.log('page refresh', app.page.name, data);
    }
  }
};
<|endoftext|>


<commit_before>/**
 * Website - Source of http://peter.szocs.info
 * @version v1.0.0
 * @license Apache License 2.0
 */
var app=angular.module("app",["ngMessages","ui.router","firebase"]).constant("FIREBASE_URL","https://peter-szocs-info.firebaseio.com/");app.config(["$stateProvider","$urlRouterProvider","$locationProvider","$sceDelegateProvider",function(e,t,o,a){t.otherwise("/404.html"),e.state("home",{url:"/",views:{about:{controller:"MainCtrl",templateUrl:"partials/about.html"},portfolio:{controller:"GitHubCtrl",templateUrl:"partials/portfolio.html"},music:{controller:"MainCtrl",templateUrl:"partials/music.html"},contact:{controller:"MainCtrl",templateUrl:"partials/contact.html"}}}),o.html5Mode(!0),o.hashPrefix("!"),a.resourceUrlWhitelist(["self","https://www.youtube.com/**"])}]),app.controller("MainCtrl",["$scope","$http","$firebaseArray","FIREBASE_URL",function(e,t,o,a){var r=new Firebase(a+"/achievements");e.achievements=o(r);var n=new Firebase(a+"/songs");e.songs=o(n),e.sendEmail=function(o){t({method:"POST",url:"/mail/contact.php",data:$.param(o),headers:{"Content-Type":"application/x-www-form-urlencoded"}}).success(function(t){if(t.success)e.contactFormModalTitle="Success",e.contactFormModalBody="Your message has been sent.";else{var a=o.name;a.indexOf(" ")>=0&&(a=a.split(" ").slice(0,-1).join(" ")),e.contactFormModalTitle="Oops ...",e.contactFormModalBody="Sorry "+a+", it seems that my mail server is not responding.  Please try again later!"}e.contactForm.$setPristine(),e.contactForm.$setUntouched(),e.formData={},$("#contactFormModal").modal("show")})}}]),app.controller("GitHubCtrl",["$scope","$http","GitHubSvc",function(e,t,o){e.repos=[{name:"chat",description:"Short description of the repo",html_url:"https://github.com/gepesz/chat",homepage:"http://cairo.peterszocs.com",screenshot:"https://cloud.githubusercontent.com/assets/12737838/9482758/7ba4804a-4b65-11e5-81cf-ee29039efc39.png",body:"This is the detailed description of the repository.",date:"2015-08-15",licenseName:"Apache License 2.0",licenseUrl:"https://api.github.com/licenses/apache-2.0"}],e.showRepo=function(t){e.selectedRepo=t,$("#portfolioModal").modal("show")}}]),app.factory("GitHubSvc",["$q","$http",function(e,t){function o(o){var a=e.defer();return t.get(o).then(function(e){a.resolve(e.data)}),a.promise}function a(e){return o(l+"repos/"+c+"/"+e+"/releases")}function r(e){return o(l+"repos/"+c+"/"+e+"/license")}function n(e){return o(l+"repos/"+c+"/"+e)}function s(){return o(l+"users/"+c+"/repos")}function i(){var t=e.defer(),o=[];return s().then(function(e){e.map(function(e){e.homepage&&a(e.name).then(function(t){t.map(function(t){var a=t.body.indexOf("(https")+1,r=t.body.substring(a);a=r.indexOf(".png)")+4,r=r.substring(0,a),a=t.body.indexOf("\r\n")+2;var n=t.body.substring(a);o.push({name:e.name,description:e.description,html_url:e.html_url,homepage:e.homepage,screenshot:r,body:n,date:t.created_at.slice(0,10)})})}).then(r(e.name).then(function(e){o[o.length-1].licenseName=e.license.name,o[o.length-1].licenseUrl=e.license.url,t.resolve(o)}))})}),t.promise}var l="https://api.github.com/",c="gepesz";return{getRepoReleases:a,getRepoLicense:r,getRepo:n,getRepos:s,getReleases:i}}]),$(function(){$(".navbar-collapse ul li a").click(function(){$(".navbar-toggle:visible").click()}),$("a.page-scroll").bind("click",function(e){var t=$(this);$("html, body").stop().animate({scrollTop:$(t.attr("href")).offset().top},1e3,"easeInOutExpo"),e.preventDefault()})});var animatedHeader={didScroll:!1,changeHeaderOn:300,scrollPage:function(){$(window).scrollTop()>=this.changeHeaderOn?$(".navbar-default").addClass("navbar-shrink"):$(".navbar-default").removeClass("navbar-shrink"),this.didScroll=!1}};$(window).on("scroll",function(e){animatedHeader.didScroll||(animatedHeader.didScroll=!0,setTimeout(animatedHeader.scrollPage(),200))});var app=angular.module("app",["ngMessages","ui.router","firebase"]).constant("FIREBASE_URL","https://peter-szocs-info.firebaseio.com/");app.config(["$stateProvider","$urlRouterProvider","$locationProvider","$sceDelegateProvider",function(e,t,o,a){t.otherwise("/404.html"),e.state("home",{url:"/",views:{about:{controller:"MainCtrl",templateUrl:"partials/about.html"},portfolio:{controller:"GitHubCtrl",templateUrl:"partials/portfolio.html"},music:{controller:"MainCtrl",templateUrl:"partials/music.html"},contact:{controller:"MainCtrl",templateUrl:"partials/contact.html"}}}),o.html5Mode(!0),o.hashPrefix("!"),a.resourceUrlWhitelist(["self","https://www.youtube.com/**"])}]),app.controller("MainCtrl",["$scope","$http","$firebaseArray","FIREBASE_URL",function(e,t,o,a){var r=new Firebase(a+"/achievements");e.achievements=o(r);var n=new Firebase(a+"/songs");e.songs=o(n),e.sendEmail=function(o){t({method:"POST",url:"/mail/contact.php",data:$.param(o),headers:{"Content-Type":"application/x-www-form-urlencoded"}}).success(function(t){if(t.success)e.contactFormModalTitle="Success",e.contactFormModalBody="Your message has been sent.";else{var a=o.name;a.indexOf(" ")>=0&&(a=a.split(" ").slice(0,-1).join(" ")),e.contactFormModalTitle="Oops ...",e.contactFormModalBody="Sorry "+a+", it seems that my mail server is not responding.  Please try again later!"}e.contactForm.$setPristine(),e.contactForm.$setUntouched(),e.formData={},$("#contactFormModal").modal("show")})}}]),app.controller("GitHubCtrl",["$scope","$http","GitHubSvc",function(e,t,o){e.repos=[{name:"chat",description:"Short description of the repo",html_url:"https://github.com/gepesz/chat",homepage:"http://cairo.peterszocs.com",screenshot:"https://cloud.githubusercontent.com/assets/12737838/9482758/7ba4804a-4b65-11e5-81cf-ee29039efc39.png",body:"This is the detailed description of the repository.",date:"2015-08-15",licenseName:"Apache License 2.0",licenseUrl:"https://api.github.com/licenses/apache-2.0"}],e.showRepo=function(t){e.selectedRepo=t,$("#portfolioModal").modal("show")}}]),app.factory("GitHubSvc",["$q","$http",function(e,t){function o(o){var a=e.defer();return t.get(o).then(function(e){a.resolve(e.data)}),a.promise}function a(e){return o(l+"repos/"+c+"/"+e+"/releases")}function r(e){return o(l+"repos/"+c+"/"+e+"/license")}function n(e){return o(l+"repos/"+c+"/"+e)}function s(){return o(l+"users/"+c+"/repos")}function i(){var t=e.defer(),o=[];return s().then(function(e){e.map(function(e){e.homepage&&a(e.name).then(function(t){t.map(function(t){var a=t.body.indexOf("(https")+1,r=t.body.substring(a);a=r.indexOf(".png)")+4,r=r.substring(0,a),a=t.body.indexOf("\r\n")+2;var n=t.body.substring(a);o.push({name:e.name,description:e.description,html_url:e.html_url,homepage:e.homepage,screenshot:r,body:n,date:t.created_at.slice(0,10)})})}).then(r(e.name).then(function(e){o[o.length-1].licenseName=e.license.name,o[o.length-1].licenseUrl=e.license.url,t.resolve(o)}))})}),t.promise}var l="https://api.github.com/",c="gepesz";return{getRepoReleases:a,getRepoLicense:r,getRepo:n,getRepos:s,getReleases:i}}]),$(function(){$(".navbar-collapse ul li a").click(function(){$(".navbar-toggle:visible").click()}),$("a.page-scroll").bind("click",function(e){var t=$(this);$("html, body").stop().animate({scrollTop:$(t.attr("href")).offset().top},1e3,"easeInOutExpo"),e.preventDefault()})});var animatedHeader={didScroll:!1,changeHeaderOn:300,scrollPage:function(){$(window).scrollTop()>=this.changeHeaderOn?$(".navbar-default").addClass("navbar-shrink"):$(".navbar-default").removeClass("navbar-shrink"),this.didScroll=!1}};$(window).on("scroll",function(e){animatedHeader.didScroll||(animatedHeader.didScroll=!0,setTimeout(animatedHeader.scrollPage(),200))});var app=angular.module("app",["ngMessages","ui.router","firebase"]).constant("FIREBASE_URL","https://peter-szocs-info.firebaseio.com/");app.config(["$stateProvider","$urlRouterProvider","$locationProvider","$sceDelegateProvider",function(e,t,o,a){t.otherwise("/404.html"),e.state("home",{url:"/",views:{about:{controller:"MainCtrl",templateUrl:"partials/about.html"},portfolio:{controller:"GitHubCtrl",templateUrl:"partials/portfolio.html"},music:{controller:"MainCtrl",templateUrl:"partials/music.html"},contact:{controller:"MainCtrl",templateUrl:"partials/contact.html"}}}),o.html5Mode(!0),o.hashPrefix("!"),a.resourceUrlWhitelist(["self","https://www.youtube.com/**"])}]),app.controller("MainCtrl",["$scope","$http","$firebaseArray","FIREBASE_URL",function(e,t,o,a){var r=new Firebase(a+"/achievements");e.achievements=o(r);var n=new Firebase(a+"/songs");e.songs=o(n),e.sendEmail=function(o){t({method:"POST",url:"/mail/contact.php",data:$.param(o),headers:{"Content-Type":"application/x-www-form-urlencoded"}}).success(function(t){if(t.success)e.contactFormModalTitle="Success",e.contactFormModalBody="Your message has been sent.";else{var a=o.name;a.indexOf(" ")>=0&&(a=a.split(" ").slice(0,-1).join(" ")),e.contactFormModalTitle="Oops ...",e.contactFormModalBody="Sorry "+a+", it seems that my mail server is not responding.  Please try again later!"}e.contactForm.$setPristine(),e.contactForm.$setUntouched(),e.formData={},$("#contactFormModal").modal("show")})}}]),app.controller("GitHubCtrl",["$scope","$http","GitHubSvc",function(e,t,o){e.repos=[{name:"chat",description:"Short description of the repo",html_url:"https://github.com/gepesz/chat",homepage:"http://cairo.peterszocs.com",screenshot:"https://cloud.githubusercontent.com/assets/12737838/9482758/7ba4804a-4b65-11e5-81cf-ee29039efc39.png",body:"This is the detailed description of the repository.",date:"2015-08-15",licenseName:"Apache License 2.0",licenseUrl:"https://api.github.com/licenses/apache-2.0"}],e.showRepo=function(t){e.selectedRepo=t,$("#portfolioModal").modal("show")}}]),app.factory("GitHubSvc",["$q","$http",function(e,t){function o(o){var a=e.defer();return t.get(o).then(function(e){a.resolve(e.data)}),a.promise}function a(e){return o(l+"repos/"+c+"/"+e+"/releases")}function r(e){return o(l+"repos/"+c+"/"+e+"/license")}function n(e){return o(l+"repos/"+c+"/"+e)}function s(){return o(l+"users/"+c+"/repos")}function i(){var t=e.defer(),o=[];return s().then(function(e){e.map(function(e){e.homepage&&a(e.name).then(function(t){t.map(function(t){var a=t.body.indexOf("(https")+1,r=t.body.substring(a);a=r.indexOf(".png)")+4,r=r.substring(0,a),a=t.body.indexOf("\r\n")+2;var n=t.body.substring(a);o.push({name:e.name,description:e.description,html_url:e.html_url,homepage:e.homepage,screenshot:r,body:n,date:t.created_at.slice(0,10)})})}).then(r(e.name).then(function(e){o[o.length-1].licenseName=e.license.name,o[o.length-1].licenseUrl=e.license.url,t.resolve(o)}))})}),t.promise}var l="https://api.github.com/",c="gepesz";return{getRepoReleases:a,getRepoLicense:r,getRepo:n,getRepos:s,getReleases:i}}]),$(function(){$(".navbar-collapse ul li a").click(function(){$(".navbar-toggle:visible").click()}),$("a.page-scroll").bind("click",function(e){var t=$(this);$("html, body").stop().animate({scrollTop:$(t.attr("href")).offset().top},1e3,"easeInOutExpo"),e.preventDefault()})});var animatedHeader={didScroll:!1,changeHeaderOn:300,scrollPage:function(){$(window).scrollTop()>=this.changeHeaderOn?$(".navbar-default").addClass("navbar-shrink"):$(".navbar-default").removeClass("navbar-shrink"),this.didScroll=!1}};$(window).on("scroll",function(e){animatedHeader.didScroll||(animatedHeader.didScroll=!0,setTimeout(animatedHeader.scrollPage(),200))});<commit_msg>updated<commit_after>/**
 * Website - Source of http://peter.szocs.info
 * @version v1.0.0
 * @license Apache License 2.0
 */
var app=angular.module("app",["ngMessages","ui.router","firebase"]).constant("FIREBASE_URL","https://peter-szocs-info.firebaseio.com/");app.config(["$stateProvider","$urlRouterProvider","$locationProvider","$sceDelegateProvider",function(e,t,o,n){t.otherwise("/404.html"),e.state("home",{url:"/",views:{about:{controller:"MainCtrl",templateUrl:"partials/about.html"},portfolio:{controller:"GitHubCtrl",templateUrl:"partials/portfolio.html"},music:{controller:"MainCtrl",templateUrl:"partials/music.html"},contact:{controller:"MainCtrl",templateUrl:"partials/contact.html"}}}),o.html5Mode(!0),o.hashPrefix("!"),n.resourceUrlWhitelist(["self","https://www.youtube.com/**"])}]),app.controller("MainCtrl",["$scope","$http","$firebaseArray","FIREBASE_URL",function(e,t,o,n){var r=new Firebase(n+"/achievements");e.achievements=o(r);var a=new Firebase(n+"/songs");e.songs=o(a),e.sendEmail=function(o){t({method:"POST",url:"/mail/contact.php",data:$.param(o),headers:{"Content-Type":"application/x-www-form-urlencoded"}}).success(function(t){if(t.success)e.contactFormModalTitle="Success",e.contactFormModalBody="Your message has been sent.";else{var n=o.name;n.indexOf(" ")>=0&&(n=n.split(" ").slice(0,-1).join(" ")),e.contactFormModalTitle="Oops ...",e.contactFormModalBody="Sorry "+n+", it seems that my mail server is not responding.  Please try again later!"}e.contactForm.$setPristine(),e.contactForm.$setUntouched(),e.formData={},$("#contactFormModal").modal("show")})}}]),app.controller("GitHubCtrl",["$scope","$http","GitHubSvc",function(e,t,o){o.getReleases().then(function(t){e.repos=t}),e.showRepo=function(t){e.selectedRepo=t,$("#portfolioModal").modal("show")}}]),app.factory("GitHubSvc",["$q","$http",function(e,t){function o(o){var n=e.defer();return t.get(o).then(function(e){n.resolve(e.data)}),n.promise}function n(e){return o(l+"repos/"+c+"/"+e+"/releases")}function r(e){return o(l+"repos/"+c+"/"+e+"/license")}function a(e){return o(l+"repos/"+c+"/"+e)}function s(){return o(l+"users/"+c+"/repos")}function i(){var t=e.defer(),o=[];return s().then(function(e){e.map(function(e){e.homepage&&n(e.name).then(function(t){t.map(function(t){var n=t.body.indexOf("(https")+1,r=t.body.substring(n);n=r.indexOf(".png)")+4,r=r.substring(0,n),n=t.body.indexOf("\r\n")+2;var a=t.body.substring(n);o.push({name:e.name,description:e.description,html_url:e.html_url,homepage:e.homepage,screenshot:r,body:a,date:t.created_at.slice(0,10)})})}).then(r(e.name).then(function(e){o[o.length-1].licenseName=e.license.name,o[o.length-1].licenseUrl=e.license.url,t.resolve(o)}))})}),t.promise}var l="https://api.github.com/",c="gepesz";return{getRepoReleases:n,getRepoLicense:r,getRepo:a,getRepos:s,getReleases:i}}]),$(function(){$(".navbar-collapse ul li a").click(function(){$(".navbar-toggle:visible").click()}),$("a.page-scroll").bind("click",function(e){var t=$(this);$("html, body").stop().animate({scrollTop:$(t.attr("href")).offset().top},1e3,"easeInOutExpo"),e.preventDefault()})});var animatedHeader={didScroll:!1,changeHeaderOn:300,scrollPage:function(){$(window).scrollTop()>=this.changeHeaderOn?$(".navbar-default").addClass("navbar-shrink"):$(".navbar-default").removeClass("navbar-shrink"),this.didScroll=!1}};$(window).on("scroll",function(e){animatedHeader.didScroll||(animatedHeader.didScroll=!0,setTimeout(animatedHeader.scrollPage(),200))});<|endoftext|>


<commit_before>'use strict';

var request = require('supertest');
var should = require('should');

// TODO: It would be better to have something like the dependency injection pattern for testing the datastore
describe('DATABASE_ABSTRACTION', function ( ) {
    var env = require('../env')( );

    it('Should able to connect to the database', function (done) {
        require('../lib/storage')(env, function ( err ) {
            should(err).be.exactly(null);
            done();
        });
    });

    it('Should throw an error when connecting to the database with an invalid connection string', function (done) {
        (function() {
            return require('../lib/storage')(env, function (err) {
            }, {
                connectionUrl: 'this is invalid'
            });
        }).should.throw('URL must be in the format mongodb://user:pass@host:port/dbname');

        done();
    });
});

<commit_msg>Not really relevant.<commit_after><|endoftext|>


<commit_before>import { createNewTab, getCurrentTab, getExtensionURL, sendTabMessage } from "../../shared/library/extension.js";

const CONTEXT_SHARED_ALL = {
    contexts: ["all"]
};
const CONTEXT_SHARED_EDITABLE = {
    contexts: ["editable"]
};

let __menu;

export function updateContextMenu() {
    chrome.contextMenus.removeAll();
    __menu = chrome.contextMenus.create({
        title: "Buttercup",
        ...CONTEXT_SHARED_ALL
    });
    const unlockArchiveMenu = chrome.contextMenus.create({
        title: "Unlock archive",
        parentId: __menu,
        ...CONTEXT_SHARED_ALL
    });
    chrome.contextMenus.create({
        title: "Lock all archives",
        parentId: __menu,
        onclick: () => {
            createNewTab(getExtensionURL("setup.html#/lock-archives"));
        },
        ...CONTEXT_SHARED_ALL
    });
    chrome.contextMenus.create({
        parentId: __menu,
        type: "separator",
        ...CONTEXT_SHARED_ALL
    });
    // chrome.contextMenus.create({
    //     title: "Log in using",
    //     parentId: __menu,
    //     onclick: () => {
    //         // todo
    //     },
    //     enabled: false,
    //     ...CONTEXT_SHARED_ALL
    // });
    // chrome.contextMenus.create({
    //     title: "Enter login details",
    //     parentId: __menu,
    //     onclick: () => {
    //         // todo
    //     },
    //     enabled: false,
    //     ...CONTEXT_SHARED_ALL
    // });
    chrome.contextMenus.create({
        title: "Generate password",
        parentId: __menu,
        onclick: () => {
            getCurrentTab()
                .then(tab => tab.id)
                .then(tabID => {
                    sendTabMessage(tabID, {
                        type: "open-generator"
                    });
                });
        },
        ...CONTEXT_SHARED_EDITABLE
    });
}
<commit_msg>Add about context menu item<commit_after>import { createNewTab, getCurrentTab, getExtensionURL, sendTabMessage } from "../../shared/library/extension.js";

const CONTEXT_SHARED_ALL = {
    contexts: ["all"]
};
const CONTEXT_SHARED_EDITABLE = {
    contexts: ["editable"]
};

let __menu;

export function updateContextMenu() {
    chrome.contextMenus.removeAll();
    __menu = chrome.contextMenus.create({
        title: "Buttercup",
        ...CONTEXT_SHARED_ALL
    });
    chrome.contextMenus.create({
        title: "About",
        parentId: __menu,
        onclick: () => {
            createNewTab(getExtensionURL("setup.html#/about"));
        },
        ...CONTEXT_SHARED_ALL
    });
    // const unlockArchiveMenu = chrome.contextMenus.create({
    //     title: "Unlock archive",
    //     parentId: __menu,
    //     ...CONTEXT_SHARED_ALL
    // });
    // chrome.contextMenus.create({
    //     title: "Lock all archives",
    //     parentId: __menu,
    //     onclick: () => {
    //         createNewTab(getExtensionURL("setup.html#/lock-archives"));
    //     },
    //     ...CONTEXT_SHARED_ALL
    // });
    chrome.contextMenus.create({
        parentId: __menu,
        type: "separator",
        ...CONTEXT_SHARED_ALL
    });
    // chrome.contextMenus.create({
    //     title: "Log in using",
    //     parentId: __menu,
    //     onclick: () => {
    //         // todo
    //     },
    //     enabled: false,
    //     ...CONTEXT_SHARED_ALL
    // });
    // chrome.contextMenus.create({
    //     title: "Enter login details",
    //     parentId: __menu,
    //     onclick: () => {
    //         // todo
    //     },
    //     enabled: false,
    //     ...CONTEXT_SHARED_ALL
    // });
    chrome.contextMenus.create({
        title: "Generate password",
        parentId: __menu,
        onclick: () => {
            getCurrentTab()
                .then(tab => tab.id)
                .then(tabID => {
                    sendTabMessage(tabID, {
                        type: "open-generator"
                    });
                });
        },
        ...CONTEXT_SHARED_EDITABLE
    });
}
<|endoftext|>


<commit_before><commit_msg>Don't run audio context setup again if web audio isn't supported<commit_after><|endoftext|>


<commit_before>var app = app || {};

(function() {

	if (location.hash === '#tabletmode') {
		sessionStorage.tabletMode = 'true';
		location.hash = '/';
	}

	// this is the place the user codes
	var myCodeMirror;

	// this is a unique id assigned to the current page
	var pageInstanceUID;

	app.readyToRun = false;

	if (localStorage.uid) {
		app.uid = JSON.parse(localStorage.uid);
	} else {
		app.uid = Date.now().toString(36);
		localStorage.uid = JSON.stringify(app.uid);
	}

	app.initPage = function() {
		// get the hash key
		app.hash = app.getHashKey();

		// create code input area
		app.initCodeMirror();

		// calculate editor layout
		refreshEditorLayout();

		app.diffEngine = window.diffEngine();
		app.diffEncoder = app.diffEngine.getEncoder();
		app.diffDecoder = app.diffEngine.getDecoder();

		// run the code
		app.run();

		// ensure CodeMirror code gets properly rendered
		requestAnimationFrame(function(){
			myCodeMirror.refresh();
		});

		// we're assuming they won't visit the same page twice within one second
		pageInstanceUID = Math.floor(Date.now()/1000);
		app.fb = new Firebase('https://udacity.firebaseio.com/android-layout/users/' + app.uid + '/' + app.hash + '/' + pageInstanceUID);

	};

	app.getHashKey = function() {
		var hash = location.hash;
		if (hash.length > 2 && hash.substr(0,2) === '#/') {
			return hash.slice(2);
		} else {
			return '';
		}
	};

	app.initCodeMirror = function(){
		// clear pre-existing code areas
		$('.input-area').html('');

		myCodeMirror = CodeMirror(document.querySelector('.input-area'), {
			value: app.getCodeForHash(),
			mode: "android-xml",
			lineNumbers: true,
	        lineWrapping: true,
			indentUnit: 4,
			fixedGutter: true,
			viewportMargin: Infinity,
			onChange: function() {
				app.run({ autorun: true });
			}
		});
	};

	app.getCodeForHash = function() {
		// this is for testing code (#/test/...)
		if (app.hash.slice(0,4) === 'test') {
			$.get('tests/android/' + app.hash.slice(12) + '.xml', function(data){
				myCodeMirror.setValue(data);
				myCodeMirror.refresh();
				app.run({
					code: data,
					force: true
				});
			}, 'text');
			$('.test-reference-image').attr('src', 'tests/android/' + app.hash.slice(12) + '.png');
			return '';
		}

		// we have a previously-saved version
		if (localStorage['code-' + app.hash]) {
			return JSON.parse( localStorage['code-' + app.hash] );
		}

		// return the default (if there is one)
		else {
			return app.getCodeForHashDefault();
		}

		return '';
	};

	app.getCodeForHashDefault = function() {
		if (app.androidCodeDefaults) {
			if (app.androidCodeDefaults[ app.hash ]) {
				return app.androidCodeDefaults[ app.hash ];
			} else {
				return app.androidCodeDefaults[ 'default' ];
			}
		}

		return '';
	};

	app.resetCodeToHashDefault = function() {
		myCodeMirror.setValue(app.getCodeForHashDefault());
		myCodeMirror.refresh();
	};

	// this runs after code is successfully evaluated
	function runSuccess(code) {
		if (!localStorage.debug) {
			clearTimeout(app.codeEvaluationTimeout);
		}

		// save current student code
		if (app.hash.slice(0,4) !== 'test') {
			localStorage['code-' + app.hash] = JSON.stringify(code);
		}

		$('html').removeClass('invalid-code evaluating-invalid-code');
		requestAnimationFrame(function(){
			$('html').addClass('valid-code');
		});

		$('.code-saved-msg').removeClass('code-not-saved');

	}

	// this runs if the code is considered invalid or unevaluatable
	function runFail (opt) {
		var code = opt.code;
		clearTimeout(app.codeEvaluationTimeout);
		$('html').removeClass('invalid-code').addClass('evaluating-invalid-code');

		app.codeEvaluationTimeout = setTimeout(function(){
			console.log('TIMEOUT');
	 		$('html').removeClass('evaluating-invalid-code').addClass('invalid-code');
		},2000);

		if (opt.errors) {
			opt.errors.forEach(function(errorID){
				// add any errors to the error stack
				app.errors.push({
					id: errorID
				});
			});
		}

		if (!localStorage.debug) {
			$('.code-saved-msg').addClass('code-not-saved');
		} else {
			console.log('failed, but saving anyway since we\'re in debug mode');
			runSuccess(code);
		}
	}

	function updateState (newState) {
		var state = app.state || {};

		// copy over any new parameters from the previous state
		for(key in newState) {
			state[key] = newState[key];
		}

		var diff = app.diffEncoder.push(state);
		app.state = state;
		// console.log(app.diffDecoder.getState().state);
		// console.log('pushing', diff);
		app.fb.child('diffs').push(diff);
	}

	// this function evaluates code based on the mode the app is in
	app.run = function (opt) {
		opt = opt || {};

		if (!app.readyToRun && !opt.force) return false;

		var codeRaw = opt.code || myCodeMirror.getValue();
		var code;
		var elemToRender;

		updateState({
			code: codeRaw
		});

		// run the code
		var mode = 'android-layout';
		if (mode === 'android-layout') {

			if (app.hash.slice(0,4) === 'test') {
				$('html').addClass('testing-mode');
				if (app.hash === 'test/android' || app.hash === 'test/android/') {
					forwardFillTestingHistory('#/test/android/', app.tests);
				}
			} else {
				$('html').removeClass('testing-mode');
			}

			// pre-processing hook
			code = app.androidLayout.prepareCodeForParsing( codeRaw );

			// catch easy-to-detect errors (like misaligned <>'s, quotes)
			app.androidLayout.xmlSanityCheck( codeRaw );

			// if we don't have code to render, exit early rather than throwing an error
			if (codeRaw === '') {
				return false;
			}

			// parse the XML
			try {
				app.parsedXML = jQuery.parseXML( code );
			} catch (e) {
				app.parsedXML = null;
			}

			if (app.parsedXML !== null) {
				// basic parsing and styling
				elemToRender = app.androidLayout.evaluateXML(app.parsedXML);

				// calculate all the layouts
				console.log('%c-------- layout pass at ' + Math.round(Date.now()/1000) + ' --------', 'color: #666');
				app.androidLayout.evaluateXMLPass2( app.parsedXML );
				if (app.errors().length > 0) {
					runFail({
						code: codeRaw
					});
				} else {
					runSuccess(codeRaw);
				}
			} else {

				runFail({
					code: codeRaw,
					errors: ['parseError']
				});

				$('html').removeClass('valid-code invalid-code')

			}
		}

		if (elemToRender) {
			$('.screen').html('').append(elemToRender);
		}

		renderErrors();

		renderHistoryLinkState();
		refreshEditorLayout();
		console.log('%c-------- end --------', 'color: #666');
	};

	function forwardFillTestingHistory (prefix, urls, startAtBeginning) {

		// add each test to the history
		urls.forEach(function(url){
			history.pushState({}, '', prefix + url);
		});

		// go to the first one
		if (startAtBeginning) {
			history.go((app.tests.length-1) * -1);
		}
	}

	// show the error list in the document
	function renderErrors () {
		var errors = app.errors();
		var errorStrArr = errors.map(function(error){ return error.value; });
		if (errors.length > 0) {
			$('.error-msg').show().html(errorStrArr.join('
'));
			errors.forEach(function(error){
				if (error.line) {
					$('.CodeMirror-lines > div > div:last-child > pre:nth-child('+error.line+')').addClass('highlighted-code');
				}
			});
		} else {
			$('.error-msg').hide();
			$('.highlighted-code').removeClass('highlighted-code');
			console.log('%c No errors!', 'color: #393');
		}
	}

	// undo/redo history state UI
	function renderHistoryLinkState () {
		// console.debug(myCodeMirror.historySize());
		if (myCodeMirror.historySize().undo > 0) {
			$('.btn-undo').attr('disabled', false);
		} else {
			$('.btn-undo').attr('disabled', true);
		}
		if (myCodeMirror.historySize().redo > 0) {
			$('.btn-redo').attr('disabled', false);
		} else {
			$('.btn-redo').attr('disabled', true);
		}
	}

	// recalculate and resize the editor to the proper height
	function refreshEditorLayout () {
		var currentHeight = $('.CodeMirror').height();
		var containerHeight = $('.input-area-wrapper').outerHeight(true);
		var windowHeight = $(window).height();
		var wiggleRoom = 10;

		$('.CodeMirror-scroll').css('height', windowHeight - (containerHeight - currentHeight) - wiggleRoom);
		myCodeMirror.refresh();
	}

	$(window).bind('hashchange', function(e) {
		app.initPage();
	});

	// recalculate editor layout on resize
	$(window).resize(function(){
		refreshEditorLayout();
	});

	// auto-run on code mutation
	$('.code-input-area').on('input', function(){
	  app.run({ autorun: true });
	}, false);

	// manually run on Cmd-Enter / Ctrl-Enter
	$(document).on('keydown', '.code-input-area', function(e) {
	  if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
	    app.run();
	  }
	});

	// manually run when run btn is clicked
	$('.btn-run').on('click', function(){
	  app.run();
	}, false);

	// toggle checkbox states
	$('#toggle-element-outline').change(function(e){
		app.elementOutlinesEnabled = e.target.checked;
		app.run();
	});

	// reset code button
	$('.btn-reset-code').click(function(e) {
		if (!confirm('Press OK to reset your code to the default for this example.\n\nNote: This will overwrite your current code, but pressing Cmd/Ctrl Z will undo this change.')) {
			return false;
		}
		app.resetCodeToHashDefault();
	});

	// undo/redo
	$('.btn-undo').click(function(e) {
		myCodeMirror.undo();
		renderHistoryLinkState();
	});

	$('.btn-redo').click(function(e) {
		myCodeMirror.redo();
		renderHistoryLinkState();
	});

	// hooks for debugging
	if (localStorage.debug) {
		window.myCodeMirror = myCodeMirror;
	}

	// hooks for tablet mode
	if (sessionStorage.tabletMode === 'true') {
		$('#input-topbar').hide().parent().css('padding-top', '12px');
		$('.input-area').css('font-size', '120%');
		$('html').addClass('tablet-mode');
	}

	$('.input-area').mousemove(function(e){ updateMousePosition(e) });

	// report-an-issue modal event listener
	$('#issue-dialog').on('shown.bs.modal', function(e){
		// grab the code from our codeMirror instance
		$('#entry_440939498').val( myCodeMirror.getValue() );

		// grab the user's uid and path
		$('#entry_1934743275').val( JSON.parse(localStorage.uid) + '/' + app.hash + '/' + pageInstanceUID );
	});

	$('#hidden_iframe').on('load', function(e){
		if (submitted) {
			$('#issue-dialog').modal('hide');
			$('#issue-submitted-dialog').modal('show');

			// clear everything
			$('#issue-dialog textarea').val('');
			$('#entry_1934743275').val('');
			$('#issue-dialog [type=radio]').prop('checked', false);

			// grab the user's uid and path
			$('#entry_1934743275').val( JSON.parse(localStorage.uid) + '/' + app.hash + '/' + pageInstanceUID );
			submitted = false;
		}
	});

	var timeOfLastUpdate;
	var updateDebounceThreshold = 200;
	var lastDebouncedState = null;
	var finalStateUpdateTimeout;

	var updateMousePosition = function(e) {
		var mouse = [e.offsetX, e.offsetY];
		var state = lastDebouncedState || {};

		// I'm setting a floor of threshold/4 to give the actual state update
		// a chance to happen. Otherwise, it'd updateDebouncedState exactly on
		// time, not giving normal state updates a chance to happen (and therefore
		// resulting in stale data).
		var timeToUpdateWithFinalState = Math.max(updateDebounceThreshold / 4, updateDebounceThreshold - (Date.now() - timeOfLastUpdate));

		state.mouse = mouse;

		clearTimeout(finalStateUpdateTimeout);

		if (timeOfLastUpdate && (Date.now() - timeOfLastUpdate < updateDebounceThreshold)) {
			lastDebouncedState = state;
			finalStateUpdateTimeout = setTimeout(updateDebouncedState, timeToUpdateWithFinalState);
			return false;
		}

		timeOfLastUpdate = Date.now();
		lastDebouncedState = null;
		updateState(state);
	};

	function updateDebouncedState () {
		timeOfLastUpdate = Date.now();
		updateState(lastDebouncedState);
	}

	app.androidInit();

	app.initPage();

})();

<commit_msg>add redirect for visitors to gh-pages-hosted path<commit_after>var app = app || {};

(function() {

  // users who visit udacity's github pages should be redirected to the official path
  if (location.host === 'udacity.github.io') {
    location.href = 'http://labs.udacity.com/android-visualizer/' + location.hash;
  }

	if (location.hash === '#tabletmode') {
		sessionStorage.tabletMode = 'true';
		location.hash = '/';
	}

	// this is the place the user codes
	var myCodeMirror;

	// this is a unique id assigned to the current page
	var pageInstanceUID;

	app.readyToRun = false;

	if (localStorage.uid) {
		app.uid = JSON.parse(localStorage.uid);
	} else {
		app.uid = Date.now().toString(36);
		localStorage.uid = JSON.stringify(app.uid);
	}

	app.initPage = function() {
		// get the hash key
		app.hash = app.getHashKey();

		// create code input area
		app.initCodeMirror();

		// calculate editor layout
		refreshEditorLayout();

		app.diffEngine = window.diffEngine();
		app.diffEncoder = app.diffEngine.getEncoder();
		app.diffDecoder = app.diffEngine.getDecoder();

		// run the code
		app.run();

		// ensure CodeMirror code gets properly rendered
		requestAnimationFrame(function(){
			myCodeMirror.refresh();
		});

		// we're assuming they won't visit the same page twice within one second
		pageInstanceUID = Math.floor(Date.now()/1000);
		app.fb = new Firebase('https://udacity.firebaseio.com/android-layout/users/' + app.uid + '/' + app.hash + '/' + pageInstanceUID);

	};

	app.getHashKey = function() {
		var hash = location.hash;
		if (hash.length > 2 && hash.substr(0,2) === '#/') {
			return hash.slice(2);
		} else {
			return '';
		}
	};

	app.initCodeMirror = function(){
		// clear pre-existing code areas
		$('.input-area').html('');

		myCodeMirror = CodeMirror(document.querySelector('.input-area'), {
			value: app.getCodeForHash(),
			mode: "android-xml",
			lineNumbers: true,
	        lineWrapping: true,
			indentUnit: 4,
			fixedGutter: true,
			viewportMargin: Infinity,
			onChange: function() {
				app.run({ autorun: true });
			}
		});
	};

	app.getCodeForHash = function() {
		// this is for testing code (#/test/...)
		if (app.hash.slice(0,4) === 'test') {
			$.get('tests/android/' + app.hash.slice(12) + '.xml', function(data){
				myCodeMirror.setValue(data);
				myCodeMirror.refresh();
				app.run({
					code: data,
					force: true
				});
			}, 'text');
			$('.test-reference-image').attr('src', 'tests/android/' + app.hash.slice(12) + '.png');
			return '';
		}

		// we have a previously-saved version
		if (localStorage['code-' + app.hash]) {
			return JSON.parse( localStorage['code-' + app.hash] );
		}

		// return the default (if there is one)
		else {
			return app.getCodeForHashDefault();
		}

		return '';
	};

	app.getCodeForHashDefault = function() {
		if (app.androidCodeDefaults) {
			if (app.androidCodeDefaults[ app.hash ]) {
				return app.androidCodeDefaults[ app.hash ];
			} else {
				return app.androidCodeDefaults[ 'default' ];
			}
		}

		return '';
	};

	app.resetCodeToHashDefault = function() {
		myCodeMirror.setValue(app.getCodeForHashDefault());
		myCodeMirror.refresh();
	};

	// this runs after code is successfully evaluated
	function runSuccess(code) {
		if (!localStorage.debug) {
			clearTimeout(app.codeEvaluationTimeout);
		}

		// save current student code
		if (app.hash.slice(0,4) !== 'test') {
			localStorage['code-' + app.hash] = JSON.stringify(code);
		}

		$('html').removeClass('invalid-code evaluating-invalid-code');
		requestAnimationFrame(function(){
			$('html').addClass('valid-code');
		});

		$('.code-saved-msg').removeClass('code-not-saved');

	}

	// this runs if the code is considered invalid or unevaluatable
	function runFail (opt) {
		var code = opt.code;
		clearTimeout(app.codeEvaluationTimeout);
		$('html').removeClass('invalid-code').addClass('evaluating-invalid-code');

		app.codeEvaluationTimeout = setTimeout(function(){
			console.log('TIMEOUT');
	 		$('html').removeClass('evaluating-invalid-code').addClass('invalid-code');
		},2000);

		if (opt.errors) {
			opt.errors.forEach(function(errorID){
				// add any errors to the error stack
				app.errors.push({
					id: errorID
				});
			});
		}

		if (!localStorage.debug) {
			$('.code-saved-msg').addClass('code-not-saved');
		} else {
			console.log('failed, but saving anyway since we\'re in debug mode');
			runSuccess(code);
		}
	}

	function updateState (newState) {
		var state = app.state || {};

		// copy over any new parameters from the previous state
		for(key in newState) {
			state[key] = newState[key];
		}

		var diff = app.diffEncoder.push(state);
		app.state = state;
		// console.log(app.diffDecoder.getState().state);
		// console.log('pushing', diff);
		app.fb.child('diffs').push(diff);
	}

	// this function evaluates code based on the mode the app is in
	app.run = function (opt) {
		opt = opt || {};

		if (!app.readyToRun && !opt.force) return false;

		var codeRaw = opt.code || myCodeMirror.getValue();
		var code;
		var elemToRender;

		updateState({
			code: codeRaw
		});

		// run the code
		var mode = 'android-layout';
		if (mode === 'android-layout') {

			if (app.hash.slice(0,4) === 'test') {
				$('html').addClass('testing-mode');
				if (app.hash === 'test/android' || app.hash === 'test/android/') {
					forwardFillTestingHistory('#/test/android/', app.tests);
				}
			} else {
				$('html').removeClass('testing-mode');
			}

			// pre-processing hook
			code = app.androidLayout.prepareCodeForParsing( codeRaw );

			// catch easy-to-detect errors (like misaligned <>'s, quotes)
			app.androidLayout.xmlSanityCheck( codeRaw );

			// if we don't have code to render, exit early rather than throwing an error
			if (codeRaw === '') {
				return false;
			}

			// parse the XML
			try {
				app.parsedXML = jQuery.parseXML( code );
			} catch (e) {
				app.parsedXML = null;
			}

			if (app.parsedXML !== null) {
				// basic parsing and styling
				elemToRender = app.androidLayout.evaluateXML(app.parsedXML);

				// calculate all the layouts
				console.log('%c-------- layout pass at ' + Math.round(Date.now()/1000) + ' --------', 'color: #666');
				app.androidLayout.evaluateXMLPass2( app.parsedXML );
				if (app.errors().length > 0) {
					runFail({
						code: codeRaw
					});
				} else {
					runSuccess(codeRaw);
				}
			} else {

				runFail({
					code: codeRaw,
					errors: ['parseError']
				});

				$('html').removeClass('valid-code invalid-code')

			}
		}

		if (elemToRender) {
			$('.screen').html('').append(elemToRender);
		}

		renderErrors();

		renderHistoryLinkState();
		refreshEditorLayout();
		console.log('%c-------- end --------', 'color: #666');
	};

	function forwardFillTestingHistory (prefix, urls, startAtBeginning) {

		// add each test to the history
		urls.forEach(function(url){
			history.pushState({}, '', prefix + url);
		});

		// go to the first one
		if (startAtBeginning) {
			history.go((app.tests.length-1) * -1);
		}
	}

	// show the error list in the document
	function renderErrors () {
		var errors = app.errors();
		var errorStrArr = errors.map(function(error){ return error.value; });
		if (errors.length > 0) {
			$('.error-msg').show().html(errorStrArr.join('
'));
			errors.forEach(function(error){
				if (error.line) {
					$('.CodeMirror-lines > div > div:last-child > pre:nth-child('+error.line+')').addClass('highlighted-code');
				}
			});
		} else {
			$('.error-msg').hide();
			$('.highlighted-code').removeClass('highlighted-code');
			console.log('%c No errors!', 'color: #393');
		}
	}

	// undo/redo history state UI
	function renderHistoryLinkState () {
		// console.debug(myCodeMirror.historySize());
		if (myCodeMirror.historySize().undo > 0) {
			$('.btn-undo').attr('disabled', false);
		} else {
			$('.btn-undo').attr('disabled', true);
		}
		if (myCodeMirror.historySize().redo > 0) {
			$('.btn-redo').attr('disabled', false);
		} else {
			$('.btn-redo').attr('disabled', true);
		}
	}

	// recalculate and resize the editor to the proper height
	function refreshEditorLayout () {
		var currentHeight = $('.CodeMirror').height();
		var containerHeight = $('.input-area-wrapper').outerHeight(true);
		var windowHeight = $(window).height();
		var wiggleRoom = 10;

		$('.CodeMirror-scroll').css('height', windowHeight - (containerHeight - currentHeight) - wiggleRoom);
		myCodeMirror.refresh();
	}

	$(window).bind('hashchange', function(e) {
		app.initPage();
	});

	// recalculate editor layout on resize
	$(window).resize(function(){
		refreshEditorLayout();
	});

	// auto-run on code mutation
	$('.code-input-area').on('input', function(){
	  app.run({ autorun: true });
	}, false);

	// manually run on Cmd-Enter / Ctrl-Enter
	$(document).on('keydown', '.code-input-area', function(e) {
	  if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
	    app.run();
	  }
	});

	// manually run when run btn is clicked
	$('.btn-run').on('click', function(){
	  app.run();
	}, false);

	// toggle checkbox states
	$('#toggle-element-outline').change(function(e){
		app.elementOutlinesEnabled = e.target.checked;
		app.run();
	});

	// reset code button
	$('.btn-reset-code').click(function(e) {
		if (!confirm('Press OK to reset your code to the default for this example.\n\nNote: This will overwrite your current code, but pressing Cmd/Ctrl Z will undo this change.')) {
			return false;
		}
		app.resetCodeToHashDefault();
	});

	// undo/redo
	$('.btn-undo').click(function(e) {
		myCodeMirror.undo();
		renderHistoryLinkState();
	});

	$('.btn-redo').click(function(e) {
		myCodeMirror.redo();
		renderHistoryLinkState();
	});

	// hooks for debugging
	if (localStorage.debug) {
		window.myCodeMirror = myCodeMirror;
	}

	// hooks for tablet mode
	if (sessionStorage.tabletMode === 'true') {
		$('#input-topbar').hide().parent().css('padding-top', '12px');
		$('.input-area').css('font-size', '120%');
		$('html').addClass('tablet-mode');
	}

	$('.input-area').mousemove(function(e){ updateMousePosition(e) });

	// report-an-issue modal event listener
	$('#issue-dialog').on('shown.bs.modal', function(e){
		// grab the code from our codeMirror instance
		$('#entry_440939498').val( myCodeMirror.getValue() );

		// grab the user's uid and path
		$('#entry_1934743275').val( JSON.parse(localStorage.uid) + '/' + app.hash + '/' + pageInstanceUID );
	});

	$('#hidden_iframe').on('load', function(e){
		if (submitted) {
			$('#issue-dialog').modal('hide');
			$('#issue-submitted-dialog').modal('show');

			// clear everything
			$('#issue-dialog textarea').val('');
			$('#entry_1934743275').val('');
			$('#issue-dialog [type=radio]').prop('checked', false);

			// grab the user's uid and path
			$('#entry_1934743275').val( JSON.parse(localStorage.uid) + '/' + app.hash + '/' + pageInstanceUID );
			submitted = false;
		}
	});

	var timeOfLastUpdate;
	var updateDebounceThreshold = 200;
	var lastDebouncedState = null;
	var finalStateUpdateTimeout;

	var updateMousePosition = function(e) {
		var mouse = [e.offsetX, e.offsetY];
		var state = lastDebouncedState || {};

		// I'm setting a floor of threshold/4 to give the actual state update
		// a chance to happen. Otherwise, it'd updateDebouncedState exactly on
		// time, not giving normal state updates a chance to happen (and therefore
		// resulting in stale data).
		var timeToUpdateWithFinalState = Math.max(updateDebounceThreshold / 4, updateDebounceThreshold - (Date.now() - timeOfLastUpdate));

		state.mouse = mouse;

		clearTimeout(finalStateUpdateTimeout);

		if (timeOfLastUpdate && (Date.now() - timeOfLastUpdate < updateDebounceThreshold)) {
			lastDebouncedState = state;
			finalStateUpdateTimeout = setTimeout(updateDebouncedState, timeToUpdateWithFinalState);
			return false;
		}

		timeOfLastUpdate = Date.now();
		lastDebouncedState = null;
		updateState(state);
	};

	function updateDebouncedState () {
		timeOfLastUpdate = Date.now();
		updateState(lastDebouncedState);
	}

	app.androidInit();

	app.initPage();

})();

<|endoftext|>


<commit_before><commit_msg>Fixing tests on OSX<commit_after><|endoftext|>


<commit_before>$(document).foundation();

function getTriad(color) {
  $.ajax({
    url: "http://www.google.com",
    cache: false,
    success: function(html) {
      alert(html);
    },
    error: function(err) {
      console.log(err);
      alert("faff err" + err);
    }
  });
}

function forResponse(url, callback) {
  $.ajax({
    url: url,
    cache: false,
    success: callback,
    error: function(err) {
      console.log(err);
    }
  });
}
function endpointForResponse(url, callback) {
  forResponse("http://pizzazz.xyz/api/" + url, callback);
}

//getTriad();

function setColorIndex(stringHex, index) {
  $("#color-" + index + "-block").css('background-color', stringHex);
  $("#color-" + index + "-text").text(stringHex);
};

//helper functions to set the colors
function setColorOne(stringHex) {
  setColorIndex(stringHex, "one")
};

function setColorTwo(stringHex) {
  setColorIndex(stringHex, "two")
};

function setColorThree(stringHex) {
  setColorIndex(stringHex, "three")
};

function setColorScheme(arrayScheme) {
  setColorOne(arrayScheme[0]);
  setColorTwo(arrayScheme[1]);
  setColorThree(arrayScheme[2]);
}

var hexCombinations = [
  ["#f48b52", "#b1dfd5", "#f5f6fa"],
  ["#f4858e", "#bfe2ca", "#a6daef"],
  ["#676c7f", "#ca8799", "#e1d5bf"]
];
var hexIndex = 0;
var loopHandle;

//test loop to cycle through colors
var funcLoop = function() {
  setColorScheme(hexCombinations[hexIndex++ % hexCombinations.length]);
  loopHandle = setTimeout(funcLoop, 3500);
}
funcLoop();

function noHex(string) {
  return string.substring(1, string.length);
}

var theColor = "#ff69b4";

function setComplementary() {
  $(".color-complementary-a").css('background-color', theColor);
  endpointForResponse("complementary?color=" + noHex(theColor), function(json) {
    $(".color-complementary-b").css('background-color', json.result.toString());
  });
}

function setAnalogous() {
  $(".color-analogous-a").css('background-color', theColor);
  endpointForResponse("analogous?color=" + noHex(theColor), function(json) {
    $(".color-analogous-b").css('background-color', json.result[1].toString());
    $(".color-analogous-c").css('background-color', json.result[2].toString());
    $(".color-analogous-d").css('background-color', json.result[3].toString());
    $(".color-analogous-e").css('background-color', json.result[4].toString());
    $(".color-analogous-f").css('background-color', json.result[5].toString());
  });
}

function setTriad() {
  $(".color-triad-a").css('background-color', theColor);
  endpointForResponse("split?color=" + noHex(theColor), function(json) {
    $(".color-triad-b").css('background-color', json.result[1].toString());
    $(".color-triad-c").css('background-color', json.result[2].toString());
  });
}

setComplementary();
setAnalogous();
setTriad();
<commit_msg>break anlogous into 2 row<commit_after>$(document).foundation();

function getTriad(color) {
  $.ajax({
    url: "http://www.google.com",
    cache: false,
    success: function(html) {
      alert(html);
    },
    error: function(err) {
      console.log(err);
      alert("faff err" + err);
    }
  });
}

function forResponse(url, callback) {
  $.ajax({
    url: url,
    cache: false,
    success: callback,
    error: function(err) {
      console.log(err);
    }
  });
}
function endpointForResponse(url, callback) {
  forResponse("http://pizzazz.xyz/api/" + url, callback);
}

//getTriad();

function setColorIndex(stringHex, index) {
  $("#color-" + index + "-block").css('background-color', stringHex);
  $("#color-" + index + "-text").text(stringHex);
};

//helper functions to set the colors
function setColorOne(stringHex) {
  setColorIndex(stringHex, "one")
};

function setColorTwo(stringHex) {
  setColorIndex(stringHex, "two")
};

function setColorThree(stringHex) {
  setColorIndex(stringHex, "three")
};

function setColorScheme(arrayScheme) {
  setColorOne(arrayScheme[0]);
  setColorTwo(arrayScheme[1]);
  setColorThree(arrayScheme[2]);
}

var hexCombinations = [
  ["#f48b52", "#b1dfd5", "#f5f6fa"],
  ["#f4858e", "#bfe2ca", "#a6daef"],
  ["#676c7f", "#ca8799", "#e1d5bf"]
];
var hexIndex = 0;
var loopHandle;

//test loop to cycle through colors
var funcLoop = function() {
  setColorScheme(hexCombinations[hexIndex++ % hexCombinations.length]);
  loopHandle = setTimeout(funcLoop, 3500);
}
funcLoop();

function noHex(string) {
  return string.substring(1, string.length);
}

var theColor = "#ff69b4";

function setComplementary() {
  $(".color-complementary-a").css('background-color', theColor);
  endpointForResponse("complementary?color=" + noHex(theColor), function(json) {
    $(".color-complementary-b").css('background-color', json.result.toString());
  });
}

function setAnalogous() {
  $(".color-analogous-a").css('background-color', theColor);
  endpointForResponse("analogous?color=" + noHex(theColor), function(json) {
    $(".color-analogous-b").css('background-color', json.result[1].toString());
    $(".color-analogous-c").css('background-color', json.result[2].toString());
    $(".color-analogous-d").css('background-color', json.result[3].toString());
    $(".color-analogous-e").css('background-color', json.result[4].toString());
    $(".color-analogous-f").css('background-color', json.result[5].toString());
  });
}

function setTriad() {
  $(".color-triad-a").css('background-color', theColor);
  endpointForResponse("triad?color=" + noHex(theColor), function(json) {
    $(".color-triad-b").css('background-color', json.result[1].toString());
    $(".color-triad-c").css('background-color', json.result[2].toString());
  });
}

setComplementary();
setAnalogous();
setTriad();
<|endoftext|>


<commit_before>var app = app || {};

/*
Functionality related to the app overall, mainly event listeners,
rendering new pages, making a search, and cookies
*/

// number of the hidden logo that will be displayed on rotation
var HIDDEN_LOGO_NUMBER;
// number of the logo that is currently displayed
var LOGO_NUMBER;

// select the logo url and render the correct page
function init() {

    // allow Handlebars templates to be used as partials
    Handlebars.partials = Templates;

    // initialize queryText cookie if not already present
    if (!Cookies.get("queryText")) {
        Cookies.set("queryText", "{}");
    }

    // initialize with google logo
    LOGO_NUMBER = 1;

    // set hidden logo number to different random logo number
    HIDDEN_LOGO_NUMBER = LOGO_NUMBER;
    while (HIDDEN_LOGO_NUMBER == LOGO_NUMBER) {
        HIDDEN_LOGO_NUMBER = Math.floor(Math.random() * 6) + 1
    }

    $(document).ready(function() {
        resolveLocation();
    });
}

// set all of the event listeners that are needed
function setListeners() {
    // whenever the url anchor changes, render the correct page
    $(window).off("hashchange");
    $(window).on("hashchange", function() {
        resolveLocation();
    });
    // rotate the logo whenever the user clicks on the logo
    $("#lucky-search-btn").off("click");
    $("#lucky-search-btn").click(function() {
        app.home.rotateLogo();
    });
    // rotate the "I'm Feeling Jimmy" text when the user hovers over the button
    $("#lucky-search-btn").off("mouseenter");
    $("#lucky-search-btn").mouseenter(function() {
        app.home.rotateFeelingJimmy();
    });
    // perform a search on the main page when the "Jimmy Search" button is clicked
    $("#main-search-btn").off("click");
    $("#main-search-btn").click(function() {
        makeSearch();
    });
    // perform a search when the magnifying glass is clicked on the search results page
    $("#search-button").off("click");
    $("#search-button").click(function() {
        makeSearch();
    });

    // perform various actions after pressing "enter" depending on which element is focused
    $(document).off("keyup");
    $(document).keyup(function(e) {
        // ignore keys presses that aren't "enter"
        if (e.which != 13) {
            return;
        }
        if ($(".search-box-input").is(":focus")) {
            // search box on main page or search results page
            makeSearch();
        } else if ($(".answer-input").is(":focus")) {
            // answer text box in admin interface
            app.admin.answerQuestion($(":focus").data("question-id"));
        } else if ($("#username-input").is(":focus") || $("#password-input").is(":focus")) {
            // login username or password text box
            var username = $("#username-input").val().trim();
            var password = $("#password-input").val();
            app.admin.login(username, password);
        }
    });
    // add box shadow to search box when the user focuses on the search input
    $(".search-box-input").off("focus");
    $(".search-box-input").focus(function() {
        app.home.changeSearchBoxShadow(true);
    });
    // remove box shadow from search box when the search input loses focus
    $(".search-box-input").off("blur");
    $(".search-box-input").blur(function() {
        app.home.changeSearchBoxShadow(false);
    });
    // try to login as admin when "LOGIN" button clicked
    $("#admin-login-btn").off("click");
    $("#admin-login-btn").click(function() {
        var username = $("#username-input").val().trim();
        var password = $("#password-input").val();
        app.admin.login(username, password);
    });
    // remove "auth" cookie and send user to admin login when "LOGOUT" button clicked
    $("#admin-logout-btn").off("click");
    $("#admin-logout-btn").click(function() {
        app.admin.logout();
    });
    // get queue of questions from server when "GET QUESTIONS" button clicked
    $("#admin-get-questions").off("click");
    $("#admin-get-questions").click(function() {
        app.admin.getQuestions();
    });
    // add an input field for a URL on an answer card when clicking "+ Add a link"
    $(".admin-add-link").off("click");
    $(".admin-add-link").click(function(event) {
        // create a new div to serve as the container for the new input field
        var newInputContainer = $(document.createElement("div"));
        // add new input container to list of answer links
        $(event.target).parent().find(".answer-links").append(newInputContainer);
        // insert input text field into new input container
        insertTemplate("answerLink", newInputContainer, {"key": $(event.target).data("question-id")});
    });
    // send answer for question to server when "RESPOND" clicked on question card
    $(".answer-btn").off("click");
    $(".answer-btn").click(function(event) {
        app.admin.answerQuestion($(event.target).data("question-id"));
    });
    // hide/show app drawer on click of app drawer icon
    $("#app-drawer-toggle").off("click");
    $("#app-drawer-toggle").click(function() {
        var appDrawerContainer = $("#app-drawer-container");
        if (!appDrawerContainer.is(":visible")) {
            appDrawerContainer.show();
        } else {
            appDrawerContainer.hide();
        }
    });
    $("#notification-icon").off("click");
    $("#notification-icon").click(function() {
        var audio = new Audio("/sounds/bell.mp3");
        audio.play();
    });
    // click events for the entire document
    $(document).off("click");
    $(document).click(function(event) {
        // hide the app drawer if anything outside the app drawer is clicked on
        var appDrawerContainer = $("#app-drawer-container");
        if (!$(event.target).closest("#app-drawer-container, #app-drawer-toggle").length) {
            if (appDrawerContainer.is(":visible")) {
                appDrawerContainer.hide();
            }
        }
    });
    // log clicks on app drawer icons with google analytics
    $(".app").off("click");
    $(".app").click(function() {
        var appName = $(this).find(".app-name").text();
        app.home.appDrawerClickAnalytics(appName);
    });
}

// insert the Handlebars template into the page.
// name should be the name of the Handlebars template, i.e. main.hbs -> "main",
// containerSelector should be the jQuery selector for the element that will have
//                   its HTML be set to the Handlebars template
// context should be a JSON object that acts as the context for the template
function insertTemplate(name, containerSelector, context) {
    $(containerSelector).html(Templates[name](context));
    setListeners();
}

// change the current URL and render the specified Handlebars template.
// name should be the name of the Handlebars template, i.e. main.hbs -> "main",
// href should typically just be the anchor portion, i.e. "#q=abc",
// context should be a JSON object that acts as the context for the template
function renderPage(name, href, context) {
    location.href = href;
    // update google analytics tracker
    ga("set", "page", "/" + name);
    ga("send", "pageview");
    insertTemplate(name, "body", context);
}

// look at the current url. if the anchor component has the form "#q={queryId}"
// then render the search results page for the query. otherwise render the main page.
function resolveLocation() {
    // get the string after the hash
    var hash = window.location.hash.substr(1);
    if (hash.substring(0, 2) == "q=" && hash.length > 2) {
        var queryId = Number(decodeURIComponent(hash.substring(2)));
        renderPage("search", window.location.hash, {logoUrl: app.home.getLogoUrl(LOGO_NUMBER), loadingMessage: app.search.getRandomLoadingMessage()});
        app.search.setQuestionText(queryId);
        app.search.resetSearchState(); //reset search result timers and poll loops
        app.search.resultsStartCounter(); //start counting
        app.search.pollAfterDelay(queryId, 0); //start checking
        app.search.loadRecentQuestions(); //fetch and render recent searches
    } else if (hash == "login" || hash == "admin") {
        if (app.admin.isAdmin()) {
            renderPage("admin", "#admin", {});
            app.admin.getQuestions(); //fetch queue of unanswered questions
        } else {
            renderPage("login", "#login", {});
            $("#username-input").focus();
        }
    } else if (hash == "privacy") {
        renderPage("privacy", "#privacy", {});
    } else if (hash == "terms") {
        renderPage("terms", "#terms", {});
    } else if (hash == "about") {
        renderPage("about", "#about", {});
    } else {
        var context = {
            logoUrl: app.home.getLogoUrl(LOGO_NUMBER),
            hiddenLogoUrl: app.home.getLogoUrl(HIDDEN_LOGO_NUMBER)
        }
        renderPage("main", "#", context);
        $(".search-box-input").focus();
    }
}

// if there is a query in the search box, then perform a search
function makeSearch() {
    var query = $(".search-box-input").val().trim();
    if (!query) {
        return;
    }

    // if the user has asked this question before, bring the user to
    // the search results page for that query
    var cachedQueries = JSON.parse(Cookies.get("queryText"));
    for (var key in cachedQueries) {
        if (cachedQueries[key] == query) {
            location.href = "#q=" + encodeURIComponent(key);
            return;
        }
    }

    $.ajax({
        contentType: "application/json",
        data: JSON.stringify({
            text: query,
            type: "search"
        }),
        method: 'POST',
        url: "/api/query",
        success: function(data) {
            data = JSON.parse(data);
            if (data.status == "true") {
                // Save query text to session cookie
                updateCachedQueries(Number(data.key), query);
                // send the user to the search results page
                location.href = "#q=" + encodeURIComponent(data.key);
                insertTemplate("search", "body", { logoUrl: app.home.getLogoUrl(LOGO_NUMBER), loadingMessage: app.search.getRandomLoadingMessage()});
                // set the contents of the search box to be the query
                $(".search-box-input").val(query);
                app.search.resetSearchState();
                app.search.resultsStartCounter();
                app.search.pollAfterDelay(data.key, app.search.getPollDelayTime(0));
            }
        },
        error: function(e) {
            console.log(e);
        }
    });
}

// adds the given query id and query text to the queryText cookie.
// however, if the current size of the cookie is already large,
// first remove the currently cached query texts
function updateCachedQueries(queryId, queryText) {
    var cachedQueries;
    var cachedQueriesString = Cookies.get("queryText");
    if (cachedQueriesString.length > 3000) {
        cachedQueries = {};
    } else {
        cachedQueries = JSON.parse(cachedQueriesString);
    }
    cachedQueries[queryId] = queryText;
    Cookies.set("queryText", JSON.stringify(cachedQueries));
}

init();
<commit_msg>Adding google analytics to bell icon<commit_after>var app = app || {};

/*
Functionality related to the app overall, mainly event listeners,
rendering new pages, making a search, and cookies
*/

// number of the hidden logo that will be displayed on rotation
var HIDDEN_LOGO_NUMBER;
// number of the logo that is currently displayed
var LOGO_NUMBER;
// number of times the user has clicked the bell icon in one session
var BELL_COUNT = 1;

// select the logo url and render the correct page
function init() {

    // allow Handlebars templates to be used as partials
    Handlebars.partials = Templates;

    // initialize queryText cookie if not already present
    if (!Cookies.get("queryText")) {
        Cookies.set("queryText", "{}");
    }

    // initialize with google logo
    LOGO_NUMBER = 1;

    // set hidden logo number to different random logo number
    HIDDEN_LOGO_NUMBER = LOGO_NUMBER;
    while (HIDDEN_LOGO_NUMBER == LOGO_NUMBER) {
        HIDDEN_LOGO_NUMBER = Math.floor(Math.random() * 6) + 1
    }

    $(document).ready(function() {
        resolveLocation();
    });
}

// set all of the event listeners that are needed
function setListeners() {
    // whenever the url anchor changes, render the correct page
    $(window).off("hashchange");
    $(window).on("hashchange", function() {
        resolveLocation();
    });
    // rotate the logo whenever the user clicks on the logo
    $("#lucky-search-btn").off("click");
    $("#lucky-search-btn").click(function() {
        app.home.rotateLogo();
    });
    // rotate the "I'm Feeling Jimmy" text when the user hovers over the button
    $("#lucky-search-btn").off("mouseenter");
    $("#lucky-search-btn").mouseenter(function() {
        app.home.rotateFeelingJimmy();
    });
    // perform a search on the main page when the "Jimmy Search" button is clicked
    $("#main-search-btn").off("click");
    $("#main-search-btn").click(function() {
        makeSearch();
    });
    // perform a search when the magnifying glass is clicked on the search results page
    $("#search-button").off("click");
    $("#search-button").click(function() {
        makeSearch();
    });

    // perform various actions after pressing "enter" depending on which element is focused
    $(document).off("keyup");
    $(document).keyup(function(e) {
        // ignore keys presses that aren't "enter"
        if (e.which != 13) {
            return;
        }
        if ($(".search-box-input").is(":focus")) {
            // search box on main page or search results page
            makeSearch();
        } else if ($(".answer-input").is(":focus")) {
            // answer text box in admin interface
            app.admin.answerQuestion($(":focus").data("question-id"));
        } else if ($("#username-input").is(":focus") || $("#password-input").is(":focus")) {
            // login username or password text box
            var username = $("#username-input").val().trim();
            var password = $("#password-input").val();
            app.admin.login(username, password);
        }
    });
    // add box shadow to search box when the user focuses on the search input
    $(".search-box-input").off("focus");
    $(".search-box-input").focus(function() {
        app.home.changeSearchBoxShadow(true);
    });
    // remove box shadow from search box when the search input loses focus
    $(".search-box-input").off("blur");
    $(".search-box-input").blur(function() {
        app.home.changeSearchBoxShadow(false);
    });
    // try to login as admin when "LOGIN" button clicked
    $("#admin-login-btn").off("click");
    $("#admin-login-btn").click(function() {
        var username = $("#username-input").val().trim();
        var password = $("#password-input").val();
        app.admin.login(username, password);
    });
    // remove "auth" cookie and send user to admin login when "LOGOUT" button clicked
    $("#admin-logout-btn").off("click");
    $("#admin-logout-btn").click(function() {
        app.admin.logout();
    });
    // get queue of questions from server when "GET QUESTIONS" button clicked
    $("#admin-get-questions").off("click");
    $("#admin-get-questions").click(function() {
        app.admin.getQuestions();
    });
    // add an input field for a URL on an answer card when clicking "+ Add a link"
    $(".admin-add-link").off("click");
    $(".admin-add-link").click(function(event) {
        // create a new div to serve as the container for the new input field
        var newInputContainer = $(document.createElement("div"));
        // add new input container to list of answer links
        $(event.target).parent().find(".answer-links").append(newInputContainer);
        // insert input text field into new input container
        insertTemplate("answerLink", newInputContainer, {"key": $(event.target).data("question-id")});
    });
    // send answer for question to server when "RESPOND" clicked on question card
    $(".answer-btn").off("click");
    $(".answer-btn").click(function(event) {
        app.admin.answerQuestion($(event.target).data("question-id"));
    });
    // hide/show app drawer on click of app drawer icon
    $("#app-drawer-toggle").off("click");
    $("#app-drawer-toggle").click(function() {
        var appDrawerContainer = $("#app-drawer-container");
        if (!appDrawerContainer.is(":visible")) {
            appDrawerContainer.show();
        } else {
            appDrawerContainer.hide();
        }
    });
    $("#notification-icon").off("click");
    $("#notification-icon").click(function() {
        var audio = new Audio("/sounds/bell.mp3");
        audio.play();
        ga("send", "event", {
            "eventCategory": "Bell",
            "eventAction": "Click",
            "eventValue": BELL_COUNT
        });
        BELL_COUNT += 1;
    });
    // click events for the entire document
    $(document).off("click");
    $(document).click(function(event) {
        // hide the app drawer if anything outside the app drawer is clicked on
        var appDrawerContainer = $("#app-drawer-container");
        if (!$(event.target).closest("#app-drawer-container, #app-drawer-toggle").length) {
            if (appDrawerContainer.is(":visible")) {
                appDrawerContainer.hide();
            }
        }
    });
    // log clicks on app drawer icons with google analytics
    $(".app").off("click");
    $(".app").click(function() {
        var appName = $(this).find(".app-name").text();
        app.home.appDrawerClickAnalytics(appName);
    });
}

// insert the Handlebars template into the page.
// name should be the name of the Handlebars template, i.e. main.hbs -> "main",
// containerSelector should be the jQuery selector for the element that will have
//                   its HTML be set to the Handlebars template
// context should be a JSON object that acts as the context for the template
function insertTemplate(name, containerSelector, context) {
    $(containerSelector).html(Templates[name](context));
    setListeners();
}

// change the current URL and render the specified Handlebars template.
// name should be the name of the Handlebars template, i.e. main.hbs -> "main",
// href should typically just be the anchor portion, i.e. "#q=abc",
// context should be a JSON object that acts as the context for the template
function renderPage(name, href, context) {
    location.href = href;
    // update google analytics tracker
    ga("set", "page", "/" + name);
    ga("send", "pageview");
    insertTemplate(name, "body", context);
}

// look at the current url. if the anchor component has the form "#q={queryId}"
// then render the search results page for the query. otherwise render the main page.
function resolveLocation() {
    // get the string after the hash
    var hash = window.location.hash.substr(1);
    if (hash.substring(0, 2) == "q=" && hash.length > 2) {
        var queryId = Number(decodeURIComponent(hash.substring(2)));
        renderPage("search", window.location.hash, {logoUrl: app.home.getLogoUrl(LOGO_NUMBER), loadingMessage: app.search.getRandomLoadingMessage()});
        app.search.setQuestionText(queryId);
        app.search.resetSearchState(); //reset search result timers and poll loops
        app.search.resultsStartCounter(); //start counting
        app.search.pollAfterDelay(queryId, 0); //start checking
        app.search.loadRecentQuestions(); //fetch and render recent searches
    } else if (hash == "login" || hash == "admin") {
        if (app.admin.isAdmin()) {
            renderPage("admin", "#admin", {});
            app.admin.getQuestions(); //fetch queue of unanswered questions
        } else {
            renderPage("login", "#login", {});
            $("#username-input").focus();
        }
    } else if (hash == "privacy") {
        renderPage("privacy", "#privacy", {});
    } else if (hash == "terms") {
        renderPage("terms", "#terms", {});
    } else if (hash == "about") {
        renderPage("about", "#about", {});
    } else {
        var context = {
            logoUrl: app.home.getLogoUrl(LOGO_NUMBER),
            hiddenLogoUrl: app.home.getLogoUrl(HIDDEN_LOGO_NUMBER)
        }
        renderPage("main", "#", context);
        $(".search-box-input").focus();
    }
}

// if there is a query in the search box, then perform a search
function makeSearch() {
    var query = $(".search-box-input").val().trim();
    if (!query) {
        return;
    }

    // if the user has asked this question before, bring the user to
    // the search results page for that query
    var cachedQueries = JSON.parse(Cookies.get("queryText"));
    for (var key in cachedQueries) {
        if (cachedQueries[key] == query) {
            location.href = "#q=" + encodeURIComponent(key);
            return;
        }
    }

    $.ajax({
        contentType: "application/json",
        data: JSON.stringify({
            text: query,
            type: "search"
        }),
        method: 'POST',
        url: "/api/query",
        success: function(data) {
            data = JSON.parse(data);
            if (data.status == "true") {
                // Save query text to session cookie
                updateCachedQueries(Number(data.key), query);
                // send the user to the search results page
                location.href = "#q=" + encodeURIComponent(data.key);
                insertTemplate("search", "body", { logoUrl: app.home.getLogoUrl(LOGO_NUMBER), loadingMessage: app.search.getRandomLoadingMessage()});
                // set the contents of the search box to be the query
                $(".search-box-input").val(query);
                app.search.resetSearchState();
                app.search.resultsStartCounter();
                app.search.pollAfterDelay(data.key, app.search.getPollDelayTime(0));
            }
        },
        error: function(e) {
            console.log(e);
        }
    });
}

// adds the given query id and query text to the queryText cookie.
// however, if the current size of the cookie is already large,
// first remove the currently cached query texts
function updateCachedQueries(queryId, queryText) {
    var cachedQueries;
    var cachedQueriesString = Cookies.get("queryText");
    if (cachedQueriesString.length > 3000) {
        cachedQueries = {};
    } else {
        cachedQueries = JSON.parse(cachedQueriesString);
    }
    cachedQueries[queryId] = queryText;
    Cookies.set("queryText", JSON.stringify(cachedQueries));
}

init();
<|endoftext|>