<commit_before>/* eslint-disable global-require */

function readRangeFromBlocks(blocks, rangeOffset, rangeLength) {
  const rangeTop = rangeOffset + rangeLength;
  const rangeData = new ArrayBuffer(rangeLength);
  const rangeView = new Uint8Array(rangeData);

  for (const block of blocks) {
    const delta = block.offset - rangeOffset;
    const topDelta = block.top - rangeTop;
    let blockInnerOffset = 0;
    let rangeInnerOffset = 0;
    let usedBlockLength;

    if (delta < 0) {
      blockInnerOffset = -delta;
    } else if (delta > 0) {
      rangeInnerOffset = delta;
    }

    if (topDelta < 0) {
      usedBlockLength = block.length - blockInnerOffset;
    } else if (topDelta > 0) {
      usedBlockLength = rangeTop - block.offset - blockInnerOffset;
    }

    const blockView = new Uint8Array(block.data, blockInnerOffset, usedBlockLength);
    rangeView.set(blockView, rangeInnerOffset);
  }

  return rangeData;
}

/**
 * Interface for Source objects.
 * @interface Source
 */

/**
 * @function Source#fetch
 * @summary The main method to retrieve the data from the source.
 * @param {number} offset The offset to read from in the source
 * @param {number} length The requested number of bytes
 */

/**
 * @typedef {object} Block
 * @property {ArrayBuffer} data The actual data of the block.
 * @property {number} offset The actual offset of the block within the file.
 * @property {number} length The actual size of the block in bytes.
 */

/**
 * Callback type for sources to request patches of data.
 * @callback requestCallback
 * @async
 * @param {number} offset The offset within the file.
 * @param {number} length The desired length of data to be read.
 * @returns {Promise<Block>} The block of data.
 */

/**
 * @module source
 */

/*
 * Split a list of identifiers to form groups of coherent ones
 */
function getCoherentBlockGroups(blockIds) {
  if (blockIds.length === 0) {
    return [];
  }

  const groups = [];
  let current = [];
  groups.push(current);

  for (let i = 0; i < blockIds.length; ++i) {
    if (i === 0 || blockIds[i] === blockIds[i - 1] + 1) {
      current.push(blockIds[i]);
    } else {
      current = [blockIds[i]];
      groups.push(current);
    }
  }
  return groups;
}

/*
 * Promisified wrapper around 'setTimeout' to allow 'await'
 */
async function wait(milliseconds) {
  return new Promise(resolve => setTimeout(resolve, milliseconds));
}

/**
 * BlockedSource - an abstraction of (remote) files.
 * @implements Source
 */
class BlockedSource {
  /**
   * @param {requestCallback} retrievalFunction Callback function to request data
   * @param {object} options Additional options
   * @param {object} options.blockSize Size of blocks to be fetched
   */
  constructor(retrievalFunction, { blockSize = 65535 } = {}) {
    this.retrievalFunction = retrievalFunction;
    this.blockSize = blockSize;

    // currently running block requests
    this.blockRequests = new Map();

    // already retrieved blocks
    this.blocks = new Map();

    // block ids waiting for a batched request. Either a Set or null
    this.blockIdsAwaitingRequest = null;
  }

  /**
   * Fetch a subset of the file.
   * @param {number} offset The offset within the file to read from.
   * @param {number} length The length in bytes to read from.
   * @returns {ArrayBuffer} The subset of the file.
   */
  async fetch(offset, length, immediate = false) {
    const top = offset + length;

    // calculate what blocks intersect the specified range (offset + length)
    // determine what blocks are already stored or beeing requested
    const firstBlockOffset = Math.floor(offset / this.blockSize) * this.blockSize;
    const allBlockIds = [];
    const missingBlockIds = [];
    const blockRequests = [];

    for (let current = firstBlockOffset; current < top; current += this.blockSize) {
      const blockId = Math.floor(current / this.blockSize);
      if (!this.blocks.has(blockId) && !this.blockRequests.has(blockId)) {
        missingBlockIds.push(blockId);
      }
      if (this.blockRequests.has(blockId)) {
        blockRequests.push(this.blockRequests.get(blockId));
      }
      allBlockIds.push(blockId);
    }

    // determine whether there are already blocks in the queue to be requested
    // if so, add the missing blocks to this list
    if (!this.blockIdsAwaitingRequest) {
      this.blockIdsAwaitingRequest = new Set(missingBlockIds);
    } else {
      for (let i = 0; i < missingBlockIds.length; ++i) {
        const id = missingBlockIds[i];
        this.blockIdsAwaitingRequest.add(id);
      }
    }

    // in immediate mode, we don't want to wait for possible additional requests coming in
    if (!immediate) {
      await wait();
    }

    // determine if we are the thread to start the requests.
    if (this.blockIdsAwaitingRequest) {
      // get all coherent blocks as groups to be requested in a single request
      const groups = getCoherentBlockGroups(
        Array.from(this.blockIdsAwaitingRequest).sort(),
      );

      // iterate over all blocks
      for (const group of groups) {
        // fetch a group as in a single request
        const request = this.requestData(
          group[0] * this.blockSize, group.length * this.blockSize,
        );

        // for each block in the request, make a small 'splitter',
        // i.e: wait for the request to finish, then cut out the bytes for
        // that block and store it there.
        // we keep that as a promise in 'blockRequests' to allow waiting on
        // a single block.
        for (let i = 0; i < group.length; ++i) {
          const id = group[i];
          this.blockRequests.set(id, (async () => {
            const response = await request;
            const o = i * this.blockSize;
            const t = Math.min(o + this.blockSize, response.data.byteLength);
            const data = response.data.slice(o, t);
            this.blockRequests.delete(id);
            this.blocks.set(id, {
              data,
              offset: response.offset + o,
              length: data.byteLength,
              top: response.offset + t,
            });
          })());
        }
      }
      this.blockIdsAwaitingRequest = null;
    }

    // get a list of currently running requests for the blocks still missing
    const missingRequests = [];
    for (const blockId of missingBlockIds) {
      if (this.blockRequests.has(blockId)) {
        missingRequests.push(this.blockRequests.get(blockId));
      }
    }

    // wait for all missing requests to finish
    await Promise.all(missingRequests);
    await Promise.all(blockRequests);

    // now get all blocks for the request and return a summary buffer
    const blocks = allBlockIds.map(id => this.blocks.get(id));
    return readRangeFromBlocks(blocks, offset, length);
  }

  async requestData(requestedOffset, requestedLength) {
    const response = await this.retrievalFunction(requestedOffset, requestedLength);
    if (!response.length) {
      response.length = response.data.byteLength;
    } else if (response.length !== response.data.byteLength) {
      response.data = response.data.slice(0, response.length);
    }
    response.top = response.offset + response.length;
    return response;
  }
}

/**
 * Create a new source to read from a remote file using the fetch API.
 * @param {string} url The URL to send requests to.
 * @param {Object} [options] Additional options.
 * @param {Number} [options.blockSize] The block size to use.
 * @param {object} [options.headers] Additional headers to be sent to the server.
 * @returns The constructed source
 */
export function makeFetchSource(url, { headers = {}, blockSize } = {}) {
  return new BlockedSource(async (offset, length) => {
    const response = await fetch(url, {
      headers: Object.assign({},
        headers, {
          Range: `bytes=${offset}-${offset + length}`,
        },
      ),
    });

    // check the response was okay and if the server actually understands range requests
    if (!response.ok) {
      throw new Error('Error fetching data.');
    } else if (response.status === 206) {
      const data = response.arrayBuffer ?
        await response.arrayBuffer() : (await response.buffer()).buffer;
      return {
        data,
        offset,
        length,
      };
    } else {
      const data = response.arrayBuffer ?
        await response.arrayBuffer() : (await response.buffer()).buffer;
      return {
        data,
        offset: 0,
        length: data.byteLength,
      };
    }
  }, { blockSize });
}

/**
 * Create a new source to read from a remote file using the XHR API.
 * @param {string} url The URL to send requests to.
 * @param {Object} [options] Additional options.
 * @param {Number} [options.blockSize] The block size to use.
 * @param {object} [options.headers] Additional headers to be sent to the server.
 * @returns The constructed source
 */
export function makeXHRSource(url, { headers = {}, blockSize } = {}) {
  return new BlockedSource(async (offset, length) => {
    return new Promise((resolve, reject) => {
      const request = new XMLHttpRequest();
      request.open('GET', url);
      request.responseType = 'arraybuffer';

      Object.entries(
        Object.assign({},
          headers, {
            Range: `bytes=${offset}-${offset + length}`,
          },
        ),
      ).forEach(([key, value]) => request.setRequestHeader(key, value));

      request.onload = () => {
        const data = request.response;
        if (request.status === 206) {
          resolve({
            data,
            offset,
            length,
          });
        } else {
          resolve({
            data,
            offset: 0,
            length: data.byteLength,
          });
        }
      };
      request.onerror = reject;
      request.send();
    });
  }, { blockSize });
}

/**
 * Create a new source to read from a remote file. Uses either XHR or fetch.
 * @param {string} url The URL to send requests to.
 * @param {Object} [options] Additional options.
 * @param {Number} [options.blockSize] The block size to use.
 * @param {object} [options.headers] Additional headers to be sent to the server.
 * @returns The constructed source
 */
export function makeRemoteSource(url, options) {
  const { forceXHR } = options;
  if (typeof fetch === 'function' && !forceXHR) {
    return makeFetchSource(url, options);
  }
  return makeXHRSource(url, options);
}

/**
 * Create a new source to read from a local
 * [ArrayBuffer]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer}.
 * @param {ArrayBuffer} arrayBuffer The ArrayBuffer to parse the GeoTIFF from.
 * @returns The constructed source
 */
export function makeBufferSource(arrayBuffer) {
  return {
    async fetch(offset, length) {
      return arrayBuffer.slice(offset, offset + length);
    },
  };
}

/**
 * Creates a new source using the node filesystem API.
 * @param {string} path The path to the file in the local filesystem.
 * @returns The constructed source
 */
export function makeFileSource(path) {
  const { promisify } = require('util');
  const { open, read } = require('fs');
  const openAsync = promisify(open);
  const readAsync = promisify(read);

  const fileOpen = openAsync(path, 'r');

  return {
    async fetch(offset, length) {
      const fd = await fileOpen;
      const { buffer } = await readAsync(fd, new Uint8Array(length), 0, length, offset);
      return buffer.buffer;
    },
  };
}

/**
 * Create a new source from a given file/blob.
 * @param {Blob} file The file or blob to read from.
 * @returns The constructed source
 */
export function makeFileReaderSource(file) {
  return {
    async fetch(offset, length) {
      return new Promise((resolve, reject) => {
        const blob = file.slice(offset, offset + length);
        const reader = new FileReader();
        reader.onload = event => resolve(event.target.result);
        reader.onerror = reject;
        reader.readAsArrayBuffer(blob);
      });
    },
  };
}
<commit_msg>Getting rid of promisify.<commit_after>const { open, read } = require('fs');

function readRangeFromBlocks(blocks, rangeOffset, rangeLength) {
  const rangeTop = rangeOffset + rangeLength;
  const rangeData = new ArrayBuffer(rangeLength);
  const rangeView = new Uint8Array(rangeData);

  for (const block of blocks) {
    const delta = block.offset - rangeOffset;
    const topDelta = block.top - rangeTop;
    let blockInnerOffset = 0;
    let rangeInnerOffset = 0;
    let usedBlockLength;

    if (delta < 0) {
      blockInnerOffset = -delta;
    } else if (delta > 0) {
      rangeInnerOffset = delta;
    }

    if (topDelta < 0) {
      usedBlockLength = block.length - blockInnerOffset;
    } else if (topDelta > 0) {
      usedBlockLength = rangeTop - block.offset - blockInnerOffset;
    }

    const blockView = new Uint8Array(block.data, blockInnerOffset, usedBlockLength);
    rangeView.set(blockView, rangeInnerOffset);
  }

  return rangeData;
}

/**
 * Interface for Source objects.
 * @interface Source
 */

/**
 * @function Source#fetch
 * @summary The main method to retrieve the data from the source.
 * @param {number} offset The offset to read from in the source
 * @param {number} length The requested number of bytes
 */

/**
 * @typedef {object} Block
 * @property {ArrayBuffer} data The actual data of the block.
 * @property {number} offset The actual offset of the block within the file.
 * @property {number} length The actual size of the block in bytes.
 */

/**
 * Callback type for sources to request patches of data.
 * @callback requestCallback
 * @async
 * @param {number} offset The offset within the file.
 * @param {number} length The desired length of data to be read.
 * @returns {Promise<Block>} The block of data.
 */

/**
 * @module source
 */

/*
 * Split a list of identifiers to form groups of coherent ones
 */
function getCoherentBlockGroups(blockIds) {
  if (blockIds.length === 0) {
    return [];
  }

  const groups = [];
  let current = [];
  groups.push(current);

  for (let i = 0; i < blockIds.length; ++i) {
    if (i === 0 || blockIds[i] === blockIds[i - 1] + 1) {
      current.push(blockIds[i]);
    } else {
      current = [blockIds[i]];
      groups.push(current);
    }
  }
  return groups;
}

/*
 * Promisified wrapper around 'setTimeout' to allow 'await'
 */
async function wait(milliseconds) {
  return new Promise(resolve => setTimeout(resolve, milliseconds));
}

/**
 * BlockedSource - an abstraction of (remote) files.
 * @implements Source
 */
class BlockedSource {
  /**
   * @param {requestCallback} retrievalFunction Callback function to request data
   * @param {object} options Additional options
   * @param {object} options.blockSize Size of blocks to be fetched
   */
  constructor(retrievalFunction, { blockSize = 65535 } = {}) {
    this.retrievalFunction = retrievalFunction;
    this.blockSize = blockSize;

    // currently running block requests
    this.blockRequests = new Map();

    // already retrieved blocks
    this.blocks = new Map();

    // block ids waiting for a batched request. Either a Set or null
    this.blockIdsAwaitingRequest = null;
  }

  /**
   * Fetch a subset of the file.
   * @param {number} offset The offset within the file to read from.
   * @param {number} length The length in bytes to read from.
   * @returns {ArrayBuffer} The subset of the file.
   */
  async fetch(offset, length, immediate = false) {
    const top = offset + length;

    // calculate what blocks intersect the specified range (offset + length)
    // determine what blocks are already stored or beeing requested
    const firstBlockOffset = Math.floor(offset / this.blockSize) * this.blockSize;
    const allBlockIds = [];
    const missingBlockIds = [];
    const blockRequests = [];

    for (let current = firstBlockOffset; current < top; current += this.blockSize) {
      const blockId = Math.floor(current / this.blockSize);
      if (!this.blocks.has(blockId) && !this.blockRequests.has(blockId)) {
        missingBlockIds.push(blockId);
      }
      if (this.blockRequests.has(blockId)) {
        blockRequests.push(this.blockRequests.get(blockId));
      }
      allBlockIds.push(blockId);
    }

    // determine whether there are already blocks in the queue to be requested
    // if so, add the missing blocks to this list
    if (!this.blockIdsAwaitingRequest) {
      this.blockIdsAwaitingRequest = new Set(missingBlockIds);
    } else {
      for (let i = 0; i < missingBlockIds.length; ++i) {
        const id = missingBlockIds[i];
        this.blockIdsAwaitingRequest.add(id);
      }
    }

    // in immediate mode, we don't want to wait for possible additional requests coming in
    if (!immediate) {
      await wait();
    }

    // determine if we are the thread to start the requests.
    if (this.blockIdsAwaitingRequest) {
      // get all coherent blocks as groups to be requested in a single request
      const groups = getCoherentBlockGroups(
        Array.from(this.blockIdsAwaitingRequest).sort(),
      );

      // iterate over all blocks
      for (const group of groups) {
        // fetch a group as in a single request
        const request = this.requestData(
          group[0] * this.blockSize, group.length * this.blockSize,
        );

        // for each block in the request, make a small 'splitter',
        // i.e: wait for the request to finish, then cut out the bytes for
        // that block and store it there.
        // we keep that as a promise in 'blockRequests' to allow waiting on
        // a single block.
        for (let i = 0; i < group.length; ++i) {
          const id = group[i];
          this.blockRequests.set(id, (async () => {
            const response = await request;
            const o = i * this.blockSize;
            const t = Math.min(o + this.blockSize, response.data.byteLength);
            const data = response.data.slice(o, t);
            this.blockRequests.delete(id);
            this.blocks.set(id, {
              data,
              offset: response.offset + o,
              length: data.byteLength,
              top: response.offset + t,
            });
          })());
        }
      }
      this.blockIdsAwaitingRequest = null;
    }

    // get a list of currently running requests for the blocks still missing
    const missingRequests = [];
    for (const blockId of missingBlockIds) {
      if (this.blockRequests.has(blockId)) {
        missingRequests.push(this.blockRequests.get(blockId));
      }
    }

    // wait for all missing requests to finish
    await Promise.all(missingRequests);
    await Promise.all(blockRequests);

    // now get all blocks for the request and return a summary buffer
    const blocks = allBlockIds.map(id => this.blocks.get(id));
    return readRangeFromBlocks(blocks, offset, length);
  }

  async requestData(requestedOffset, requestedLength) {
    const response = await this.retrievalFunction(requestedOffset, requestedLength);
    if (!response.length) {
      response.length = response.data.byteLength;
    } else if (response.length !== response.data.byteLength) {
      response.data = response.data.slice(0, response.length);
    }
    response.top = response.offset + response.length;
    return response;
  }
}

/**
 * Create a new source to read from a remote file using the fetch API.
 * @param {string} url The URL to send requests to.
 * @param {Object} [options] Additional options.
 * @param {Number} [options.blockSize] The block size to use.
 * @param {object} [options.headers] Additional headers to be sent to the server.
 * @returns The constructed source
 */
export function makeFetchSource(url, { headers = {}, blockSize } = {}) {
  return new BlockedSource(async (offset, length) => {
    const response = await fetch(url, {
      headers: Object.assign({},
        headers, {
          Range: `bytes=${offset}-${offset + length}`,
        },
      ),
    });

    // check the response was okay and if the server actually understands range requests
    if (!response.ok) {
      throw new Error('Error fetching data.');
    } else if (response.status === 206) {
      const data = response.arrayBuffer ?
        await response.arrayBuffer() : (await response.buffer()).buffer;
      return {
        data,
        offset,
        length,
      };
    } else {
      const data = response.arrayBuffer ?
        await response.arrayBuffer() : (await response.buffer()).buffer;
      return {
        data,
        offset: 0,
        length: data.byteLength,
      };
    }
  }, { blockSize });
}

/**
 * Create a new source to read from a remote file using the XHR API.
 * @param {string} url The URL to send requests to.
 * @param {Object} [options] Additional options.
 * @param {Number} [options.blockSize] The block size to use.
 * @param {object} [options.headers] Additional headers to be sent to the server.
 * @returns The constructed source
 */
export function makeXHRSource(url, { headers = {}, blockSize } = {}) {
  return new BlockedSource(async (offset, length) => {
    return new Promise((resolve, reject) => {
      const request = new XMLHttpRequest();
      request.open('GET', url);
      request.responseType = 'arraybuffer';

      Object.entries(
        Object.assign({},
          headers, {
            Range: `bytes=${offset}-${offset + length}`,
          },
        ),
      ).forEach(([key, value]) => request.setRequestHeader(key, value));

      request.onload = () => {
        const data = request.response;
        if (request.status === 206) {
          resolve({
            data,
            offset,
            length,
          });
        } else {
          resolve({
            data,
            offset: 0,
            length: data.byteLength,
          });
        }
      };
      request.onerror = reject;
      request.send();
    });
  }, { blockSize });
}

/**
 * Create a new source to read from a remote file. Uses either XHR or fetch.
 * @param {string} url The URL to send requests to.
 * @param {Object} [options] Additional options.
 * @param {Number} [options.blockSize] The block size to use.
 * @param {object} [options.headers] Additional headers to be sent to the server.
 * @returns The constructed source
 */
export function makeRemoteSource(url, options) {
  const { forceXHR } = options;
  if (typeof fetch === 'function' && !forceXHR) {
    return makeFetchSource(url, options);
  }
  return makeXHRSource(url, options);
}

/**
 * Create a new source to read from a local
 * [ArrayBuffer]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer}.
 * @param {ArrayBuffer} arrayBuffer The ArrayBuffer to parse the GeoTIFF from.
 * @returns The constructed source
 */
export function makeBufferSource(arrayBuffer) {
  return {
    async fetch(offset, length) {
      return arrayBuffer.slice(offset, offset + length);
    },
  };
}

function openAsync(path, flags, mode = undefined) {
  return new Promise((resolve, reject) => {
    open(path, flags, mode, (err, fd) => {
      if (err) {
        reject(err);
      } else {
        resolve(fd);
      }
    })
  })
}

function readAsync(fd, readBuffer, offset, length, position) {
  return new Promise((resolve, reject) => {
    read(fd, readBuffer, offset, length, position, (err, bytesRead, buffer) => {
      if (err) {
        reject(err);
      } else {
        resolve({ bytesRead, buffer });
      }
    })
  })
}

/**
 * Creates a new source using the node filesystem API.
 * @param {string} path The path to the file in the local filesystem.
 * @returns The constructed source
 */
export function makeFileSource(path) {
  const fileOpen = openAsync(path, 'r');

  return {
    async fetch(offset, length) {
      const fd = await fileOpen;
      const { buffer } = await readAsync(fd, new Uint8Array(length), 0, length, offset);
      return buffer.buffer;
    },
  };
}

/**
 * Create a new source from a given file/blob.
 * @param {Blob} file The file or blob to read from.
 * @returns The constructed source
 */
export function makeFileReaderSource(file) {
  return {
    async fetch(offset, length) {
      return new Promise((resolve, reject) => {
        const blob = file.slice(offset, offset + length);
        const reader = new FileReader();
        reader.onload = event => resolve(event.target.result);
        reader.onerror = reject;
        reader.readAsArrayBuffer(blob);
      });
    },
  };
}
<|endoftext|>


<commit_before>'use strict';

const { Collector } = require("istanbul");

var World,
Skill = function(newWorld) {
	World = newWorld;
};

/*
* Passive Skills, typically called by name within commands
*/

// Return a mod for chance to block with shield
Skill.prototype.shieldBlock = function(skillObj, player, roomObj, shield) {
	var conMod = World.dice.getConMod(skillUser),
	skillOutput = this.createSkillProfile();

	if (skillObj.train >= 80 && World.dice.roll(1, 100) > (98 - conMod)) {
		skillObj.train += 1;

		World.msgPlayer(skillUser, {
			msg: 'Your Shield Block abilities improve!',
			styleClass: 'green',
			noPrompt: true
		});
	}

	if (skillObj.train >= 20) {
		return 1 + Math.round(player.level / 8);
	} else {
		return 0;
	}
};

// Returns a modifier for number of attacks per round
Skill.prototype.secondAttack = function(skillObj, skillUser) {
	var intMod = World.dice.getIntMod(skillUser);

	if (skillObj.train >= 80 && World.dice.roll(1, 100) > (98 - intMod)) {
		skillObj.train += 1;

		World.msgPlayer(skillUser, {
			msg: 'Your ability to Second Attack has improved!',
			styleClass: 'green',
			noPrompt: true
		});
	}

	if (skillObj.train >= 20) {
		return 1;
	} else {
		return 0;
	}
};

/*
* Non combat skills, typically checked by a game entity
*/
Skill.prototype.sneak = function(skillObj, player, roomObj, command, World) {
	var skillAff = World.getAffect(player, 'sneak');
	var affObj;

	if (!skillAff) {
		if (player.position === 'standing') {
			// run a check; chance of auto failure
			if (skillObj.train > 0 && World.dice.roll(1, 6) < 6) {
				affObj = {
					id: skillObj.id,
					affect: 'sneak',
					display: 'Sneaking',
					decayMsg: 'You are no longer sneaking',
					decay: World.dice.roll(1 + player.level/2, 10, (player.detection + player.knowledge/2) + skillObj.train/5)
				};

				World.addAffect(player, affObj);

				if (skillObj.wait) {
					player.wait += skillObj.wait;
				} else {
					player.wait += 1;
				}
			}

			// Players never know if they're successfully sneaking
			World.msgPlayer(player, {
				msg: 'You begin sneaking.'
			});
		} else {
			World.msgPlayer(player, {
				msg: 'You can\'t sneak in this position.'
			});
		}
	} else {
		// quit sneaking
		World.character.removeAffect(player, 'sneak');

		World.msgPlayer(player, {
			msg: 'You are no longer sneaking.'
		});
	}
};

/*
* Melee Skills, called by a game entity
*/

/*
* Can only work on standing opponents
* Chance of knocking the target down; chances increased with a shield
* If the target is already on the ground dex check to fall
* If the target is two sizes smaller do a dex check against missing, a critical fail causes the user to trip
* Attacker does .5 more damage per size difference in target
*
* Since this is a combat skill it must output a Skill Profile Object
*/
Skill.prototype.bash = function(skillObj, player, roomObj, command) {
	var opponent = World.combat.getBattleTargetByRefId(player.refId),
	weaponSlots,
	i = 0,
	strMod = World.dice.getStrMod(player),
	oppDexMod,
	shieldArr,
	shield,
	skillOutput = World.combat.createSkillProfile(player, skillObj),
	dmg,
	rollDamage = function(shield) {
		var dmg = 0;

		dmg = World.dice.roll(player.diceNum, player.diceSides + player.size.value, strMod + player.size.value)
			* Math.round(player.level/2) + 1;

		if (player.mainStat === 'str') {
			dmg += World.dice.roll(1, 2 + player.level, strMod);
		}

		if (shield) {
			if (!shield.diceNum) {
				dmg += World.dice.roll(1, 1 + player.level);
			} else {
				dmg += World.dice.roll(shield.diceNum, shield.diceSides, strMod);
			}
		}

		return dmg;
	};

	if (skillObj.train > 5) {
		if (!opponent && command.arg && player.position === 'standing') {
			opponent = World.room.getMonster(roomObj, command);
		}

		skillOutput.winMsg = 'You smash into ' + opponent.displayName + ' and they splatter into a thousand different pieces!';

		if (opponent) {
			shieldArr = World.character.getSlotsWithShields(player);

			if (shieldArr.length) {
				shield = shieldArr[0].item;
			}

			if (player.position === 'standing') {
				if (World.dice.roll(1, 100) <= skillObj.train) {
					dmg = rollDamage(shield);

					skillOutput.defenderMods.chp = -dmg;

					if (!shield) {
						skillOutput.msgToAttacker = 'You bash and charge at a ' + opponent.name + ' (' + dmg + ')';

						skillOutput.msgToDefender = 'A ' + player.displayName + ' bashes and charges at you!' + ' (' + dmg + ')';
					} else {
						skillOutput.msgToAttacker = 'You use a ' + shield.displayName + ' to bash and charge at a '
							+ opponent.name + ' (' + dmg + ')';

						skillOutput.msgToDefender = 'A ' + player.displayName + ' bashes and charges at you with a '
							+ shield.displayName + '! (' + dmg + ')';
					}

					if (player.mainStat === 'str') {
						skillOutput.attackerMods.wait += 3;
					} else {
						skillOutput.attackerMods.wait += 4;
					}

					skillOutput.defenderMods.wait += 4;

					World.combat.processSkill(player, opponent, skillOutput);
				} else {
					skillOutput.msgToAttacker = 'You lunge forward and miss your bash but manage to keep your footing!';

					if (World.dice.roll(1, 20, player.knowledge) >= (10 + player.level)) {
						skillOutput.attackerMods.wait += 3;
					} else {
						skillOutput.attackerMods.wait += 5;
					}

					World.combat.processSkill(player, opponent, skillOutput);
				}
			}
		} else {
			World.msgPlayer(player, {
				msg: 'Bash what?'
			});
		}
	} else {
		World.msgPlayer(player, {
			msg: 'You need to train more before using Bash.',
			styleClass: 'error'
		});
	}
};

Skill.prototype.backstab = function(skillObj, player, roomObj, command) {
	var opponent = World.room.getMonster(roomObj, command),
	weaponSlots,
	i = 0,
	dexMod = World.dice.getDexMod(player),
	damage;

	if (opponent && player.position === 'standing' && !opponent.fighting) {
		if (World.dice.roll(1, 100) <= skillObj.train) {
			// backstab!
			damage = World.dice.roll(1, 20 + dexMod, dexMod);

			if (World.dice.roll(1, 20 + player.level, dexMod) > (17 + player.level + 1)) {
				if (!player.sneaking) {
					damage = damage * 1.5;
				} else {
					damage = (damage * 2) + dexMod;
				}
			}

			if (player.mainStat === 'dex') {
				damage += World.dice.roll(1, 20 + player.level);
			}

			player.wait += 3;
			opponent.wait += 3;
		} else {
			// missed
			if (World.dice.roll(1, 20, player.knowledge) >= (10 + player.level)) {
				player.wait += 3;
			} else {
				player.wait += 6;
			}
		}
	}
};

module.exports = Skill;
<commit_msg>remove istanbul reference<commit_after>'use strict';
var World,
Skill = function(newWorld) {
	World = newWorld;
};

/*
* Passive Skills, typically called by name within commands
*/

// Return a mod for chance to block with shield
Skill.prototype.shieldBlock = function(skillObj, player, roomObj, shield) {
	var conMod = World.dice.getConMod(skillUser),
	skillOutput = this.createSkillProfile();

	if (skillObj.train >= 80 && World.dice.roll(1, 100) > (98 - conMod)) {
		skillObj.train += 1;

		World.msgPlayer(skillUser, {
			msg: 'Your Shield Block abilities improve!',
			styleClass: 'green',
			noPrompt: true
		});
	}

	if (skillObj.train >= 20) {
		return 1 + Math.round(player.level / 8);
	} else {
		return 0;
	}
};

// Returns a modifier for number of attacks per round
Skill.prototype.secondAttack = function(skillObj, skillUser) {
	var intMod = World.dice.getIntMod(skillUser);

	if (skillObj.train >= 80 && World.dice.roll(1, 100) > (98 - intMod)) {
		skillObj.train += 1;

		World.msgPlayer(skillUser, {
			msg: 'Your ability to Second Attack has improved!',
			styleClass: 'green',
			noPrompt: true
		});
	}

	if (skillObj.train >= 20) {
		return 1;
	} else {
		return 0;
	}
};

/*
* Non combat skills, typically checked by a game entity
*/
Skill.prototype.sneak = function(skillObj, player, roomObj, command, World) {
	var skillAff = World.getAffect(player, 'sneak');
	var affObj;

	if (!skillAff) {
		if (player.position === 'standing') {
			// run a check; chance of auto failure
			if (skillObj.train > 0 && World.dice.roll(1, 6) < 6) {
				affObj = {
					id: skillObj.id,
					affect: 'sneak',
					display: 'Sneaking',
					decayMsg: 'You are no longer sneaking',
					decay: World.dice.roll(1 + player.level/2, 10, (player.detection + player.knowledge/2) + skillObj.train/5)
				};

				World.addAffect(player, affObj);

				if (skillObj.wait) {
					player.wait += skillObj.wait;
				} else {
					player.wait += 1;
				}
			}

			// Players never know if they're successfully sneaking
			World.msgPlayer(player, {
				msg: 'You begin sneaking.'
			});
		} else {
			World.msgPlayer(player, {
				msg: 'You can\'t sneak in this position.'
			});
		}
	} else {
		// quit sneaking
		World.character.removeAffect(player, 'sneak');

		World.msgPlayer(player, {
			msg: 'You are no longer sneaking.'
		});
	}
};

/*
* Melee Skills, called by a game entity
*/

/*
* Can only work on standing opponents
* Chance of knocking the target down; chances increased with a shield
* If the target is already on the ground dex check to fall
* If the target is two sizes smaller do a dex check against missing, a critical fail causes the user to trip
* Attacker does .5 more damage per size difference in target
*
* Since this is a combat skill it must output a Skill Profile Object
*/
Skill.prototype.bash = function(skillObj, player, roomObj, command) {
	var opponent = World.combat.getBattleTargetByRefId(player.refId),
	weaponSlots,
	i = 0,
	strMod = World.dice.getStrMod(player),
	oppDexMod,
	shieldArr,
	shield,
	skillOutput = World.combat.createSkillProfile(player, skillObj),
	dmg,
	rollDamage = function(shield) {
		var dmg = 0;

		dmg = World.dice.roll(player.diceNum, player.diceSides + player.size.value, strMod + player.size.value)
			* Math.round(player.level/2) + 1;

		if (player.mainStat === 'str') {
			dmg += World.dice.roll(1, 2 + player.level, strMod);
		}

		if (shield) {
			if (!shield.diceNum) {
				dmg += World.dice.roll(1, 1 + player.level);
			} else {
				dmg += World.dice.roll(shield.diceNum, shield.diceSides, strMod);
			}
		}

		return dmg;
	};

	if (skillObj.train > 5) {
		if (!opponent && command.arg && player.position === 'standing') {
			opponent = World.room.getMonster(roomObj, command);
		}

		skillOutput.winMsg = 'You smash into ' + opponent.displayName + ' and they splatter into a thousand different pieces!';

		if (opponent) {
			shieldArr = World.character.getSlotsWithShields(player);

			if (shieldArr.length) {
				shield = shieldArr[0].item;
			}

			if (player.position === 'standing') {
				if (World.dice.roll(1, 100) <= skillObj.train) {
					dmg = rollDamage(shield);

					skillOutput.defenderMods.chp = -dmg;

					if (!shield) {
						skillOutput.msgToAttacker = 'You bash and charge at a ' + opponent.name + ' (' + dmg + ')';

						skillOutput.msgToDefender = 'A ' + player.displayName + ' bashes and charges at you!' + ' (' + dmg + ')';
					} else {
						skillOutput.msgToAttacker = 'You use a ' + shield.displayName + ' to bash and charge at a '
							+ opponent.name + ' (' + dmg + ')';

						skillOutput.msgToDefender = 'A ' + player.displayName + ' bashes and charges at you with a '
							+ shield.displayName + '! (' + dmg + ')';
					}

					if (player.mainStat === 'str') {
						skillOutput.attackerMods.wait += 3;
					} else {
						skillOutput.attackerMods.wait += 4;
					}

					skillOutput.defenderMods.wait += 4;

					World.combat.processSkill(player, opponent, skillOutput);
				} else {
					skillOutput.msgToAttacker = 'You lunge forward and miss your bash but manage to keep your footing!';

					if (World.dice.roll(1, 20, player.knowledge) >= (10 + player.level)) {
						skillOutput.attackerMods.wait += 3;
					} else {
						skillOutput.attackerMods.wait += 5;
					}

					World.combat.processSkill(player, opponent, skillOutput);
				}
			}
		} else {
			World.msgPlayer(player, {
				msg: 'Bash what?'
			});
		}
	} else {
		World.msgPlayer(player, {
			msg: 'You need to train more before using Bash.',
			styleClass: 'error'
		});
	}
};

Skill.prototype.backstab = function(skillObj, player, roomObj, command) {
	var opponent = World.room.getMonster(roomObj, command),
	weaponSlots,
	i = 0,
	dexMod = World.dice.getDexMod(player),
	damage;

	if (opponent && player.position === 'standing' && !opponent.fighting) {
		if (World.dice.roll(1, 100) <= skillObj.train) {
			// backstab!
			damage = World.dice.roll(1, 20 + dexMod, dexMod);

			if (World.dice.roll(1, 20 + player.level, dexMod) > (17 + player.level + 1)) {
				if (!player.sneaking) {
					damage = damage * 1.5;
				} else {
					damage = (damage * 2) + dexMod;
				}
			}

			if (player.mainStat === 'dex') {
				damage += World.dice.roll(1, 20 + player.level);
			}

			player.wait += 3;
			opponent.wait += 3;
		} else {
			// missed
			if (World.dice.roll(1, 20, player.knowledge) >= (10 + player.level)) {
				player.wait += 3;
			} else {
				player.wait += 6;
			}
		}
	}
};

module.exports = Skill;
<|endoftext|>


<commit_before>const inputN = +process.argv[2];

let N;

if (inputN && typeof inputN === "number" && inputN > 0 && inputN % 1 === 0)
    N = inputN;
else {
    console.log("incorrect N or absent, using default N = 3 (it possible to call program with argument N, where N is whole positive number)");
    N = 3;
}

const
    side = 2 * N - 1,
    size = side * side,
    matrix = [],
    startIndex = (side - 1) / 2;

for (let i = 0; i < side; i ++) {
    matrix[i] = [];
    for (let j = 0; j < side; j ++)
        matrix[i][j] = Math.ceil(Math.random() * size);
}

console.log("\nRandom matrix:\n");

let matrixAsString = "";
for (let i = 0; i < side; i ++) {
    for (let j = 0; j < side; j ++)
        matrixAsString += matrix[i][j] + (matrix[i][j] < 10 ? "  " : " ");
    matrixAsString += "\n";
}

console.log(matrixAsString);

const arr = [matrix[startIndex][startIndex]];

let
    direction = 0, // Направление движения по строкам и столбцам матрицы
    totalSteps = 1, // количество шагов, которое необходимо сделать по выбранному направлению движения
    steps = 0, // число уже сделанных шагов по выбранному направлению движения
    x = startIndex, // начальный индекс по "горизонтали"
    y = startIndex; // начальный индекс по "вертикали"

for (let i = 0; i < size; i ++) {
    arr[i] = matrix[y][x];
    switch (direction) {
        case 0: { // Вправо
            x = x - 1;
            break;
        }
        case 1: { // Вниз
            y = y + 1;
            break;
        }
        case 2: { // Влево
            x = x + 1;
            break;
        }
        case 3: { // Вверх
            y = y - 1;
            break;
        }
    }

    steps ++;

    if (i === totalSteps * (totalSteps + 1))
        totalSteps ++;

    if (steps === totalSteps)
        changeDirection();
}

console.log(`\nOutput spiral-way view:\n\n${arr.join(" ")}`);

function changeDirection() {
    if (direction === 3)
        direction = 0;
    else
        direction ++;

    steps = 0;
}
<commit_msg>"Matrix as string by spiral" task solution added.<commit_after>const inputN = +process.argv[2];

let N;

if (inputN && typeof inputN === "number" && inputN > 0 && inputN % 1 === 0)
    N = inputN;
else {
    console.log("incorrect N or absent, using default N = 3 (it possible to call program with argument N, where N is whole positive number)");
    N = 3;
}

const
    side = 2 * N - 1,
    size = side * side,
    matrix = [],
    startIndex = (side - 1) / 2;

for (let i = 0; i < side; i ++) {
    matrix[i] = [];
    for (let j = 0; j < side; j ++)
        matrix[i][j] = Math.ceil(Math.random() * size);
}

console.log("\nRandom matrix:\n");

let matrixAsString = "";
for (let i = 0; i < side; i ++) {
    for (let j = 0; j < side; j ++)
        matrixAsString += matrix[i][j] + (matrix[i][j] < 10 ? "  " : " ");
    matrixAsString += "\n";
}

console.log(matrixAsString);

const arr = [matrix[startIndex][startIndex]];

let
    direction = 0,  // Направление движения по строкам и столбцам матрицы
    totalSteps = 1, // количество шагов, которое необходимо сделать по выбранному направлению движения
    steps = 0,      // число уже сделанных шагов по выбранному направлению движения
    x = startIndex, // начальный индекс по "горизонтали"
    y = startIndex; // начальный индекс по "вертикали"

for (let i = 0; i < size; i ++) {
    arr[i] = matrix[y][x];
    switch (direction) {
        case 0: { // Вправо
            x = x - 1;
            break;
        }
        case 1: { // Вниз
            y = y + 1;
            break;
        }
        case 2: { // Влево
            x = x + 1;
            break;
        }
        case 3: { // Вверх
            y = y - 1;
            break;
        }
    }

    steps ++;

    if (i === totalSteps * (totalSteps + 1))
        totalSteps ++;

    if (steps === totalSteps)
        changeDirection();
}

console.log(`\nOutput spiral-way view:\n\n${arr.join(" ")}`);

function changeDirection() {
    if (direction === 3)
        direction = 0;
    else
        direction ++;

    steps = 0;
}
<|endoftext|>


<commit_before>/*
* http://addyosmani.com/blog/essential-js-namespacing/
*/
(function(app) {
  'use strict';
  /*global FB, Foundation*/

  app.menuActiveFeatureClicked = function(activeFeature) {
    /*
    http://stackoverflow.com/a/6944834
    https://css-tricks.com/snippets/javascript/get-url-and-url-parts-in-javascript/
    */
    var pathArray = window.location.pathname.split('/');
    var lastLevelLocation = pathArray[pathArray.length - 1];
    if (lastLevelLocation !== activeFeature && lastLevelLocation !== '') {
      // We are in a subpage, redirect to main page of the active feature.
      window.location.href = '/' + activeFeature;
    }
    if (typeof Foundation !== undefined) {
      Foundation.libs.topbar.toggle();
    }
  };

  app.facebookShareBlog = function(event, lead, path, title, pictureUrl) {
    event.preventDefault();
    FB.ui(
    {
      method: 'share',
      href: 'https://filosofianakatemia.fi/blogi/' + path,
      picture: pictureUrl,
      title: title,
      description: lead
    },
    function(/*response*/) {
      return null;
    });
  };

  app.twitterShareBlog = function(event, path, title) {
    event.preventDefault();
    // http://gpiot.com/blog/elegant-twitter-share-button-and-dialog-with-jquery/
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var shareVia = 'filosofianakate';
    var url = 'https://twitter.com/intent/tweet?via=' + shareVia + '&url=' + encodeURIComponent(sharelUrl) + '&text=' + encodeURIComponent(title);
    window.open(url, '_blank', 'height=420, width=550');
  };

  app.linkedInShareBlog = function(event, lead, path, title) {
    event.preventDefault();
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var url = 'https://www.linkedin.com/shareArticle?mini=true&url=' + encodeURIComponent(sharelUrl) + '&title=' + encodeURIComponent(title) +
    '&summary=' + encodeURIComponent(lead) + '&source=Filosofian%20Akatemia';
    window.open(url, '_blank', 'height=420, width=550');
  };

  function httpGetAsync(theUrl, callback)
  {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
        callback(xmlHttp.responseText);
    };
    xmlHttp.open('GET', theUrl, true); // true for asynchronous
    xmlHttp.send(null);
  }

  app.getShareCount = function(path) {
    // http://stackoverflow.com/a/19119580
    var totalCount = 0;
    var totalCountElement = document.getElementById('total-shares_count');
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;

    var facebookUrl = 'https://api.facebook.com/method/links.getStats?urls=' + sharelUrl + '&format=json';
    httpGetAsync(facebookUrl, facebookCount);
    function facebookCount(response) {
      totalCount += JSON.parse(response)[0].share_count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }

    var twitterUrl = 'https://cdn.api.twitter.com/1/urls/count.json?url=' + sharelUrl;
    // Remove this for now because of No 'Access-Control-Allow-Origin' header
    //httpGetAsync(twitterUrl, twitterCount);
    function twitterCount(response) {
      totalCount += JSON.parse(response).count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }

    var linkedInUrl = 'https://www.linkedin.com/countserv/count/share?url=' + sharelUrl + '&format=json';
    // Remove this for now because of No 'Access-Control-Allow-Origin' header
    //httpGetAsync(linkedInUrl, linkedInCount);
    function linkedInCount(response) {
      totalCount += JSON.parse(response).count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }
  };

})(window.app = window.app || {});
<commit_msg>Fixed FB share count<commit_after>/*
* http://addyosmani.com/blog/essential-js-namespacing/
*/
(function(app) {
  'use strict';
  /*global FB, Foundation*/

  app.menuActiveFeatureClicked = function(activeFeature) {
    /*
    http://stackoverflow.com/a/6944834
    https://css-tricks.com/snippets/javascript/get-url-and-url-parts-in-javascript/
    */
    var pathArray = window.location.pathname.split('/');
    var lastLevelLocation = pathArray[pathArray.length - 1];
    if (lastLevelLocation !== activeFeature && lastLevelLocation !== '') {
      // We are in a subpage, redirect to main page of the active feature.
      window.location.href = '/' + activeFeature;
    }
    if (typeof Foundation !== undefined) {
      Foundation.libs.topbar.toggle();
    }
  };

  app.facebookShareBlog = function(event, lead, path, title, pictureUrl) {
    event.preventDefault();
    FB.ui(
    {
      method: 'share',
      href: 'https://filosofianakatemia.fi/blogi/' + path,
      picture: pictureUrl,
      title: title,
      description: lead
    },
    function(/*response*/) {
      return null;
    });
  };

  app.twitterShareBlog = function(event, path, title) {
    event.preventDefault();
    // http://gpiot.com/blog/elegant-twitter-share-button-and-dialog-with-jquery/
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var shareVia = 'filosofianakate';
    var url = 'https://twitter.com/intent/tweet?via=' + shareVia + '&url=' + encodeURIComponent(sharelUrl) + '&text=' + encodeURIComponent(title);
    window.open(url, '_blank', 'height=420, width=550');
  };

  app.linkedInShareBlog = function(event, lead, path, title) {
    event.preventDefault();
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var url = 'https://www.linkedin.com/shareArticle?mini=true&url=' + encodeURIComponent(sharelUrl) + '&title=' + encodeURIComponent(title) +
    '&summary=' + encodeURIComponent(lead) + '&source=Filosofian%20Akatemia';
    window.open(url, '_blank', 'height=420, width=550');
  };

  function httpGetAsync(theUrl, callback)
  {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
        callback(xmlHttp.responseText);
    };
    xmlHttp.open('GET', theUrl, true); // true for asynchronous
    xmlHttp.send(null);
  }

  app.getShareCount = function(path) {
    // http://stackoverflow.com/a/19119580
    var totalCount = 0;
    var totalCountElement = document.getElementById('total-shares_count');
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var facebookUrl = 'https://graph.facebook.com?id=' + sharelUrl;
    httpGetAsync(facebookUrl, facebookCount);
    function facebookCount(response) {
      totalCount += JSON.parse(response).share.share_count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }

    var twitterUrl = 'https://cdn.api.twitter.com/1/urls/count.json?url=' + sharelUrl;
    // Remove this for now because of No 'Access-Control-Allow-Origin' header
    //httpGetAsync(twitterUrl, twitterCount);
    function twitterCount(response) {
      totalCount += JSON.parse(response).count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }

    var linkedInUrl = 'https://www.linkedin.com/countserv/count/share?url=' + sharelUrl + '&format=json';
    // Remove this for now because of No 'Access-Control-Allow-Origin' header
    //httpGetAsync(linkedInUrl, linkedInCount);
    function linkedInCount(response) {
      totalCount += JSON.parse(response).count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }
  };

})(window.app = window.app || {});
<|endoftext|>


<commit_before>(function (window) {
    'use strict';

    function Sprite() {
        // Position de l'animation courante parmi les frames
        this.currentAnimationFrame = 0;

        // Sert à controler la boucle d'animation
        this.animationLoop;

        this.animations = {};

        this.currentState;
    }

    Sprite.prototype.clearCurrentAnimation = function () {
        this.currentAnimationFrame = 0;
        clearTimeout(this.animationLoop);
    };

    Sprite.prototype.startLoop = function (animation) {
        if (this.currentState !== animation) {
            this.clearCurrentAnimation();
            this.animationY = this.animations[animation].animationY;
            this.animationFrameWidth = this.animations[animation].animationFrameWidth;

            this.currentState = animation;

            this.animationLoop = setTimeout(function () {
                this.animLoop(animation);
            }.bind(this), this.animations[animation].speedRate);
        }
    };

    Sprite.prototype.animLoop = function (animation) {
        this.currentAnimationFrame += 1;
        if (this.currentAnimationFrame === this.animations[animation].nbFrames) {
            this.currentAnimationFrame = 0;
        }

        this.animationLoop = setTimeout(function () {
            this.animLoop(animation);
        }.bind(this), this.animations[animation].speedRate);
    };

    window.Sprite = Sprite;

})(window);
<commit_msg>fix(sprite): initialisation des valeurs à la création.<commit_after>(function (window) {
    'use strict';

    function Sprite() {
        // Position de l'animation courante parmi les frames
        this.currentAnimationFrame = 0;

        // Sert à controler la boucle d'animation
        this.animationLoop = null;

        this.animations = {};

        this.currentState = '';
    }

    Sprite.prototype.clearCurrentAnimation = function () {
        this.currentAnimationFrame = 0;
        clearTimeout(this.animationLoop);
    };

    Sprite.prototype.startLoop = function (animation) {
        if (this.currentState !== animation) {
            this.clearCurrentAnimation();
            this.animationY = this.animations[animation].animationY;
            this.animationFrameWidth = this.animations[animation].animationFrameWidth;

            this.currentState = animation;

            this.animationLoop = setTimeout(function () {
                this.animLoop(animation);
            }.bind(this), this.animations[animation].speedRate);
        }
    };

    Sprite.prototype.animLoop = function (animation) {
        this.currentAnimationFrame += 1;
        if (this.currentAnimationFrame === this.animations[animation].nbFrames) {
            this.currentAnimationFrame = 0;
        }

        this.animationLoop = setTimeout(function () {
            this.animLoop(animation);
        }.bind(this), this.animations[animation].speedRate);
    };

    window.Sprite = Sprite;

})(window);
<|endoftext|>


<commit_before>var TimeSegments = {

  // Segment an array of events by scale
  segment(events, scale, options) {
    scale = scale || 'weeks';
    options = options || {};
    _.defaults(options, {
      startAttribute: 'start',
      endAttribute: 'end'
    });
    events = _.chain(events).clone().sortBy(options.startAttribute).value();
    var segments = {};

    // Clone our events so that we're not modifying the original
    // objects. Loop through them, inserting the events into the
    // corresponding segments
    _.each(_.clone(events), e => {

      // Calculate the duration of the event; this determines
      // how many segments it will be in
      var startMoment = moment.utc(e[options.startAttribute]).startOf(scale);
      var endMoment = moment.utc(e[options.endAttribute]).endOf(scale).add(1, 'milliseconds');

      // For each duration, add the event to the corresponding segment
      var segmentStart;
      for(var i = 0, duration = endMoment.diff(startMoment, scale); i < duration; i++) {
        segmentStart = moment.utc(startMoment).add(i, scale).unix();
        if (!segments[segmentStart]) { segments[segmentStart] = []; }
        segments[segmentStart].push(_.clone(e));
      }
    });
    return segments;
  }
};

export default TimeSegments;
<commit_msg>Add ES6 import to source file.<commit_after>import _ from 'underscore';
import moment from 'moment';

var TimeSegments = {

  // Segment an array of events by scale
  segment(events, scale, options) {
    scale = scale || 'weeks';
    options = options || {};
    _.defaults(options, {
      startAttribute: 'start',
      endAttribute: 'end'
    });
    events = _.chain(events).clone().sortBy(options.startAttribute).value();
    var segments = {};

    // Clone our events so that we're not modifying the original
    // objects. Loop through them, inserting the events into the
    // corresponding segments
    _.each(_.clone(events), e => {

      // Calculate the duration of the event; this determines
      // how many segments it will be in
      var startMoment = moment.utc(e[options.startAttribute]).startOf(scale);
      var endMoment = moment.utc(e[options.endAttribute]).endOf(scale).add(1, 'milliseconds');

      // For each duration, add the event to the corresponding segment
      var segmentStart;
      for(var i = 0, duration = endMoment.diff(startMoment, scale); i < duration; i++) {
        segmentStart = moment.utc(startMoment).add(i, scale).unix();
        if (!segments[segmentStart]) { segments[segmentStart] = []; }
        segments[segmentStart].push(_.clone(e));
      }
    });
    return segments;
  }
};

export default TimeSegments;
<|endoftext|>


<commit_before>// Swiper Class
import Swiper from './components/core/core-class';

// Core Modules
import Device from './modules/device/device';
import Support from './modules/support/support';
import Browser from './modules/browser/browser';
import Resize from './modules/resize/resize';
import Observer from './modules/observer/observer';

//IMPORT_COMPONENTS

const components = [
  Device,
  Support,
  Browser,
  Resize,
  Observer,
  //INSTALL_COMPONENTS
];

if (typeof Swiper.use !== 'undefined') Swiper.use(components);
else Swiper.Class.use(components);

//EXPORT
<commit_msg>Correct fix<commit_after>// Swiper Class
import Swiper from './components/core/core-class';

// Core Modules
import Device from './modules/device/device';
import Support from './modules/support/support';
import Browser from './modules/browser/browser';
import Resize from './modules/resize/resize';
import Observer from './modules/observer/observer';

//IMPORT_COMPONENTS

const components = [
  Device,
  Support,
  Browser,
  Resize,
  Observer,
  //INSTALL_COMPONENTS
];

if (typeof Swiper.use === 'undefined') {
  Swiper.use = Swiper.Class.use;
  Swiper.installModule = Swiper.Class.installModule;
}

Swiper.use(components);

//EXPORT
<|endoftext|>


<commit_before>import deepEqual from 'deep-equal';

/*
* stream constructor
* constructor returns a stream
* get the current value of stream like: stream.value
*/
export const stream = function(init_value) {
	let s = function(value) {
		if (value === undefined) {
			return s.value;
		}
		update(s, value);
		return s;
	}

	s.IS_STREAM = true;
	s.value = init_value;
	s.listeners = [];

	s.map = (fn) => map(s, fn);
	s.is = (value) => map(s, (cur) => cur === value);
	s.flatMap = (fn) => flatMap(s, fn);
	s.filter = (fn) => filter(s, fn);
	s.deepSelect = (fn) => deepSelect(s, fn);
	s.distinct = (fn) => distinct(s, fn);
	s.$ = (selectorArr) => query(s, selectorArr);
	s.until = (stopEmit$) => until(s, stopEmit$);
	s.patch = (partialChange) => patch(s, partialChange);
	s.reduce = (fn, startValue) => reduce(s, fn, startValue);
	s.debounce = (timer) => debounce(s, timer);
	s.log = (prefix = 'Stream:') => log(s, prefix);

	return s;
};

/*
* wrapper for the diffing of stream values
*/
function valuesChanged(oldValue, newValue) {
	return !deepEqual(oldValue, newValue);
}

/*
* update the stream value and notify listeners on the stream
*/
function update(parent$, newValue) {
	parent$.value = newValue;
	notifyListeners(parent$.listeners, newValue);
}

/*
* provide a new value to all listeners registered for a stream
*/
function notifyListeners(listeners, value) {
	listeners.forEach(function notifyListener(listener) {
		listener(value);
	});
}

/*
* Do not pipe the value undefined. This allows to wait for an external initialization.
* It also saves you from checking for an initial null on every map function.
*/
function fork$(parent$, mapFunction) {
	let initValue = parent$.value !== undefined ? mapFunction(parent$.value) : undefined
	return stream(initValue);
}

/*
* provides a new stream applying a transformation function to the value of a parent stream
*/
function map(parent$, fn) {
	let newStream = fork$(parent$, fn);
	parent$.listeners.push(function mapValue(value) {
		newStream(fn(value));
	});
	return newStream;
}

/*
* helper function to debug, calls console.log on every value returnin the parent stream
*/
function log (parent$, prefix) {
  map(parent$, value => console.log(prefix, value))
  return parent$
}

/*
* provides a new stream applying a transformation function to the value of a parent stream
*/
function flatMap(parent$, fn) {
	let result$;
	let listener = function updateOuterStream(result) {
		newStream(result);
	};
	function attachToResult$(mapFn, parentValue, listener) {
		let result$ = mapFn(parentValue);
		result$.listeners.push(listener);
		return result$;
	}
	let newStream = fork$(parent$, function getChildStreamValue(value) {
		result$ = attachToResult$(fn, value, listener);
		return result$.value;
	});
	parent$.listeners.push(function flatMapValue(value) {
		// clean up listeners or they will stack on child streams
		if (result$) {
			removeItem(result$.listeners, listener);
		}

		result$ = attachToResult$(fn, value, listener);
		newStream(result$.value);
	});
	return newStream;
}

/*
* provides a new stream that only serves the values that a filter function returns true for
* still a stream ALWAYS has a value -> so it starts at least with NULL
*/
function filter(parent$, fn) {
	let newStream = fork$(parent$, (value) => fn(value) ? value : undefined);
	parent$.listeners.push(function filterValue(value) {
		if (fn(value)) {
			newStream(value);
		}
	});
	return newStream;
}

/*
* recursivly return the nested property of an object defined by an array of selectors
* parent: {foo: {bar:1}}, selectors: ['foo','bar'] returns 1
*/
function select(parent, selectors) {
	if (parent === null || parent === undefined) {
		return null
	}
	if (selectors.length === 0) {
		return parent
	}
	let selector = selectors[0]
	return select(parent[selector], selectors.splice(1, selectors.length - 1));
}
/*
* provides a new stream that has a selected sub property of the object value of the parent stream
* the selector has the format [{propertyName}.]*
*/
function deepSelect(parent$, selector) {
	let selectors = selector.split('.');

	let newStream = fork$(parent$, (value) => select(value, selectors));
	parent$.listeners.push(function deepSelectValue(newValue) {
		newStream(select(newValue, selectors));
	});
	return newStream;
}

function query(parent$, selectorsArr) {
	if(!Array.isArray(selectorsArr)) {
		return parent$.map(value => select(value, selectorsArr.split('.')))
	}
	return parent$.map(value => selectorsArr.map(selectors => select(value, selectors.split('.'))))
}

// TODO: maybe refactor with filter
/*
* provide a new stream that only notifys its children if the containing value actualy changes
*/
function distinct(parent$, fn = (a, b) => valuesChanged(a, b)) {
	let newStream = fork$(parent$, (value) => value);
	parent$.listeners.push(function deepSelectValue(value) {
		if (fn(newStream.value, value)) {
			newStream(value);
		}
	});
	return newStream;
}

/*
* update only the properties of an object passed
* i.e. {name: 'Fabian', lastname: 'Weber} patched with {name: 'Fabo'} produces {name: 'Fabo', lastname: 'Weber}
*/
function patch(parent$, partialChange) {
	return new Promise((resolve) => {
		if (partialChange === null || typeof partialChange !== 'object' || typeof parent$.value !== 'object') {
			parent$(partialChange);
		} else {
			parent$(Object.assign({}, parent$.value, partialChange));
		}
		resolve(parent$);
	})
}

function until(parent$, stopEmitValues$) {
	let newStream = stream();
	let subscribeTo = (stream, listener) => {
		listener(parent$.value);
		stream.listeners.push(listener);
	}
	if (stopEmitValues$.value === undefined) {
		subscribeTo(parent$, newStream)
	}
	stopEmitValues$.map(stopEmitValues => {
		if(stopEmitValues) {
			removeItem(parent$.listeners, newStream);
		} else {
			subscribeTo(parent$, newStream);
		}
	});
	return newStream;
}

/*
* reduce a stream over time
* this will pass the last output value to the calculation function
* reads like the array reduce function
*/
function reduce(parent$, fn, startValue) {
	let aggregate = startValue;
	let newStream = stream();
	function reduceValue(value) {
		aggregate = fn(aggregate, parent$.value);
		newStream(aggregate);
	}
	if (parent$.value !== undefined) {
		reduceValue(parent$.value);
	}
	parent$.listeners.push(reduceValue);
	return newStream;
}

function debounce(parent$, timer) {
	let curTimer;
	function debounceValue(value) {
		if (curTimer) {
			window.clearTimeout(curTimer);
		}
		curTimer = setTimeout(function updateChildStream() {
			newStream(value);
			curTimer = null;
		}, timer);
	}
	let newStream = stream();
	if (parent$.value !== undefined) {
		debounceValue(parent$.value);
	}
	parent$.listeners.push(debounceValue);
	return newStream;
}

/*
* merge several streams into one stream providing the values of all streams as an array
* accepts also non stream elements, those are just copied to the output
* the merge will only have a value if every stream for the merge has a value
*/
export function merge$(potentialStreamsArr) {
	let values = potentialStreamsArr.map(parent$ => parent$ && parent$.IS_STREAM ? parent$.value : parent$);
	let newStream = stream(values.indexOf(undefined) === -1 ? values : undefined);

	potentialStreamsArr.forEach((potentialStream, index) => {
		if (potentialStream.IS_STREAM) {
			potentialStream.listeners.push(function updateMergedStream(value) {
				values[index] = value;
				newStream(values.indexOf(undefined) === -1 ? values : undefined);
			});
		}
	});
	return newStream;
}

export function isStream(parent$) {
	return parent$ != null && !!parent$.IS_STREAM;
}

function removeItem(arr, item) {
	var index = arr.indexOf(item);
	if (index !== -1) {
		arr.splice(index, 1);
	}
}
<commit_msg>made .patch return the stream to chain patches<commit_after>import deepEqual from 'deep-equal';

/*
* stream constructor
* constructor returns a stream
* get the current value of stream like: stream.value
*/
export const stream = function(init_value) {
	let s = function(value) {
		if (value === undefined) {
			return s.value;
		}
		update(s, value);
		return s;
	}

	s.IS_STREAM = true;
	s.value = init_value;
	s.listeners = [];

	s.map = (fn) => map(s, fn);
	s.is = (value) => map(s, (cur) => cur === value);
	s.flatMap = (fn) => flatMap(s, fn);
	s.filter = (fn) => filter(s, fn);
	s.deepSelect = (fn) => deepSelect(s, fn);
	s.distinct = (fn) => distinct(s, fn);
	s.$ = (selectorArr) => query(s, selectorArr);
	s.until = (stopEmit$) => until(s, stopEmit$);
	s.patch = (partialChange) => patch(s, partialChange);
	s.reduce = (fn, startValue) => reduce(s, fn, startValue);
	s.debounce = (timer) => debounce(s, timer);
	s.log = (prefix = 'Stream:') => log(s, prefix);

	return s;
};

/*
* wrapper for the diffing of stream values
*/
function valuesChanged(oldValue, newValue) {
	return !deepEqual(oldValue, newValue);
}

/*
* update the stream value and notify listeners on the stream
*/
function update(parent$, newValue) {
	parent$.value = newValue;
	notifyListeners(parent$.listeners, newValue);
}

/*
* provide a new value to all listeners registered for a stream
*/
function notifyListeners(listeners, value) {
	listeners.forEach(function notifyListener(listener) {
		listener(value);
	});
}

/*
* Do not pipe the value undefined. This allows to wait for an external initialization.
* It also saves you from checking for an initial null on every map function.
*/
function fork$(parent$, mapFunction) {
	let initValue = parent$.value !== undefined ? mapFunction(parent$.value) : undefined
	return stream(initValue);
}

/*
* provides a new stream applying a transformation function to the value of a parent stream
*/
function map(parent$, fn) {
	let newStream = fork$(parent$, fn);
	parent$.listeners.push(function mapValue(value) {
		newStream(fn(value));
	});
	return newStream;
}

/*
* helper function to debug, calls console.log on every value returnin the parent stream
*/
function log (parent$, prefix) {
  map(parent$, value => console.log(prefix, value))
  return parent$
}

/*
* provides a new stream applying a transformation function to the value of a parent stream
*/
function flatMap(parent$, fn) {
	let result$;
	let listener = function updateOuterStream(result) {
		newStream(result);
	};
	function attachToResult$(mapFn, parentValue, listener) {
		let result$ = mapFn(parentValue);
		result$.listeners.push(listener);
		return result$;
	}
	let newStream = fork$(parent$, function getChildStreamValue(value) {
		result$ = attachToResult$(fn, value, listener);
		return result$.value;
	});
	parent$.listeners.push(function flatMapValue(value) {
		// clean up listeners or they will stack on child streams
		if (result$) {
			removeItem(result$.listeners, listener);
		}

		result$ = attachToResult$(fn, value, listener);
		newStream(result$.value);
	});
	return newStream;
}

/*
* provides a new stream that only serves the values that a filter function returns true for
* still a stream ALWAYS has a value -> so it starts at least with NULL
*/
function filter(parent$, fn) {
	let newStream = fork$(parent$, (value) => fn(value) ? value : undefined);
	parent$.listeners.push(function filterValue(value) {
		if (fn(value)) {
			newStream(value);
		}
	});
	return newStream;
}

/*
* recursivly return the nested property of an object defined by an array of selectors
* parent: {foo: {bar:1}}, selectors: ['foo','bar'] returns 1
*/
function select(parent, selectors) {
	if (parent === null || parent === undefined) {
		return null
	}
	if (selectors.length === 0) {
		return parent
	}
	let selector = selectors[0]
	return select(parent[selector], selectors.splice(1, selectors.length - 1));
}
/*
* provides a new stream that has a selected sub property of the object value of the parent stream
* the selector has the format [{propertyName}.]*
*/
function deepSelect(parent$, selector) {
	let selectors = selector.split('.');

	let newStream = fork$(parent$, (value) => select(value, selectors));
	parent$.listeners.push(function deepSelectValue(newValue) {
		newStream(select(newValue, selectors));
	});
	return newStream;
}

function query(parent$, selectorsArr) {
	if(!Array.isArray(selectorsArr)) {
		return parent$.map(value => select(value, selectorsArr.split('.')))
	}
	return parent$.map(value => selectorsArr.map(selectors => select(value, selectors.split('.'))))
}

// TODO: maybe refactor with filter
/*
* provide a new stream that only notifys its children if the containing value actualy changes
*/
function distinct(parent$, fn = (a, b) => valuesChanged(a, b)) {
	let newStream = fork$(parent$, (value) => value);
	parent$.listeners.push(function deepSelectValue(value) {
		if (fn(newStream.value, value)) {
			newStream(value);
		}
	});
	return newStream;
}

/*
* update only the properties of an object passed
* i.e. {name: 'Fabian', lastname: 'Weber} patched with {name: 'Fabo'} produces {name: 'Fabo', lastname: 'Weber}
*/
function patch(parent$, partialChange) {
  if (partialChange === null || typeof partialChange !== 'object' || typeof parent$.value !== 'object') {
    parent$(partialChange);
  } else {
    parent$(Object.assign({}, parent$.value, partialChange));
  }
  return parent$
}

function until(parent$, stopEmitValues$) {
	let newStream = stream();
	let subscribeTo = (stream, listener) => {
		listener(parent$.value);
		stream.listeners.push(listener);
	}
	if (stopEmitValues$.value === undefined) {
		subscribeTo(parent$, newStream)
	}
	stopEmitValues$.map(stopEmitValues => {
		if(stopEmitValues) {
			removeItem(parent$.listeners, newStream);
		} else {
			subscribeTo(parent$, newStream);
		}
	});
	return newStream;
}

/*
* reduce a stream over time
* this will pass the last output value to the calculation function
* reads like the array reduce function
*/
function reduce(parent$, fn, startValue) {
	let aggregate = startValue;
	let newStream = stream();
	function reduceValue(value) {
		aggregate = fn(aggregate, parent$.value);
		newStream(aggregate);
	}
	if (parent$.value !== undefined) {
		reduceValue(parent$.value);
	}
	parent$.listeners.push(reduceValue);
	return newStream;
}

function debounce(parent$, timer) {
	let curTimer;
	function debounceValue(value) {
		if (curTimer) {
			window.clearTimeout(curTimer);
		}
		curTimer = setTimeout(function updateChildStream() {
			newStream(value);
			curTimer = null;
		}, timer);
	}
	let newStream = stream();
	if (parent$.value !== undefined) {
		debounceValue(parent$.value);
	}
	parent$.listeners.push(debounceValue);
	return newStream;
}

/*
* merge several streams into one stream providing the values of all streams as an array
* accepts also non stream elements, those are just copied to the output
* the merge will only have a value if every stream for the merge has a value
*/
export function merge$(potentialStreamsArr) {
	let values = potentialStreamsArr.map(parent$ => parent$ && parent$.IS_STREAM ? parent$.value : parent$);
	let newStream = stream(values.indexOf(undefined) === -1 ? values : undefined);

	potentialStreamsArr.forEach((potentialStream, index) => {
		if (potentialStream.IS_STREAM) {
			potentialStream.listeners.push(function updateMergedStream(value) {
				values[index] = value;
				newStream(values.indexOf(undefined) === -1 ? values : undefined);
			});
		}
	});
	return newStream;
}

export function isStream(parent$) {
	return parent$ != null && !!parent$.IS_STREAM;
}

function removeItem(arr, item) {
	var index = arr.indexOf(item);
	if (index !== -1) {
		arr.splice(index, 1);
	}
}
<|endoftext|>


<commit_before>// typist v0.1.0
// Reliable typeOf function and related utilities.
// (c) 2012 Ben Brooks Scholz
// MIT Licensed.

(function () {
	var root = this;

	var typist = function () {

	    var STRING = {
			'type'       :'string',
			'constructor': String,
			'prototype'  :'[object String]'
	    };

	    var NUMBER = {
			'type'       :'number',
			'constructor': Number,
			'prototype'  :'[object Number]'
	    };

	    var BOOLEAN = {
			'type'       :'boolean',
			'constructor': Boolean,
			'prototype'  :'[object Boolean]'
	    };

	    var ARRAY = {
			'type'       :'array',
			'constructor': Array,
			'prototype'  :'[object Array]'
	    };

	    var OBJECT = {
			'type'       :'object',
			'constructor': Object,
			'prototype'  :'[object Object]'
	    };

	    var FUNCTION = {
			'type'       :'function',
			'constructor': Function,
			'prototype'  :'[object Function]'
	    };

	    var typeOf = function (item) {
			var type = typeof item;
			var prototype;

			if (type === 'string'  || item.constructor === String)   return 'string';
			if (type === 'number'  || item.constructor === Number)   return 'number';
			if (type === 'boolean' || item.constructor === Boolean)  return 'boolean';
			if (type === 'function'|| item.constructor === Function) return 'function';
			if (type === 'array'   || item.constructor === Array)    return 'array';

			prototype = Object.prototype.toString.call(item);

			if (prototype === STRING.prototype)   return 'string';
			if (prototype === NUMBER.prototype)   return 'number';
			if (prototype === BOOLEAN.prototype)  return 'boolean';
			if (prototype === FUNCTION.prototype) return 'function';
			if (prototype === ARRAY.prototype)    return 'array';

			return 'object';
	    };

		var isType = function (item, type) {
			if (item && item.constructor === type.constructor)
		    	return true;
			else if (Object.prototype.toString.call(item) === type.constructor)
		    	return true;
			else
		    	return false;
	    };

	    var isString = function (item) {
			return typeof item === 'string' ? true : isType(item, STRING);
	    };

	    var isNumber = function (item) {
			return typeof item === 'number' ? true : isType(item, NUMBER);
	    };

	    var isBoolean = function (item) {
			return typeof item === 'boolean' ? true : isType(item, BOOLEAN);
	    };

	    var isArray = function (item) {
			return typeof item === 'array' ? true : isType(item, ARRAY);
	    };

	    var isFunction = function (item) {
			return typeof item === 'function' ? true : isType(item, FUNCTION);
	    };

	    var isObject = function (item) {
			return isType(item, OBJECT);
	    };

	    // To build an 'isType' function for any type, use buildIsType.
	    // We can build one for typed arrays of 8 bit signed integers.
	    //
	    // var isInt8Array = buildIsType('Int8Array', Int8Array);
	    //
	    // The first argument is the name of the type as a string.
	    // It is used to build to string returned by the call to
	    //
	    // Object.prototype.toString.call(item);
	    //
	    // The case of the type string is corrected automatically.
	    //
	    // 'Int8Array' becomes '[object Int8Array]'
	    // 'int8Array' becomes '[object Int8Array]'
	    //
	    // The second argument is the constructor function of the type.
	    //
	    // As another example, we can construct any of the primitive type
	    // identifying functions.
	    //
	    // var isNumber = buildIsType('number', Number);
	    // var isArray = buildIsType('array', Array);
	    //
	    // These constructed versions are less efficient than the ones provided
	    // below since the type operator will never succeed (the types you construct
	    // will assume that `typeof yourObj` returns 'object').
	    //
	    var buildIsType = function (type, constructor) {
			return function (item) {
		    	return isType(item, buildType(type, constructor));
			}
	    };

	    var buildType = function (type, constructor) {
			var upperCaseType = type[0].toUpperCase()+type.slice(1,type.length);
			var prototype     = '[object '+upperCaseType+']';

			return {
				'type'       :'object',
				'constructor':constructor,
			 	'prototype'  :prototype
			};
	    };

	    return {
			typeOf     :typeOf,
			isString   :isString,
			isNumber   :isNumber,
			isBoolean  :isBoolean,
			isArray    :isArray,
			isFunction :isFunction,
			isObject   :isObject,
			buildIsType:buildIsType
	    };
	};

	if (typeof module !== 'undefined' && module.exports) {
		module.exports = typist();
	}

	root.typist = typist();

})();<commit_msg>removed redundant comment<commit_after>// typist v0.1.0
// Reliable typeOf function and related utilities.
// (c) 2012 Ben Brooks Scholz
// MIT Licensed.

(function () {
	var root = this;

	var typist = function () {

	    var STRING = {
			'type'       :'string',
			'constructor': String,
			'prototype'  :'[object String]'
	    };

	    var NUMBER = {
			'type'       :'number',
			'constructor': Number,
			'prototype'  :'[object Number]'
	    };

	    var BOOLEAN = {
			'type'       :'boolean',
			'constructor': Boolean,
			'prototype'  :'[object Boolean]'
	    };

	    var ARRAY = {
			'type'       :'array',
			'constructor': Array,
			'prototype'  :'[object Array]'
	    };

	    var OBJECT = {
			'type'       :'object',
			'constructor': Object,
			'prototype'  :'[object Object]'
	    };

	    var FUNCTION = {
			'type'       :'function',
			'constructor': Function,
			'prototype'  :'[object Function]'
	    };

	    var typeOf = function (item) {
			var type = typeof item;
			var prototype;

			if (type === 'string'  || item.constructor === String)   return 'string';
			if (type === 'number'  || item.constructor === Number)   return 'number';
			if (type === 'boolean' || item.constructor === Boolean)  return 'boolean';
			if (type === 'function'|| item.constructor === Function) return 'function';
			if (type === 'array'   || item.constructor === Array)    return 'array';

			prototype = Object.prototype.toString.call(item);

			if (prototype === STRING.prototype)   return 'string';
			if (prototype === NUMBER.prototype)   return 'number';
			if (prototype === BOOLEAN.prototype)  return 'boolean';
			if (prototype === FUNCTION.prototype) return 'function';
			if (prototype === ARRAY.prototype)    return 'array';

			return 'object';
	    };

		var isType = function (item, type) {
			if (item && item.constructor === type.constructor)
		    	return true;
			else if (Object.prototype.toString.call(item) === type.constructor)
		    	return true;
			else
		    	return false;
	    };

	    var isString = function (item) {
			return typeof item === 'string' ? true : isType(item, STRING);
	    };

	    var isNumber = function (item) {
			return typeof item === 'number' ? true : isType(item, NUMBER);
	    };

	    var isBoolean = function (item) {
			return typeof item === 'boolean' ? true : isType(item, BOOLEAN);
	    };

	    var isArray = function (item) {
			return typeof item === 'array' ? true : isType(item, ARRAY);
	    };

	    var isFunction = function (item) {
			return typeof item === 'function' ? true : isType(item, FUNCTION);
	    };

	    var isObject = function (item) {
			return isType(item, OBJECT);
	    };

	    var buildIsType = function (type, constructor) {
			return function (item) {
		    	return isType(item, buildType(type, constructor));
			}
	    };

	    var buildType = function (type, constructor) {
			var upperCaseType = type[0].toUpperCase()+type.slice(1,type.length);
			var prototype     = '[object '+upperCaseType+']';

			return {
				'type'       :'object',
				'constructor':constructor,
			 	'prototype'  :prototype
			};
	    };

	    return {
			typeOf     :typeOf,
			isString   :isString,
			isNumber   :isNumber,
			isBoolean  :isBoolean,
			isArray    :isArray,
			isFunction :isFunction,
			isObject   :isObject,
			buildIsType:buildIsType
	    };
	};

	if (typeof module !== 'undefined' && module.exports) {
		module.exports = typist();
	}

	root.typist = typist();

})();<|endoftext|>


<commit_before>var Key = new function() {
	// TODO: make sure the keys are called the same in Scriptographer
	var keys = {
		 '8': 'backspace',
		'13': 'enter',
		'27': 'escape',
		'32': 'space',
		'37': 'left',
		'38': 'up',
		'39': 'right',
		'40': 'down',
		'46': 'delete',

	};
	var modifierNames = [
		'shift', 'shiftKey',
		'control', 'ctrlKey',
		'alt', 'altKey',
		'command', 'metaKey'
		// TODO: capslock
	];
	var activeKeys = {};

	var eventHandlers = Base.each(['keyDown', 'keyUp'], function(type) {
		var toolHandler = 'on' + Base.capitalize(type),
			down = type == 'keyDown';
		this[type.toLowerCase()] = function(event) {
			var code = event.which || event.keyCode,
				key = keys[code] || String.fromCharCode(code).toLowerCase(),
				modifiers = {};
			activeKeys[key] = down;
			// Add the modifier keys to or remove from the activeKeys
			// and construct the modifiers object to be passed to the
			// key event
			for (var i = 0, l = modifierNames.length; i < l; i += 2) {
				var modifierKey = modifierNames[i];
				if ((down && event[modifierNames[i + 1]])
						|| (!down && modifierKey)) {
					activeKeys[modifierKey] = down;
				}
				modifiers[modifierKey] = down;
			}

			if(paper.tool[toolHandler]) {
				paper.tool[toolHandler]({
					keyCode: code,
					character: key,
					modifiers: modifiers
				});
			}
		}
	}, {});

	Event.add(document, eventHandlers);

	return {
		isDown: function(key) {
			return !!activeKeys[key];
		}
	};
};<commit_msg>Key: add type to the key event.<commit_after>var Key = new function() {
	// TODO: make sure the keys are called the same in Scriptographer
	var keys = {
		 '8': 'backspace',
		'13': 'enter',
		'27': 'escape',
		'32': 'space',
		'37': 'left',
		'38': 'up',
		'39': 'right',
		'40': 'down',
		'46': 'delete',

	};
	var modifierNames = [
		'shift', 'shiftKey',
		'control', 'ctrlKey',
		'alt', 'altKey',
		'command', 'metaKey'
		// TODO: capslock
	];
	var activeKeys = {};

	var eventHandlers = Base.each(['keyDown', 'keyUp'], function(type) {
		var toolHandler = 'on' + Base.capitalize(type),
			down = type == 'keyDown';
		this[type.toLowerCase()] = function(event) {
			var code = event.which || event.keyCode,
				key = keys[code] || String.fromCharCode(code).toLowerCase(),
				modifiers = {};
			activeKeys[key] = down;
			// Add the modifier keys to or remove from the activeKeys
			// and construct the modifiers object to be passed to the
			// key event
			for (var i = 0, l = modifierNames.length; i < l; i += 2) {
				var modifierKey = modifierNames[i];
				if ((down && event[modifierNames[i + 1]])
						|| (!down && modifierKey)) {
					activeKeys[modifierKey] = down;
				}
				modifiers[modifierKey] = down;
			}

			if(paper.tool[toolHandler]) {
				paper.tool[toolHandler]({
					type: down ? 'key-down' : 'key-up',
					keyCode: code,
					character: key,
					modifiers: modifiers
				});
			}
		}
	}, {});

	Event.add(document, eventHandlers);

	return {
		isDown: function(key) {
			return !!activeKeys[key];
		}
	};
};<|endoftext|>


<commit_before>import _ from 'lodash';
import latestVersion from 'latest-version';
import fs from 'fs-extra';
import { exec } from 'child_process';
import { hostname } from 'os';
import { basename } from 'path';
import untildify from 'untildify';
import util from './util';
import packageJson from '../package.json';
import constants from '../conf/constants';
import text from '../conf/text';

let now = Date.now(),
    updateInfo = fs.existsSync(util.getUpdatePath()) ?
        require(util.getUpdatePath()) :
        {
            lastChecked: now,
            version: packageJson.version
        };

let getLatestVersion = _.partial(_.ary(latestVersion, 2), 'sicksync');

function updateRemote (project) {
    let ssh = util.shellIntoRemote(project.username + '@' + project.hostname);

    let updateRemoteOnce = _.once(function(stdin){
        stdin.write(constants.UPDATE_CMD + '\n');
    });

    // Update devbox
    ssh.stdout.on('data', (data) => {
        let message = data.toString();

        if (_.contains(message, 'sicksync@')) {
            console.info(project.hostname, text.UPDATE_SUCCESS);

            return ssh.kill('SIGINT');
        }

        if (_.contains(message, 'ERR!')) {
            console.info(project.hostname, text.UPDATE_FAIL);

            return ssh.kill('SIGINT');
        }

        updateRemoteOnce(ssh.stdin);
    });
}

function updateLocal () {
    exec(constants.UPDATE_CMD,  (error, stdout, stderr) => {
        if (!!error || _.contains(stderr, 'ERR!')) {
            return console.info(hostname, text.UPDATE_FAIL, (error || stderr));
        }

        console.info(hostname(), text.UPDATE_SUCCESS);
    });
}

function update (config, opts) {
    if (opts.check) {
        return getLatestVersion(function(err, version) {
            if (err) return;
            console.info('Latest Version:', version);
            console.info('Current Version:', packageJson.version);
        });
    }

    if (opts.migrateConfig) {
        return migrateConfig(config);
    }

    _.each(config.projects, updateRemote);

    updateLocal();
}

function notify () {
    if (updateInfo.version !== packageJson.version) {
        return console.info(
            text.UPDATE_AVAILABLE, '\n',
            'Current version:', packageJson.version, '\n',
            'Latest version:', updateInfo.version);
    }
}

function check () {
    if (now - updateInfo.lastChecked >= constants.UPDATE_INTERVAL) {
        getLatestVersion(function (err, version) {
            if (err) return;
            fs.writeFileSync(
                util.getUpdatePath(),
                JSON.stringify({
                    version: version,
                    lastChecked: now
                })
            );
        });
    }
}

function migrate1to2(config) {
    if (_.isEmpty(config)) {
        let configLocation = untildify(constants.CONFIG_FILE_V1);
        config = require(configLocation);
        fs.delete(configLocation);
    }

    config.project = basename(config.sourceLocation);

    return {
        version: packageJson.version,
        debug: config.debug,
        retryOnDisconnect: config.retryOnDisconnect,
        projects: [
            _.chain(config)
                .omit('debug', 'retryOnDisconnect')
                .mapKeys(function(value, key) {
                    if (key === 'userName') return 'username';
                    return key;
                })
                .value()
        ]
    };
}

function migrateConfig(config) {
    let configVersion = config.version ? +configVersion.replace('.', '') : null;

    if (!configVersion) {
        util.writeConfig(migrate1to2(config));
    }
}

export default {
    migrate1to2,
    migrateConfig,
    update,
    notify,
    check,
    updateLocal,
    updateRemote,
    getLatestVersion
};
<commit_msg>Small fixe in update helper<commit_after>import _ from 'lodash';
import latestVersion from 'latest-version';
import fs from 'fs-extra';
import { exec } from 'child_process';
import { hostname } from 'os';
import { basename } from 'path';
import untildify from 'untildify';
import util from './util';
import { version as currentVersion } from '../package.json';
import constants from '../conf/constants';
import text from '../conf/text';

let now = Date.now(),
    updateInfo = fs.existsSync(util.getUpdatePath()) ?
        require(util.getUpdatePath()) :
        {
            lastChecked: now,
            version: currentVersion
        };

let getLatestVersion = _.partial(_.ary(latestVersion, 2), 'sicksync');

function updateRemote (project) {
    let ssh = util.shellIntoRemote(project.username + '@' + project.hostname);

    let updateRemoteOnce = _.once(function(stdin){
        stdin.write(constants.UPDATE_CMD + '\n');
    });

    // Update devbox
    ssh.stdout.on('data', (data) => {
        let message = data.toString();

        if (_.contains(message, 'sicksync@')) {
            console.info(project.hostname, text.UPDATE_SUCCESS);

            return ssh.kill('SIGINT');
        }

        if (_.contains(message, 'ERR!')) {
            console.info(project.hostname, text.UPDATE_FAIL);

            return ssh.kill('SIGINT');
        }

        updateRemoteOnce(ssh.stdin);
    });
}

function updateLocal () {
    exec(constants.UPDATE_CMD,  (error, stdout, stderr) => {
        if (!!error || _.contains(stderr, 'ERR!')) {
            return console.info(hostname, text.UPDATE_FAIL, (error || stderr));
        }

        console.info(hostname(), text.UPDATE_SUCCESS);
    });
}

function update (config, opts) {
    if (opts.check) {
        return getLatestVersion(function(err, version) {
            if (err) return;
            console.info('Latest Version:', version);
            console.info('Current Version:', currentVersion);
        });
    }

    if (opts.migrateConfig) {
        return migrateConfig(config);
    }

    _.each(config.projects, updateRemote);

    updateLocal();
}

function notify () {
    if (updateInfo.version !== currentVersion) {
        return console.info(
            text.UPDATE_AVAILABLE, '\n',
            'Current version:', currentVersion, '\n',
            'Latest version:', updateInfo.version);
    }
}

function check () {
    if (now - updateInfo.lastChecked >= constants.UPDATE_INTERVAL) {
        getLatestVersion(function (err, version) {
            if (err) return;
            fs.writeFileSync(
                util.getUpdatePath(),
                JSON.stringify({
                    version: version,
                    lastChecked: now
                })
            );
        });
    }
}

function migrate1to2(config) {
    if (_.isEmpty(config)) {
        let configLocation = untildify(constants.CONFIG_FILE_V1);
        config = require(configLocation);
        fs.delete(configLocation);
    }

    config.project = basename(config.sourceLocation);

    return {
        version: currentVersion,
        debug: config.debug,
        retryOnDisconnect: config.retryOnDisconnect,
        projects: [
            _.chain(config)
                .omit('debug', 'retryOnDisconnect')
                .mapKeys(function(value, key) {
                    if (key === 'userName') return 'username';
                    return key;
                })
                .value()
        ]
    };
}

function migrateConfig(config) {
    let configVersion = config.version ? +configVersion.replace('.', '') : null;

    if (!configVersion) {
        util.writeConfig(migrate1to2(config));
    }
}

export default {
    migrate1to2,
    migrateConfig,
    update,
    notify,
    check,
    updateLocal,
    updateRemote,
    getLatestVersion
};
<|endoftext|>