<commit_before>/**
 * @license
 * Copyright (c) 2017 Google Inc. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
'use strict';

import assert from '../platform/assert-web.js';
import {
  Particle,
  ViewChanges
} from './particle.js';

import XenStateMixin from '../shell/components/xen/xen-state.js';

/** @class DomParticle
 * Particle that does stuff with DOM.
 */
class DomParticle extends XenStateMixin(Particle) {
  /** @method get template()
   * Override to return a String defining primary markup.
   */
  get template() {
    return '';
  }
  /** @method getTemplate(slotName)
   * Override to return a String defining primary markup for the given slot name.
   */
  getTemplate(slotName) {
    // TODO: only supports a single template for now. add multiple templates support.
    return this.template;
  }
  /** @method willReceiveProps(props, state, oldProps, oldState)
   * Override if necessary, to do things when props change.
   */
  willReceiveProps() {
  }
  /** @method update(props, state, oldProps, oldState)
   * Override if necessary, to modify superclass config.
   */
  update() {
  }
  /** @method shouldRender(props, state, oldProps, oldState)
   * Override to return false if the Particle won't use
   * it's slot.
   */
  shouldRender() {
    return true;
  }
  /** @method render(props, state, oldProps, oldState)
   * Override to return a dictionary to map into the template.
   */
  render() {
    return {};
  }
  setState(state) {
    this._setState(state);
  }
  setIfDirty(state) {
    this._setIfDirty(state);
  }
  _willReceiveProps(...args) {
    this.willReceiveProps(...args);
  }
  _update(...args) {
    this.update(...args);
    if (this.shouldRender(...args)) { // TODO: should shouldRender be slot specific?
      this.relevance = 1; // TODO: improve relevance signal.
    }
    this.config.slotNames.forEach(s => this.renderSlot(s, ['model']));
  }
  /** @method get config()
   * Override if necessary, to modify superclass config.
   */
  get config() {
    // TODO(sjmiles): getter that does work is a bad idea, this is temporary
    return {
      views: this.spec.inputs.map(i => i.name),
      // TODO(mmandlis): this.spec needs to be replaced with a particle-spec loaded from
      // .manifest files, instead of .ptcl ones.
      slotNames: [...this.spec.slots.values()].map(s => s.name)
    };
  }
  _info() {
    return `---------- DomParticle::[${this.spec.name}]`;
  }
  async setViews(views) {
    this._views = views;
    let config = this.config;
    this.when([new ViewChanges(views, config.views, 'change')], async () => {
      await this._handlesToProps(views, config);
    });
    // make sure we invalidate once, even if there are no incoming views
    this._setState({});
  }
  async _handlesToProps(views, config) {
    // acquire (async) list data from views
    let data = await Promise.all(
      config.views
      .map(name => views.get(name))
      .map(view => view.toList ? view.toList() : view.get())
    );
    // convert view data (array) into props (dictionary)
    let props = Object.create(null);
    config.views.forEach((name, i) => {
      props[name] = data[i];
    });
    this._setProps(props);
  }
  renderSlot(slotName, contentTypes) {
    const stateArgs = [this._props, this._state, this._lastProps, this._lastState];
    let slot = this.getSlot(slotName);
    if (!slot) {
      return; // didn't receive StartRender.
    }
    contentTypes.forEach(ct => slot._requestedContentTypes.add(ct));
    // TODO(sjmiles): redundant, same answer for every
    if (this.shouldRender(...stateArgs)) {
      let content = {};
      if (slot._requestedContentTypes.has('template')) {
        content['template'] = this.getTemplate(slot.slotName);
      }
      if (slot._requestedContentTypes.has('model')) {
        content['model'] = this.render(...stateArgs);
      }
      slot.render(content);
    } else if (slot.isRendered) {
      // Send empty object, to clear rendered slot contents.
      slot.render({});
    }
  }
  fireEvent(slotName, {handler, data}) {
    if (this[handler]) {
      // TODO(sjmiles): remove `this._state` parameter
      this[handler]({data}, this._state);
    }
  }
  setParticleDescription(pattern) {
    if (typeof pattern === 'string') {
      return super.setParticleDescription(pattern);
    }
    assert(!!pattern.template && !!pattern.model, 'Description pattern must either be string or have template and model');
    super.setDescriptionPattern('_template_', pattern.template);
    super.setDescriptionPattern('_model_', JSON.stringify(pattern.model));
  }
}

export default DomParticle;
<commit_msg>use _getStateArgs<commit_after>/**
 * @license
 * Copyright (c) 2017 Google Inc. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
'use strict';

import assert from '../platform/assert-web.js';
import {
  Particle,
  ViewChanges
} from './particle.js';

import XenStateMixin from '../shell/components/xen/xen-state.js';

/** @class DomParticle
 * Particle that does stuff with DOM.
 */
class DomParticle extends XenStateMixin(Particle) {
  /** @method get template()
   * Override to return a String defining primary markup.
   */
  get template() {
    return '';
  }
  /** @method getTemplate(slotName)
   * Override to return a String defining primary markup for the given slot name.
   */
  getTemplate(slotName) {
    // TODO: only supports a single template for now. add multiple templates support.
    return this.template;
  }
  /** @method willReceiveProps(props, state, oldProps, oldState)
   * Override if necessary, to do things when props change.
   */
  willReceiveProps() {
  }
  /** @method update(props, state, oldProps, oldState)
   * Override if necessary, to modify superclass config.
   */
  update() {
  }
  /** @method shouldRender(props, state, oldProps, oldState)
   * Override to return false if the Particle won't use
   * it's slot.
   */
  shouldRender() {
    return true;
  }
  /** @method render(props, state, oldProps, oldState)
   * Override to return a dictionary to map into the template.
   */
  render() {
    return {};
  }
  setState(state) {
    this._setState(state);
  }
  setIfDirty(state) {
    this._setIfDirty(state);
  }
  _willReceiveProps(...args) {
    this.willReceiveProps(...args);
  }
  _update(...args) {
    this.update(...args);
    if (this.shouldRender(...args)) { // TODO: should shouldRender be slot specific?
      this.relevance = 1; // TODO: improve relevance signal.
    }
    this.config.slotNames.forEach(s => this.renderSlot(s, ['model']));
  }
  /** @method get config()
   * Override if necessary, to modify superclass config.
   */
  get config() {
    // TODO(sjmiles): getter that does work is a bad idea, this is temporary
    return {
      views: this.spec.inputs.map(i => i.name),
      // TODO(mmandlis): this.spec needs to be replaced with a particle-spec loaded from
      // .manifest files, instead of .ptcl ones.
      slotNames: [...this.spec.slots.values()].map(s => s.name)
    };
  }
  _info() {
    return `---------- DomParticle::[${this.spec.name}]`;
  }
  async setViews(views) {
    this._views = views;
    let config = this.config;
    this.when([new ViewChanges(views, config.views, 'change')], async () => {
      await this._handlesToProps(views, config);
    });
    // make sure we invalidate once, even if there are no incoming views
    this._setState({});
  }
  async _handlesToProps(views, config) {
    // acquire (async) list data from views
    let data = await Promise.all(
      config.views
      .map(name => views.get(name))
      .map(view => view.toList ? view.toList() : view.get())
    );
    // convert view data (array) into props (dictionary)
    let props = Object.create(null);
    config.views.forEach((name, i) => {
      props[name] = data[i];
    });
    this._setProps(props);
  }
  renderSlot(slotName, contentTypes) {
    const stateArgs = this._getStateArgs();
    let slot = this.getSlot(slotName);
    if (!slot) {
      return; // didn't receive StartRender.
    }
    contentTypes.forEach(ct => slot._requestedContentTypes.add(ct));
    // TODO(sjmiles): redundant, same answer for every
    if (this.shouldRender(...stateArgs)) {
      let content = {};
      if (slot._requestedContentTypes.has('template')) {
        content['template'] = this.getTemplate(slot.slotName);
      }
      if (slot._requestedContentTypes.has('model')) {
        content['model'] = this.render(...stateArgs);
      }
      slot.render(content);
    } else if (slot.isRendered) {
      // Send empty object, to clear rendered slot contents.
      slot.render({});
    }
  }
  fireEvent(slotName, {handler, data}) {
    if (this[handler]) {
      // TODO(sjmiles): remove `this._state` parameter
      this[handler]({data}, this._state);
    }
  }
  setParticleDescription(pattern) {
    if (typeof pattern === 'string') {
      return super.setParticleDescription(pattern);
    }
    assert(!!pattern.template && !!pattern.model, 'Description pattern must either be string or have template and model');
    super.setDescriptionPattern('_template_', pattern.template);
    super.setDescriptionPattern('_model_', JSON.stringify(pattern.model));
  }
}

export default DomParticle;
<|endoftext|>


<commit_before>(function (Marionette, Backbone, zeus_project) {

    var ZeusApp = Marionette.Application.extend({
        initialize: function (options) {
            this.project = options.project;
            delete options.project;
            Marionette.Application.prototype.call(this, arguments);
        },

        simpleModule: function (moduleNames, moduleDefinition) {
            var args = Array.prototype.slice.call(arguments);
            var self = this;

            // wrapper would receive module as first argument
            // any extra arguments must be explicitly passed to simpleModule
            // arguments
            args[1] = function moduleDefinitionWrapper () {
                var wrapperArgs = Array.prototype.slice.call(arguments);
                // only pass explicit arguments
                var newArgs = wrapperArgs.slice(6);
                // and include only module definition as first argument
                newArgs.unshift(wrapperArgs[0]);
                return moduleDefinition.apply(self, newArgs);
            }
            Marionette.Application.prototype.module.apply(this, args);
        },

        navigate: function (route, options) {
            options = options || {};
            Backbone.history.navigate(route, options)
        },

        getCurrentRoute: function () {
            return Backbone.history.fragment;
        }
    });

    zeus = new ZeusApp({project: zeus_project});

    zeus.addRegions({
        breadcrumbsRegion: "#breadcrumbs-region",
        mainRegion: "#main-region"
    });

    window.zeus = zeus;
    // start app when all js/templates are loaded
})(Marionette, Backbone, zeus_project);
<commit_msg>Addd missing semicolon<commit_after>(function (Marionette, Backbone, zeus_project) {

    var ZeusApp = Marionette.Application.extend({
        initialize: function (options) {
            this.project = options.project;
            delete options.project;
            Marionette.Application.prototype.call(this, arguments);
        },

        simpleModule: function (moduleNames, moduleDefinition) {
            var args = Array.prototype.slice.call(arguments);
            var self = this;

            // wrapper would receive module as first argument
            // any extra arguments must be explicitly passed to simpleModule
            // arguments
            args[1] = function moduleDefinitionWrapper () {
                var wrapperArgs = Array.prototype.slice.call(arguments);
                // only pass explicit arguments
                var newArgs = wrapperArgs.slice(6);
                // and include only module definition as first argument
                newArgs.unshift(wrapperArgs[0]);
                return moduleDefinition.apply(self, newArgs);
            }
            Marionette.Application.prototype.module.apply(this, args);
        },

        navigate: function (route, options) {
            options = options || {};
            Backbone.history.navigate(route, options);
        },

        getCurrentRoute: function () {
            return Backbone.history.fragment;
        }
    });

    zeus = new ZeusApp({project: zeus_project});

    zeus.addRegions({
        breadcrumbsRegion: "#breadcrumbs-region",
        mainRegion: "#main-region"
    });

    window.zeus = zeus;
    // start app when all js/templates are loaded
})(Marionette, Backbone, zeus_project);
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */
/*
 * IMPORTANT: This is a private module, its API must not be used and is subject to change.
 * Code other than the OpenUI5 libraries must not introduce dependencies to this module.
 */
sap.ui.define(["sap/base/assert"], function (assert) {
	"use strict";

	/**
	 * Prefix added to all storage keys. The prefix is used as namespace for data using the same key.
	 *
	 * @private
	 */
	var STATE_STORAGE_KEY_PREFIX = "state.key_";

	/**
	 * @class A Storage API for JavaScript.
	 * Note: The Web Storage API stores the data on the client. Therefore, you must not use this API for confidential information.
 	 *
	 * Provides a unified interface and methods to store data on the client using the Web Storage API or a custom implementation.
	 * By default, data can be persisted inside localStorage or a sessionStorage.
	 *
	 * You can access the 'default' storage by using {@link module:sap/ui/util/Storage} methods
	 * static on the module export or by creating an own instance of Storage via the constructor.
	 *
	 * A typical intended usage of this API is the storage of a string representing the state of
	 * a control. In this case, the data is stored in the browser session, and the methods to be
	 * used are {@link #put} and {@link #get}. The method {@link #remove} can be used to delete
	 * the previously saved state.
	 *
	 * For the sake of completeness, the method {@link #clear} is available. However, it should be
	 * called only in very particular situations, when a global erasing of data is required. If
	 * only keys with certain prefix should be deleted, the method {@link #removeAll} should be
	 * used.
	 *
	 * @example
	 *

	 * // Default Storage
	 * sap.ui.require(["sap/ui/util/Storage"], function(Storage) {
	 *  Storage.get("stored_data");
	 * });
	 *

	 * @example
	 *

	 * // Storage Instance
	 * sap.ui.require(["sap/ui/util/Storage"], function(Storage) {
	 *  var oMyStorage = new Storage(Storage.Type.session, "my_prefix");
	 *  oMyStorage.put("stored_data", "{ state: 'active' }");
	 *  oMyStorage.get("stored_data");
	 * });
	 *

	 * @since 1.58
	 * @alias module:sap/ui/util/Storage
	 * @param {module:sap/ui/util/Storage.Type | Storage} [pStorage=module:sap/ui/util/Storage.Type.session] The type this storage should be of or an Object implementing the typical Storage API for direct usage.
	 * @param {string} [sStorageKeyPrefix='state.key_'] The prefix to use in this storage.
	 * @public
	 */
	var Storage = function (pStorage, sStorageKeyPrefix) {

		var sType = "unknown",
			sPrefix = (sStorageKeyPrefix || STATE_STORAGE_KEY_PREFIX) + "-",
			oStorageImpl;

		if (!pStorage || typeof (pStorage) === "string") {
			sType = pStorage || Storage.Type.session;
			try {
				oStorageImpl = window[sType + "Storage"];
				// Test for QUOTA_EXCEEDED_ERR (Happens e.g. in mobile Safari when private browsing active)
				if (oStorageImpl) {
					var sTestKey = sPrefix + "___sapui5TEST___";
					oStorageImpl.setItem(sTestKey, "1");
					oStorageImpl.removeItem(sTestKey);
				}
			} catch (e) {
				oStorageImpl = null;
			}
		} else if (typeof (pStorage) === "object") {
			sType = pStorage.getType ? pStorage.getType() : "unknown";
			oStorageImpl = pStorage;
		}

		/**
		 * Helper function for function execution ignoring errors and checking for support.
		 *
		 * @param {function} fnToExecute
		 * @returns {boolean}
	 	*/
		var hasExecuted = function (fnToExecute) {
			try {
				if (this.isSupported()) {
					fnToExecute();
					return true;
				}
			} catch (e) {
				return false;
			}

			return false;

		}.bind(this);

		/**
		 * Returns whether the given storage is suppported.
		 *
		 * @return {boolean} true if storage is supported, false otherwise (e.g. due to browser security settings)
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#isSupported
		 */
		this.isSupported = function () {
			//Possibility to define for custom storage
			return typeof (oStorageImpl.isSupported) == "function" ? oStorageImpl.isSupported() : true;
		};

		/**
		 * Add key to the storage or updates value if the key already exists.
		 *
		 * @param {string} sKey key to create
		 * @param {string} sValue value to create/update
		 * @return {boolean} true if the data was successfully stored, otherwise false
		 *
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#put
		 */
		this.put = function (sKey, sStateToStore) {
			//precondition: non-empty sKey and available storage feature
			assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string");
			return hasExecuted(function () {
				oStorageImpl.setItem(sPrefix + sKey, JSON.stringify(sStateToStore));
			});
		};

		/**
		 * Retrieves data item for a specific key.
		 *
		 * @param {string} sKey key to retrieve
		 * @return {object|null} keys value or null
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#get
		 */
		this.get = function (sKey) {
			//precondition: non-empty sKey and available storage feature
			assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string");

			var oData;

			hasExecuted(function () {
				oData = JSON.parse(oStorageImpl.getItem(sPrefix + sKey));
			});

			return oData !== undefined ?  oData : null;
		};

		/**
		 * Removes key from storage if it exists.
		 *
		 * @param {string} sKey key to remove
		 * @return {boolean} true if the deletion
		 * was successful or the data doesn't exist under the specified key,
		 * and false if the feature is unavailable or a problem occurred
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#remove
		 */
		this.remove = function (sKey) {
			//precondition: non-empty sKey and available storage feature
			assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string");
			return hasExecuted(function () {
				oStorageImpl.removeItem(sPrefix + sKey);
			});
		};

		/**
		 * Removes all stored keys.
		 *
		 * @param {string} sIdPrefix prefix id for the states to delete
		 * @return {boolean} true if the deletion
		 * was successful or the data doesn't exist under the specified key,
		 * and false if the feature is unavailable or a problem occurred
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#removeAll
		 */
		this.removeAll = function (sIdPrefix) {
			return hasExecuted(function () {
				var key, p = sPrefix + (sIdPrefix || "");

				for (var i = 0, max = oStorageImpl.length; i < max;) {
					key = oStorageImpl.key(i);
					if (key && key.startsWith(p)) {
						oStorageImpl.removeItem(key);
					} else {
						i++;
					}
				}
			});
		};

		/**
		 * Clears the whole storage (Independent of the current Storage instance!).
		 *
		 * CAUTION This method should be called only in very particular situations,
		 * when a global erasing of data is required. Given that the method deletes
		 * the data saved under any ID, it should not be called when managing data
		 * for specific controls.
		 *
 		 * @return {boolean} true if execution of removal
		 * was successful or the data to remove doesn't exist,
		 * and false if the feature is unavailable or a problem occurred
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#clear
		 */
		this.clear = function () {
			return hasExecuted(function () {
				oStorageImpl.clear();
			});
		};

		/**
		 * Returns the storage type.
		 *
		 * @returns {module:sap/ui/util/Storage.Type | string} storage type or "unknown"
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#getType
		 */
		this.getType = function () {
			return sType;
		};
	};

	/**
	 * Enumeration of the storage types supported by {@link module:sap/ui/util/Storage}.
	 *
	 * @enum {string}
	 * @public
	 * @version ${version}
	 */
	Storage.Type = {
		/**
		 * Indicates usage of the browser's localStorage feature
		 * @public
		 */
		local: "local",
		/**
		 * Indicates usage of the browser's sessionStorage feature
		 * @public
		 */
		session: "session"
	};

	Object.assign(Storage, new Storage());

	return Storage;
});<commit_msg>[INTERNAL] sap.ui.util: Minor JSDoc improvements<commit_after>/*!
 * ${copyright}
 */
/*
 * IMPORTANT: This is a private module, its API must not be used and is subject to change.
 * Code other than the OpenUI5 libraries must not introduce dependencies to this module.
 */
sap.ui.define(["sap/base/assert"], function (assert) {
	"use strict";

	/**
	 * Prefix added to all storage keys. The prefix is used as namespace for data using the same key.
	 *
	 * @private
	 */
	var STATE_STORAGE_KEY_PREFIX = "state.key_";

	/**
	 * @class A Storage API for JavaScript.
	 *
	 * Note: The Web Storage API stores the data on the client. Therefore, you must not use this API for confidential information.
 	 *
	 * Provides a unified interface and methods to store data on the client using the Web Storage API or a custom implementation.
	 * By default, data can be persisted inside localStorage or a sessionStorage.
	 *
	 * You can access the 'default' storage by using {@link module:sap/ui/util/Storage} methods
	 * static on the module export or by creating an own instance of Storage via the constructor.
	 *
	 * A typical intended usage of this API is the storage of a string representing the state of
	 * a control. In this case, the data is stored in the browser session, and the methods to be
	 * used are {@link #put} and {@link #get}. The method {@link #remove} can be used to delete
	 * the previously saved state.
	 *
	 * For the sake of completeness, the method {@link #clear} is available. However, it should be
	 * called only in very particular situations, when a global erasing of data is required. If
	 * only keys with certain prefix should be deleted, the method {@link #removeAll} should be
	 * used.
	 *
	 * @example
	 *

	 * // Default Storage
	 * sap.ui.require(["sap/ui/util/Storage"], function(Storage) {
	 *  Storage.get("stored_data");
	 * });
	 *

	 * @example
	 *

	 * // Storage Instance
	 * sap.ui.require(["sap/ui/util/Storage"], function(Storage) {
	 *  var oMyStorage = new Storage(Storage.Type.session, "my_prefix");
	 *  oMyStorage.put("stored_data", "{ state: 'active' }");
	 *  oMyStorage.get("stored_data");
	 * });
	 *

	 * @since 1.58
	 * @alias module:sap/ui/util/Storage
	 * @param {module:sap/ui/util/Storage.Type | Storage} [pStorage=module:sap/ui/util/Storage.Type.session] The type this storage should be of or an Object implementing the typical Storage API for direct usage.
	 * @param {string} [sStorageKeyPrefix='state.key_'] The prefix to use in this storage.
	 * @public
	 */
	var Storage = function (pStorage, sStorageKeyPrefix) {

		var sType = "unknown",
			sPrefix = (sStorageKeyPrefix || STATE_STORAGE_KEY_PREFIX) + "-",
			oStorageImpl;

		if (!pStorage || typeof (pStorage) === "string") {
			sType = pStorage || Storage.Type.session;
			try {
				oStorageImpl = window[sType + "Storage"];
				// Test for QUOTA_EXCEEDED_ERR (Happens e.g. in mobile Safari when private browsing active)
				if (oStorageImpl) {
					var sTestKey = sPrefix + "___sapui5TEST___";
					oStorageImpl.setItem(sTestKey, "1");
					oStorageImpl.removeItem(sTestKey);
				}
			} catch (e) {
				oStorageImpl = null;
			}
		} else if (typeof (pStorage) === "object") {
			sType = pStorage.getType ? pStorage.getType() : "unknown";
			oStorageImpl = pStorage;
		}

		/**
		 * Helper function for function execution ignoring errors and checking for support.
		 *
		 * @param {function} fnToExecute
		 * @returns {boolean}
	 	*/
		var hasExecuted = function (fnToExecute) {
			try {
				if (this.isSupported()) {
					fnToExecute();
					return true;
				}
			} catch (e) {
				return false;
			}

			return false;

		}.bind(this);

		/**
		 * Returns whether the given storage is suppported.
		 *
		 * @return {boolean} true if storage is supported, false otherwise (e.g. due to browser security settings)
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#isSupported
		 */
		this.isSupported = function () {
			//Possibility to define for custom storage
			return typeof (oStorageImpl.isSupported) == "function" ? oStorageImpl.isSupported() : true;
		};

		/**
		 * Add key to the storage or updates value if the key already exists.
		 *
		 * @param {string} sKey key to create
		 * @param {string} sValue value to create/update
		 * @return {boolean} true if the data was successfully stored, otherwise false
		 *
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#put
		 */
		this.put = function (sKey, sStateToStore) {
			//precondition: non-empty sKey and available storage feature
			assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string");
			return hasExecuted(function () {
				oStorageImpl.setItem(sPrefix + sKey, JSON.stringify(sStateToStore));
			});
		};

		/**
		 * Retrieves data item for a specific key.
		 *
		 * @param {string} sKey key to retrieve
		 * @return {object|null} keys value or null
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#get
		 */
		this.get = function (sKey) {
			//precondition: non-empty sKey and available storage feature
			assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string");

			var oData;

			hasExecuted(function () {
				oData = JSON.parse(oStorageImpl.getItem(sPrefix + sKey));
			});

			return oData !== undefined ?  oData : null;
		};

		/**
		 * Removes key from storage if it exists.
		 *
		 * @param {string} sKey key to remove
		 * @return {boolean} true if the deletion
		 * was successful or the data doesn't exist under the specified key,
		 * and false if the feature is unavailable or a problem occurred
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#remove
		 */
		this.remove = function (sKey) {
			//precondition: non-empty sKey and available storage feature
			assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string");
			return hasExecuted(function () {
				oStorageImpl.removeItem(sPrefix + sKey);
			});
		};

		/**
		 * Removes all stored keys.
		 *
		 * @param {string} sIdPrefix prefix id for the states to delete
		 * @return {boolean} true if the deletion
		 * was successful or the data doesn't exist under the specified key,
		 * and false if the feature is unavailable or a problem occurred
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#removeAll
		 */
		this.removeAll = function (sIdPrefix) {
			return hasExecuted(function () {
				var key, p = sPrefix + (sIdPrefix || "");

				for (var i = 0, max = oStorageImpl.length; i < max;) {
					key = oStorageImpl.key(i);
					if (key && key.startsWith(p)) {
						oStorageImpl.removeItem(key);
					} else {
						i++;
					}
				}
			});
		};

		/**
		 * Clears the whole storage (Independent of the current Storage instance!).
		 *
		 * CAUTION This method should be called only in very particular situations,
		 * when a global erasing of data is required. Given that the method deletes
		 * the data saved under any ID, it should not be called when managing data
		 * for specific controls.
		 *
 		 * @return {boolean} true if execution of removal
		 * was successful or the data to remove doesn't exist,
		 * and false if the feature is unavailable or a problem occurred
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#clear
		 */
		this.clear = function () {
			return hasExecuted(function () {
				oStorageImpl.clear();
			});
		};

		/**
		 * Returns the storage type.
		 *
		 * @returns {module:sap/ui/util/Storage.Type | string} storage type or "unknown"
		 * @public
		 * @function
		 * @name module:sap/ui/util/Storage#getType
		 */
		this.getType = function () {
			return sType;
		};
	};

	/**
	 * Enumeration of the storage types supported by {@link module:sap/ui/util/Storage}.
	 *
	 * @enum {string}
	 * @public
	 * @version ${version}
	 */
	Storage.Type = {
		/**
		 * Indicates usage of the browser's localStorage feature
		 * @public
		 */
		local: "local",
		/**
		 * Indicates usage of the browser's sessionStorage feature
		 * @public
		 */
		session: "session"
	};

	Object.assign(Storage, new Storage());

	return Storage;
});<|endoftext|>


<commit_before>"use strict";

/* import-globals-from common.js */

// Send the blind review flag CC via the bugzilla rest API
function sendFlag(flag) {
  const url = `https://${location.host}/rest/bug/${bug_id}?Bugzilla_api_token=${api_token}`;
  return fetch(url, {
    method: "PUT",
    credentials: "include",
    headers: new Headers({"Content-Type": "application/json"}),
    body: JSON.stringify({cc: {add: [`${flag}-blind-review@mozilla.bugs`]}}),
  });
}

// Add the <select> box for setting the blind review flag
function addFlagging(bug) {
  const box = document.querySelector("#buttonBox");
  const publish = document.querySelector("#publishButton");

  const options = ["don't log this review", "fully blind", "partially blind"];
  const select = document.createElement("select");
  select.append(...options.map(o => new Option(o)));

  select.selectedIndex = !bug.visible;
  publish.addEventListener("click", () => {
    storage(bug_id, true);
    if (select.selectedIndex > 0) {
      sendFlag(select.selectedIndex === 1 ? "fully" : "partially");
    }
  });

  box.insertBefore(select, box.firstChild);
  box.insertBefore(icon(), select);
}

async function splinterActual() {
  const visible = await storage(bug_id);
  const ac = document.querySelector("#attachCreator");
  const br = document.querySelector("#bugReporter");
  const mentions = [ac];

  if (ac.textContent === br.textContent) {
    mentions.push(br);
  }

  const flags = document.querySelectorAll(`#flags span[title="${ac.textContent}"]`);
  for (const f of flags) {
    mentions.push(f);
  }

  for (const m of mentions) {
    const img = icon();
    const fn = document.createElement("span");
    fn.className = "br-r";

    m.parentNode.insertBefore(img, m);
    m.parentNode.insertBefore(fn, m);
    m.parentNode.classList.toggle("br-vcard", true);
  }

  const intro = document.querySelectorAll("#patchIntro>.pre-wrap");
  for (const line of intro) {
    if (line.textContent.startsWith("# User ")) {
      line.textContent = "# User [redacted]";
    }
  }

  setVisible(visible);
  // TODO: fix flagging
  // addFlagging(bug);
}

function init() {
  const author = document.querySelector("#attachCreator");
  const observer = new MutationObserver(splinterActual);
  observer.observe(author, {childList: true});
}

init();
<commit_msg>Switch to reading the published CC flag from bugzilla<commit_after>"use strict";

/* import-globals-from common.js */

const FLAGS = ["fully-blind-review@mozilla.bugs", "partially-blind-review@mozilla.bugs"];

// Make a Bugzilla rest API request
async function rest(method, data) {
  const url = `https://${location.host}/rest/bug/${bug_id}?Bugzilla_api_token=${api_token}`;
  const response = await fetch(url, {
    method,
    credentials: "include",
    headers: new Headers({"Content-Type": "application/json"}),
    body: JSON.stringify(data),
  });
  return response.json();
}

// Add <select> for picking the blind review flag
function addTracking(visible) {
  const box = document.querySelector("#buttonBox");

  const options = ["fully blind", "partially blind", "don't track this review"];

  const select = document.createElement("select");
  select.append(...options.map(o => new Option(o)));
  select.selectedIndex = [undefined, 0, 1].indexOf(visible);

  const original = document.querySelector("#publishButton");
  const publish = original.cloneNode();
  original.replaceWith(publish);

  publish.addEventListener("click", async () => {
    if (select.selectedIndex < 2) {
      await rest("PUT", {cc: {add: [FLAGS[select.selectedIndex]]}});
    }
    await storage(bug_id, true);
    Splinter.publishReview();
  });

  box.insertBefore(select, box.firstChild);
  box.insertBefore(icon(), select);
}

async function splinter() {
  const visible = await storage(bug_id);
  const ac = document.querySelector("#attachCreator");
  const br = document.querySelector("#bugReporter");
  const mentions = [ac];

  if (ac.textContent === br.textContent) {
    mentions.push(br);
  }

  const flags = document.querySelectorAll(`#flags span[title="${ac.textContent}"]`);
  for (const f of flags) {
    mentions.push(f);
  }

  for (const m of mentions) {
    const img = icon();
    const fn = document.createElement("span");
    fn.className = "br-r";

    m.parentNode.insertBefore(img, m);
    m.parentNode.insertBefore(fn, m);
    m.parentNode.classList.toggle("br-vcard", true);
  }

  const intro = document.querySelectorAll("#patchIntro>.pre-wrap");
  for (const line of intro) {
    if (line.textContent.startsWith("# User ")) {
      line.textContent = "# User [redacted]";
    }
  }

  setVisible(visible);

  const json = await rest();
  if (!json.bugs[0].cc.some(m => FLAGS.includes(m))) {
    addTracking(visible);
  }
}

function init() {
  const author = document.querySelector("#attachCreator");
  if (author.textContent) {
    splinter();
  } else {
    const observer = new MutationObserver(splinter);
    observer.observe(author, {childList: true});
  }
}

init();
<|endoftext|>


<commit_before>var request = require('request');
var cache = require('./cache');
var config = require('./config');

module.exports.fetchMenu = function(url, date, postParams, parseCallback, doneCallback) {
    var cached = cache.get(date + ":" + url);
    if (cached && !process.env.AT11_NO_CACHE)
    {
        doneCallback(null, cached);
    }
    else
    {
        load(url, date, postParams, parseCallback, function(error, menu) {
            if (!error) {
                if(menu.length > 0) {
                    cache.set(date + ":" + url, menu);
                }
                //we need to go through cache to get cache timestamp
                doneCallback(null, cache.get(date + ":" + url));
            }
            else {
                console.log(error);
                doneCallback(error);
            }
        });
    }
};

function load(url, date, postParams, parseCallback, doneCallback) {
    var options = {
        url: url,
        method: postParams ? "POST" : "GET",
        form: postParams
    };
    request(options, function(error, response, body) {
        if (!error && response.statusCode === 200)
        {
            var timer = setTimeout(function() {
                timer = null;//clear needed as value is kept even after timeout fired
                doneCallback(new Error("Parser timeout"));
            }, config.parserTimeout);

            try
            {
                parseCallback(body, date, function(menu) {
                    if (!timer)
                    {
                        //multiple calls in parser or parser called after timeout
                        return;
                    }
                    clearTimeout(timer);
                    timer = null;//clearTimeout does not null the value

                    try
                    {
                        if (!Array.isArray(menu))
                        {
                            throw "Invalid menu returned (expected array, got " + typeof menu + ")";
                        }
                        menu.forEach(function(item) {
                            if (typeof item !== "object")
                            {
                                throw "Menu item should be object, but got " + typeof item;
                            }
                            if (typeof item.isSoup !== "boolean")
                            {
                                throw "Menu item has wrong 'isSoup' flag (" + typeof item.isSoup + ")";
                            }
                            if (typeof item.text !== "string")
                            {
                                throw "Menu item has wrong 'text' property (" + typeof item.text + ")";
                            }
                            if (typeof item.price !== "number")
                            {
                                throw "Menu item has wrong 'price' property (" + typeof item.price + ")";
                            }
                            item.price = isNaN(item.price) ? "" : item.price.toFixed(2).replace(".", ",") + " €";//convert to presentable form
                        });
                        doneCallback(null, menu);
                    }
                    catch(err)
                    {
                        doneCallback(err);
                    }
                });
            }
            catch (err)//catches only synchronous errors in parser code
            {
                clearTimeout(timer);
                doneCallback(err);
            }
        }
        else
        {
            doneCallback(error || new Error("Response code" + response.statusCode));
        }
    });
}
<commit_msg>improved error logging<commit_after>var request = require('request');
var cache = require('./cache');
var config = require('./config');

module.exports.fetchMenu = function(url, date, postParams, parseCallback, doneCallback) {
    var cached = cache.get(date + ":" + url);
    if (cached && !process.env.AT11_NO_CACHE)
    {
        doneCallback(null, cached);
    }
    else
    {
        load(url, date, postParams, parseCallback, function(error, menu) {
            if (!error) {
                if(menu.length > 0) {
                    cache.set(date + ":" + url, menu);
                }
                //we need to go through cache to get cache timestamp
                doneCallback(null, cache.get(date + ":" + url));
            }
            else {
                console.error("Error for %s: %s", url, error);
                doneCallback(error);
            }
        });
    }

  function load(url, date, postParams, parse, done) {
      var options = {
          url: url,
          method: postParams ? "POST" : "GET",
          form: postParams
      };
      request(options, function(error, response, body) {
          if (!error && response.statusCode === 200)
          {
              var timer = setTimeout(function() {
                  timer = null;//clear needed as value is kept even after timeout fired
                  done(new Error("Parser timeout"));
              }, config.parserTimeout);

              try
              {
                  parse(body, date, function(menu) {
                      if (!timer)
                      {
                          //multiple calls in parser or parser called after timeout
                          return;
                      }
                      clearTimeout(timer);
                      timer = null; //clearTimeout does not null the value

                      try
                      {
                          if (!Array.isArray(menu))
                          {
                              throw "Invalid menu returned (expected array, got " + typeof menu + ")";
                          }
                          menu.forEach(function(item) {
                              if (typeof item !== "object")
                              {
                                  throw "Menu item should be object, but got " + typeof item;
                              }
                              if (typeof item.isSoup !== "boolean")
                              {
                                  throw "Menu item has wrong 'isSoup' flag (" + typeof item.isSoup + ")";
                              }
                              if (typeof item.text !== "string")
                              {
                                  throw "Menu item has wrong 'text' property (" + typeof item.text + ")";
                              }
                              if (typeof item.price !== "number")
                              {
                                  throw "Menu item has wrong 'price' property (" + typeof item.price + ")";
                              }
                              item.price = isNaN(item.price) ? "" : item.price.toFixed(2).replace(".", ",") + " €"; //convert to presentable form
                          });
                          done(null, menu);
                      }
                      catch(err)
                      {
                          done(err);
                      }
                  });
              }
              catch (err) //catches only synchronous errors in parser code
              {
                  clearTimeout(timer);
                  doneCallback(err);
              }
          }
          else
          {
              doneCallback(error || new Error("Response code " + response.statusCode));
          }
      });
  }
};
<|endoftext|>


<commit_before>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendfile('index.html');
});

io.on('connection', function(socket){
  console.log('a user connected');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});
<commit_msg>kekekekeke<commit_after>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendfile('index.html');
});

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});
<|endoftext|>


<commit_before>'use strict';

// http://stackoverflow.com/questions/5348685/node-js-require-inheritance
global.YUI = require('yui').YUI;

var fs = require('fs'),
    syspath = require('path'),
    compressor = require('node-minify'),
    modules = {},
    paths = [];

function minify(file) {
  var execution = new compressor.minify({
    type: 'uglifyjs',
    fileIn: file,
    fileOut: file,
    callback: function(err) {
      if (err) {
        console.log(err);
      }
    }
  });
}

function loop(arr, callback) {
  if (!arr) {
    return;
  }

  if (Array.isArray(arr)) {
    for (var i = 0; i < arr.length; i = i + 1) {
      callback(arr[i], i);
    }
  } else {
    for (var key in arr) {
      if (arr.hasOwnProperty(key)) {
        callback(arr[key], key);
      }
    }
  }
}

// Reading the 'requires' attribute of all our custom js files
(function() {
  function readdir(path) {
    var file, dirs = [], fileName, files = fs.readdirSync(path);

    loop(files, function(value) {
      fileName = path + '/' + value;
      file = fs.statSync(fileName);

      if (file.isFile()) {
        if (syspath.extname(fileName).toLowerCase() === '.js') {
          if ('./app/modules-debug.js' === fileName) {
            console.log('SKIPPING FILE -> ' + fileName);
          } else {
            paths.push(fileName);
          }
        }
      } else if (file.isDirectory()) {
        console.log('DIRECTORY -> ' + fileName);
        if ('./app/assets' === fileName) {
          console.log('SKIPPING DIRECTORY -> ' + fileName);
        } else {
          dirs.push(fileName);
        }
      }
    });

    // We wrote all the files. Now it is time to read and write the files
    // inside the children directories.
    loop(dirs, function(directory) {
      readdir(directory);
    });
  }

  // reading all JS files under './app'
  readdir('./app');
  console.log('FILES loaded');

  var originalAdd = YUI.add;
  // This is a trick to get the 'requires' value from the module definition
  YUI.add = function(name, fn, version, details) {
    modules[name] = [];
    if (details && details.requires) {
      loop(details.requires, function(value) {
        modules[name].push(value);
      });
    }
  };

  loop(paths, function(value) {
    // It triggers the custom 'add' method above
    require(value);
  });
  YUI.add = originalAdd;
})();

// Getting all the YUI dependencies that we need
var reqs = (function() {
  var yuiRequirements = [];
  loop(modules, function(requires) {
    loop(requires, function(value) {
      if (!modules[value]) {
        // This is not one of our modules but a yui one.
        if (yuiRequirements.indexOf(value) < 0) {
          // avoid duplicates
          yuiRequirements.push(value);
        }
      }
    });
  });
  console.log('REQS loaded');
  return yuiRequirements;
})();

// Using the example http://yuilibrary.com/yui/docs/yui/loader-resolve.html
(function() {
  var Y, loader, out, str = [];
  Y = YUI();
  loader = new Y.Loader({
    base: syspath.join(__dirname, './node_modules/yui/'),
    ignoreRegistered: true,
    require: reqs
  });
  out = loader.resolve(true);
  out.js.forEach(function(file) {
    console.log('file -> ' + file);
    str.push(fs.readFileSync(file, 'utf8'));
  });
  fs.writeFileSync('./app/all-yui.js', str.join('\n'), 'utf8');
  minify('./app/all-yui.js');
})();

// Creating the combined file for all the third part js code
(function() {

  var strDirectory = './app/assets/javascripts/', str = [];
  str.push(fs.readFileSync(strDirectory + 'd3.v2.min.js', 'utf8'));
  str.push(fs.readFileSync(strDirectory + 'reconnecting-websocket.js',
      'utf8'));
  str.push(fs.readFileSync(strDirectory + 'svg-layouts.js', 'utf8'));
  fs.writeFileSync('./app/all-third.js', str.join('\n'), 'utf8');
  minify('./app/all-third.js');
})();

//Creating the combined file for the modules-debug.js and config.js files
(function() {

  var str = [];
  str.push(fs.readFileSync('./app/modules-debug.js', 'utf8'));
  str.push(fs.readFileSync('./app/config.js', 'utf8'));
  fs.writeFileSync('./app/all-app-debug.js', str.join('\n'), 'utf8');
})();

// Creating the combined file for all our files
(function() {
  var str = [];
  loop(paths, function(file) {
    console.log('file -> ' + file);
    str.push(fs.readFileSync(file, 'utf8'));
  });
  fs.writeFileSync('./app/all-app.js', str.join('\n'), 'utf8');
  minify('./app/all-app.js');
})();

<commit_msg>lint fixes<commit_after>'use strict';

// http://stackoverflow.com/questions/5348685/node-js-require-inheritance
global.YUI = require('yui').YUI;

var fs = require('fs'),
    syspath = require('path'),
    compressor = require('node-minify'),
    modules = {},
    paths = [];

function minify(file) {
  var execution = new compressor.minify({
    type: 'uglifyjs',
    fileIn: file,
    fileOut: file,
    callback: function(err) {
      if (err) {
        console.log(err);
      }
    }
  });
}

function loop(arr, callback) {
  if (!arr) {
    return;
  }

  if (Array.isArray(arr)) {
    for (var i = 0; i < arr.length; i = i + 1) {
      callback(arr[i], i);
    }
  } else {
    for (var key in arr) {
      if (arr.hasOwnProperty(key)) {
        callback(arr[key], key);
      }
    }
  }
}

// Reading the 'requires' attribute of all our custom js files
(function() {
  function readdir(path) {
    var file, dirs = [], fileName, files = fs.readdirSync(path);

    loop(files, function(value) {
      fileName = path + '/' + value;
      file = fs.statSync(fileName);

      if (file.isFile()) {
        if (syspath.extname(fileName).toLowerCase() === '.js') {
          if ('./app/modules-debug.js' === fileName) {
            console.log('SKIPPING FILE -> ' + fileName);
          } else {
            paths.push(fileName);
          }
        }
      } else if (file.isDirectory()) {
        console.log('DIRECTORY -> ' + fileName);
        if ('./app/assets' === fileName) {
          console.log('SKIPPING DIRECTORY -> ' + fileName);
        } else {
          dirs.push(fileName);
        }
      }
    });

    // We wrote all the files. Now it is time to read and write the files
    // inside the children directories.
    loop(dirs, function(directory) {
      readdir(directory);
    });
  }

  // reading all JS files under './app'
  readdir('./app');
  console.log('FILES loaded');

  var originalAdd = YUI.add;
  // This is a trick to get the 'requires' value from the module definition
  YUI.add = function(name, fn, version, details) {
    modules[name] = [];
    if (details && details.requires) {
      loop(details.requires, function(value) {
        modules[name].push(value);
      });
    }
  };

  loop(paths, function(value) {
    // It triggers the custom 'add' method above
    require(value);
  });
  YUI.add = originalAdd;
})();

// Getting all the YUI dependencies that we need
var reqs = (function() {
  var yuiRequirements = [];
  loop(modules, function(requires) {
    loop(requires, function(value) {
      if (!modules[value]) {
        // This is not one of our modules but a yui one.
        if (yuiRequirements.indexOf(value) < 0) {
          // avoid duplicates
          yuiRequirements.push(value);
        }
      }
    });
  });
  console.log('REQS loaded');
  return yuiRequirements;
})();

// Using the example http://yuilibrary.com/yui/docs/yui/loader-resolve.html
(function() {
  var Y, loader, out, str = [];
  Y = YUI();
  loader = new Y.Loader({
    base: syspath.join(__dirname, './node_modules/yui/'),
    ignoreRegistered: true,
    require: reqs
  });
  out = loader.resolve(true);
  out.js.forEach(function(file) {
    console.log('file -> ' + file);
    str.push(fs.readFileSync(file, 'utf8'));
  });
  fs.writeFileSync('./app/all-yui.js', str.join('\n'), 'utf8');
  minify('./app/all-yui.js');
})();

// Creating the combined file for all the third part js code
(function() {
  var strDirectory = './app/assets/javascripts/', str = [];
  str.push(fs.readFileSync(strDirectory + 'd3.v2.min.js', 'utf8'));
  str.push(fs.readFileSync(strDirectory + 'reconnecting-websocket.js',
      'utf8'));
  str.push(fs.readFileSync(strDirectory + 'svg-layouts.js', 'utf8'));
  fs.writeFileSync('./app/all-third.js', str.join('\n'), 'utf8');
  minify('./app/all-third.js');
})();

//Creating the combined file for the modules-debug.js and config.js files
(function() {

  var str = [];
  str.push(fs.readFileSync('./app/modules-debug.js', 'utf8'));
  str.push(fs.readFileSync('./app/config.js', 'utf8'));
  fs.writeFileSync('./app/all-app-debug.js', str.join('\n'), 'utf8');
})();

// Creating the combined file for all our files
(function() {
  var str = [];
  loop(paths, function(file) {
    console.log('file -> ' + file);
    str.push(fs.readFileSync(file, 'utf8'));
  });
  fs.writeFileSync('./app/all-app.js', str.join('\n'), 'utf8');
  minify('./app/all-app.js');
})();

<|endoftext|>


<commit_before>import '../../../../tests/e2e/commands';

import ApiInitializer from '../../../../api/local-mock-api/e2e/ApiInitializer';
import ValidateVeteran from '../../../../tests/e2e/pages/ValidateVeteran';
import Demographics from '../../../../tests/e2e/pages/Demographics';
import EmergencyContact from '../../../../tests/e2e/pages/EmergencyContact';
import NextOfKin from '../../../../tests/e2e/pages/NextOfKin';
import Appointments from '../pages/Appointments';
import Confirmation from '../pages/Confirmation';

describe('Check In Experience -- ', () => {
  describe('Confirmation display -- ', () => {
    beforeEach(() => {
      const {
        initializeFeatureToggle,
        initializeSessionGet,
        initializeSessionPost,
        initializeCheckInDataGet,
        initializeCheckInDataPost,
        initializeDemographicsPatch,
      } = ApiInitializer;
      initializeFeatureToggle.withCurrentFeatures();
      initializeSessionGet.withSuccessfulNewSession();
      initializeSessionPost.withSuccess();
      initializeCheckInDataGet.withSuccess();
      initializeCheckInDataPost.withSuccess();
      initializeDemographicsPatch.withSuccess();
      cy.visitWithUUID();
      ValidateVeteran.validatePage.dayOf();
      ValidateVeteran.validateVeteran();
      ValidateVeteran.attemptToGoToNextPage();
      Demographics.attemptToGoToNextPage();
      EmergencyContact.attemptToGoToNextPage();
      NextOfKin.attemptToGoToNextPage();
      Appointments.validatePageLoaded();
      Appointments.attemptCheckIn(2);
    });
    afterEach(() => {
      cy.window().then(window => {
        window.sessionStorage.clear();
      });
    });
    it('confirm page display', () => {
      Confirmation.validatePageLoaded();
      cy.injectAxeThenAxeCheck();
    });
    it('confirm page has BTSSS link', () => {
      Confirmation.validateBTSSSLink();
      cy.injectAxeThenAxeCheck();
    });
    it('confirm back button', () => {
      Confirmation.validateBackButton();
      cy.injectAxeThenAxeCheck();
    });
    it.skip('refreshes appointment data when pressing the browser back button', () => {
      cy.intercept(
        '/check_in/v2/patient_check_ins/*',
        cy.spy().as('apptRefresh'),
      );
      cy.go('back');
      cy.get('@apptRefresh')
        .its('callCount')
        .should('equal', 1);
      cy.injectAxeThenAxeCheck();
    });
  });
});
<commit_msg>Fix flaky Check In confirmation E2E test (#22196)<commit_after>import '../../../../tests/e2e/commands';

import ApiInitializer from '../../../../api/local-mock-api/e2e/ApiInitializer';
import ValidateVeteran from '../../../../tests/e2e/pages/ValidateVeteran';
import Demographics from '../../../../tests/e2e/pages/Demographics';
import EmergencyContact from '../../../../tests/e2e/pages/EmergencyContact';
import NextOfKin from '../../../../tests/e2e/pages/NextOfKin';
import Appointments from '../pages/Appointments';
import Confirmation from '../pages/Confirmation';

describe('Check In Experience -- ', () => {
  describe('Confirmation display -- ', () => {
    beforeEach(() => {
      const {
        initializeFeatureToggle,
        initializeSessionGet,
        initializeSessionPost,
        initializeCheckInDataGet,
        initializeCheckInDataPost,
        initializeDemographicsPatch,
      } = ApiInitializer;
      initializeFeatureToggle.withCurrentFeatures();
      initializeSessionGet.withSuccessfulNewSession();
      initializeSessionPost.withSuccess();
      initializeCheckInDataGet.withSuccess();
      initializeCheckInDataPost.withSuccess();
      initializeDemographicsPatch.withSuccess();
      cy.visitWithUUID();
      ValidateVeteran.validatePage.dayOf();
      ValidateVeteran.validateVeteran();
      ValidateVeteran.attemptToGoToNextPage();
      Demographics.attemptToGoToNextPage();
      EmergencyContact.attemptToGoToNextPage();
      NextOfKin.attemptToGoToNextPage();
      Appointments.validatePageLoaded();
      Appointments.attemptCheckIn(2);
    });
    afterEach(() => {
      cy.window().then(window => {
        window.sessionStorage.clear();
      });
    });
    it('confirm page display', () => {
      Confirmation.validatePageLoaded();
      cy.injectAxeThenAxeCheck();
    });
    it('confirm page has BTSSS link', () => {
      Confirmation.validateBTSSSLink();
      cy.injectAxeThenAxeCheck();
    });
    it('confirm back button', () => {
      Confirmation.validateBackButton();
      cy.injectAxeThenAxeCheck();
    });
    it('refreshes appointment data when pressing the browser back button', () => {
      Confirmation.validatePageLoaded();
      cy.intercept(
        '/check_in/v2/patient_check_ins/*',
        cy.spy().as('apptRefresh'),
      );
      cy.go('back');
      cy.get('@apptRefresh')
        .its('callCount')
        .should('equal', 1);
      cy.injectAxeThenAxeCheck();
    });
  });
});
<|endoftext|>


<commit_before>var assert = require('assert');

//
//
//function toEnglish(a) {
//    if(a == 1) {
//    return "one";
//    } else {
//        return "this is not number 1";
//    }
//
//};
//
//it ('should equal the english word "one" instead of "1"', function() {
//assert.equal(toEnglish(1), "one");
//});

//function toEnglish (a) {
//    if (a == 2) {
//        return "two"
//    } else {
//        return "this is not number 2";
//    }
//};
//
//it ('should equal the english word "two" instead of "2"', function (){
//    assert.equal(toEnglish(2), "two");
//});

//function toEnglish (a) {
//    if (a == 3) {
//        return "three"
//    } else {
//        return "this is not number 3";
//    }
//}
//
//it ('should equal the english word "three" instead of "3"', function () {
//    assert.equal(toEnglish(3), "three");
//});

//function toEnglish (a) {
//    if (a == 4) {
//        return "four"
//    }   else {
//        return "this is not numnber 4";
//    }
//}
//
//it ('should equal the english word "four" instead of "4"', function() {
//    assert.equal(toEnglish(4), "four");
//});
//
//function toEnglish (a) {
//    if (a==5) {
//        return "five"
//    } else {
//        return "this is not number 5";
//    }
//}
//
//it ('should equal the english word "five" instead of "5"', function() {
//    assert.equal(toEnglish(5), "five");
//});
//
//function toEnglish (a) {
//    if (a==6) {
//        return "six"
//    } else {
//        return "this is not number 6";
//    }
//}
//
//it ('should equal the english word "six" instead of "6"', function (){
//    assert.equal(toEnglish(6), "six");
//});

//function toEnglish (a) {
//    if (a==7) {
//        return "seven"
//    } else {
//        return "this is not number 7";
//    }
//}
//
//it ('should equal the english word "seven" instead of "seven"', function() {
//    assert.equal(toEnglish(7), "seven");
//});

//function toEnglish (a) {
//    if (a==8) {
//        return "eight"
//    } else {
//        return "this is not  number 8";
//    }
//}
//
//it ('should equal the english word "eight" instead of "8"', function () {
//    assert.equal(toEnglish(8), "eight");
//});
//
//function toEnglish (a) {
//    if (a==9) {
//        return "nine"
//    } else {
//        return "this is not a number 9";
//    }
//}
//
//it ('should equal the english word "nine" instead of "nine"', function () {
//    assert.equal(toEnglish(9), "nine");
//});

function toEnglish (a) {
    if (a==10) {
        return "ten"
    } else {
        return "this is not number 10";
    }
}

it ('should equal the english word "ten" instead of "ten"', function () {
    assert.equal(toEnglish(10), "ten");
});<commit_msg>new checks checks<commit_after>var assert = require('assert');

//
//
//function toEnglish(a) {
//    if(a == 1) {
//    return "one";
//    } else {
//        return "this is not number 1";
//    }
//
//};
//
//it ('should equal the english word "one" instead of "1"', function() {
//assert.equal(toEnglish(1), "one");
//});

//function toEnglish (a) {
//    if (a == 2) {
//        return "two"
//    } else {
//        return "this is not number 2";
//    }
//};
//
//it ('should equal the english word "two" instead of "2"', function (){
//    assert.equal(toEnglish(2), "two");
//});

//function toEnglish (a) {
//    if (a == 3) {
//        return "three"
//    } else {
//        return "this is not number 3";
//    }
//}
//
//it ('should equal the english word "three" instead of "3"', function () {
//    assert.equal(toEnglish(3), "three");
//});

//function toEnglish (a) {
//    if (a == 4) {
//        return "four"
//    }   else {
//        return "this is not numnber 4";
//    }
//}
//
//it ('should equal the english word "four" instead of "4"', function() {
//    assert.equal(toEnglish(4), "four");
//});
//
//function toEnglish (a) {
//    if (a==5) {
//        return "five"
//    } else {
//        return "this is not number 5";
//    }
//}
//
//it ('should equal the english word "five" instead of "5"', function() {
//    assert.equal(toEnglish(5), "five");
//});
//
//function toEnglish (a) {
//    if (a==6) {
//        return "six"
//    } else {
//        return "this is not number 6";
//    }
//}
//
//it ('should equal the english word "six" instead of "6"', function (){
//    assert.equal(toEnglish(6), "six");
//});

//function toEnglish (a) {
//    if (a==7) {
//        return "seven"
//    } else {
//        return "this is not number 7";
//    }
//}
//
//it ('should equal the english word "seven" instead of "seven"', function() {
//    assert.equal(toEnglish(7), "seven");
//});

//function toEnglish (a) {
//    if (a==8) {
//        return "eight"
//    } else {
//        return "this is not  number 8";
//    }
//}
//
//it ('should equal the english word "eight" instead of "8"', function () {
//    assert.equal(toEnglish(8), "eight");
//});
//
//function toEnglish (a) {
//    if (a==9) {
//        return "nine"
//    } else {
//        return "this is not a number 9";
//    }
//}
//
//it ('should equal the english word "nine" instead of "nine"', function () {
//    assert.equal(toEnglish(9), "nine");
//});

//function toEnglish (a) {
//    if (a==10) {
//        return "ten"
//    } else {
//        return "this is not number 10";
//    }
//}
//
//it ('should equal the english word "ten" instead of "ten"', function () {
//    assert.equal(toEnglish(10), "ten");
//});

function toEnglish(a) {
    if (a == 1) {
        return "one";
    } else if (a== 2) {
        return "two";
    } else if (a==3) {
        return "three";
    } else if (a==4) {
        return "four";
    } else if (a==5) {
        return "five";
    } else if (a==6) {
        return "six";
    } else if (a==7){
        return "seven";
    } else if (a==8){
        return "eight";
    } else if (a==9) {
        return "nine";
    } else if (a==10) {
        return "ten";
    }

}

var toEnglish=["zero","one","two","three","four","five","six","seven","eight","nine","ten"]

function print(n){
    return toEnglish[n];
}

it('should print numbers from string"', function (){
    assert.equal(print(4),"four");
})

it('should return 1 as string "one"', function() {
    assert.equal(toEnglish(1), "one");
})

it('should return "two" when 2 is entered and "not two" if any other number is entered', function () {
    assert.equal(toEnglish(2), "two");

} )

it('should return "three" when 3 is entered and "not the number 3" is any other number is entered', function() {
    assert.equal(toEnglish(3), "three");
})

it('should return 4 as string "four"', function(){
   assert.equal(toEnglish(4),"four");
})

it('should return 5 as string "five"', function(){
    assert.equal(toEnglish(5),"five");
})

it('should return 6 as string "six"', function (){
    assert.equal(toEnglish(6),"six");
})

it('should return 7 as string "seven"', function(){
    assert.equal(toEnglish(7),"seven");
})

it('should return 8 as string "eight"', function(){
    assert.equal(toEnglish(8),"eight");
})

it('should return 9 as string "nine"', function(){
    assert.equal(toEnglish(9),"nine");
})

it('should return 10 as strign "ten"', function () {
    assert.equal(toEnglish(10),"ten");
})<|endoftext|>


<commit_before>require([
	'$api/models',
	'$views/image#Image',
	'$views/list#List'
], function(models, Image, List) {
	'use strict';

//move to playlist-control
	function updateLocalPlaylist(callback) {
		// console.log('The callback: ', callback);

		models.Playlist.createTemporary('Spotiparty').done(function(p) {
			console.log("playlist " + p.name + " created");
			p.load("tracks").done(function(spotipartyPlaylist) {
				window.spotipartyPlaylist = spotipartyPlaylist;

				models.player.load('track').done(function(p) {
					if(p.track != null){
						// spotipartyPlaylist.tracks.trim(p.track);
						spotipartyPlaylist.tracks.clear();
						// console.log(spotipartyPlaylist.tracks.toArray());
					}
					updatePlaylistFromWeb(spotipartyPlaylist);
				});

				setTimeout($.proxy(function() {
					var list = List.forPlaylist(p); // add options later, like height and number of items before scroll
					$('#playlistContainer').html(list.node);
					list.init();
				}, this), 10);
				callback ? callback() : undefined;
			});
		}).fail(function(error) {
			console.log(error);
		});

	}

window.theSongs = {
			'songs': [
				'spotify:track:6IKNeMqF1V1gmNkiZh1MmZ',
				'spotify:track:3PJikMV2xGNCooQttQrAw5',
				'spotify:track:30g7tH1rfMratchnaLfgqJ',
				'spotify:track:3kZC0ZmFWrEHdUCmUqlvgZ',
				'spotify:track:5yc59J3MR3tVDPTOgwgRI5',
				'spotify:track:2bD1AW4yqiCurGCva6r88a',
				'spotify:track:1x5MjCffpcdHLf65eR9r3T',
				'spotify:track:5KQrOv9nFVnM465CVGriW9',
				'spotify:track:5qEn8c0MBzyRKgQq91Vevi',
				'spotify:track:7Ik1qCkU5NIeBNFzoehjix',
				'spotify:track:0GO8y8jQk1PkHzS31d699N',
				'spotify:track:3l8dM1wjgFh98jpiq5ZCe7',
				'spotify:track:2XbqxKjCnE9YWfPRqwgtPq'
			]
		};

	function updatePlaylistFromWeb(localPlaylist) {
		// AJAX call would go here...

		// var window.theSongs = {'songs':[]};

		if (window.theSongs.songs.length > 0) {

			// localPlaylist.tracks.insert(0, window.theSongs.songs); // that 0 might not be right

			$.each(window.theSongs.songs, function(index, value) {
				localPlaylist.tracks.add(models.Track.fromURI(value));

				console.log("added track uri " + value);
			});
			///// This is to remove a song each time one is played
			window.theSongs.songs.shift();
		} else {
			console.log('No songs in the queue');
		}
	}

//move to view
	if(localStorage.backupPlaylist != undefined){
	    models.Playlist.fromURI(localStorage.backupPlaylist).load('name').done(function(playlist) {
	    	$('#backupPlaylist').val(playlist.name);
	    });
	}

	var imageURI = null;

	$('#backupPlaylist').bind('dragenter', function() {

		$('#backupPlaylist').val('');
	});

	$('#backupPlaylist').bind('change', function() {

		console.log('The changed conent: ' + $('#backupPlaylist').val());
	});

	$('#backupPlaylist').bind('drop', function() {

		// spotify:user:danmandle:playlist:5ZwcCib9Fp38CygXSTi9Fw
		// http://open.spotify.com/user/danmandle/playlist/5ZwcCib9Fp38CygXSTi9Fw

		setTimeout($.proxy(function() {
			// have to set the timeout for, well, unknown reasons, but the value of the field wasn't populating

			var playlistURI = urlToUri($('#backupPlaylist').val());
			localStorage.backupPlaylist = playlistURI;

			models.Playlist.fromURI(playlistURI).load('name').done(function(playlist) {
				$('#backupPlaylist').val(playlist.name);
			});
		}, this), 0);
	});

	function updateCoverArt(track) {
		var image = Image.forTrack(track, {
			width: 500,
			height: 500,
			player: false
		});
		if (imageURI != image._item.uri) {
			// evaluate so that it doesn't reload the image each time the play state changes
			imageURI = image._item.uri;
			$('#albumCoverContainer').html(image.node);
		}
	}

	function updateTrackTitle(track) {
		$('h1#current-track').text(track.artists[0].name + ' - ' + track.name);
	}

	function trackChange() {
		models.player.load('track').done(function(p) {

			/// something about being here

			if(p.track != undefined){
				updateCoverArt(p.track);
				updateTrackTitle(p.track);
				updateLocalPlaylist();
			}
			else{
				console.log("yo dawg, we're undefined."); //Probably from that moment between when a track stops and starts
			}

		}).fail(function(error) {
			console.log(error);
		});

	};

// move to player-functions
	$('#startTheParty').click(function(){
		console.log('Let the party begin');
		updateLocalPlaylist(function(){
			models.player.stop().done(function(p) {
				var theTempPlaylist = models.Playlist.fromURI('spotify:internal:temp_playlist:spotify:app:spotiparty@Spotiparty');
				models.player.playContext(theTempPlaylist); // There's probably a more right way to do this
			});
		});

	});

	models.player.addEventListener('change:playing', function(p) {
		console.log((p.target.playing ? 'Started' : 'Stopped') + ' playing');
		(p.target.playing) ? window.startChecking() : stopChecking();
	});

	// Gets fired when a track ends or is skipped
	models.player.addEventListener('change:track', function(p) {
		console.log('song changed');
		trackChange();
	});

	window.songPosition = function() {

		models.player.load('position', 'playing').done(function(p) {
			console.log(Math.round((p.duration - p.position)/1000) + " seconds left", Math.round((p.position / p.duration)*100) + '% complete');

			!p.playing ? stopChecking() : null;
			if(p.position > 0){

				if ((p.duration - p.position) < 30000) { // if there's less that 30 seconds left in the song
					updateLocalPlaylist();
					stopChecking();
				}
			}
		}).fail(function(error) {
			console.log(error);
		});
	};

	window.startChecking = function(){window.songPositionChecker = window.setInterval(songPosition, 2000)};
	window.stopChecking = function() {clearInterval(window.songPositionChecker)};

	window.urlToUri = function(url) {
		// convert URL to URI
		//// http://open.spotify.com/user/danmandle/playlist/5ZwcCib9Fp38CygXSTi9Fw
		//// spotify:user:danmandle:playlist:5ZwcCib9Fp38CygXSTi9Fw
		return 'spotify' + url.replace('http://open.spotify.com', '').replace(/\//gi, ':');
	}

// we should initialize some values
	trackChange();
	updateLocalPlaylist();
	startChecking();

});<commit_msg>stopping point<commit_after>require([
	'$api/models',
	'$views/image#Image',
	'$views/list#List'
], function(models, Image, List) {
	'use strict';

//move to playlist-control
	function updateLocalPlaylist(callback) {
		// console.log('The callback: ', callback);

		models.Playlist.createTemporary('Spotiparty').done(function(p) {
			console.log("playlist " + p.name + " created");
			p.load("tracks").done(function(spotipartyPlaylist) {
				window.spotipartyPlaylist = spotipartyPlaylist;

				models.player.load('track').done(function(p) {
					if(p.track != null){
						// spotipartyPlaylist.tracks.trim(p.track);
						spotipartyPlaylist.tracks.clear();
						// console.log(spotipartyPlaylist.tracks.toArray());
					}
					updatePlaylistFromWeb(spotipartyPlaylist);
				});

				setTimeout($.proxy(function() {
					var list = List.forPlaylist(p); // add options later, like height and number of items before scroll
					$('#playlistContainer').html(list.node);
					list.init();
				}, this), 10);
				callback ? callback() : undefined;
			});
		}).fail(function(error) {
			console.log(error);
		});

	}

window.theSongs = {
			'songs': [
				'spotify:track:6IKNeMqF1V1gmNkiZh1MmZ',
				'spotify:track:3PJikMV2xGNCooQttQrAw5',
				'spotify:track:30g7tH1rfMratchnaLfgqJ',
				'spotify:track:3kZC0ZmFWrEHdUCmUqlvgZ',
				'spotify:track:5yc59J3MR3tVDPTOgwgRI5',
				'spotify:track:2bD1AW4yqiCurGCva6r88a',
				'spotify:track:1x5MjCffpcdHLf65eR9r3T',
				'spotify:track:5KQrOv9nFVnM465CVGriW9',
				'spotify:track:5qEn8c0MBzyRKgQq91Vevi',
				'spotify:track:7Ik1qCkU5NIeBNFzoehjix',
				'spotify:track:0GO8y8jQk1PkHzS31d699N',
				'spotify:track:3l8dM1wjgFh98jpiq5ZCe7',
				'spotify:track:2XbqxKjCnE9YWfPRqwgtPq'
			]
		};

	function updatePlaylistFromWeb(localPlaylist) {
		// AJAX call would go here...

		// var window.theSongs = {'songs':[]};

		if (window.theSongs.songs.length > 0) {

			// localPlaylist.tracks.insert(0, window.theSongs.songs); // that 0 might not be right

			$.each(window.theSongs.songs, function(index, value) {
				localPlaylist.tracks.add(models.Track.fromURI(value));

				// console.log("added track uri " + value);
			});
			console.log('Added a bunch of songs');

			///// This is to remove a song each time one is played
			// window.theSongs.songs.shift();
		} else {
			console.log('No songs in the queue');
		}
	}

//move to view
	if(localStorage.backupPlaylist != undefined){
	    models.Playlist.fromURI(localStorage.backupPlaylist).load('name').done(function(playlist) {
	    	$('#backupPlaylist').val(playlist.name);
	    });
	}

	var imageURI = null;

	$('#backupPlaylist').bind('dragenter', function() {

		$('#backupPlaylist').val('');
	});

	$('#backupPlaylist').bind('change', function() {

		console.log('The changed conent: ' + $('#backupPlaylist').val());
	});

	$('#backupPlaylist').bind('drop', function() {

		// spotify:user:danmandle:playlist:5ZwcCib9Fp38CygXSTi9Fw
		// http://open.spotify.com/user/danmandle/playlist/5ZwcCib9Fp38CygXSTi9Fw

		setTimeout($.proxy(function() {
			// have to set the timeout for, well, unknown reasons, but the value of the field wasn't populating

			var playlistURI = urlToUri($('#backupPlaylist').val());
			localStorage.backupPlaylist = playlistURI;

			models.Playlist.fromURI(playlistURI).load('name').done(function(playlist) {
				$('#backupPlaylist').val(playlist.name);
			});
		}, this), 0);
	});

	function updateCoverArt(track) {
		var image = Image.forTrack(track, {
			width: 500,
			height: 500,
			player: false
		});
		if (imageURI != image._item.uri) {
			// evaluate so that it doesn't reload the image each time the play state changes
			imageURI = image._item.uri;
			$('#albumCoverContainer').html(image.node);
		}
	}

	function updateTrackTitle(track) {
		$('h1#current-track').text(track.artists[0].name + ' - ' + track.name);
	}

	function trackChange() {
		models.player.load('track').done(function(p) {

			/// something about being here

			if(p.track != undefined){
				updateCoverArt(p.track);
				updateTrackTitle(p.track);
				updateLocalPlaylist();
			}
			else{
				console.log("yo dawg, we're undefined."); //Probably from that moment between when a track stops and starts
			}

		}).fail(function(error) {
			console.log(error);
		});

	};

// move to player-functions
	$('#startTheParty').click(function(){
		console.log('Let the party begin');
		updateLocalPlaylist(function(){
			models.player.stop().done(function(p) {
				var theTempPlaylist = models.Playlist.fromURI('spotify:internal:temp_playlist:spotify:app:spotiparty@Spotiparty');
				models.player.playContext(theTempPlaylist); // There's probably a more right way to do this
			});
		});

	});

	models.player.addEventListener('change:playing', function(p) {
		console.log((p.target.playing ? 'Started' : 'Stopped') + ' playing');
		if(p.target.playing){
			window.startChecking();
		}
		else{
			stopChecking();
		}
	});

	// Gets fired when a track ends or is skipped
	models.player.addEventListener('change:track', function(p) {
		console.log('song changed');
		trackChange();
	});

	window.songPosition = function() {

		models.player.load('position', 'playing').done(function(p) {

			// !p.playing ? stopChecking() : null;
			if(p.playing && p.position > 0){

				console.log(Math.round((p.duration - p.position)/1000) + " seconds left", Math.round((p.position / p.duration)*100) + '% complete');

				if ((p.duration - p.position) < 30000) { // if there's less that 30 seconds left in the song
					console.log('Time to update the localPlaylist');
					updateLocalPlaylist();
					stopChecking();
				}
			}
			else if(p.playing){
				console.log("We're playing ,but Position not available, wait till next time.", p.positon);
			}
			else{
				console.log(p.playing, p.positon);
				console.log("was going to check positon, but decieded against it. Also stopping checking.");
				stopChecking();
			}
		}).fail(function(error) {
			console.log(error);
		});
	};

	window.startChecking = function(){
		console.log('started checking, waiting 5 seconds');
		setTimeout($.proxy(function() {
			window.songPositionChecker = window.setInterval(songPosition, 2000);
		}, this), 5000);
	};
	window.stopChecking = function() {console.log('stopped checking');clearInterval(window.songPositionChecker)};

	window.urlToUri = function(url) {
		// convert URL to URI
		//// http://open.spotify.com/user/danmandle/playlist/5ZwcCib9Fp38CygXSTi9Fw
		//// spotify:user:danmandle:playlist:5ZwcCib9Fp38CygXSTi9Fw
		return 'spotify' + url.replace('http://open.spotify.com', '').replace(/\//gi, ':');
	}

// we should initialize some values
	trackChange();
	updateLocalPlaylist();
	startChecking();

});<|endoftext|>


<commit_before>import React from 'react'
import { Redirect, Route, Router, Switch } from 'react-router-dom'
import { browserHistory } from 'js/navigation/navigation'
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'
import defaultTheme from 'js/theme/defaultV1'
import BaseContainer from 'js/components/General/BaseContainer'
import ErrorBoundary from 'js/components/General/ErrorBoundary'
import { initializeFirebase } from 'js/authentication/firebaseConfig'
import logger from 'js/utils/logger'

// This is a hack to generate separate apps for the new tab
// page and search. We do this because create-react-app does
// not currently support more than one entry point. See:
// https://github.com/facebook/create-react-app/issues/1084#issuecomment-365495580
// Our goal is to use load only the necessary assets for the
// root new tab and search pages without downloading any
// critical JS asynchronously, while not switching away from
// CRA, ejecting from CRA, or dealing with the overhead of
// managing distinct codebases. In the future, it would be
// better for us to have a monorepo structure of some kind
// (see: https://github.com/facebook/create-react-app/issues/1492),
// use the built-in multiple entry points (if CRA supports
// it down the line), or switching to another framework.
var TheApp
var appPath
switch (process.env.REACT_APP_WHICH_APP) {
  case 'newtab': {
    TheApp = require('js/components/App/App').default
    appPath = '/newtab/'
    break
  }
  case 'search': {
    TheApp = require('js/components/Search/SearchView').default
    appPath = '/search/'
    break
  }
  default: {
    TheApp = require('js/components/App/App').default
    appPath = '/newtab/'
  }
}

const muiTheme = createMuiTheme(defaultTheme)

class Root extends React.Component {
  constructor(props) {
    super(props)

    // Initialize Firebase.
    try {
      initializeFirebase()
    } catch (e) {
      logger.error(e)
    }
  }

  componentDidMount() {
    // Measure time to interactive (TTI):
    // https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics#time_to_interactive
    // https://github.com/GoogleChromeLabs/tti-polyfill
    try {
      if (process.env.REACT_APP_MEASURE_TIME_TO_INTERACTIVE === 'true') {
        import('tti-polyfill').then(ttiPolyfill => {
          ttiPolyfill.getFirstConsistentlyInteractive().then(tti => {
            console.log(`Time to interactive: ${tti}`)
          })
        })
      }
    } catch (e) {
      console.error(e)
    }
  }

  render() {
    // TODO: Show 404 page
    return (
      <MuiThemeProvider theme={muiTheme}>
        <ErrorBoundary>
          <BaseContainer>
            <Router history={browserHistory}>
              <Switch>
                <Route path={appPath} component={TheApp} />
                <Redirect from="*" to={appPath} />
              </Switch>
            </Router>
          </BaseContainer>
        </ErrorBoundary>
      </MuiThemeProvider>
    )
  }
}

export default Root
<commit_msg>Debugging: remove React Router redirect<commit_after>import React from 'react'
import { Route, Router, Switch } from 'react-router-dom'
import { browserHistory } from 'js/navigation/navigation'
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'
import defaultTheme from 'js/theme/defaultV1'
import BaseContainer from 'js/components/General/BaseContainer'
import ErrorBoundary from 'js/components/General/ErrorBoundary'
import { initializeFirebase } from 'js/authentication/firebaseConfig'
import logger from 'js/utils/logger'

// This is a hack to generate separate apps for the new tab
// page and search. We do this because create-react-app does
// not currently support more than one entry point. See:
// https://github.com/facebook/create-react-app/issues/1084#issuecomment-365495580
// Our goal is to use load only the necessary assets for the
// root new tab and search pages without downloading any
// critical JS asynchronously, while not switching away from
// CRA, ejecting from CRA, or dealing with the overhead of
// managing distinct codebases. In the future, it would be
// better for us to have a monorepo structure of some kind
// (see: https://github.com/facebook/create-react-app/issues/1492),
// use the built-in multiple entry points (if CRA supports
// it down the line), or switching to another framework.
var TheApp
var appPath
switch (process.env.REACT_APP_WHICH_APP) {
  case 'newtab': {
    TheApp = require('js/components/App/App').default
    appPath = '/newtab/'
    break
  }
  case 'search': {
    TheApp = require('js/components/Search/SearchView').default
    appPath = '/search/'
    break
  }
  default: {
    TheApp = require('js/components/App/App').default
    appPath = '/newtab/'
  }
}

const muiTheme = createMuiTheme(defaultTheme)

class Root extends React.Component {
  constructor(props) {
    super(props)

    // Initialize Firebase.
    try {
      initializeFirebase()
    } catch (e) {
      logger.error(e)
    }
  }

  componentDidMount() {
    // Measure time to interactive (TTI):
    // https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics#time_to_interactive
    // https://github.com/GoogleChromeLabs/tti-polyfill
    try {
      if (process.env.REACT_APP_MEASURE_TIME_TO_INTERACTIVE === 'true') {
        import('tti-polyfill').then(ttiPolyfill => {
          ttiPolyfill.getFirstConsistentlyInteractive().then(tti => {
            console.log(`Time to interactive: ${tti}`)
          })
        })
      }
    } catch (e) {
      console.error(e)
    }
  }

  render() {
    // TODO: Show 404 page
    return (
      <MuiThemeProvider theme={muiTheme}>
        <ErrorBoundary>
          <BaseContainer>
            <Router history={browserHistory}>
              <Switch>
                <Route path={appPath} component={TheApp} />
              </Switch>
            </Router>
          </BaseContainer>
        </ErrorBoundary>
      </MuiThemeProvider>
    )
  }
}

export default Root
<|endoftext|>


<commit_before>module.exports = require('../number/NumberFilter');
<commit_msg>Implement number array selection options in the interface<commit_after>import React from 'react';
import ReactDOM from 'react-dom';

import { FormField, FormInput, FormRow, FormSelect } from 'elemental';

const CONTROL_OPTIONS = [
	{ label: 'Exactly', value: 'equals' },
	{ label: 'Greater Than', value: 'gt' },
	{ label: 'Less Than', value: 'lt' },
	{ label: 'Between', value: 'between' },
];

const SELECTION_OPTIONS = [
	{ label: 'All elements', value: 'all' },
	{ label: 'At least one element', value: 'moreThan' },
	{ label: 'No element', value: 'none' },
];

var NumberArrayFilter = React.createClass({

	getInitialState () {
		return {
			modeValue: CONTROL_OPTIONS[0].value, // 'matches'
			modeLabel: CONTROL_OPTIONS[0].label, // 'Matches'
			selectionValue: SELECTION_OPTIONS[0].value,
			selectionLabel: SELECTION_OPTIONS[0].label,
			value: '',
			minValue: '',
			maxValue: '',
		};
	},

	componentDidMount () {
		// focus the text input
		ReactDOM.findDOMNode(this.refs.input).focus();
	},

	handleChangeBuilder (type) {
		const self = this;
		return function handleChange (e) {
			const { value } = e.target;
			const { modeValue } = self.state;
			const { onChange } = self.props;
			self.setState({
				[type]: value,
			});

			switch (type) {
				case 'minValue':
					onChange({
						mode: modeValue,
						value: {
							min: value,
							max: self.state.maxValue,
						},
					});
					break;
				case 'maxValue':
					onChange({
						mode: modeValue,
						value: {
							max: value,
							min: self.state.minValue,
						},
					});
					break;
				case 'value':
					onChange({
						mode: modeValue,
						value,
					});
			}
		};
	},

	toggleMode (mode) {
		this.setState({
			modeValue: mode,
			modeLabel: CONTROL_OPTIONS.find(option => option.value === mode).label,
		});

		// focus the text input after a mode selection is made
		ReactDOM.findDOMNode(this.refs.input).focus();
	},

	toggleSelection (selection) {
		this.setState({
			selectionValue: selection,
			selectionLabel: SELECTION_OPTIONS.find(currSelection => currSelection.value === selection).label,
		});

		// focus the text input after a selection choice is made
		ReactDOM.findDOMNode(this.refs.input).focus();
	},

	renderControls () {
		let controls;
		const { field } = this.props;
		const { modeLabel, modeValue, selectionLabel, selectionValue } = this.state;
		const beingVerb = selectionValue === 'all' ? ' are ' : ' is ';
		const placeholder = selectionLabel + beingVerb + modeLabel.toLowerCase() + '...';

		if (modeValue === 'between') {
			controls = (
				<FormRow>
					<FormField width="one-half" style={{ marginBottom: 0 }}>
						<FormInput type="number" ref="input" placeholder="Min." onChange={this.handleChangeBuilder('minValue')} />
					</FormField>
					<FormField width="one-half" style={{ marginBottom: 0 }}>
						<FormInput type="number" placeholder="Max." onChange={this.handleChangeBuilder('maxValue')} />
					</FormField>
				</FormRow>
			);
		} else {
			controls = (
				<FormField>
					<FormInput type="number" ref="input" placeholder={placeholder} onChange={this.handleChangeBuilder('value')} />
				</FormField>
			);
		}

		return controls;
	},

	render () {
		const { modeValue, selectionValue } = this.state;

		return (
			<div>
				<FormSelect options={CONTROL_OPTIONS} onChange={this.toggleMode} value={modeValue} />
				<FormSelect options={SELECTION_OPTIONS} onChange={this.toggleSelection} value={selectionValue} />
				{this.renderControls()}
			</div>
		);
	},

});

module.exports = NumberArrayFilter;
<|endoftext|>


<commit_before>import View from '../base/view';

import {trigger} from '../utils';

import template from '../../templates/search.ejs';

export default class Search extends View {
  constructor({app, isOnSearchPage, query}) {
    super({app});

    this.isOnSearchPage = isOnSearchPage;
    this.query = query;
  }

  getHTML() {
    return this.app.renderTemplate(template, {
      isOnSearchPage: this.isOnSearchPage,
      query: this.query,
    });
  }

  mount() {
    this.input = this.element.querySelector('input');
    this.events.bind('submit', 'onSubmit');
    this.events.bind('focus input', 'onFocus');
    this.events.bind('blur input', 'onBlur');
    this.events.bind('keyup input', 'onType');
    this.events.bind('input input', 'onType');
  }

  onFocus() {
    this.element.classList.add('active');
  }

  onBlur() {
    if (this.input.value) return;
    this.element.classList.remove('active');
  }

  onType(event) {
    if (this.input.value == this.query) return;
    if (this.typeTimeout) window.clearTimeout(this.typeTimeout);
    this.typeTimeout = window.setTimeout(() => {
      const action = this.isOnSearchPage ? 'redirect' : 'navigate';
      const url = this.getSearchPageURL();
      trigger(window, action, url);
    }, 100);
  }

  onSubmit(event) {
    event.preventDefault();
    if (this.typeTimeout) window.clearTimeout(this.typeTimeout);
    const url = this.getSearchPageURL();
    trigger(window, 'navigate', url);
  }

  getSearchPageURL() {
    const query = this.input.value;
    const path = this.app.url('search', {});
    return `${path}?q=${encodeURIComponent(query)}`;
  }
}
<commit_msg>Implement a custom sync function for Search box<commit_after>import View from '../base/view';

import {trigger, toggleClass} from '../utils';

import template from '../../templates/search.ejs';

export default class Search extends View {
  constructor({app, isOnSearchPage, query}) {
    super({app});

    this.isOnSearchPage = isOnSearchPage;
    this.query = query;
  }

  getHTML() {
    return this.app.renderTemplate(template, {
      isOnSearchPage: this.isOnSearchPage,
      query: this.query,
    });
  }

  mount() {
    this.input = this.element.querySelector('input');
    this.events.bind('submit', 'onSubmit');
    this.events.bind('focus input', 'onFocus');
    this.events.bind('blur input', 'onBlur');
    this.events.bind('keyup input', 'onType');
    this.events.bind('input input', 'onType');
  }

  sync() {
    if (this.input.value != this.query) this.input.value = this.query;
    toggleClass(this.element, 'active', this.isOnSearchPage);
  }

  onFocus() {
    this.element.classList.add('active');
  }

  onBlur() {
    if (this.input.value) return;
    this.element.classList.remove('active');
  }

  onType(event) {
    if (this.input.value == this.query) return;
    if (this.typeTimeout) window.clearTimeout(this.typeTimeout);
    this.typeTimeout = window.setTimeout(() => {
      const action = this.isOnSearchPage ? 'redirect' : 'navigate';
      const url = this.getSearchPageURL();
      trigger(window, action, url);
    }, 100);
  }

  onSubmit(event) {
    event.preventDefault();
    if (this.typeTimeout) window.clearTimeout(this.typeTimeout);
    const url = this.getSearchPageURL();
    trigger(window, 'navigate', url);
  }

  getSearchPageURL() {
    const query = this.input.value;
    const path = this.app.url('search', {});
    return `${path}?q=${encodeURIComponent(query)}`;
  }
}
<|endoftext|>


<commit_before>const functions = require("firebase-functions");
const firestore = require("firebase-functions/lib/providers/datastore");
const Firestore = require("@google-cloud/firestore");

const algoliasearch = require("algoliasearch");

// [START init_algolia]
// Initialize Algolia, requires installing Algolia dependencies:
// https://www.algolia.com/doc/api-client/javascript/getting-started/#install
//
// App ID and API Key are stored in functions config variables
const ALGOLIA_ID = functions.config().algolia.app_id;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.api_key;

const ALGOLIA_INDEX_NAME = "notes";
const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
// [END init_algolia]

// Initialize Firestore
const firestoreOptions = {
  projectId: process.env.GCLOUD_PROJECT
};
const db = new Firestore(firestoreOptions);

// [START update_index_function]
// Update the search index every time a blog post is written.
exports.onNoteCreated = firestore.document("notes/{noteId}").onCreate(event => {
  // Get the note document
  const note = event.data.data();

  // Add an "objectID" field which Algolia requires
  note.objectID = event.params.postId;

  // Write to the algolia index
  const index = client.initIndex(ALGOLIA_INDEX_NAME);
  return index.saveObject(note);
});
// [END update_index_function]

// [START get_firebase_user]
const admin = require("admin");

function getFirebaseUser(req, res, next) {
  console.log("Check if request is authorized with Firebase ID token");

  if (
    !req.headers.authorization ||
    !req.headers.authorization.startsWith("Bearer ")
  ) {
    console.error(
      "No Firebase ID token was passed as a Bearer token in the Authorization header.",
      "Make sure you authorize your request by providing the following HTTP header:",
      "Authorization: Bearer <Firebase ID Token>"
    );
    res.status(403).send("Unauthorized");
    return;
  }

  let idToken;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith("Bearer ")
  ) {
    console.log("Found 'Authorization' header");
    idToken = req.headers.authorization.split("Bearer ")[1];
  }

  admin
    .auth()
    .verifyIdToken(idToken)
    .then(decodedIdToken => {
      console.log("ID Token correctly decoded", decodedIdToken);
      req.user = decodedIdToken;
      next();
    })
    .catch(error => {
      console.error("Error while verifying Firebase ID token:", error);
      res.status(403).send("Unauthorized");
    });
}
// [END get_firebase_user]

// [START get_algolia_user_token]
// This complex HTTP function will be created as an ExpressJS app:
// https://expressjs.com/en/4x/api.html
const app = require("express")();

// We'll enable CORS support to allow the function to be invoked
// from our app client-side.
app.use(require("cors")({ origin: true }));

// Then we'll also use a special "getFirebaseUser" middleware which
// verifies the Authorization header and adds a `user` field to the
// incoming request:
// https://gist.github.com/abehaskins/832d6f8665454d0cd99ef08c229afb42
app.use(getFirebaseUser);

// Finally, we'll add a route handler to
app.get("/", (req, res) => {
  const params = {
    hitsPerPage: 20,
    filters: `author:${req.user.user_id}`,
    userToken: req.user.user_id
  };
  const key = client.generateSecuredApiKey(ALGOLIA_SEARCH_KEY, params);
  res.json({ key });
});

exports.getSearchKey = functions.https.onRequest(app);
// [END get_algolia_user_token]
<commit_msg>More comments<commit_after>const functions = require("firebase-functions");
const firestore = require("firebase-functions/lib/providers/datastore");
const Firestore = require("@google-cloud/firestore");

const algoliasearch = require("algoliasearch");

// [START init_algolia]
// Initialize Algolia, requires installing Algolia dependencies:
// https://www.algolia.com/doc/api-client/javascript/getting-started/#install
//
// App ID and API Key are stored in functions config variables
const ALGOLIA_ID = functions.config().algolia.app_id;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.api_key;

const ALGOLIA_INDEX_NAME = "notes";
const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
// [END init_algolia]

// Initialize Firestore
const firestoreOptions = {
  projectId: process.env.GCLOUD_PROJECT
};
const db = new Firestore(firestoreOptions);

// [START update_index_function]
// Update the search index every time a blog post is written.
exports.onNoteCreated = firestore.document("notes/{noteId}").onCreate(event => {
  // Get the note document
  const note = event.data.data();

  // Add an "objectID" field which Algolia requires
  note.objectID = event.params.postId;

  // Write to the algolia index
  const index = client.initIndex(ALGOLIA_INDEX_NAME);
  return index.saveObject(note);
});
// [END update_index_function]

// [START get_firebase_user]
const admin = require("admin");

function getFirebaseUser(req, res, next) {
  console.log("Check if request is authorized with Firebase ID token");

  if (
    !req.headers.authorization ||
    !req.headers.authorization.startsWith("Bearer ")
  ) {
    console.error(
      "No Firebase ID token was passed as a Bearer token in the Authorization header.",
      "Make sure you authorize your request by providing the following HTTP header:",
      "Authorization: Bearer <Firebase ID Token>"
    );
    res.status(403).send("Unauthorized");
    return;
  }

  let idToken;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith("Bearer ")
  ) {
    console.log("Found 'Authorization' header");
    idToken = req.headers.authorization.split("Bearer ")[1];
  }

  admin
    .auth()
    .verifyIdToken(idToken)
    .then(decodedIdToken => {
      console.log("ID Token correctly decoded", decodedIdToken);
      req.user = decodedIdToken;
      next();
    })
    .catch(error => {
      console.error("Error while verifying Firebase ID token:", error);
      res.status(403).send("Unauthorized");
    });
}
// [END get_firebase_user]

// [START get_algolia_user_token]
// This complex HTTP function will be created as an ExpressJS app:
// https://expressjs.com/en/4x/api.html
const app = require("express")();

// We'll enable CORS support to allow the function to be invoked
// from our app client-side.
app.use(require("cors")({ origin: true }));

// Then we'll also use a special "getFirebaseUser" middleware which
// verifies the Authorization header and adds a `user` field to the
// incoming request:
// https://gist.github.com/abehaskins/832d6f8665454d0cd99ef08c229afb42
app.use(getFirebaseUser);

// Add a route handler to the app to generate the secured key
app.get("/", (req, res) => {
  // Create the params object as described in the Algolia documentation:
  // https://www.algolia.com/doc/guides/security/api-keys/#generating-api-keys
  const params = {
    // This filter ensures that only documents where author == user_id will be readable
    filters: `author:${req.user.user_id}`,
    // We also proxy the user_id as a unique token for this key.
    userToken: req.user.user_id
  };

  // Call the Algolia API to generate a unique key based on our search key
  const key = client.generateSecuredApiKey(ALGOLIA_SEARCH_KEY, params);

  // Then return this key as {key: "...key"}
  res.json({ key });
});

// Finally, pass our ExpressJS app to Cloud Functions as a function
// called "getSearchKey";
exports.getSearchKey = functions.https.onRequest(app);
// [END get_algolia_user_token]
<|endoftext|>