<commit_before>const browser = require('os').platform() === 'browser';
const EventEmitter = require('events');
const Constants = require('../../util/Constants');
const zlib = require('zlib');
const PacketManager = require('./packets/WebSocketPacketManager');
const erlpack = (function findErlpack() {
  try {
    const e = require('erlpack');
    if (!e.pack) return null;
    return e;
  } catch (e) {
    return null;
  }
}());

const WebSocket = (function findWebSocket() {
  if (browser) return window.WebSocket; // eslint-disable-line no-undef
  try {
    return require('uws');
  } catch (e) {
    return require('ws');
  }
}());

/**
 * Abstracts a WebSocket connection with decoding/encoding for the Discord gateway.
 * @private
 */
class WebSocketConnection extends EventEmitter {
  /**
   * @param {WebSocketManager} manager The WebSocket manager
   * @param {string} gateway WebSocket gateway to connect to
   */
  constructor(manager, gateway) {
    super();
    /**
     * WebSocket Manager of this connection
     * @type {WebSocketManager}
     */
    this.manager = manager;

    /**
     * The client this belongs to
     * @type {Client}
     */
    this.client = manager.client;

    /**
     * The WebSocket connection itself
     * @type {WebSocket}
     */
    this.ws = null;

    /**
     * The current sequence of the WebSocket
     * @type {number}
     */
    this.sequence = -1;

    /**
     * The current status of the client
     * @type {number}
     */
    this.status = Constants.Status.IDLE;

    /**
     * The Packet Manager of the connection
     * @type {WebSocketPacketManager}
     */
    this.packetManager = new PacketManager(this);

    /**
     * The last time a ping was sent (a timestamp)
     * @type {number}
     */
    this.lastPingTimestamp = 0;

    /**
     * Contains the rate limit queue and metadata
     * @type {Object}
     */
    this.ratelimit = {
      queue: [],
      remaining: 120,
      resetTime: -1,
    };
    this.connect(gateway);

    /**
     * Events that are disabled (will not be processed)
     * @type {Object}
     */
    this.disabledEvents = {};

    /**
     * The sequence on WebSocket close
     * @type {number}
     */
    this.closeSequence = 0;
    for (const event of this.client.options.disabledEvents) this.disabledEvents[event] = true;
  }

  /**
   * Causes the client to be marked as ready and emits the ready event.
   * @returns {void}
   */
  triggerReady() {
    if (this.status === Constants.Status.READY) {
      this.debug('Tried to mark self as ready, but already ready');
      return;
    }
    this.status = Constants.Status.READY;
    this.client.emit(Constants.Events.READY);
    this.packetManager.handleQueue();
  }

  /**
   * Checks whether the client is ready to be marked as ready.
   * @returns {void}
   */
  checkIfReady() {
    if (this.status === Constants.Status.READY || this.status === Constants.Status.NEARLY) return false;
    let unavailableGuilds = 0;
    for (const guild of this.client.guilds.values()) {
      if (!guild.available) unavailableGuilds++;
    }
    if (unavailableGuilds === 0) {
      this.status = Constants.Status.NEARLY;
      if (!this.client.options.fetchAllMembers) return this.triggerReady();
      // Fetch all members before marking self as ready
      const promises = this.client.guilds.map(g => g.fetchMembers());
      Promise.all(promises)
        .then(() => this.triggerReady())
        .catch(e => {
          this.debug(`Failed to fetch all members before ready! ${e}`);
          this.triggerReady();
        });
    }
    return true;
  }

  // Util
  /**
   * Emits a debug message.
   * @param {string} message Debug message
   * @returns {void}
   */
  debug(message) {
    if (message instanceof Error) message = message.stack;
    return this.manager.debug(`[connection] ${message}`);
  }

  /**
   * Attempts to serialise data from the WebSocket.
   * @param {string|Object} data Data to unpack
   * @returns {Object}
   */
  unpack(data) {
    if (data instanceof ArrayBuffer) data = Buffer.from(new Uint8Array(data));

    if (erlpack && typeof data !== 'string') return erlpack.unpack(data);
    else if (data instanceof Buffer) data = zlib.inflateSync(data).toString();

    return JSON.parse(data);
  }

  /**
   * Packs an object ready to be sent.
   * @param {Object} data Data to pack
   * @returns {string|Buffer}
   */
  pack(data) {
    return erlpack ? erlpack.pack(data) : JSON.stringify(data);
  }

  /**
   * Processes the current WebSocket queue.
   */
  processQueue() {
    if (this.ratelimit.remaining === 0) return;
    if (this.ratelimit.queue.length === 0) return;
    if (this.ratelimit.remaining === 120) {
      this.ratelimit.resetTimer = setTimeout(() => {
        this.ratelimit.remaining = 120;
        this.processQueue();
      }, 120e3); // eslint-disable-line
    }
    while (this.ratelimit.remaining > 0) {
      const item = this.ratelimit.queue.shift();
      if (!item) return;
      this._send(item);
      this.ratelimit.remaining--;
    }
  }

  /**
   * Sends data, bypassing the queue.
   * @param {Object} data Packet to send
   * @returns {void}
   */
  _send(data) {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      this.debug(`Tried to send packet ${data} but no WebSocket is available!`);
      return;
    }
    this.ws.send(this.pack(data));
  }

  /**
   * Adds data to the queue to be sent.
   * @param {Object} data Packet to send
   * @returns {void}
   */
  send(data) {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      this.debug(`Tried to send packet ${data} but no WebSocket is available!`);
      return;
    }
    this.ratelimit.queue.push(data);
    this.processQueue();
  }

  /**
   * Creates a connection to a gateway.
   * @param {string} gateway Gateway to connect to
   * @param {number} [after=0] How long to wait before connecting
   * @param {boolean} [force=false] Whether or not to force a new connection even if one already exists
   * @returns {boolean}
   */
  connect(gateway = this.gateway, after = 0, force = false) {
    if (after) return this.client.setTimeout(() => this.connect(gateway, 0, force), after); // eslint-disable-line
    if (this.ws && !force) {
      this.debug('WebSocket connection already exists');
      return false;
    } else if (typeof gateway !== 'string') {
      this.debug(`Tried to connect to an invalid gateway: ${gateway}`);
      return false;
    }
    this.gateway = gateway;
    this.debug(`Connecting to ${gateway}`);
    const ws = this.ws = new WebSocket(gateway);
    if (browser) ws.binaryType = 'arraybuffer';
    ws.onmessage = this.onMessage.bind(this);
    ws.onopen = this.onOpen.bind(this);
    ws.onerror = this.onError.bind(this);
    ws.onclose = this.onClose.bind(this);
    this.status = Constants.Status.CONNECTING;
    return true;
  }

  /**
   * Destroys the connection.
   * @returns {boolean}
   */
  destroy() {
    const ws = this.ws;
    if (!ws) {
      this.debug('Attempted to destroy WebSocket but no connection exists!');
      return false;
    }
    this.heartbeat(-1);
    ws.close(1000);
    this.packetManager.handleQueue();
    this.ws = null;
    this.status = Constants.Status.DISCONNECTED;
    return true;
  }

  /**
   * Called whenever a message is received.
   * @param {Event} event Event received
   * @returns {boolean}
   */
  onMessage(event) {
    try {
      this.onPacket(this.unpack(event.data));
      return true;
    } catch (err) {
      this.debug(err);
      return false;
    }
  }

  /**
   * Sets the current sequence of the connection.
   * @param {number} s New sequence
   */
  setSequence(s) {
    this.sequence = s > this.sequence ? s : this.sequence;
  }

  /**
   * Called whenever a packet is received.
   * @param {Object} packet Received packet
   * @returns {boolean}
   */
  onPacket(packet) {
    if (!packet) {
      this.debug('Received null packet');
      return false;
    }
    this.client.emit('raw', packet);
    switch (packet.op) {
      case Constants.OPCodes.HELLO:
        return this.heartbeat(packet.d.heartbeat_interval);
      case Constants.OPCodes.RECONNECT:
        return this.reconnect();
      case Constants.OPCodes.INVALID_SESSION:
        if (!packet.d) this.sessionID = null;
        this.sequence = -1;
        this.debug('Session invalidated -- will identify with a new session');
        return this.identify(packet.d ? 2500 : 0);
      case Constants.OPCodes.HEARTBEAT_ACK:
        return this.ackHeartbeat();
      case Constants.OPCodes.HEARTBEAT:
        return this.heartbeat();
      default:
        return this.packetManager.handle(packet);
    }
  }

  /**
   * Called whenever a connection is opened to the gateway.
   * @param {Event} event Received open event
   */
  onOpen(event) {
    if (event && event.target && event.target.url) this.gateway = event.target.url;
    this.debug(`Connected to gateway ${this.gateway}`);
    this.identify();
  }

  /**
   * Causes a reconnection to the gateway.
   */
  reconnect() {
    this.debug('Attemping to reconnect in 5500ms...');
    this.client.emit(Constants.Events.RECONNECTING);
    this.connect(this.gateway, 5500, true);
  }

  /**
   * Called whenever an error occurs with the WebSocket.
   * @param {Error} error Error that occurred
   */
  onError(error) {
    this.client.emit(Constants.Events.ERROR, error);
    if (error.message === 'uWs client connection error') this.reconnect();
  }

  /**
   * @external CloseEvent
   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
   */

  /**
   * Called whenever a connection to the gateway is closed.
   * @param {CloseEvent} event Close event that was received
   */
  onClose(event) {
    this.debug(`Closed: ${event.code}`);
    this.closeSequence = this.sequence;
    // Reset the state before trying to fix anything
    this.emit('close', event);
    this.heartbeat(-1);
    // Should we reconnect?
    if (Constants.WSCodes[event.code]) {
      this.debug(Constants.WSCodes[event.code]);
      this.destroy();
      return;
    }
    this.reconnect();
  }

  // Heartbeat
  /**
   * Acknowledges a heartbeat.
   */
  ackHeartbeat() {
    this.debug(`Heartbeat acknowledged, latency of ${Date.now() - this.lastPingTimestamp}ms`);
    this.client._pong(this.lastPingTimestamp);
  }

  /**
   * Sends a heartbeat or sets an interval for sending heartbeats.
   * @param {number} [time] If -1, clears the interval, any other number sets an interval
   * If no value is given, a heartbeat will be sent instantly
   */
  heartbeat(time) {
    if (!isNaN(time)) {
      if (time === -1) {
        this.debug('Clearing heartbeat interval');
        this.client.clearInterval(this.heartbeatInterval);
        this.heartbeatInterval = null;
      } else {
        this.debug(`Setting a heartbeat interval for ${time}ms`);
        this.heartbeatInterval = this.client.setInterval(() => this.heartbeat(), time);
      }
      return;
    }
    this.debug('Sending a heartbeat');
    this.lastPingTimestamp = Date.now();
    this.send({
      op: Constants.OPCodes.HEARTBEAT,
      d: this.sequence,
    });
  }

  // Identification
  /**
   * Identifies the client on a connection.
   * @param {number} [after] How long to wait before identifying
   * @returns {void}
   */
  identify(after) {
    if (after) return this.client.setTimeout(this.identify.apply(this), after);
    return this.sessionID ? this.identifyResume() : this.identifyNew();
  }

  /**
   * Identifies as a new connection on the gateway.
   * @returns {void}
   */
  identifyNew() {
    if (!this.client.token) {
      this.debug('No token available to identify a new session with');
      return;
    }
    // Clone the generic payload and assign the token
    const d = Object.assign({ token: this.client.token }, this.client.options.ws);

    // Sharding stuff
    const { shardId, shardCount } = this.client.options;
    if (shardCount > 0) d.shard = [Number(shardId), Number(shardCount)];

    // Send the payload
    this.debug('Identifying as a new session');
    this.send({ op: Constants.OPCodes.IDENTIFY, d });
  }

  /**
   * Resumes a session on the gateway.
   * @returns {void}
   */
  identifyResume() {
    if (!this.sessionID) {
      this.debug('Warning: wanted to resume but session ID not available; identifying as a new session instead');
      return this.identifyNew();
    }
    this.debug(`Attempting to resume session ${this.sessionID}`);

    const d = {
      token: this.client.token,
      session_id: this.sessionID,
      seq: this.sequence,
    };

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

/**
 * Encoding the WebSocket connections will use.
 * @type {string}
 */
WebSocketConnection.ENCODING = erlpack ? 'etf' : 'json';
WebSocketConnection.WebSocket = WebSocket;

module.exports = WebSocketConnection;
<commit_msg>Readding Client#disconnect and docs for Client#reconnecting (#1437)<commit_after>const browser = require('os').platform() === 'browser';
const EventEmitter = require('events');
const Constants = require('../../util/Constants');
const zlib = require('zlib');
const PacketManager = require('./packets/WebSocketPacketManager');
const erlpack = (function findErlpack() {
  try {
    const e = require('erlpack');
    if (!e.pack) return null;
    return e;
  } catch (e) {
    return null;
  }
}());

const WebSocket = (function findWebSocket() {
  if (browser) return window.WebSocket; // eslint-disable-line no-undef
  try {
    return require('uws');
  } catch (e) {
    return require('ws');
  }
}());

/**
 * Abstracts a WebSocket connection with decoding/encoding for the Discord gateway.
 * @private
 */
class WebSocketConnection extends EventEmitter {
  /**
   * @param {WebSocketManager} manager The WebSocket manager
   * @param {string} gateway WebSocket gateway to connect to
   */
  constructor(manager, gateway) {
    super();
    /**
     * WebSocket Manager of this connection
     * @type {WebSocketManager}
     */
    this.manager = manager;

    /**
     * The client this belongs to
     * @type {Client}
     */
    this.client = manager.client;

    /**
     * The WebSocket connection itself
     * @type {WebSocket}
     */
    this.ws = null;

    /**
     * The current sequence of the WebSocket
     * @type {number}
     */
    this.sequence = -1;

    /**
     * The current status of the client
     * @type {number}
     */
    this.status = Constants.Status.IDLE;

    /**
     * The Packet Manager of the connection
     * @type {WebSocketPacketManager}
     */
    this.packetManager = new PacketManager(this);

    /**
     * The last time a ping was sent (a timestamp)
     * @type {number}
     */
    this.lastPingTimestamp = 0;

    /**
     * Contains the rate limit queue and metadata
     * @type {Object}
     */
    this.ratelimit = {
      queue: [],
      remaining: 120,
      resetTime: -1,
    };
    this.connect(gateway);

    /**
     * Events that are disabled (will not be processed)
     * @type {Object}
     */
    this.disabledEvents = {};

    /**
     * The sequence on WebSocket close
     * @type {number}
     */
    this.closeSequence = 0;
    for (const event of this.client.options.disabledEvents) this.disabledEvents[event] = true;
  }

  /**
   * Causes the client to be marked as ready and emits the ready event.
   * @returns {void}
   */
  triggerReady() {
    if (this.status === Constants.Status.READY) {
      this.debug('Tried to mark self as ready, but already ready');
      return;
    }
    this.status = Constants.Status.READY;
    this.client.emit(Constants.Events.READY);
    this.packetManager.handleQueue();
  }

  /**
   * Checks whether the client is ready to be marked as ready.
   * @returns {void}
   */
  checkIfReady() {
    if (this.status === Constants.Status.READY || this.status === Constants.Status.NEARLY) return false;
    let unavailableGuilds = 0;
    for (const guild of this.client.guilds.values()) {
      if (!guild.available) unavailableGuilds++;
    }
    if (unavailableGuilds === 0) {
      this.status = Constants.Status.NEARLY;
      if (!this.client.options.fetchAllMembers) return this.triggerReady();
      // Fetch all members before marking self as ready
      const promises = this.client.guilds.map(g => g.fetchMembers());
      Promise.all(promises)
        .then(() => this.triggerReady())
        .catch(e => {
          this.debug(`Failed to fetch all members before ready! ${e}`);
          this.triggerReady();
        });
    }
    return true;
  }

  // Util
  /**
   * Emits a debug message.
   * @param {string} message Debug message
   * @returns {void}
   */
  debug(message) {
    if (message instanceof Error) message = message.stack;
    return this.manager.debug(`[connection] ${message}`);
  }

  /**
   * Attempts to serialise data from the WebSocket.
   * @param {string|Object} data Data to unpack
   * @returns {Object}
   */
  unpack(data) {
    if (data instanceof ArrayBuffer) data = Buffer.from(new Uint8Array(data));

    if (erlpack && typeof data !== 'string') return erlpack.unpack(data);
    else if (data instanceof Buffer) data = zlib.inflateSync(data).toString();

    return JSON.parse(data);
  }

  /**
   * Packs an object ready to be sent.
   * @param {Object} data Data to pack
   * @returns {string|Buffer}
   */
  pack(data) {
    return erlpack ? erlpack.pack(data) : JSON.stringify(data);
  }

  /**
   * Processes the current WebSocket queue.
   */
  processQueue() {
    if (this.ratelimit.remaining === 0) return;
    if (this.ratelimit.queue.length === 0) return;
    if (this.ratelimit.remaining === 120) {
      this.ratelimit.resetTimer = setTimeout(() => {
        this.ratelimit.remaining = 120;
        this.processQueue();
      }, 120e3); // eslint-disable-line
    }
    while (this.ratelimit.remaining > 0) {
      const item = this.ratelimit.queue.shift();
      if (!item) return;
      this._send(item);
      this.ratelimit.remaining--;
    }
  }

  /**
   * Sends data, bypassing the queue.
   * @param {Object} data Packet to send
   * @returns {void}
   */
  _send(data) {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      this.debug(`Tried to send packet ${data} but no WebSocket is available!`);
      return;
    }
    this.ws.send(this.pack(data));
  }

  /**
   * Adds data to the queue to be sent.
   * @param {Object} data Packet to send
   * @returns {void}
   */
  send(data) {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      this.debug(`Tried to send packet ${data} but no WebSocket is available!`);
      return;
    }
    this.ratelimit.queue.push(data);
    this.processQueue();
  }

  /**
   * Creates a connection to a gateway.
   * @param {string} gateway Gateway to connect to
   * @param {number} [after=0] How long to wait before connecting
   * @param {boolean} [force=false] Whether or not to force a new connection even if one already exists
   * @returns {boolean}
   */
  connect(gateway = this.gateway, after = 0, force = false) {
    if (after) return this.client.setTimeout(() => this.connect(gateway, 0, force), after); // eslint-disable-line
    if (this.ws && !force) {
      this.debug('WebSocket connection already exists');
      return false;
    } else if (typeof gateway !== 'string') {
      this.debug(`Tried to connect to an invalid gateway: ${gateway}`);
      return false;
    }
    this.gateway = gateway;
    this.debug(`Connecting to ${gateway}`);
    const ws = this.ws = new WebSocket(gateway);
    if (browser) ws.binaryType = 'arraybuffer';
    ws.onmessage = this.onMessage.bind(this);
    ws.onopen = this.onOpen.bind(this);
    ws.onerror = this.onError.bind(this);
    ws.onclose = this.onClose.bind(this);
    this.status = Constants.Status.CONNECTING;
    return true;
  }

  /**
   * Destroys the connection.
   * @returns {boolean}
   */
  destroy() {
    const ws = this.ws;
    if (!ws) {
      this.debug('Attempted to destroy WebSocket but no connection exists!');
      return false;
    }
    this.heartbeat(-1);
    ws.close(1000);
    this.packetManager.handleQueue();
    this.ws = null;
    this.status = Constants.Status.DISCONNECTED;
    return true;
  }

  /**
   * Called whenever a message is received.
   * @param {Event} event Event received
   * @returns {boolean}
   */
  onMessage(event) {
    try {
      this.onPacket(this.unpack(event.data));
      return true;
    } catch (err) {
      this.debug(err);
      return false;
    }
  }

  /**
   * Sets the current sequence of the connection.
   * @param {number} s New sequence
   */
  setSequence(s) {
    this.sequence = s > this.sequence ? s : this.sequence;
  }

  /**
   * Called whenever a packet is received.
   * @param {Object} packet Received packet
   * @returns {boolean}
   */
  onPacket(packet) {
    if (!packet) {
      this.debug('Received null packet');
      return false;
    }
    this.client.emit('raw', packet);
    switch (packet.op) {
      case Constants.OPCodes.HELLO:
        return this.heartbeat(packet.d.heartbeat_interval);
      case Constants.OPCodes.RECONNECT:
        return this.reconnect();
      case Constants.OPCodes.INVALID_SESSION:
        if (!packet.d) this.sessionID = null;
        this.sequence = -1;
        this.debug('Session invalidated -- will identify with a new session');
        return this.identify(packet.d ? 2500 : 0);
      case Constants.OPCodes.HEARTBEAT_ACK:
        return this.ackHeartbeat();
      case Constants.OPCodes.HEARTBEAT:
        return this.heartbeat();
      default:
        return this.packetManager.handle(packet);
    }
  }

  /**
   * Called whenever a connection is opened to the gateway.
   * @param {Event} event Received open event
   */
  onOpen(event) {
    if (event && event.target && event.target.url) this.gateway = event.target.url;
    this.debug(`Connected to gateway ${this.gateway}`);
    this.identify();
  }

  /**
   * Causes a reconnection to the gateway.
   */
  reconnect() {
    this.debug('Attemping to reconnect in 5500ms...');
    /**
     * Emitted whenever the client tries to reconnect to the WebSocket.
     * @event Client#reconnecting
     */
    this.client.emit(Constants.Events.RECONNECTING);
    this.connect(this.gateway, 5500, true);
  }

  /**
   * Called whenever an error occurs with the WebSocket.
   * @param {Error} error Error that occurred
   */
  onError(error) {
    this.client.emit(Constants.Events.ERROR, error);
    if (error.message === 'uWs client connection error') this.reconnect();
  }

  /**
   * @external CloseEvent
   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
   */

  /**
   * Called whenever a connection to the gateway is closed.
   * @param {CloseEvent} event Close event that was received
   */
  onClose(event) {
    this.debug(`Closed: ${event.code}`);
    this.closeSequence = this.sequence;
    // Reset the state before trying to fix anything
    this.emit('close', event);
    this.heartbeat(-1);
    // Should we reconnect?
    if (Constants.WSCodes[event.code]) {
      /**
       * Emitted when the client's WebSocket disconnects and will no longer attempt to reconnect.
       * @event Client#disconnect
       * @param {CloseEvent} event The WebSocket close event
       */
      this.client.emit(Constants.Events.DISCONNECT, event);
      this.debug(Constants.WSCodes[event.code]);
      this.destroy();
      return;
    }
    this.reconnect();
  }

  // Heartbeat
  /**
   * Acknowledges a heartbeat.
   */
  ackHeartbeat() {
    this.debug(`Heartbeat acknowledged, latency of ${Date.now() - this.lastPingTimestamp}ms`);
    this.client._pong(this.lastPingTimestamp);
  }

  /**
   * Sends a heartbeat or sets an interval for sending heartbeats.
   * @param {number} [time] If -1, clears the interval, any other number sets an interval
   * If no value is given, a heartbeat will be sent instantly
   */
  heartbeat(time) {
    if (!isNaN(time)) {
      if (time === -1) {
        this.debug('Clearing heartbeat interval');
        this.client.clearInterval(this.heartbeatInterval);
        this.heartbeatInterval = null;
      } else {
        this.debug(`Setting a heartbeat interval for ${time}ms`);
        this.heartbeatInterval = this.client.setInterval(() => this.heartbeat(), time);
      }
      return;
    }
    this.debug('Sending a heartbeat');
    this.lastPingTimestamp = Date.now();
    this.send({
      op: Constants.OPCodes.HEARTBEAT,
      d: this.sequence,
    });
  }

  // Identification
  /**
   * Identifies the client on a connection.
   * @param {number} [after] How long to wait before identifying
   * @returns {void}
   */
  identify(after) {
    if (after) return this.client.setTimeout(this.identify.apply(this), after);
    return this.sessionID ? this.identifyResume() : this.identifyNew();
  }

  /**
   * Identifies as a new connection on the gateway.
   * @returns {void}
   */
  identifyNew() {
    if (!this.client.token) {
      this.debug('No token available to identify a new session with');
      return;
    }
    // Clone the generic payload and assign the token
    const d = Object.assign({ token: this.client.token }, this.client.options.ws);

    // Sharding stuff
    const { shardId, shardCount } = this.client.options;
    if (shardCount > 0) d.shard = [Number(shardId), Number(shardCount)];

    // Send the payload
    this.debug('Identifying as a new session');
    this.send({ op: Constants.OPCodes.IDENTIFY, d });
  }

  /**
   * Resumes a session on the gateway.
   * @returns {void}
   */
  identifyResume() {
    if (!this.sessionID) {
      this.debug('Warning: wanted to resume but session ID not available; identifying as a new session instead');
      return this.identifyNew();
    }
    this.debug(`Attempting to resume session ${this.sessionID}`);

    const d = {
      token: this.client.token,
      session_id: this.sessionID,
      seq: this.sequence,
    };

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

/**
 * Encoding the WebSocket connections will use.
 * @type {string}
 */
WebSocketConnection.ENCODING = erlpack ? 'etf' : 'json';
WebSocketConnection.WebSocket = WebSocket;

module.exports = WebSocketConnection;
<|endoftext|>


<commit_before>var CloudCmd, Util, DOM, CloudFunc, $;

(function(CloudCmd, Util, DOM, CloudFunc) {
    'use strict';

    CloudCmd.View = ViewProto;

    function ViewProto(CallBack) {
        var Name        = 'View',
            Loading     = false,
            FocusWas    = false,
            Events      = DOM.Events,
            Info        = DOM.CurrentInfo,
            Key         = CloudCmd.Key,
            Images      = DOM.Images,
            View        = Util.exec.bind(Util),
            Element, TemplateAudio, Overlay,
            Config      = {
                beforeShow      : function(callback) {
                    Images.hide();
                    Key.unsetBind();
                    DOM.show(Overlay);

                    Util.exec(callback);
                },
                beforeClose     : function(callback) {
                    Key.setBind();
                    Util.exec(callback);
                    DOM.hide(Overlay);
                },
                afterShow       : function(callback) {
                    if (!FocusWas) {
                        Element.focus();
                        FocusWas = true;
                    }

                    Util.exec(callback);
                },
                afterClose      : function(callback) {
                    FocusWas = false;

                    Util.exec(callback);
                },
                fitToView       : true,
                loop            : false,
                openEffect      : 'none',
                closeEffect     : 'none',
                autoSize        : false,
                height          : '100%',
                width           : '100%',
                minWidth        : 0,
                minHeight       : 0,
                padding         : 0,
                preload         : 0,
                keys            : null,
                mouseWheel      : false,
                arrows          : false,
                helpers         : {
                    overlay : null,
                    title   : null
                }
            };

        View.show   = show;
        View.hide   = hide;

        function init() {
            var func = CallBack || Util.exec.with(show, null);

            Loading = true;

            Util.exec.series([
                DOM.loadJquery,
                load,
                function(callback) {
                    Loading = false;
                    Util.exec(callback);
                },
                func
            ]);

            Config.parent = Overlay = DOM.load({
                id          : 'js-view',
                name        : 'div',
                className   : 'view-overlay fancybox-overlay fancybox-overlay-fixed'
            });

            Events.addClick(Util.exec.with(onOverLayClick, Overlay), Overlay);
            Events.addKey(listener);
        }

        /**
         * function shows FancyBox
         */
        function show(data, options) {
            var path, element, type,
                config = {};

            if (!Loading) {
                Element         = $('
');

                if (data) {
                    element    = $(Element).append(data);

                    Util.copyObj(config, Config);

                    if (options)
                        Object.keys(options).forEach(function(name) {
                            var func,
                                isConfig        = !!config[name],
                                series          = Util.exec.series,
                                item            = options[name],
                                isFunc          = Util.isFunction(item);

                            if (isFunc && isConfig) {
                                func            = config[name];
                                config[name]    = function() {
                                    series([func, item]);
                                };
                            } else {
                                config[name]    = options[name];
                            }
                        });

                    $.fancybox(element, config);

                } else {
                    Images.showLoad();
                    path    = CloudFunc.FS + Info.path;
                    type    = getType(path);

                    switch(type) {
                    default:
                        Info.getData(function(error, data) {
                                var element = document.createTextNode(data);
                                /* add margin only for view text documents */
                                Element.css('margin', '2%');

                                $.fancybox(Element.append(element), Config);
                            });
                        break;

                    case 'image':
                        config = Util.copyObj({
                                autoSize    : true,
                                type        : 'image'
                            }, Config);

                        $.fancybox.open(path, config);
                        break;

                    case 'media':
                         getMediaElement(path, function(element) {
                            var media       = DOM.getByDataName('js-media', element),
                                onKey       = Util.exec.with(onMediaKey, media);

                            $.fancybox.open(element, {
                                parent      : Overlay,
                                beforeShow  : function() {
                                    Config.beforeShow();
                                    Events.addKey(onKey);
                                },
                                beforeClose : function() {
                                    Config.beforeClose();
                                    Events.rmKey(onKey);
                                },
                                helpers: {
                                    overlay : null,
                                    title   : null
                                }
                            });
                        });
                        break;
                    }
                }
            }
        }

        function hide() {
            $.fancybox.close();
        }

        function isImage(name) {
            var isMatch;

            isMatch = Util.checkExt(name, [
                'jp(e|g|eg)',
                'gif',
                'png',
                'bmp',
                'webp',
                'svg',
                'ico'
            ]);

            return isMatch;
        }

        function isMedia(name) {
            var isMatch;

            isMatch     = isAudio(name) || isVideo(name);

            return isMatch;
        }

        function isAudio(name) {
            var isMatch;

            isMatch     = Util.checkExt(name, ['mp3', 'ogg']);

            return isMatch;
        }

        function isVideo(name) {
            var isMatch;

            isMatch = Util.checkExt(name, ['mp4', 'avi']);

            return isMatch;
        }

        function getType(name) {
            var type;

            if (isImage(name))
                type    = 'image';
            else if (isMedia(name))
                type    = 'media';

            return type;
        }

        function getMediaElement(src, callback) {
            CloudCmd.getTemplate(TemplateAudio, 'view/media', function(template) {
                var rendered, element, type, is,
                    name = Info.name;

                if (!TemplateAudio)
                    TemplateAudio   = template;

                is      = isAudio(name);
                type    =  is ? 'audio' : 'video';

                rendered    = Util.render(TemplateAudio, {
                    src : src,
                    type: type,
                    name: Info.name
                });

                element     = $(rendered)[0];
                Util.exec(callback, element);
            });
        }

        function onMediaKey(media, event) {
            var key = event.keyCode;

            if (key === Key.SPACE) {
                if (media.paused)
                    media.play();
                else
                    media.pause();
            }
        }

        /**
         * function loads css and js of FancyBox
         * @callback   -  executes, when everything loaded
         */
        function load(callback) {
            Util.time(Name + ' load');

            DOM.loadRemote('fancybox', function() {
                DOM.load.css('/css/view.css', callback);

                DOM.load.style({
                    id:'view-css',
                    inner : '#fancybox-loading {'   +
                            'display: none'         +
                        '}'
                    });
            });
        }

        function onOverLayClick(overlay) {
            var isCurrent, isFiles, isFilesPassive,
                files       = Util.slice(Info.files),
                filesPassive= Util.slice(Info.filesPassive),
                position    = CloudCmd.MousePosition,
                element     = document.elementFromPoint(position.x, position.y),
                isOverlay   = element === overlay;

            if (isOverlay) {
                DOM.hide(overlay);
                element     = DOM.getCurrentByPosition(position);

                if (element) {
                    isFiles         = files.indexOf(element) > 0;
                    isFilesPassive  = filesPassive.indexOf(element) > 0;

                    if (isFiles || isFilesPassive) {
                        isCurrent = DOM.isCurrentFile(element);

                        if (!isCurrent)
                            DOM.setCurrentFile(element);
                    }
                }

                View.hide();
            }
        }

        function listener(event) {
            var keyCode = event.keyCode,
                ESC     = Key.ESC;

            if (keyCode === ESC)
                hide();
        }

        init();

        return View;
    }

})(CloudCmd, Util, DOM, CloudFunc);
<commit_msg>refactor(view) indexOf > 0 -> !~indexOf<commit_after>var CloudCmd, Util, DOM, CloudFunc, $;

(function(CloudCmd, Util, DOM, CloudFunc) {
    'use strict';

    CloudCmd.View = ViewProto;

    function ViewProto(CallBack) {
        var Name        = 'View',
            Loading     = false,
            FocusWas    = false,
            Events      = DOM.Events,
            Info        = DOM.CurrentInfo,
            Key         = CloudCmd.Key,
            Images      = DOM.Images,
            View        = Util.exec.bind(Util),
            Element, TemplateAudio, Overlay,
            Config      = {
                beforeShow      : function(callback) {
                    Images.hide();
                    Key.unsetBind();
                    DOM.show(Overlay);

                    Util.exec(callback);
                },
                beforeClose     : function(callback) {
                    Key.setBind();
                    Util.exec(callback);
                    DOM.hide(Overlay);
                },
                afterShow       : function(callback) {
                    if (!FocusWas) {
                        Element.focus();
                        FocusWas = true;
                    }

                    Util.exec(callback);
                },
                afterClose      : function(callback) {
                    FocusWas = false;

                    Util.exec(callback);
                },
                fitToView       : true,
                loop            : false,
                openEffect      : 'none',
                closeEffect     : 'none',
                autoSize        : false,
                height          : '100%',
                width           : '100%',
                minWidth        : 0,
                minHeight       : 0,
                padding         : 0,
                preload         : 0,
                keys            : null,
                mouseWheel      : false,
                arrows          : false,
                helpers         : {
                    overlay : null,
                    title   : null
                }
            };

        View.show   = show;
        View.hide   = hide;

        function init() {
            var func = CallBack || Util.exec.with(show, null);

            Loading = true;

            Util.exec.series([
                DOM.loadJquery,
                load,
                function(callback) {
                    Loading = false;
                    Util.exec(callback);
                },
                func
            ]);

            Config.parent = Overlay = DOM.load({
                id          : 'js-view',
                name        : 'div',
                className   : 'view-overlay fancybox-overlay fancybox-overlay-fixed'
            });

            Events.addClick(Util.exec.with(onOverLayClick, Overlay), Overlay);
            Events.addKey(listener);
        }

        /**
         * function shows FancyBox
         */
        function show(data, options) {
            var path, element, type,
                config = {};

            if (!Loading) {
                Element         = $('
');

                if (data) {
                    element    = $(Element).append(data);

                    Util.copyObj(config, Config);

                    if (options)
                        Object.keys(options).forEach(function(name) {
                            var func,
                                isConfig        = !!config[name],
                                series          = Util.exec.series,
                                item            = options[name],
                                isFunc          = Util.isFunction(item);

                            if (isFunc && isConfig) {
                                func            = config[name];
                                config[name]    = function() {
                                    series([func, item]);
                                };
                            } else {
                                config[name]    = options[name];
                            }
                        });

                    $.fancybox(element, config);

                } else {
                    Images.showLoad();
                    path    = CloudFunc.FS + Info.path;
                    type    = getType(path);

                    switch(type) {
                    default:
                        Info.getData(function(error, data) {
                                var element = document.createTextNode(data);
                                /* add margin only for view text documents */
                                Element.css('margin', '2%');

                                $.fancybox(Element.append(element), Config);
                            });
                        break;

                    case 'image':
                        config = Util.copyObj({
                                autoSize    : true,
                                type        : 'image'
                            }, Config);

                        $.fancybox.open(path, config);
                        break;

                    case 'media':
                         getMediaElement(path, function(element) {
                            var media       = DOM.getByDataName('js-media', element),
                                onKey       = Util.exec.with(onMediaKey, media);

                            $.fancybox.open(element, {
                                parent      : Overlay,
                                beforeShow  : function() {
                                    Config.beforeShow();
                                    Events.addKey(onKey);
                                },
                                beforeClose : function() {
                                    Config.beforeClose();
                                    Events.rmKey(onKey);
                                },
                                helpers: {
                                    overlay : null,
                                    title   : null
                                }
                            });
                        });
                        break;
                    }
                }
            }
        }

        function hide() {
            $.fancybox.close();
        }

        function isImage(name) {
            var isMatch;

            isMatch = Util.checkExt(name, [
                'jp(e|g|eg)',
                'gif',
                'png',
                'bmp',
                'webp',
                'svg',
                'ico'
            ]);

            return isMatch;
        }

        function isMedia(name) {
            var isMatch;

            isMatch     = isAudio(name) || isVideo(name);

            return isMatch;
        }

        function isAudio(name) {
            var isMatch;

            isMatch     = Util.checkExt(name, ['mp3', 'ogg']);

            return isMatch;
        }

        function isVideo(name) {
            var isMatch;

            isMatch = Util.checkExt(name, ['mp4', 'avi']);

            return isMatch;
        }

        function getType(name) {
            var type;

            if (isImage(name))
                type    = 'image';
            else if (isMedia(name))
                type    = 'media';

            return type;
        }

        function getMediaElement(src, callback) {
            CloudCmd.getTemplate(TemplateAudio, 'view/media', function(template) {
                var rendered, element, type, is,
                    name = Info.name;

                if (!TemplateAudio)
                    TemplateAudio   = template;

                is      = isAudio(name);
                type    =  is ? 'audio' : 'video';

                rendered    = Util.render(TemplateAudio, {
                    src : src,
                    type: type,
                    name: Info.name
                });

                element     = $(rendered)[0];
                Util.exec(callback, element);
            });
        }

        function onMediaKey(media, event) {
            var key = event.keyCode;

            if (key === Key.SPACE) {
                if (media.paused)
                    media.play();
                else
                    media.pause();
            }
        }

        /**
         * function loads css and js of FancyBox
         * @callback   -  executes, when everything loaded
         */
        function load(callback) {
            Util.time(Name + ' load');

            DOM.loadRemote('fancybox', function() {
                DOM.load.css('/css/view.css', callback);

                DOM.load.style({
                    id:'view-css',
                    inner : '#fancybox-loading {'   +
                            'display: none'         +
                        '}'
                    });
            });
        }

        function onOverLayClick(overlay) {
            var isCurrent, isFiles, isFilesPassive,
                files       = Util.slice(Info.files),
                filesPassive= Util.slice(Info.filesPassive),
                position    = CloudCmd.MousePosition,
                element     = document.elementFromPoint(position.x, position.y),
                isOverlay   = element === overlay;

            if (isOverlay) {
                DOM.hide(overlay);
                element     = DOM.getCurrentByPosition(position);

                if (element) {
                    isFiles         = !~files.indexOf(element);
                    isFilesPassive  = !~filesPassive.indexOf(element);

                    if (isFiles || isFilesPassive) {
                        isCurrent = DOM.isCurrentFile(element);

                        if (!isCurrent)
                            DOM.setCurrentFile(element);
                    }
                }

                View.hide();
            }
        }

        function listener(event) {
            var keyCode = event.keyCode,
                ESC     = Key.ESC;

            if (keyCode === ESC)
                hide();
        }

        init();

        return View;
    }

})(CloudCmd, Util, DOM, CloudFunc);
<|endoftext|>


<commit_before>/* @flow */

import { Emitter, CompositeDisposable } from 'atom'
import type { Disposable } from 'atom'

import * as Validate from './validate'
import { normalizeMessages } from './helpers'
import type { Indie, Message } from './types'

export default class IndieDelegate {
  indie: Indie
  scope: 'project'
  emitter: Emitter
  version: 2
  messages: Map<?string, Array<Message>>
  subscriptions: CompositeDisposable

  constructor(indie: Indie, version: 2) {
    this.indie = indie
    this.scope = 'project'
    this.version = version
    this.emitter = new Emitter()
    this.messages = new Map()
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.emitter)
  }
  get name(): string {
    return this.indie.name
  }
  getMessages(): Array<Message> {
    return Array.from(this.messages.values()).reduce(function(toReturn, entry) {
      return toReturn.concat(entry)
    }, [])
  }
  clearMessages(): void {
    if (!this.subscriptions.disposed) {
      this.emitter.emit('did-update', [])
      this.messages.clear()
    }
  }
  setMessages(filePath: string | Array<Object>, messages: ?Array<Object> = null): void {
    // v2 Support from here on
    if (typeof filePath !== 'string' || !Array.isArray(messages)) {
      throw new Error('Invalid Parameters to setMessages()')
    }
    if (this.subscriptions.disposed || !Validate.messages(this.name, messages)) {
      return
    }
    messages.forEach(function(message) {
      if (message.location.file !== filePath) {
        console.debug('[Linter-UI-Default] Expected File', filePath, 'Message', message)
        throw new Error('message.location.file does not match the given filePath')
      }
    })

    normalizeMessages(this.name, messages)
    this.messages.set(filePath, messages)
    this.emitter.emit('did-update', this.getMessages())
  }
  setAllMessages(messages: Array<Object>): void {
    if (this.subscriptions.disposed) {
      return
    }

    if (atom.inDevMode() || !Array.isArray(messages)) {
      if (!Validate.messages(this.name, messages)) return
    }
    normalizeMessages(this.name, messages)

    this.messages.clear()
    for (let i = 0, { length } = messages; i < length; ++i) {
      const message: Message = messages[i]
      const filePath = message.location.file
      let fileMessages = this.messages.get(filePath)
      if (!fileMessages) {
        this.messages.set(filePath, (fileMessages = []))
      }
      fileMessages.push(message)
    }
    this.emitter.emit('did-update', this.getMessages())
  }
  onDidUpdate(callback: Function): Disposable {
    return this.emitter.on('did-update', callback)
  }
  onDidDestroy(callback: Function): Disposable {
    return this.emitter.on('did-destroy', callback)
  }
  dispose(): void {
    this.emitter.emit('did-destroy')
    this.subscriptions.dispose()
    this.messages.clear()
  }
}
<commit_msg>faster getMessages<commit_after>/* @flow */

import { Emitter, CompositeDisposable } from 'atom'
import type { Disposable } from 'atom'

import * as Validate from './validate'
import { normalizeMessages, mergeArray } from './helpers'
import type { Indie, Message } from './types'

export default class IndieDelegate {
  indie: Indie
  scope: 'project'
  emitter: Emitter
  version: 2
  messages: Map<?string, Array<Message>>
  subscriptions: CompositeDisposable

  constructor(indie: Indie, version: 2) {
    this.indie = indie
    this.scope = 'project'
    this.version = version
    this.emitter = new Emitter()
    this.messages = new Map()
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.emitter)
  }
  get name(): string {
    return this.indie.name
  }
  getMessages(): Array<Message> {
    const out = []
    this.messages.forEach(m => {
      mergeArray(out, m)
    })
    return out
  }
  clearMessages(): void {
    if (!this.subscriptions.disposed) {
      this.emitter.emit('did-update', [])
      this.messages.clear()
    }
  }
  setMessages(filePath: string | Array<Object>, messages: ?Array<Object> = null): void {
    // v2 Support from here on
    if (typeof filePath !== 'string' || !Array.isArray(messages)) {
      throw new Error('Invalid Parameters to setMessages()')
    }
    if (this.subscriptions.disposed || !Validate.messages(this.name, messages)) {
      return
    }
    messages.forEach(function(message) {
      if (message.location.file !== filePath) {
        console.debug('[Linter-UI-Default] Expected File', filePath, 'Message', message)
        throw new Error('message.location.file does not match the given filePath')
      }
    })

    normalizeMessages(this.name, messages)
    this.messages.set(filePath, messages)
    this.emitter.emit('did-update', this.getMessages())
  }
  setAllMessages(messages: Array<Object>): void {
    if (this.subscriptions.disposed) {
      return
    }

    if (atom.inDevMode() || !Array.isArray(messages)) {
      if (!Validate.messages(this.name, messages)) return
    }
    normalizeMessages(this.name, messages)

    this.messages.clear()
    for (let i = 0, { length } = messages; i < length; ++i) {
      const message: Message = messages[i]
      const filePath = message.location.file
      let fileMessages = this.messages.get(filePath)
      if (!fileMessages) {
        this.messages.set(filePath, (fileMessages = []))
      }
      fileMessages.push(message)
    }
    this.emitter.emit('did-update', this.getMessages())
  }
  onDidUpdate(callback: Function): Disposable {
    return this.emitter.on('did-update', callback)
  }
  onDidDestroy(callback: Function): Disposable {
    return this.emitter.on('did-destroy', callback)
  }
  dispose(): void {
    this.emitter.emit('did-destroy')
    this.subscriptions.dispose()
    this.messages.clear()
  }
}
<|endoftext|>


<commit_before>var CloudCmd, Util, DOM, CloudFunc, $;

(function(CloudCmd, Util, DOM, CloudFunc) {
    'use strict';

    CloudCmd.View = ViewProto;

    function ViewProto(CallBack) {
        var Name    = 'View',
            Loading = false,
            Events  = DOM.Events,
            Info    = DOM.CurrentInfo,
            Key     = CloudCmd.Key,
            Images  = DOM.Images,
            View    = Util.exec.bind(Util),
            Element, TemplateAudio,
            Config      = {
                beforeShow      : function() {
                    Images.hide();
                    Key.unsetBind();
                    addOverLayClick();
                },
                beforeClose     : function() {
                    Key.setBind();
                    console.trace();
                },
                fitToView       : true,
                loop            : false,
                openEffect      : 'none',
                closeEffect     : 'none',
                autoSize        : false,
                height          : '100%',
                width           : '100%',
                minWidth        : 0,
                minHeight       : 0,
                padding         : 0,
                preload         : 0,
                overlay         : {
                    closeClick: false
                }
            };

        View.show   = show;
        View.hide   = hide;
        View.rmKeys = rmKeys;

        function rmKeys() {
            /* remove default key binding
             * which is ruin terminal
             */
            $.fancybox.defaults.keys = null;
        }

        function init() {
            var func = CallBack || Util.bind(show, null);

            Loading = true;

            Util.loadOnLoad([
                DOM.jqueryLoad,
                load,
                func
            ]);

            Events.addKey(listener);
        }

        /**
         * function shows FancyBox
         */
        function show(data, callback, newConfig) {
            var path, element, func, name,
                config = {};

            if (!Loading) {
                Element         = $('
');

                if (data) {
                    element    = $(Element).append(data);
                    func       = Util.retExec(callback);

                    Config.afterShow = func;

                    Util.copyObj(config, Config);

                    for (name in newConfig)
                        config[name] = newConfig[name];

                    $.fancybox(element, config);

                } else {
                    Images.showLoad();
                    path   = CloudFunc.FS + Info.path;

                    if (isImage(path)) {
                        config = Util.copyObj({
                            autoSize    : true
                        }, Config);

                        $.fancybox.open(path, config);
                    } else if (isMusic(path))
                        getMusicElement(path, function(element) {
                            var audio       = element.querySelector('audio'),
                                onKey       = Util.bind(onMusicKey, audio);

                            $.fancybox.open(element, {
                                beforeShow  : function() {
                                    Config.beforeShow();
                                    musicBeforeShow();
                                    Events.addKey(onKey);
                                },
                                beforeClose : function() {
                                    Config.beforeClose();
                                    Events.rmKey(onKey);
                                }
                            });
                        });
                    else
                        Info.getData(function(data) {
                            var element = document.createTextNode(data);
                            /* add margin only for view text documents */
                            Element.css('margin', '2%');

                            $.fancybox(Element.append(element), Config);
                        });
                }
            }
        }

        function hide() {
            $.fancybox.close();
        }

        function isImage(name) {
            var isMatch = $.fancybox.isImage(name);

            return isMatch;
        }

        function isMusic(name) {
            var isMatch,
                isStr       = Util.isString(name),
                exts        = '.mp3|.mp4',
                extsReg     = new RegExp(exts);

            if (isStr)
                isMatch     = name.match(extsReg);

            return isMatch;
        }

        function getMusicElement(src, callback) {
            CloudCmd.getTemplate(TemplateAudio, 'view/audio', function(template) {
                var rendered, element;

                if (!TemplateAudio)
                    TemplateAudio   = template;

                rendered    = Util.render(TemplateAudio, {
                    src: src,
                    name: Info.name
                });

                element     = $(rendered)[0];
                Util.exec(callback, element);
            });
        }

        function onMusicKey(audio, event) {
            var key = event.keyCode;

            if (key === Key.SPACE) {
                if (audio.paused)
                    audio.play();
                else
                    audio.pause();
            }
        }

        function musicBeforeShow() {
            var audioDiv    = $('#js-audio'),
                audio       = audioDiv.find('audio'),
                width       = audio.width() +'px';

            audioDiv.width(width);

            Key.unsetBind();
        }

        /**
         * function loads css and js of FancyBox
         * @callback   -  executes, when everything loaded
         */
        function load(callback) {
            var dir    = CloudCmd.LIBDIRCLIENT + 'view/fancyBox/source/',
                files  = [
                    dir + 'jquery.fancybox.css',
                    dir + 'jquery.fancybox.js'
                ];

            Util.time(Name + ' load');

            DOM.anyLoadOnLoad([files], function() {
                Util.timeEnd(Name + ' load');
                Loading = false;
                Util.exec(callback);
            })
            .cssSet({id:'view-css',
                inner : '#view {'                               +
                            'font-size: 16px;'                  +
                            'white-space :pre;'                 +
                            'outline: 0;'                       +
                        '}'                                     +
                        '#view::selection {'                    +
                            /*
                                'background: #fe57a1;'
                                'color: #fff;'
                            */
                            'background: #b3d4fc;'              +
                            'text-shadow: none;'                +
                        '}'                                     +
                        '#fancybox-loading div {'               +
                            'background: none;'                 +
                            'width: 0;'                         +
                            'height: 0'                         +
                        '}'                                     +
                        '.fancybox-overlay {'                   +
                            'background: rgba(255, 255, 255, 0.1)' +
                        '}'                                     +
                        '.fancybox-lock .fancybox-overlay {'    +
                            'overflow-y: hidden'                +
                        '}'                                     +
                        '.fancybox-wrap {'                      +
                            /* when search element with
                             * document.elementFromPoint
                             */
                            'z-index: 1'                        +
                        '}'
            });

        }

        function addOverLayClick() {
            var NAME            = 'fancybox-overlay',
                overlay         = DOM.getByClass(NAME),
                onOverLayClick  = function() {
                    var isCurrent,
                        position    = CloudCmd.MousePosition,
                        element     = document.elementFromPoint(position.x, position.y),
                        isChild     = element.firstChild,
                        classList   = element.classList,
                        isOverlay   = classList.contains(NAME);

                    if (isOverlay && isChild) {
                        DOM.hide(overlay);
                        element     = DOM.getCurrentByPosition(position);

                        if (element) {
                            isCurrent = DOM.isCurrentFile(element);

                            if (!isCurrent)
                                DOM.setCurrentFile(element);
                        }
                    }
                };

            if (overlay)
                Events.addClick(onOverLayClick, overlay);
        }

        function listener(event) {
            var keyCode = event.keyCode,
                ESC     = Key.ESC;

            if (keyCode === ESC)
                hide();
        }

        init();

        return View;
    }

})(CloudCmd, Util, DOM, CloudFunc);
<commit_msg>fix(view) overlay -> helpers.overlay<commit_after>var CloudCmd, Util, DOM, CloudFunc, $;

(function(CloudCmd, Util, DOM, CloudFunc) {
    'use strict';

    CloudCmd.View = ViewProto;

    function ViewProto(CallBack) {
        var Name    = 'View',
            Loading = false,
            Events  = DOM.Events,
            Info    = DOM.CurrentInfo,
            Key     = CloudCmd.Key,
            Images  = DOM.Images,
            View    = Util.exec.bind(Util),
            Element, TemplateAudio,
            Config      = {
                beforeShow      : function() {
                    Images.hide();
                    Key.unsetBind();
                    addOverLayClick();
                },
                beforeClose     : function() {
                    Key.setBind();
                    console.trace();
                },
                fitToView       : true,
                loop            : false,
                openEffect      : 'none',
                closeEffect     : 'none',
                autoSize        : false,
                height          : '100%',
                width           : '100%',
                minWidth        : 0,
                minHeight       : 0,
                padding         : 0,
                preload         : 0,
                helpers         : {
                    overlay         : {
                        closeClick: false
                    }
                }
            };

        View.show   = show;
        View.hide   = hide;
        View.rmKeys = rmKeys;

        function rmKeys() {
            /* remove default key binding
             * which is ruin terminal
             */
            $.fancybox.defaults.keys = null;
        }

        function init() {
            var func = CallBack || Util.bind(show, null);

            Loading = true;

            Util.loadOnLoad([
                DOM.jqueryLoad,
                load,
                func
            ]);

            Events.addKey(listener);
        }

        /**
         * function shows FancyBox
         */
        function show(data, callback, newConfig) {
            var path, element, func, name,
                config = {};

            if (!Loading) {
                Element         = $('
');

                if (data) {
                    element    = $(Element).append(data);
                    func       = Util.retExec(callback);

                    Config.afterShow = func;

                    Util.copyObj(config, Config);

                    for (name in newConfig)
                        config[name] = newConfig[name];

                    $.fancybox(element, config);

                } else {
                    Images.showLoad();
                    path   = CloudFunc.FS + Info.path;

                    if (isImage(path)) {
                        config = Util.copyObj({
                            autoSize    : true
                        }, Config);

                        $.fancybox.open(path, config);
                    } else if (isMusic(path))
                        getMusicElement(path, function(element) {
                            var audio       = element.querySelector('audio'),
                                onKey       = Util.bind(onMusicKey, audio);

                            $.fancybox.open(element, {
                                beforeShow  : function() {
                                    Config.beforeShow();
                                    musicBeforeShow();
                                    Events.addKey(onKey);
                                },
                                beforeClose : function() {
                                    Config.beforeClose();
                                    Events.rmKey(onKey);
                                }
                            });
                        });
                    else
                        Info.getData(function(data) {
                            var element = document.createTextNode(data);
                            /* add margin only for view text documents */
                            Element.css('margin', '2%');

                            $.fancybox(Element.append(element), Config);
                        });
                }
            }
        }

        function hide() {
            $.fancybox.close();
        }

        function isImage(name) {
            var isMatch = $.fancybox.isImage(name);

            return isMatch;
        }

        function isMusic(name) {
            var isMatch,
                isStr       = Util.isString(name),
                exts        = '.mp3|.mp4',
                extsReg     = new RegExp(exts);

            if (isStr)
                isMatch     = name.match(extsReg);

            return isMatch;
        }

        function getMusicElement(src, callback) {
            CloudCmd.getTemplate(TemplateAudio, 'view/audio', function(template) {
                var rendered, element;

                if (!TemplateAudio)
                    TemplateAudio   = template;

                rendered    = Util.render(TemplateAudio, {
                    src: src,
                    name: Info.name
                });

                element     = $(rendered)[0];
                Util.exec(callback, element);
            });
        }

        function onMusicKey(audio, event) {
            var key = event.keyCode;

            if (key === Key.SPACE) {
                if (audio.paused)
                    audio.play();
                else
                    audio.pause();
            }
        }

        function musicBeforeShow() {
            var audioDiv    = $('#js-audio'),
                audio       = audioDiv.find('audio'),
                width       = audio.width() +'px';

            audioDiv.width(width);

            Key.unsetBind();
        }

        /**
         * function loads css and js of FancyBox
         * @callback   -  executes, when everything loaded
         */
        function load(callback) {
            var dir    = CloudCmd.LIBDIRCLIENT + 'view/fancyBox/source/',
                files  = [
                    dir + 'jquery.fancybox.css',
                    dir + 'jquery.fancybox.js'
                ];

            Util.time(Name + ' load');

            DOM.anyLoadOnLoad([files], function() {
                Util.timeEnd(Name + ' load');
                Loading = false;
                Util.exec(callback);
            })
            .cssSet({id:'view-css',
                inner : '#view {'                               +
                            'font-size: 16px;'                  +
                            'white-space :pre;'                 +
                            'outline: 0;'                       +
                        '}'                                     +
                        '#view::selection {'                    +
                            /*
                                'background: #fe57a1;'
                                'color: #fff;'
                            */
                            'background: #b3d4fc;'              +
                            'text-shadow: none;'                +
                        '}'                                     +
                        '#fancybox-loading div {'               +
                            'background: none;'                 +
                            'width: 0;'                         +
                            'height: 0'                         +
                        '}'                                     +
                        '.fancybox-overlay {'                   +
                            'background: rgba(255, 255, 255, 0.1)' +
                        '}'                                     +
                        '.fancybox-lock .fancybox-overlay {'    +
                            'overflow-y: hidden'                +
                        '}'                                     +
                        '.fancybox-wrap {'                      +
                            /* when search element with
                             * document.elementFromPoint
                             */
                            'z-index: 1'                        +
                        '}'
            });

        }

        function addOverLayClick() {
            var NAME            = 'fancybox-overlay',
                overlay         = DOM.getByClass(NAME),
                onOverLayClick  = function() {
                    var isCurrent,
                        position    = CloudCmd.MousePosition,
                        element     = document.elementFromPoint(position.x, position.y),
                        isChild     = element.firstChild,
                        classList   = element.classList,
                        isOverlay   = classList.contains(NAME);

                    if (isOverlay && isChild) {
                        DOM.hide(overlay);
                        element     = DOM.getCurrentByPosition(position);

                        if (element) {
                            isCurrent = DOM.isCurrentFile(element);

                            if (!isCurrent)
                                DOM.setCurrentFile(element);
                        }
                    }
                };

            if (overlay)
                Events.addClick(onOverLayClick, overlay);
        }

        function listener(event) {
            var keyCode = event.keyCode,
                ESC     = Key.ESC;

            if (keyCode === ESC)
                hide();
        }

        init();

        return View;
    }

})(CloudCmd, Util, DOM, CloudFunc);
<|endoftext|>


<commit_before>var qs = require('querystring');
var iconv = require('iconv-lite');
var util = require('../util');
var extend = require('util')._extend;
var Transform = require('pipestream').Transform;
var WhistleTransform = util.WhistleTransform;
var MAX_REQ_SIZE = 256 * 1024;

/**
 * 处理请求数据
 *
 * @param req：method、body、headers，top，bottom，speed、delay，charset,timeout
 * @param data
 */
function handleReq(req, data) {
	if (data.headers) {
		data.headers = util.lowerCaseify(data.headers);
	}
	req.method = data.method || req.method;
	req.timeout = parseInt(data.timeout, 10);
	extend(req.headers, data.headers);

	if (data.top || data.bottom || data.body) {
		delete req.headers['content-length'];
	}

	!util.isEmptyObject(data) && req.add(new WhistleTransform(data));
}

function readReqRules(rules, callback) {
	var count = 4;
	var result = {};
	function handleCallback() {
		--count <= 0 && callback(result);
	}

	util.parseRuleToJson(rules.reqHeaders, function(headers) {
		if (headers) {
			result.headers = headers;
		}
		handleCallback();
	});

	['reqBody', 'prependReq', 'appendReq'].forEach(function(key) {
		util.getRuleValue(rules[key], function(value) {
			if (value != null) {
				if (key == 'reqBody') {
					result.body = value;
				} else if (key == 'prependReq') {
					result.top = value;
				} else {
					result.bottom = value;
				}
			}
			handleCallback();
		});
	});
}

module.exports = function(req, res, next) {
	var rules = req.rules;
	util.parseRuleToJson(rules.req,
			function(data) {
		if (rules.head && rules.head.req) {
			data = extend(rules.head.req, data);
		}

		util.readInjectFiles(data, function(data) {
			readReqRules(rules, function(result) {
				data = extend(data || {}, result);
				handleReq(req, data);
				util.removeUnsupportsHeaders(req.headers);
				util.parseRuleToJson(req.rules.params, function(params) {
					if (params = params && qs.stringify(params)) {
						if (!req.method || /^GET$/i.test(req.method)) {
							var fullUrl = req.fullUrl;
							req.fullUrl = fullUrl.replace(/\?.*$/, '') + '?'
											+ util.replaceQueryString(util.getQueryString(fullUrl), params);
						} else if (util.isUrlEncoded(req)) {
							var transform = new Transform();
							var buffer, interrupt;
							transform._transform = function(chunk, encoding, callback) {
								if (chunk) {
									if (!interrupt) {
										buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
										if (buffer.length > MAX_REQ_SIZE) {
											interrupt = true;
											chunk = buffer;
											buffer = null;
										}
									}
								} else if (buffer) {
									var body = buffer + '';
									var isGBK = body.indexOf('�') == -1;
									if (isGBK) {
										body = iconv.decode(buffer, 'GB18030');
										body = util.replaceQueryString(body, params);
										chunk = iconv.encode(body, 'GB18030');
									} else {
										chunk = new Buffer(body);
									}
								}

								callback(null, chunk);
							};
							req.add(transform);
						}
					}
					next();
				});
			});
		});
	});
};<commit_msg>content-length<commit_after>var qs = require('querystring');
var iconv = require('iconv-lite');
var util = require('../util');
var extend = require('util')._extend;
var Transform = require('pipestream').Transform;
var WhistleTransform = util.WhistleTransform;
var MAX_REQ_SIZE = 256 * 1024;

/**
 * 处理请求数据
 *
 * @param req：method、body、headers，top，bottom，speed、delay，charset,timeout
 * @param data
 */
function handleReq(req, data) {
	if (data.headers) {
		data.headers = util.lowerCaseify(data.headers);
	}
	req.method = data.method || req.method;
	req.timeout = parseInt(data.timeout, 10);
	extend(req.headers, data.headers);

	if (data.top || data.bottom || data.body) {
		delete req.headers['content-length'];
	}

	!util.isEmptyObject(data) && req.add(new WhistleTransform(data));
}

function readReqRules(rules, callback) {
	var count = 4;
	var result = {};
	function handleCallback() {
		--count <= 0 && callback(result);
	}

	util.parseRuleToJson(rules.reqHeaders, function(headers) {
		if (headers) {
			result.headers = headers;
		}
		handleCallback();
	});

	['reqBody', 'prependReq', 'appendReq'].forEach(function(key) {
		util.getRuleValue(rules[key], function(value) {
			if (value != null) {
				if (key == 'reqBody') {
					result.body = value;
				} else if (key == 'prependReq') {
					result.top = value;
				} else {
					result.bottom = value;
				}
			}
			handleCallback();
		});
	});
}

module.exports = function(req, res, next) {
	var rules = req.rules;
	util.parseRuleToJson(rules.req,
			function(data) {
		if (rules.head && rules.head.req) {
			data = extend(rules.head.req, data);
		}

		util.readInjectFiles(data, function(data) {
			readReqRules(rules, function(result) {
				data = extend(data || {}, result);
				handleReq(req, data);
				util.removeUnsupportsHeaders(req.headers);
				util.parseRuleToJson(req.rules.params, function(params) {
					if (params = params && qs.stringify(params)) {
						if (!req.method || /^GET$/i.test(req.method)) {
							var fullUrl = req.fullUrl;
							req.fullUrl = fullUrl.replace(/\?.*$/, '') + '?'
											+ util.replaceQueryString(util.getQueryString(fullUrl), params);
						} else if (util.isUrlEncoded(req)) {
							delete req.headers['content-length'];
							var transform = new Transform();
							var buffer, interrupt;
							transform._transform = function(chunk, encoding, callback) {
								if (chunk) {
									if (!interrupt) {
										buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
										chunk = null;
										if (buffer.length > MAX_REQ_SIZE) {
											interrupt = true;
											chunk = buffer;
											buffer = null;
										}
									}
								} else if (buffer) {
									var body = buffer + '';
									var isGBK = body.indexOf('�') == -1;
									if (isGBK) {
										body = iconv.decode(buffer, 'GB18030');
										body = util.replaceQueryString(body, params);
										chunk = iconv.encode(body, 'GB18030');
									} else {
										chunk = new Buffer(body);
									}
									buffer = null;
								}

								callback(null, chunk);
							};
							req.add(transform);
						}
					}
					next();
				});
			});
		});
	});
};<|endoftext|>


<commit_before>var https = require('https');
var http = require('http');
var extend = require('util')._extend;
var util = require('../../util');
var WhistleTransform = util.WhistleTransform;

function addRuleHeaders(headers, req, name) {
	name = 'x-' + name + '-';
	var rules = req.rules;
	for (var i in rules) {
		headers[name + i] = rules[i].matcher;
	}
	headers['x-remote-ip'] = req.hostIp || '127.0.0.1';
	return headers;
}

function handleRes(res, data) {
	if (data) {
		extend(res.headers, data.headers);
		res.add(new WhistleTransform(data));
	}

}

module.exports = function(req, res, next) {
	var config = this.config;
	var responsed, resData;
	req.request = function(options) {
		if (!options.proxy && util.isLocalAddress(options.host) && (options.port || 80) == config.port) {
			res.redirect(302, 'http://' + config.localUIHost + (options.path || ''));
			return;
		}

		req.hostIp = options.host;
		req.pipe((options.protocol == 'https:' ? https : http).request(options, res.response));
	};

	res.response = function(_res) {
		if (responsed) {
			return;
		}
		responsed = true;
		var headers = res.headers = _res.headers;
		res.trailers = _res.trailers;
		res.statusCode = _res.statusCode = _res.statusCode || 0;
		handleRes(res, resData);
		addRuleHeaders(headers, req, config.name);
		if (headers.location) {
			//nodejs的url只支持ascii，对非ascii的字符要encodeURIComponent，否则传到浏览器是乱码
			headers.location = util.encodeNonAsciiChar(headers.location);
		}
		res.src(_res);
		res.writeHead(_res.statusCode, _res.headers);
		res.trailers && res.addTrailers(res.trailers);
	};

	util.parseRuleToJson(req.rules.res,
			function(err, data) {
		if (req.rules.head && req.rules.head.res) {
			data = extend(req.rules.head.res, data);
		}
		if (resData = data) {
			data.headers = util.lowerCaseify(data.headers);
			if (data.statusCode) {
				util.drain(req, function() {
					res.response(util.wrapResponse(data));
				});
				return;
			}
		}
		next();
	});
};<commit_msg>add zip transform<commit_after>var https = require('https');
var http = require('http');
var extend = require('util')._extend;
var util = require('../../util');
var WhistleTransform = util.WhistleTransform;

function addRuleHeaders(headers, req, name) {
	name = 'x-' + name + '-';
	var rules = req.rules;
	for (var i in rules) {
		headers[name + i] = rules[i].matcher;
	}
	headers['x-remote-ip'] = req.hostIp || '127.0.0.1';
	return headers;
}

function handleRes(res, data) {
	if (data) {
		extend(res.headers, data.headers);
		res.addZipTransform(new WhistleTransform(data));
	}

}

module.exports = function(req, res, next) {
	var config = this.config;
	var responsed, resData;
	req.request = function(options) {
		if (!options.proxy && util.isLocalAddress(options.host) && (options.port || 80) == config.port) {
			res.redirect(302, 'http://' + config.localUIHost + (options.path || ''));
			return;
		}

		req.hostIp = options.host;
		req.pipe((options.protocol == 'https:' ? https : http).request(options, res.response));
	};

	res.response = function(_res) {
		if (responsed) {
			return;
		}
		responsed = true;
		var headers = res.headers = _res.headers;
		res.trailers = _res.trailers;
		res.statusCode = _res.statusCode = _res.statusCode || 0;
		handleRes(res, resData);
		addRuleHeaders(headers, req, config.name);
		if (headers.location) {
			//nodejs的url只支持ascii，对非ascii的字符要encodeURIComponent，否则传到浏览器是乱码
			headers.location = util.encodeNonAsciiChar(headers.location);
		}
		res.src(_res);
		res.writeHead(_res.statusCode, _res.headers);
		res.trailers && res.addTrailers(res.trailers);
	};

	util.parseRuleToJson(req.rules.res,
			function(err, data) {
		if (req.rules.head && req.rules.head.res) {
			data = extend(req.rules.head.res, data);
		}
		if (resData = data) {
			data.headers = util.lowerCaseify(data.headers);
			if (data.statusCode) {
				util.drain(req, function() {
					res.response(util.wrapResponse(data));
				});
				return;
			}
		}
		next();
	});
};<|endoftext|>


<commit_before>'use strict';
exports.info = {
  desc: 'Embeds the users avatar.',
  usage: '',
  aliases: [],
  permissions: ['SEND_MESSAGES', 'EMBED_LINKS'],
};

exports.run = (client, msg) => new Promise((resolve, reject) => {
  // Create new embed
  const embed = new client.Discord.RichEmbed()
    .setImage(msg.author.displayAvatarURL);
  // If msg.member exists we are in a guild channel
  if (msg.member) {
    embed.setTitle(msg.member.displayName)
      .setColor(msg.member.displayColor);
  } else {
    // We are in a dm channel
    embed.setTitle(msg.author.username);
  }
  msg.channel.send({ embed }).then(resolve).catch(reject);
});
<commit_msg>don't embed avatar<commit_after>'use strict';
exports.info = {
  desc: 'Embeds the users avatar.',
  usage: '',
  aliases: [],
  permissions: ['SEND_MESSAGES', 'ATTACH_FILES'],
};

exports.run = (client, msg) => new Promise((resolve, reject) => {
  const name = msg.member ? msg.member.displayName : msg.author.username;
  msg.channel.send(`**${name}**`,
    { files: [{ attachment: msg.author.displayAvatarURL() }] }).then(resolve).catch(reject);
});
<|endoftext|>


<commit_before>// Profile Images Collection
ProfileImages = new FS.Collection('ProfileImages', {
  stores: [new FS.Store.GridFS('ProfileImages')]
});

// User Images Collection
UserImages = new Mongo.Collection("UserImages");

// Posts Collection
Posts = new Mongo.Collection("posts");

// Posts schema
Posts.attachSchema(new SimpleSchema({
  body : {
    type: String,
    max: 600
  },
  userId: {
    type: String,
    autoValue: function() {
      return Meteor.userId();
    }
  },
  username: {
    type: String,
    autoValue: function() {
      return Meteor.users.findOne({_id: this.userId}).username;
    }
  },
  createdAt: {
    type: Date,
    autoValue: function() {
      return new Date();
    }
  }
}));
<commit_msg>created profile image permissions<commit_after>// Profile Images Collection
ProfileImages = new FS.Collection('ProfileImages', {
  stores: [new FS.Store.GridFS('ProfileImages')]
});

// Permissions to allow profile images to show
ProfileImages.allow({
  insert: function(userId, doc) {
    return true;
  },
  update: function(userId, doc, fields, modifier) {
    return true;
  },
  download: function() {
    return true;
  }
});

// User Images Collection
UserImages = new Mongo.Collection("UserImages");

// Posts Collection
Posts = new Mongo.Collection("posts");

// Posts schema
Posts.attachSchema(new SimpleSchema({
  body : {
    type: String,
    max: 600
  },
  userId: {
    type: String,
    autoValue: function() {
      return Meteor.userId();
    }
  },
  username: {
    type: String,
    autoValue: function() {
      return Meteor.users.findOne({_id: this.userId}).username;
    }
  },
  createdAt: {
    type: Date,
    autoValue: function() {
      return new Date();
    }
  }
}));
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var Suite = require('../suite')
  , Test = require('../test');

/**
 * BDD-style interface:
 *
 *      describe('Array', function(){
 *        describe('#indexOf()', function(){
 *          it('should return -1 when not present', function(){
 *
 *          });
 *
 *          it('should return the index when present', function(){
 *
 *          });
 *        });
 *      });
 *
 */

module.exports = function(suite){
  var suites = [suite];

  suite.on('pre-require', function(context, file){

    /**
     * Do this before each example
     *
     */
    context.beforeEach = function(fn){
      suites[0].addSetup(fn);
    };

    /**
     * Do this after each example
     *
     */
    context.afterEach = function(fn){
      suites[0].addTearDown(fn);
    };
    /**
     * Describe a "suite" with the given `title`
     * and callback `fn` containing nested suites
     * and/or tests.
     */

    context.describe = function(title, fn){
      var suite = suite = new Suite(title);
      suites[0].addSuite(suite);
      suites.unshift(suite);
      fn();
      suites.shift();
    };

    /**
     * Describe a specification or test-case
     * with the given `title` and callback `fn`
     * acting as a thunk.
     */

    context.it = function(title, fn){
      suites[0].addTest(new Test(title, fn));
    };
  });
};
<commit_msg>Fixed bdd ui styling<commit_after>
/**
 * Module dependencies.
 */

var Suite = require('../suite')
  , Test = require('../test');

/**
 * BDD-style interface:
 *
 *      describe('Array', function(){
 *        describe('#indexOf()', function(){
 *          it('should return -1 when not present', function(){
 *
 *          });
 *
 *          it('should return the index when present', function(){
 *
 *          });
 *        });
 *      });
 *
 */

module.exports = function(suite){
  var suites = [suite];

  suite.on('pre-require', function(context, file){

    /**
     * Do this before each test case.
     */

    context.beforeEach = function(fn){
      suites[0].addSetup(fn);
    };

    /**
     * Do this after each test case.
     */

    context.afterEach = function(fn){
      suites[0].addTearDown(fn);
    };

    /**
     * Describe a "suite" with the given `title`
     * and callback `fn` containing nested suites
     * and/or tests.
     */

    context.describe = function(title, fn){
      var suite = suite = new Suite(title);
      suites[0].addSuite(suite);
      suites.unshift(suite);
      fn();
      suites.shift();
    };

    /**
     * Describe a specification or test-case
     * with the given `title` and callback `fn`
     * acting as a thunk.
     */

    context.it = function(title, fn){
      suites[0].addTest(new Test(title, fn));
    };
  });
};
<|endoftext|>


<commit_before>$(document).ready(function () {
  start($("#content"));
  document.title = metadata.title;
});

var beetle = {
  switch___to: function (element, fn) {
    element.empty();
    fn(element);
  },

  paragraph: function (element, string) {
    var $par = $("<p/>");
    $par.append(document.createTextNode(string));
    element.append($par);
  },

  field: function (element, fn) {
    var $form = $("<form/>");
    var $text = $("<input/>", {type : "text"});
    $form.append($text);
    $form.submit(function () {
      fn(element, $text.val());
      return false;
    });
    element.append($form);
  },

  link: function (_, f) {
    return function (element, g) {
      var $a = $('<a/>');
      $a.addClass("link");
      $a.click(function () {
        g(element);
      });
      f($a);
      element.append($a);
    };
  },

  exec: function (element, f) {
    f(element);
  },

  debug___print: function (_, x) {
    console.log(x);
  },

  $if: function (_, c) {
    return function (_, f) {
      return function (element, g) {
        if (c) { f(element); } else { g(element); };
      }
    }
  },
  _______t: true,
  _______f: false

};
<commit_msg>fixed 'field' in the runtime to work with the new way functions work.<commit_after>$(document).ready(function () {
  start($("#content"));
  document.title = metadata.title;
});

var beetle = {
  switch___to: function (element, fn) {
    element.empty();
    fn(element);
  },

  paragraph: function (element, string) {
    var $par = $("<p/>");
    $par.append(document.createTextNode(string));
    element.append($par);
  },

  field: function (element, fn) {
    var $form = $("<form/>");
    var $text = $("<input/>", {type : "text"});
    $form.append($text);
    $form.submit(function () {
      fn(element, $text.val())(element);
      return false;
    });
    element.append($form);
  },

  link: function (_, f) {
    return function (element, g) {
      var $a = $('<a/>');
      $a.addClass("link");
      $a.click(function () {
        g(element);
      });
      f($a);
      element.append($a);
    };
  },

  exec: function (element, f) {
    f(element);
  },

  debug___print: function (_, x) {
    console.log(x);
  },

  $if: function (_, c) {
    return function (_, f) {
      return function (element, g) {
        if (c) { f(element); } else { g(element); };
      }
    }
  },
  _______t: true,
  _______f: false

};
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var Suite = require('../suite')
  , Test = require('../test');

/**
 * BDD-style interface:
 *
 *      describe('Array', function(){
 *        describe('#indexOf()', function(){
 *          it('should return -1 when not present', function(){
 *
 *          });
 *
 *          it('should return the index when present', function(){
 *
 *          });
 *        });
 *      });
 *
 */

module.exports = function(suite){
  var suites = [suite];

  suite.on('pre-require', function(context){

    /**
     * Execute before running tests.
     */

    context.before = function(fn){
      suites[0].beforeAll(fn);
    };

    /**
     * Execute after running tests.
     */

    context.after = function(fn){
      suites[0].afterAll(fn);
    };

    /**
     * Execute before each test case.
     */

    context.beforeEach = function(fn){
      suites[0].beforeEach(fn);
    };

    /**
     * Execute after each test case.
     */

    context.afterEach = function(fn){
      suites[0].afterEach(fn);
    };

    /**
     * Pending describe.
     */

    context.xdescribe = context.xcontext = function(title, fn){
      var suite = Suite.create(suites[0], title);
      suite.pending = true;
      suites.unshift(suite);
      fn();
      suites.shift();
    };

    /**
     * Describe a "suite" with the given `title`
     * and callback `fn` containing nested suites
     * and/or tests.
     */

    context.describe = context.context = function(title, fn){
      var suite = Suite.create(suites[0], title);
      suites.unshift(suite);
      fn();
      suites.shift();
    };

    /**
     * Describe a specification or test-case
     * with the given `title` and callback `fn`
     * acting as a thunk.
     */

    context.it = context.specify = function(title, fn){
      var suite = suites[0];
      if (suite.pending) var fn = null;
      suite.addTest(new Test(title, fn));
    };

    /**
     * Pending test case.
     */

    context.xit = context.xspecify = function(title){
      context.it(title);
    };
  });
};
<commit_msg>remove context() and specify()<commit_after>
/**
 * Module dependencies.
 */

var Suite = require('../suite')
  , Test = require('../test');

/**
 * BDD-style interface:
 *
 *      describe('Array', function(){
 *        describe('#indexOf()', function(){
 *          it('should return -1 when not present', function(){
 *
 *          });
 *
 *          it('should return the index when present', function(){
 *
 *          });
 *        });
 *      });
 *
 */

module.exports = function(suite){
  var suites = [suite];

  suite.on('pre-require', function(context){

    /**
     * Execute before running tests.
     */

    context.before = function(fn){
      suites[0].beforeAll(fn);
    };

    /**
     * Execute after running tests.
     */

    context.after = function(fn){
      suites[0].afterAll(fn);
    };

    /**
     * Execute before each test case.
     */

    context.beforeEach = function(fn){
      suites[0].beforeEach(fn);
    };

    /**
     * Execute after each test case.
     */

    context.afterEach = function(fn){
      suites[0].afterEach(fn);
    };

    /**
     * Pending describe.
     */

    context.xdescribe = function(title, fn){
      var suite = Suite.create(suites[0], title);
      suite.pending = true;
      suites.unshift(suite);
      fn();
      suites.shift();
    };

    /**
     * Describe a "suite" with the given `title`
     * and callback `fn` containing nested suites
     * and/or tests.
     */

    context.describe = function(title, fn){
      var suite = Suite.create(suites[0], title);
      suites.unshift(suite);
      fn();
      suites.shift();
    };

    /**
     * Describe a specification or test-case
     * with the given `title` and callback `fn`
     * acting as a thunk.
     */

    context.it = function(title, fn){
      var suite = suites[0];
      if (suite.pending) var fn = null;
      suite.addTest(new Test(title, fn));
    };

    /**
     * Pending test case.
     */

    context.xit = function(title){
      context.it(title);
    };
  });
};
<|endoftext|>