<commit_before>// @flow

/* eslint-env browser */
/* eslint-disable react/no-multi-comp, react/prefer-stateless-function */

import React from 'react';
import { Link } from 'react-router-dom';
import {
  Icon,
  hoverable,
  flexContainer,
  flexItem,
  darken,
  lighten,
  isHintShown,
  hintDefine,
  hintShow,
} from 'giu';
import { UI } from '../gral/constants';
import { isWaiting } from '../gral/helpers';

let fHintAlreadyShown = false;

// ==========================================
// Declarations
// ==========================================
type Props = {
  id: string,
  label: string,
  dirty?: boolean,
  deleted?: boolean,
  icon: string,
  link: string,
  fSelected: boolean,
  showBaseline?: () => any,
  hideBaseline?: () => any,
  saveAsBaseline?: (snapshotId: string) => any,
  // hoverable HOC
  hovering: any,
  onHoverStart: Function,
  onHoverStop: Function,
};

// ==========================================
// Component
// ==========================================
class SidebarItem extends React.Component<Props> {
  fDirtyIconShown: boolean;

  componentDidMount() {
    this.hintIfNeeded();
  }
  componentDidUpdate() {
    this.hintIfNeeded();
  }

  // ------------------------------------------
  render() {
    const { id, deleted, fSelected } = this.props;
    const fHovered = this.props.hovering === id;
    return (
      <Link
        id={id}
        to={this.props.link}
        style={style.outer({ fSelected, fHovered, fDeleted: deleted })}
        onMouseEnter={this.props.onHoverStart}
        onMouseLeave={this.props.onHoverStop}
      >

          <Icon icon={this.props.icon} />

          {this.props.label} {deleted && (deleted)}

        {this.renderDirtyIcon()}
      </Link>
    );
  }

  renderDirtyIcon() {
    this.fDirtyIconShown = Boolean(this.props.dirty) && !this.props.deleted;
    if (!this.fDirtyIconShown) return null;
    const { saveAsBaseline, showBaseline, hideBaseline } = this.props;
    return (

        <DirtyIcon
          id={this.props.id}
          fSelected={this.props.fSelected}
          fSnapshot={!!showBaseline}
          onHoverStart={showBaseline}
          onHoverStop={hideBaseline}
          onClick={ev => {
            saveAsBaseline && saveAsBaseline(ev.target.id);
            hideBaseline && hideBaseline();
          }}
        />

    );
  }

  // ------------------------------------------
  hintIfNeeded() {
    if (!this.fDirtyIconShown) return;
    if (fHintAlreadyShown || isHintShown() || isWaiting()) return;
    const elements = () => {
      const out = [];
      const node = document.getElementsByClassName('jh-dirty-icon')[0];
      if (node) {
        const bcr = node.getBoundingClientRect();
        const x = bcr.left + bcr.width + 70;
        const y = bcr.top + bcr.height / 2;
        out.push({
          type: 'LABEL',
          x,
          y,
          align: 'left',
          children: (

              Changed! In snapshots, hover
              to see the baseline (old) version, and click to accept as a new
              baseline

          ),
        });
        out.push({
          type: 'ARROW',
          from: { x, y },
          to: { x: x - 70 + 5, y },
          counterclockwise: true,
        });
      }
      return out;
    };
    hintDefine('dirtyIcon', { elements });
    hintShow('dirtyIcon');
    fHintAlreadyShown = true;
  }
}

const SidebarGroup = ({ name, children }: { name: string, children?: any }) => (

{name}

    {children}

);

class _DirtyIcon extends React.Component<{}> {
  render() {
    const {
      hovering,
      id,
      fSelected,
      fSnapshot,
      onHoverStart,
      onHoverStop,
      onClick,
    } = this.props;
    let tooltip = 'Modified since the last time jest-html was launched';
    if (hovering) {
      tooltip += '. Click to save baseline. Press ESC to dismiss this tooltip';
    } else {
      tooltip += fSnapshot
        ? '. Select this snapshot and hover to see baseline'
        : '. Click for more details on what changed';
    }
    return (
      <Icon
        id={id}
        icon="asterisk"
        onMouseEnter={fSelected ? onHoverStart : undefined}
        onMouseLeave={fSelected ? onHoverStop : undefined}
        onClick={fSnapshot ? onClick : undefined}
        style={style.dirtyIcon({ fSelected, fSnapshot, fHovering: hovering })}
        title={tooltip}
      />
    );
  }
}
const DirtyIcon = hoverable(_DirtyIcon);

// ------------------------------------------
const style = {
  outer: ({
    fSelected,
    fHovered,
    fDeleted,
  }: {
    fSelected?: boolean,
    fHovered?: boolean,
    fDeleted?: boolean,
  }) => {
    let backgroundColor;
    if (fSelected && fHovered) backgroundColor = darken(UI.color.accentBg, 10);
    else if (fHovered) backgroundColor = darken('white', 10);
    else if (fSelected) backgroundColor = UI.color.accentBg;
    let color = 'currentColor';
    if (fSelected && fDeleted) color = lighten(UI.color.accentBg, 25);
    else if (fDeleted) color = UI.color.textDim;
    else if (fSelected) color = UI.color.accentFg;
    return flexContainer('row', {
      padding: '0.3em 1em',
      cursor: 'pointer',
      color,
      backgroundColor,
      wordBreak: 'break-word',
      alignItems: 'center',
      textDecoration: 'none',
    });
  },
  dirtyIcon: ({ fSelected, fSnapshot, fHovering }) => {
    let color;
    if (fSelected && fSnapshot && fHovering)
      color = lighten(UI.color.accentBg, 25);
    else if (fSelected && fSnapshot) color = UI.color.accentFg;
    else if (fSelected) color = lighten(UI.color.accentBg, 25);
    else if (fSnapshot) color = UI.color.accentBg;
    else color = UI.color.textDim;
    return { color };
  },
  group: {
    margin: '0.5em 0',
    padding: '0.3em 0',
    backgroundColor: 'white',
    // border: '1px solid #aaa',
  },
  groupTitle: {
    color: '#999',
    padding: '0.3em 1em',
    fontSize: '0.8em',
    textTransform: 'uppercase',
  },
  highlight: {
    fontWeight: 'bold',
    color: 'yellow',
  },
};

// ==========================================
// Public
// ==========================================
export default hoverable(SidebarItem);
export { SidebarItem as _SidebarItem, SidebarGroup };
<commit_msg>Minor<commit_after>// @flow

/* eslint-env browser */
/* eslint-disable react/no-multi-comp, react/prefer-stateless-function */

import React from 'react';
import { Link } from 'react-router-dom';
import {
  Icon,
  hoverable,
  flexContainer,
  flexItem,
  darken,
  lighten,
  isHintShown,
  hintDefine,
  hintShow,
} from 'giu';
import { UI } from '../gral/constants';
import { isWaiting } from '../gral/helpers';

let fHintAlreadyShown = false;

// ==========================================
// Declarations
// ==========================================
type Props = {
  id: string,
  label: string,
  dirty?: boolean,
  deleted?: boolean,
  icon: string,
  link: string,
  fSelected: boolean,
  showBaseline?: () => any,
  hideBaseline?: () => any,
  saveAsBaseline?: (snapshotId: string) => any,
  // hoverable HOC
  hovering: any,
  onHoverStart: Function,
  onHoverStop: Function,
};

// ==========================================
// Component
// ==========================================
class SidebarItem extends React.Component<Props> {
  fDirtyIconShown: boolean;

  componentDidMount() {
    this.hintIfNeeded();
  }
  componentDidUpdate() {
    this.hintIfNeeded();
  }

  // ------------------------------------------
  render() {
    const { id, deleted, fSelected } = this.props;
    const fHovered = this.props.hovering === id;
    return (
      <Link
        id={id}
        to={this.props.link}
        style={style.outer({ fSelected, fHovered, fDeleted: deleted })}
        onMouseEnter={this.props.onHoverStart}
        onMouseLeave={this.props.onHoverStop}
      >

          <Icon icon={this.props.icon} />

          {this.props.label} {deleted && (deleted)}

        {this.renderDirtyIcon()}
      </Link>
    );
  }

  renderDirtyIcon() {
    this.fDirtyIconShown = Boolean(this.props.dirty) && !this.props.deleted;
    if (!this.fDirtyIconShown) return null;
    const { saveAsBaseline, showBaseline, hideBaseline } = this.props;
    return (

        <DirtyIcon
          id={this.props.id}
          fSelected={this.props.fSelected}
          fSnapshot={!!showBaseline}
          onHoverStart={showBaseline}
          onHoverStop={hideBaseline}
          onClick={ev => {
            saveAsBaseline && saveAsBaseline(ev.target.id);
            hideBaseline && hideBaseline();
          }}
        />

    );
  }

  // ------------------------------------------
  hintIfNeeded() {
    if (!this.fDirtyIconShown) return;
    if (fHintAlreadyShown || isHintShown() || isWaiting()) return;
    const elements = () => {
      const out = [];
      const node = document.getElementsByClassName('jh-dirty-icon')[0];
      if (node) {
        const bcr = node.getBoundingClientRect();
        const x = bcr.left + bcr.width + 70;
        const y = bcr.top + bcr.height / 2;
        out.push({
          type: 'LABEL',
          x,
          y,
          align: 'left',
          children: (

              Changed! In snapshots, hover
              to see the baseline (old) version, and click to accept as a new
              baseline

          ),
        });
        out.push({
          type: 'ARROW',
          from: { x, y },
          to: { x: x - 70 + 5, y },
          counterclockwise: true,
        });
      }
      return out;
    };
    hintDefine('dirtyIcon', { elements });
    hintShow('dirtyIcon');
    fHintAlreadyShown = true;
  }
}

const SidebarGroup = ({ name, children }: { name: string, children?: any }) => (

{name}

    {children}

);

class _DirtyIcon extends React.Component<{}> {
  render() {
    const {
      hovering,
      id,
      fSelected,
      fSnapshot,
      onHoverStart,
      onHoverStop,
      onClick,
    } = this.props;
    const tooltip = ['Modified since the last time jest-html was launched'];
    if (hovering) {
      tooltip.push('Click to save baseline. Press ESC to dismiss this tooltip');
    } else {
      tooltip.push(
        fSnapshot
          ? 'Select this snapshot and hover to see baseline'
          : 'Click for more details on what changed'
      );
    }
    return (
      <Icon
        id={id}
        icon="asterisk"
        onMouseEnter={fSelected ? onHoverStart : undefined}
        onMouseLeave={fSelected ? onHoverStop : undefined}
        onClick={fSnapshot ? onClick : undefined}
        style={style.dirtyIcon({ fSelected, fSnapshot, fHovering: hovering })}
        title={tooltip.join('. ')}
      />
    );
  }
}
const DirtyIcon = hoverable(_DirtyIcon);

// ------------------------------------------
const style = {
  outer: ({
    fSelected,
    fHovered,
    fDeleted,
  }: {
    fSelected?: boolean,
    fHovered?: boolean,
    fDeleted?: boolean,
  }) => {
    let backgroundColor;
    if (fSelected && fHovered) backgroundColor = darken(UI.color.accentBg, 10);
    else if (fHovered) backgroundColor = darken('white', 10);
    else if (fSelected) backgroundColor = UI.color.accentBg;
    let color = 'currentColor';
    if (fSelected && fDeleted) color = lighten(UI.color.accentBg, 25);
    else if (fDeleted) color = UI.color.textDim;
    else if (fSelected) color = UI.color.accentFg;
    return flexContainer('row', {
      padding: '0.3em 1em',
      cursor: 'pointer',
      color,
      backgroundColor,
      wordBreak: 'break-word',
      alignItems: 'center',
      textDecoration: 'none',
    });
  },
  dirtyIcon: ({ fSelected, fSnapshot, fHovering }) => {
    let color;
    if (fSelected && fSnapshot && fHovering)
      color = lighten(UI.color.accentBg, 25);
    else if (fSelected && fSnapshot) color = UI.color.accentFg;
    else if (fSelected) color = lighten(UI.color.accentBg, 25);
    else if (fSnapshot) color = UI.color.accentBg;
    else color = UI.color.textDim;
    return { color };
  },
  group: {
    margin: '0.5em 0',
    padding: '0.3em 0',
    backgroundColor: 'white',
    // border: '1px solid #aaa',
  },
  groupTitle: {
    color: '#999',
    padding: '0.3em 1em',
    fontSize: '0.8em',
    textTransform: 'uppercase',
  },
  highlight: {
    fontWeight: 'bold',
    color: 'yellow',
  },
};

// ==========================================
// Public
// ==========================================
export default hoverable(SidebarItem);
export { SidebarItem as _SidebarItem, SidebarGroup };
<|endoftext|>


<commit_before>/* jslint node: true */
'use strict';

/*
* @name /lib/tapestry-logger-loggly.js
* @description A Tapestry logger module to send logs to Loggly
* @since Wed Feb 12 2014
* @author Kevin Hodges <kevin.hodges@holidayextras.com>
*/
var https = require( 'https' );
var path = require( 'path' );

/**
* Constructor for a Loggly object
* @param {Object} connectionOptions, proxies whatever is passed in to Tapestry as the logger.connection
*/
function Loggly( connectionOptions ) {
	this.connection = connectionOptions;
};

/**
* Push to Loggly the passed value
* @param {Object} options:
* - service, tell Loggly who this log is from, probably the name of your app/module
* - type, payload? error? system log?
* - namespace, which of the services "buckets" should we throw this in?
* @param {Object} log, the object to push to Loggly
*/
Loggly.prototype.log = function( options, log ) {
	try {
		var self = this;
		// if we have stuff...
		if( log && options && options.service && options.type && options.namespace ) {

			// generate our tag based on options passed in
			var tag = [ options.service, options.type, options.namespace ].join( ',' );

			var httpsOptions = {
				hostname: self.connection.host,
				port: 443,
				// build a path containing our tag for loggly
				path: path.join( self.connection.path, self.connection.key, 'tag', tag ),
				method: 'POST'
			};
			var request = https.request( httpsOptions );
			// add the namespace to the log
			log.namespace = options.namespace;
			// ensure the log is a string
			if( typeof log !== 'string' ) {
				log = JSON.stringify( log );
			}
			// write data to request body
			request.write( log );
			request.end();
		}
	} catch ( error ) {
		console.log( 'Loggly interface encountered an exception ' + error );
	}
};

exports = module.exports = Loggly;<commit_msg>Fixed odd issue where leading slash was needed for loggly path<commit_after>/* jslint node: true */
'use strict';

/*
* @name /lib/tapestry-logger-loggly.js
* @description A Tapestry logger module to send logs to Loggly
* @since Wed Feb 12 2014
* @author Kevin Hodges <kevin.hodges@holidayextras.com>
*/
var https = require( 'https' );
var path = require( 'path' );

/**
* Constructor for a Loggly object
* @param {Object} connectionOptions, proxies whatever is passed in to Tapestry as the logger.connection
*/
function Loggly( connectionOptions ) {
	this.connection = connectionOptions;
};

/**
* Push to Loggly the passed value
* @param {Object} options:
* - service, tell Loggly who this log is from, probably the name of your app/module
* - type, payload? error? system log?
* - namespace, which of the services "buckets" should we throw this in?
* @param {Object} log, the object to push to Loggly
*/
Loggly.prototype.log = function( options, log ) {
	try {
		var self = this;
		// if we have stuff...
		if( log && options && options.service && options.type && options.namespace ) {

			// generate our tag based on options passed in
			var tag = [ options.service, options.type, options.namespace ].join( ',' );

			var httpsOptions = {
				hostname: self.connection.host,
				port: 443,
				// build a path containing our tag for loggly, this MUST contain a leading slash.
				path: path.join( '/', self.connection.path, self.connection.key, 'tag', tag ),
				method: 'POST'
			};
			var request = https.request( httpsOptions );
			// add the namespace to the log
			log.namespace = options.namespace;
			// ensure the log is a string
			if( typeof log !== 'string' ) {
				log = JSON.stringify( log );
			}
			// write data to request body
			request.write( log );
			request.end();
		}
	} catch ( error ) {
		console.log( 'Loggly interface encountered an exception ' + error );
	}
};

exports = module.exports = Loggly;<|endoftext|>


<commit_before>// Copyright (C) 2012,2013 Colin Walters <walters@verbum.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.

const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;

const Builtin = imports.builtin;
const Task = imports.task;
const ProcUtil = imports.procutil;

var AutoBuilderIface = <interface name="org.gnome.OSTreeBuild.AutoBuilder">
<method name="queueResolve">
    <arg type="as" direction="in" />
</method>
<property name="Status" type="s" access="read" />
</interface>;

const Autobuilder = new Lang.Class({
    Name: 'Autobuilder',
    Extends: Builtin.Builtin,

    DESCRIPTION: "Automatically fetch git repositories and build",

    _init: function() {
	this.parent();

        this.parser.addArgument('--autoupdate-self', { action: 'store' });

	this._buildNeeded = true;
	this._initialResolveNeeded = true;
	this._fullResolveNeeded = true;
	this._resolveTimeout = 0;
	this._resolveSrcUrls = [];
    },

    execute: function(args, loop, cancellable) {
	this._initWorkdir(null, cancellable);

	if (args.autoupdate_self)
	    this._autoupdate_self = Gio.File.new_for_path(args.autoupdate_self);

	this._ownId = Gio.DBus.session.own_name('org.gnome.OSTreeBuild', Gio.BusNameOwnerFlags.NONE,
						function(name) {},
						function(name) { loop.quit(); });

	this._impl = Gio.DBusExportedObject.wrapJSObject(AutoBuilderIface, this);
	this._impl.export(Gio.DBus.session, '/org/gnome/OSTreeBuild/AutoBuilder');

	this._taskmaster = new Task.TaskMaster(this.workdir.get_child('tasks'),
						  { onEmpty: Lang.bind(this, this._onTasksComplete) });
	this._taskmaster.connect('task-executing', Lang.bind(this, this._onTaskExecuting));
	this._taskmaster.connect('task-complete', Lang.bind(this, this._onTaskCompleted));

	/* Start an initial, non-fetching resolve */
	this._runResolve();
	/* Flag immediately that we need a full resolve */
	this._fullResolveNeeded = true;
	/* And set a timeout for 10 minutes for the next full resolve */
	this._resolveTimeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT,
							 60 * 10, Lang.bind(this, this._triggerFullResolve));

	this._updateStatus();

	loop.run();
    },

    _onTasksComplete: function() {
    },

    _onTaskExecuting: function(taskmaster, task) {
	print("Task " + task.name + " executing in " + task._taskCwd.get_path());
	this._updateStatus();
    },

    _onTaskCompleted: function(taskmaster, task, success, error) {
	if (task.name == 'resolve')
	    this._runResolve();
	if (success) {
	    print("Task " + task.name + " complete: " + task._taskCwd.get_path());
	} else {
	    this._failed = true;
	    print("Task " + task.name + " failed: " + task._taskCwd.get_path());
	}
	this._updateStatus();
    },

    _updateStatus: function() {
	let newStatus = "";
	let taskstateList = this._taskmaster.getTaskState();
	for (let i = 0; i < taskstateList.length; i++) {
	    let taskstate = taskstateList[i];
	    if (taskstate.running)
		newStatus += ("[" + taskstate.task.name + "] ");
	    else
		newStatus += (taskstate.task.name + " ");
	}
	if (newStatus == "")
	    newStatus = "[idle]";
	if (newStatus != this._status) {
	    this._status = newStatus;
	    print(this._status);
	    this._impl.emit_property_changed('Status', new GLib.Variant("s", this._status));
	}
    },

    get Status() {
	return this._status;
    },

    queueResolve: function(srcUrls) {
        this._resolveSrcUrls.push.apply(srcUrls);
        this._runResolve();
    },

    _triggerFullResolve: function() {
	this._fullResolveNeeded = true;
	this._runResolve();
	return true;
    },

    _runResolve: function() {
	let cancellable = null;

	if (!(this._initialResolveNeeded ||
	      this._resolveSrcUrls.length > 0 ||
	      this._fullResolveNeeded))
	    return;

	if (this._taskmaster.isTaskQueued('resolve'))
	    return;

	if (this._autoupdate_self)
	    ProcUtil.runSync(['git', 'pull', '-r'], cancellable,
			     { cwd: this._autoupdate_self })

	if (this._initialResolveNeeded) {
	    this._initialResolveNeeded = false;
	    this._taskmaster.pushTask('resolve', { });
	} else if (this._fullResolveNeeded) {
	    this._fullResolveNeeded = false;
	    this._taskmaster.pushTask('resolve', { fetchAll: true });
	} else {
	    this._taskmaster.pushTask('resolve', { fetchSrcUrls: this._resolveSrcUrls });
	}
	this._resolveSrcUrls = [];

	this._updateStatus();
    }
});
<commit_msg>autobuilder: Still print a message when we're queuing a force resolve<commit_after>// Copyright (C) 2012,2013 Colin Walters <walters@verbum.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.

const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;

const Builtin = imports.builtin;
const Task = imports.task;
const ProcUtil = imports.procutil;

var AutoBuilderIface = <interface name="org.gnome.OSTreeBuild.AutoBuilder">
<method name="queueResolve">
    <arg type="as" direction="in" />
</method>
<property name="Status" type="s" access="read" />
</interface>;

const Autobuilder = new Lang.Class({
    Name: 'Autobuilder',
    Extends: Builtin.Builtin,

    DESCRIPTION: "Automatically fetch git repositories and build",

    _init: function() {
	this.parent();

        this.parser.addArgument('--autoupdate-self', { action: 'store' });

	this._buildNeeded = true;
	this._initialResolveNeeded = true;
	this._fullResolveNeeded = true;
	this._resolveTimeout = 0;
	this._resolveSrcUrls = [];
    },

    execute: function(args, loop, cancellable) {
	this._initWorkdir(null, cancellable);

	if (args.autoupdate_self)
	    this._autoupdate_self = Gio.File.new_for_path(args.autoupdate_self);

	this._ownId = Gio.DBus.session.own_name('org.gnome.OSTreeBuild', Gio.BusNameOwnerFlags.NONE,
						function(name) {},
						function(name) { loop.quit(); });

	this._impl = Gio.DBusExportedObject.wrapJSObject(AutoBuilderIface, this);
	this._impl.export(Gio.DBus.session, '/org/gnome/OSTreeBuild/AutoBuilder');

	this._taskmaster = new Task.TaskMaster(this.workdir.get_child('tasks'),
						  { onEmpty: Lang.bind(this, this._onTasksComplete) });
	this._taskmaster.connect('task-executing', Lang.bind(this, this._onTaskExecuting));
	this._taskmaster.connect('task-complete', Lang.bind(this, this._onTaskCompleted));

	/* Start an initial, non-fetching resolve */
	this._runResolve();
	/* Flag immediately that we need a full resolve */
	this._fullResolveNeeded = true;
	/* And set a timeout for 10 minutes for the next full resolve */
	this._resolveTimeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT,
							 60 * 10, Lang.bind(this, this._triggerFullResolve));

	this._updateStatus();

	loop.run();
    },

    _onTasksComplete: function() {
    },

    _onTaskExecuting: function(taskmaster, task) {
	print("Task " + task.name + " executing in " + task._taskCwd.get_path());
	this._updateStatus();
    },

    _onTaskCompleted: function(taskmaster, task, success, error) {
	if (task.name == 'resolve')
	    this._runResolve();
	if (success) {
	    print("Task " + task.name + " complete: " + task._taskCwd.get_path());
	} else {
	    this._failed = true;
	    print("Task " + task.name + " failed: " + task._taskCwd.get_path());
	}
	this._updateStatus();
    },

    _updateStatus: function() {
	let newStatus = "";
	let taskstateList = this._taskmaster.getTaskState();
	for (let i = 0; i < taskstateList.length; i++) {
	    let taskstate = taskstateList[i];
	    if (taskstate.running)
		newStatus += ("[" + taskstate.task.name + "] ");
	    else
		newStatus += (taskstate.task.name + " ");
	}
	if (newStatus == "")
	    newStatus = "[idle]";
	if (newStatus != this._status) {
	    this._status = newStatus;
	    print(this._status);
	    this._impl.emit_property_changed('Status', new GLib.Variant("s", this._status));
	}
    },

    get Status() {
	return this._status;
    },

    queueResolve: function(srcUrls) {
	print("Queuing force resolve for " + JSON.stringify(srcUrls));
        this._resolveSrcUrls.push.apply(srcUrls);
        this._runResolve();
    },

    _triggerFullResolve: function() {
	this._fullResolveNeeded = true;
	this._runResolve();
	return true;
    },

    _runResolve: function() {
	let cancellable = null;

	if (!(this._initialResolveNeeded ||
	      this._resolveSrcUrls.length > 0 ||
	      this._fullResolveNeeded))
	    return;

	if (this._taskmaster.isTaskQueued('resolve'))
	    return;

	if (this._autoupdate_self)
	    ProcUtil.runSync(['git', 'pull', '-r'], cancellable,
			     { cwd: this._autoupdate_self })

	if (this._initialResolveNeeded) {
	    this._initialResolveNeeded = false;
	    this._taskmaster.pushTask('resolve', { });
	} else if (this._fullResolveNeeded) {
	    this._fullResolveNeeded = false;
	    this._taskmaster.pushTask('resolve', { fetchAll: true });
	} else {
	    this._taskmaster.pushTask('resolve', { fetchSrcUrls: this._resolveSrcUrls });
	}
	this._resolveSrcUrls = [];

	this._updateStatus();
    }
});
<|endoftext|>


<commit_before>module.exports = {
  siteMetadata: {
    title: `Neon Tsunami`,
    author: `Dwight Watson`,
    description: `A blog on Laravel & Rails.`,
    siteUrl: `https://www.neontsunami.com`,
    social: {
      twitter: `DwightConrad`,
    },
  },
  plugins: [
    `gatsby-plugin-postcss`,
    {
      resolve: `gatsby-plugin-purgecss`,
      options: {
        tailwind: true,
        ignore: ['github.css']
      }
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `markdown`,
        path: `${__dirname}/src/markdown`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          `gatsby-remark-prismjs`,
        ],
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-google-analytics`,
      options: {
        trackingId: 'UA-23727271-4',
      },
    },
    `gatsby-plugin-feed`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `Neon Tsunami`,
        short_name: `Neon Tsunami`,
        start_url: `/`,
        background_color: `#ffffff`,
        theme_color: `#4299e1`,
        display: `minimal-ui`,
        icon: `src/images/tsunami.png`,
      },
    },
    `gatsby-plugin-offline`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-netlify`,
  ],
}
<commit_msg>Disable the offline plugin for Gatsby<commit_after>module.exports = {
  siteMetadata: {
    title: `Neon Tsunami`,
    author: `Dwight Watson`,
    description: `A blog on Laravel & Rails.`,
    siteUrl: `https://www.neontsunami.com`,
    social: {
      twitter: `DwightConrad`,
    },
  },
  plugins: [
    `gatsby-plugin-postcss`,
    {
      resolve: `gatsby-plugin-purgecss`,
      options: {
        tailwind: true,
        ignore: ['github.css']
      }
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `markdown`,
        path: `${__dirname}/src/markdown`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          `gatsby-remark-prismjs`,
        ],
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-google-analytics`,
      options: {
        trackingId: 'UA-23727271-4',
      },
    },
    `gatsby-plugin-feed`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `Neon Tsunami`,
        short_name: `Neon Tsunami`,
        start_url: `/`,
        background_color: `#ffffff`,
        theme_color: `#4299e1`,
        display: `minimal-ui`,
        icon: `src/images/tsunami.png`,
      },
    },
    // `gatsby-plugin-offline`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-netlify`,
  ],
}
<|endoftext|>


<commit_before>var progress = require('./progress');
var fromJson = require('vdom-as-json/fromJson');
var patchElement = require('virtual-dom/patch');
var debounce = require('debounce');
var $ = document.querySelector.bind(document);

var detailViewOrchestrator = require('./detailViewOrchestrator');
var worker = require('./worker');

var monstersList;

// use a higher debounce for safari, which seems to ignore it if you set it
// too low
var isSafari = typeof openDatabase !== 'undefined' &&
  /(Safari|iPhone|iPad|iPod)/.test(navigator.userAgent) &&
  !/Chrome/.test(navigator.userAgent) &&
  !/BlackBerry/.test(navigator.platform);
var delay = isSafari ? 200 : 100;

function binarySearchForFirstVisibleChild(children) {
  var low = 0, high = children.length, mid, rect, val;
  while (low < high) {
    mid = (low + high) >>> 1; // faster version of Math.floor((low + high) / 2)
    rect = children[mid].getBoundingClientRect();
    val = rect.top + rect.height;
    val < 0 ? low = mid + 1 : high = mid;
  }
  return low;
}

function renderSprites() {
  monstersList = monstersList || $('#monsters-list');
  var children = monstersList.children;
  if (!children.length) {
    return;
  }
  console.time('renderSprites');
  console.time('binarySearch');
  var windowHeight = window.innerHeight;
  var numShown = 0;
  var numHidden = 0;
  var firstVisibleIndex = binarySearchForFirstVisibleChild(children);
  console.timeEnd('binarySearch');
  console.log('firstVisibleIndex', firstVisibleIndex);
  var i = -1;
  var done = false;
  console.time('loop');
  while (++i < children.length) {
    var child = children[i];
    if (i < firstVisibleIndex) {
      // before the visible viewport
      child.classList.add('hidden');
      numHidden++;
      continue;
    }
    if (done) {
      // after the visible viewport
      child.classList.add('hidden');
      numHidden++;
      continue;
    }
    console.time('getBoundingClientRect');
    // possibly within the visible viewport
    var rect = child.getBoundingClientRect();
    console.timeEnd('getBoundingClientRect');
    if ((rect.bottom - rect.height) < windowHeight) {
      child.classList.remove('hidden');
      numShown++;
      continue;
    }
    child.classList.add('hidden');
    numHidden++;
    done = true;
  }
  console.timeEnd('loop');
  console.log('numShown', numShown, 'numHidden', numHidden);
  console.timeEnd('renderSprites');
}

renderSprites();

function applyPatch(patchString) {
  console.time('JSON.parse()');
  var patchJson = JSON.parse(patchString);
  console.timeEnd('JSON.parse()');
  console.time('fromJson');
  var patch = fromJson(patchJson);
  console.timeEnd('fromJson');
  console.time('patchElement');
  patchElement(monstersList, patch);
  console.timeEnd('patchElement');
  progress.end();
}

function onFiltered(message) {
  console.timeEnd('worker-detail');
  console.log('worker sent message');

  if (message.type === 'monstersListPatch') {
    applyPatch(message.patch);
  }
}

function onMessage(message) {
  if (message.type === 'monstersListPatch') {
    onFiltered(message);
  }
}

worker.addEventListener('message', e => {
  onMessage(e.data);
});

document.addEventListener('DOMContentLoaded', () => {
  monstersList = $('#monsters-list');
  monstersList.addEventListener('click', e => {
    e.stopPropagation();
    var el = e.target.parentElement.querySelector('.monster-sprite');
    var nationalId = parseInt(el.dataset.nationalId);
    console.time('worker-detail');
    worker.postMessage({
      type: 'detail',
      nationalId: nationalId
    });
    detailViewOrchestrator.animateInPartOne(nationalId);
  });
  window.addEventListener('scroll', debounce(renderSprites, delay));
}, false);

// This happens e.g. when the keyboard moves in/out on Android, in which
// case the window.innerHeight also changes, so we need to recalculate.
// This is debounced for the benefit of web developers manually resizing
// their window, so it doesn't end up looking so janky.
window.addEventListener('resize', debounce(renderSprites, 50));<commit_msg>disable scrolling stuff<commit_after>var progress = require('./progress');
var fromJson = require('vdom-as-json/fromJson');
var patchElement = require('virtual-dom/patch');
var debounce = require('debounce');
var $ = document.querySelector.bind(document);

var detailViewOrchestrator = require('./detailViewOrchestrator');
var worker = require('./worker');

var monstersList;
/*
var DEBOUNCE_DELAY = 100;

function binarySearchForFirstVisibleChild(children) {
  var low = 0, high = children.length, mid, rect, val;
  while (low < high) {
    mid = (low + high) >>> 1; // faster version of Math.floor((low + high) / 2)
    rect = children[mid].getBoundingClientRect();
    val = rect.top + rect.height;
    val < 0 ? low = mid + 1 : high = mid;
  }
  return low;
}

function renderSprites() {
  monstersList = monstersList || $('#monsters-list');
  var children = monstersList.children;
  if (!children.length) {
    return;
  }
  console.time('renderSprites');
  console.time('binarySearch');
  var windowHeight = window.innerHeight;
  var numShown = 0;
  var numHidden = 0;
  var firstVisibleIndex = binarySearchForFirstVisibleChild(children);
  console.timeEnd('binarySearch');
  console.log('firstVisibleIndex', firstVisibleIndex);
  var i = -1;
  var done = false;
  console.time('loop');
  while (++i < children.length) {
    var child = children[i];
    if (i < firstVisibleIndex) {
      // before the visible viewport
      child.classList.add('hidden');
      numHidden++;
      continue;
    }
    if (done) {
      // after the visible viewport
      child.classList.add('hidden');
      numHidden++;
      continue;
    }
    console.time('getBoundingClientRect');
    // possibly within the visible viewport
    var rect = child.getBoundingClientRect();
    console.timeEnd('getBoundingClientRect');
    if ((rect.bottom - rect.height) < windowHeight) {
      child.classList.remove('hidden');
      numShown++;
      continue;
    }
    child.classList.add('hidden');
    numHidden++;
    done = true;
  }
  console.timeEnd('loop');
  console.log('numShown', numShown, 'numHidden', numHidden);
  console.timeEnd('renderSprites');
}

renderSprites();

 */

function applyPatch(patchString) {
  console.time('JSON.parse()');
  var patchJson = JSON.parse(patchString);
  console.timeEnd('JSON.parse()');
  console.time('fromJson');
  var patch = fromJson(patchJson);
  console.timeEnd('fromJson');
  console.time('patchElement');
  patchElement(monstersList, patch);
  console.timeEnd('patchElement');
  progress.end();
}

function onFiltered(message) {
  console.timeEnd('worker-detail');
  console.log('worker sent message');

  if (message.type === 'monstersListPatch') {
    applyPatch(message.patch);
  }
}

function onMessage(message) {
  if (message.type === 'monstersListPatch') {
    onFiltered(message);
  }
}

worker.addEventListener('message', e => {
  onMessage(e.data);
});

document.addEventListener('DOMContentLoaded', () => {
  monstersList = $('#monsters-list');
  monstersList.addEventListener('click', e => {
    e.stopPropagation();
    var el = e.target.parentElement.querySelector('.monster-sprite');
    var nationalId = parseInt(el.dataset.nationalId);
    console.time('worker-detail');
    worker.postMessage({
      type: 'detail',
      nationalId: nationalId
    });
    detailViewOrchestrator.animateInPartOne(nationalId);
  });
  //window.addEventListener('scroll', debounce(renderSprites, DEBOUNCE_DELAY));
}, false);

// This happens e.g. when the keyboard moves in/out on Android, in which
// case the window.innerHeight also changes, so we need to recalculate.
// This is debounced for the benefit of web developers manually resizing
// their window, so it doesn't end up looking so janky.
//window.addEventListener('resize', debounce(renderSprites, 50));<|endoftext|>


<commit_before>// ==UserScript==
// @name         Slither.io-bot
// @namespace    http://slither.io/
// @version      0.3.1
// @description  Slither.io bot
// @author       Ermiya Eskandary & Théophile Cailliau
// @match        http://slither.io/
// @grant        none
// ==/UserScript==

// Functions needed for the bot
// Custom logging function - disabled by default
window.logDebugging = false;

window.log = function () {
    if (window.logDebugging === true) {
        console.log.apply(console, arguments);
    }
};
// Appends divs to the page - used to display things on the screen
window.appendDiv = function (id, className, style) {
    // Create a div
    var div = document.createElement('div');
    // Check for id
    if (id) {
        // Set the id
        div.id = id;
    }
    // Check for class name
    if (className) {
        // Set the class name
        div.className = className;
    }
    // Check for css styles
    if (style) {
        // Set the css styles
        div.style = style;
    }
    // Append the div to the page
    document.body.appendChild(div);
};
// Set fake mouse coordinates
window.setMouseCoordinates = function (x, y) {
    window.xm = x;
    window.ym = y;
};
// Return the coordinates relative to the center (snake position).
window.mouseRelativeToCenter = function (x, y) {
    var mapX = x - window.getHeight() / 2;
    var mapY = y - window.getWidth() / 2;
    return [mapX, mapY];
};
// mouse coordinates to screen coordinates
window.mouseToScreen = function (x, y) {
    var screenX = x + (window.getHeight() / 2);
    var screenY = y + (window.getWidth() / 2);
    return [screenX, screenY];
};
window.screenToCanvas = function (x, y) {
    var canvasX = window.csc * x * window.canvasRatio[0] - window.csc * parseInt(window.mc.style.left);
    var canvasY = window.csc * y * window.canvasRatio[1] - window.csc * parseInt(window.mc.style.top);
    return [canvasX, canvasY];
};
// Map to mouse coordinates
window.mapToMouse = function (x, y) {
    var mouseX = (x - window.getX()) * window.gsc;
    var mouseY = (y - window.getY()) * window.gsc;
    return [mouseX, mouseY];
};
// Canvas width
window.getWidth = function () {
    return window.ww;
};
// Canvas height
window.getHeight = function () {
    return window.hh;
};
// X coordinates on the screen
window.getX = function () {
    return window.snake.xx;
};
// Y coordinates on the screen
window.getY = function () {
    return window.snake.yy;
};
window.onresize = function () {
    window.resize();
    window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
};
window.setZoom = function (e) {
    if (window.gsc) {
        window.gsc *= Math.pow(0.9, e.wheelDelta / -120 || e.detail / 2 || 0);
    }
};

// Overlays
window.position_overlay;
window.generalstyle = 'color: #FFF; font-family: Arial, \'Helvetica Neue\', Helvetica, sans-serif; font-size: 14px; position: fixed; opacity: 0.35; z-index: 7;';
window.appendDiv('position_overlay', 'nsi', window.generalstyle + 'right: 30; bottom: 120px;');
window.position_overlay = document.getElementById('position_overlay');

document.body.addEventListener('mousewheel', window.setZoom);
document.body.addEventListener('DOMMouseScroll', window.setZoom);

// Get scaling ratio
window.getScale = function () {
    return window.gsc;
};

window.isBotRunning = false;
window.isBotEnabled = true;

// Save the original slither.io onmousemove function so we can re enable it back later
window.mousemovelistener = window.onmousemove;

// Starts the bot
window.launchBot = function (d) {
    window.log('Starting Bot.');
    window.isBotRunning = true;
    // Removed the onemousemove listener so we can move the snake manually by setting coordinates
    window.onmousemove = function () {};
    window.botInterval = setInterval(window.loop, d);
    return window.botInterval;
};

// Stops the bot
window.stopBot = function () {
    window.log('Stopping Bot.');
    // Re enable the original onmousemove function
    window.onmousemove = window.mousemovelistener;
    window.isBotRunning = false;
    // Clear the interval which starts the bot
    return clearInterval(window.botInterval);
};

window.connectBot = function () {
    window.stopBot();
    window.log('Connecting...');
    window.connect();
    window.botCanStart = setInterval(function () {
        if (window.playing) {
            window.launchBot(5);
            clearInterval(window.botCanStart);
        }
    }, 100);
};

// Save the original slither.io onkeydown function so we can add stuff to it
document.oldKeyDown = document.onkeydown;

// Re write the function with our function
document.onkeydown = function (e) {
    // Original slither.io onkeydown function + whatever is under it
    document.oldKeyDown(e);
    // If the letter 't' is pressed, check if the bot is running. If it is, stop the bot. If it isn't, start the bot.
    if (e.keyCode === 84) {
        if (window.isBotRunning) {
            window.stopBot();
            window.isBotEnabled = false;
        } else {
            window.launchBot(5);
            window.isBotEnabled = true;
        }
    }
};

// Sorting function, from property 'distance'
window.sortObjects = function (a, b) {
    return a.distance - b.distance;
};

// Given an object (of which properties xx and yy are not null), return the object with an additional property 'distance'
window.getDistanceFromMe = function (point) {
    if (point === null) return null;
    point.distance = window.getDistance(window.getX(), window.getY(), point.xx, point.yy);
    return point;
};

// Get a distance from point (x1; y1) to point (x2; y2).
window.getDistance = function (x1, y1, x2, y2) {
    // Calculate the vector coordinates.
    var xDistance = (x1 - x2);
    var yDistance = (y1 - y2);
    // Get the absolute value of each coordinate
    xDistance = xDistance < 0 ? xDistance * -1 : xDistance;
    yDistance = yDistance < 0 ? yDistance * -1 : yDistance;
    //Add the coordinates of the vector to get a distance. Not the real distance, but reliable for distance comparison.
    var distance = xDistance + yDistance;
    return distance;
};

// Sort food based on distance
window.getSortedFood = function () {
    // Filters the nearest food by getting the distance
    return window.foods.filter(function (val) {
        return val !== null;
    }).map(window.getDistanceFromMe).sort(window.sortObjects);
};

// Sort enemies based on distance
window.getSortedEnemies = function () {
    // Filters the nearest food by getting the distance
    return window.snakes.filter(function (val) {
        return val !== null && val.id !== window.snake.id;
    }).map(window.getDistanceFromMe).sort(window.sortObjects);
};

// Draw dots on the canvas
window.drawDot = function (x, y, radius, colour) {
    var context = window.mc.getContext('2d');
    context.beginPath();
    context.arc(x, y, radius, 0, Math.PI * 2);
    context.closePath();
    context.fillStyle = ('green red white yellow black cyan blue'.indexOf(colour) < 0) ? 'white' : colour;
    context.fill();
};

// Draw lines on the canvas
window.drawLine = function (x2, y2, colour) {
    var context = window.mc.getContext('2d');
    var center = [window.mc.height / 2, window.mc.width / 2];
    context.lineWidth = 5;
    context.strokeStyle = (colour === 'green') ? '#00FF00' : '#FF0000';
    context.moveTo(center[1], center[0]);
    context.lineTo(x2, y2);
    context.stroke();
};

window.oldOef = window.oef;

window.oef = function () {
    window.oldOef();
    window.onFrameUpdate();
};

window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
window.onFrameUpdate = function () {
    if (window.playing && window.isBotRunning) {
        var foodCoordinates = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
        foodCoordinates = window.mouseToScreen(foodCoordinates[0], foodCoordinates[1]);
        foodCoordinates = window.screenToCanvas(foodCoordinates[0], foodCoordinates[1]);
        window.drawLine(foodCoordinates[0], foodCoordinates[1], 'green');
        for (var i = 0; i < window.sortedFood.length; i++) {
            var item = window.sortedFood[i];
            foodCoordinates = window.mapToMouse(item.xx, item.yy);
            foodCoordinates = window.mouseToScreen(foodCoordinates[0], foodCoordinates[1]);
            foodCoordinates = window.screenToCanvas(foodCoordinates[0], foodCoordinates[1]);
            window.drawDot(foodCoordinates[0], foodCoordinates[1], 5, 'red');
        }
    }
};

/*
window.isInFoods = function (foodObject) {
    return (foodObject === null) ? false : (window.foods.indexOf(foodObject) >= 0);
};
window.currentFood = null;
window.sortedFood = getSortedFood();
window.loop = function () {
    if (!isInFoods(currentFood)) {
        window.sortedFood = getSortedFood();
        window.currentFood = sortedFood[0];
        var coordinatesOfClosestFood = window.mapToMouse(window.sortedFood[0].xx, window.sortedFood[0].yy);
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);
    }
};
*/
// Actual bot code

// Loop for running the bot
window.loop = function () {
    // If the game and the bot are running
    if (window.playing && window.isBotEnabled) {
        // Check to see if there is a position overlay
        if (window.position_overlay) {
            // Display the X and Y of the snake
            window.position_overlay.textContent = 'X: ' + (Math.round(window.snake.xx) || 0) + ' Y: ' + (Math.round(window.snake.yy) || 0);
        }
        // Sort the food and enemies based on their distance relative to player's snake
        window.sortedFood = window.getSortedFood();
        window.sortedEnemies = window.getSortedEnemies();
        // Take the closest of each
        window.closestEnemy = window.sortedEnemies[0];
        window.currentFood = window.sortedFood[0];
        // Convert coordinates of the closest food using mapToMouse
        var coordinatesOfClosestFood = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
        if (window.closestEnemy.distance < 300) {
            //window.log('close enemy! (distance = ' + window.closestEnemy.distance);
            // !handle close enemies!
        }
        // Set the mouse coordinates to the coordinates of the closest food
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);

    } else {
        window.startInterval = setInterval(window.startInterval, 1000);
        window.stopBot();
    }
};

window.startInterval = function () {
    if (window.playing === false && window.isBotEnabled === true) {
        window.connectBot();
        clearInterval(window.startInterval);
    }
};
window.startInterval();
<commit_msg>Commented everything - formatting<commit_after>// ==UserScript==
// @name         Slither.io-bot
// @namespace    http://slither.io/
// @version      0.3.2
// @description  Slither.io bot
// @author       Ermiya Eskandary & Théophile Cailliau
// @match        http://slither.io/
// @grant        none
// ==/UserScript==
// Functions needed for the bot
// Custom logging function - disabled by default
window.logDebugging = false;

window.log = function() {
    if (window.logDebugging === true) {
        console.log.apply(console, arguments);
    }
};
// Appends divs to the page - used to display things on the screen
window.appendDiv = function(id, className, style) {
    // Create a div
    var div = document.createElement('div');
    // Check for id
    if (id) {
        // Set the id
        div.id = id;
    }
    // Check for class name
    if (className) {
        // Set the class name
        div.className = className;
    }
    // Check for css styles
    if (style) {
        // Set the css styles
        div.style = style;
    }
    // Append the div to the page
    document.body.appendChild(div);
};
// Set fake mouse coordinates
window.setMouseCoordinates = function(x, y) {
    window.xm = x;
    window.ym = y;
};
// Coordinates relative to the center (snake position).
window.mouseRelativeToCenter = function(x, y) {
    var mapX = x - window.getHeight() / 2;
    var mapY = y - window.getWidth() / 2;
    return [mapX, mapY];
};
// Mouse coordinates to screen coordinates
window.mouseToScreen = function(x, y) {
    var screenX = x + (window.getHeight() / 2);
    var screenY = y + (window.getWidth() / 2);
    return [screenX, screenY];
};
window.screenToCanvas = function(x, y) {
    var canvasX = window.csc * x * window.canvasRatio[0] - window.csc * parseInt(window.mc.style.left);
    var canvasY = window.csc * y * window.canvasRatio[1] - window.csc * parseInt(window.mc.style.top);
    return [canvasX, canvasY];
};
// Map to mouse coordinates
window.mapToMouse = function(x, y) {
    var mouseX = (x - window.getX()) * window.gsc;
    var mouseY = (y - window.getY()) * window.gsc;
    return [mouseX, mouseY];
};
// Canvas width
window.getWidth = function() {
    return window.ww;
};
// Canvas height
window.getHeight = function() {
    return window.hh;
};
// X coordinates on the screen
window.getX = function() {
    return window.snake.xx;
};
// Y coordinates on the screen
window.getY = function() {
    return window.snake.yy;
};
// Updates the relation between the screen and the canvas
window.onresize = function() {
    window.resize();
    // Canvas different size from the screen (often bigger). Gives a ratio so we can convert
    window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
};
// Lets you zoom in and out using the mosue wheel
window.setZoom = function(e) {
    // Scaling ratio
    if (window.gsc) {
        window.gsc *= Math.pow(0.9, e.wheelDelta / -120 || e.detail / 2 || 0);
    }
};

// Overlays
window.position_overlay;
window.generalstyle = 'color: #FFF; font-family: Arial, \'Helvetica Neue\', Helvetica, sans-serif; font-size: 14px; position: fixed; opacity: 0.35; z-index: 7;';
window.appendDiv('position_overlay', 'nsi', window.generalstyle + 'right: 30; bottom: 120px;');
window.position_overlay = document.getElementById('position_overlay');
// Listener for mouse wheel scroll - used for setZoom function
document.body.addEventListener('mousewheel', window.setZoom);
document.body.addEventListener('DOMMouseScroll', window.setZoom);

// Get scaling ratio
window.getScale = function() {
    return window.gsc;
};

window.isBotRunning = false;
window.isBotEnabled = true;

// Save the original slither.io onmousemove function so we can re enable it back later
window.mousemovelistener = window.onmousemove;

// Starts the bot
window.launchBot = function(d) {
    window.log('Starting Bot.');
    window.isBotRunning = true;
    // Removed the onemousemove listener so we can move the snake manually by setting coordinates
    window.onmousemove = function() {};
    window.botInterval = setInterval(window.loop, d);
    return window.botInterval;
};

// Stops the bot
window.stopBot = function() {
    window.log('Stopping Bot.');
    // Re enable the original onmousemove function
    window.onmousemove = window.mousemovelistener;
    window.isBotRunning = false;
    // Clear the interval which starts the bot
    return clearInterval(window.botInterval);
};

// Connects the bot
window.connectBot = function() {
    // Stop the bot
    window.stopBot();
    window.log('Connecting...');
    // Connect the bot
    window.connect();
    // Check if bot can start
    window.botCanStart = setInterval(function() {
        if (window.playing) {
            window.launchBot(5);
            clearInterval(window.botCanStart);
        }
    }, 100);
};

// Save the original slither.io onkeydown function so we can add stuff to it
document.oldKeyDown = document.onkeydown;

// Re write the function with our function
document.onkeydown = function(e) {
    // Original slither.io onkeydown function + whatever is under it
    document.oldKeyDown(e);
    // If the letter 't' is pressed, check if the bot is running. If it is, stop the bot. If it isn't, start the bot.
    if (e.keyCode === 84) {
        if (window.isBotRunning) {
            window.stopBot();
            window.isBotEnabled = false;
        } else {
            window.launchBot(5);
            window.isBotEnabled = true;
        }
    }
};

// Sorting function, from property 'distance'
window.sortObjects = function(a, b) {
    return a.distance - b.distance;
};

// Given an object (of which properties xx and yy are not null), return the object with an additional property 'distance'
window.getDistanceFromMe = function(point) {
    if (point === null) return null;
    point.distance = window.getDistance(window.getX(), window.getY(), point.xx, point.yy);
    return point;
};

// Get a distance from point (x1; y1) to point (x2; y2).
window.getDistance = function(x1, y1, x2, y2) {
    // Calculate the vector coordinates.
    var xDistance = (x1 - x2);
    var yDistance = (y1 - y2);
    // Get the absolute value of each coordinate
    xDistance = xDistance < 0 ? xDistance * -1 : xDistance;
    yDistance = yDistance < 0 ? yDistance * -1 : yDistance;
    //Add the coordinates of the vector to get a distance. Not the real distance, but reliable for distance comparison.
    var distance = xDistance + yDistance;
    // Real distance but not needed. Here for reference
    // var distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
    return distance;
};

// Sort food based on distance
window.getSortedFood = function() {
    // Filters the nearest food by getting the distance
    return window.foods.filter(function(val) {
        return val !== null;
    }).map(window.getDistanceFromMe).sort(window.sortObjects);
};

// Sort enemies based on distance
window.getSortedEnemies = function() {
    // Filters the nearest food by getting the distance
    return window.snakes.filter(function(val) {
        return val !== null && val.id !== window.snake.id;
    }).map(window.getDistanceFromMe).sort(window.sortObjects);
};

// Draw dots on the canvas
window.drawDot = function(x, y, radius, colour) {
    var context = window.mc.getContext('2d');
    context.beginPath();
    context.arc(x, y, radius, 0, Math.PI * 2);
    context.closePath();
    context.fillStyle = ('green red white yellow black cyan blue'.indexOf(colour) < 0) ? 'white' : colour;
    context.fill();
};

// Draw lines on the canvas
window.drawLine = function(x2, y2, colour) {
    var context = window.mc.getContext('2d');
    var center = [window.mc.height / 2, window.mc.width / 2];
    context.lineWidth = 5;
    context.strokeStyle = (colour === 'green') ? '#00FF00' : '#FF0000';
    context.moveTo(center[1], center[0]);
    context.lineTo(x2, y2);
    context.stroke();
};
// Save the original slither.io oef function so we can add things to it later
window.oldOef = window.oef;

window.oef = function() {
    // Original slithe.io oef function + whatever is under it
    window.oldOef();
    window.onFrameUpdate();
};

window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
window.onFrameUpdate = function() {
    if (window.playing && window.isBotRunning) {
        var foodCoordinates = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
        foodCoordinates = window.mouseToScreen(foodCoordinates[0], foodCoordinates[1]);
        foodCoordinates = window.screenToCanvas(foodCoordinates[0], foodCoordinates[1]);
        window.drawLine(foodCoordinates[0], foodCoordinates[1], 'green');
        for (var i = 0; i < window.sortedFood.length; i++) {
            var item = window.sortedFood[i];
            foodCoordinates = window.mapToMouse(item.xx, item.yy);
            foodCoordinates = window.mouseToScreen(foodCoordinates[0], foodCoordinates[1]);
            foodCoordinates = window.screenToCanvas(foodCoordinates[0], foodCoordinates[1]);
            window.drawDot(foodCoordinates[0], foodCoordinates[1], 5, 'red');
        }
    }
};

/*
window.isInFoods = function (foodObject) {
    return (foodObject === null) ? false : (window.foods.indexOf(foodObject) >= 0);
};
window.currentFood = null;
window.sortedFood = getSortedFood();
window.loop = function () {
    if (!isInFoods(currentFood)) {
        window.sortedFood = getSortedFood();
        window.currentFood = sortedFood[0];
        var coordinatesOfClosestFood = window.mapToMouse(window.sortedFood[0].xx, window.sortedFood[0].yy);
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);
    }
};
*/
// Actual bot code

// Loop for running the bot
window.loop = function() {
    // If the game and the bot are running
    if (window.playing && window.isBotEnabled) {
        // Check to see if there is a position overlay
        if (window.position_overlay) {
            // Display the X and Y of the snake
            window.position_overlay.textContent = 'X: ' + (Math.round(window.snake.xx) || 0) + ' Y: ' + (Math.round(window.snake.yy) || 0);
        }
        // Sort the food and enemies based on their distance relative to player's snake
        window.sortedFood = window.getSortedFood();
        window.sortedEnemies = window.getSortedEnemies();
        // Take the closest of each
        window.closestEnemy = window.sortedEnemies[0];
        window.currentFood = window.sortedFood[0];
        // Convert coordinates of the closest food using mapToMouse
        var coordinatesOfClosestFood = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
        if (window.closestEnemy.distance < 300) {
            //window.log('close enemy! (distance = ' + window.closestEnemy.distance);
            // !handle close enemies!
        }
        // Set the mouse coordinates to the coordinates of the closest food
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);

    } else {
        window.startInterval = setInterval(window.startInterval, 1000);
        window.stopBot();
    }
};
// First function called
window.startInterval = function() {
    if (window.playing === false && window.isBotEnabled === true) {
        window.connectBot();
        clearInterval(window.startInterval);
    }
};
window.startInterval();
<|endoftext|>


<commit_before>var progress = require('./progress');
var debounce = require('debounce');
var fromJson = require('vdom-as-json/fromJson');
var patchElement = require('virtual-dom/patch');
var $ = document.querySelector.bind(document);

var worker = require('./worker');

var monstersList;

function applyPatch(patchString) {
  monstersList = monstersList || $('#monsters-list');
  console.time('JSON.parse()');
  var patch = JSON.parse(patchString);
  console.timeEnd('JSON.parse()');
  console.time('fromJson');
  var patch = fromJson(patch);
  console.timeEnd('fromJson');
  console.time('patchElement');
  patchElement(monstersList, patch);
  console.timeEnd('patchElement');
  progress.end();
}

function onFiltered(message) {
  console.timeEnd('worker-filter');
  console.log('worker sent message');

  if (message.type === 'monstersListPatch') {
    applyPatch(message.content);
  }
}

function onMessage(message) {
  if (message.type === 'monstersListPatch') {
    onFiltered(message);
  }
}

worker.addEventListener('message', e => {
  onMessage(e.data);
});<commit_msg>fix bad variable usage<commit_after>var progress = require('./progress');
var debounce = require('debounce');
var fromJson = require('vdom-as-json/fromJson');
var patchElement = require('virtual-dom/patch');
var $ = document.querySelector.bind(document);

var worker = require('./worker');

var monstersList;

function applyPatch(patchString) {
  monstersList = monstersList || $('#monsters-list');
  console.time('JSON.parse()');
  var patchJson = JSON.parse(patchString);
  console.timeEnd('JSON.parse()');
  console.time('fromJson');
  var patch = fromJson(patchJson);
  console.timeEnd('fromJson');
  console.time('patchElement');
  patchElement(monstersList, patch);
  console.timeEnd('patchElement');
  progress.end();
}

function onFiltered(message) {
  console.timeEnd('worker-filter');
  console.log('worker sent message');

  if (message.type === 'monstersListPatch') {
    applyPatch(message.content);
  }
}

function onMessage(message) {
  if (message.type === 'monstersListPatch') {
    onFiltered(message);
  }
}

worker.addEventListener('message', e => {
  onMessage(e.data);
});<|endoftext|>


<commit_before>const browser = typeof window !== 'undefined';
const EventEmitter = require('events').EventEmitter;
const Constants = require('../../util/Constants');
const convertArrayBuffer = require('../../util/ConvertArrayBuffer');
const pako = require('pako');
const zlib = require('zlib');
const PacketManager = require('./packets/WebSocketPacketManager');

let WebSocket, erlpack;
let serialize = JSON.stringify;
if (browser) {
  WebSocket = window.WebSocket; // eslint-disable-line no-undef
} else {
  try {
    WebSocket = require('uws');
  } catch (err) {
    WebSocket = require('ws');
  }

  try {
    erlpack = require('erlpack');
    serialize = erlpack.pack;
  } catch (err) {
    erlpack = null;
  }
}

/**
 * The WebSocket Manager of the Client
 * @private
 */
class WebSocketManager extends EventEmitter {
  constructor(client) {
    super();
    /**
     * The Client that instantiated this WebSocketManager
     * @type {Client}
     */
    this.client = client;

    /**
     * A WebSocket Packet manager, it handles all the messages
     * @type {PacketManager}
     */
    this.packetManager = new PacketManager(this);

    /**
     * The status of the WebSocketManager, a type of Constants.Status. It defaults to IDLE.
     * @type {number}
     */
    this.status = Constants.Status.IDLE;

    /**
     * The session ID of the connection, null if not yet available.
     * @type {?string}
     */
    this.sessionID = null;

    /**
     * The packet count of the client, null if not yet available.
     * @type {?number}
     */
    this.sequence = -1;

    /**
     * The gateway address for this WebSocket connection, null if not yet available.
     * @type {?string}
     */
    this.gateway = null;

    /**
     * Whether READY was emitted normally (all packets received) or not
     * @type {boolean}
     */
    this.normalReady = false;

    /**
     * The WebSocket connection to the gateway
     * @type {?WebSocket}
     */
    this.ws = null;

    /**
     * An object with keys that are websocket event names that should be ignored
     * @type {Object}
     */
    this.disabledEvents = {};
    for (const event of client.options.disabledEvents) this.disabledEvents[event] = true;

    this.first = true;
  }

  /**
   * Connects the client to a given gateway
   * @param {string} gateway The gateway to connect to
   */
  _connect(gateway) {
    this.client.emit('debug', `Connecting to gateway ${gateway}`);
    this.normalReady = false;
    if (this.status !== Constants.Status.RECONNECTING) this.status = Constants.Status.CONNECTING;
    this.ws = new WebSocket(gateway);
    if (browser) this.ws.binaryType = 'arraybuffer';
    this.ws.onopen = this.eventOpen.bind(this);
    this.ws.onmessage = this.eventMessage.bind(this);
    this.ws.onclose = this.eventClose.bind(this);
    this.ws.onerror = this.eventError.bind(this);
    this._queue = [];
    this._remaining = 3;
  }

  connect(gateway) {
    gateway = `${gateway}&encoding=${erlpack ? 'etf' : 'json'}`;
    if (this.first) {
      this._connect(gateway);
      this.first = false;
    } else {
      this.client.setTimeout(() => this._connect(gateway), 5500);
    }
  }

  /**
   * Sends a packet to the gateway
   * @param {Object} data An object that can be JSON stringified
   * @param {boolean} force Whether or not to send the packet immediately
   */
  send(data, force = false) {
    if (force) {
      this._send(serialize(data));
      return;
    }
    this._queue.push(serialize(data));
    this.doQueue();
  }

  destroy() {
    this.ws.close(1000);
    this._queue = [];
    this.status = Constants.Status.IDLE;
  }

  _send(data) {
    if (this.ws.readyState === WebSocket.OPEN) {
      this.emit('send', data);
      this.ws.send(data);
    }
  }

  doQueue() {
    const item = this._queue[0];
    if (this.ws.readyState === WebSocket.OPEN && item) {
      if (this._remaining === 0) {
        this.client.setTimeout(this.doQueue.bind(this), 1000);
        return;
      }
      this._remaining--;
      this._send(item);
      this._queue.shift();
      this.doQueue();
      this.client.setTimeout(() => this._remaining++, 1000);
    }
  }

  /**
   * Run whenever the gateway connections opens up
   */
  eventOpen() {
    this.client.emit('debug', 'Connection to gateway opened');
    if (this.status === Constants.Status.RECONNECTING) this._sendResume();
    else this._sendNewIdentify();
  }

  /**
   * Sends a gateway resume packet, in cases of unexpected disconnections.
   */
  _sendResume() {
    if (!this.sessionID) {
      this._sendNewIdentify();
      return;
    }
    this.client.emit('debug', 'Identifying as resumed session');
    const payload = {
      token: this.client.token,
      session_id: this.sessionID,
      seq: this.sequence,
    };

    this.send({
      op: Constants.OPCodes.RESUME,
      d: payload,
    });
  }

  /**
   * Sends a new identification packet, in cases of new connections or failed reconnections.
   */
  _sendNewIdentify() {
    this.reconnecting = false;
    const payload = this.client.options.ws;
    payload.token = this.client.token;
    if (this.client.options.shardCount > 0) {
      payload.shard = [Number(this.client.options.shardId), Number(this.client.options.shardCount)];
    }
    this.client.emit('debug', 'Identifying as new session');
    this.send({
      op: Constants.OPCodes.IDENTIFY,
      d: payload,
    });
    this.sequence = -1;
  }

  /**
   * Run whenever the connection to the gateway is closed, it will try to reconnect the client.
   * @param {Object} event The received websocket data
   */
  eventClose(event) {
    this.emit('close', event);
    this.client.clearInterval(this.client.manager.heartbeatInterval);
    this.status = Constants.Status.DISCONNECTED;
    /**
     * Emitted whenever the client websocket is disconnected
     * @event Client#disconnect
     */
    if (!this.reconnecting) this.client.emit(Constants.Events.DISCONNECT);
    if (event.code === 4004) return;
    if (event.code === 4010) return;
    if (!this.reconnecting && event.code !== 1000) this.tryReconnect();
  }

  /**
   * Run whenever a message is received from the WebSocket. Returns `true` if the message
   * was handled properly.
   * @param {Object} event The received websocket data
   * @returns {boolean}
   */
  eventMessage(event) {
    const data = this.tryParseEventData(event.data);
    if (data === null) {
      this.eventError(new Error(Constants.Errors.BAD_WS_MESSAGE));
      return false;
    }

    this.client.emit('raw', data);

    if (data.op === Constants.OPCodes.HELLO) this.client.manager.setupKeepAlive(data.d.heartbeat_interval);
    return this.packetManager.handle(data);
  }

  /**
   * Parses the raw data from a websocket event, inflating it if necessary
   * @param {*} data Event data
   * @returns {Object}
   */
  parseEventData(data) {
    if (erlpack) {
      if (data instanceof ArrayBuffer) data = convertArrayBuffer(data);
      return erlpack.unpack(data);
    } else {
      if (data instanceof ArrayBuffer) data = pako.inflate(data, { to: 'string' });
      else if (data instanceof Buffer) data = zlib.inflateSync(data).toString();
      return JSON.parse(data);
    }
  }

  /**
   * Tries to call `parseEventData()` and return its result, or returns `null` upon thrown errors.
   * @param {*} data Event data
   * @returns {?Object}
   */
  tryParseEventData(data) {
    try {
      return this.parseEventData(data);
    } catch (err) {
      return null;
    }
  }

  /**
   * Run whenever an error occurs with the WebSocket connection. Tries to reconnect
   * @param {Error} err The encountered error
   */
  eventError(err) {
    /**
     * Emitted whenever the Client encounters a serious connection error
     * @event Client#error
     * @param {Error} error The encountered error
     */
    if (this.client.listenerCount('error') > 0) this.client.emit('error', err);
    this.tryReconnect();
  }

  _emitReady(normal = true) {
    /**
     * Emitted when the Client becomes ready to start working
     * @event Client#ready
     */
    this.status = Constants.Status.READY;
    this.client.emit(Constants.Events.READY);
    this.packetManager.handleQueue();
    this.normalReady = normal;
  }

  /**
   * Runs on new packets before `READY` to see if the Client is ready yet, if it is prepares
   * the `READY` event.
   */
  checkIfReady() {
    if (this.status !== Constants.Status.READY && this.status !== Constants.Status.NEARLY) {
      let unavailableCount = 0;
      for (const guildID of this.client.guilds.keys()) {
        unavailableCount += this.client.guilds.get(guildID).available ? 0 : 1;
      }
      if (unavailableCount === 0) {
        this.status = Constants.Status.NEARLY;
        if (this.client.options.fetchAllMembers) {
          const promises = this.client.guilds.map(g => g.fetchMembers());
          Promise.all(promises).then(() => this._emitReady(), e => {
            this.client.emit(Constants.Events.WARN, 'Error in pre-ready guild member fetching');
            this.client.emit(Constants.Events.ERROR, e);
            this._emitReady();
          });
          return;
        }
        this._emitReady();
      }
    }
  }

  /**
   * Tries to reconnect the client, changing the status to Constants.Status.RECONNECTING.
   */
  tryReconnect() {
    if (this.status === Constants.Status.RECONNECTING || this.status === Constants.Status.CONNECTING) return;
    this.status = Constants.Status.RECONNECTING;
    this.ws.close();
    this.packetManager.handleQueue();
    /**
     * Emitted when the Client tries to reconnect after being disconnected
     * @event Client#reconnecting
     */
    this.client.emit(Constants.Events.RECONNECTING);
    this.connect(this.client.ws.gateway);
  }
}

module.exports = WebSocketManager;
<commit_msg>Emit the close event on disconnect<commit_after>const browser = typeof window !== 'undefined';
const EventEmitter = require('events').EventEmitter;
const Constants = require('../../util/Constants');
const convertArrayBuffer = require('../../util/ConvertArrayBuffer');
const pako = require('pako');
const zlib = require('zlib');
const PacketManager = require('./packets/WebSocketPacketManager');

let WebSocket, erlpack;
let serialize = JSON.stringify;
if (browser) {
  WebSocket = window.WebSocket; // eslint-disable-line no-undef
} else {
  try {
    WebSocket = require('uws');
  } catch (err) {
    WebSocket = require('ws');
  }

  try {
    erlpack = require('erlpack');
    serialize = erlpack.pack;
  } catch (err) {
    erlpack = null;
  }
}

/**
 * The WebSocket Manager of the Client
 * @private
 */
class WebSocketManager extends EventEmitter {
  constructor(client) {
    super();
    /**
     * The Client that instantiated this WebSocketManager
     * @type {Client}
     */
    this.client = client;

    /**
     * A WebSocket Packet manager, it handles all the messages
     * @type {PacketManager}
     */
    this.packetManager = new PacketManager(this);

    /**
     * The status of the WebSocketManager, a type of Constants.Status. It defaults to IDLE.
     * @type {number}
     */
    this.status = Constants.Status.IDLE;

    /**
     * The session ID of the connection, null if not yet available.
     * @type {?string}
     */
    this.sessionID = null;

    /**
     * The packet count of the client, null if not yet available.
     * @type {?number}
     */
    this.sequence = -1;

    /**
     * The gateway address for this WebSocket connection, null if not yet available.
     * @type {?string}
     */
    this.gateway = null;

    /**
     * Whether READY was emitted normally (all packets received) or not
     * @type {boolean}
     */
    this.normalReady = false;

    /**
     * The WebSocket connection to the gateway
     * @type {?WebSocket}
     */
    this.ws = null;

    /**
     * An object with keys that are websocket event names that should be ignored
     * @type {Object}
     */
    this.disabledEvents = {};
    for (const event of client.options.disabledEvents) this.disabledEvents[event] = true;

    this.first = true;
  }

  /**
   * Connects the client to a given gateway
   * @param {string} gateway The gateway to connect to
   */
  _connect(gateway) {
    this.client.emit('debug', `Connecting to gateway ${gateway}`);
    this.normalReady = false;
    if (this.status !== Constants.Status.RECONNECTING) this.status = Constants.Status.CONNECTING;
    this.ws = new WebSocket(gateway);
    if (browser) this.ws.binaryType = 'arraybuffer';
    this.ws.onopen = this.eventOpen.bind(this);
    this.ws.onmessage = this.eventMessage.bind(this);
    this.ws.onclose = this.eventClose.bind(this);
    this.ws.onerror = this.eventError.bind(this);
    this._queue = [];
    this._remaining = 3;
  }

  connect(gateway) {
    gateway = `${gateway}&encoding=${erlpack ? 'etf' : 'json'}`;
    if (this.first) {
      this._connect(gateway);
      this.first = false;
    } else {
      this.client.setTimeout(() => this._connect(gateway), 5500);
    }
  }

  /**
   * Sends a packet to the gateway
   * @param {Object} data An object that can be JSON stringified
   * @param {boolean} force Whether or not to send the packet immediately
   */
  send(data, force = false) {
    if (force) {
      this._send(serialize(data));
      return;
    }
    this._queue.push(serialize(data));
    this.doQueue();
  }

  destroy() {
    this.ws.close(1000);
    this._queue = [];
    this.status = Constants.Status.IDLE;
  }

  _send(data) {
    if (this.ws.readyState === WebSocket.OPEN) {
      this.emit('send', data);
      this.ws.send(data);
    }
  }

  doQueue() {
    const item = this._queue[0];
    if (this.ws.readyState === WebSocket.OPEN && item) {
      if (this._remaining === 0) {
        this.client.setTimeout(this.doQueue.bind(this), 1000);
        return;
      }
      this._remaining--;
      this._send(item);
      this._queue.shift();
      this.doQueue();
      this.client.setTimeout(() => this._remaining++, 1000);
    }
  }

  /**
   * Run whenever the gateway connections opens up
   */
  eventOpen() {
    this.client.emit('debug', 'Connection to gateway opened');
    if (this.status === Constants.Status.RECONNECTING) this._sendResume();
    else this._sendNewIdentify();
  }

  /**
   * Sends a gateway resume packet, in cases of unexpected disconnections.
   */
  _sendResume() {
    if (!this.sessionID) {
      this._sendNewIdentify();
      return;
    }
    this.client.emit('debug', 'Identifying as resumed session');
    const payload = {
      token: this.client.token,
      session_id: this.sessionID,
      seq: this.sequence,
    };

    this.send({
      op: Constants.OPCodes.RESUME,
      d: payload,
    });
  }

  /**
   * Sends a new identification packet, in cases of new connections or failed reconnections.
   */
  _sendNewIdentify() {
    this.reconnecting = false;
    const payload = this.client.options.ws;
    payload.token = this.client.token;
    if (this.client.options.shardCount > 0) {
      payload.shard = [Number(this.client.options.shardId), Number(this.client.options.shardCount)];
    }
    this.client.emit('debug', 'Identifying as new session');
    this.send({
      op: Constants.OPCodes.IDENTIFY,
      d: payload,
    });
    this.sequence = -1;
  }

  /**
   * Run whenever the connection to the gateway is closed, it will try to reconnect the client.
   * @param {Object} event The received websocket data
   */
  eventClose(event) {
    this.emit('close', event);
    this.client.clearInterval(this.client.manager.heartbeatInterval);
    this.status = Constants.Status.DISCONNECTED;
    /**
     * Emitted whenever the client websocket is disconnected
     * @event Client#disconnect
     * @param {CloseEvent} event The WebSocket close event
     */
    if (!this.reconnecting) this.client.emit(Constants.Events.DISCONNECT, event);
    if (event.code === 4004) return;
    if (event.code === 4010) return;
    if (!this.reconnecting && event.code !== 1000) this.tryReconnect();
  }

  /**
   * Run whenever a message is received from the WebSocket. Returns `true` if the message
   * was handled properly.
   * @param {Object} event The received websocket data
   * @returns {boolean}
   */
  eventMessage(event) {
    const data = this.tryParseEventData(event.data);
    if (data === null) {
      this.eventError(new Error(Constants.Errors.BAD_WS_MESSAGE));
      return false;
    }

    this.client.emit('raw', data);

    if (data.op === Constants.OPCodes.HELLO) this.client.manager.setupKeepAlive(data.d.heartbeat_interval);
    return this.packetManager.handle(data);
  }

  /**
   * Parses the raw data from a websocket event, inflating it if necessary
   * @param {*} data Event data
   * @returns {Object}
   */
  parseEventData(data) {
    if (erlpack) {
      if (data instanceof ArrayBuffer) data = convertArrayBuffer(data);
      return erlpack.unpack(data);
    } else {
      if (data instanceof ArrayBuffer) data = pako.inflate(data, { to: 'string' });
      else if (data instanceof Buffer) data = zlib.inflateSync(data).toString();
      return JSON.parse(data);
    }
  }

  /**
   * Tries to call `parseEventData()` and return its result, or returns `null` upon thrown errors.
   * @param {*} data Event data
   * @returns {?Object}
   */
  tryParseEventData(data) {
    try {
      return this.parseEventData(data);
    } catch (err) {
      return null;
    }
  }

  /**
   * Run whenever an error occurs with the WebSocket connection. Tries to reconnect
   * @param {Error} err The encountered error
   */
  eventError(err) {
    /**
     * Emitted whenever the Client encounters a serious connection error
     * @event Client#error
     * @param {Error} error The encountered error
     */
    if (this.client.listenerCount('error') > 0) this.client.emit('error', err);
    this.tryReconnect();
  }

  _emitReady(normal = true) {
    /**
     * Emitted when the Client becomes ready to start working
     * @event Client#ready
     */
    this.status = Constants.Status.READY;
    this.client.emit(Constants.Events.READY);
    this.packetManager.handleQueue();
    this.normalReady = normal;
  }

  /**
   * Runs on new packets before `READY` to see if the Client is ready yet, if it is prepares
   * the `READY` event.
   */
  checkIfReady() {
    if (this.status !== Constants.Status.READY && this.status !== Constants.Status.NEARLY) {
      let unavailableCount = 0;
      for (const guildID of this.client.guilds.keys()) {
        unavailableCount += this.client.guilds.get(guildID).available ? 0 : 1;
      }
      if (unavailableCount === 0) {
        this.status = Constants.Status.NEARLY;
        if (this.client.options.fetchAllMembers) {
          const promises = this.client.guilds.map(g => g.fetchMembers());
          Promise.all(promises).then(() => this._emitReady(), e => {
            this.client.emit(Constants.Events.WARN, 'Error in pre-ready guild member fetching');
            this.client.emit(Constants.Events.ERROR, e);
            this._emitReady();
          });
          return;
        }
        this._emitReady();
      }
    }
  }

  /**
   * Tries to reconnect the client, changing the status to Constants.Status.RECONNECTING.
   */
  tryReconnect() {
    if (this.status === Constants.Status.RECONNECTING || this.status === Constants.Status.CONNECTING) return;
    this.status = Constants.Status.RECONNECTING;
    this.ws.close();
    this.packetManager.handleQueue();
    /**
     * Emitted when the Client tries to reconnect after being disconnected
     * @event Client#reconnecting
     */
    this.client.emit(Constants.Events.RECONNECTING);
    this.connect(this.client.ws.gateway);
  }
}

module.exports = WebSocketManager;
<|endoftext|>


<commit_before>/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// All inputs/outputs are arraybuffers!
window.textsecure.subtle = (function() {
	var StaticArrayBufferProto = new ArrayBuffer().__proto__;
	function assertIsArrayBuffer(thing) {
		if (thing !== Object(thing) || thing.__proto__ != StaticArrayBufferProto)
			throw new Error("Needed a ArrayBuffer");
	}

	// private implementation functions
	function HmacSHA256(key, input) {
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(input);
		return CryptoJS.HmacSHA256(
				CryptoJS.lib.WordArray.create(input),
				CryptoJS.enc.Latin1.parse(getString(key))
			).toString(CryptoJS.enc.Latin1);
	};

	function encryptAESCTR(plaintext, key, counter) {
		assertIsArrayBuffer(plaintext);
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(counter);
			return CryptoJS.AES.encrypt(CryptoJS.enc.Latin1.parse(getString(plaintext)),
					CryptoJS.enc.Latin1.parse(getString(key)),
					{mode: CryptoJS.mode.CTR, iv: CryptoJS.enc.Latin1.parse(getString(counter)),
						padding: CryptoJS.pad.NoPadding})
				.ciphertext.toString(CryptoJS.enc.Latin1);
	};

	function decryptAESCTR(ciphertext, key, counter) {
		assertIsArrayBuffer(ciphertext);
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(counter);
			return CryptoJS.AES.decrypt(btoa(getString(ciphertext)),
					CryptoJS.enc.Latin1.parse(getString(key)),
					{mode: CryptoJS.mode.CTR, iv: CryptoJS.enc.Latin1.parse(getString(counter)),
						padding: CryptoJS.pad.NoPadding})
				.toString(CryptoJS.enc.Latin1);
	};

	function encryptAESCBC(plaintext, key, iv) {
		assertIsArrayBuffer(plaintext);
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(iv);
		return CryptoJS.AES.encrypt(CryptoJS.enc.Latin1.parse(getString(plaintext)),
				CryptoJS.enc.Latin1.parse(getString(key)),
				{iv: CryptoJS.enc.Latin1.parse(getString(iv))})
			.ciphertext.toString(CryptoJS.enc.Latin1);
	};
	function decryptAESCBC(ciphertext, key, iv) {
		assertIsArrayBuffer(ciphertext);
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(iv);
		return CryptoJS.AES.decrypt(btoa(getString(ciphertext)),
				CryptoJS.enc.Latin1.parse(getString(key)),
				{iv: CryptoJS.enc.Latin1.parse(getString(iv))})
			.toString(CryptoJS.enc.Latin1);
	};

	// utility function for connecting front and back ends via promises
	// Takes an implementation function and 0 or more arguments
	function promise(implementation) {
		var args = Array.prototype.slice.call(arguments);
		args.shift();
		return Promise.resolve(toArrayBuffer(implementation.apply(this, args)));
	}

	// public interface functions
	function encrypt(algorithm, key, data) {
		if (algorithm.name === "AES-CTR")
			return promise(encryptAESCTR, data, key, algorithm.counter);
		if (algorithm.name === "AES-CBC")
			return promise(encryptAESCBC, data, key, algorithm.iv);
	};
	function decrypt(algorithm, key, data) {
		if (algorithm.name === "AES-CTR")
			return promise(decryptAESCTR, data, key, algorithm.counter);
		if (algorithm.name === "AES-CBC")
			return promise(decryptAESCBC, data, key, algorithm.iv);
	};
	function sign(algorithm, key, data) {
		if (algorithm.name === "HMAC" && algorithm.hash === "SHA-256")
			return promise(HmacSHA256, key, data);
	};

	return {
		encrypt	 : encrypt,
		decrypt	 : decrypt,
		sign     : sign,
	}
})();
<commit_msg>Fix borked spacing in webcrypto.js<commit_after>/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// All inputs/outputs are arraybuffers!
window.textsecure.subtle = (function() {
	var StaticArrayBufferProto = new ArrayBuffer().__proto__;
	function assertIsArrayBuffer(thing) {
		if (thing !== Object(thing) || thing.__proto__ != StaticArrayBufferProto)
			throw new Error("Needed a ArrayBuffer");
	}

	// private implementation functions
	function HmacSHA256(key, input) {
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(input);
		return CryptoJS.HmacSHA256(
				CryptoJS.lib.WordArray.create(input),
				CryptoJS.enc.Latin1.parse(getString(key))
			).toString(CryptoJS.enc.Latin1);
	};

	function encryptAESCTR(plaintext, key, counter) {
		assertIsArrayBuffer(plaintext);
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(counter);
		return CryptoJS.AES.encrypt(CryptoJS.enc.Latin1.parse(getString(plaintext)),
				CryptoJS.enc.Latin1.parse(getString(key)),
				{mode: CryptoJS.mode.CTR, iv: CryptoJS.enc.Latin1.parse(getString(counter)),
					padding: CryptoJS.pad.NoPadding})
			.ciphertext.toString(CryptoJS.enc.Latin1);
	};

	function decryptAESCTR(ciphertext, key, counter) {
		assertIsArrayBuffer(ciphertext);
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(counter);
		return CryptoJS.AES.decrypt(btoa(getString(ciphertext)),
				CryptoJS.enc.Latin1.parse(getString(key)),
				{mode: CryptoJS.mode.CTR, iv: CryptoJS.enc.Latin1.parse(getString(counter)),
					padding: CryptoJS.pad.NoPadding})
			.toString(CryptoJS.enc.Latin1);
	};

	function encryptAESCBC(plaintext, key, iv) {
		assertIsArrayBuffer(plaintext);
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(iv);
		return CryptoJS.AES.encrypt(CryptoJS.enc.Latin1.parse(getString(plaintext)),
				CryptoJS.enc.Latin1.parse(getString(key)),
				{iv: CryptoJS.enc.Latin1.parse(getString(iv))})
			.ciphertext.toString(CryptoJS.enc.Latin1);
	};

	function decryptAESCBC(ciphertext, key, iv) {
		assertIsArrayBuffer(ciphertext);
		assertIsArrayBuffer(key);
		assertIsArrayBuffer(iv);
		return CryptoJS.AES.decrypt(btoa(getString(ciphertext)),
				CryptoJS.enc.Latin1.parse(getString(key)),
				{iv: CryptoJS.enc.Latin1.parse(getString(iv))})
			.toString(CryptoJS.enc.Latin1);
	};

	// utility function for connecting front and back ends via promises
	// Takes an implementation function and 0 or more arguments
	function promise(implementation) {
		var args = Array.prototype.slice.call(arguments);
		args.shift();
		return Promise.resolve(toArrayBuffer(implementation.apply(this, args)));
	}

	// public interface functions
	function encrypt(algorithm, key, data) {
		if (algorithm.name === "AES-CTR")
			return promise(encryptAESCTR, data, key, algorithm.counter);
		if (algorithm.name === "AES-CBC")
			return promise(encryptAESCBC, data, key, algorithm.iv);
	};
	function decrypt(algorithm, key, data) {
		if (algorithm.name === "AES-CTR")
			return promise(decryptAESCTR, data, key, algorithm.counter);
		if (algorithm.name === "AES-CBC")
			return promise(decryptAESCBC, data, key, algorithm.iv);
	};
	function sign(algorithm, key, data) {
		if (algorithm.name === "HMAC" && algorithm.hash === "SHA-256")
			return promise(HmacSHA256, key, data);
	};

	return {
		encrypt	 : encrypt,
		decrypt	 : decrypt,
		sign     : sign,
	}
})();
<|endoftext|>


<commit_before>var is = require('type-is')
var Busboy = require('busboy')
var extend = require('xtend')
var appendField = require('append-field')

var Counter = require('./counter')
var makeError = require('./make-error')
var FileAppender = require('./file-appender')
var removeUploadedFiles = require('./remove-uploaded-files')

function makeMiddleware (setup) {
  return function multerMiddleware (req, res, next) {
    if (!is(req, ['multipart'])) return next()

    var options = setup()

    var limits = options.limits
    var storage = options.storage
    var fileFilter = options.fileFilter
    var fileStrategy = options.fileStrategy

    req.body = Object.create(null)

    var busboy = new Busboy({ headers: req.headers, limits: limits })
    var appender = new FileAppender(fileStrategy, req)
    var isDone = false
    var readFinished = false
    var pendingWrites = new Counter()
    var uploadedFiles = []

    function done (err) {
      if (isDone) return
      isDone = true
      req.unpipe(busboy)
      busboy.removeAllListeners()
      next(err)
    }

    function indicateDone () {
      if (readFinished && pendingWrites.isZero()) done()
    }

    function abortWithError (uploadError) {
      pendingWrites.onceZero(function () {
        function remove (file, cb) {
          storage._removeFile(req, file, cb)
        }

        removeUploadedFiles(uploadedFiles, remove, function (err, storageErrors) {
          if (err) return done(err)

          uploadError.storageErrors = storageErrors
          done(uploadError)
        })
      })
    }

    function abortWithCode (code, optionalField) {
      abortWithError(makeError(code, optionalField))
    }

    // handle text field data
    busboy.on('field', function (fieldname, value, fieldnameTruncated, valueTruncated) {
      if (fieldnameTruncated) return abortWithCode('LIMIT_FIELD_KEY')
      if (valueTruncated) return abortWithCode('LIMIT_FIELD_VALUE', fieldname)

      // Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
      if (limits && limits.hasOwnProperty('fieldNameSize')) {
        if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY')
      }

      appendField(req.body, fieldname, value)
    })

    // handle files
    busboy.on('file', function (fieldname, fileStream, filename, encoding, mimetype) {
      // don't attach to the files object, if there is no file
      if (!filename) return fileStream.resume()

      // Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
      if (limits && limits.hasOwnProperty('fieldNameSize')) {
        if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY')
      }

      var file = {
        fieldname: fieldname,
        originalname: filename,
        encoding: encoding,
        mimetype: mimetype
      }

      var placeholder = appender.insertPlaceholder(file)

      fileFilter(req, file, function (err, includeFile) {
        if (err) {
          appender.removePlaceholder(placeholder)
          return abortWithError(err)
        }

        if (!includeFile) {
          appender.removePlaceholder(placeholder)
          return fileStream.resume()
        }

        var aborting = false
        pendingWrites.increment()

        Object.defineProperty(file, 'stream', {
          configurable: true,
          enumerable: false,
          value: fileStream
        })

        fileStream.on('error', function (err) {
          pendingWrites.decrement()
          abortWithError(err)
        })

        fileStream.on('limit', function () {
          aborting = true
          abortWithCode('LIMIT_FILE_SIZE', fieldname)
        })

        storage._handleFile(req, file, function (err, info) {
          if (aborting) {
            appender.removePlaceholder(placeholder)
            uploadedFiles.push(extend(file, info))
            return pendingWrites.decrement()
          }

          if (err) {
            appender.removePlaceholder(placeholder)
            pendingWrites.decrement()
            return abortWithError(err)
          }

          var fileInfo = extend(file, info)

          appender.replacePlaceholder(placeholder, fileInfo)
          uploadedFiles.push(fileInfo)
          pendingWrites.decrement()
          indicateDone()
        })

      })

    })

    busboy.on('partsLimit', function () { abortWithCode('LIMIT_PART_COUNT') })
    busboy.on('filesLimit', function () { abortWithCode('LIMIT_FILE_COUNT') })
    busboy.on('fieldsLimit', function () { abortWithCode('LIMIT_FIELD_COUNT') })
    busboy.on('finish', function () {
      readFinished = true
      indicateDone()
    })

    req.pipe(busboy)
  }
}

module.exports = makeMiddleware
<commit_msg>Catch busboy errors.<commit_after>var is = require('type-is')
var Busboy = require('busboy')
var extend = require('xtend')
var appendField = require('append-field')

var Counter = require('./counter')
var makeError = require('./make-error')
var FileAppender = require('./file-appender')
var removeUploadedFiles = require('./remove-uploaded-files')

function makeMiddleware (setup) {
  return function multerMiddleware (req, res, next) {
    if (!is(req, ['multipart'])) return next()

    var options = setup()

    var limits = options.limits
    var storage = options.storage
    var fileFilter = options.fileFilter
    var fileStrategy = options.fileStrategy

    req.body = Object.create(null)

    var busboy = new Busboy({ headers: req.headers, limits: limits })
    var appender = new FileAppender(fileStrategy, req)
    var isDone = false
    var readFinished = false
    var pendingWrites = new Counter()
    var uploadedFiles = []

    function done (err) {
      if (isDone) return
      isDone = true
      req.unpipe(busboy)
      busboy.removeAllListeners()
      next(err)
    }

    function indicateDone () {
      if (readFinished && pendingWrites.isZero()) done()
    }

    function abortWithError (uploadError) {
      pendingWrites.onceZero(function () {
        function remove (file, cb) {
          storage._removeFile(req, file, cb)
        }

        removeUploadedFiles(uploadedFiles, remove, function (err, storageErrors) {
          if (err) return done(err)

          uploadError.storageErrors = storageErrors
          done(uploadError)
        })
      })
    }

    function abortWithCode (code, optionalField) {
      abortWithError(makeError(code, optionalField))
    }

    // handle text field data
    busboy.on('field', function (fieldname, value, fieldnameTruncated, valueTruncated) {
      if (fieldnameTruncated) return abortWithCode('LIMIT_FIELD_KEY')
      if (valueTruncated) return abortWithCode('LIMIT_FIELD_VALUE', fieldname)

      // Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
      if (limits && limits.hasOwnProperty('fieldNameSize')) {
        if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY')
      }

      appendField(req.body, fieldname, value)
    })

    // handle files
    busboy.on('file', function (fieldname, fileStream, filename, encoding, mimetype) {
      // don't attach to the files object, if there is no file
      if (!filename) return fileStream.resume()

      // Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
      if (limits && limits.hasOwnProperty('fieldNameSize')) {
        if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY')
      }

      var file = {
        fieldname: fieldname,
        originalname: filename,
        encoding: encoding,
        mimetype: mimetype
      }

      var placeholder = appender.insertPlaceholder(file)

      fileFilter(req, file, function (err, includeFile) {
        if (err) {
          appender.removePlaceholder(placeholder)
          return abortWithError(err)
        }

        if (!includeFile) {
          appender.removePlaceholder(placeholder)
          return fileStream.resume()
        }

        var aborting = false
        pendingWrites.increment()

        Object.defineProperty(file, 'stream', {
          configurable: true,
          enumerable: false,
          value: fileStream
        })

        fileStream.on('error', function (err) {
          pendingWrites.decrement()
          abortWithError(err)
        })

        fileStream.on('limit', function () {
          aborting = true
          abortWithCode('LIMIT_FILE_SIZE', fieldname)
        })

        storage._handleFile(req, file, function (err, info) {
          if (aborting) {
            appender.removePlaceholder(placeholder)
            uploadedFiles.push(extend(file, info))
            return pendingWrites.decrement()
          }

          if (err) {
            appender.removePlaceholder(placeholder)
            pendingWrites.decrement()
            return abortWithError(err)
          }

          var fileInfo = extend(file, info)

          appender.replacePlaceholder(placeholder, fileInfo)
          uploadedFiles.push(fileInfo)
          pendingWrites.decrement()
          indicateDone()
        })

      })

    })

    busboy.on('partsLimit', function () { abortWithCode('LIMIT_PART_COUNT') })
    busboy.on('filesLimit', function () { abortWithCode('LIMIT_FILE_COUNT') })
    busboy.on('fieldsLimit', function () { abortWithCode('LIMIT_FIELD_COUNT') })
    busboy.on('finish', function () {
      readFinished = true
      indicateDone()
    })
    busboy.on('error', function (err) { abortWithError(err) })

    req.pipe(busboy)
  }
}

module.exports = makeMiddleware
<|endoftext|>