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

/**
 * @fileoverview MockUserAgent overrides goog.userAgent.getUserAgentString()
 *     depending on a specified configuration.
 *
 */

goog.setTestOnly('goog.testing.MockUserAgent');
goog.provide('goog.testing.MockUserAgent');

goog.require('goog.Disposable');
goog.require('goog.labs.userAgent.util');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.userAgent');

/**
 * Class for unit testing code that uses goog.userAgent.
 *
 * @extends {goog.Disposable}
 * @constructor
 * @final
 */
goog.testing.MockUserAgent = function() {
  goog.Disposable.call(this);

  /**
   * Property replacer used to mock out User-Agent functions.
   * @type {!goog.testing.PropertyReplacer}
   * @private
   */
  this.propertyReplacer_ = new goog.testing.PropertyReplacer();

  /**
   * The userAgent string used by goog.userAgent.
   * @type {?string}
   * @private
   */
  this.userAgent_ = goog.userAgent.getUserAgentString();

  /**
   * The navigator object used by goog.userAgent
   * @type {Object}
   * @private
   */
  this.navigator_ = goog.userAgent.getNavigator();

  /**
   * The documentMode number used by goog.userAgent
   * @type {number|undefined}
   * @private
   */
  this.documentMode_ = goog.userAgent.DOCUMENT_MODE;
};
goog.inherits(goog.testing.MockUserAgent, goog.Disposable);

/**
 * Whether this MockUserAgent has been installed.
 * @type {boolean}
 * @private
 */
goog.testing.MockUserAgent.prototype.installed_;

/**
 * Installs this MockUserAgent.
 */
goog.testing.MockUserAgent.prototype.install = function() {
  if (!this.installed_) {
    // Stub out user agent functions.
    this.propertyReplacer_.replace(
        goog.userAgent, 'getUserAgentString',
        goog.bind(this.getUserAgentString, this));

    this.propertyReplacer_.replace(
        goog.labs.userAgent.util, 'getUserAgent',
        goog.bind(this.getUserAgentString, this));

    // Stub out navigator functions.
    this.propertyReplacer_.replace(
        goog.userAgent, 'getNavigator', goog.bind(this.getNavigator, this));

    // Stub out documentMode functions.
    this.propertyReplacer_.replace(
        goog.userAgent, 'getDocumentMode_',
        goog.bind(this.getDocumentMode, this));

    this.propertyReplacer_.replace(
        goog.userAgent, 'DOCUMENT_MODE', this.getDocumentMode());

    this.installed_ = true;
  }
};

/**
 * @return {?string} The userAgent set in this class.
 */
goog.testing.MockUserAgent.prototype.getUserAgentString = function() {
  return this.userAgent_;
};

/**
 * @param {string} userAgent The desired userAgent string to use.
 */
goog.testing.MockUserAgent.prototype.setUserAgentString = function(userAgent) {
  this.userAgent_ = userAgent;
};

/**
 * @return {Object} The Navigator set in this class.
 */
goog.testing.MockUserAgent.prototype.getNavigator = function() {
  return this.navigator_;
};

/**
 * @param {Object} navigator The desired Navigator object to use.
 */
goog.testing.MockUserAgent.prototype.setNavigator = function(navigator) {
  this.navigator_ = navigator;
};

/**
 * @return {number|undefined} The documentMode set in this class.
 */
goog.testing.MockUserAgent.prototype.getDocumentMode = function() {
  return this.documentMode_;
};

/**
 * @param {number} documentMode The desired documentMode to use.
 */
goog.testing.MockUserAgent.prototype.setDocumentMode = function(documentMode) {
  this.documentMode_ = documentMode;
  this.propertyReplacer_.set(goog.userAgent, 'DOCUMENT_MODE', documentMode);
};

/**
 * Uninstalls the MockUserAgent.
 */
goog.testing.MockUserAgent.prototype.uninstall = function() {
  if (this.installed_) {
    this.propertyReplacer_.reset();
    this.installed_ = false;
  }

};

/** @override */
goog.testing.MockUserAgent.prototype.disposeInternal = function() {
  this.uninstall();
  delete this.propertyReplacer_;
  delete this.navigator_;
  delete this.documentMode_;
  goog.testing.MockUserAgent.base(this, 'disposeInternal');
};
<commit_msg>Update goog.testing.MockUserAgent for #getNavigatorTyped<commit_after>// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview MockUserAgent overrides goog.userAgent.getUserAgentString()
 *     depending on a specified configuration.
 *
 */

goog.setTestOnly('goog.testing.MockUserAgent');
goog.provide('goog.testing.MockUserAgent');

goog.require('goog.Disposable');
goog.require('goog.labs.userAgent.util');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.userAgent');

/**
 * Class for unit testing code that uses goog.userAgent.
 *
 * @extends {goog.Disposable}
 * @constructor
 * @final
 */
goog.testing.MockUserAgent = function() {
  goog.Disposable.call(this);

  /**
   * Property replacer used to mock out User-Agent functions.
   * @type {!goog.testing.PropertyReplacer}
   * @private
   */
  this.propertyReplacer_ = new goog.testing.PropertyReplacer();

  /**
   * The userAgent string used by goog.userAgent.
   * @type {?string}
   * @private
   */
  this.userAgent_ = goog.userAgent.getUserAgentString();

  /**
   * The navigator object used by goog.userAgent
   * @type {?Navigator}
   * @private
   */
  this.navigator_ = goog.userAgent.getNavigatorTyped();

  /**
   * The documentMode number used by goog.userAgent
   * @type {number|undefined}
   * @private
   */
  this.documentMode_ = goog.userAgent.DOCUMENT_MODE;
};
goog.inherits(goog.testing.MockUserAgent, goog.Disposable);

/**
 * Whether this MockUserAgent has been installed.
 * @type {boolean}
 * @private
 */
goog.testing.MockUserAgent.prototype.installed_;

/**
 * Installs this MockUserAgent.
 */
goog.testing.MockUserAgent.prototype.install = function() {
  if (!this.installed_) {
    // Stub out user agent functions.
    this.propertyReplacer_.replace(
        goog.userAgent, 'getUserAgentString',
        goog.bind(this.getUserAgentString, this));

    this.propertyReplacer_.replace(
        goog.labs.userAgent.util, 'getUserAgent',
        goog.bind(this.getUserAgentString, this));

    // Stub out navigator functions.
    this.propertyReplacer_.replace(
        goog.userAgent, 'getNavigator', goog.bind(this.getNavigator, this));

    // Stub out navigator functions.
    this.propertyReplacer_.replace(
        goog.userAgent, 'getNavigatorTyped',
        goog.bind(this.getNavigator, this));

    // Stub out documentMode functions.
    this.propertyReplacer_.replace(
        goog.userAgent, 'getDocumentMode_',
        goog.bind(this.getDocumentMode, this));

    this.propertyReplacer_.replace(
        goog.userAgent, 'DOCUMENT_MODE', this.getDocumentMode());

    this.installed_ = true;
  }
};

/**
 * @return {?string} The userAgent set in this class.
 */
goog.testing.MockUserAgent.prototype.getUserAgentString = function() {
  return this.userAgent_;
};

/**
 * @param {string} userAgent The desired userAgent string to use.
 */
goog.testing.MockUserAgent.prototype.setUserAgentString = function(userAgent) {
  this.userAgent_ = userAgent;
};

/**
 * @return {?Object} The Navigator set in this class.
 */
goog.testing.MockUserAgent.prototype.getNavigator = function() {
  return this.navigator_;
};

/**
 * @return {?Navigator} The Navigator set in this class.
 */
goog.testing.MockUserAgent.prototype.getNavigatorTyped = function() {
  return this.navigator_;
};

/**
 * @param {Object} navigator The desired Navigator object to use.
 */
goog.testing.MockUserAgent.prototype.setNavigator = function(navigator) {
  this.navigator_ = /** @type {?Navigator} */ (navigator);
};

/**
 * @return {number|undefined} The documentMode set in this class.
 */
goog.testing.MockUserAgent.prototype.getDocumentMode = function() {
  return this.documentMode_;
};

/**
 * @param {number} documentMode The desired documentMode to use.
 */
goog.testing.MockUserAgent.prototype.setDocumentMode = function(documentMode) {
  this.documentMode_ = documentMode;
  this.propertyReplacer_.set(goog.userAgent, 'DOCUMENT_MODE', documentMode);
};

/**
 * Uninstalls the MockUserAgent.
 */
goog.testing.MockUserAgent.prototype.uninstall = function() {
  if (this.installed_) {
    this.propertyReplacer_.reset();
    this.installed_ = false;
  }

};

/** @override */
goog.testing.MockUserAgent.prototype.disposeInternal = function() {
  this.uninstall();
  delete this.propertyReplacer_;
  delete this.navigator_;
  delete this.documentMode_;
  goog.testing.MockUserAgent.base(this, 'disposeInternal');
};
<|endoftext|>


<commit_before>'use strict';
const expect = require('chai').expect;
const Time = require('../../src/faker/time');

describe('Time', () => {
  describe('#between', () => {
    it('should return a Date', () => {
      expect(Time.between(new Date(), new Date())).to.be.a('Date');
    });

    it('should return a date between two dates', () => {
      const from = new Date(2017, 9, 1);
      const to = new Date(2017, 9, 31);
      expect(Time.between(from, to)).to.be.within(from, to);
    });

    it('should return only date if Time.BETWEEN is the period', () => {
      const from = new Date(2017, 9, 1);
      const to = new Date(2017, 9, 31);
      const date = Time.between(from, to, Time.BETWEEN);
      expect(date.getHours()).to.equal(0);
      expect(date.getMinutes()).to.equal(0);
      expect(date.getSeconds()).to.equal(0);
    });

    it('should return a time between a specified period', () => {
      expect(Time.between(new Date(), new Date(), Time.ALL).getHours()).to.be.within(0, 23);
      expect(Time.between(new Date(), new Date(), Time.DAY).getHours()).to.be.within(9, 17);
      expect(Time.between(new Date(), new Date(), Time.NIGHT).getHours()).to.be.within(18, 23);
      expect(Time.between(new Date(), new Date(), Time.MORNING).getHours()).to.be.within(6, 11);
      expect(Time.between(new Date(), new Date(), Time.AFTERNOON).getHours()).to.be.within(12, 17);
      expect(Time.between(new Date(), new Date(), Time.EVENING).getHours()).to.be.within(17, 21);
      expect(Time.between(new Date(), new Date(), Time.MIDNIGHT).getHours()).to.be.within(0, 4);
      expect(Time.between(new Date(), new Date(), Time.BETWEEN).getHours()).to.be.within(0, 23);
    });

    it('should return a formatted date', () => {
      const date = new Date();
      expect(Time.between(date, date, Time.ALL, 'yyyy-MM-dd HH:mm:ss')).to.match(/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/);
    });
  });

  describe('#forward', () => {
    it('should return a Date', () => {
      expect(Time.forward(10)).to.be.a('Date');
    });

    it('should return a time in the future', () => {
      expect(Time.forward(10)).to.be.at.least(new Date());
    });

    it('should return a time no greater than the specified number of days', () => {
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      [...Array(100).keys()].forEach(_ => {
        expect(Time.forward(10)).to.be.above(today);
      });
    });

    it('should return a time between a specified period', () => {
      expect(Time.forward(10, Time.ALL).getHours()).to.be.within(0, 23);
      expect(Time.forward(10, Time.DAY).getHours()).to.be.within(9, 17);
      expect(Time.forward(10, Time.NIGHT).getHours()).to.be.within(18, 23);
      expect(Time.forward(10, Time.MORNING).getHours()).to.be.within(6, 11);
      expect(Time.forward(10, Time.AFTERNOON).getHours()).to.be.within(12, 17);
      expect(Time.forward(10, Time.EVENING).getHours()).to.be.within(17, 21);
      expect(Time.forward(10, Time.MIDNIGHT).getHours()).to.be.within(0, 4);
    });

    it('should throw if BETWEEN period specified', () => {
      expect(() => Time.forward(10, Time.BETWEEN)).to.throw('invalid period');
    });

    it('should return a formatted date', () => {
      const date = new Date();
      expect(Time.forward(10, Time.ALL, 'yyyy-MM-dd HH:mm:ss')).to.match(/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/);
    });
  });

  describe('#backward', () => {
    it('should return a Date', () => {
      expect(Time.backward(10)).to.be.a('Date');
    });

    it('should return a time in the past', () => {
      expect(Time.backward(10)).to.be.at.most(new Date());
    });

    it('should return a time no less than the specified number of days', () => {
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      [...Array(100).keys()].forEach(_ => {
        expect(Time.backward(10)).to.be.below(today);
      });
    });

    it('should return a time between a specified period', () => {
      expect(Time.backward(10, Time.ALL).getHours()).to.be.within(0, 23);
      expect(Time.backward(10, Time.DAY).getHours()).to.be.within(9, 17);
      expect(Time.backward(10, Time.NIGHT).getHours()).to.be.within(18, 23);
      expect(Time.backward(10, Time.MORNING).getHours()).to.be.within(6, 11);
      expect(Time.backward(10, Time.AFTERNOON).getHours()).to.be.within(12, 17);
      expect(Time.backward(10, Time.EVENING).getHours()).to.be.within(17, 21);
      expect(Time.backward(10, Time.MIDNIGHT).getHours()).to.be.within(0, 4);
    });

    it('should throw if BETWEEN period specified', () => {
      expect(() => Time.backward(10, Time.BETWEEN)).to.throw('invalid period');
    });

    it('should return a formatted date', () => {
      const date = new Date();
      expect(Time.backward(10, Time.ALL, 'yyyy-MM-dd HH:mm:ss')).to.match(/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/);
    });
  });
});
<commit_msg>Improved coverage of the time faker.<commit_after>'use strict';
const expect = require('chai').expect;
const Time = require('../../src/faker/time');

describe('Time', () => {
  describe('#between', () => {
    it('should return a Date', () => {
      expect(Time.between(new Date(), new Date())).to.be.a('Date');
    });

    it('should return a date between two dates', () => {
      const from = new Date(2017, 9, 1);
      const to = new Date(2017, 9, 31);
      expect(Time.between(from, to)).to.be.within(from, to);
    });

    it('should return only date if Time.BETWEEN is the period', () => {
      const from = new Date(2017, 9, 1);
      const to = new Date(2017, 9, 31);
      const date = Time.between(from, to, Time.BETWEEN);
      expect(date.getHours()).to.equal(0);
      expect(date.getMinutes()).to.equal(0);
      expect(date.getSeconds()).to.equal(0);
    });

    it('should return a time between a specified period', () => {
      expect(Time.between(new Date(), new Date(), Time.ALL).getHours()).to.be.within(0, 23);
      expect(Time.between(new Date(), new Date(), Time.DAY).getHours()).to.be.within(9, 17);
      expect(Time.between(new Date(), new Date(), Time.NIGHT).getHours()).to.be.within(18, 23);
      expect(Time.between(new Date(), new Date(), Time.MORNING).getHours()).to.be.within(6, 11);
      expect(Time.between(new Date(), new Date(), Time.AFTERNOON).getHours()).to.be.within(12, 17);
      expect(Time.between(new Date(), new Date(), Time.EVENING).getHours()).to.be.within(17, 21);
      expect(Time.between(new Date(), new Date(), Time.MIDNIGHT).getHours()).to.be.within(0, 4);
      expect(Time.between(new Date(), new Date(), Time.BETWEEN).getHours()).to.be.within(0, 23);
    });

    it('should return a formatted date', () => {
      const date = new Date();
      expect(Time.between(date, date, Time.ALL, 'yyyy-MM-dd HH:mm:ss')).to.match(/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/);
    });
  });

  describe('#forward', () => {
    it('should return a Date', () => {
      expect(Time.forward()).to.be.a('Date');
    });

    it('should return a time in the future', () => {
      expect(Time.forward()).to.be.at.least(new Date());
    });

    it('should return a time no greater than the specified number of days', () => {
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      [...Array(100).keys()].forEach(_ => {
        expect(Time.forward(10)).to.be.above(today);
      });
    });

    it('should return a time between a specified period', () => {
      expect(Time.forward(10, Time.ALL).getHours()).to.be.within(0, 23);
      expect(Time.forward(10, Time.DAY).getHours()).to.be.within(9, 17);
      expect(Time.forward(10, Time.NIGHT).getHours()).to.be.within(18, 23);
      expect(Time.forward(10, Time.MORNING).getHours()).to.be.within(6, 11);
      expect(Time.forward(10, Time.AFTERNOON).getHours()).to.be.within(12, 17);
      expect(Time.forward(10, Time.EVENING).getHours()).to.be.within(17, 21);
      expect(Time.forward(10, Time.MIDNIGHT).getHours()).to.be.within(0, 4);
    });

    it('should throw if BETWEEN period specified', () => {
      expect(() => Time.forward(10, Time.BETWEEN)).to.throw('invalid period');
    });

    it('should return a formatted date', () => {
      const date = new Date();
      expect(Time.forward(10, Time.ALL, 'yyyy-MM-dd HH:mm:ss')).to.match(/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/);
    });
  });

  describe('#backward', () => {
    it('should return a Date', () => {
      expect(Time.backward()).to.be.a('Date');
    });

    it('should return a time in the past', () => {
      expect(Time.backward()).to.be.at.most(new Date());
    });

    it('should return a time no less than the specified number of days', () => {
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      [...Array(100).keys()].forEach(_ => {
        expect(Time.backward(10)).to.be.below(today);
      });
    });

    it('should return a time between a specified period', () => {
      expect(Time.backward(10, Time.ALL).getHours()).to.be.within(0, 23);
      expect(Time.backward(10, Time.DAY).getHours()).to.be.within(9, 17);
      expect(Time.backward(10, Time.NIGHT).getHours()).to.be.within(18, 23);
      expect(Time.backward(10, Time.MORNING).getHours()).to.be.within(6, 11);
      expect(Time.backward(10, Time.AFTERNOON).getHours()).to.be.within(12, 17);
      expect(Time.backward(10, Time.EVENING).getHours()).to.be.within(17, 21);
      expect(Time.backward(10, Time.MIDNIGHT).getHours()).to.be.within(0, 4);
    });

    it('should throw if BETWEEN period specified', () => {
      expect(() => Time.backward(10, Time.BETWEEN)).to.throw('invalid period');
    });

    it('should return a formatted date', () => {
      const date = new Date();
      expect(Time.backward(10, Time.ALL, 'yyyy-MM-dd HH:mm:ss')).to.match(/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/);
    });
  });
});
<|endoftext|>


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

// Initializes FriendlyChat.
function FriendlyChat() {
  this.checkSetup();

  // Shortcuts to DOM Elements.
  this.messageList = document.getElementById('messages');
  this.messageForm = document.getElementById('message-form');
  this.messageInput = document.getElementById('message');
  this.submitButton = document.getElementById('submit');
  this.submitImageButton = document.getElementById('submitImage');
  this.imageForm = document.getElementById('image-form');
  this.mediaCapture = document.getElementById('mediaCapture');
  this.userPic = document.getElementById('user-pic');
  this.userName = document.getElementById('user-name');
  this.signInButton = document.getElementById('sign-in');
  this.signOutButton = document.getElementById('sign-out');
  this.signInSnackbar = document.getElementById('must-signin-snackbar');

  // Saves message on form submit.
  this.messageForm.addEventListener('submit', this.saveMessage.bind(this));
  this.signOutButton.addEventListener('click', this.signOut.bind(this));
  this.signInButton.addEventListener('click', this.signIn.bind(this));

  // Toggle for the button.
  var buttonTogglingHandler = this.toggleButton.bind(this);
  this.messageInput.addEventListener('keyup', buttonTogglingHandler);
  this.messageInput.addEventListener('change', buttonTogglingHandler);

  // Events for image upload.
  this.submitImageButton.addEventListener('click', function(e) {
    e.preventDefault();
    this.mediaCapture.click();
  }.bind(this));
  this.mediaCapture.addEventListener('change', this.saveImageMessage.bind(this));

  this.initFirebase();
}

// Sets up shortcuts to Firebase features and initiate firebase auth.
FriendlyChat.prototype.initFirebase = function() {
  // Shortcuts to Firebase SDK features.
  this.auth = firebase.auth();
  this.database = firebase.database();
  this.storage = firebase.storage();
  // Initiates Firebase auth and listen to auth state changes.
  this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
};

// Loads chat messages history and listens for upcoming ones.
FriendlyChat.prototype.loadMessages = function() {
  // Reference to the /messages/ database path.
  this.messagesRef = this.database.ref('messages');
  // Make sure we remove all previous listeners.
  this.messagesRef.off();

  // Loads the last 12 messages and listen for new ones.
  var setMessage = function(data) {
    var val = data.val();
    this.displayMessage(data.key, val.name, val.text, val.photoUrl, val.imageUrl);
  }.bind(this);
  this.messagesRef.limitToLast(12).on('child_added', setMessage);
  this.messagesRef.limitToLast(12).on('child_changed', setMessage);
};

// Saves a new message on the Firebase DB.
FriendlyChat.prototype.saveMessage = function(e) {
  e.preventDefault();
  // Check that the user entered a message and is signed in.
  if (this.messageInput.value && this.checkSignedInWithMessage()) {
    var currentUser = this.auth.currentUser;
    // Add a new message entry to the Firebase Database.
    this.messagesRef.push({
      name: currentUser.displayName,
      text: this.messageInput.value,
      photoUrl: currentUser.photoURL || '/images/profile_placeholder.png'
    }).then(function() {
      // Clear message text field and SEND button state.
      FriendlyChat.resetMaterialTextfield(this.messageInput);
      this.toggleButton();
    }.bind(this)).catch(function(error) {
      console.error('Error writing new message to Firebase Database', error);
    });
  }
};

// Sets the URL of the given img element with the URL of the image stored in Firebase Storage.
FriendlyChat.prototype.setImageUrl = function(imageUri, imgElement) {
  // If the image is a Firebase Storage URI we fetch the URL.
  if (imageUri.startsWith('gs://')) {
    imgElement.src = FriendlyChat.LOADING_IMAGE_URL; // Display a loading image first.
    this.storage.refFromURL(imageUri).getMetadata().then(function(metadata) {
      imgElement.src = metadata.downloadURLs[0];
    });
  } else {
    imgElement.src = imageUri;
  }
};

// Saves a new message containing an image URI in Firebase.
// This first saves the image in Firebase storage.
FriendlyChat.prototype.saveImageMessage = function(event) {
  event.preventDefault();
  var file = event.target.files[0];

  // Clear the selection in the file picker input.
  this.imageForm.reset();

  // Check if the file is an image.
  if (!file.type.match('image.*')) {
    var data = {
      message: 'You can only share images',
      timeout: 2000
    };
    this.signInSnackbar.MaterialSnackbar.showSnackbar(data);
    return;
  }

  // Check if the user is signed-in
  if (this.checkSignedInWithMessage()) {

    // We add a message with a loading icon that will get updated with the shared image.
    var currentUser = this.auth.currentUser;
    this.messagesRef.push({
      name: currentUser.displayName,
      imageUrl: FriendlyChat.LOADING_IMAGE_URL,
      photoUrl: currentUser.photoURL || '/images/profile_placeholder.png'
    }).then(function(data) {

      // Upload the image to Firebase Storage.
      var filePath = currentUser.uid + '/' + data.key + '/' + file.name;
      return this.storage.ref(filePath).put(file).then(function(snapshot) {

        // Get the file's Storage URI and update the chat message placeholder.
        var fullPath = snapshot.metadata.fullPath;
        return data.update({imageUrl: this.storage.ref(fullPath).toString()});
      }.bind(this));
    }.bind(this)).catch(function(error) {
      console.error('There was an error uploading a file to Firebase Storage:', error);
    });
  }
};

// Signs-in Friendly Chat.
FriendlyChat.prototype.signIn = function() {
  // Sign in Firebase using popup auth and Google as the identity provider.
  var provider = new firebase.auth.GoogleAuthProvider();
  this.auth.signInWithPopup(provider);
};

// Signs-out of Friendly Chat.
FriendlyChat.prototype.signOut = function() {
  // Sign out of Firebase.
  this.auth.signOut();
};

// Triggers when the auth state change for instance when the user signs-in or signs-out.
FriendlyChat.prototype.onAuthStateChanged = function(user) {
  if (user) { // User is signed in!
    // Get profile pic and user's name from the Firebase user object.
    var profilePicUrl = user.photoURL;
    var userName = user.displayName;

    // Set the user's profile pic and name.
    this.userPic.style.backgroundImage = 'url(' + (profilePicUrl || '/images/profile_placeholder.png') + ')';
    this.userName.textContent = userName;

    // Show user's profile and sign-out button.
    this.userName.removeAttribute('hidden');
    this.userPic.removeAttribute('hidden');
    this.signOutButton.removeAttribute('hidden');

    // Hide sign-in button.
    this.signInButton.setAttribute('hidden', 'true');

    // We load currently existing chat messages.
    this.loadMessages();

    // We save the Firebase Messaging Device token and enable notifications.
    this.saveMessagingDeviceToken();
  } else { // User is signed out!
    // Hide user's profile and sign-out button.
    this.userName.setAttribute('hidden', 'true');
    this.userPic.setAttribute('hidden', 'true');
    this.signOutButton.setAttribute('hidden', 'true');

    // Show sign-in button.
    this.signInButton.removeAttribute('hidden');
  }
};

// Returns true if user is signed-in. Otherwise false and displays a message.
FriendlyChat.prototype.checkSignedInWithMessage = function() {
  // Return true if the user is signed in Firebase
  if (this.auth.currentUser) {
    return true;
  }

  // Display a message to the user using a Toast.
  var data = {
    message: 'You must sign-in first',
    timeout: 2000
  };
  this.signInSnackbar.MaterialSnackbar.showSnackbar(data);
  return false;
};

// Saves the messaging device token to the datastore.
FriendlyChat.prototype.saveMessagingDeviceToken = function() {
  firebase.messaging().getToken().then(function(currentToken) {
    if (currentToken) {
      console.log('Got FCM device token:', currentToken);
      // Saving the Device Token to the datastore.
      firebase.database().ref('/fcmTokens').child(currentToken)
          .set(firebase.auth().currentUser.uid);
    } else {
      // Need to request permissions to show notifications.
      this.requestNotificationsPermissions();
    }
  }.bind(this)).catch(function(error){
    console.error('Unable to get messaging token.', error);
  });
};

// Requests permissions to show notifications.
FriendlyChat.prototype.requestNotificationsPermissions = function() {
  console.log('Requesting notifications permission...');
  firebase.messaging().requestPermission().then(function() {
    // Notification permission granted.
    this.saveMessagingDeviceToken();
  }.bind(this)).catch(function(error) {
    console.error('Unable to get permission to notify.', error);
  });
};

// Resets the given MaterialTextField.
FriendlyChat.resetMaterialTextfield = function(element) {
  element.value = '';
  element.parentNode.MaterialTextfield.boundUpdateClassesHandler();
};

// Template for messages.
FriendlyChat.MESSAGE_TEMPLATE =
    '
' +
      '

' +
      '

' +
      '

' +
    '
';

// A loading image URL.
FriendlyChat.LOADING_IMAGE_URL = 'https://www.google.com/images/spin-32.gif';

// Displays a Message in the UI.
FriendlyChat.prototype.displayMessage = function(key, name, text, picUrl, imageUri) {
  var div = document.getElementById(key);
  // If an element for that message does not exists yet we create it.
  if (!div) {
    var container = document.createElement('div');
    container.innerHTML = FriendlyChat.MESSAGE_TEMPLATE;
    div = container.firstChild;
    div.setAttribute('id', key);
    this.messageList.appendChild(div);
  }
  if (picUrl) {
    div.querySelector('.pic').style.backgroundImage = 'url(' + picUrl + ')';
  }
  div.querySelector('.name').textContent = name;
  var messageElement = div.querySelector('.message');
  if (text) { // If the message is text.
    messageElement.textContent = text;
    // Replace all line breaks by
.
    messageElement.innerHTML = messageElement.innerHTML.replace(/\n/g, '
');
  } else if (imageUri) { // If the message is an image.
    var image = document.createElement('img');
    image.addEventListener('load', function() {
      this.messageList.scrollTop = this.messageList.scrollHeight;
    }.bind(this));
    this.setImageUrl(imageUri, image);
    messageElement.innerHTML = '';
    messageElement.appendChild(image);
  }
  // Show the card fading-in and scroll to view the new message.
  setTimeout(function() {div.classList.add('visible')}, 1);
  this.messageList.scrollTop = this.messageList.scrollHeight;
  this.messageInput.focus();
};

// Enables or disables the submit button depending on the values of the input
// fields.
FriendlyChat.prototype.toggleButton = function() {
  if (this.messageInput.value) {
    this.submitButton.removeAttribute('disabled');
  } else {
    this.submitButton.setAttribute('disabled', 'true');
  }
};

// Checks that the Firebase SDK has been correctly setup and configured.
FriendlyChat.prototype.checkSetup = function() {
  if (!window.firebase || !(firebase.app instanceof Function) || !firebase.app().options) {
    window.alert('You have not configured and imported the Firebase SDK. ' +
        'Make sure you go through the codelab setup instructions and make ' +
        'sure you are running the codelab using `firebase serve`');
  }
};

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

// Initializes FriendlyChat.
function FriendlyChat() {
  this.checkSetup();

  // Shortcuts to DOM Elements.
  this.messageList = document.getElementById('messages');
  this.messageForm = document.getElementById('message-form');
  this.messageInput = document.getElementById('message');
  this.submitButton = document.getElementById('submit');
  this.submitImageButton = document.getElementById('submitImage');
  this.imageForm = document.getElementById('image-form');
  this.mediaCapture = document.getElementById('mediaCapture');
  this.userPic = document.getElementById('user-pic');
  this.userName = document.getElementById('user-name');
  this.signInButton = document.getElementById('sign-in');
  this.signOutButton = document.getElementById('sign-out');
  this.signInSnackbar = document.getElementById('must-signin-snackbar');

  // Saves message on form submit.
  this.messageForm.addEventListener('submit', this.saveMessage.bind(this));
  this.signOutButton.addEventListener('click', this.signOut.bind(this));
  this.signInButton.addEventListener('click', this.signIn.bind(this));

  // Toggle for the button.
  var buttonTogglingHandler = this.toggleButton.bind(this);
  this.messageInput.addEventListener('keyup', buttonTogglingHandler);
  this.messageInput.addEventListener('change', buttonTogglingHandler);

  // Events for image upload.
  this.submitImageButton.addEventListener('click', function(e) {
    e.preventDefault();
    this.mediaCapture.click();
  }.bind(this));
  this.mediaCapture.addEventListener('change', this.saveImageMessage.bind(this));

  this.initFirebase();
}

// Sets up shortcuts to Firebase features and initiate firebase auth.
FriendlyChat.prototype.initFirebase = function() {
  // Shortcuts to Firebase SDK features.
  this.auth = firebase.auth();
  this.database = firebase.database();
  this.storage = firebase.storage();
  // Initiates Firebase auth and listen to auth state changes.
  this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
};

// Loads chat messages history and listens for upcoming ones.
FriendlyChat.prototype.loadMessages = function() {
  // Reference to the /messages/ database path.
  this.messagesRef = this.database.ref('messages');
  // Make sure we remove all previous listeners.
  this.messagesRef.off();

  // Loads the last 12 messages and listen for new ones.
  var setMessage = function(data) {
    var val = data.val();
    this.displayMessage(data.key, val.name, val.text, val.photoUrl, val.imageUrl);
  }.bind(this);
  this.messagesRef.limitToLast(12).on('child_added', setMessage);
  this.messagesRef.limitToLast(12).on('child_changed', setMessage);
};

// Saves a new message on the Firebase DB.
FriendlyChat.prototype.saveMessage = function(e) {
  e.preventDefault();
  // Check that the user entered a message and is signed in.
  if (this.messageInput.value && this.checkSignedInWithMessage()) {
    var currentUser = this.auth.currentUser;
    // Add a new message entry to the Firebase Database.
    this.messagesRef.push({
      name: currentUser.displayName,
      text: this.messageInput.value,
      photoUrl: currentUser.photoURL || '/images/profile_placeholder.png'
    }).then(function() {
      // Clear message text field and SEND button state.
      FriendlyChat.resetMaterialTextfield(this.messageInput);
      this.toggleButton();
    }.bind(this)).catch(function(error) {
      console.error('Error writing new message to Firebase Database', error);
    });
  }
};

// Sets the URL of the given img element with the URL of the image stored in Firebase Storage.
FriendlyChat.prototype.setImageUrl = function(imageUri, imgElement) {
  // If the image is a Firebase Storage URI we fetch the URL.
  if (imageUri.startsWith('gs://')) {
    imgElement.src = FriendlyChat.LOADING_IMAGE_URL; // Display a loading image first.
    this.storage.refFromURL(imageUri).getMetadata().then(function(metadata) {
      imgElement.src = metadata.downloadURLs[0];
    });
  } else {
    imgElement.src = imageUri;
  }
};

// Saves a new message containing an image URI in Firebase.
// This first saves the image in Firebase storage.
FriendlyChat.prototype.saveImageMessage = function(event) {
  event.preventDefault();
  var file = event.target.files[0];

  // Clear the selection in the file picker input.
  this.imageForm.reset();

  // Check if the file is an image.
  if (!file.type.match('image.*')) {
    var data = {
      message: 'You can only share images',
      timeout: 2000
    };
    this.signInSnackbar.MaterialSnackbar.showSnackbar(data);
    return;
  }

  // Check if the user is signed-in
  if (this.checkSignedInWithMessage()) {

    // We add a message with a loading icon that will get updated with the shared image.
    var currentUser = this.auth.currentUser;
    this.messagesRef.push({
      name: currentUser.displayName,
      imageUrl: FriendlyChat.LOADING_IMAGE_URL,
      photoUrl: currentUser.photoURL || '/images/profile_placeholder.png'
    }).then(function(data) {

      // Upload the image to Firebase Storage.
      var filePath = currentUser.uid + '/' + data.key + '/' + file.name;
      return this.storage.ref(filePath).put(file).then(function(snapshot) {

        // Get the file's Storage URI and update the chat message placeholder.
        var fullPath = snapshot.metadata.fullPath;
        return data.update({imageUrl: this.storage.ref(fullPath).toString()});
      }.bind(this));
    }.bind(this)).catch(function(error) {
      console.error('There was an error uploading a file to Firebase Storage:', error);
    });
  }
};

// Signs-in Friendly Chat.
FriendlyChat.prototype.signIn = function() {
  // Sign in Firebase using popup auth and Google as the identity provider.
  var provider = new firebase.auth.GoogleAuthProvider();
  this.auth.signInWithPopup(provider);
};

// Signs-out of Friendly Chat.
FriendlyChat.prototype.signOut = function() {
  // Sign out of Firebase.
  this.auth.signOut();
};

// Triggers when the auth state change for instance when the user signs-in or signs-out.
FriendlyChat.prototype.onAuthStateChanged = function(user) {
  if (user) { // User is signed in!
    // Get profile pic and user's name from the Firebase user object.
    var profilePicUrl = user.photoURL;
    var userName = user.displayName;

    // Set the user's profile pic and name.
    this.userPic.style.backgroundImage = 'url(' + (profilePicUrl || '/images/profile_placeholder.png') + ')';
    this.userName.textContent = userName;

    // Show user's profile and sign-out button.
    this.userName.removeAttribute('hidden');
    this.userPic.removeAttribute('hidden');
    this.signOutButton.removeAttribute('hidden');

    // Hide sign-in button.
    this.signInButton.setAttribute('hidden', 'true');

    // We load currently existing chat messages.
    this.loadMessages();

    // We save the Firebase Messaging Device token and enable notifications.
    this.saveMessagingDeviceToken();
  } else { // User is signed out!
    // Hide user's profile and sign-out button.
    this.userName.setAttribute('hidden', 'true');
    this.userPic.setAttribute('hidden', 'true');
    this.signOutButton.setAttribute('hidden', 'true');

    // Show sign-in button.
    this.signInButton.removeAttribute('hidden');
  }
};

// Returns true if user is signed-in. Otherwise false and displays a message.
FriendlyChat.prototype.checkSignedInWithMessage = function() {
  // Return true if the user is signed in Firebase
  if (this.auth.currentUser) {
    return true;
  }

  // Display a message to the user using a Toast.
  var data = {
    message: 'You must sign-in first',
    timeout: 2000
  };
  this.signInSnackbar.MaterialSnackbar.showSnackbar(data);
  return false;
};

// Saves the messaging device token to the datastore.
FriendlyChat.prototype.saveMessagingDeviceToken = function() {
  firebase.messaging().getToken().then(function(currentToken) {
    if (currentToken) {
      console.log('Got FCM device token:', currentToken);
      // Saving the Device Token to the datastore.
      firebase.database().ref('/fcmTokens').child(currentToken)
          .set(firebase.auth().currentUser.uid);
    } else {
      // Need to request permissions to show notifications.
      this.requestNotificationsPermissions();
    }
  }.bind(this)).catch(function(error){
    console.error('Unable to get messaging token.', error);
  });
};

// Requests permissions to show notifications.
FriendlyChat.prototype.requestNotificationsPermissions = function() {
  console.log('Requesting notifications permission...');
  firebase.messaging().requestPermission().then(function() {
    // Notification permission granted.
    this.saveMessagingDeviceToken();
  }.bind(this)).catch(function(error) {
    console.error('Unable to get permission to notify.', error);
  });
};

// Resets the given MaterialTextField.
FriendlyChat.resetMaterialTextfield = function(element) {
  element.value = '';
  element.parentNode.MaterialTextfield.boundUpdateClassesHandler();
};

// Template for messages.
FriendlyChat.MESSAGE_TEMPLATE =
    '
' +
      '

' +
      '

' +
      '

' +
    '
';

// A loading image URL.
FriendlyChat.LOADING_IMAGE_URL = 'https://www.google.com/images/spin-32.gif';

// Displays a Message in the UI.
FriendlyChat.prototype.displayMessage = function(key, name, text, picUrl, imageUri) {
  var div = document.getElementById(key);
  // If an element for that message does not exists yet we create it.
  if (!div) {
    var container = document.createElement('div');
    container.innerHTML = FriendlyChat.MESSAGE_TEMPLATE;
    div = container.firstChild;
    div.setAttribute('id', key);
    this.messageList.appendChild(div);
  }
  if (picUrl) {
    div.querySelector('.pic').style.backgroundImage = 'url(' + picUrl + ')';
  }
  div.querySelector('.name').textContent = name;
  var messageElement = div.querySelector('.message');
  if (text) { // If the message is text.
    messageElement.textContent = text;
    // Replace all line breaks by
.
    messageElement.innerHTML = messageElement.innerHTML.replace(/\n/g, '
');
  } else if (imageUri) { // If the message is an image.
    var image = document.createElement('img');
    image.addEventListener('load', function() {
      this.messageList.scrollTop = this.messageList.scrollHeight;
    }.bind(this));
    this.setImageUrl(imageUri, image);
    messageElement.innerHTML = '';
    messageElement.appendChild(image);
  }
  // Show the card fading-in and scroll to view the new message.
  setTimeout(function() {div.classList.add('visible')}, 1);
  this.messageList.scrollTop = this.messageList.scrollHeight;
  this.messageInput.focus();
};

// Enables or disables the submit button depending on the values of the input
// fields.
FriendlyChat.prototype.toggleButton = function() {
  if (this.messageInput.value) {
    this.submitButton.removeAttribute('disabled');
  } else {
    this.submitButton.setAttribute('disabled', 'true');
  }
};

// Checks that the Firebase SDK has been correctly setup and configured.
FriendlyChat.prototype.checkSetup = function() {
  if (!window.firebase || !(firebase.app instanceof Function) || !firebase.app().options) {
    window.alert('You have not configured and imported the Firebase SDK. ' +
        'Make sure you go through the codelab setup instructions and make ' +
        'sure you are running the codelab using `firebase serve`');
  }
};

window.addEventListener('load' , function() {
  window.friendlyChat = new FriendlyChat();
});
<|endoftext|>


<commit_before>var url = require('url'),
  Player = require('videojs-automation'),
  players = [{
    suiteName: browser.name + ': MPEG-DASH Player',
    source: {
      src: 'http://wams.edgesuite.net/media/' +
        'SintelTrailer_MP4_from_WAME/sintel_trailer-1080p.ism/manifest(format=mpd-time-csf)',
      type: 'application/dash+xml'
    }
  }];

if (/chrome/i.test(browser.browserName)) {
  players.push({
    suiteName: browser.name + ': MPEG-DASH Player w/ Widevine DRM',
    source: {
      src: 'http://html5.cablelabs.com:8100/cenc/wv/dash.mpd',
      type: 'application/dash+xml',
      keySystemOptions: [{
        name: 'com.widevine.alpha',
        options: {
          'licenseUrl': 'https://html5.cablelabs.com:8025'
        }
      }]
    }
  });
}

players.map(function(p) {
  return describe(p.suiteName, function() {
    var player;

    beforeEach(function() {
      player = new Player(url.resolve(browser.baseUrl, 'test/functional/player.html'));
      browser.executeScript(function(source) {
        player.src(source);
      }, p.source);
    });

    if (!/explorer/i.test(browser.browserName)) {
      it('should have no console errors', function() {
        player.bigPlayButton().click();
        player.consoleLog().then(function(logs) {
          expect(logs.length).toBe(0);
        });
      });
    }

    it('should have no player errors', function() {
      expect(player.error()).toBeNull();
    });

    it('should play', function() {
      player.bigPlayButton().click();
      browser.executeAsyncScript(function(done) {
        player.one('timeupdate', done);
      });
    });
  });
});
<commit_msg>Skip Sauce Labs Firefox<commit_after>var url = require('url'),
  Player = require('videojs-automation'),
  players = [];

if (/chrome|explorer/i.test(browser.browserName)) {
  players.push({
    suiteName: browser.name + ': MPEG-DASH Player',
    source: {
      src: 'http://wams.edgesuite.net/media/' +
        'SintelTrailer_MP4_from_WAME/sintel_trailer-1080p.ism/manifest(format=mpd-time-csf)',
      type: 'application/dash+xml'
    }
  });
}

if (/chrome/i.test(browser.browserName)) {
  players.push({
    suiteName: browser.name + ': MPEG-DASH Player w/ Widevine DRM',
    source: {
      src: 'http://html5.cablelabs.com:8100/cenc/wv/dash.mpd',
      type: 'application/dash+xml',
      keySystemOptions: [{
        name: 'com.widevine.alpha',
        options: {
          'licenseUrl': 'https://html5.cablelabs.com:8025'
        }
      }]
    }
  });
}

players.map(function(p) {
  return describe(p.suiteName, function() {
    var player;

    beforeEach(function() {
      player = new Player(url.resolve(browser.baseUrl, 'test/functional/player.html'));
      browser.executeScript(function(source) {
        player.src(source);
      }, p.source);
    });

    if (!/explorer/i.test(browser.browserName)) {
      it('should have no console errors', function() {
        player.bigPlayButton().click();
        player.consoleLog().then(function(logs) {
          expect(logs.length).toBe(0);
        });
      });
    }

    it('should have no player errors', function() {
      expect(player.error()).toBeNull();
    });

    it('should play', function() {
      player.bigPlayButton().click();
      browser.executeAsyncScript(function(done) {
        player.one('timeupdate', done);
      });
    });
  });
});
<|endoftext|>


<commit_before>import assign from 'lodash/object/assign';
import storage from './storage';
import StrongSocket from './StrongSocket';
import * as utils from './utils';
import * as xhr from './xhr';
import i18n from './i18n';
import friendsApi from './lichess/friends';
import challengesApi from './lichess/challenges';
import session from './session';
import signals from './signals';
import m from 'mithril';

var socketInstance;
var errorDetected = false;
var connectedWS = true;

var alreadyWarned = false;
var proxyFailTimeoutID;
const proxyFailMsg = 'The connection to lichess server has failed. If you see that the problem is persistent it is probably due to a proxy in your network that prevents establishing the connection. In that case, we\'re sorry: lichess won\'t work.';

const defaultHandlers = {
  following_onlines: data => utils.autoredraw(utils.partialf(friendsApi.set, data)),
  following_enters: name => utils.autoredraw(utils.partialf(friendsApi.add, name)),
  following_leaves: name => utils.autoredraw(utils.partialf(friendsApi.remove, name)),
  challengeReminder: o => {
    if (challengesApi.hasKey(o.id)) challengesApi.remind(o.id);
    else xhr.getChallenge(o.id).then(g => challengesApi.add(o.id, g)).then(m.redraw);
  }
};

function destroy() {
  if (socketInstance) {
    socketInstance.destroy();
    socketInstance = null;
  }
}

function createGame(url, version, receiveHandler, gameUrl, userTv) {
  errorDetected = false;
  destroy();
  const opts = {
    options: {
      name: 'game',
      debug: window.lichess.mode !== 'prod',
      ignoreUnknownMessages: true,
      onError: function() {
        // we can't get socket error, so we send an xhr to test whether the
        // rejection is an authorization issue
        if (!errorDetected) {
          // just to be sure that we don't send an xhr every second when the
          // websocket is trying to reconnect
          errorDetected = true;
          xhr.game(gameUrl.substring(1)).then(function() {}, function(err) {
            if (err.message === 'unauthorizedError') {
              window.plugins.toast.show(i18n('unauthorizedError'), 'short', 'center');
              m.route('/');
            }
          });
        }
      },
      onOpen: () => socketInstance.send('following_onlines')
    },
    events: defaultHandlers,
    receive: receiveHandler
  };
  if (userTv) opts.params = { userTv };
  socketInstance = new StrongSocket(url, version, opts);
}

function createAwait(url, version, handlers) {
  destroy();
  socketInstance = new StrongSocket(
    url, version, {
      options: {
        name: 'await',
        debug: window.lichess.mode !== 'prod',
        ignoreUnknownMessages: true,
        pingDelay: 2000,
        onOpen: () => socketInstance.send('following_onlines')
      },
      events: assign({}, defaultHandlers, handlers)
    }
  );
}

function createLobby(lobbyVersion, onOpen, handlers) {
  destroy();
  socketInstance = new StrongSocket(
    '/lobby/socket/v1',
    lobbyVersion, {
      options: {
        name: 'lobby',
        debug: window.lichess.mode !== 'prod',
        ignoreUnknownMessages: true,
        pingDelay: 2000,
        onOpen: () => {
          onOpen();
          socketInstance.send('following_onlines');
        }
      },
      events: assign({}, defaultHandlers, handlers)
    }
  );
}

function createDefault() {
  // default socket is useless when anon.
  if (utils.hasNetwork() && session.isConnected()) {
    destroy();
    socketInstance = new StrongSocket(
      '/socket', 0, {
        options: {
          name: 'default',
          debug: window.lichess.mode !== 'prod',
          pingDelay: 2000,
          onOpen: () => socketInstance.send('following_onlines')
        },
        events: defaultHandlers
      }
    );
  }
}

function onConnected() {
  connectedWS = true;
  clearTimeout(proxyFailTimeoutID);
}

function onDisconnected() {
  const wasOn = connectedWS;
  connectedWS = false;
  if (wasOn && !alreadyWarned && !storage.get('donotshowproxyfailwarning')) proxyFailTimeoutID = setTimeout(() => {
    // check if disconnection lasts, it could mean a proxy prevents
    // establishing a tunnel
    if (utils.hasNetwork() && !connectedWS) {
      alreadyWarned = true;
      window.navigator.notification.alert(proxyFailMsg, function() {
        storage.set('donotshowproxyfailwarning', true);
      });
    }
  }, 15000);
}

document.addEventListener('deviceready', () => {
  document.addEventListener('pause', () => clearTimeout(proxyFailTimeoutID), false);
}, false);

signals.socket.connected.add(onConnected);
signals.socket.disconnected.add(onDisconnected);

export default {
  createGame,
  createLobby,
  createAwait,
  createDefault,
  setVersion(version) {
    if (socketInstance) socketInstance.setVersion(version);
  },
  getAverageLag() {
    if (socketInstance) return socketInstance.averageLag;
  },
  send(...args) {
    if (socketInstance) socketInstance.send(...args);
  },
  connect() {
    if (socketInstance) socketInstance.connect();
  },
  disconnect() {
    if (socketInstance) socketInstance.destroy();
  },
  destroy
};
<commit_msg>Tweak message<commit_after>import assign from 'lodash/object/assign';
import storage from './storage';
import StrongSocket from './StrongSocket';
import * as utils from './utils';
import * as xhr from './xhr';
import i18n from './i18n';
import friendsApi from './lichess/friends';
import challengesApi from './lichess/challenges';
import session from './session';
import signals from './signals';
import m from 'mithril';

var socketInstance;
var errorDetected = false;
var connectedWS = true;

var alreadyWarned = false;
var proxyFailTimeoutID;
const proxyFailMsg = 'The connection to lichess server has failed. If the problem is persistent this may be caused by proxy or network issues. In that case, we\'re sorry: lichess online features such as games, connected friends or challenges won\'t work.';

const defaultHandlers = {
  following_onlines: data => utils.autoredraw(utils.partialf(friendsApi.set, data)),
  following_enters: name => utils.autoredraw(utils.partialf(friendsApi.add, name)),
  following_leaves: name => utils.autoredraw(utils.partialf(friendsApi.remove, name)),
  challengeReminder: o => {
    if (challengesApi.hasKey(o.id)) challengesApi.remind(o.id);
    else xhr.getChallenge(o.id).then(g => challengesApi.add(o.id, g)).then(m.redraw);
  }
};

function destroy() {
  if (socketInstance) {
    socketInstance.destroy();
    socketInstance = null;
  }
}

function createGame(url, version, receiveHandler, gameUrl, userTv) {
  errorDetected = false;
  destroy();
  const opts = {
    options: {
      name: 'game',
      debug: window.lichess.mode !== 'prod',
      ignoreUnknownMessages: true,
      onError: function() {
        // we can't get socket error, so we send an xhr to test whether the
        // rejection is an authorization issue
        if (!errorDetected) {
          // just to be sure that we don't send an xhr every second when the
          // websocket is trying to reconnect
          errorDetected = true;
          xhr.game(gameUrl.substring(1)).then(function() {}, function(err) {
            if (err.message === 'unauthorizedError') {
              window.plugins.toast.show(i18n('unauthorizedError'), 'short', 'center');
              m.route('/');
            }
          });
        }
      },
      onOpen: () => socketInstance.send('following_onlines')
    },
    events: defaultHandlers,
    receive: receiveHandler
  };
  if (userTv) opts.params = { userTv };
  socketInstance = new StrongSocket(url, version, opts);
}

function createAwait(url, version, handlers) {
  destroy();
  socketInstance = new StrongSocket(
    url, version, {
      options: {
        name: 'await',
        debug: window.lichess.mode !== 'prod',
        ignoreUnknownMessages: true,
        pingDelay: 2000,
        onOpen: () => socketInstance.send('following_onlines')
      },
      events: assign({}, defaultHandlers, handlers)
    }
  );
}

function createLobby(lobbyVersion, onOpen, handlers) {
  destroy();
  socketInstance = new StrongSocket(
    '/lobby/socket/v1',
    lobbyVersion, {
      options: {
        name: 'lobby',
        debug: window.lichess.mode !== 'prod',
        ignoreUnknownMessages: true,
        pingDelay: 2000,
        onOpen: () => {
          onOpen();
          socketInstance.send('following_onlines');
        }
      },
      events: assign({}, defaultHandlers, handlers)
    }
  );
}

function createDefault() {
  // default socket is useless when anon.
  if (utils.hasNetwork() && session.isConnected()) {
    destroy();
    socketInstance = new StrongSocket(
      '/socket', 0, {
        options: {
          name: 'default',
          debug: window.lichess.mode !== 'prod',
          pingDelay: 2000,
          onOpen: () => socketInstance.send('following_onlines')
        },
        events: defaultHandlers
      }
    );
  }
}

function onConnected() {
  connectedWS = true;
  clearTimeout(proxyFailTimeoutID);
}

function onDisconnected() {
  const wasOn = connectedWS;
  connectedWS = false;
  if (wasOn && !alreadyWarned && !storage.get('donotshowproxyfailwarning')) proxyFailTimeoutID = setTimeout(() => {
    // check if disconnection lasts, it could mean a proxy prevents
    // establishing a tunnel
    if (utils.hasNetwork() && !connectedWS) {
      alreadyWarned = true;
      window.navigator.notification.alert(proxyFailMsg, function() {
        storage.set('donotshowproxyfailwarning', true);
      });
    }
  }, 15000);
}

document.addEventListener('deviceready', () => {
  document.addEventListener('pause', () => clearTimeout(proxyFailTimeoutID), false);
}, false);

signals.socket.connected.add(onConnected);
signals.socket.disconnected.add(onDisconnected);

export default {
  createGame,
  createLobby,
  createAwait,
  createDefault,
  setVersion(version) {
    if (socketInstance) socketInstance.setVersion(version);
  },
  getAverageLag() {
    if (socketInstance) return socketInstance.averageLag;
  },
  send(...args) {
    if (socketInstance) socketInstance.send(...args);
  },
  connect() {
    if (socketInstance) socketInstance.connect();
  },
  disconnect() {
    if (socketInstance) socketInstance.destroy();
  },
  destroy
};
<|endoftext|>


<commit_before>/*##################################################|*/
/* #CMS# */

// ensuring django namespace is set correctly
var django = window.django || undefined;

// ensuring jQuery namespace is set correctly
var jQuery = (django) ? django.jQuery : window.jQuery || undefined;

// ensuring Class namespace is set correctly
var Class = window.Class || undefined;

// ensuring CMS namespace is set correctly
var CMS = {
	'$': (jQuery) ? jQuery.noConflict() : undefined,
	'Class': (Class) ? Class.noConflict() : undefined,
	'API': {}
};

/*##################################################|*/
/* #CMS.API# */
(function($) {
// CMS.$ will be passed for $
$(document).ready(function () {
	/*!
	 * CNS.API.Helpers
	 * @version: 1.0.0
	 * @public_methods:
	 *	- CMS.API.Helpers.reloadBrowser();
	 */
	CMS.API.Helpers = {

		// redirects to a specific url or reloads browser
		reloadBrowser: function (url, timeout) {
			// is there a parent window?
			parent = (window.parent) ? window.parent : window;
			// add timeout if provided
			parent.setTimeout(function () {
				(url) ? parent.location.href = url : parent.location.reload();
			}, timeout || 0);
		},

		// disable multiple form submissions
		preventSubmit: function () {
			$('#cms_toolbar form').submit(function () {
				// we cannot use disabled as the name action will be ignored
				$('input[type="submit"]').bind('click', function (e) {
					e.preventDefault();
				}).css('opacity', 0.5);
			});
		},

		// fixes csrf behaviour
		csrf: function (csrf_token) {
			$.ajaxSetup({
				beforeSend: function (xhr) {
					// set csrf_token
					xhr.setRequestHeader("X-CSRFToken", csrf_token);
				}
			});
		},

		// handles the tooltip within the cms-wrapper
		showTooltip: function (name, id) {
			var tooltip = $('.cms_placeholders-tooltip');

			// change css and attributes
			tooltip.css('visibility', 'visible')
				.data('plugin_id', id)
				.show()
				.find('span').html(name);

			// attaches move event
			// this sets the correct position for the edit tooltip
			$('body').bind('mousemove.cms', function (e) {
				// so lets figure out where we are
				var offset = 20;
				var bound = $(document).width();
				var pos = e.pageX + tooltip.outerWidth(true) + offset;

				tooltip.css({
					'left': (pos >= bound) ? e.pageX - tooltip.outerWidth(true) - offset : e.pageX + offset,
					'top': e.pageY - 12
				});
			});

			// attach tooltip event for touch devices
			tooltip.bind('touchstart.cms', function () {
				$('#cms_plugin-' + $(this).data('plugin_id')).trigger('dblclick');
			});
		},

		hideTooltip: function () {
			var tooltip = $('.cms_placeholders-tooltip');

			// change css
			tooltip.css('visibility', 'hidden').hide();

			// unbind events
			$('body').unbind('mousemove.cms');
			tooltip.unbind('touchstart.cms');
		}

		// sends or retrieves a JSON from localStorage or the session if local storage is not available
		//setSettings: function () {},

		//getSettings: function () {},

		//resetSettings: function () {}

	};

	// autoinits
	CMS.API.Helpers.preventSubmit();

});
})(CMS.$);

// this will be fixed in jQuery 1.6+
(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) {
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );<commit_msg>make jquery expr faster<commit_after>/*##################################################|*/
/* #CMS# */

// ensuring django namespace is set correctly
var django = window.django || undefined;

// ensuring jQuery namespace is set correctly
var jQuery = (django) ? django.jQuery : window.jQuery || undefined;

// ensuring Class namespace is set correctly
var Class = window.Class || undefined;

// ensuring CMS namespace is set correctly
var CMS = {
	'$': (jQuery) ? jQuery.noConflict() : undefined,
	'Class': (Class) ? Class.noConflict() : undefined,
	'API': {}
};

/*##################################################|*/
/* #CMS.API# */
(function($) {
// CMS.$ will be passed for $
$(document).ready(function () {
	/*!
	 * CNS.API.Helpers
	 * @version: 1.0.0
	 * @public_methods:
	 *	- CMS.API.Helpers.reloadBrowser();
	 */
	CMS.API.Helpers = {

		// redirects to a specific url or reloads browser
		reloadBrowser: function (url, timeout) {
			// is there a parent window?
			parent = (window.parent) ? window.parent : window;
			// add timeout if provided
			parent.setTimeout(function () {
				(url) ? parent.location.href = url : parent.location.reload();
			}, timeout || 0);
		},

		// disable multiple form submissions
		preventSubmit: function () {
			var forms = $('#cms_toolbar').find('form');
			forms.submit(function () {
				// we cannot use disabled as the name action will be ignored
				$('input[type="submit"]').bind('click', function (e) {
					e.preventDefault();
				}).css('opacity', 0.5);
			});
		},

		// fixes csrf behaviour
		csrf: function (csrf_token) {
			$.ajaxSetup({
				beforeSend: function (xhr) {
					// set csrf_token
					xhr.setRequestHeader("X-CSRFToken", csrf_token);
				}
			});
		},

		// handles the tooltip within the cms-wrapper
		showTooltip: function (name, id) {
			var tooltip = $('.cms_placeholders-tooltip');

			// change css and attributes
			tooltip.css('visibility', 'visible')
				.data('plugin_id', id)
				.show()
				.find('span').html(name);

			// attaches move event
			// this sets the correct position for the edit tooltip
			$('body').bind('mousemove.cms', function (e) {
				// so lets figure out where we are
				var offset = 20;
				var bound = $(document).width();
				var pos = e.pageX + tooltip.outerWidth(true) + offset;

				tooltip.css({
					'left': (pos >= bound) ? e.pageX - tooltip.outerWidth(true) - offset : e.pageX + offset,
					'top': e.pageY - 12
				});
			});

			// attach tooltip event for touch devices
			tooltip.bind('touchstart.cms', function () {
				$('#cms_plugin-' + $(this).data('plugin_id')).trigger('dblclick');
			});
		},

		hideTooltip: function () {
			var tooltip = $('.cms_placeholders-tooltip');

			// change css
			tooltip.css('visibility', 'hidden').hide();

			// unbind events
			$('body').unbind('mousemove.cms');
			tooltip.unbind('touchstart.cms');
		}

		// sends or retrieves a JSON from localStorage or the session if local storage is not available
		//setSettings: function () {},

		//getSettings: function () {},

		//resetSettings: function () {}

	};

	// autoinits
	CMS.API.Helpers.preventSubmit();

});
})(CMS.$);

// this will be fixed in jQuery 1.6+
(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) {
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );<|endoftext|>


<commit_before><commit_msg>display shipping rates without the flat rate prefix<commit_after><|endoftext|>


<commit_before>export default function binarySearch(array, index, length, value, comparer) {
    var lo = index,
        hi = index + length - 1,
        order = 0,
        i = 0;

    while (lo <= hi) {
        i = lo + ((hi - lo) >> 1);
        order = comparer(array[i], value);

        if (order === 0) {
            return i;
        }
        else if (order < 0) {
            lo = i + 1;
        }
        else {
            hi = i - 1;
        }
    }

    return ~lo;
}
<commit_msg>fix binary search<commit_after>export default function binarySearch(array, index, length, value, compare) {
    var lo = index,
        hi = index + length - 1,
        order = 0,
        i = 0;

    while (lo <= hi) {
        i = lo + ((hi - lo) >> 1);
        order = compare(array[i], value);

        if (order === 0) {
            return i;
        }
        else if (order < 0) {
            lo = i + 1;
        }
        else {
            hi = i - 1;
        }
    }

    return ~lo;
}
<|endoftext|>


<commit_before>var riot = require('riot');
var helloworld = require('../tags/hello-world.tag');

/*global riot, describe, it, beforeEach, expect*/
describe('Hello World', function () {

  beforeEach(function () {
    // create mounting points
    var html = document.createElement('hello-world');
    document.body.appendChild(html);
  });

  it('should mount the tag', function () {
    riot.mount('hello-world');
    expect(document.querySelector('hello-world h1').textContent)
      .toBe('Hello World');
  });

});
<commit_msg>Breaking the test<commit_after>var riot = require('riot');
var helloworld = require('../tags/hello-world.tag');

/*global riot, describe, it, beforeEach, expect*/
describe('Hello World', function () {

  beforeEach(function () {
    // create mounting points
    var html = document.createElement('hello-world');
    document.body.appendChild(html);
  });

  it('should mount the tag', function () {
    riot.mount('hello-world');
    expect(document.querySelector('hello-world h1').textContent)
      .toBe('Hello Worlds');
  });

});
<|endoftext|>


<commit_before>const lodash = require('lodash');

module.exports = (client, app) => {
  const registry = {}

  const fetchGauge = (state) => {
    if (!registry[state.name]) {
      registry[state.name] = buildGauge(state);
    }

    return registry[state.name];
  }

  const buildGauge = (state) => {
    const name = lodash.snakeCase(state.name);
    console.log(state);
    console.log(name);
  }

  app.on('devices:cozytouch', setup => {
    setup.devices.forEach(device => {
      device.states.forEach(state => {
        const gauge = fetchGauge(state);
      });
    });
  });
}
<commit_msg>Collect cozytouch metrics<commit_after>const lodash = require('lodash');

const PREFIX = 'cozytouch';

module.exports = (client, app) => {
  const REGISTRY = {}

  app.on('devices:cozytouch', setup => {
    setup.devices.forEach(device => {
      device.states.forEach(state => {
        handleState(device, state);
      });
    });
  });

  const handleState = (device, state) => {
    if (state.type > 3) {
      return;
    }

    const labels = {
      name: device.name,
      model: device.model,
      widget: device.widget,
      uiClass: device.uiClass,
      oid: device.oid,
      placeOID: device.placeOID,
      url: device.url,
    }

    let value = state.value;

    if (state.type == 3) {
      labels.value = value;
      value = 1;
    }

    fetchGauge(state).set(labels, value);
  }

  const fetchGauge = (state) => {
    if (!REGISTRY[state.name]) {
      REGISTRY[state.name] = buildGauge(state);
    }

    return REGISTRY[state.name];
  }

  const buildGauge = (state) => {
    const name = PREFIX + '_' + lodash.snakeCase(state.name);
    const labelNames = ['name', 'model', 'widget', 'uiClass', 'oid', 'placeOID', 'url'];

    if (state.type == 3) {
      labelNames.push('value');
    }

    return new client.Gauge({
      name,
      labelNames,
      help: state.name,
    });
  }
}
<|endoftext|>


<commit_before>"use strict";
var config = require("./config");

if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position){
        position = position || 0;
        return this.substr(position, searchString.length) === searchString;
    };
}

var ITEMS = {
    messages: {},
    stars: {},
    flags: {},
    lastEvent: {}
};
var noFormattingLinked = function() {
    throw new Error("There is no formatting linked.");
};
var blacklistedUsers = config.blacklistedUsers || [];
var acceptableUsers = config.acceptableUsers || [];

acceptableUsers = acceptableUsers.concat([
    //ID here with //comment with your name
    '145604', // Quill SE
    '24697', // PhiNotPi SE
    '175356', // Downgoat SE
    '116494' // Conor O Brien SE
]);
var messageFormatting = {
    room: noFormattingLinked,
    user: noFormattingLinked,
    activity: noFormattingLinked,
    content: noFormattingLinked,
    edited: noFormattingLinked,
    messageId: noFormattingLinked,
    connection: noFormattingLinked
};
var say = function(){};
var specialSay = function(){};
var noPrefixSay = function(){};
var reply = function(){};
var commands = {};
var limitedAccessCommands = {};

var set = {
    messageFormatting: function(value) {
        messageFormatting = value;
    },
    say: function(value){
        say = value;
    },
    specialSay: function(value){
        specialSay = value;
    },
    noPrefixSay: function(value){
        noPrefixSay = value;
    },
    reply: function(value){
        reply = value;
    },
    commands: function(value){
        commands = value;
    },
    limitedAccessCommands: function(value){
        limitedAccessCommands = value;
    }
};
var EVENT_TYPES = {
    MessagePosted: 1,
    MessageEdited: 2,
    UserEntered: 3,
    UserLeft: 4,
    RoomNameChanged: 5,
    MessageStarred: 6,
    UserMentioned: 8,
    MessageFlagged: 9,
    MessageDeleted: 10,
    UserNotification: 16,
    Invitation: 17,
    MessageReply: 18,
    MessageMovedOut: 19,
    MessageMovedIn: 20
};

var convert = function(str) {
    return !str ? "" // eslint-disable-line no-negated-condition
    : str.replace(/&/g, "&")
         .replace(/>/g, ">")
         .replace(/</g, "<")
         .replace(/"/g, "\"")
         .replace(/'/g, "'");
};

var processCommand = function(event){
    if (String(event.room_id) != "39270" && String(event.room_id) != "89"){
        return false;
    }
    if (!event.content.startsWith("@Marvin ") && !event.content.startsWith("!!/")){
        return false;
    }
    if ((event.content.startsWith("@Marvin") || event.content.startsWith("!!/")) && String(event.room_id) == "89"){
        return false;
    }
    if (String(event.room_id) != "89" && event.content.startsWith("@Quill")){
        return false;
    }
    if (blacklistedUsers.indexOf(String(event.user_id)) !== -1){
        return reply("I can't let you do that.", event);
    }
    var commandArguments = event.content
        .replace("@Marvin ", "")
        .replace("@Quill ", "")
        .replace("!!/", "")
        .split(" ");
    var commandName = commandArguments[0];
    if (commandName == ''){
        return reply("You need to actually type a command...");
    }
    var command = commands[commandName];
    var commandArgs = commandArguments.slice(1);
    if (limitedAccessCommands.hasOwnProperty(commandName) && acceptableUsers.indexOf(String(event.user_id)) === -1)){
        if (event.domain == "SE"){
            return reply("I can't let you do that.", event);
        }
    }
    var speaker = (event.domain == "SE" ? say : specialSay);
    if (commands.hasOwnProperty(commandName)){
        switch (commandName){
            case "delete":
            case "join":
            case "leave":
                return say(command("SE", commandArgs));
                break;
            case "restart":
            case "stop":
            case "pull":
                return speaker(say, commandArgs);
                break;
            case "blacklist":
                if (blacklistedUsers.indexOf(commandArgs[0]) > -1){
                    return reply("They're already blacklisted.", event);
                }
                if (acceptableUsers.indexOf(String(commandArgs[0])) !== -1){
                    return reply("They're a special user... don't even try it, sassy pants.", event)
                }
                blacklistedUsers.push(commandArgs[0]);
                return command(commandArgs);
                break;
            case "removeBlacklist":
                if (blacklistedUsers.indexOf(commandArgs[0]) === -1){
                    reply("They're not blacklisted.", event);
                }
                blacklistedUsers.splice(blacklistedUsers.indexOf(commandArgs[0]), 1);
                return command(commandArgs);
                break;
            case "alive":
            case "rampDownTheSarcasm":
            case "rampUpTheSarcasm":
            case "help":
                return reply(
                    command(commandArgs),
                    event
                );
                break;
            case "listCommands":
                return reply(
                    command(acceptableUsers.indexOf(String(event.user_id)) !== -1, commandArgs),
                    event
                );
                break;
            case "listFlagCount":
                return speaker(command(ITEMS.flags, commandArgs));
                break;
            default:
                return say(command(commandArgs))
                break;

        }
    } else {
        return say("Command " + commandName + " not recognised.")
    }
}

/* eslint-disable complexity, max-statements */
var processEvent = function(event) {
    if (event.content === ITEMS.lastEventContent) {
        return false;
    }
    ITEMS.lastEventContent = event.content;
    event.content = convert(event.content);
    switch (event.event_type) {
        case EVENT_TYPES.MessagePosted:
            return processCommand(event);
            break;
        case EVENT_TYPES.MessageEdited:
            return processCommand(event);
            break;
        case EVENT_TYPES.MessageStarred:
            if (!event.message_stars) {
                delete ITEMS.stars[event.message_id];
                return;
            }
            if (ITEMS.stars.hasOwnProperty(event.message_id)){
                return;
            }
            if (event.message_stars > config.star_threshold) {
                ITEMS.stars[event.message_id] = event.message_stars;
                return say(
                    messageFormatting.room(event) +
                    messageFormatting.activity(" highly starred [message](http://chat.stackexchange.com/transcript/message/" + event.message_id + "#" + event.message_id + ") with ") +
                    event.message_stars +
                    " stars."
                )
                .then(function(){
                    return noPrefixSay(
                        "http://chat.stackexchange.com/transcript/message/" + event.message_id + "#" + event.message_id
                    );
                });
            }
            break;
        case EVENT_TYPES.MessageFlagged:
            if (!ITEMS.flags.hasOwnProperty(event.message_id)){
                ITEMS.flags[event.message_id] = event;
                ITEMS.flags[event.message_id].site = "SE";
                specialSay(
                    messageFormatting.activity("A [message](http://chat.stackexchange.com/transcript/message/" + event.message_id + "#" + event.message_id + ") in ") +
                    messageFormatting.room(event) +
                    messageFormatting.activity(" was flagged.")
                ).then(function(){
                    return say(
                        messageFormatting.activity("A [message](http://chat.stackexchange.com/transcript/message/" + event.message_id + "#" + event.message_id + ") in ") +
                        messageFormatting.room(event) +
                        messageFormatting.activity(" was flagged.")
                    );
                });
                // Uncomment the line below to turn on sharing of the message
                //say(messageFormatting.content(event));
            }
            break;
        default:
            return false;
            break;
    }
};
module.exports = {
    processEvent: processEvent,
    convert: convert,
    set: set,
    ITEMS: ITEMS,
    EVENT_TYPES: EVENT_TYPES
};
<commit_msg>fixed extraneous brace<commit_after>"use strict";
var config = require("./config");

if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position){
        position = position || 0;
        return this.substr(position, searchString.length) === searchString;
    };
}

var ITEMS = {
    messages: {},
    stars: {},
    flags: {},
    lastEvent: {}
};
var noFormattingLinked = function() {
    throw new Error("There is no formatting linked.");
};
var blacklistedUsers = config.blacklistedUsers || [];
var acceptableUsers = config.acceptableUsers || [];

acceptableUsers = acceptableUsers.concat([
    //ID here with //comment with your name
    '145604', // Quill SE
    '24697', // PhiNotPi SE
    '175356', // Downgoat SE
    '116494' // Conor O Brien SE
]);
var messageFormatting = {
    room: noFormattingLinked,
    user: noFormattingLinked,
    activity: noFormattingLinked,
    content: noFormattingLinked,
    edited: noFormattingLinked,
    messageId: noFormattingLinked,
    connection: noFormattingLinked
};
var say = function(){};
var specialSay = function(){};
var noPrefixSay = function(){};
var reply = function(){};
var commands = {};
var limitedAccessCommands = {};

var set = {
    messageFormatting: function(value) {
        messageFormatting = value;
    },
    say: function(value){
        say = value;
    },
    specialSay: function(value){
        specialSay = value;
    },
    noPrefixSay: function(value){
        noPrefixSay = value;
    },
    reply: function(value){
        reply = value;
    },
    commands: function(value){
        commands = value;
    },
    limitedAccessCommands: function(value){
        limitedAccessCommands = value;
    }
};
var EVENT_TYPES = {
    MessagePosted: 1,
    MessageEdited: 2,
    UserEntered: 3,
    UserLeft: 4,
    RoomNameChanged: 5,
    MessageStarred: 6,
    UserMentioned: 8,
    MessageFlagged: 9,
    MessageDeleted: 10,
    UserNotification: 16,
    Invitation: 17,
    MessageReply: 18,
    MessageMovedOut: 19,
    MessageMovedIn: 20
};

var convert = function(str) {
    return !str ? "" // eslint-disable-line no-negated-condition
    : str.replace(/&/g, "&")
         .replace(/>/g, ">")
         .replace(/</g, "<")
         .replace(/"/g, "\"")
         .replace(/'/g, "'");
};

var processCommand = function(event){
    if (String(event.room_id) != "39270" && String(event.room_id) != "89"){
        return false;
    }
    if (!event.content.startsWith("@Marvin ") && !event.content.startsWith("!!/")){
        return false;
    }
    if ((event.content.startsWith("@Marvin") || event.content.startsWith("!!/")) && String(event.room_id) == "89"){
        return false;
    }
    if (String(event.room_id) != "89" && event.content.startsWith("@Quill")){
        return false;
    }
    if (blacklistedUsers.indexOf(String(event.user_id)) !== -1){
        return reply("I can't let you do that.", event);
    }
    var commandArguments = event.content
        .replace("@Marvin ", "")
        .replace("@Quill ", "")
        .replace("!!/", "")
        .split(" ");
    var commandName = commandArguments[0];
    if (commandName == ''){
        return reply("You need to actually type a command...");
    }
    var command = commands[commandName];
    var commandArgs = commandArguments.slice(1);
    if (limitedAccessCommands.hasOwnProperty(commandName) && acceptableUsers.indexOf(String(event.user_id)) === -1){
        if (event.domain == "SE"){
            return reply("I can't let you do that.", event);
        }
    }
    var speaker = (event.domain == "SE" ? say : specialSay);
    if (commands.hasOwnProperty(commandName)){
        switch (commandName){
            case "delete":
            case "join":
            case "leave":
                return say(command("SE", commandArgs));
                break;
            case "restart":
            case "stop":
            case "pull":
                return speaker(say, commandArgs);
                break;
            case "blacklist":
                if (blacklistedUsers.indexOf(commandArgs[0]) > -1){
                    return reply("They're already blacklisted.", event);
                }
                if (acceptableUsers.indexOf(String(commandArgs[0])) !== -1){
                    return reply("They're a special user... don't even try it, sassy pants.", event)
                }
                blacklistedUsers.push(commandArgs[0]);
                return command(commandArgs);
                break;
            case "removeBlacklist":
                if (blacklistedUsers.indexOf(commandArgs[0]) === -1){
                    reply("They're not blacklisted.", event);
                }
                blacklistedUsers.splice(blacklistedUsers.indexOf(commandArgs[0]), 1);
                return command(commandArgs);
                break;
            case "alive":
            case "rampDownTheSarcasm":
            case "rampUpTheSarcasm":
            case "help":
                return reply(
                    command(commandArgs),
                    event
                );
                break;
            case "listCommands":
                return reply(
                    command(acceptableUsers.indexOf(String(event.user_id)) !== -1, commandArgs),
                    event
                );
                break;
            case "listFlagCount":
                return speaker(command(ITEMS.flags, commandArgs));
                break;
            default:
                return say(command(commandArgs))
                break;

        }
    } else {
        return say("Command " + commandName + " not recognised.")
    }
}

/* eslint-disable complexity, max-statements */
var processEvent = function(event) {
    if (event.content === ITEMS.lastEventContent) {
        return false;
    }
    ITEMS.lastEventContent = event.content;
    event.content = convert(event.content);
    switch (event.event_type) {
        case EVENT_TYPES.MessagePosted:
            return processCommand(event);
            break;
        case EVENT_TYPES.MessageEdited:
            return processCommand(event);
            break;
        case EVENT_TYPES.MessageStarred:
            if (!event.message_stars) {
                delete ITEMS.stars[event.message_id];
                return;
            }
            if (ITEMS.stars.hasOwnProperty(event.message_id)){
                return;
            }
            if (event.message_stars > config.star_threshold) {
                ITEMS.stars[event.message_id] = event.message_stars;
                return say(
                    messageFormatting.room(event) +
                    messageFormatting.activity(" highly starred [message](http://chat.stackexchange.com/transcript/message/" + event.message_id + "#" + event.message_id + ") with ") +
                    event.message_stars +
                    " stars."
                )
                .then(function(){
                    return noPrefixSay(
                        "http://chat.stackexchange.com/transcript/message/" + event.message_id + "#" + event.message_id
                    );
                });
            }
            break;
        case EVENT_TYPES.MessageFlagged:
            if (!ITEMS.flags.hasOwnProperty(event.message_id)){
                ITEMS.flags[event.message_id] = event;
                ITEMS.flags[event.message_id].site = "SE";
                specialSay(
                    messageFormatting.activity("A [message](http://chat.stackexchange.com/transcript/message/" + event.message_id + "#" + event.message_id + ") in ") +
                    messageFormatting.room(event) +
                    messageFormatting.activity(" was flagged.")
                ).then(function(){
                    return say(
                        messageFormatting.activity("A [message](http://chat.stackexchange.com/transcript/message/" + event.message_id + "#" + event.message_id + ") in ") +
                        messageFormatting.room(event) +
                        messageFormatting.activity(" was flagged.")
                    );
                });
                // Uncomment the line below to turn on sharing of the message
                //say(messageFormatting.content(event));
            }
            break;
        default:
            return false;
            break;
    }
};
module.exports = {
    processEvent: processEvent,
    convert: convert,
    set: set,
    ITEMS: ITEMS,
    EVENT_TYPES: EVENT_TYPES
};
<|endoftext|>


<commit_before>const lodash = require('lodash');

const PREFIX = 'cozytouch';

module.exports = (client, app) => {
  const REGISTRY = {}

  app.on('devices:cozytouch', setup => {
    setup.devices.forEach(device => {
      device.states.forEach(state => {
        handleState(device, state);
      });
    });
  });

  const handleState = (device, state) => {
    if (state.type > 3) {
      return;
    }

    const labels = {
      name: device.name,
      model: device.model,
      widget: device.widget,
      uiClass: device.uiClass,
      oid: device.oid,
      placeOID: device.placeOID,
      url: device.URL,
    }

    let value = state.value;

    if (state.type == 3) {
      labels.value = value;
      value = 1;
    }

    fetchGauge(state).set(labels, value);
  }

  const fetchGauge = (state) => {
    if (!REGISTRY[state.name]) {
      REGISTRY[state.name] = buildGauge(state);
    }

    return REGISTRY[state.name];
  }

  const buildGauge = (state) => {
    const name = PREFIX + '_' + lodash.snakeCase(state.name);
    const labelNames = ['name', 'model', 'widget', 'uiClass', 'oid', 'placeOID', 'url'];

    if (state.type == 3) {
      labelNames.push('value');
    }

    return new client.Gauge({
      name,
      labelNames,
      help: state.name,
    });
  }
}
<commit_msg>Handle empty states<commit_after>const lodash = require('lodash');

const PREFIX = 'cozytouch';

module.exports = (client, app) => {
  const REGISTRY = {}

  app.on('devices:cozytouch', setup => {
    setup.devices.forEach(device => {
      (device.states || []).forEach(state => {
        handleState(device, state);
      });
    });
  });

  const handleState = (device, state) => {
    if (state.type > 3) {
      return;
    }

    const labels = {
      name: device.name,
      model: device.model,
      widget: device.widget,
      uiClass: device.uiClass,
      oid: device.oid,
      placeOID: device.placeOID,
      url: device.URL,
    }

    let value = state.value;

    if (state.type == 3) {
      labels.value = value;
      value = 1;
    }

    fetchGauge(state).set(labels, value);
  }

  const fetchGauge = (state) => {
    if (!REGISTRY[state.name]) {
      REGISTRY[state.name] = buildGauge(state);
    }

    return REGISTRY[state.name];
  }

  const buildGauge = (state) => {
    const name = PREFIX + '_' + lodash.snakeCase(state.name);
    const labelNames = ['name', 'model', 'widget', 'uiClass', 'oid', 'placeOID', 'url'];

    if (state.type == 3) {
      labelNames.push('value');
    }

    return new client.Gauge({
      name,
      labelNames,
      help: state.name,
    });
  }
}
<|endoftext|>


<commit_before>'use strict';

var chai = require('chai');
var expect = chai.expect;

var Config = require('../../lib/config');
var path = require('path');
var _ = require('lodash');

var _fixtureDir = function(name) {
  return path.resolve(__dirname, '../fixtures/' + name);
};

describe('Config', function() {
  describe('#new', function() {
    it('should hoist legacy hosting keys', function() {
      var config = new Config({
        name: 'throwaway',
        public: 'public',
        ignore: ['**/.*'],
        rewrites: [],
        redirects: [],
        headers: []
      }, {});

      expect(config.data.hosting).to.have.property('public', 'public');
      expect(config.data.hosting).to.have.property('ignore');
      expect(config.data.hosting).to.have.property('rewrites');
      expect(config.data.hosting).to.have.property('redirects');
      expect(config.data.hosting).to.have.property('headers');
    });

    it('should not hoist if hosting key is present', function() {
      var config = new Config({
        name: 'throwaway',
        hosting: {public: '.'},
        rewrites: []
      }, {});

      expect(config.data.hosting).to.have.property('public', '.');
      expect(config.data.hosting).not.to.have.property('rewrites');
    });

    it('should generate trigger rules for functions', function() {
      var config = new Config({
        functions: {myfunc: {triggers: {database: {path: '/abc'}}}},
        rules: {abc: {'.read': true}}
      }, {});

      expect(config.data.rules.abc).to.deep.eq({
        '.function': {name: '\'myfunc\'', condition: 'true'},
        '.read': true
      });
    });

    it('should error out if .function is defined in rules', function() {
      expect(function() {
        _.noop(new Config({rules: {
          abc: {'.function': {name: '"myfunc"', condition: 'true'}}
        }}, {}));
      }).to.throw('Cannot define .function in rules, please use functions config instead');
    });
  });

  describe('#importLegacyKeys', function() {
    it('should respect non-overlapping keys in hosting', function() {
      var redirects = [{source: '/foo', destination: '/bar.html', type: 301}];
      var rewrites = [{source: '**', destination: '/index.html'}];
      var config = new Config({
        rewrites: rewrites,
        hosting: {
          redirects: redirects
        }
      }, {});

      config.importLegacyKeys();
      expect(config.get('hosting.redirects')).to.eq(redirects);
      expect(config.get('hosting.rewrites')).to.eq(rewrites);
    });
  });

  describe('#_parseFile', function() {
    it('should load a cjson file', function() {
      var config = new Config({}, {cwd: _fixtureDir('config-imports')});
      expect(config._parseFile('hosting', 'hosting.json').public).to.equal('.');
    });

    it('should error out for an unknown file', function() {
      var config = new Config({}, {cwd: _fixtureDir('config-imports')});
      expect(function() {
        config._parseFile('hosting', 'i-dont-exist.json');
      }).to.throw('Imported file i-dont-exist.json does not exist');
    });

    it('should error out for an unrecognized extension', function() {
      var config = new Config({}, {cwd: _fixtureDir('config-imports')});
      expect(function() {
        config._parseFile('hosting', 'unsupported.txt');
      }).to.throw('unsupported.txt is not of a supported config file type');
    });
  });

  describe('#_materialize', function() {
    it('should assign unaltered if an object is found', function() {
      var config = new Config({example: {foo: 'bar'}}, {});
      expect(config._materialize('example').foo).to.equal('bar');
    });
  });
});
<commit_msg>Add test for functions without rules.<commit_after>'use strict';

var chai = require('chai');
var expect = chai.expect;

var Config = require('../../lib/config');
var path = require('path');
var _ = require('lodash');

var _fixtureDir = function(name) {
  return path.resolve(__dirname, '../fixtures/' + name);
};

describe('Config', function() {
  describe('#new', function() {
    it('should hoist legacy hosting keys', function() {
      var config = new Config({
        name: 'throwaway',
        public: 'public',
        ignore: ['**/.*'],
        rewrites: [],
        redirects: [],
        headers: []
      }, {});

      expect(config.data.hosting).to.have.property('public', 'public');
      expect(config.data.hosting).to.have.property('ignore');
      expect(config.data.hosting).to.have.property('rewrites');
      expect(config.data.hosting).to.have.property('redirects');
      expect(config.data.hosting).to.have.property('headers');
    });

    it('should not hoist if hosting key is present', function() {
      var config = new Config({
        name: 'throwaway',
        hosting: {public: '.'},
        rewrites: []
      }, {});

      expect(config.data.hosting).to.have.property('public', '.');
      expect(config.data.hosting).not.to.have.property('rewrites');
    });

    it('should generate trigger rules for functions', function() {
      var config = new Config({
        functions: {myfunc: {triggers: {database: {path: '/abc'}}}},
        rules: {abc: {'.read': true}}
      }, {});

      expect(config.data.rules.abc).to.deep.eq({
        '.function': {name: '\'myfunc\'', condition: 'true'},
        '.read': true
      });
    });

    it('should generate trigger rules even when rules is undefined', function() {
      var config = new Config({
        functions: {myfunc: {triggers: {database: {path: '/abc'}}}}
      }, {});

      expect(config.data.rules.abc).to.deep.eq({
        '.function': {name: '\'myfunc\'', condition: 'true'}
      });
    });

    it('should error out if .function is defined in rules', function() {
      expect(function() {
        _.noop(new Config({rules: {
          abc: {'.function': {name: '"myfunc"', condition: 'true'}}
        }}, {}));
      }).to.throw('Cannot define .function in rules, please use functions config instead');
    });
  });

  describe('#importLegacyKeys', function() {
    it('should respect non-overlapping keys in hosting', function() {
      var redirects = [{source: '/foo', destination: '/bar.html', type: 301}];
      var rewrites = [{source: '**', destination: '/index.html'}];
      var config = new Config({
        rewrites: rewrites,
        hosting: {
          redirects: redirects
        }
      }, {});

      config.importLegacyKeys();
      expect(config.get('hosting.redirects')).to.eq(redirects);
      expect(config.get('hosting.rewrites')).to.eq(rewrites);
    });
  });

  describe('#_parseFile', function() {
    it('should load a cjson file', function() {
      var config = new Config({}, {cwd: _fixtureDir('config-imports')});
      expect(config._parseFile('hosting', 'hosting.json').public).to.equal('.');
    });

    it('should error out for an unknown file', function() {
      var config = new Config({}, {cwd: _fixtureDir('config-imports')});
      expect(function() {
        config._parseFile('hosting', 'i-dont-exist.json');
      }).to.throw('Imported file i-dont-exist.json does not exist');
    });

    it('should error out for an unrecognized extension', function() {
      var config = new Config({}, {cwd: _fixtureDir('config-imports')});
      expect(function() {
        config._parseFile('hosting', 'unsupported.txt');
      }).to.throw('unsupported.txt is not of a supported config file type');
    });
  });

  describe('#_materialize', function() {
    it('should assign unaltered if an object is found', function() {
      var config = new Config({example: {foo: 'bar'}}, {});
      expect(config._materialize('example').foo).to.equal('bar');
    });
  });
});
<|endoftext|>