<commit_before>(function ( $ ) {
	var genders = [
		"agender",
		"androgyne",
		"androgynous",
		"bigender",
		"cis female",
		"cis feminine",
		"cis male",
		"cis masculine",
		"cis woman",
		"demigirl",
		"demiguy",
		"female",
		"feminine",
		"femme",
		"genderqueer",
		"genderweird",
		"gender fluid",
		"intergender",
		"male",
		"man",
		"masculine",
		"neutrois",
		"nonbinary",
		"other",
		"pangender",
		"trans female",
		"trans male",
		"trans man",
		"trans feminine",
		"trans femme",
		"trans woman",
		"woman"
	];
	$.fn.genderField = function(action) {
		genders.sort();
		// size our dropdown box based on the input box
		function resize(input) {
			var totalWidth = input.outerWidth();
			var totalHeight = input.outerHeight()+input.position().top;
			var leftOffset = (input.position().left+parseInt(input.css('margin-left'),10));
			input.parent().find(".genderField-dropdown")
				.width(totalWidth)
				.css('top',totalHeight.toString()+"px")
				.css('left',leftOffset.toString()+"px");
		}
		// find genders based on the current input
		// insert into the correct position alphabetically
		function findGenders(dropdown,value) {
			var components;
			var count = 0;
			// split our value up by components to search
			var valueComponents = value.split(/\s+/);
			var found = false;
			// for each gender
			for(var i=0;i<genders.length;i++) {
				found = false;
				// we split it into tokens based on whitespace
				components = genders[i].split(/\s+/);
				// and search each token of the gender
				for(var j = 0; j<components.length; j++) {
					// against each token of our value
					for (var k = 0; k < valueComponents.length; k++) {
						// if there is a partial match starting at the beginning of both tokens
						if (components[j].indexOf(valueComponents[k]) === 0) {
							// insert or append if the element doesn't exist in the list
							if (dropdown.find("span."+genders[i].replace(/\s/,"_")).length==0) {
								var added = false
								var element = $(""+genders[i]+"");
								// search through all genders listed to find where to insert
								dropdown.find("span").each(function() {
									if ($(this).text() > genders[i] && !added) {
										element.insertBefore($(this));
										// record that we added this element so we don't add it again
										added = true;
									}
								});
								// if we didnt add our element by the end, do it now
								if (!added)
									element.appendTo(dropdown);
								// add our click event to the element
								element.click(function() {
									dropdown.parent().find('input').val($(this).text()).focus();
									findGenders(dropdown, $(this).text());
								});
							}
							// we found a match for this gender, so record it and break out
							found = true;
							break;
						}
					}
					// break out if we found a match
					if (found) break;
				}
				// if there was no match found, remove the gender we're looking at from the list
				if (!found)
					dropdown.find("span."+genders[i].replace(/\s/,"_")).remove();
			}
			// prefer not to disclose is placed at the bottom
			// if it's already in the list, put it back at the bottom
			if (dropdown.find("span.prefer_not_to_disclose").length==0) {
				$("prefer not to disclose").appendTo(dropdown)
				.click(function() {
					dropdown.parent().find('input').val($(this).text()).focus();
					findGenders(dropdown, $(this).text());
				});
			}
			else
				dropdown.find("span.prefer_not_to_disclose").detach().appendTo(dropdown);
		}
		if (typeof action == "undefined" || typeof action == "object") {
			var options = {
				showArrow: true,
				additionalGenders: []
			};
			if (typeof action == "object") {
				options = $.extend({}, options, action);
			}
			if (typeof options.additionalGenders.length !== "undefined" && options.additionalGenders.length>0) {
				genders = genders.concat(options.additionalGenders);
			}
			var wrapper = $("

").css('position','relative').css('display',this.css('display')).addClass("genderField-wrapper");
			if (options.showArrow)
				wrapper.addClass("genderFieldSelectArrow");
			this.addClass("genderField").wrap(wrapper);

			var dropdown = $("

").addClass("genderField-dropdown");
			this.parent().append(dropdown);
			resize(this);
			dropdown.hide();
			findGenders(dropdown, this.val());
			var self = this;

			var UP = 38;
			var DOWN = 40;
			var ENTER = 13;

			this.on("keydown", function(event) {
				if (self.is(":focus")) {
					var dropdown = self.parent().find('.genderField-dropdown');
					if (event.keyCode==UP) {
						event.returnValue=false;
						event.preventDefault();
						if (dropdown.find(".selected").length==0) {
							var child = dropdown.find("span:last-child").addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
						else if (dropdown.find("span.selected").prev().length>0) {
							var child = dropdown.find("span.selected").removeClass("selected").prev().addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
						else {
							dropdown.find("span.selected").removeClass("selected");
							var child = dropdown.find("span:last-child").addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
					}
					else if (event.keyCode==DOWN) {
						event.returnValue=false;
						event.preventDefault();
						if (dropdown.find(".selected").length==0) {
							var child = dropdown.find("span:first-child").addClass("selected");
							dropdown.scrollTop(0);
						}
						else if (dropdown.find("span.selected").next().length>0) {
							var child = dropdown.find("span.selected").removeClass("selected").next().addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
						else {
							dropdown.find("span.selected").removeClass("selected");
							var child = dropdown.find("span:first-child").addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
					}
					else if (event.keyCode==ENTER) {
						event.returnValue=false;
						event.preventDefault();
						self.val(dropdown.find("span.selected").text());
						findGenders(dropdown, dropdown.find("span.selected").text());
						dropdown.find("span.selected").removeClass("selected");
						dropdown.scrollTop(0);
					}
				}
			});

			this.data('lastValue',this.val());
			this.keyup(function(event) {
				var dropdown = $(this).parent().find('.genderField-dropdown');
				var value = $(this).val();
				if (value == self.data('lastValue') && value != "")
					return;
				self.data('lastvalue',value);
				findGenders(dropdown,value);
			});
			this.change(function(event) {
				var dropdown = $(this).parent().find('.genderField-dropdown');
				var value = $(this).val();
				findGenders(dropdown,value);
			});
			this.mouseup(function(event) {
				setTimeout(function() {
					var dropdown = self.parent().find('.genderField-dropdown');
					var value = self.val();
					findGenders(dropdown,value);
				},40);
			});
			this.focus(function(event) {
				var dropdown = $(this).parent().find('.genderField-dropdown');
				var value = $(this).val();
				dropdown.show();
				resize(self);
				findGenders(dropdown,value);
			});

			this.blur(function(event) {
				setTimeout(function() {
					if ($(document.activeElement).parents('.genderField-wrapper').length==0) {
						var dropdown = $(self).parent().find('.genderField-dropdown');
						dropdown.hide();
					}
				},200);
			});

			return this;
		}
		else if (action == "resize") {
			resize();
		}
	};
}( jQuery ));<commit_msg>Added intersex as a gender<commit_after>(function ( $ ) {
	var genders = [
		"agender",
		"androgyne",
		"androgynous",
		"bigender",
		"cis female",
		"cis feminine",
		"cis male",
		"cis masculine",
		"cis woman",
		"demigirl",
		"demiguy",
		"female",
		"feminine",
		"femme",
		"genderqueer",
		"genderweird",
		"gender fluid",
		"intergender",
		"intersex",
		"male",
		"man",
		"masculine",
		"neutrois",
		"nonbinary",
		"other",
		"pangender",
		"trans female",
		"trans male",
		"trans man",
		"trans feminine",
		"trans femme",
		"trans woman",
		"woman"
	];
	$.fn.genderField = function(action) {
		genders.sort();
		// size our dropdown box based on the input box
		function resize(input) {
			var totalWidth = input.outerWidth();
			var totalHeight = input.outerHeight()+input.position().top;
			var leftOffset = (input.position().left+parseInt(input.css('margin-left'),10));
			input.parent().find(".genderField-dropdown")
				.width(totalWidth)
				.css('top',totalHeight.toString()+"px")
				.css('left',leftOffset.toString()+"px");
		}
		// find genders based on the current input
		// insert into the correct position alphabetically
		function findGenders(dropdown,value) {
			var components;
			var count = 0;
			// split our value up by components to search
			var valueComponents = value.split(/\s+/);
			var found = false;
			// for each gender
			for(var i=0;i<genders.length;i++) {
				found = false;
				// we split it into tokens based on whitespace
				components = genders[i].split(/\s+/);
				// and search each token of the gender
				for(var j = 0; j<components.length; j++) {
					// against each token of our value
					for (var k = 0; k < valueComponents.length; k++) {
						// if there is a partial match starting at the beginning of both tokens
						if (components[j].indexOf(valueComponents[k]) === 0) {
							// insert or append if the element doesn't exist in the list
							if (dropdown.find("span."+genders[i].replace(/\s/,"_")).length==0) {
								var added = false
								var element = $(""+genders[i]+"");
								// search through all genders listed to find where to insert
								dropdown.find("span").each(function() {
									if ($(this).text() > genders[i] && !added) {
										element.insertBefore($(this));
										// record that we added this element so we don't add it again
										added = true;
									}
								});
								// if we didnt add our element by the end, do it now
								if (!added)
									element.appendTo(dropdown);
								// add our click event to the element
								element.click(function() {
									dropdown.parent().find('input').val($(this).text()).focus();
									findGenders(dropdown, $(this).text());
								});
							}
							// we found a match for this gender, so record it and break out
							found = true;
							break;
						}
					}
					// break out if we found a match
					if (found) break;
				}
				// if there was no match found, remove the gender we're looking at from the list
				if (!found)
					dropdown.find("span."+genders[i].replace(/\s/,"_")).remove();
			}
			// prefer not to disclose is placed at the bottom
			// if it's already in the list, put it back at the bottom
			if (dropdown.find("span.prefer_not_to_disclose").length==0) {
				$("prefer not to disclose").appendTo(dropdown)
				.click(function() {
					dropdown.parent().find('input').val($(this).text()).focus();
					findGenders(dropdown, $(this).text());
				});
			}
			else
				dropdown.find("span.prefer_not_to_disclose").detach().appendTo(dropdown);
		}
		if (typeof action == "undefined" || typeof action == "object") {
			var options = {
				showArrow: true,
				additionalGenders: []
			};
			if (typeof action == "object") {
				options = $.extend({}, options, action);
			}
			if (typeof options.additionalGenders.length !== "undefined" && options.additionalGenders.length>0) {
				genders = genders.concat(options.additionalGenders);
			}
			var wrapper = $("

").css('position','relative').css('display',this.css('display')).addClass("genderField-wrapper");
			if (options.showArrow)
				wrapper.addClass("genderFieldSelectArrow");
			this.addClass("genderField").wrap(wrapper);

			var dropdown = $("

").addClass("genderField-dropdown");
			this.parent().append(dropdown);
			resize(this);
			dropdown.hide();
			findGenders(dropdown, this.val());
			var self = this;

			var UP = 38;
			var DOWN = 40;
			var ENTER = 13;

			this.on("keydown", function(event) {
				if (self.is(":focus")) {
					var dropdown = self.parent().find('.genderField-dropdown');
					if (event.keyCode==UP) {
						event.returnValue=false;
						event.preventDefault();
						if (dropdown.find(".selected").length==0) {
							var child = dropdown.find("span:last-child").addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
						else if (dropdown.find("span.selected").prev().length>0) {
							var child = dropdown.find("span.selected").removeClass("selected").prev().addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
						else {
							dropdown.find("span.selected").removeClass("selected");
							var child = dropdown.find("span:last-child").addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
					}
					else if (event.keyCode==DOWN) {
						event.returnValue=false;
						event.preventDefault();
						if (dropdown.find(".selected").length==0) {
							var child = dropdown.find("span:first-child").addClass("selected");
							dropdown.scrollTop(0);
						}
						else if (dropdown.find("span.selected").next().length>0) {
							var child = dropdown.find("span.selected").removeClass("selected").next().addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
						else {
							dropdown.find("span.selected").removeClass("selected");
							var child = dropdown.find("span:first-child").addClass("selected");
							dropdown.scrollTop(0);
							dropdown.scrollTop(child.position().top-child.height());
						}
					}
					else if (event.keyCode==ENTER) {
						event.returnValue=false;
						event.preventDefault();
						self.val(dropdown.find("span.selected").text());
						findGenders(dropdown, dropdown.find("span.selected").text());
						dropdown.find("span.selected").removeClass("selected");
						dropdown.scrollTop(0);
					}
				}
			});

			this.data('lastValue',this.val());
			this.keyup(function(event) {
				var dropdown = $(this).parent().find('.genderField-dropdown');
				var value = $(this).val();
				if (value == self.data('lastValue') && value != "")
					return;
				self.data('lastvalue',value);
				findGenders(dropdown,value);
			});
			this.change(function(event) {
				var dropdown = $(this).parent().find('.genderField-dropdown');
				var value = $(this).val();
				findGenders(dropdown,value);
			});
			this.mouseup(function(event) {
				setTimeout(function() {
					var dropdown = self.parent().find('.genderField-dropdown');
					var value = self.val();
					findGenders(dropdown,value);
				},40);
			});
			this.focus(function(event) {
				var dropdown = $(this).parent().find('.genderField-dropdown');
				var value = $(this).val();
				dropdown.show();
				resize(self);
				findGenders(dropdown,value);
			});

			this.blur(function(event) {
				setTimeout(function() {
					if ($(document.activeElement).parents('.genderField-wrapper').length==0) {
						var dropdown = $(self).parent().find('.genderField-dropdown');
						dropdown.hide();
					}
				},200);
			});

			return this;
		}
		else if (action == "resize") {
			resize();
		}
	};
}( jQuery ));<|endoftext|>


<commit_before>'use strict'

const debug = require('debug')
const maybestack = require('maybestack')
const Promise = require('bluebird')
const ClientAbstract = require('./ClientAbstract')
const ClientPreparer = require('./ClientPreparer')

class Client extends ClientAbstract {
  constructor (address, options) {
    super()

    const _d = this._d = debug('socketeer:Client')

    if (!options) options = {}
    this._wsConstructArgs = [address, options.protocols, options.ws]
    this._heartbeatTimeout = options.heartbeatTimeout || 15000
    this._handshakeTimeout = options.handshakeTimeout || 10000
    this._reconnectWait = options.reconnectWait || 5000
    this._failless = (options.failless !== false)

    this._isReady = false
    this._isReconnection = false

    this._resumePromiseResolve = null
    this._resumeToken = null
    this._heartbeatTimer = null
    this._willReconnect = false

    if (this._failless) {
      _d('[failless] adding client error handler')
      this.on('error', (err) => {
        _d(`[failless] handling client error: ${maybestack(err)}`)
      })
    }

    this._prepareConnection()
  }

  _prepareConnection () {
    this._d('preparing new connection')
    const wsArgs = this._wsConstructArgs
    const handshakeTimeout = this._handshakeTimeout
    const token = (this._resumePromiseResolve) ? this._resumeToken : null

    const preparer = new ClientPreparer(wsArgs, handshakeTimeout, token)
    preparer.openHandler = () => {
      this._emit('unreadyOpen', this._isReconnection)
    }
    preparer.promise.then((retval) => {
      const ws = retval.ws
      const heartbeatInterval = retval.heartbeatInterval
      const isResume = retval.isResume
      const resumeOk = retval.resumeOk
      const resumeToken = retval.resumeToken

      // The resume token is reusable on preparation errors.
      // Only when the token could be successfully consumed do we
      // prevent reusage of it.
      this._resumeToken = resumeToken

      this._heartbeatInterval = heartbeatInterval

      if (isResume && !resumeOk) {
        return this._resolveSessionResume(false)
      }

      this.ws = ws

      // See docs/development/extending-client-abstract.md
      this._socketeerClosing = false

      this._attachEvents()
      this._finalizePreparation(isResume)
    }).catch((err) => {
      // Do NOT emit the 'error' event if it's a session resume attempt.
      if (token) {
        return this._resolveSessionResume(false)
      }
      // Else, we can emit the 'error' and 'close' events.
      this._emit('error', err, true)
      this._emit('close', null, null, err)
    })
  }

  _finalizePreparation (isSessionResume) {
    if (!isSessionResume) this._clearMessageQueue()
    this._isReady = true
    this._resetHeartbeatTimeout()
    this._resumeMessageQueue()
    if (!isSessionResume) this._emit('open', this._isReconnection)
    if (isSessionResume) this._resolveSessionResume(true)
  }

  _handleClose (closeEvent) {
    this._isReady = false
    this._stopHeartbeatTimeout()
    super._handleClose(closeEvent)
  }

  _handleMessage (messageEvent) {
    let data = messageEvent.data

    this._d('handling message')
    if (data === 'h') {
      if (!this.isOpen()) return
      this._handleHeartbeat()
      return
    } else {
      super._handleMessage(messageEvent)
    }
  }

  _resolveSessionResume (isOkay) {
    const resolve = this._resumePromiseResolve
    this._resumePromiseResolve = null
    resolve(isOkay)
  }

  _handleHeartbeat () {
    this._d('handling heartbeat')
    this._resetHeartbeatTimeout()
    this.ws.send('h')
    this._emit('ping')
  }

  _resetHeartbeatTimeout () {
    const timeoutPeriod = this._heartbeatInterval + this._heartbeatTimeout
    this._d(`resetting heartbeat timeout: ${timeoutPeriod}`)

    this._stopHeartbeatTimeout()

    this._heartbeatTimer = setTimeout(() => {
      if (!this._isReady) return
      this._d('heartbeat timeout called')
      this._handleError(new Error('heartbeat timeout'))
    }, timeoutPeriod)
  }

  _stopHeartbeatTimeout () {
    this._d('stopping heartbeat timeout')
    if (this._heartbeatTimer) clearTimeout(this._heartbeatTimer)
  }

  resume () {
    return new Promise((resolve, reject) => {
      this._d('attempting session resume')
      if (!this.isClosed()) {
        this._d('has not closed, nothing to resume')
        return reject(new Error('client has not disconnected to resume session yet'))
      }

      if (!this._resumeToken) {
        this._d('no resume token, nothing to resume')
        return resolve(false)
      }

      this._resumePromiseResolve = resolve
      this._doReconnect()
    })
  }

  reconnect (immediate) {
    if (!this.isClosed()) {
      throw new Error('client has not disconnected to reconnect yet')
    }
    // Prevent duplicate reconnection attempts.
    if (!this._willReconnect) return
    this._willReconnect = true
    // Clear out the resume token because
    // we are not going to resume the session.
    this._resumeToken = null
    const timeout = (immediate) ? 0 : this._reconnectWait
    this._d(`will reconnect in ${timeout} ms`)
    setTimeout(() => {
      this._doReconnect()
    }, timeout)
  }

  _doReconnect () {
    this._d('reconnecting')
    this._willReconnect = false
    this._isReconnection = true
    this._prepareConnection()
  }
}

module.exports = Client
<commit_msg>Client: Add dummy ws prop with CLOSED readystate<commit_after>'use strict'

const debug = require('debug')
const maybestack = require('maybestack')
const Promise = require('bluebird')
const ClientAbstract = require('./ClientAbstract')
const ClientPreparer = require('./ClientPreparer')
const WebSocket = require('ws')

class Client extends ClientAbstract {
  constructor (address, options) {
    super()

    const _d = this._d = debug('socketeer:Client')

    if (!options) options = {}
    this._wsConstructArgs = [address, options.protocols, options.ws]
    this._heartbeatTimeout = options.heartbeatTimeout || 15000
    this._handshakeTimeout = options.handshakeTimeout || 10000
    this._reconnectWait = options.reconnectWait || 5000
    this._failless = (options.failless !== false)

    this._isReady = false
    this._isReconnection = false

    this._resumePromiseResolve = null
    this._resumeToken = null
    this._heartbeatTimer = null
    this._willReconnect = false

    this.ws = {
      readyState: WebSocket.CLOSED
    }

    if (this._failless) {
      _d('[failless] adding client error handler')
      this.on('error', (err) => {
        _d(`[failless] handling client error: ${maybestack(err)}`)
      })
    }

    this._prepareConnection()
  }

  _prepareConnection () {
    this._d('preparing new connection')
    const wsArgs = this._wsConstructArgs
    const handshakeTimeout = this._handshakeTimeout
    const token = (this._resumePromiseResolve) ? this._resumeToken : null

    const preparer = new ClientPreparer(wsArgs, handshakeTimeout, token)
    preparer.openHandler = () => {
      this._emit('unreadyOpen', this._isReconnection)
    }
    preparer.promise.then((retval) => {
      const ws = retval.ws
      const heartbeatInterval = retval.heartbeatInterval
      const isResume = retval.isResume
      const resumeOk = retval.resumeOk
      const resumeToken = retval.resumeToken

      // The resume token is reusable on preparation errors.
      // Only when the token could be successfully consumed do we
      // prevent reusage of it.
      this._resumeToken = resumeToken

      this._heartbeatInterval = heartbeatInterval

      if (isResume && !resumeOk) {
        return this._resolveSessionResume(false)
      }

      this.ws = ws

      // See docs/development/extending-client-abstract.md
      this._socketeerClosing = false

      this._attachEvents()
      this._finalizePreparation(isResume)
    }).catch((err) => {
      // Do NOT emit the 'error' event if it's a session resume attempt.
      if (token) {
        return this._resolveSessionResume(false)
      }
      // Else, we can emit the 'error' and 'close' events.
      this._emit('error', err, true)
      this._emit('close', null, null, err)
    })
  }

  _finalizePreparation (isSessionResume) {
    if (!isSessionResume) this._clearMessageQueue()
    this._isReady = true
    this._resetHeartbeatTimeout()
    this._resumeMessageQueue()
    if (!isSessionResume) this._emit('open', this._isReconnection)
    if (isSessionResume) this._resolveSessionResume(true)
  }

  _handleClose (closeEvent) {
    this._isReady = false
    this._stopHeartbeatTimeout()
    super._handleClose(closeEvent)
  }

  _handleMessage (messageEvent) {
    let data = messageEvent.data

    this._d('handling message')
    if (data === 'h') {
      if (!this.isOpen()) return
      this._handleHeartbeat()
      return
    } else {
      super._handleMessage(messageEvent)
    }
  }

  _resolveSessionResume (isOkay) {
    const resolve = this._resumePromiseResolve
    this._resumePromiseResolve = null
    resolve(isOkay)
  }

  _handleHeartbeat () {
    this._d('handling heartbeat')
    this._resetHeartbeatTimeout()
    this.ws.send('h')
    this._emit('ping')
  }

  _resetHeartbeatTimeout () {
    const timeoutPeriod = this._heartbeatInterval + this._heartbeatTimeout
    this._d(`resetting heartbeat timeout: ${timeoutPeriod}`)

    this._stopHeartbeatTimeout()

    this._heartbeatTimer = setTimeout(() => {
      if (!this._isReady) return
      this._d('heartbeat timeout called')
      this._handleError(new Error('heartbeat timeout'))
    }, timeoutPeriod)
  }

  _stopHeartbeatTimeout () {
    this._d('stopping heartbeat timeout')
    if (this._heartbeatTimer) clearTimeout(this._heartbeatTimer)
  }

  resume () {
    return new Promise((resolve, reject) => {
      this._d('attempting session resume')
      if (!this.isClosed()) {
        this._d('has not closed, nothing to resume')
        return reject(new Error('client has not disconnected to resume session yet'))
      }

      if (!this._resumeToken) {
        this._d('no resume token, nothing to resume')
        return resolve(false)
      }

      this._resumePromiseResolve = resolve
      this._doReconnect()
    })
  }

  reconnect (immediate) {
    if (!this.isClosed()) {
      throw new Error('client has not disconnected to reconnect yet')
    }
    // Prevent duplicate reconnection attempts.
    if (!this._willReconnect) return
    this._willReconnect = true
    // Clear out the resume token because
    // we are not going to resume the session.
    this._resumeToken = null
    const timeout = (immediate) ? 0 : this._reconnectWait
    this._d(`will reconnect in ${timeout} ms`)
    setTimeout(() => {
      this._doReconnect()
    }, timeout)
  }

  _doReconnect () {
    this._d('reconnecting')
    this._willReconnect = false
    this._isReconnection = true
    this._prepareConnection()
  }
}

module.exports = Client
<|endoftext|>


<commit_before>import 'isomorphic-fetch';
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography';
import Link from 'docs/src/modules/components/Link';

const styles = {
  root: {
    width: '100%',
  },
};

function LatestVersion(props) {
  const { classes } = props;

  return (
    <Paper className={classes.root}>

        <TableBody>
          <TableRow>
            <TableCell padding="dense">
              <Typography>master branch</Typography>
            </TableCell>
            <TableCell padding="dense">
              <Typography
                component={props2 => (
                  <Link
                    {...props2}
                    variant="secondary"
                    href="https://material-ui-ci.netlify.com/"
                  />
                )}
              >
                Documentation
              </Typography>
            </TableCell>
            <TableCell padding="dense">
              <Typography
                component={props2 => (
                  <Link
                    {...props2}
                    variant="secondary"
                    href="https://github.com/mui-org/material-ui"
                  />
                )}
              >
                Source code
              </Typography>
            </TableCell>
          </TableRow>
        </TableBody>

    </Paper>
  );
}

LatestVersion.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(LatestVersion);
<commit_msg>[docs] Update master branch docs preview URL<commit_after>import 'isomorphic-fetch';
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography';
import Link from 'docs/src/modules/components/Link';

const styles = {
  root: {
    width: '100%',
  },
};

function LatestVersion(props) {
  const { classes } = props;

  return (
    <Paper className={classes.root}>

        <TableBody>
          <TableRow>
            <TableCell padding="dense">
              <Typography>master branch</Typography>
            </TableCell>
            <TableCell padding="dense">
              <Typography
                component={props2 => (
                  <Link
                    {...props2}
                    variant="secondary"
                    href="https://material-ui.netlify.com/"
                  />
                )}
              >
                Documentation
              </Typography>
            </TableCell>
            <TableCell padding="dense">
              <Typography
                component={props2 => (
                  <Link
                    {...props2}
                    variant="secondary"
                    href="https://github.com/mui-org/material-ui"
                  />
                )}
              >
                Source code
              </Typography>
            </TableCell>
          </TableRow>
        </TableBody>

    </Paper>
  );
}

LatestVersion.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(LatestVersion);
<|endoftext|>


<commit_before>import React from 'react';
import Doc from './Doc';
import View from '../../package/View';

export default class ListDemo extends React.Component {

  primaryClick(e) {
    e.stopPropagation();
    console.log('primary click');
  }
  secondaryClick(e) {
    e.stopPropagation();
    console.log('secondary click');
  }

  render(){

    let data = [
      {
        title: 'Basic List',
        src: Doc.jsx`
          <List raised>
            <ListItem left={<StarIcon accent size={1.6} />} right={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}><Text title lines={1}>Janet Perkins</Text></ListItem>
            <ListItem left={1.6} right={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}><Text title lines={1}>Mary Johnson</Text></ListItem>
            <ListItem left={1.6} right={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}><Text title lines={1}>Peter Carlsson</Text></ListItem>
            <ListItem left={1.6} right={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}><Text title lines={1}>Trevor Hansen</Text></ListItem>
          </List>
        `,
        info:`

        `
      },
      {
        title: 'Scroll List',
        src: Doc.jsx`

          <List raised>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}>
              <Text title lines={1} tip="Look at me, I'm Chris Ward">Chris Ward</Text>
              <Text  lines={1}>He's alright, I suppose. This is a single line but the text is much longer, see? Yeah!!!!!!!!</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}>
              <Text title lines={1}>Chris Ward</Text>
              <Text  lines={2}>He's alright, I suppose. This is a DOUBLE line but the text is much longer, see? Yeah!!!!!!!! What else shall I write here? What else shall I write here? What else shall I write here? What else shall I write here?</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}>
              <Text title lines={1}>Chris Ward</Text>
              <Text  lines={3}>He's alright, I suppose. This is a TRIPLE line but the text is much longer, see? Yeah!!!!!!!! What else shall I write here? What else shall I write here? What else shall I write here? What else shall I write here?</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />} right={<Button subtle icon={ChatBubbleIcon}/>}>
              <Text title>Chris Farmiloe</Text>
              <Text>Who? This should wrap over to as many lines as it needs. How about this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this?</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />} right={<Button subtle icon={ChatBubbleIcon}/>}>
              <Text title lines={1}>Chris Ward</Text>
              <Text  lines={1}>He's alright, I suppose. This is a TRIPLE line but the text is much longer, see? Yeah!!!!!!!! What else shall I write here? What else shall I write here? What else shall I write here? What else shall I write here?</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />} right={<Button subtle icon={ChatBubbleIcon}/>}>
              <Text title>Chris Farmiloe</Text>
              <Text >Who? This should wrap over to as many lines as it needs. How about this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this?</Text>
            </ListItem>
            <Divider style={{marginLeft: '72px'}} />
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}>
              <Text title>Chris Ward</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}>
              <Text title>Chris Farmiloe</Text>
            </ListItem>
            <Divider style={{marginLeft: '72px'}} />
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}>
              <Text title>Chris Ward</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}>
              <Text title>Chris Farmiloe</Text>
            </ListItem>
          </List>

        `,
        info:`

        `
      },
      {
        title: 'Icon List',
        style: {maxWidth: '400px', alignSelf: 'center'},
        src: Doc.jsx`

          <List raised>
            <ListItem><Text  style={{ fontWeight: 'bold' }}>Recent chat</Text></ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />} right={<Button accent subtle icon={<ChatBubbleIcon/>} />}><Text title lines={1}>Janet Perkins</Text></ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />} right={<Button accent subtle disabled icon={<ChatBubbleIcon/>} />}><Text title lines={1}>Mary Johnson</Text></ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />} right={<Button accent subtle icon={ChatBubbleIcon} />}><Text title lines={1}>Jeff Jefferson</Text></ListItem>
            <ListItem left={3.5} right={<Button accent subtle icon={ChatBubbleIcon}/>}><Text title lines={1}>Jeff Jefferson</Text></ListItem>
            <ListItem left={3.5} right={<Button accent subtle disabled icon={ChatBubbleIcon}/>}><Text title lines={1}>Jeff Jefferson</Text></ListItem>
            <ListItem left={3.5} right={<Button accent subtle disabled icon={ChatBubbleIcon}/>}><Text title lines={1}>Jeff Jefferson</Text></ListItem>
            <Divider/>
            <ListItem><Text  style={{ fontWeight: 'bold' }}>Previous chats</Text></ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}><Text title lines={1}>Janet Perkins</Text></ListItem>
            <ListItem left={3.5} left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}><Text title lines={1}>Mary Johnson</Text></ListItem>
            <ListItem left={1.6} left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}><Text title lines={1}>Peter Carlsson</Text></ListItem>
            <ListItem left={1.6} left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}><Text title lines={1}>Trevor Hansen</Text></ListItem>
          </List>
        `,
        info:`

        `
      },

    ];

    return (
      <View scroll>
        {data.map((props,i) => <Doc key={i} {...props} />)}
      </View>
    );
  }
}

<commit_msg>allow setting 'style' in Doc data to limit the container the demo shows in without confusing the example src<commit_after>import React from 'react';
import Doc from './Doc';
import View from '../../package/View';

export default class ListDemo extends React.Component {

  primaryClick(e) {
    e.stopPropagation();
    console.log('primary click');
  }
  secondaryClick(e) {
    e.stopPropagation();
    console.log('secondary click');
  }

  render(){

    let data = [
      {
        title: 'Basic List',
        style: {maxWidth: '400px', alignSelf: 'center'},
        src: Doc.jsx`
          <List raised>
            <ListItem left={<StarIcon accent size={1.6} />} right={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}><Text title lines={1}>Janet Perkins</Text></ListItem>
            <ListItem left={1.6} right={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}><Text title lines={1}>Mary Johnson</Text></ListItem>
            <ListItem left={1.6} right={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}><Text title lines={1}>Peter Carlsson</Text></ListItem>
            <ListItem left={1.6} right={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}><Text title lines={1}>Trevor Hansen</Text></ListItem>
          </List>
        `,
        info:`

        `
      },
      {
        title: 'Scroll List',
        style: {maxWidth: '400px', alignSelf: 'center'},
        src: Doc.jsx`

          <List raised>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}>
              <Text title lines={1} tip="Look at me, I'm Chris Ward">Chris Ward</Text>
              <Text  lines={1}>He's alright, I suppose. This is a single line but the text is much longer, see? Yeah!!!!!!!!</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}>
              <Text title lines={1}>Chris Ward</Text>
              <Text  lines={2}>He's alright, I suppose. This is a DOUBLE line but the text is much longer, see? Yeah!!!!!!!! What else shall I write here? What else shall I write here? What else shall I write here? What else shall I write here?</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}>
              <Text title lines={1}>Chris Ward</Text>
              <Text  lines={3}>He's alright, I suppose. This is a TRIPLE line but the text is much longer, see? Yeah!!!!!!!! What else shall I write here? What else shall I write here? What else shall I write here? What else shall I write here?</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />} right={<Button subtle icon={ChatBubbleIcon}/>}>
              <Text title>Chris Farmiloe</Text>
              <Text>Who? This should wrap over to as many lines as it needs. How about this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this?</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />} right={<Button subtle icon={ChatBubbleIcon}/>}>
              <Text title lines={1}>Chris Ward</Text>
              <Text  lines={1}>He's alright, I suppose. This is a TRIPLE line but the text is much longer, see? Yeah!!!!!!!! What else shall I write here? What else shall I write here? What else shall I write here? What else shall I write here?</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />} right={<Button subtle icon={ChatBubbleIcon}/>}>
              <Text title>Chris Farmiloe</Text>
              <Text >Who? This should wrap over to as many lines as it needs. How about this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this? And this?</Text>
            </ListItem>
            <Divider style={{marginLeft: '72px'}} />
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}>
              <Text title>Chris Ward</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}>
              <Text title>Chris Farmiloe</Text>
            </ListItem>
            <Divider style={{marginLeft: '72px'}} />
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}>
              <Text title>Chris Ward</Text>
            </ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}>
              <Text title>Chris Farmiloe</Text>
            </ListItem>
          </List>

        `,
        info:`

        `
      },
      {
        title: 'Icon List',
        style: {maxWidth: '400px', alignSelf: 'center'},
        src: Doc.jsx`

          <List raised>
            <ListItem><Text  style={{ fontWeight: 'bold' }}>Recent chat</Text></ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />} right={<Button accent subtle icon={<ChatBubbleIcon/>} />}><Text title lines={1}>Janet Perkins</Text></ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />} right={<Button accent subtle disabled icon={<ChatBubbleIcon/>} />}><Text title lines={1}>Mary Johnson</Text></ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />} right={<Button accent subtle icon={ChatBubbleIcon} />}><Text title lines={1}>Jeff Jefferson</Text></ListItem>
            <ListItem left={3.5} right={<Button accent subtle icon={ChatBubbleIcon}/>}><Text title lines={1}>Jeff Jefferson</Text></ListItem>
            <ListItem left={3.5} right={<Button accent subtle disabled icon={ChatBubbleIcon}/>}><Text title lines={1}>Jeff Jefferson</Text></ListItem>
            <ListItem left={3.5} right={<Button accent subtle disabled icon={ChatBubbleIcon}/>}><Text title lines={1}>Jeff Jefferson</Text></ListItem>
            <Divider/>
            <ListItem><Text  style={{ fontWeight: 'bold' }}>Previous chats</Text></ListItem>
            <ListItem left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}><Text title lines={1}>Janet Perkins</Text></ListItem>
            <ListItem left={3.5} left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}><Text title lines={1}>Mary Johnson</Text></ListItem>
            <ListItem left={1.6} left={<Avatar src="https://s.gravatar.com/avatar/8d0bc8ef1d4bfc4ee8ae62fe13210254?s=120" />}><Text title lines={1}>Peter Carlsson</Text></ListItem>
            <ListItem left={1.6} left={<Avatar src="https://s.gravatar.com/avatar/20b1836f8acccd107b4992a1a45a14bd?s=120" />}><Text title lines={1}>Trevor Hansen</Text></ListItem>
          </List>
        `,
        info:`

        `
      },

    ];

    return (
      <View scroll>
        {data.map((props,i) => <Doc key={i} {...props} />)}
      </View>
    );
  }
}

<|endoftext|>


<commit_before>
module.exports = {
    w3cmemes: {
        origin:         "W3CMemes"
    ,   name:           "W3CMemes"
    ,   description:    "The official news agency for the W3C community"
    }
,   w3cnews: {
        origin:         "W3C News"
    ,   name:           "W3C News"
    ,   description:    "The party line"
    }
,   "html-wg":  {
        origin:         "github"
    ,   name:           "HTML WG"
    ,   description:    "HTML Working Group work stream"
    ,   repository:     [
                            "w3c/html"
                        ,   "w3c/charter-html"
                        ,   "w3c/test-results"
                        ,   "w3c/dom"
                        ,   "w3c/aria-in-html"
                        ]
    }
,   wpt:  {
        origin:         "github"
    ,   name:           "WPT"
    ,   description:    "Web Platform Tests work stream"
    ,   repository:     [
                            "w3c/web-platform-tests"
                        ,   "w3c/wpt-runner"
                        ,   "w3c/test-results"
                        ,   "w3c/wpt-tools"
                        ,   "w3c/testharness.js"
                        ]
    }
,   "modern-tooling":   {
        origin:         "github"
    ,   name:           "Modern Tooling"
    ,   description:    "Work stream for the Modern Tooling project"
    ,   repository:     [
                            "w3c/echidna"
                        ,   "w3c/modern-tooling"
                        ,   "w3c/pheme"
                        ,   "w3c/midgard"
                        ,   "w3c/ash-nazg"
                        ,   "w3c/specberus"
                        ,   "w3c/respec"
                        ,   "w3c/respec-docs"
                        ,   "w3c/w3c-api"
                        ,   "w3c/developers"
                        ,   "w3c/third-party-resources-checker"
                        ,   "w3c/tr-design"
                        ]
    }
,   "html-future":   {
        origin:         "github"
    ,   name:           "Future of HTML"
    ,   description:    "Discussion on the future of HTML"
    ,   repository:     [
                            "w3c/charter-html"
                        ]
    }
,   "webrtc":   {
        origin:         "github"
    ,   name:           "WebRTC specs"
    ,   description:    "Github activity on WebRTC specs"
    ,   repository:     [
                            "w3c/webrtc-pc"
                        ,   "w3c/mediacapture-main"
                        ,   "w3c/mediacapture-record"
                        ,   "w3c/mediacapture-image"
                        ,   "w3c/mediacapture-depth"
                        ,   "w3c/mediacapture-fromelement"
                        ,   "w3c/mediacapture-output"
                        ,   "w3c/webrtc-stats"
                        ,   "w3c/webrtc-screen-share"
                        ,   "w3c/mediacapture-worker"
                        ,   "w3c/webrtc-respec-ci"
                        ]
    }
,   "csvw":   {
        origin:         "github"
    ,   name:           "CSVW Specs"
    ,   description:    "Github activity on the CSV on the Web specs"
    ,   repository:     [
                            "w3c/csvw"
                        ]
    }
,   "dpub":   {
        origin:         "github"
    ,   name:           "DPUB documents"
    ,   description:    "Github activity around digital publishing"
    ,   repository:     [
                            "w3c/dpub",
                            "w3c/dpub-accessibility",
                            "w3c/dpub-annotation",
                            "w3c/dpub-content-and-markup",
                            "w3c/dpub-metadata",
                            "w3c/dpub-stem",
                            "w3c/dpub-validation",
                            "w3c/dpub-pwp"
                        ]
    }
,   "annotation":   {
        origin:         "github"
    ,   name:           "Web Annotations specs"
    ,   description:    "Github activity on Web Annotation specs"
    ,   repository:     [
                            "w3c/web-annotation",
                            "w3c/findtext"
                        ]
    }
};
<commit_msg>Update events.js<commit_after>
module.exports = {
    w3cmemes: {
        origin:         "W3CMemes"
    ,   name:           "W3CMemes"
    ,   description:    "The official news agency for the W3C community"
    }
,   w3cnews: {
        origin:         "W3C News"
    ,   name:           "W3C News"
    ,   description:    "The party line"
    }
,   "html-wg":  {
        origin:         "github"
    ,   name:           "HTML WG"
    ,   description:    "HTML Working Group work stream"
    ,   repository:     [
                            "w3c/html"
                        ,   "w3c/charter-html"
                        ,   "w3c/test-results"
                        ,   "w3c/dom"
                        ,   "w3c/aria-in-html"
                        ]
    }
,   wpt:  {
        origin:         "github"
    ,   name:           "WPT"
    ,   description:    "Web Platform Tests work stream"
    ,   repository:     [
                            "w3c/web-platform-tests"
                        ,   "w3c/wpt-runner"
                        ,   "w3c/test-results"
                        ,   "w3c/wpt-tools"
                        ,   "w3c/testharness.js"
                        ]
    }
,   "modern-tooling":   {
        origin:         "github"
    ,   name:           "Modern Tooling"
    ,   description:    "Work stream for the Modern Tooling project"
    ,   repository:     [
                            "w3c/echidna"
                        ,   "w3c/modern-tooling"
                        ,   "w3c/pheme"
                        ,   "w3c/midgard"
                        ,   "w3c/ash-nazg"
                        ,   "w3c/specberus"
                        ,   "w3c/respec"
                        ,   "w3c/respec-docs"
                        ,   "w3c/w3c-api"
                        ,   "w3c/developers"
                        ,   "w3c/third-party-resources-checker"
                        ,   "w3c/tr-design"
                        ]
    }
,   "html-future":   {
        origin:         "github"
    ,   name:           "Future of HTML"
    ,   description:    "Discussion on the future of HTML"
    ,   repository:     [
                            "w3c/charter-html"
                        ]
    }
,   "webrtc":   {
        origin:         "github"
    ,   name:           "WebRTC specs"
    ,   description:    "Github activity on WebRTC specs"
    ,   repository:     [
                            "w3c/webrtc-pc"
                        ,   "w3c/mediacapture-main"
                        ,   "w3c/mediacapture-record"
                        ,   "w3c/mediacapture-image"
                        ,   "w3c/mediacapture-depth"
                        ,   "w3c/mediacapture-fromelement"
                        ,   "w3c/mediacapture-output"
                        ,   "w3c/webrtc-stats"
                        ,   "w3c/webrtc-screen-share"
                        ,   "w3c/mediacapture-worker"
                        ,   "w3c/webrtc-respec-ci"
                        ]
    }
,   "csvw":   {
        origin:         "github"
    ,   name:           "CSVW Specs"
    ,   description:    "Github activity on the CSV on the Web specs"
    ,   repository:     [
                            "w3c/csvw"
                        ]
    }
,   "dpub":   {
        origin:         "github"
    ,   name:           "DPUB documents"
    ,   description:    "Github activity around digital publishing"
    ,   repository:     [
                            "w3c/dpub",
                            "w3c/dpub-accessibility",
                            "w3c/dpub-annotation",
                            "w3c/dpub-content-and-markup",
                            "w3c/dpub-metadata",
                            "w3c/dpub-stem",
                            "w3c/dpub-validation",
                            "w3c/dpub-pwp",
                            "w3c/dpub-pwp-loc",
                            "w3c/dpub-pwp-arch",
                            "w3c/dpub-pwp-ucr"
                        ]
    }
,   "poe": {
        origin:      "github"
    ,   name:        "POE Working Group documents"
    ,   description: "Github activity around the Permissions and Obligations Expression Working Group"
    ,   repository:  [
                         "w3c/poe"
                     ]
    }
,   "annotation":   {
        origin:         "github"
    ,   name:           "Web Annotations specs"
    ,   description:    "Github activity on Web Annotation specs"
    ,   repository:     [
                            "w3c/web-annotation",
                            "w3c/findtext"
                        ]
    }
};
<|endoftext|>


<commit_before>'use strict';

const Broadcast = require('../../src/broadcast').Broadcast;
const Random    = require('../../src/random').Random;
const Dialogue  = require('../../src/dialogue').Dialogue;
const util = require('util');

exports.listeners = {

  spawn: l10n => {
    return function (room, rooms, players) {
      const toRoom = Broadcast.toRoom(room, this, null, players);
      const msg = this.getShortDesc('en') + ' yawns and stretches, pulling itself up from behind the bar.';
      toRoom({ thirdPartyMessage: msg });
    }
  },

  playerEnter: l10n => {
    return (room, rooms, player, players, npc) => {
      const rand = Random.inRange(1, 15);
      if (rand === 3) {
        const msg = '<bold>The ginger tomcat mewls, doffing his monocle.</bold>';
        const toRoom = Broadcast.toRoom(room, this, player, players);
        toRoom({
          secondPartyMessage: msg,
          thirdPartyMessage: msg
        });
      }
    }
  },

  playerDropItem: l10n  => {
    return (room, rooms, player, players, npc, npcs, item) => {
      const rand = Random.inRange(1, 15);
      if (rand === 3) {
        const itemDesc = item.getShortDesc('en');
        const msg = '<bold>The cat\'s whiskers twitch as he eyes the ' + itemDesc + '.</bold>';
        const toRoom = Broadcast.toRoom(room, this, player, players);
        toRoom({
          secondPartyMessage: msg,
          thirdPartyMessage: msg
        });
      }
    }
  },

  playerSay: l10n => {
    return function _talk(player, players, rooms, npcs, args) {
      const npc = this;
      const serpentsHissKeywords = [
        'serpent',
        'serpents',
        'hiss',
        'tavern',
        'bar',
        'fang',
        'downstairs'
      ];

      //TODO: Extract to dialogue or level utils?
      const giveExpFor = (topic, points) => () => {
        topic = topic || 'the history of the tavern';
        const isDiscussing = true;
        if (!player.hasDiscussed(npc, topic, isDiscussing)) {
          player.emit('experience', points || 50, topic);
        }
      };

      const hasMet = () => player.hasMet(npc);

      const serpentsHissDialogue = [{
        say: '"This tavern has been around for as long as I\'ve been around, for what that\'s worth," the cat murmurs, licking its paws.',
        action: giveExpFor('the age of the half-abandoned tavern, the Serpent\'s Hiss'),
      }, {
        say: '"My humans used to run this place," the cat says, glancing up at you. "Their kit is still in the basement."',
        action: giveExpFor('the former owners of the Serpent\'s Hiss', 75),
      }, {
        say: '"Since the Quarantine, I\'ve been taking care of the place," the cat purrs, "I locked the upstairs room and the cellar door.  For good reason."',
        action: giveExpFor('the Quarantine, and the duties of a curious cat', 100)
      }];

      const quarantineDialogue = [{
        say: '"Ah, yes," Baxter nods, "that is what those who were left behind call it. The changed ones."'
      },
      {
        say: '"The other humans all left. Or tried to leave." He looks wistful for a second.',
        delay: 2000
      },
      {
        say: '"Or, they died," he finishes, licking his lips. "Some were good meat, others bad."',
        delay: 1500
      },
      {
        say: '"Everything has changed, since. What was a city is now a trap," the cat waxes, adjusting his monocle.',
        action: giveExpFor('the effects of the Quarantine, according to Baxter', 200)
      }];

      const npcDialogueTree = {
        npc, player,

        'where am i': {
          priority: Dialogue.Priority.LOW,
          keywords: {
            every: 'this place',
            some:   serpentsHissKeywords,
            find:   Dialogue.Keywords.HERE.concat(serpentsHissKeywords)
          },
          dialogue: {
            type:    Dialogue.Types.RANDOM,
            choices: serpentsHissDialogue
          },
          prerequisite: hasMet
        },

        'what is the quarantine': {
          priority: Dialogue.Priority.LOW,
          keywords: {
            every: 'quarantine',
            some: ['the quarantine', 'quarantining', 'history of the'],
            find: Dialogue.Keywords.QUARANTINE
          },
          dialogue: {
            type:     Dialogue.Types.TIMED,
            sequence: quarantineDialogue
          },
          prerequisite: hasMet
        },

        // Next dialogue branch...

      };

      const room   = rooms.getAt(this.getLocation());
      const toRoom = Broadcast.toRoom(room, this, player, players);
      Dialogue.handleInteraction(npcDialogueTree, args, toRoom);

    }
  },

  playerYell: l10n => {
    return function _respond(player, players, rooms, npcs, args) {
      const npcRoom = this.getLocation();

      if (player.getLocation() === npcRoom) {
        player.say('<yellow>The cat looks at you, annoyed, and hisses.</yellow>');
        //TODO: Lower reputation with cat. Use emitter to handle this. Use a behavior file.
      }

      players.broadcastIf(
        '<blue>The cat looks annoyed, and hisses.</yellow>',
        p => p !== player && p.getLocation() === npcRoom);
    }
  },
  hit: l10n => {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const playerName = player.getShortDesc('en');

      if (!this.getEffects('flurry')) {
        player.say('<yellow>The cat pounces on you with a flurry of blows!');
        this.addEffect('flurry', {
          duration: 6 * 1000,
          activate: () => {
            this.combat.addSpeedMod({
              name: 'ferocious feline',
              effect: speed => Math.round(speed * .75)
            });
            this.combat.addDamageMod({
              name: 'ferocious feline',
              effect: damage => damage + 10
            });
          },
          deactivate: () => {
            this.combat.deleteAllMods('ferocious feline');
          }
        })
      }

      let secondPartyMessage, thirdPartyMessage;

      //TODO: Extract this to some kind of combat messaging helper?
      switch(hitLocation) {
        case 'head':
          secondPartyMessage = ['The tomcat flies at your face, a ball of fur, his claws <red>raking</red> your eyes.'];
          thirdPartyMessage = ['The tomcat flies at '+ playerName + '\'s face, a ball of fur, his claws <red>raking</red> their eyes.'];
          break;

        case 'neck':
          secondPartyMessage = ['The ginger cat <red>tears</red> at your throat, screeching.'];
          thirdPartyMessage = ['The ginger cat <red>tears</red> at ' + playerName + '\'s throat, screeching.'];
          break;

        default:
          secondPartyMessage = [
            'The tomcat\'s claws rake your ' + hitLocation + ', drawing <red>lines</led> <white>of</white> <red>blood</red>.',
            'The cat fiercely <yellow>nips</yellow> your ' + hitLocation + '.',
            'A <bold>screeching</bold> ball of fur, the tomcat sinks its claws into your ' + hitLocation + '.'
          ];
          thirdPartyMessage = [
            'The tomcat <red>rakes</red> ' + playerName + '\'s' + hitLocation + ' with his sharpened claws.',
            'The cat quickly nips ' + playerName + '\'s ' + hitLocation + ' and darts away, an orange <yellow>flash</yellow>.',
            'The cat <bold>flies</bold> through the air at ' + playerName + ' and sinks his claws in their ' + hitLocation + '.'
          ];
          break;
      }

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  damaged: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);

      const moderateDamage = damage < (this.getAttribute('health') * .8);

      const whackedInHead = hitLocation === 'head' && damage > 10;
      if (whackedInHead && !this.getEffects('monocle broke')) {
        this.addEffect('monocle broke', {
          duration: 15 * 1000,

          activate: () => {
            player.say('<bold>You whack the cat in the head and his monocle cracks.</bold>');
            this.combat.addToHitMod({
              name: 'monocle broke' + damage,
              effect: toHit => toHit - 3
            });
          },

          deactivate: () => {
            this.combat.removeToHitMod('monocle broke' + damage);
            player.say('<white>The sassy feline swaps out their broken monocle for a fresh one.</white>')
          }
        });
      }

      const secondPartyMessage = moderateDamage ?
      [
        'The cat screeches in anguish.',
        'The tomcat leaps back, to lick his <red>wounds</red> for a second.',
        'The tomcat is knocked back by the blow, his monocle <bold><cyan>popping</cyan></bold> loose for a second.',
        'The cat\'s ' + hitLocation + ' is <blue>bruised</blue> by your strike.'
      ] :
      [
        'The tomcat\'s '+ hitLocation + ' is smashed open, and his <red>blood</red> spatters on the floor.'
      ];
      const thirdPartyMessage = moderateDamage ?
      [
        'The cat screeches in pain as its ' + hitLocation + ' is <blue>bruised</blue>.',
        'The tomcat retreats after ' + player.getShortDesc('en') + '\'s vicious attack, to lick his <red>wounds</red>.',
        'The tomcat is bashed away by ' + player.getShortDesc('en') + ', and his monocle <bold>pops</bold> loose.',
        'The tomcat\'s ' + hitLocation + ' is bashed, and begins <blue>swelling</blue> immediately.'
      ] :
      [
        'The cat\'s '+ hitLocation + ' is smashed to a furry ginger <red>pulp</red>, thanks to ' + player.getShortDesc('en') + '.'
      ];

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  dodge: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);

      const secondPartyMessage = [
        'The cat leaps away from your strike, and bows ironically.',
        'Your attack hits nothing but fur as the cat darts past you.',
        'The tomcat jumps out of the way, and you swear it laughs at you.',
      ];
      const thirdPartyMessage = [
        'The cat leaps away from ' + player.getShortDesc('en') + '\'s attack.',
        player.getShortDesc('en') + '\'s attack hits nothing as the tomcat runs circles around them.',
        'The sassy tomcat jumps away ' + player.getShortDesc('en') + ', causing them to miss his ' + hitLocation + '.',
      ];

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  missedAttack: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);

      const secondPartyMessage = [
        '<yellow>The tomcat leaps for your ' + hitLocation + ', but flies past in a blur of claws.</yellow>',
        '<yellow>The tomcat\'s claws miss your ' + hitLocation + '.</yellow>',
        '<yellow>The cat adjusts his monocle after missing your ' + hitLocation + '.</yellow>',
      ];
      const thirdPartyMessage = [
        '<yellow>The tomcat leaps for ' + player.getShortDesc('en') + '\s ' + hitLocation + ', but flies past in a blur of claws.</yellow>',
        '<yellow>The tomcat claws at ' + player.getShortDesc('en') + ' but whiffs.</yellow>',
        '<yellow>The classy cat adjusts his monocle after missing ' + player.getShortDesc('en') + '.</yellow>',
      ];

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  introduction: function(l10n) {
    return function(player, players, room) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const playerName = player.getName();

      const introDialogue = {
        dialogue: {
          sequence: [{
            say: '<bold>The cat rears up on his hind legs and considers you for a moment.</bold>',
            delay: 1500
          },
          {
            say: '"This one seems sane," he mutters to himself quietly.'
          },
          {
            say: '"Welcome to my tavern, human," the cat announces to you, "My name is Baxter J. Truthteller."',
            delay: 2000
          },
          {
            say: '"Let me know if you need vittles or other sustenance," he finishes with a curt nod.',
            delay: 750
          },
          {
            say: 'Baxter resumes licking his paws and grooming himself.'
          }]
        }
      }

      Dialogue.timedDialogueHandler(player, this, introDialogue);

    }
  },

  /* No enter and leave script since this NPC is stationary for now. */

};
<commit_msg>Add dialogue about the basement monster thing<commit_after>'use strict';

const Broadcast = require('../../src/broadcast').Broadcast;
const Random    = require('../../src/random').Random;
const Dialogue  = require('../../src/dialogue').Dialogue;
const util = require('util');

exports.listeners = {

  spawn: l10n => {
    return function (room, rooms, players) {
      const toRoom = Broadcast.toRoom(room, this, null, players);
      const msg = this.getShortDesc('en') + ' yawns and stretches, pulling itself up from behind the bar.';
      toRoom({ thirdPartyMessage: msg });
    }
  },

  playerEnter: l10n => {
    return (room, rooms, player, players, npc) => {
      const rand = Random.inRange(1, 15);
      if (rand === 3) {
        const msg = '<bold>The ginger tomcat mewls, doffing his monocle.</bold>';
        const toRoom = Broadcast.toRoom(room, this, player, players);
        toRoom({
          secondPartyMessage: msg,
          thirdPartyMessage: msg
        });
      }
    }
  },

  playerDropItem: l10n  => {
    return (room, rooms, player, players, npc, npcs, item) => {
      const rand = Random.inRange(1, 15);
      if (rand === 3) {
        const itemDesc = item.getShortDesc('en');
        const msg = '<bold>The cat\'s whiskers twitch as he eyes the ' + itemDesc + '.</bold>';
        const toRoom = Broadcast.toRoom(room, this, player, players);
        toRoom({
          secondPartyMessage: msg,
          thirdPartyMessage: msg
        });
      }
    }
  },

  playerSay: l10n => {
    return function _talk(player, players, rooms, npcs, args) {
      const npc = this;
      const serpentsHissKeywords = [
        'serpent',
        'serpents',
        'hiss',
        'tavern',
        'bar',
        'fang',
        'downstairs'
      ];

      //TODO: Extract to dialogue or level utils?
      const giveExpFor = (topic, points) => () => {
        topic = topic || 'the history of the tavern';
        const isDiscussing = true;
        if (!player.hasDiscussed(npc, topic, isDiscussing)) {
          player.emit('experience', points || 50, topic);
        }
      };

      const hasMet = () => player.hasMet(npc);

      const serpentsHissDialogue = [{
        say: '"This tavern has been around for as long as I\'ve been around, for what that\'s worth," the cat murmurs, licking its paws.',
        action: giveExpFor('the age of the half-abandoned tavern, the Serpent\'s Hiss'),
      }, {
        say: '"My humans used to run this place," the cat says, glancing up at you. "Their kit is still in the basement."',
        action: giveExpFor('the former owners of the Serpent\'s Hiss', 75),
      }, {
        say: '"Since the Quarantine, I\'ve been taking care of the place," the cat purrs, "I locked the upstairs room and the cellar door.  For good reason."',
        action: giveExpFor('the Quarantine, and the duties of a curious cat', 100)
      }];

      const quarantineDialogue = [{
        say: '"Ah, yes," Baxter nods, "that is what those who were left behind call it. The changed ones."'
      },
      {
        say: '"The other humans all left. Or tried to leave." He looks wistful for a second.',
        delay: 2000
      },
      {
        say: '"Or, they died," he finishes, licking his lips. "Some were good meat, others bad."',
        delay: 1500
      },
      {
        say: '"Everything has changed, since. What was a city is now a trap," the cat waxes, adjusting his monocle.',
        action: giveExpFor('the effects of the Quarantine, according to Baxter', 200)
      }];

      const cellarDialogue = [{
        say: '"The cellar... I had to lock it to save myself from the thing... the horrible, sucking mouths... like snakes for arms... I lost the key..." he trails off, a look of horror on his face.',
        delay: 1500
      }, {
        say: '"The key, to hold the beast in place. I dropped it," Baxter says, whiskers twitching, "I was attacked by my mortal nemesis, in a room upstairs."',
        action: giveExpFor('where Baxter dropped the key to the cellar'),
        delay: 2500
      }, {
        say: '"If you do find the key, be careful. That thing is not human, not of this world," Baxter replies, "I\'m not sure the cellar door can hold it forever."'
      }];

      const npcDialogueTree = {
        npc, player,

        'where am i': {
          priority: Dialogue.Priority.LOW,
          keywords: {
            every: 'this place',
            some:   serpentsHissKeywords,
            find:   Dialogue.Keywords.HERE.concat(serpentsHissKeywords)
          },
          dialogue: {
            type:    Dialogue.Types.RANDOM,
            choices: serpentsHissDialogue
          },
          prerequisite: hasMet
        },

        'what is the quarantine': {
          priority: Dialogue.Priority.LOW,
          keywords: {
            every: 'quarantine',
            some: ['the quarantine', 'quarantining', 'history of the'],
            find: Dialogue.Keywords.QUARANTINE
          },
          dialogue: {
            type:     Dialogue.Types.TIMED,
            sequence: quarantineDialogue
          },
          prerequisite: hasMet
        },

        'what is in the cellar': {
          priority: Dialogue.Priority.MEDIUM,
          keywords: {
            every: 'cellar',
            some: ['basement', 'downstairs', 'trapdoor'],
            find: ['cell', 'base', 'down', 'monster', 'key']
          },
          dialogue: {
            type:     Dialogue.Types.TIMED,
            sequence:  cellarDialogue
          }
        }

        // Next dialogue branch...

      };

      const room   = rooms.getAt(this.getLocation());
      const toRoom = Broadcast.toRoom(room, this, player, players);
      Dialogue.handleInteraction(npcDialogueTree, args, toRoom);

    }
  },

  playerYell: l10n => {
    return function _respond(player, players, rooms, npcs, args) {
      const npcRoom = this.getLocation();

      if (player.getLocation() === npcRoom) {
        player.say('<yellow>The cat looks at you, annoyed, and hisses.</yellow>');
        //TODO: Lower reputation with cat. Use emitter to handle this. Use a behavior file.
      }

      players.broadcastIf(
        '<blue>The cat looks annoyed, and hisses.</yellow>',
        p => p !== player && p.getLocation() === npcRoom);
    }
  },
  hit: l10n => {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const playerName = player.getShortDesc('en');

      if (!this.getEffects('flurry')) {
        player.say('<yellow>The cat pounces on you with a flurry of blows!');
        this.addEffect('flurry', {
          duration: 6 * 1000,
          activate: () => {
            this.combat.addSpeedMod({
              name: 'ferocious feline',
              effect: speed => Math.round(speed * .75)
            });
            this.combat.addDamageMod({
              name: 'ferocious feline',
              effect: damage => damage + 10
            });
          },
          deactivate: () => {
            this.combat.deleteAllMods('ferocious feline');
          }
        })
      }

      let secondPartyMessage, thirdPartyMessage;

      //TODO: Extract this to some kind of combat messaging helper?
      switch(hitLocation) {
        case 'head':
          secondPartyMessage = ['The tomcat flies at your face, a ball of fur, his claws <red>raking</red> your eyes.'];
          thirdPartyMessage = ['The tomcat flies at '+ playerName + '\'s face, a ball of fur, his claws <red>raking</red> their eyes.'];
          break;

        case 'neck':
          secondPartyMessage = ['The ginger cat <red>tears</red> at your throat, screeching.'];
          thirdPartyMessage = ['The ginger cat <red>tears</red> at ' + playerName + '\'s throat, screeching.'];
          break;

        default:
          secondPartyMessage = [
            'The tomcat\'s claws rake your ' + hitLocation + ', drawing <red>lines</led> <white>of</white> <red>blood</red>.',
            'The cat fiercely <yellow>nips</yellow> your ' + hitLocation + '.',
            'A <bold>screeching</bold> ball of fur, the tomcat sinks its claws into your ' + hitLocation + '.'
          ];
          thirdPartyMessage = [
            'The tomcat <red>rakes</red> ' + playerName + '\'s' + hitLocation + ' with his sharpened claws.',
            'The cat quickly nips ' + playerName + '\'s ' + hitLocation + ' and darts away, an orange <yellow>flash</yellow>.',
            'The cat <bold>flies</bold> through the air at ' + playerName + ' and sinks his claws in their ' + hitLocation + '.'
          ];
          break;
      }

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  damaged: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);

      const moderateDamage = damage < (this.getAttribute('health') * .8);

      const whackedInHead = hitLocation === 'head' && damage > 10;
      if (whackedInHead && !this.getEffects('monocle broke')) {
        this.addEffect('monocle broke', {
          duration: 15 * 1000,

          activate: () => {
            player.say('<bold>You whack the cat in the head and his monocle cracks.</bold>');
            this.combat.addToHitMod({
              name: 'monocle broke' + damage,
              effect: toHit => toHit - 3
            });
          },

          deactivate: () => {
            this.combat.removeToHitMod('monocle broke' + damage);
            player.say('<white>The sassy feline swaps out their broken monocle for a fresh one.</white>')
          }
        });
      }

      const secondPartyMessage = moderateDamage ?
      [
        'The cat screeches in anguish.',
        'The tomcat leaps back, to lick his <red>wounds</red> for a second.',
        'The tomcat is knocked back by the blow, his monocle <bold><cyan>popping</cyan></bold> loose for a second.',
        'The cat\'s ' + hitLocation + ' is <blue>bruised</blue> by your strike.'
      ] :
      [
        'The tomcat\'s '+ hitLocation + ' is smashed open, and his <red>blood</red> spatters on the floor.'
      ];
      const thirdPartyMessage = moderateDamage ?
      [
        'The cat screeches in pain as its ' + hitLocation + ' is <blue>bruised</blue>.',
        'The tomcat retreats after ' + player.getShortDesc('en') + '\'s vicious attack, to lick his <red>wounds</red>.',
        'The tomcat is bashed away by ' + player.getShortDesc('en') + ', and his monocle <bold>pops</bold> loose.',
        'The tomcat\'s ' + hitLocation + ' is bashed, and begins <blue>swelling</blue> immediately.'
      ] :
      [
        'The cat\'s '+ hitLocation + ' is smashed to a furry ginger <red>pulp</red>, thanks to ' + player.getShortDesc('en') + '.'
      ];

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  dodge: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);

      const secondPartyMessage = [
        'The cat leaps away from your strike, and bows ironically.',
        'Your attack hits nothing but fur as the cat darts past you.',
        'The tomcat jumps out of the way, and you swear it laughs at you.',
      ];
      const thirdPartyMessage = [
        'The cat leaps away from ' + player.getShortDesc('en') + '\'s attack.',
        player.getShortDesc('en') + '\'s attack hits nothing as the tomcat runs circles around them.',
        'The sassy tomcat jumps away ' + player.getShortDesc('en') + ', causing them to miss his ' + hitLocation + '.',
      ];

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  missedAttack: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);

      const secondPartyMessage = [
        '<yellow>The tomcat leaps for your ' + hitLocation + ', but flies past in a blur of claws.</yellow>',
        '<yellow>The tomcat\'s claws miss your ' + hitLocation + '.</yellow>',
        '<yellow>The cat adjusts his monocle after missing your ' + hitLocation + '.</yellow>',
      ];
      const thirdPartyMessage = [
        '<yellow>The tomcat leaps for ' + player.getShortDesc('en') + '\s ' + hitLocation + ', but flies past in a blur of claws.</yellow>',
        '<yellow>The tomcat claws at ' + player.getShortDesc('en') + ' but whiffs.</yellow>',
        '<yellow>The classy cat adjusts his monocle after missing ' + player.getShortDesc('en') + '.</yellow>',
      ];

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  introduction: function(l10n) {
    return function(player, players, room) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const playerName = player.getName();

      const introDialogue = {
        dialogue: {
          sequence: [{
            say: '<bold>The cat rears up on his hind legs and considers you for a moment.</bold>',
            delay: 1500
          },
          {
            say: '"This one seems sane," he mutters to himself quietly.'
          },
          {
            say: '"Welcome to my tavern, human," the cat announces to you, "My name is Baxter J. Truthteller."',
            delay: 2000
          },
          {
            say: '"Let me know if you need vittles or other sustenance," he finishes with a curt nod.',
            delay: 750
          },
          {
            say: 'Baxter resumes licking his paws and grooming himself.'
          }]
        }
      };

      Dialogue.timedDialogueHandler(player, this, introDialogue);

    }
  },

  /* No enter and leave script since this NPC is stationary for now. */

};
<|endoftext|>


<commit_before>// Copyright (c) 2020 Silicon Labs. All rights reserved.

/*
 * This file provides the functionality that reads the ZAP data from a database
 * and exports it into a file.
 */
import fs from 'fs'
import { setSessionClean } from '../db/query-session'
import { logInfo } from '../util/env'
import { exportSessionKeyValues, exportEndpointTypes } from './mapping'

/**
 * Toplevel file that takes a given session ID and exports the data into the file
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @param {*} filePath
 * @returns A promise that resolves with the path of the file written.
 */
export function exportDataIntoFile(db, sessionId, filePath) {
  logInfo(`Writing state from session ${sessionId} into file ${filePath}`)
  return createStateFromDatabase(db, sessionId)
    .then((state) => {
      logInfo(`About to write the file to ${filePath}`)
      logInfo(state)
      return new Promise((resolve, reject) => {
        logInfo(`Writing the file to ${filePath}`)
        fs.writeFile(filePath, JSON.stringify(state, null, 2), (err) => {
          if (err) reject(err)
          resolve()
        })
      })
    })
    .then(() => {
      return setSessionClean(db, sessionId)
    })
    .then(() => {
      return Promise.resolve(filePath)
    })
}

/**
 * Given a database and a session id, this method returns a promise that
 * resolves with a state object that needs to be saved into a file.
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @returns state object that needs to be saved into a file.
 */
export function createStateFromDatabase(db, sessionId) {
  return new Promise((resolve, reject) => {
    var state = {
      writeTime: new Date().toString(),
      creator: 'zap',
    }
    var promises = []

    // Deal with the key/value table
    var getKeyValues = exportSessionKeyValues(db, sessionId).then((rows) => {
      state.keyValuePairs = rows
      logInfo(`Retrieved session keys: ${rows.length}`)
      return Promise.resolve(rows)
    })
    promises.push(getKeyValues)

    var getAllEndpoint = exportEndpointTypes(db, sessionId).then((rows) => {
      logInfo(`Retrieved endpoint types: ${rows.length}`)
      state.endpointTypes = rows
      return Promise.resolve(rows)
    })
    promises.push(getAllEndpoint)

    return Promise.all(promises)
      .then(() => resolve(state))
      .catch((err) => reject(err))
  })
}
<commit_msg>Clean up imports.<commit_after>// Copyright (c) 2020 Silicon Labs. All rights reserved.

/*
 * This file provides the functionality that reads the ZAP data from a database
 * and exports it into a file.
 */
import * as Fs from 'fs'
import * as QuerySession from '../db/query-session'
import * as Env from '../util/env'
import * as Mapping from './mapping'

/**
 * Toplevel file that takes a given session ID and exports the data into the file
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @param {*} filePath
 * @returns A promise that resolves with the path of the file written.
 */
export function exportDataIntoFile(db, sessionId, filePath) {
  Env.logInfo(`Writing state from session ${sessionId} into file ${filePath}`)
  return createStateFromDatabase(db, sessionId)
    .then((state) => {
      Env.logInfo(`About to write the file to ${filePath}`)
      Env.logInfo(state)
      return new Promise((resolve, reject) => {
        Env.logInfo(`Writing the file to ${filePath}`)
        Fs.writeFile(filePath, JSON.stringify(state, null, 2), (err) => {
          if (err) reject(err)
          resolve()
        })
      })
    })
    .then(() => {
      return QuerySession.setSessionClean(db, sessionId)
    })
    .then(() => {
      return Promise.resolve(filePath)
    })
}

/**
 * Given a database and a session id, this method returns a promise that
 * resolves with a state object that needs to be saved into a file.
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @returns state object that needs to be saved into a file.
 */
export function createStateFromDatabase(db, sessionId) {
  return new Promise((resolve, reject) => {
    var state = {
      writeTime: new Date().toString(),
      creator: 'zap',
    }
    var promises = []

    // Deal with the key/value table
    var getKeyValues = Mapping.exportSessionKeyValues(db, sessionId).then(
      (rows) => {
        state.keyValuePairs = rows
        Env.logInfo(`Retrieved session keys: ${rows.length}`)
        return Promise.resolve(rows)
      }
    )
    promises.push(getKeyValues)

    var getAllEndpoint = Mapping.exportEndpointTypes(db, sessionId).then(
      (rows) => {
        Env.logInfo(`Retrieved endpoint types: ${rows.length}`)
        state.endpointTypes = rows
        return Promise.resolve(rows)
      }
    )
    promises.push(getAllEndpoint)

    return Promise.all(promises)
      .then(() => resolve(state))
      .catch((err) => reject(err))
  })
}
<|endoftext|>


<commit_before><commit_msg>giving us dj+song. monkey patch<commit_after><|endoftext|>


<commit_before>'use strict';

var status = require('hapi-status'),
	dummy = [
		{
			id: '123',
			path: '/dit-is-een-test',
			title: 'Dit is een test!',
			intro: 'Pork belly jowl sausage, corned beef pork drumstick pancetta tongue biltong shank t-bone hamburger cupim. Beef ribs picanha ground round jerky alcatra hamburger. Prosciutto pork flank corned beef strip steak, tail ham hock shank cupim venison hamburger kielbasa. Capicola pork belly shank leberkas jowl ham chicken short loin bacon flank sirloin alcatra biltong venison. Ribeye kielbasa pig, turducken spare ribs biltong turkey shoulder fatback tail landjaeger jerky. Jerky leberkas kevin ball tip t-bone bresaola venison pork loin brisket fatback. Sirloin boudin beef ribs drumstick, pork belly short ribs pancetta filet mignon.',
			content: '
Brisket jerky alcatra cupim frankfurter pig pastrami chicken turkey meatloaf pork belly shank shoulder drumstick. Drumstick biltong cow tenderloin short loin pork loin jowl hamburger flank spare ribs rump swine ribeye. Hamburger t-bone ham hock beef ribs alcatra meatloaf short ribs, porchetta picanha short loin doner jowl boudin. Sausage ground round doner pork chop beef tri-tip picanha shoulder shankle pancetta. Jerky pig biltong cow, beef tail sirloin capicola.

so this could be some full width thingy

Drumstick venison jowl short ribs ground round ribeye. Pancetta shankle alcatra tri-tip, bacon rump beef ribs. Beef bresaola cow, rump venison drumstick pork loin kevin porchetta flank beef ribs andouille. Hamburger jowl beef fatback chuck shankle. Beef ribs chicken andouille pig. Alcatra ball tip kevin capicola tri-tip kielbasa shoulder pork. Short ribs tenderloin porchetta tail capicola frankfurter shank.
',
			created: '2015-10-01 18:00:00'
		},
		{
			id: '345',
			path: '/hier-is-er-nog-een',
			title: 'Hier is er nog een!',
			intro: 'Tenderloin jerky pancetta, spare ribs filet mignon prosciutto pastrami turkey boudin ham pork ham hock. Fatback prosciutto venison t-bone brisket meatball chicken pig biltong. Beef ribs tongue pastrami shank bacon ham hock kielbasa, fatback ball tip corned beef capicola pork chop flank strip steak pork. Turducken ball tip ham tenderloin andouille pastrami rump filet mignon cupim spare ribs. Cow ribeye landjaeger, venison pork belly beef ribs doner porchetta. Beef bresaola tri-tip spare ribs, prosciutto swine venison jerky jowl ham hock pork chop andouille meatloaf flank ground round. Pork chop turkey swine, pig picanha kevin pastrami capicola spare ribs.',
			content: '

so this could be some full width thingy

Jowl cupim sausage, strip steak t-bone landjaeger shankle bacon drumstick doner shoulder. Venison swine ground round ball tip, brisket biltong frankfurter andouille short loin. Cow spare ribs ground round, pancetta meatball beef ribs tail rump t-bone tenderloin. Tail t-bone filet mignon tongue chuck, beef ribs ground round flank pancetta meatball leberkas strip steak tenderloin. Boudin leberkas short ribs capicola. Shoulder filet mignon short loin ham hock landjaeger rump tenderloin bresaola kevin prosciutto turducken tail short ribs cow.
',
			created: '2015-10-01 18:00:00'
		},
		{
			id: '567',
			path: '/tests-all-over-the-place',
			title: 'Tests all over the place!',
			intro: 'Tenderloin frankfurter meatball, tri-tip swine hamburger rump ball tip short loin salami flank boudin pork belly capicola. Jerky bresaola pancetta, pork belly ground round cupim leberkas shoulder picanha swine tongue porchetta. Doner leberkas pork loin meatloaf picanha beef ribs. Salami turducken tongue doner. Prosciutto fatback pancetta tongue, short ribs turducken jerky strip steak beef cow andouille porchetta meatball.',
			content: '
Meatloaf tri-tip kielbasa porchetta, sirloin drumstick bresaola pancetta jowl frankfurter biltong. Pig ball tip tail flank corned beef. Filet mignon drumstick landjaeger, beef ribs tenderloin bresaola corned beef. Sirloin tongue salami porchetta ribeye jowl jerky beef filet mignon meatball picanha shankle bacon. Tri-tip landjaeger t-bone pastrami bresaola biltong prosciutto ham.

config: {
	  cache: {
    expiresIn: 60 * 60 * 1000 * 24 * 7,
    privacy: "private"
  },
  cors: {
    origin: ["https://vanham.io"]
  }
}

',
			created: '2015-10-01 18:00:00'
		},
		{
			id: '789',
			path: '/and-yet-another',
			title: 'And yet another!',
			intro: 'Brisket strip steak drumstick flank filet mignon pig frankfurter bresaola ball tip. Shankle tail frankfurter salami doner ham hock chuck bresaola t-bone bacon hamburger short ribs pig. Ball tip ham kielbasa, short loin alcatra jerky pig turkey venison shankle doner sirloin. Brisket tenderloin t-bone alcatra, hamburger turkey sirloin shankle cupim.',
			content: '
Beef ribs rump ball tip drumstick, bresaola tail frankfurter chicken turkey porchetta filet mignon kielbasa shoulder fatback. Ham kielbasa short loin, cupim drumstick bresaola hamburger. Capicola frankfurter bresaola rump jerky kevin. Jowl chicken ham hock, pastrami venison andouille tongue chuck prosciutto biltong hamburger pork pork chop.
',
			created: '2015-10-01 18:00:00'
		}
	].reverse();

function API() {
	var api = this;

	api.index = function index(request, reply) {
		return status.ok(reply, dummy);
	};

	api.fetch = function fetch(request, reply) {
		var result;
		dummy.forEach(function(item) {
			if (item.id === request.params.id) {
				result = item;
			}
		});

		return status.ok(reply, result);
	};
}

module.exports = new API();
<commit_msg>checkin blog post as dummy for now<commit_after>'use strict';

var status = require('hapi-status'),
	mongoose = require('mongoose'),
	dummy = [
		{
			id: 'mjouv9o3bl61',
			path: '/styling-checkboxes',
			title: 'Styling checkboxes',
			intro: 'An easy yet not uncommon task the most of us have to deal with is the styling of form elements. In this small post I\'ll show you one of the many possible ways to accomplish this in a clean way.',
			content: 'Note: For this solution we assume you have a <label> element right after the checkbox. If this is not your current situation you might need to add a different element (like <span>) and you can add all the styling for label::before to that element.

The basic HTML as we all know it. Just an ordinary checkbox with its corresponding label. I prefer not using id myself, so I would\'ve wrapped the label around the input field. But since it\'s shorter we use this markup for now.

<input type=checkbox id=checkbox />
<label for=checkbox>This is a label</label>

For the fake "checkbox" box we add a pseudo element with ::before. This way we can add styling for this box, without the need for an (obsolete) extra element in our HTML.

label::before {
 content: \'\';
  display: inline-block;
  width: 20px;
  height: 20px;
  border: 1px solid #ccc;
}

Add the checked state to the ::after so people can actually see the checkbox is now checked!

input:checked + label::before {
  box-shadow: 0 0 0 3px white inset;
  background-color: green;
}

Adding a fake checkbox is useless when we still have the real checkbox in sight, so let\'s not forget to hide it. This could be accomplished in two ways. Some browsers don\'t like it when you just use display: none, so depending on the browser support

input {
  display: none;
}

The good samaritans as we are we should not forget to give the user some nice feedback and add this small CSS snippet so the user knows it can click on the label:

label:hover {
  cursor: pointer;
}

And there you go, a nice, easily styled checkbox!

Of course there are many many other ways you could accomplish this. Wrap the label around the input and add an extra element on which you can apply the styling for label::before for example is one I would normally use to prevent the usage of the id attribute.
',
			created: '2015-12-08 23:37:43'
		}
	].reverse();

function API() {
	var api = this;

	api.index = function index(request, reply) {
		return status.ok(reply, dummy);
	};

	api.fetch = function fetch(request, reply) {
		var result;
		dummy.forEach(function(item) {
			if (item.id === request.params.id) {
				result = item;
			}
		});

		return status.ok(reply, result);
	};
}

module.exports = new API();
<|endoftext|>