<commit_before>"use strict";

angular.module('backAnd.controllers')
.controller('tableController', ['$scope', 'Global', 'tableService', 'configService', '$http','$location','$route','$sce',
    function ($scope, Global, tableService, configService, $http, $location, $route, $sce) {

        $scope.global = Global;

        // Read the configuration of the current view
        $scope.$watch('tableName', function() {
            if ($scope.tableName)  {
                $scope.getConfigDataAsync();
            }

        });

        // All of the configurations will be part of the directive and we can change things
        // like default page size in when we call the directive

        $scope.filterOptions = {
            filterText: '',
            useExternalFilter: true
        };

        $scope.showColumnMenu = true;
        $scope.showMenu = true;

        /*Enables display of the filterbox in the column menu.
        If both showColumnMenu and showFilter are false the menu button will not display.*/
        $scope.showFilter = true;

        $scope.activateFilter = function() {
            var searchText = $scope.searchText || null;
            $scope.getData(searchText);
        };

        $scope.refreshData = function () {
            $scope.getData();
        };

        $scope.editSelected = function () {
            if ($scope.mySelections != null && $scope.mySelections.length == 1) {
                $location.search({
                  id: $scope.mySelections[0].__metadata.id,
                  table: $scope.tableName
              });
                $location.path('/formsExample');
            }
        };

        $scope.deleteSelected = function () {
            angular.forEach($scope.mySelections, function (rowItem) {
                $scope.dataFill.splice($scope.dataFill.indexOf(rowItem), 1);
                    //alert('delete:' + $scope.dataFill.indexOf(rowItem));
                    //todo: call the service to delete the record
                });
        }

        $scope.totalServerItems = 0;

        $scope.pagingOptions = {
            pageSizes: [5, 10, 15, 20, 30, 50, 100, 200, 500, 1000],
            pageSize: 0,
            currentPage: 1,
        };

        var isSort = true;
        $scope.sortOptions = {};
        $scope.$on('ngGridEventSorted', function(event, sortInfo) {
                // don't call getPagedDataAsync here cos this function
                // is called multiple times for the same update.
                $scope.sortOptions = {
                    fieldName: sortInfo.columns[0].displayName,
                    order: sortInfo.directions[0]
                };
            });
        $scope.mySelections = [];

        if (!Global.configTable) {
            $scope.dataTable = {
                columnDefs: 'columns',
                data: 'dataFill',
                selectedItems: $scope.mySelections,
                enablePaging: true,
                showFooter: true,
                useExternalSorting: true,
                sortOptions: $scope.sortOptions,
                totalServerItems: 'totalServerItems',
                pagingOptions: $scope.pagingOptions,
                rowHeight: 30,
                headerRowHeight: 30,
                footerRowHeight: 47,
                multiSelect: false
            };
        }
        else {
            $scope.dataTable = {
                columnDefs: 'columns',
                data: 'dataFill',
                selectedItems: $scope.mySelections,
                enablePaging: true,
                showFooter: true,
                useExternalSorting: true,
                sortOptions: $scope.sortOptions,
                totalServerItems: 'totalServerItems',
                pagingOptions: $scope.pagingOptions,
                rowHeight: Global.configTable.design && Global.configTable.design.rowHeightInPixels ? Global.configTable.design.rowHeightInPixels : 30,
                headerRowHeight: 30,
                footerRowHeight: 47,
                multiSelect: false
            };
        }

        // This is the call to get the data based on the table
        // and receives arguments of page size and page number
        // should look into creating a table directive that receives
        // arguments eg table name, and paging information

        $scope.getConfigDataAsync = function() {
            $scope.isLoad = true;
            $scope.columns = [];

            //update the configuration
            $scope.pagingOptions.pageSize = Global.configTable.design.rowsperPage;

            // We are adding columns and its custom filter to the table based on type
            // this will also need to be changed to handle multiple tables on the same page
            angular.forEach(Global.configTable.fields, function (col) {
                if (!col.donotDisplayinGrid && col.type != 'MultiSelect') {
                    $scope.columns.push({
                        cellFilter: col.type,
                        displayName: col.displayName,
                        width: col.columnWidth,
                        cellTemplate: $scope.getCellTemplate(col, Global.configTable)
                    });
                }
            });

            $scope.getData();
        };
        $scope.renderHtml = function (html_code) {
            return $sce.trustAsHtml(html_code);
        };

        $scope.getCellTemplate = function (col, view) {
            switch (col.type) {
                case 'Image':
                    var height = 'auto';// (view.rowHeight != '') ? view.rowHeight : 'auto';
                    var width = (height != 'auto') ? 'auto' : col.columnWidth;
                    return '

';
                    case 'Html':
                    return '

'; //'{{row.entity["' + col.name + '"]}}';
                    default:
                    return '
{{row.entity["' + col.name + '"]}}
';
            }
        }

        $scope.getData = function(searchText) {
            $scope.isLoad = true;
            if(searchText == 'undefined') searchText == null;
            // We are requesting data for the specific page of the table.
            var sortString = '[' + JSON.stringify($scope.sortOptions) + ']';
            tableService.queryjsonp({
                // This will also need to be adjusted to deal with mutiple tables on the same page
                table: $scope.tableName,
                pageSize: $scope.pagingOptions.pageSize,
                pageNumber: $scope.pagingOptions.currentPage,
                sort : sortString,
                search: searchText
            }, function(largeLoad) {
                // We have received table data and add the data to the scope
                $scope.dataFill = largeLoad.data;
                $scope.totalServerItems = largeLoad.totalRows;
                $scope.isLoad = false;
            });
        }
        $scope.afterSelectionChange = function (rowItem) {
            if (rowItem.selected)  {  // I don't know if this is true or just truey
                //write code to execute only when selected.
                //rowItem.entity is the "data" here
            } else {
                //write code on deselection.
            }
        }

        $scope.$watch('pagingOptions', function(newVal, oldVal) {
            if (newVal !== oldVal) {
                $scope.getData();
            }
        }, true);

        $scope.$watch('filterOptions', function(newVal, oldVal) {
            if (newVal !== oldVal) {
                $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
            }
        }, true);

        $scope.$watch('sortOptions', function(newVal, oldVal) {
            if (isSort && newVal !== oldVal) {
                $scope.getData();
                isSort = false;
                $scope.setIsSort();
            }
        }, true);

        $scope.setIsSort = function() {
            setTimeout(function(){isSort = true;}, 1500);
        }

            // this is the intitialization of the table data above
            $scope.$on('loadData', function() {
            $scope.getConfigDataAsync();
        });

    }
 ]);

<commit_msg>fix-sort<commit_after>"use strict";

angular.module('backAnd.controllers')
.controller('tableController', ['$scope', 'Global', 'tableService', 'configService', '$http','$location','$route','$sce',
    function ($scope, Global, tableService, configService, $http, $location, $route, $sce) {

        $scope.global = Global;

        // Read the configuration of the current view
        $scope.$watch('tableName', function() {
            if ($scope.tableName)  {
                $scope.getConfigDataAsync();
            }

        });

        // All of the configurations will be part of the directive and we can change things
        // like default page size in when we call the directive

        $scope.filterOptions = {
            filterText: '',
            useExternalFilter: true
        };

        $scope.showColumnMenu = true;
        $scope.showMenu = true;

        /*Enables display of the filterbox in the column menu.
        If both showColumnMenu and showFilter are false the menu button will not display.*/
        $scope.showFilter = true;

        $scope.activateFilter = function() {
            var searchText = $scope.searchText || null;
            $scope.getData(searchText);
        };

        $scope.refreshData = function () {
            $scope.getData();
        };

        $scope.editSelected = function () {
            if ($scope.mySelections != null && $scope.mySelections.length == 1) {
                $location.search({
                  id: $scope.mySelections[0].__metadata.id,
                  table: $scope.tableName
              });
                $location.path('/formsExample');
            }
        };

        $scope.deleteSelected = function () {
            angular.forEach($scope.mySelections, function (rowItem) {
                $scope.dataFill.splice($scope.dataFill.indexOf(rowItem), 1);
                    //alert('delete:' + $scope.dataFill.indexOf(rowItem));
                    //todo: call the service to delete the record
                });
        }

        $scope.totalServerItems = 0;

        $scope.pagingOptions = {
            pageSizes: [5, 10, 15, 20, 30, 50, 100, 200, 500, 1000],
            pageSize: 0,
            currentPage: 1,
        };

        var isSort = true;
        $scope.sortOptions = {};
        // $scope.$on('ngGridEventSorted', function(event, sortInfo) {
        //         // don't call getPagedDataAsync here cos this function
        //         // is called multiple times for the same update.
        //         $scope.sortOptions = {
        //             fieldName: sortInfo.columns[0].displayName,
        //             order: sortInfo.directions[0]
        //         };
        //     });
        $scope.mySelections = [];

        if (!Global.configTable) {
            $scope.dataTable = {
                columnDefs: 'columns',
                data: 'dataFill',
                selectedItems: $scope.mySelections,
                enablePaging: true,
                showFooter: true,
                useExternalSorting: true,
                sortOptions: $scope.sortOptions,
                totalServerItems: 'totalServerItems',
                pagingOptions: $scope.pagingOptions,
                rowHeight: 30,
                headerRowHeight: 30,
                footerRowHeight: 47,
                multiSelect: false
            };
        }
        else {
            $scope.dataTable = {
                columnDefs: 'columns',
                data: 'dataFill',
                selectedItems: $scope.mySelections,
                enablePaging: true,
                showFooter: true,
                useExternalSorting: true,
                sortOptions: $scope.sortOptions,
                totalServerItems: 'totalServerItems',
                pagingOptions: $scope.pagingOptions,
                rowHeight: Global.configTable.design && Global.configTable.design.rowHeightInPixels ? Global.configTable.design.rowHeightInPixels : 30,
                headerRowHeight: 30,
                footerRowHeight: 47,
                multiSelect: false
            };
        }

        // This is the call to get the data based on the table
        // and receives arguments of page size and page number
        // should look into creating a table directive that receives
        // arguments eg table name, and paging information

        var myHeaderCellTemplate = '
'+
                               '
{{col.displayName}}
'+
                               '

'+
                               '

'+
                               '
{{col.sortPriority}}
'+
                               '
'+
                               '

';

        $scope.myCustomSort = function(col) {
            if (!col.sortDirection || col.sortDirection == "asc")
               col.sortDirection = "desc";
            else
                col.sortDirection = "asc";
            $scope.sortOptions = {
                fieldName: col.displayName,
                order: col.sortDirection
            };
            $scope.getData();
        }

        $scope.getConfigDataAsync = function() {
            $scope.isLoad = true;
            $scope.columns = [];

            //update the configuration
            $scope.pagingOptions.pageSize = Global.configTable.design.rowsperPage;

            // We are adding columns and its custom filter to the table based on type
            // this will also need to be changed to handle multiple tables on the same page
            angular.forEach(Global.configTable.fields, function (col) {
                if (!col.donotDisplayinGrid && col.type != 'MultiSelect') {
                    $scope.columns.push({
                        headerCellTemplate: myHeaderCellTemplate,
                        cellFilter: col.type,
                        displayName: col.displayName,
                        width: col.columnWidth,
                        cellTemplate: $scope.getCellTemplate(col, Global.configTable)
                    });
                }
            });

            $scope.getData();
        };
        $scope.renderHtml = function (html_code) {
            return $sce.trustAsHtml(html_code);
        };

        $scope.getCellTemplate = function (col, view) {
            switch (col.type) {
                case 'Image':
                    var height = 'auto';// (view.rowHeight != '') ? view.rowHeight : 'auto';
                    var width = (height != 'auto') ? 'auto' : col.columnWidth;
                    return '

';
                    case 'Html':
                    return '

'; //'{{row.entity["' + col.name + '"]}}';
                    default:
                    return '
{{row.entity["' + col.name + '"]}}
';
            }
        }

        $scope.getData = function(searchText) {
            $scope.isLoad = true;
            if(searchText == 'undefined') searchText == null;
            // We are requesting data for the specific page of the table.
            var sortString = '[' + JSON.stringify($scope.sortOptions) + ']';
            tableService.queryjsonp({
                // This will also need to be adjusted to deal with mutiple tables on the same page
                table: $scope.tableName,
                pageSize: $scope.pagingOptions.pageSize,
                pageNumber: $scope.pagingOptions.currentPage,
                sort : sortString,
                search: searchText
            }, function(largeLoad) {
                // We have received table data and add the data to the scope
                $scope.dataFill = largeLoad.data;
                $scope.totalServerItems = largeLoad.totalRows;
                $scope.isLoad = false;
            });
        }
        $scope.afterSelectionChange = function (rowItem) {
            if (rowItem.selected)  {  // I don't know if this is true or just truey
                //write code to execute only when selected.
                //rowItem.entity is the "data" here
            } else {
                //write code on deselection.
            }
        }

        $scope.$watch('pagingOptions', function(newVal, oldVal) {
            if (newVal !== oldVal) {
                $scope.getData();
            }
        }, true);

        $scope.$watch('filterOptions', function(newVal, oldVal) {
            if (newVal !== oldVal) {
                $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
            }
        }, true);

        // $scope.$watch('sortOptions', function(newVal, oldVal) {
        //     if (isSort && newVal !== oldVal) {
        //         $scope.getData();
        //         isSort = false;
        //         $scope.setIsSort();
        //     }
        // }, true);

        // $scope.setIsSort = function() {
        //     setTimeout(function(){isSort = true;}, 1500);
        // }

            // this is the intitialization of the table data above
            $scope.$on('loadData', function() {
            $scope.getConfigDataAsync();
        });

    }
 ]);

<|endoftext|>


<commit_before>/* global URLSearchParams */

'use strict';

import { Service } from 'components/mvc';

import Settings from './settings';
import Db from './db';
import Network from './network';
import Recipes from './recipes';
import WebPush from './webpush';

// Private members.
const p = Object.freeze({
  // Private properties.
  settings: Symbol('settings'),
  db: Symbol('db'),
  net: Symbol('net'),
  boxes: Symbol('boxes'),
  isPollingEnabled: Symbol('isPollingEnabled'),
  nextPollTimeout: Symbol('nextPollTimeout'),
  webPush: Symbol('webPush'),

  // Private methods.
  fetchServices: Symbol('fetchServices'),
  getOperationValueType: Symbol('getOperationValueType')
});

/**
 * Compare 2 objects. Returns true if all properties of object A have the same
 * value in object B. Extraneous properties in object B are ignored.
 * Properties order is not important.
 *
 * @param {Object} objectA
 * @param {Object} objectB
 * @return {boolean}
 */
const isSimilar = (objectA, objectB) => {
  for (let prop in objectA) {
    if (!(prop in objectB) || objectA[prop] !== objectB[prop]) {
      return false;
    }
  }

  return true;
};

export default class Foxbox extends Service {
  constructor() {
    super();

    // Private properties.
    this[p.settings] = new Settings();
    this[p.db] = new Db();
    this[p.net] = new Network(this[p.settings], foxboxOnline => {
      this._dispatchEvent('box-online', foxboxOnline);
    });
    this[p.boxes] = Object.freeze([]);
    this[p.isPollingEnabled] = false;
    this[p.nextPollTimeout] = null;
    this[p.webPush] = new WebPush(this[p.net], this[p.settings],
      (msg) => {
        this._dispatchEvent('push-action', msg);
      });

    // Public properties.
    this.recipes = null;

    Object.seal(this);
  }

  init() {
    window.foxbox = this;

    // No need to block the UI on the discovery process.
    // Once we discover a box we can connect to, we will start
    // polling and triggering box-online events with a boolean
    // indicating if we have access to box or not.
    this._initDiscovery().then(() => {
      return this[p.net].init();
    })
    .then(() => {
      // Start polling.
      this[p.settings].on('pollingEnabled', () => {
        this.togglePolling(this[p.settings].pollingEnabled);
      });
      this.togglePolling(this[p.settings].pollingEnabled);

      this.recipes = new Recipes({
        settings: this[p.settings],
        net: this[p.net]
      });
    });

    return this._initUserSession()
      .then(() => {
        // The DB is only initialised if there's no redirection to the box.
        return this[p.db].init();
      });
  }

  /**
   * Clear all data/settings stored on the browser. Use with caution.
   */
  clear(ignoreServiceWorker) {
    let promises = [this[p.settings].clear(), this[p.db].clear()];
    if (!navigator.serviceWorker) {
      return Promise.all(promises);
    }

    if (!ignoreServiceWorker) {
      promises.push(navigator.serviceWorker.ready
        .then((registration) => registration.unregister()));
    }

    return Promise.all(promises);
  }

  get localOrigin() {
    return this[p.settings].localOrigin;
  }

  get clientId() {
    return this[p.settings].clientId;
  }

  get boxes() {
    return this[p.boxes];
  }

  /**
   * Get the URL of the box using the registration server.
   * If it fails, we fallback to the previously set hostname.
   * It there isn't, we schedule a retry.
   *
   * @returns {Promise}
   * @private
   */
  _initDiscovery() {
    // For development purposes if you want to skip the
    // discovery phase set the 'foxbox-skipDiscovery' variable to
    // 'true'.
    if (this[p.settings].skipDiscovery) {
      return Promise.resolve();
    }

    return this[p.net].fetchJSON(this[p.settings].registrationService)
      .then((boxes) => {
        if (!Array.isArray(boxes)) {
          console.warn('Got unexpected response from registry server', boxes);
          return;
        }

        // We filter out boxes registered more than 2 minutes ago.
        const now = Math.floor(Date.now() / 1000) - 60 * 2;
        this[p.boxes] = Object.freeze(
          boxes
            .filter(box => box.timestamp - now >= 0)
            .map(box => {
                // NOTE(sgiles): There is consideration to allow
                // only "local_origin" and "tunnel_origin", removing the
                // need to parse message - this merges the relevant message
                // fields into the main object
                const { local_origin, tunnel_origin } =
                  JSON.parse(box.message);
                box.local_origin  = local_origin;
                box.tunnel_origin = tunnel_origin;
                return Object.freeze(box);
            })
        );

        // If the registration server didn't give us any info and
        // we have no record of previous registrations, we schedule
        // a retry.
        if (!this[p.boxes].length &&
            !this[p.settings]._localOrigin &&
            !this[p.settings]._tunnelOrigin) {
          console.warn('No boxes found. Retrying...');
          return new Promise((resolve) => {
            setTimeout(() => {
              this._initDiscovery().then(resolve, resolve);
            }, 1000);
          });
        }

        if (!this[p.settings].configured) {
          this.selectBox();
        }

        this._dispatchEvent('box-online', true);
      })
      .catch(() => {
        // Default to a previously stored box registration.
        if (this[p.settings]._localOrigin ||
            this[p.settings]._tunnelOrigin) {
          this._dispatchEvent('box-online', true);
        }
      });
  }

  /**
   * Change the currently selected box.
   *
   * @param {number} index The index of the box in the boxes array.
   */
  selectBox(index = 0) {
    if (!this[p.boxes].length) {
      this[p.settings].configured = false;
      console.error('No boxes found. Is this app online? Is the box online?');

      return;
    }

    if (index >= this[p.boxes].length) {
      this[p.settings].configured = false;
      console.error('Index out of range.');

      return;
    }

    const box = this[p.boxes][index];

    this[p.settings].localOrigin = box.local_origin;
    if (box.tunnel_origin) {
      this[p.settings].tunnelOrigin = box.tunnel_origin;
    } else {
      this[p.settings].tunnelOrigin = '';
    }

    this[p.settings].clientId = box.client;
    this[p.settings].configured = true;
  }

  /**
   * Detect a session token in the URL and process it if present.
   *
   * @return {Promise}
   * @private
   */
  _initUserSession() {
    if (this.isLoggedIn) {
      return Promise.resolve();
    }

    const queryString = location.search.substring(1);
    const searchParams = new URLSearchParams(queryString);

    if (searchParams.has('session_token')) {
      // There is a session token in the URL, let's remember it.
      // @todo Find a better way to handle URL escape.
      this[p.settings].session = searchParams.get('session_token')
        .replace(/ /g, '+');

      // Remove the session param from the current location.
      searchParams.delete('session_token');
      location.search = searchParams.toString();

      // Throwing here to abort the promise chain.
      throw(new Error('Redirecting to a URL without session'));
    }

    return Promise.resolve();
  }

  get isLoggedIn() {
    return !!this[p.settings].session;
  }

  /**
   * Redirect the user to the box to get authenticated if she isn't already.
   */
  login() {
    if (this.isLoggedIn) {
      return;
    }

    const redirectUrl = encodeURIComponent(location);
    location.replace(`${this[p.net].origin}/?redirect_url=${redirectUrl}`);
  }

  /**
   * Log out the user.
   */
  logout() {
    this[p.settings].session = undefined;
  }

  /**
   * Start or stop polling.
   *
   * @param {boolean} pollingEnabled Flag that indicates whether polling should
   * be started or stopped.
   */
  togglePolling(pollingEnabled) {
    this[p.isPollingEnabled] = pollingEnabled;

    if (pollingEnabled) {
      this.schedulePoll();
    } else {
      // Cancel next poll attempt if it has been scheduled.
      clearTimeout(this[p.nextPollTimeout]);
      this[p.nextPollTimeout] = null;
    }
  }

  /**
   * Schedules an attempt to poll the server, does nothing if polling is not
   * enabled or it has already been scheduled. New poll is scheduled only once
   * previous one is completed or failed.
   */
  schedulePoll() {
    // Return early if polling is not enabled or it has already been scheduled.
    if (!this[p.isPollingEnabled]
      || this[p.nextPollTimeout]
      || !this.isLoggedIn) {
      return;
    }

    this[p.nextPollTimeout] = setTimeout(() => {
      this.refreshServicesByPolling()
        .catch((e) => {
          console.error('Polling has failed, scheduling one more attempt: ', e);
        })
        .then(() => {
          this[p.nextPollTimeout] = null;

          this.schedulePoll();
        });
    }, this[p.settings].pollingInterval);
  }

  /**
   * Detect changes in the services:
   * * Emits a `service-change` event if a service is connected/disconnected.
   * * Emits a `service-state-change` event if the state of a service changes.
   *
   * @return {Promise}
   */
  refreshServicesByPolling() {
    if (!this.isLoggedIn) {
      return Promise.resolve();
    }

    /*const fetchedServicesPromise = this[p.net]
      .fetchJSON(`${this[p.net].origin}/services/list`)
      .then((services) => {
        // @todo We should ask for state only for services that actually support
        // it.
        return Promise.all(
          services.map((service) => {
            // Use empty state if service failed to return actual state.
            return this.getServiceState(service.id)
              .catch(() => ({}))
              .then((state) => service.state = state);
          })
        ).then(() => services);
      });*/

    return Promise.all([this.getServices(), this[p.fetchServices]()])
      .then(([storedServices, fetchedServices]) => {
        let hasNewServices = fetchedServices.reduce(
          (hasNewServices, fetchedService) => {
            const storedService = storedServices.find(
              s => s.id === fetchedService.id
            );

            const isExistingService = !!storedService;

            if (isExistingService &&
              isSimilar(fetchedService.state, storedService.state)) {
              return hasNewServices;
            }

            fetchedService = isExistingService ?
              Object.assign(storedService, fetchedService) : fetchedService;

            this._dispatchEvent('service-state-change', fetchedService);

            // Populate the db with the latest service.
            this[p.db].setService(fetchedService);

            return hasNewServices || !isExistingService;
          },
          false /* hasNewServices */
        );

        if (hasNewServices ||
          fetchedServices.length !== storedServices.length) {
          // The state of the services changes.
          this._dispatchEvent('service-change', fetchedServices);
        }

        return fetchedServices;
      });
  }

  /**
   * Retrieve the list of the services available.
   * Use the database as a source of truth.
   *
   * @return {Promise} A promise that resolves with an array of objects.
   */
  getServices() {
    return this[p.db].getServices()
      .then(services => {
        return services.map(service => service.data);
      });
  }

  getTags() {
    return this[p.db].getTags.apply(this[p.db], arguments);
  }

  getService() {
    // Get data from the DB so we get the attributes, the state and the tags.
    return this[p.db].getService.apply(this[p.db], arguments);
  }

  setService() {
    return this[p.db].setService.apply(this[p.db], arguments);
  }

  setTag() {
    return this[p.db].setTag.apply(this[p.db], arguments);
  }

  /**
   * Ask the user for acepting push notifications from the box.
   * This method will be call each time that we log in, but will
   * stop the execution if we already have the push subcription
   * information.
   *
   * @param {boolean} resubscribe Parameter used for testing
   * purposes, and follow the whole subscrition process even if
   * we have push subscription information.
   */
  subscribeToNotifications(resubscribe = false) {
    return this[p.webPush].subscribeToNotifications(resubscribe);
  }

  performSetOperation(operation, value) {
    let operationType = this[p.getOperationValueType](operation.kind);
    return this[p.net].fetchJSON(
      `${this[p.net].origin}/api/v${this[p.settings].apiVersion}/channels/set`,
      'PUT',
      // Query operation by id.
      [[{ id: operation.id }, { [operationType]: value }]]
    );
  }

  performGetOperation(operation) {
    let payload = { id: operation.id };

    if (operation.kind.type === 'Binary') {
      return this[p.net].fetchBlob(
        `${this[p.net].origin}/api/v${this[p.settings].apiVersion}` +
        '/channels/get',
        // For now we only support JPEG blobs.
        'image/jpeg',
        'PUT',
        payload
      );
    }

    return this[p.net].fetchJSON(
      `${this[p.net].origin}/api/v${this[p.settings].apiVersion}/channels/get`,
      'PUT',
      payload
    );
  }

  [p.fetchServices]() {
    return this[p.net].fetchJSON(
      `${this[p.net].origin}/api/v${this[p.settings].apiVersion}/services`)
      .then((services) => {
        return services.map((service) => {
          // Some service don't have name, but can have product_name instead,
          // eventually we should get rid of this line and use unified service
          // label field provided by taxonomy.
          service.properties.name = service.properties.name ||
            service.properties.product_name;

          return {
            id: service.id,
            type: service.adapter,
            getters: service.getters,
            setters: service.setters,
            properties: service.properties
          };
        });
      });
  }

  /**
   * Returns value type string for the specified operation kind.
   *
   * @param {string|Object} operationKind Kind of the operation, string for the
   * well known type and object for the Extension channel kind.
   * @return {string}
   * @private
   */
  [p.getOperationValueType](operationKind) {
    if (!operationKind) {
      throw new Error('Operation kind is not defined!');
    }

    // Operation kind can be either object or string.
    if (typeof operationKind === 'object') {
      return operationKind.type;
    }

    switch (operationKind) {
      case 'TakeSnapshot':
        return 'Unit';
      case 'LightOn':
        return 'OnOff';
      default:
        return operationKind;
    }
  }
}
<commit_msg>Do not ping to <origin>/null/ping if reg server ping fails. r=azasypkin (#106)<commit_after>/* global URLSearchParams */

'use strict';

import { Service } from 'components/mvc';

import Settings from './settings';
import Db from './db';
import Network from './network';
import Recipes from './recipes';
import WebPush from './webpush';

// Private members.
const p = Object.freeze({
  // Private properties.
  settings: Symbol('settings'),
  db: Symbol('db'),
  net: Symbol('net'),
  boxes: Symbol('boxes'),
  isPollingEnabled: Symbol('isPollingEnabled'),
  nextPollTimeout: Symbol('nextPollTimeout'),
  webPush: Symbol('webPush'),

  // Private methods.
  fetchServices: Symbol('fetchServices'),
  getOperationValueType: Symbol('getOperationValueType')
});

/**
 * Compare 2 objects. Returns true if all properties of object A have the same
 * value in object B. Extraneous properties in object B are ignored.
 * Properties order is not important.
 *
 * @param {Object} objectA
 * @param {Object} objectB
 * @return {boolean}
 */
const isSimilar = (objectA, objectB) => {
  for (let prop in objectA) {
    if (!(prop in objectB) || objectA[prop] !== objectB[prop]) {
      return false;
    }
  }

  return true;
};

export default class Foxbox extends Service {
  constructor() {
    super();

    // Private properties.
    this[p.settings] = new Settings();
    this[p.db] = new Db();
    this[p.net] = new Network(this[p.settings], foxboxOnline => {
      this._dispatchEvent('box-online', foxboxOnline);
    });
    this[p.boxes] = Object.freeze([]);
    this[p.isPollingEnabled] = false;
    this[p.nextPollTimeout] = null;
    this[p.webPush] = new WebPush(this[p.net], this[p.settings],
      (msg) => {
        this._dispatchEvent('push-action', msg);
      });

    // Public properties.
    this.recipes = null;

    Object.seal(this);
  }

  init() {
    window.foxbox = this;

    // No need to block the UI on the discovery process.
    // Once we discover a box we can connect to, we will start
    // polling and triggering box-online events with a boolean
    // indicating if we have access to box or not.
    this._initDiscovery().then(() => {
      return this[p.net].init();
    })
    .then(() => {
      // Start polling.
      this[p.settings].on('pollingEnabled', () => {
        this.togglePolling(this[p.settings].pollingEnabled);
      });
      this.togglePolling(this[p.settings].pollingEnabled);

      this.recipes = new Recipes({
        settings: this[p.settings],
        net: this[p.net]
      });
    });

    return this._initUserSession()
      .then(() => {
        // The DB is only initialised if there's no redirection to the box.
        return this[p.db].init();
      });
  }

  /**
   * Clear all data/settings stored on the browser. Use with caution.
   */
  clear(ignoreServiceWorker) {
    let promises = [this[p.settings].clear(), this[p.db].clear()];
    if (!navigator.serviceWorker) {
      return Promise.all(promises);
    }

    if (!ignoreServiceWorker) {
      promises.push(navigator.serviceWorker.ready
        .then((registration) => registration.unregister()));
    }

    return Promise.all(promises);
  }

  get localOrigin() {
    return this[p.settings].localOrigin;
  }

  get clientId() {
    return this[p.settings].clientId;
  }

  get boxes() {
    return this[p.boxes];
  }

  /**
   * Get the URL of the box using the registration server.
   * If it fails, we fallback to the previously set hostname.
   * It there isn't, we schedule a retry.
   *
   * @returns {Promise}
   * @private
   */
  _initDiscovery() {
    // For development purposes if you want to skip the
    // discovery phase set the 'foxbox-skipDiscovery' variable to
    // 'true'.
    if (this[p.settings].skipDiscovery) {
      return Promise.resolve();
    }

    return this[p.net].fetchJSON(this[p.settings].registrationService)
      .then((boxes) => {
        if (!Array.isArray(boxes)) {
          console.warn('Got unexpected response from registry server', boxes);
          return;
        }

        // We filter out boxes registered more than 2 minutes ago.
        const now = Math.floor(Date.now() / 1000) - 60 * 2;
        this[p.boxes] = Object.freeze(
          boxes
            .filter(box => box.timestamp - now >= 0)
            .map(box => {
                // NOTE(sgiles): There is consideration to allow
                // only "local_origin" and "tunnel_origin", removing the
                // need to parse message - this merges the relevant message
                // fields into the main object
                const { local_origin, tunnel_origin } =
                  JSON.parse(box.message);
                box.local_origin  = local_origin;
                box.tunnel_origin = tunnel_origin;
                return Object.freeze(box);
            })
        );

        // If the registration server didn't give us any info and
        // we have no record of previous registrations, we schedule
        // a retry.
        if (!this[p.boxes].length &&
            !this[p.settings]._localOrigin &&
            !this[p.settings]._tunnelOrigin) {
          throw new Error('Registration service did not return any boxes.');
        }

        if (!this[p.settings].configured) {
          this.selectBox();
        }

        this._dispatchEvent('box-online', true);
      })
      .catch((e) => {
        if (this[p.settings]._localOrigin ||
            this[p.settings]._tunnelOrigin) {
          // Default to a previously stored box registration.
          this._dispatchEvent('box-online', true);
        } else {
          // If there's no previously stored box registration, we schedule a
          // retry.
          console.warn('Retrying box discovery... Reason is %o', e);
          return new Promise((resolve) => {
            setTimeout(() => {
              this._initDiscovery().then(resolve, resolve);
            }, 1000);
          });
        }
      });
  }

  /**
   * Change the currently selected box.
   *
   * @param {number} index The index of the box in the boxes array.
   */
  selectBox(index = 0) {
    if (!this[p.boxes].length) {
      this[p.settings].configured = false;
      console.error('No boxes found. Is this app online? Is the box online?');

      return;
    }

    if (index >= this[p.boxes].length) {
      this[p.settings].configured = false;
      console.error('Index out of range.');

      return;
    }

    const box = this[p.boxes][index];

    this[p.settings].localOrigin = box.local_origin;
    if (box.tunnel_origin) {
      this[p.settings].tunnelOrigin = box.tunnel_origin;
    } else {
      this[p.settings].tunnelOrigin = '';
    }

    this[p.settings].clientId = box.client;
    this[p.settings].configured = true;
  }

  /**
   * Detect a session token in the URL and process it if present.
   *
   * @return {Promise}
   * @private
   */
  _initUserSession() {
    if (this.isLoggedIn) {
      return Promise.resolve();
    }

    const queryString = location.search.substring(1);
    const searchParams = new URLSearchParams(queryString);

    if (searchParams.has('session_token')) {
      // There is a session token in the URL, let's remember it.
      // @todo Find a better way to handle URL escape.
      this[p.settings].session = searchParams.get('session_token')
        .replace(/ /g, '+');

      // Remove the session param from the current location.
      searchParams.delete('session_token');
      location.search = searchParams.toString();

      // Throwing here to abort the promise chain.
      throw(new Error('Redirecting to a URL without session'));
    }

    return Promise.resolve();
  }

  get isLoggedIn() {
    return !!this[p.settings].session;
  }

  /**
   * Redirect the user to the box to get authenticated if she isn't already.
   */
  login() {
    if (this.isLoggedIn) {
      return;
    }

    const redirectUrl = encodeURIComponent(location);
    location.replace(`${this[p.net].origin}/?redirect_url=${redirectUrl}`);
  }

  /**
   * Log out the user.
   */
  logout() {
    this[p.settings].session = undefined;
  }

  /**
   * Start or stop polling.
   *
   * @param {boolean} pollingEnabled Flag that indicates whether polling should
   * be started or stopped.
   */
  togglePolling(pollingEnabled) {
    this[p.isPollingEnabled] = pollingEnabled;

    if (pollingEnabled) {
      this.schedulePoll();
    } else {
      // Cancel next poll attempt if it has been scheduled.
      clearTimeout(this[p.nextPollTimeout]);
      this[p.nextPollTimeout] = null;
    }
  }

  /**
   * Schedules an attempt to poll the server, does nothing if polling is not
   * enabled or it has already been scheduled. New poll is scheduled only once
   * previous one is completed or failed.
   */
  schedulePoll() {
    // Return early if polling is not enabled or it has already been scheduled.
    if (!this[p.isPollingEnabled]
      || this[p.nextPollTimeout]
      || !this.isLoggedIn) {
      return;
    }

    this[p.nextPollTimeout] = setTimeout(() => {
      this.refreshServicesByPolling()
        .catch((e) => {
          console.error('Polling has failed, scheduling one more attempt: ', e);
        })
        .then(() => {
          this[p.nextPollTimeout] = null;

          this.schedulePoll();
        });
    }, this[p.settings].pollingInterval);
  }

  /**
   * Detect changes in the services:
   * * Emits a `service-change` event if a service is connected/disconnected.
   * * Emits a `service-state-change` event if the state of a service changes.
   *
   * @return {Promise}
   */
  refreshServicesByPolling() {
    if (!this.isLoggedIn) {
      return Promise.resolve();
    }

    /*const fetchedServicesPromise = this[p.net]
      .fetchJSON(`${this[p.net].origin}/services/list`)
      .then((services) => {
        // @todo We should ask for state only for services that actually support
        // it.
        return Promise.all(
          services.map((service) => {
            // Use empty state if service failed to return actual state.
            return this.getServiceState(service.id)
              .catch(() => ({}))
              .then((state) => service.state = state);
          })
        ).then(() => services);
      });*/

    return Promise.all([this.getServices(), this[p.fetchServices]()])
      .then(([storedServices, fetchedServices]) => {
        let hasNewServices = fetchedServices.reduce(
          (hasNewServices, fetchedService) => {
            const storedService = storedServices.find(
              s => s.id === fetchedService.id
            );

            const isExistingService = !!storedService;

            if (isExistingService &&
              isSimilar(fetchedService.state, storedService.state)) {
              return hasNewServices;
            }

            fetchedService = isExistingService ?
              Object.assign(storedService, fetchedService) : fetchedService;

            this._dispatchEvent('service-state-change', fetchedService);

            // Populate the db with the latest service.
            this[p.db].setService(fetchedService);

            return hasNewServices || !isExistingService;
          },
          false /* hasNewServices */
        );

        if (hasNewServices ||
          fetchedServices.length !== storedServices.length) {
          // The state of the services changes.
          this._dispatchEvent('service-change', fetchedServices);
        }

        return fetchedServices;
      });
  }

  /**
   * Retrieve the list of the services available.
   * Use the database as a source of truth.
   *
   * @return {Promise} A promise that resolves with an array of objects.
   */
  getServices() {
    return this[p.db].getServices()
      .then(services => {
        return services.map(service => service.data);
      });
  }

  getTags() {
    return this[p.db].getTags.apply(this[p.db], arguments);
  }

  getService() {
    // Get data from the DB so we get the attributes, the state and the tags.
    return this[p.db].getService.apply(this[p.db], arguments);
  }

  setService() {
    return this[p.db].setService.apply(this[p.db], arguments);
  }

  setTag() {
    return this[p.db].setTag.apply(this[p.db], arguments);
  }

  /**
   * Ask the user for acepting push notifications from the box.
   * This method will be call each time that we log in, but will
   * stop the execution if we already have the push subcription
   * information.
   *
   * @param {boolean} resubscribe Parameter used for testing
   * purposes, and follow the whole subscrition process even if
   * we have push subscription information.
   */
  subscribeToNotifications(resubscribe = false) {
    return this[p.webPush].subscribeToNotifications(resubscribe);
  }

  performSetOperation(operation, value) {
    let operationType = this[p.getOperationValueType](operation.kind);
    return this[p.net].fetchJSON(
      `${this[p.net].origin}/api/v${this[p.settings].apiVersion}/channels/set`,
      'PUT',
      // Query operation by id.
      [[{ id: operation.id }, { [operationType]: value }]]
    );
  }

  performGetOperation(operation) {
    let payload = { id: operation.id };

    if (operation.kind.type === 'Binary') {
      return this[p.net].fetchBlob(
        `${this[p.net].origin}/api/v${this[p.settings].apiVersion}` +
        '/channels/get',
        // For now we only support JPEG blobs.
        'image/jpeg',
        'PUT',
        payload
      );
    }

    return this[p.net].fetchJSON(
      `${this[p.net].origin}/api/v${this[p.settings].apiVersion}/channels/get`,
      'PUT',
      payload
    );
  }

  [p.fetchServices]() {
    return this[p.net].fetchJSON(
      `${this[p.net].origin}/api/v${this[p.settings].apiVersion}/services`)
      .then((services) => {
        return services.map((service) => {
          // Some service don't have name, but can have product_name instead,
          // eventually we should get rid of this line and use unified service
          // label field provided by taxonomy.
          service.properties.name = service.properties.name ||
            service.properties.product_name;

          return {
            id: service.id,
            type: service.adapter,
            getters: service.getters,
            setters: service.setters,
            properties: service.properties
          };
        });
      });
  }

  /**
   * Returns value type string for the specified operation kind.
   *
   * @param {string|Object} operationKind Kind of the operation, string for the
   * well known type and object for the Extension channel kind.
   * @return {string}
   * @private
   */
  [p.getOperationValueType](operationKind) {
    if (!operationKind) {
      throw new Error('Operation kind is not defined!');
    }

    // Operation kind can be either object or string.
    if (typeof operationKind === 'object') {
      return operationKind.type;
    }

    switch (operationKind) {
      case 'TakeSnapshot':
        return 'Unit';
      case 'LightOn':
        return 'OnOff';
      default:
        return operationKind;
    }
  }
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    //if (move == "rock" || move == "paper" || move == "scissors")
    if (move === null || move === '') {
    return getInput();
    }
    else {
    return move;
    }
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    if (move === null || move === '') {
    return randomPlay();
    }
    else {
    return move;
    }
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>unit 4 exercise<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    //if (move == "rock" || move == "paper" || move == "scissors")
    if (move === null || move === '') {
    return getInput();
    }
    else {
    return move;
    }
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    if (move === null || move === '') {
    return randomPlay();
    }
    else {
    return move;
    }
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    if (playerMove === computerMove) {
        return winner = "tie";
    }
    else if (playerMove === "rock") {
        if (computerMove === "paper") {
             winner = "computer";
        }
        else {
             winner = "player";
        }
    }
    else if (playerMove === "paper") {
        if (computerMove === "rock") {
             winner = "player";
        }
        else {
             winner = "computer";
        }
    }
    else if (playerMove === "scissors") {
        if (computerMove === "rock") {
             winner = "computer";
        }
        else {
             winner = "player";
        }
    }
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<|endoftext|>


<commit_before>// if(!ViewSpot) {
//   ViewSpot = new Mongo.Collection('ViewSpot');
// }

ViewSpot = new Mongo.Collection('ViewSpot');
Locality = new Mongo.Collection('Locality');
Hotel = new Mongo.Collection('Hotel');
Shopping = new Mongo.Collection('Shopping');
Restaurant = new Mongo.Collection('Restaurant');

var reviewItems = ['Locality', 'ViewSpot', 'Restaurant', 'Hotel', 'Shopping'];
var conn = [Locality, ViewSpot, Restaurant, Hotel, Shopping];

for(var i = 0, len = reviewItems.length; i < len; i++) {
  (function(dbConn, colName){
    new Meteor.FilterCollections(dbConn, {
      name:  colName + '-list',
      template: colName + 'leftRegionNavi',
      sort: {
        order: ['desc', 'asc'],
        defaults: [
          ['hotness', 'desc']
        ]
      },
      pager: {
        showPages: 7,
      },
      // fields: {'fields': {'_id': 1, 'zhName': 1, 'targets': 1, 'hotness': 1}},  //必须加targets和hotness
      filters: {
        "targets": {
          title: '地理信息',
          condition: '$and',
          searchable: 'true',
          transform: function (value) {
            return new Mongo.ObjectID(value);
          },
        },
        "locList.zhName": {
          title: '国家名字',
          condition: '$and',
          searchable: 'true'
        },
        "zhName": {
          title: '名字',
          operator: ['$regex', 'i'],
          condition: '$and',
          searchable: 'required'
        },
      },
    });
  })(conn[i], reviewItems[i]);
}<commit_msg>use new field[hotnessTag] for sort<commit_after>// if(!ViewSpot) {
//   ViewSpot = new Mongo.Collection('ViewSpot');
// }

ViewSpot = new Mongo.Collection('ViewSpot');
Locality = new Mongo.Collection('Locality');
Hotel = new Mongo.Collection('Hotel');
Shopping = new Mongo.Collection('Shopping');
Restaurant = new Mongo.Collection('Restaurant');

var reviewItems = ['Locality', 'ViewSpot', 'Restaurant', 'Hotel', 'Shopping'];
var conn = [Locality, ViewSpot, Restaurant, Hotel, Shopping];

for(var i = 0, len = reviewItems.length; i < len; i++) {
  (function(dbConn, colName){
    new Meteor.FilterCollections(dbConn, {
      name:  colName + '-list',
      template: colName + 'leftRegionNavi',
      sort: {
        order: ['desc', 'asc'],
        defaults: [
          ['hotnessTag', 'asc']
        ]
      },
      pager: {
        showPages: 7,
      },
      // fields: {'fields': {'_id': 1, 'zhName': 1, 'targets': 1, 'hotness': 1}},  //必须加targets和hotness
      filters: {
        "targets": {
          title: '地理信息',
          condition: '$and',
          searchable: 'true',
          transform: function (value) {
            return new Mongo.ObjectID(value);
          },
        },
        "locList.zhName": {
          title: '国家名字',
          condition: '$and',
          searchable: 'true'
        },
        "zhName": {
          title: '名字',
          operator: ['$regex', 'i'],
          condition: '$and',
          searchable: 'required'
        },
      },
    });
  })(conn[i], reviewItems[i]);
}<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return /* Your Expression */;
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return /* Your Expression */;
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>Unit 4 Homework<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    if (playerMove === computerMove) {
        return "It's a tie!";
    }
    else if (playerMove === 'rock' && computerMove === 'scissors') {
        winner = player;
    }
    else if (playerMove === 'paper' && computerMove === 'rock') {
        winner = player;
    }
    else if (playerMove === 'scissors' && computerMove === 'paper') {
        winner = player;
    }
    else {
        winner = computer;
    }
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.

    if (playerMove == "paper" && computerMove == "rock") {
        winner = "player"
        console.log("Player Wins!");}

    else if (playerMove == "paper" && computerMove == "scissors") {
        winner = "computer"
        console.log("Computer Wins");}

    else if (playerMove == "rock" && computerMove == "paper"){
        winner = "player"
        console.log("Player Wins!");}

    else if (playerMove == "rock" && computerMove == "scissors"){
        winner = "computer"
        console.log("Computer Wins");}

    else if (playerMove == "scissors" && computerMove == "paper"){
        winner = "player"
        console.log("Player Wins!");}

    else if (playerMove == "scissors" && computerMove == "rock"){
        winner = "computer"
        console.log("Computer Wins");}

    else {
        winner = "tie"
        console.log("It's a tie!");}

    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
while (playerWins > 5 && computerWins > 5) {
    var playerMove = getPlayerMove();
    var computerMove = getComputerMove();
    var winner = getwinner(playerMove, computerMove);

    if (winner === 'player') {
        playerWins += 1;
    }
    else if (winner === 'computer') {
        computerWins += 1;
    }

    console.log ("Player chose " + playerMove " and Computer chose " + computerMove + ".");

    console.log ("Scoreboard: Player " + playersWins + ", Computer " + computerWins);
}

    if (playerWins === 5){
        console.log ("Player wins! All is safe on planet Earth");
}
    else (computerWins === 5) {
        console.log ("Uh oh, Computer wins, time to move. Earth 452b, here we come.");
}
    return [playerWins, computerWins];
<commit_msg>Edited playToFive, game works now<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.

    if (playerMove == "paper" && computerMove == "rock") {
        winner = "player"
        console.log("Player Wins!");}

    else if (playerMove == "paper" && computerMove == "scissors") {
        winner = "computer"
        console.log("Computer Wins");}

    else if (playerMove == "rock" && computerMove == "paper"){
        winner = "player"
        console.log("Player Wins!");}

    else if (playerMove == "rock" && computerMove == "scissors"){
        winner = "computer"
        console.log("Computer Wins");}

    else if (playerMove == "scissors" && computerMove == "paper"){
        winner = "player"
        console.log("Player Wins!");}

    else if (playerMove == "scissors" && computerMove == "rock"){
        winner = "computer"
        console.log("Computer Wins");}

    else {
        winner = "tie"
        console.log("It's a tie!");}

    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
while (playerWins < 5 && computerWins < 5) {
    var playerMove = getPlayerMove();
    var computerMove = getComputerMove();
    var winner = getWinner(playerMove,computerMove);

    if (winner === 'player') {
        playerWins += 1;
    } else if (winner === 'computer') {
        computerWins += 1;
    }

    console.log ("Player chose " + playerMove + " and Computer chose " + computerMove + ".");

    console.log ("Scoreboard: Player " + playerWins + ", Computer " + computerWins);
    }

    if (playerWins === 5){
        console.log ("Player wins! All is safe on planet Earth");
    }else (computerWins === 5); {
        console.log ("Uh oh, Computer wins, time to move. Earth 452b, here we come.")
    }
}<|endoftext|>


<commit_before>import * as dispatcher from 'source/browser/events/polyfill';
import parsePath from 'source/browser/path/parse';

const ua = window.navigator.userAgent;
export const native = window.history;
export const HashChangeEvent = 'hashchange';
export const HashChangeHook = `on${HashChangeEvent}`;
export const PopStateEvent = 'popstate';
export const PopStateHook = `on${PopStateEvent}`;
export const ReplaceStateEvent = 'replacestate';
export const ChangeStateEvent = 'changestate';
export const PushStateEvent = 'pushstate';

/*!
 * @name hasStateList
 *
 * @description
 *
 * @return {Boolean}
 *
 * @see http://caniuse.com/#search=history
 *
 * @api public
`*/
export const hasStateList = 'pushState' in Object(native) &&
	!/Android\s(2\..+|4\.0)|Mobile\sSafari/gi.test(ua) &&
	/Windows\sPhone|Chrome/gi.test(ua)
;

/*!
 * @name updateStateList
 *
 * @description
 *
 * @api private
`*/
export function updateStateList(URL, put) {
	put(parsePath(URL)); // @TODO: storage
}

/*!
 * @name pushState
 *
 * @description
 *
 * @api public
`*/
export function pushState(state, title, URL) {
	return updateStateList(URL, () => {
		native.pushState(state, title, URL);
		dispatcher.dispatchEvent(window, PushStateEvent, { state, title, URL });
		dispatcher.dispatchEvent(window, ChangeStateEvent, { state, title, URL });
	});
}

/*!
 * @name replaceState
 *
 * @description
 *
 * @api public
`*/
export function replaceState(state, title, URL) {
	return updateStateList(URL, () => {
		native.replaceState(state, title, URL);
		dispatcher.dispatchEvent(window, ReplaceStateEvent, { state, title, URL });
		dispatcher.dispatchEvent(window, ChangeStateEvent, { state, title, URL });
	});
}

/*!
 * @name go
 *
 * @description
 *
 * @api public
`*/
export function go(factor) {
	return native.go(factor);
}

/*!
 * @name forward
 *
 * @description
 *
 * @api public
`*/
export function forward() {
	return native.forward();
}

/*!
 * @name back
 *
 * @description
 *
 * @api public
`*/
export function back() {
	return native.back();
}
<commit_msg>docs: comments<commit_after>import * as dispatcher from 'source/browser/events/polyfill';
import parsePath from 'source/browser/path/parse';

export const HashChangeEvent = 'hashchange';
export const HashChangeHook = `on${HashChangeEvent}`;
export const PopStateEvent = 'popstate';
export const PopStateHook = `on${PopStateEvent}`;
export const ReplaceStateEvent = 'replacestate';
export const ChangeStateEvent = 'changestate';
export const PushStateEvent = 'pushstate';

/*!
 * @name ua
 *
 * @description
 *
 * @api private
`*/
const ua = window.navigator.userAgent;

/*!
 * @name native
 *
 * @description
 *
 * @api public
`*/
export const native = window.history;

/*!
 * @name hasStateList
 *
 * @description
 *
 * @return {Boolean}
 *
 * @see http://caniuse.com/#search=history
 *
 * @api public
`*/
export const hasStateList = 'pushState' in Object(native) &&
	!/Android\s(2\..+|4\.0)|Mobile\sSafari/gi.test(ua) &&
	/Windows\sPhone|Chrome/gi.test(ua)
;

/*!
 * @name updateStateList
 *
 * @description
 *
 * @api private
`*/
export function updateStateList(URL, put) {
	put(parsePath(URL)); // @TODO: storage
}

/*!
 * @name pushState
 *
 * @description
 *
 * @api public
`*/
export function pushState(state, title, URL) {
	return updateStateList(URL, () => {
		native.pushState(state, title, URL);
		dispatcher.dispatchEvent(window, PushStateEvent, { state, title, URL });
		dispatcher.dispatchEvent(window, ChangeStateEvent, { state, title, URL });
	});
}

/*!
 * @name replaceState
 *
 * @description
 *
 * @api public
`*/
export function replaceState(state, title, URL) {
	return updateStateList(URL, () => {
		native.replaceState(state, title, URL);
		dispatcher.dispatchEvent(window, ReplaceStateEvent, { state, title, URL });
		dispatcher.dispatchEvent(window, ChangeStateEvent, { state, title, URL });
	});
}

/*!
 * @name go
 *
 * @description
 *
 * @api public
`*/
export function go(factor) {
	return native.go(factor);
}

/*!
 * @name forward
 *
 * @description
 *
 * @api public
`*/
export function forward() {
	return native.forward();
}

/*!
 * @name back
 *
 * @description
 *
 * @api public
`*/
export function back() {
	return native.back();
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    var move;
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
	var move;
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if (playerMove === computerMove) {
    	winner = "tie";
    }
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>Commit after Unit 4<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    var move;
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
	var move;
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if (playerMove === computerMove) {
    	winner = 'tie';
    } else if (playerMove === 'rock') {
    	if (computerMove === 'paper') {
    		winner = 'computer';
    	} else
    		winner = 'player';
    	}
    } else if (playerMove === 'paper') {
    	if (computerMove === 'scissors') {
    		winner = 'computer';
    	} else
    		winner = 'player';
    	}
    } else if (playerMove === 'scissors') {
    	if (computerMove === 'rock') {
    		winner = 'computer';
    	} else
    		winner = 'player';
    	}
    }

    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    console.log("player chose " + playerMove);
    console.log("computer chose " + computerMove);
    if ( ((playerMove === 'rock') && (computerMove === 'scissors')) || ((playerMove === 'paper') && (computerMove === 'rock')) || ((playerMove === 'scissors') && (computerMove === 'paper')) ) {
        winner = 'player'; console.log("player wins.")
    } else if (playerMove === computerMove) {
        winner = 'tie'; console.log("it's a tie.")
    }
    else {
        winner = 'computer'; console.log("computer wins.")
    }
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    function play(winner) { var winner = getWinner(getPlayerMove(),getComputerMove()) };

    while (playerWins < 5 || computerWins < 5) {

    play();

    if (winner === 'player') {
        playerWins++;
    } else if (winner === 'computer') {
        computerWins++;
    } else {
        console.log("Play again.");
    }
    return [playerWins, computerWins];
};
}

playToFive();<commit_msg>Fixed bug where loop wasn't working properly.<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

var winner;

function getWinner(playerMove,computerMove) {
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    console.log("Player chose " + playerMove + ".");
    console.log("Computer chose " + computerMove + ".");
    if ( ((playerMove === 'rock') && (computerMove === 'scissors')) || ((playerMove === 'paper') && (computerMove === 'rock')) || ((playerMove === 'scissors') && (computerMove === 'paper')) ) {
        winner = 'player'; console.log("Player wins.")
    } else if (playerMove === computerMove) {
        winner = 'tie'; console.log("It's a tie.")
    }
    else {
        winner = 'computer'; console.log("Computer wins.")
    }
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    var round = 0;

    while (playerWins < 5 && computerWins < 5) {

    round += 1;
    console.log("Round " + round + ":");

    getWinner(getPlayerMove(),getComputerMove());

    if (winner === 'player') {
        playerWins++; console.log("Player's score is now " + playerWins + ".");
    } else if (winner === 'computer') {
        computerWins++; console.log("Computer's score is now " + computerWins + ".");
    } else {
        console.log("Play again.");
    }
}
}

playToFive();<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move = move || getInput();/* Your Expression */
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move = move || randomPlay();/* Your Expression */
}

function getWinner(playerMove,computerMove) { // opening fuctions statement
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    if (playerMove == computerMove) {
        winner = 'tie';
    } else if (playerMove == 'rock') {
        if (computerMove == 'paper') {
            winner = 'computer';
        } else if (computerMove == 'scissors') {
            winner = 'player';
        }
    } else if (playerMove == 'paper') {
        if (computerMove == 'rock') {
            winner = 'player';
        } else if (computerMove == 'scissors') {
            winner = 'computer';
        }
    } else if (playerMove == 'scissors') {
        if (computerMove == 'rock') {
            winner = 'computer';
        } else if (computerMove == 'paper') {
            winner = 'player';
        }
    }
    return winner;
} // closing function statement

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>HW Unit 5.5 - added code to playToFive function<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    if (playerMove == computerMove) {
        winner = 'tie';
    } else if (playerMove == 'rock') {
        if (computerMove == 'paper') {
            winner = 'computer';
        } else if (computerMove == 'scissors') {
            winner = 'player';
        }
    } else if (playerMove == 'paper') {
        if (computerMove == 'rock') {
            winner = 'player';
        } else if (computerMove == 'scissors') {
            winner = 'computer';
        }
    } else if (playerMove == 'scissors') {
        if (computerMove == 'rock') {
            winner = 'computer';
        } else if (computerMove == 'paper') {
            winner = 'player';
        }
    }
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;

    while (playerWins <5 && computerWins <5) {
        playerMove = getPlayerMove();
        computerMove = getComputerMove();
        roundWinner = getWinner(playerMove, computerMove);
        if (roundWinner == "computer") {
            computerWins += 1;
        }
        else if (roundWinner == "player") {
         playerWins += 1;
        }
        console.log("Player chose " + playerMove + " while computer chose " + computerMove);
        console.log("The score is currently " + playerWins +" to "+ computerWins + "\n");
    }
    return [playerWins, computerWins];
}

playToFive();

<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();

}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if (playerMove === "rock") {
        if (computerMove === "rock") {
            winner = "tie";
        }
        else if (computerMove === "scissors") {
            winner = "player";
        }
        else if (computerMove === "paper") {
            winner = "computer";
        }
    }
    if (playerMove === "paper") {
        if (computerMove === "rock") {
            winner = "player";
        }
        else if (computerMove === "scissors") {
            winner = "computer";
        }
        else if (computerMove ==="paper") {
            winner = "tie";
        }
    }
    if (playerMove === "scissors") {
        if (computerMove === "rock") {
            winner = "computer";
        }
        else if (computerMove === "scissors") {
            winner = "tie";
        }
        else if (computerMove === "paper") {
            winner = "player";
        }
    }
return winner;

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    var playerMove = getPlayerMove();
    var computerMove = getComputerMove();
    var winner = getWinner();
    while (playerWins<5 && computerWins<5) {
        if (winner = "player") {
            playerWins += 1;
            console.log('Player chose ' + playerMove + ' while Computer chose ' + computerMove);
            console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
        }
        if (winner = "computer") {
            computerWins +=1;
            console.log('Player chose ' + playerMove + ' while Computer chose ' + computerMove);
            console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
        }
        if (winner = "tie") {
            computerWins +=1;
            playerWins +=1;
            console.log('Player chose ' + playerMove + ' while Computer chose ' + computerMove);
            console.log('You tied. ' + 'The score is currently ' + playerWins + ' to ' + computerWins + '\n');
        }
            if (playerWins === 5 && computerWins < 5) {
        console.log("You win!");
    } else if (playerWins < 5 && computerWins === 5) {
        console.log("You lose, try again.");
    } else if (playerWins === computerWins) {
        console.log("It's a tie!");
    }
    return [playerWins, computerWins];
}
}
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    <commit_msg>now it works<commit_after>'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}

function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();

}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if (playerMove === "rock") {
        if (computerMove === "rock") {
            return "tie";
        }
        else if (computerMove === "scissors") {
            return "player";
        }
        else if (computerMove === "paper") {
            return "computer";
        }
    }
    if (playerMove === "paper") {
        if (computerMove === "rock") {
            return "player";
        }
        else if (computerMove === "scissors") {
            return "computer";
        }
        else if (computerMove ==="paper") {
            return "tie";
        }
    }
    if (playerMove === "scissors") {
        if (computerMove === "rock") {
            return "computer";
        }
        else if (computerMove === "scissors") {
            return "tie";
        }
        else if (computerMove === "paper") {
            return "player";
        }
    }
    return winner;
}
function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    while (playerWins<5 && computerWins<5) {
        var playerMove = getPlayerMove(move);
        var computerMove = getComputerMove(move);
        var winner = getWinner(playerMove, computerMove);
        console.log("playerWins", playerWins);
        console.log("computerWins", computerWins);
        console.log("winner:", winner);
        if (winner === undefined){
             console.log("Not a Valid Move! Player:" + playerMove + ", Computer:" + computerMove);
        }
        if (winner === "player") {
            playerWins += 1;
            console.log('Player chose ' + playerMove + ' while Computer chose ' + computerMove);
            console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
        }
        if (winner === "computer") {
            computerWins +=1;
            console.log('Player chose ' + playerMove + ' while Computer chose ' + computerMove);
            console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
        }
        if (winner === "tie") {
            computerWins +=1;
            playerWins +=1;
            console.log('Player chose ' + playerMove + ' while Computer chose ' + computerMove);
            console.log('You tied. ' + 'The score is currently ' + playerWins + ' to ' + computerWins + '\n');
        }
        if (playerWins === 5 && computerWins < 5) {
            console.log("You win!");
        } else if (playerWins < 5 && computerWins === 5) {
            console.log("You lose, try again.");
        } else if (playerWins === computerWins) {
            console.log("It's a tie!");
        }

    }
    return [playerWins, computerWins];

}
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
// console.log("win1:", getWinner("foo", "bar"));
// console.log("win2:", getWinner("rock", "paper"));
playToFive();
<|endoftext|>


<commit_before>export default class ShadowOverlay extends createjs.Container {
  constructor(width, height) {
    super();

    this.shadow = new createjs.Shape();
    this.shadow.graphics.beginFill('rgba(0,0,0,0.6)').drawRect(0, 0, width, height);

    this.shadowText = new createjs.Text('', '25px Arial', '#fff');
    this.shadowText.y = height / 2;
    this.shadowText.x = width / 2;
    this.shadowText.textAlign = 'center';
    this.shadowText.textBaseline = 'middle';

    this.addChild(this.shadow, this.shadowText);
  }
  setText(text) {
    this.shadowText.text = text;
  }
}
<commit_msg>add spaces<commit_after>export default class ShadowOverlay extends createjs.Container {
  constructor(width, height) {
    super();

    this.shadow = new createjs.Shape();
    this.shadow.graphics.beginFill('rgba(0, 0, 0, 0.6)').drawRect(0, 0, width, height);

    this.shadowText = new createjs.Text('', '25px Arial', '#fff');
    this.shadowText.y = height / 2;
    this.shadowText.x = width / 2;
    this.shadowText.textAlign = 'center';
    this.shadowText.textBaseline = 'middle';

    this.addChild(this.shadow, this.shadowText);
  }
  setText(text) {
    this.shadowText.text = text;
  }
}
<|endoftext|>