<commit_before>const path = require('path');
const fs = require('fs');
const snekfetch = require('snekfetch');

const Constants = require('../util/Constants');
const convertToBuffer = require('../util/Util').convertToBuffer;
const User = require('../structures/User');
const Message = require('../structures/Message');
const Guild = require('../structures/Guild');
const Channel = require('../structures/Channel');
const GuildMember = require('../structures/GuildMember');
const Emoji = require('../structures/Emoji');
const ReactionEmoji = require('../structures/ReactionEmoji');

/**
 * The DataResolver identifies different objects and tries to resolve a specific piece of information from them, e.g.
 * extracting a User from a Message object.
 * @private
 */
class ClientDataResolver {
  /**
   * @param {Client} client The client the resolver is for
   */
  constructor(client) {
    this.client = client;
  }

  /**
   * Data that resolves to give a User object. This can be:
   * * A User object
   * * A Snowflake
   * * A Message object (resolves to the message author)
   * * A Guild object (owner of the guild)
   * * A GuildMember object
   * @typedef {User|Snowflake|Message|Guild|GuildMember} UserResolvable
   */

  /**
   * Resolves a UserResolvable to a User object.
   * @param {UserResolvable} user The UserResolvable to identify
   * @returns {?User}
   */
  resolveUser(user) {
    if (user instanceof User) return user;
    if (typeof user === 'string') return this.client.users.get(user) || null;
    if (user instanceof GuildMember) return user.user;
    if (user instanceof Message) return user.author;
    if (user instanceof Guild) return user.owner;
    return null;
  }

  /**
   * Resolves a UserResolvable to a user ID string.
   * @param {UserResolvable} user The UserResolvable to identify
   * @returns {?Snowflake}
   */
  resolveUserID(user) {
    if (user instanceof User || user instanceof GuildMember) return user.id;
    if (typeof user === 'string') return user || null;
    if (user instanceof Message) return user.author.id;
    if (user instanceof Guild) return user.ownerID;
    return null;
  }

  /**
   * Data that resolves to give a Guild object. This can be:
   * * A Guild object
   * * A Snowflake
   * @typedef {Guild|Snowflake} GuildResolvable
   */

  /**
   * Resolves a GuildResolvable to a Guild object.
   * @param {GuildResolvable} guild The GuildResolvable to identify
   * @returns {?Guild}
   */
  resolveGuild(guild) {
    if (guild instanceof Guild) return guild;
    if (typeof guild === 'string') return this.client.guilds.get(guild) || null;
    return null;
  }

  /**
   * Data that resolves to give a GuildMember object. This can be:
   * * A GuildMember object
   * * A User object
   * @typedef {GuildMember|User} GuildMemberResolvable
   */

  /**
   * Resolves a GuildMemberResolvable to a GuildMember object.
   * @param {GuildResolvable} guild The guild that the member is part of
   * @param {UserResolvable} user The user that is part of the guild
   * @returns {?GuildMember}
   */
  resolveGuildMember(guild, user) {
    if (user instanceof GuildMember) return user;
    guild = this.resolveGuild(guild);
    user = this.resolveUser(user);
    if (!guild || !user) return null;
    return guild.members.get(user.id) || null;
  }

  /**
   * Data that can be resolved to give a Channel object. This can be:
   * * A Channel object
   * * A Message object (the channel the message was sent in)
   * * A Guild object (the #general channel)
   * * A Snowflake
   * @typedef {Channel|Guild|Message|Snowflake} ChannelResolvable
   */

  /**
   * Resolves a ChannelResolvable to a Channel object.
   * @param {ChannelResolvable} channel The channel resolvable to resolve
   * @returns {?Channel}
   */
  resolveChannel(channel) {
    if (channel instanceof Channel) return channel;
    if (typeof channel === 'string') return this.client.channels.get(channel) || null;
    if (channel instanceof Message) return channel.channel;
    if (channel instanceof Guild) return channel.channels.get(channel.id) || null;
    return null;
  }

  /**
   * Resolves a ChannelResolvable to a channel ID.
   * @param {ChannelResolvable} channel The channel resolvable to resolve
   * @returns {?Snowflake}
   */
  resolveChannelID(channel) {
    if (channel instanceof Channel) return channel.id;
    if (typeof channel === 'string') return channel;
    if (channel instanceof Message) return channel.channel.id;
    if (channel instanceof Guild) return channel.defaultChannel.id;
    return null;
  }

  /**
   * Data that can be resolved to give an invite code. This can be:
   * * An invite code
   * * An invite URL
   * @typedef {string} InviteResolvable
   */

  /**
   * Resolves InviteResolvable to an invite code.
   * @param {InviteResolvable} data The invite resolvable to resolve
   * @returns {string}
   */
  resolveInviteCode(data) {
    const inviteRegex = /discord(?:app\.com\/invite|\.gg)\/([\w-]{2,255})/i;
    const match = inviteRegex.exec(data);
    if (match && match[1]) return match[1];
    return data;
  }

  /**
   * Data that can be resolved to give a string. This can be:
   * * A string
   * * An array (joined with a new line delimiter to give a string)
   * * Any value
   * @typedef {string|Array|*} StringResolvable
   */

  /**
   * Resolves a StringResolvable to a string.
   * @param {StringResolvable} data The string resolvable to resolve
   * @returns {string}
   */
  resolveString(data) {
    if (typeof data === 'string') return data;
    if (data instanceof Array) return data.join('\n');
    return String(data);
  }

  /**
   * Resolves a Base64Resolvable, a string, or a BufferResolvable to a Base 64 image.
   * @param {string|BufferResolvable|Base64Resolvable} image The image to be resolved
   * @returns {Promise<string>}
   */
  resolveImage(image) {
    if (!image) return Promise.resolve(null);
    if (typeof image === 'string' && image.startsWith('data:')) {
      return Promise.resolve(image);
    }
    return this.resolveFile(image).then(this.resolveBase64);
  }

  /**
   * Data that resolves to give a Base64 string, typically for image uploading. This can be:
   * * A Buffer
   * * A base64 string
   * @typedef {Buffer|string} Base64Resolvable
   */

  /**
   * Resolves a Base64Resolvable to a Base 64 image.
   * @param {Base64Resolvable} data The base 64 resolvable you want to resolve
   * @returns {?string}
   */
  resolveBase64(data) {
    if (data instanceof Buffer) return `data:image/jpg;base64,${data.toString('base64')}`;
    return data;
  }

  /**
    * Data that can be resolved to give a Buffer. This can be:
    * * A Buffer
    * * The path to a local file
    * * A URL
    * * A Stream
    * @typedef {string|Buffer} BufferResolvable
    */

  /**
    * @external Stream
    * @see {@link https://nodejs.org/api/stream.html}
    */

  /**
    * Resolves a BufferResolvable to a Buffer.
    * @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
    * @returns {Promise<Buffer>}
    */
  resolveFile(resource) {
    if (resource instanceof Buffer) return Promise.resolve(resource);
    if (this.client.browser && resource instanceof ArrayBuffer) return Promise.resolve(convertToBuffer(resource));

    if (typeof resource === 'string') {
      return new Promise((resolve, reject) => {
        if (/^https?:\/\//.test(resource)) {
          snekfetch.get(resource)
            .end((err, res) => {
              if (err) return reject(err);
              if (!(res.body instanceof Buffer)) return reject(new TypeError('The response body isn\'t a Buffer.'));
              return resolve(res.body);
            });
        } else {
          const file = path.resolve(resource);
          fs.stat(file, (err, stats) => {
            if (err) return reject(err);
            if (!stats || !stats.isFile()) return reject(new Error(`The file could not be found: ${file}`));
            fs.readFile(file, (err2, data) => {
              if (err2) reject(err2); else resolve(data);
            });
            return null;
          });
        }
      });
    } else if (resource.pipe && typeof resource.pipe === 'function') {
      return new Promise((resolve, reject) => {
        const buffers = [];
        resource.once('error', reject);
        resource.on('data', data => buffers.push(data));
        resource.once('end', () => resolve(Buffer.concat(buffers)));
      });
    }

    return Promise.reject(new TypeError('The resource must be a string or Buffer.'));
  }

  /**
   * Data that can be resolved to give an emoji identifier. This can be:
   * * The unicode representation of an emoji
   * * A custom emoji ID
   * * An Emoji object
   * * A ReactionEmoji object
   * @typedef {string|Emoji|ReactionEmoji} EmojiIdentifierResolvable
   */

  /**
   * Resolves an EmojiResolvable to an emoji identifier.
   * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve
   * @returns {?string}
   */
  resolveEmojiIdentifier(emoji) {
    if (emoji instanceof Emoji || emoji instanceof ReactionEmoji) return emoji.identifier;
    if (typeof emoji === 'string') {
      if (this.client.emojis.has(emoji)) return this.client.emojis.get(emoji).identifier;
      else if (!emoji.includes('%')) return encodeURIComponent(emoji);
      else return emoji;
    }
    return null;
  }

  /**
   * Can be a Hex Literal, Hex String, Number, RGB Array, or one of the following
   * ```
   * [
   *   'DEFAULT',
   *   'AQUA',
   *   'GREEN',
   *   'BLUE',
   *   'PURPLE',
   *   'GOLD',
   *   'ORANGE',
   *   'RED',
   *   'GREY',
   *   'DARKER_GREY',
   *   'NAVY',
   *   'DARK_AQUA',
   *   'DARK_GREEN',
   *   'DARK_BLUE',
   *   'DARK_PURPLE',
   *   'DARK_GOLD',
   *   'DARK_ORANGE',
   *   'DARK_RED',
   *   'DARK_GREY',
   *   'LIGHT_GREY',
   *   'DARK_NAVY',
   *   'RANDOM',
   * ]
   * ```
   * or something like
   * ```
   * [255, 0, 255]
   * ```
   * for purple
   * @typedef {string|number|Array} ColorResolvable
   */

  /**
   * Resolves a ColorResolvable into a color number.
   * @param {ColorResolvable} color Color to resolve
   * @returns {number} A color
   */
  static resolveColor(color) {
    if (typeof color === 'string') {
      if (color === 'RANDOM') return Math.floor(Math.random() * (0xFFFFFF + 1));
      color = Constants.Colors[color] || parseInt(color.replace('#', ''), 16);
    } else if (color instanceof Array) {
      color = (color[0] << 16) + (color[1] << 8) + color[2];
    }

    if (color < 0 || color > 0xFFFFFF) {
      throw new RangeError('Color must be within the range 0 - 16777215 (0xFFFFFF).');
    } else if (color && isNaN(color)) {
      throw new TypeError('Unable to convert color to a number.');
    }

    return color;
  }

  /**
   * @param {ColorResolvable} color Color to resolve
   * @returns {number} A color
   */
  resolveColor(color) {
    return this.constructor.resolveColor(color);
  }
}

module.exports = ClientDataResolver;
<commit_msg>Fix docs on resolveImage<commit_after>const path = require('path');
const fs = require('fs');
const snekfetch = require('snekfetch');

const Constants = require('../util/Constants');
const convertToBuffer = require('../util/Util').convertToBuffer;
const User = require('../structures/User');
const Message = require('../structures/Message');
const Guild = require('../structures/Guild');
const Channel = require('../structures/Channel');
const GuildMember = require('../structures/GuildMember');
const Emoji = require('../structures/Emoji');
const ReactionEmoji = require('../structures/ReactionEmoji');

/**
 * The DataResolver identifies different objects and tries to resolve a specific piece of information from them, e.g.
 * extracting a User from a Message object.
 * @private
 */
class ClientDataResolver {
  /**
   * @param {Client} client The client the resolver is for
   */
  constructor(client) {
    this.client = client;
  }

  /**
   * Data that resolves to give a User object. This can be:
   * * A User object
   * * A Snowflake
   * * A Message object (resolves to the message author)
   * * A Guild object (owner of the guild)
   * * A GuildMember object
   * @typedef {User|Snowflake|Message|Guild|GuildMember} UserResolvable
   */

  /**
   * Resolves a UserResolvable to a User object.
   * @param {UserResolvable} user The UserResolvable to identify
   * @returns {?User}
   */
  resolveUser(user) {
    if (user instanceof User) return user;
    if (typeof user === 'string') return this.client.users.get(user) || null;
    if (user instanceof GuildMember) return user.user;
    if (user instanceof Message) return user.author;
    if (user instanceof Guild) return user.owner;
    return null;
  }

  /**
   * Resolves a UserResolvable to a user ID string.
   * @param {UserResolvable} user The UserResolvable to identify
   * @returns {?Snowflake}
   */
  resolveUserID(user) {
    if (user instanceof User || user instanceof GuildMember) return user.id;
    if (typeof user === 'string') return user || null;
    if (user instanceof Message) return user.author.id;
    if (user instanceof Guild) return user.ownerID;
    return null;
  }

  /**
   * Data that resolves to give a Guild object. This can be:
   * * A Guild object
   * * A Snowflake
   * @typedef {Guild|Snowflake} GuildResolvable
   */

  /**
   * Resolves a GuildResolvable to a Guild object.
   * @param {GuildResolvable} guild The GuildResolvable to identify
   * @returns {?Guild}
   */
  resolveGuild(guild) {
    if (guild instanceof Guild) return guild;
    if (typeof guild === 'string') return this.client.guilds.get(guild) || null;
    return null;
  }

  /**
   * Data that resolves to give a GuildMember object. This can be:
   * * A GuildMember object
   * * A User object
   * @typedef {GuildMember|User} GuildMemberResolvable
   */

  /**
   * Resolves a GuildMemberResolvable to a GuildMember object.
   * @param {GuildResolvable} guild The guild that the member is part of
   * @param {UserResolvable} user The user that is part of the guild
   * @returns {?GuildMember}
   */
  resolveGuildMember(guild, user) {
    if (user instanceof GuildMember) return user;
    guild = this.resolveGuild(guild);
    user = this.resolveUser(user);
    if (!guild || !user) return null;
    return guild.members.get(user.id) || null;
  }

  /**
   * Data that can be resolved to give a Channel object. This can be:
   * * A Channel object
   * * A Message object (the channel the message was sent in)
   * * A Guild object (the #general channel)
   * * A Snowflake
   * @typedef {Channel|Guild|Message|Snowflake} ChannelResolvable
   */

  /**
   * Resolves a ChannelResolvable to a Channel object.
   * @param {ChannelResolvable} channel The channel resolvable to resolve
   * @returns {?Channel}
   */
  resolveChannel(channel) {
    if (channel instanceof Channel) return channel;
    if (typeof channel === 'string') return this.client.channels.get(channel) || null;
    if (channel instanceof Message) return channel.channel;
    if (channel instanceof Guild) return channel.channels.get(channel.id) || null;
    return null;
  }

  /**
   * Resolves a ChannelResolvable to a channel ID.
   * @param {ChannelResolvable} channel The channel resolvable to resolve
   * @returns {?Snowflake}
   */
  resolveChannelID(channel) {
    if (channel instanceof Channel) return channel.id;
    if (typeof channel === 'string') return channel;
    if (channel instanceof Message) return channel.channel.id;
    if (channel instanceof Guild) return channel.defaultChannel.id;
    return null;
  }

  /**
   * Data that can be resolved to give an invite code. This can be:
   * * An invite code
   * * An invite URL
   * @typedef {string} InviteResolvable
   */

  /**
   * Resolves InviteResolvable to an invite code.
   * @param {InviteResolvable} data The invite resolvable to resolve
   * @returns {string}
   */
  resolveInviteCode(data) {
    const inviteRegex = /discord(?:app\.com\/invite|\.gg)\/([\w-]{2,255})/i;
    const match = inviteRegex.exec(data);
    if (match && match[1]) return match[1];
    return data;
  }

  /**
   * Data that can be resolved to give a string. This can be:
   * * A string
   * * An array (joined with a new line delimiter to give a string)
   * * Any value
   * @typedef {string|Array|*} StringResolvable
   */

  /**
   * Resolves a StringResolvable to a string.
   * @param {StringResolvable} data The string resolvable to resolve
   * @returns {string}
   */
  resolveString(data) {
    if (typeof data === 'string') return data;
    if (data instanceof Array) return data.join('\n');
    return String(data);
  }

  /**
   * Resolves a Base64Resolvable, a string, or a BufferResolvable to a Base 64 image.
   * @param {BufferResolvable|Base64Resolvable} image The image to be resolved
   * @returns {Promise<string>}
   */
  resolveImage(image) {
    if (!image) return Promise.resolve(null);
    if (typeof image === 'string' && image.startsWith('data:')) {
      return Promise.resolve(image);
    }
    return this.resolveFile(image).then(this.resolveBase64);
  }

  /**
   * Data that resolves to give a Base64 string, typically for image uploading. This can be:
   * * A Buffer
   * * A base64 string
   * @typedef {Buffer|string} Base64Resolvable
   */

  /**
   * Resolves a Base64Resolvable to a Base 64 image.
   * @param {Base64Resolvable} data The base 64 resolvable you want to resolve
   * @returns {?string}
   */
  resolveBase64(data) {
    if (data instanceof Buffer) return `data:image/jpg;base64,${data.toString('base64')}`;
    return data;
  }

  /**
    * Data that can be resolved to give a Buffer. This can be:
    * * A Buffer
    * * The path to a local file
    * * A URL
    * * A Stream
    * @typedef {string|Buffer} BufferResolvable
    */

  /**
    * @external Stream
    * @see {@link https://nodejs.org/api/stream.html}
    */

  /**
    * Resolves a BufferResolvable to a Buffer.
    * @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
    * @returns {Promise<Buffer>}
    */
  resolveFile(resource) {
    if (resource instanceof Buffer) return Promise.resolve(resource);
    if (this.client.browser && resource instanceof ArrayBuffer) return Promise.resolve(convertToBuffer(resource));

    if (typeof resource === 'string') {
      return new Promise((resolve, reject) => {
        if (/^https?:\/\//.test(resource)) {
          snekfetch.get(resource)
            .end((err, res) => {
              if (err) return reject(err);
              if (!(res.body instanceof Buffer)) return reject(new TypeError('The response body isn\'t a Buffer.'));
              return resolve(res.body);
            });
        } else {
          const file = path.resolve(resource);
          fs.stat(file, (err, stats) => {
            if (err) return reject(err);
            if (!stats || !stats.isFile()) return reject(new Error(`The file could not be found: ${file}`));
            fs.readFile(file, (err2, data) => {
              if (err2) reject(err2); else resolve(data);
            });
            return null;
          });
        }
      });
    } else if (resource.pipe && typeof resource.pipe === 'function') {
      return new Promise((resolve, reject) => {
        const buffers = [];
        resource.once('error', reject);
        resource.on('data', data => buffers.push(data));
        resource.once('end', () => resolve(Buffer.concat(buffers)));
      });
    }

    return Promise.reject(new TypeError('The resource must be a string or Buffer.'));
  }

  /**
   * Data that can be resolved to give an emoji identifier. This can be:
   * * The unicode representation of an emoji
   * * A custom emoji ID
   * * An Emoji object
   * * A ReactionEmoji object
   * @typedef {string|Emoji|ReactionEmoji} EmojiIdentifierResolvable
   */

  /**
   * Resolves an EmojiResolvable to an emoji identifier.
   * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve
   * @returns {?string}
   */
  resolveEmojiIdentifier(emoji) {
    if (emoji instanceof Emoji || emoji instanceof ReactionEmoji) return emoji.identifier;
    if (typeof emoji === 'string') {
      if (this.client.emojis.has(emoji)) return this.client.emojis.get(emoji).identifier;
      else if (!emoji.includes('%')) return encodeURIComponent(emoji);
      else return emoji;
    }
    return null;
  }

  /**
   * Can be a Hex Literal, Hex String, Number, RGB Array, or one of the following
   * ```
   * [
   *   'DEFAULT',
   *   'AQUA',
   *   'GREEN',
   *   'BLUE',
   *   'PURPLE',
   *   'GOLD',
   *   'ORANGE',
   *   'RED',
   *   'GREY',
   *   'DARKER_GREY',
   *   'NAVY',
   *   'DARK_AQUA',
   *   'DARK_GREEN',
   *   'DARK_BLUE',
   *   'DARK_PURPLE',
   *   'DARK_GOLD',
   *   'DARK_ORANGE',
   *   'DARK_RED',
   *   'DARK_GREY',
   *   'LIGHT_GREY',
   *   'DARK_NAVY',
   *   'RANDOM',
   * ]
   * ```
   * or something like
   * ```
   * [255, 0, 255]
   * ```
   * for purple
   * @typedef {string|number|Array} ColorResolvable
   */

  /**
   * Resolves a ColorResolvable into a color number.
   * @param {ColorResolvable} color Color to resolve
   * @returns {number} A color
   */
  static resolveColor(color) {
    if (typeof color === 'string') {
      if (color === 'RANDOM') return Math.floor(Math.random() * (0xFFFFFF + 1));
      color = Constants.Colors[color] || parseInt(color.replace('#', ''), 16);
    } else if (color instanceof Array) {
      color = (color[0] << 16) + (color[1] << 8) + color[2];
    }

    if (color < 0 || color > 0xFFFFFF) {
      throw new RangeError('Color must be within the range 0 - 16777215 (0xFFFFFF).');
    } else if (color && isNaN(color)) {
      throw new TypeError('Unable to convert color to a number.');
    }

    return color;
  }

  /**
   * @param {ColorResolvable} color Color to resolve
   * @returns {number} A color
   */
  resolveColor(color) {
    return this.constructor.resolveColor(color);
  }
}

module.exports = ClientDataResolver;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import {
  StyleSheet,
  Dimensions,
  Platform,
  View,
  TextInput,
  TouchableOpacity,
  Animated,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { filter, some, includes } from 'lodash/collection';
import { debounce } from 'lodash/function';

const INITIAL_TOP = Platform.OS === 'ios' ? -80 : -60;

export default class Search extends Component {

  static propTypes = {
    data: PropTypes.array,
    placeholder: PropTypes.string,
    handleChangeText: PropTypes.func,
    handleSearch: PropTypes.func,
    handleResults: PropTypes.func,
    onHide: PropTypes.func,
    onBack: PropTypes.func,
    heightAdjust: PropTypes.number,
    backgroundColor: PropTypes.string,
    iconColor: PropTypes.string,
    textColor: PropTypes.string,
    placeholderTextColor: PropTypes.string,
    animate: PropTypes.bool,
    animationDuration: PropTypes.number,
    showOnLoad: PropTypes.bool,
    hideBack: PropTypes.bool,
    hideX: PropTypes.bool,
    iOSPadding: PropTypes.bool,
    clearOnShow: PropTypes.bool,
    clearOnHide: PropTypes.bool,
    focusOnLayout: PropTypes.bool,
  }

  static defaultProps = {
    data: [],
    placeholder: 'Search',
    heightAdjust: 0,
    backgroundColor: 'white',
    iconColor: 'gray',
    textColor: 'gray',
    placeholderTextColor: 'lightgray',
    animate: true,
    animationDuration: 200,
    showOnLoad: false,
    hideBack: false,
    hideX: false,
    iOSPadding: true,
    clearOnShow: false,
    clearOnHide: true,
    focusOnLayout: true,
  }

  constructor(props) {
    super(props);
    this.state = {
      input: '',
      show: props.showOnLoad,
      top: new Animated.Value(props.showOnLoad ? 0 : INITIAL_TOP + props.heightAdjust),
    };

    this.hide = this.hide.bind(this);
    this._doHide = this._doHide.bind(this);
    this._onChangeText = this._onChangeText.bind(this);
    this._internalSearch = this._internalSearch.bind(this);
    this._clearInput = this._clearInput.bind(this);
  }

  show() {
    const { animate, animationDuration, clearOnShow } = this.props;
    if (clearOnShow) {
      this.setState({ input: '' })
    }
    this.setState({ show: true });
    if (animate) {
      Animated.timing(
        this.state.top, {
            toValue: 0,
            duration: animationDuration,
        }
      ).start();
    } else {
      this.setState({ top: new Animated.Value(0) })
    }
  }

  hide() {
    const { onHide, animate, animationDuration } = this.props;
    if (onHide) {
      onHide(this.state.input);
    }
    if (animate) {
      Animated.timing(
        this.state.top, {
            toValue: INITIAL_TOP,
            duration: animationDuration,
        }
      ).start();
      setTimeout(() => {
        this._doHide();
      }, animationDuration)
    } else {
      this.setState({ top: new Animated.Value(INITIAL_TOP) })
      this._doHide()
    }
  }

  _doHide() {
    const { clearOnHide } = this.props;
    this.setState({ show: false });
    if (clearOnHide) {
      this.setState({ input: '' });
    }
  }

  _onChangeText(input) {
    const { handleChangeText, handleSearch, handleResults } = this.props;
    this.setState({ input });
    if (handleChangeText) {
      handleChangeText(input);
    }
    if (handleSearch) {
      handleSearch(input);
    } else {
      debounce(() => {
        // use internal search logic (depth first)!
        if (handleResults) {
          const results = this._internalSearch(input);
          handleResults(results);
        }
      }, 500)();
    }
  }

  _internalSearch(input) {
    if (input === '') {
      return [];
    }
    return filter(this.props.data, (item) => {
      return this._depthFirstSearch(item, input)
    });
  }

  _depthFirstSearch(collection, input) {
    // let's get recursive boi
    let type = typeof collection;
    // base case(s)
    if (type === 'string' || type === 'number' || type === 'boolean') {
      return includes(collection.toString().toLowerCase(), input.toString().toLowerCase());
    }
    return some(collection, (item) => this._depthFirstSearch(item, input));
  }

  _clearInput() {
    this.setState({ input: '' });
    this._onChangeText('');
  }

  render() {
    const { placeholder, heightAdjust, backgroundColor, iconColor, textColor, placeholderTextColor, onBack, hideBack, hideX, iOSPadding } = this.props;
    return (
      <Animated.View style={[styles.container, { top: this.state.top }]}>
        {
          this.state.show &&
          <View style={[styles.navWrapper, { backgroundColor }]} >
            {  Platform.OS === 'ios' && iOSPadding && <View style={{ height: 20 }} /> }
            <View style={[
                styles.nav,
                { height: (Platform.OS === 'ios' ? 52 : 62) + heightAdjust },
              ]}
            >
              {
                !hideBack &&
                <TouchableOpacity onPress={onBack || this.hide}>
                  <Icon
                    name='arrow-back'
                    size={28}
                    style={{
                      color: iconColor,
                      padding: heightAdjust / 2 + 10
                    }}
                  />
                </TouchableOpacity>
              }
              <TextInput
                ref={(ref) => this.textInput = ref}
                onLayout={() => this.props.focusOnLayout && this.textInput.focus()}
                style={[
                  styles.input,
                  {
                    color: textColor, marginLeft: hideBack ? 30 : 0,
                    marginTop: (Platform.OS === 'ios' ? heightAdjust / 2 + 10 : 0)
                  }
                ]}
                onChangeText={(input) => this._onChangeText(input)}
                placeholder={placeholder}
                placeholderTextColor={placeholderTextColor}
                value={this.state.input}
                underlineColorAndroid='transparent'
                returnKeyType='search'
              />
            <TouchableOpacity onPress={hideX || this.state.input === '' ? null : this._clearInput}>
                  <Icon
                    name={'close'}
                    size={28}
                    style={{
                      color: hideX || this.state.input == '' ? backgroundColor : iconColor,
                      padding: heightAdjust / 2 + 10
                    }}
                  />
              </TouchableOpacity>
            </View>
          </View>
        }
      </Animated.View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    zIndex: 10,
    position: 'absolute',
    shadowRadius: 5,
    shadowOpacity: 0.7,
    elevation: 2,
  },
  navWrapper: {
    width: Dimensions.get('window').width,
  },
  nav: {
    ...Platform.select({
        android: {
          borderBottomColor: 'lightgray',
          borderBottomWidth: StyleSheet.hairlineWidth,
        },
    }),
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-around',
    alignItems: 'center',
  },
  input: {
    ...Platform.select({
        ios: { height: 30 },
        android: { height: 50 },
    }),
    width: Dimensions.get('window').width - 120,
    fontSize: 20,
  }
});
<commit_msg>Added orientation listener, changed the width of search bar based on orientation<commit_after>import React, { Component, PropTypes } from 'react';
import {
  StyleSheet,
  Dimensions,
  Platform,
  View,
  TextInput,
  TouchableOpacity,
  Animated,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { filter, some, includes } from 'lodash/collection';
import Orientation from 'react-native-orientation';
import { debounce } from 'lodash/function';

const INITIAL_TOP = Platform.OS === 'ios' ? -80 : -60;

export default class Search extends Component {

  static propTypes = {
    data: PropTypes.array,
    placeholder: PropTypes.string,
    handleChangeText: PropTypes.func,
    handleSearch: PropTypes.func,
    handleResults: PropTypes.func,
    onHide: PropTypes.func,
    onBack: PropTypes.func,
    heightAdjust: PropTypes.number,
    backgroundColor: PropTypes.string,
    iconColor: PropTypes.string,
    textColor: PropTypes.string,
    placeholderTextColor: PropTypes.string,
    animate: PropTypes.bool,
    animationDuration: PropTypes.number,
    showOnLoad: PropTypes.bool,
    hideBack: PropTypes.bool,
    hideX: PropTypes.bool,
    iOSPadding: PropTypes.bool,
    clearOnShow: PropTypes.bool,
    clearOnHide: PropTypes.bool,
    focusOnLayout: PropTypes.bool,
  }

  static defaultProps = {
    data: [],
    placeholder: 'Search',
    heightAdjust: 0,
    backgroundColor: 'white',
    iconColor: 'gray',
    textColor: 'gray',
    placeholderTextColor: 'lightgray',
    animate: true,
    animationDuration: 200,
    showOnLoad: false,
    hideBack: false,
    hideX: false,
    iOSPadding: true,
    clearOnShow: false,
    clearOnHide: true,
    focusOnLayout: true,
  }

  constructor(props) {
    super(props);
    this.state = {
      input: '',
      show: props.showOnLoad,
      top: new Animated.Value(props.showOnLoad ? 0 : INITIAL_TOP + props.heightAdjust),
    };

    this.hide = this.hide.bind(this);
    this._doHide = this._doHide.bind(this);
    this._onChangeText = this._onChangeText.bind(this);
    this._internalSearch = this._internalSearch.bind(this);
    this._clearInput = this._clearInput.bind(this);
  }

  componentWillMount = () => {
  var initial = Orientation.getInitialOrientation();
  if (initial === 'PORTRAIT') {
    this.setState({ width: Dimensions.get('window').width});
  } else {
    this.setState({ width: Dimensions.get('window').width, landscape: true });
  }
}

componentDidMount = () => {
  Orientation.addOrientationListener(this.orientationDidChange);
}

orientationDidChange = (orientation) => {
  if (orientation === 'PORTRAIT') {
    this.setState({ width: Dimensions.get('window').width});
  } else {
    this.setState({ width: Dimensions.get('window').width, landscape: true });
  }
}

  show() {
    const { animate, animationDuration, clearOnShow } = this.props;
    if (clearOnShow) {
      this.setState({ input: '' })
    }
    this.setState({ show: true });
    if (animate) {
      Animated.timing(
        this.state.top, {
            toValue: 0,
            duration: animationDuration,
        }
      ).start();
    } else {
      this.setState({ top: new Animated.Value(0) })
    }
  }

  hide() {
    const { onHide, animate, animationDuration } = this.props;
    if (onHide) {
      onHide(this.state.input);
    }
    if (animate) {
      Animated.timing(
        this.state.top, {
            toValue: INITIAL_TOP,
            duration: animationDuration,
        }
      ).start();
      setTimeout(() => {
        this._doHide();
      }, animationDuration)
    } else {
      this.setState({ top: new Animated.Value(INITIAL_TOP) })
      this._doHide()
    }
  }

  _doHide() {
    const { clearOnHide } = this.props;
    this.setState({ show: false });
    if (clearOnHide) {
      this.setState({ input: '' });
    }
  }

  _onChangeText(input) {
    const { handleChangeText, handleSearch, handleResults } = this.props;
    this.setState({ input });
    if (handleChangeText) {
      handleChangeText(input);
    }
    if (handleSearch) {
      handleSearch(input);
    } else {
      debounce(() => {
        // use internal search logic (depth first)!
        if (handleResults) {
          const results = this._internalSearch(input);
          handleResults(results);
        }
      }, 500)();
    }
  }

  _internalSearch(input) {
    if (input === '') {
      return [];
    }
    return filter(this.props.data, (item) => {
      return this._depthFirstSearch(item, input)
    });
  }

  _depthFirstSearch(collection, input) {
    // let's get recursive boi
    let type = typeof collection;
    // base case(s)
    if (type === 'string' || type === 'number' || type === 'boolean') {
      return includes(collection.toString().toLowerCase(), input.toString().toLowerCase());
    }
    return some(collection, (item) => this._depthFirstSearch(item, input));
  }

  _clearInput() {
    this.setState({ input: '' });
    this._onChangeText('');
  }

  render() {
    const { placeholder, heightAdjust, backgroundColor, iconColor, textColor, placeholderTextColor, onBack, hideBack, hideX, iOSPadding } = this.props;
    const { width, landscape } = this.state;
    return (
      <Animated.View style={[styles.container, { top: this.state.top }]}>
        {
          this.state.show &&
          <View style={{ backgroundColor, width }} >
            {  Platform.OS === 'ios' && iOSPadding && <View style={{ height: 20 }} /> }
            <View style={[
                styles.nav,
                { height: (Platform.OS === 'ios' ? 52 : 62) + heightAdjust },
              ]}
            >
              {
                !hideBack &&
                <TouchableOpacity onPress={onBack || this.hide}>
                  <Icon
                    name='arrow-back'
                    size={28}
                    style={{
                      color: iconColor,
                      padding: heightAdjust / 2 + 10
                    }}
                  />
                </TouchableOpacity>
              }
              <TextInput
                ref={(ref) => this.textInput = ref}
                onLayout={() => this.props.focusOnLayout && this.textInput.focus()}
                style={[
                  styles.input,
                  {
                    color: textColor, marginLeft: hideBack ? 30 : 0,
                    marginTop: (Platform.OS === 'ios' ? heightAdjust / 2 + 10 : 0)
                  }
                ]}
                onChangeText={(input) => this._onChangeText(input)}
                placeholder={placeholder}
                placeholderTextColor={placeholderTextColor}
                value={this.state.input}
                underlineColorAndroid='transparent'
                returnKeyType='search'
              />
            <TouchableOpacity onPress={hideX || this.state.input === '' ? null : this._clearInput}>
                  <Icon
                    name={'close'}
                    size={28}
                    style={{
                      color: hideX || this.state.input == '' ? backgroundColor : iconColor,
                      padding: heightAdjust / 2 + 10
                    }}
                  />
              </TouchableOpacity>
            </View>
          </View>
        }
      </Animated.View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    zIndex: 10,
    position: 'absolute',
    shadowRadius: 5,
    shadowOpacity: 0.7,
    elevation: 2,
  },
  nav: {
    ...Platform.select({
        android: {
          borderBottomColor: 'lightgray',
          borderBottomWidth: StyleSheet.hairlineWidth,
        },
    }),
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-around',
    alignItems: 'center',
  },
  input: {
    ...Platform.select({
        ios: { height: 30 },
        android: { height: 50 },
    }),
    width: Dimensions.get('window').width - 120,
    fontSize: 20,
  }
});
<|endoftext|>


<commit_before><commit_msg>Update project webtorrent to 0.78.0<commit_after><|endoftext|>


<commit_before>import config from 'config';
import _ from 'lodash';
import Promise from 'bluebird';
import juice from 'juice';
import nodemailer from 'nodemailer';

const debug = require('debug')('email');
const templates = require('./loadEmailTemplates')();
import activities from '../constants/activities';
import utils from './utils';
import crypto from 'crypto';

const render = (name, data, config) => {
    data.config = config;
    data.logoNotSvg = data.group && data.group.logo && !data.group.logo.endsWith('.svg');
    return templates[name](data);
};

const generateUnsubscribeToken = (email, groupSlug, type) => {
  const uid = `${email}.${groupSlug}.${type}.${config.keys.opencollective.resetPasswordSecret}`;
  return crypto.createHash('md5').update(uid).digest("hex");
}

/*
 * Gets the body from a string (usually a template)
 */
const getBody = str => str.split('\n').slice(2).join('\n');

/*
 * Appends appropriate prefix and cleans up subject
 */
const getSubject = str => {
    let subj = '';
    if (process.env.NODE_ENV === 'staging') {
      subj += '[STAGING] ';
    } else if (process.env.NODE_ENV !== 'production'){
      subj += '[TESTING] ';
    }
    subj += str.split('\n')[0].replace(/^Subject: ?/i, '');
    return subj;
};

/*
 * sends an email message to a recipient with given subject and body
 */
const sendMessage = (recipient, subject, html, options) => {
  options = options || {};
  debug("email: ", recipient, subject, html, options);

  // if not in production, only send out emails to bcc'd opencollective address
  if (process.env.NODE_ENV !== 'production' && !utils.isEmailInternal(recipient)) {
    recipient = '';
  }

  if (config.mailgun.user) {
    const mailgun = nodemailer.createTransport({
      service: 'Mailgun',
      auth: {
        user: config.mailgun.user,
        pass: config.mailgun.password
      }
    });

    return new Promise((resolve, reject) => {
      mailgun.sendMail({
        from: options.from || config.email.from,
        to: recipient,
        bcc: `ops@opencollective.com,${options.bcc}`,
        subject,
        html
      }, (err, info) => {
        if (err) {
          return reject(err);
        } else {
          return resolve(info);
        }
      })
    });
  } else {
    console.warn("Warning: No mail sent - Mailgun is not configured");
    return Promise.resolve();
  }
};

const getNotificationLabel = (template, recipient) => {

  const notificationTypeLabels = {
    'group.monthlyreport': 'monthly reports',
    'group.transaction.created': 'notifications of new transactions for this collective',
    'email.approve': 'notifications of new emails pending approval',
    'email.message': recipient
  }

  return notificationTypeLabels[template];

};

/*
 * Given a template, recipient and data, generates email.
 */

const generateEmailFromTemplate = (template, recipient, data, options) => {

  options = options || {};

  data.notificationTypeLabel = getNotificationLabel(template, recipient);

  if (template === 'thankyou') {
    if (data.group.name.match(/WWCode/i))
      template += '.wwcode';
    if (data.group.name.match(/ispcwa/i))
      template += '.ispcwa';
    if (_.contains(['lesbarbares', 'nuitdebout', 'laprimaire'], data.group.slug)) {
      template += '.fr';

      if (data.group.slug === 'laprimaire')
        template = 'thankyou.laprimaire';

      // xdamman: hack
      switch (data.interval) {
        case 'month':
          data.interval = 'mois';
          break;
        case 'year':
          data.interval = 'an';
          break;
      }
    }
  }

  if (template === 'group.transaction.created') {
    template = (data.transaction.amount > 0) ? 'group.donation.created' : 'group.expense.created';
    if (data.user && data.user.twitterHandle) {
      const groupMention = (data.group.twitterHandle) ? `@${data.group.twitterHandle}` : data.group.name;
      const text = `Hi @${data.user.twitterHandle} thanks for your donation to ${groupMention} https://opencollective.com/${data.group.slug} 🎉😊`;
      data.tweet = {
        text,
        encoded: encodeURIComponent(text)
      };
    }
  }

  const slug = (data.group && data.group.slug) ? data.group.slug : 'undefined';
  data.unsubscribeUrl = `${config.host.website}/api/services/email/unsubscribe/${encodeURIComponent(options.bcc || recipient)}/${slug}/${options.type || template}/${generateUnsubscribeToken(options.bcc || recipient, slug, options.type)}`;

  if (!templates[template]) {
    return Promise.reject(new Error("Invalid email template"));
  }
  return Promise.resolve(juice(render(template, data, config)));
};

/*
 * Given a template, recipient and data, generates email and sends it.
 * Deprecated. Should use sendMessageFromActivity() for sending new emails.
 */
const generateEmailFromTemplateAndSend = (template, recipient, data, options) => {
  return generateEmailFromTemplate(template, recipient, data, options)
    .then(templateString => emailLib.sendMessage(recipient, getSubject(templateString), getBody(templateString), options));
};

/*
 * Given an activity, it sends out an email to the right people and right template
 */
const sendMessageFromActivity = (activity, notification) => {
  if (activity.type === activities.GROUP_TRANSACTION_CREATED) {
    return generateEmailFromTemplateAndSend('group.transaction.created', notification.User.email, activity.data);
  } else {
    return Promise.resolve();
  }
}

const emailLib = {
  getBody,
  getSubject,
  sendMessage,
  generateEmailFromTemplate,
  send: generateEmailFromTemplateAndSend,
  sendMessageFromActivity
};

export default emailLib;<commit_msg>making tests great again<commit_after>import config from 'config';
import _ from 'lodash';
import Promise from 'bluebird';
import juice from 'juice';
import nodemailer from 'nodemailer';

const debug = require('debug')('email');
const templates = require('./loadEmailTemplates')();
import activities from '../constants/activities';
import utils from './utils';
import crypto from 'crypto';

const render = (name, data, config) => {
    data.config = config;
    data.logoNotSvg = data.group && data.group.logo && !data.group.logo.endsWith('.svg');
    return templates[name](data);
};

const generateUnsubscribeToken = (email, groupSlug, type) => {
  const uid = `${email}.${groupSlug}.${type}.${config.keys.opencollective.resetPasswordSecret}`;
  return crypto.createHash('md5').update(uid).digest("hex");
}

/*
 * Gets the body from a string (usually a template)
 */
const getBody = str => str.split('\n').slice(2).join('\n');

/*
 * Appends appropriate prefix and cleans up subject
 */
const getSubject = str => {
    let subj = '';
    if (process.env.NODE_ENV === 'staging') {
      subj += '[STAGING] ';
    } else if (process.env.NODE_ENV !== 'production'){
      subj += '[TESTING] ';
    }
    subj += str.split('\n')[0].replace(/^Subject: ?/i, '');
    return subj;
};

/*
 * sends an email message to a recipient with given subject and body
 */
const sendMessage = (recipient, subject, html, options) => {
  options = options || {};
  debug("email: ", recipient, subject, html, options);

  // if not in production, only send out emails to bcc'd opencollective address
  if (process.env.NODE_ENV !== 'production' && !utils.isEmailInternal(recipient)) {
    recipient = '';
  }

  if (config.mailgun.user) {
    const mailgun = nodemailer.createTransport({
      service: 'Mailgun',
      auth: {
        user: config.mailgun.user,
        pass: config.mailgun.password
      }
    });

    return new Promise((resolve, reject) => {
      mailgun.sendMail({
        from: options.from || config.email.from,
        to: recipient,
        bcc: `ops@opencollective.com,${options.bcc}`,
        subject,
        html
      }, (err, info) => {
        if (err) {
          return reject(err);
        } else {
          return resolve(info);
        }
      })
    });
  } else {
    console.warn("Warning: No mail sent - Mailgun is not configured");
    return Promise.resolve();
  }
};

const getNotificationLabel = (template, recipient) => {

  const notificationTypeLabels = {
    'group.monthlyreport': 'monthly reports',
    'group.transaction.created': 'notifications of new transactions for this collective',
    'email.approve': 'notifications of new emails pending approval',
    'email.message': recipient
  }

  return notificationTypeLabels[template];

};

/*
 * Given a template, recipient and data, generates email.
 */

const generateEmailFromTemplate = (template, recipient, data, options) => {

  options = options || {};

  if (template === 'thankyou') {
    if (data.group.name.match(/WWCode/i))
      template += '.wwcode';
    if (data.group.name.match(/ispcwa/i))
      template += '.ispcwa';
    if (_.contains(['lesbarbares', 'nuitdebout', 'laprimaire'], data.group.slug)) {
      template += '.fr';

      if (data.group.slug === 'laprimaire')
        template = 'thankyou.laprimaire';

      // xdamman: hack
      switch (data.interval) {
        case 'month':
          data.interval = 'mois';
          break;
        case 'year':
          data.interval = 'an';
          break;
      }
    }
  }

  if (template === 'group.transaction.created') {
    template = (data.transaction.amount > 0) ? 'group.donation.created' : 'group.expense.created';
    if (data.user && data.user.twitterHandle) {
      const groupMention = (data.group.twitterHandle) ? `@${data.group.twitterHandle}` : data.group.name;
      const text = `Hi @${data.user.twitterHandle} thanks for your donation to ${groupMention} https://opencollective.com/${data.group.slug} 🎉😊`;
      data.tweet = {
        text,
        encoded: encodeURIComponent(text)
      };
    }
  }

  const slug = (data.group && data.group.slug) ? data.group.slug : 'undefined';
  data.unsubscribeUrl = `${config.host.website}/api/services/email/unsubscribe/${encodeURIComponent(options.bcc || recipient)}/${slug}/${options.type || template}/${generateUnsubscribeToken(options.bcc || recipient, slug, options.type)}`;
  data.notificationTypeLabel = getNotificationLabel(template, recipient);

  if (!templates[template]) {
    return Promise.reject(new Error("Invalid email template"));
  }
  return Promise.resolve(juice(render(template, data, config)));
};

/*
 * Given a template, recipient and data, generates email and sends it.
 * Deprecated. Should use sendMessageFromActivity() for sending new emails.
 */
const generateEmailFromTemplateAndSend = (template, recipient, data, options) => {
  return generateEmailFromTemplate(template, recipient, data, options)
    .then(templateString => emailLib.sendMessage(recipient, getSubject(templateString), getBody(templateString), options));
};

/*
 * Given an activity, it sends out an email to the right people and right template
 */
const sendMessageFromActivity = (activity, notification) => {
  if (activity.type === activities.GROUP_TRANSACTION_CREATED) {
    return generateEmailFromTemplateAndSend('group.transaction.created', notification.User.email, activity.data);
  } else {
    return Promise.resolve();
  }
}

const emailLib = {
  getBody,
  getSubject,
  sendMessage,
  generateEmailFromTemplate,
  send: generateEmailFromTemplateAndSend,
  sendMessageFromActivity
};

export default emailLib;<|endoftext|>


<commit_before>var VirtualJoystick	= function(opts)
{
	opts			= opts			|| {};
	this._container		= opts.container	|| document.body;
	this._strokeStyle	= opts.strokeStyle	|| 'cyan';
	this._stickEl		= opts.stickElement	|| this._buildJoystickStick();
	this._baseEl		= opts.baseElement	|| this._buildJoystickBase();
	this._mouseSupport	= opts.mouseSupport !== undefined ? opts.mouseSupport : false;
	this._stationaryBase	= opts.stationaryBase || false;
	this._baseX		= this._stickX = opts.baseX || 0
	this._baseY		= this._stickY = opts.baseY || 0
	this._limitStickTravel	= opts.limitStickTravel || false
	this._stickRadius	= opts.stickRadius !== undefined ? opts.stickRadius : 100
	this._useCssTransform	= opts.useCssTransform !== undefined ? opts.useCssTransform : false

	this._container.style.position	= "relative"

	this._container.appendChild(this._baseEl)
	this._baseEl.style.position	= "absolute"
	this._baseEl.style.display	= "none"
	this._container.appendChild(this._stickEl)
	this._stickEl.style.position	= "absolute"
	this._stickEl.style.display	= "none"

	this._pressed	= false;
	this._touchIdx	= null;

	if(this._stationaryBase === true){
		this._baseEl.style.display	= "";
		this._baseEl.style.left		= (this._baseX - this._baseEl.width /2)+"px";
		this._baseEl.style.top		= (this._baseY - this._baseEl.height/2)+"px";
	}

	this._transform	= this._useCssTransform ? this._getTransformProperty() : false;
	this._has3d	= this._check3D();

	var __bind	= function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
	this._$onTouchStart	= __bind(this._onTouchStart	, this);
	this._$onTouchEnd	= __bind(this._onTouchEnd	, this);
	this._$onTouchMove	= __bind(this._onTouchMove	, this);
	this._container.addEventListener( 'touchstart'	, this._$onTouchStart	, false );
	this._container.addEventListener( 'touchend'	, this._$onTouchEnd	, false );
	this._container.addEventListener( 'touchmove'	, this._$onTouchMove	, false );
	if( this._mouseSupport ){
		this._$onMouseDown	= __bind(this._onMouseDown	, this);
		this._$onMouseUp	= __bind(this._onMouseUp	, this);
		this._$onMouseMove	= __bind(this._onMouseMove	, this);
		this._container.addEventListener( 'mousedown'	, this._$onMouseDown	, false );
		this._container.addEventListener( 'mouseup'	, this._$onMouseUp	, false );
		this._container.addEventListener( 'mousemove'	, this._$onMouseMove	, false );
	}
}

VirtualJoystick.prototype.destroy	= function()
{
	this._container.removeChild(this._baseEl);
	this._container.removeChild(this._stickEl);

	this._container.removeEventListener( 'touchstart'	, this._$onTouchStart	, false );
	this._container.removeEventListener( 'touchend'		, this._$onTouchEnd	, false );
	this._container.removeEventListener( 'touchmove'	, this._$onTouchMove	, false );
	if( this._mouseSupport ){
		this._container.removeEventListener( 'mouseup'		, this._$onMouseUp	, false );
		this._container.removeEventListener( 'mousedown'	, this._$onMouseDown	, false );
		this._container.removeEventListener( 'mousemove'	, this._$onMouseMove	, false );
	}
}

/**
 * @returns {Boolean} true if touchscreen is currently available, false otherwise
*/
VirtualJoystick.touchScreenAvailable	= function()
{
	return 'createTouch' in document ? true : false;
}

/**
 * microevents.js - https://github.com/jeromeetienne/microevent.js
*/
;(function(destObj){
	destObj.addEventListener	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		this._events[event] = this._events[event]	|| [];
		this._events[event].push(fct);
		return fct;
	};
	destObj.removeEventListener	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		if( event in this._events === false  )	return;
		this._events[event].splice(this._events[event].indexOf(fct), 1);
	};
	destObj.dispatchEvent		= function(event /* , args... */){
		if(this._events === undefined) 	this._events	= {};
		if( this._events[event] === undefined )	return;
		var tmpArray	= this._events[event].slice();
		for(var i = 0; i < tmpArray.length; i++){
			var result	= tmpArray[i].apply(this, Array.prototype.slice.call(arguments, 1))
			if( result !== undefined )	return result;
		}
		return undefined
	};
})(VirtualJoystick.prototype);

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype.deltaX	= function(){ return this._stickX - this._baseX;	}
VirtualJoystick.prototype.deltaY	= function(){ return this._stickY - this._baseY;	}

VirtualJoystick.prototype.up	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaY >= 0 )				return false;
	if( Math.abs(deltaX) > 2*Math.abs(deltaY) )	return false;
	return true;
}
VirtualJoystick.prototype.down	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaY <= 0 )				return false;
	if( Math.abs(deltaX) > 2*Math.abs(deltaY) )	return false;
	return true;
}
VirtualJoystick.prototype.right	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaX <= 0 )				return false;
	if( Math.abs(deltaY) > 2*Math.abs(deltaX) )	return false;
	return true;
}
VirtualJoystick.prototype.left	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaX >= 0 )				return false;
	if( Math.abs(deltaY) > 2*Math.abs(deltaX) )	return false;
	return true;
}

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype._onUp	= function()
{
	this._pressed	= false;
	this._stickEl.style.display	= "none";

	if(this._stationaryBase == false){
		this._baseEl.style.display	= "none";

		this._baseX	= this._baseY	= 0;
		this._stickX	= this._stickY	= 0;
	}
}

VirtualJoystick.prototype._onDown	= function(x, y)
{
	this._pressed	= true;
	if(this._stationaryBase == false){
		this._baseX	= x;
		this._baseY	= y;
		this._baseEl.style.display	= "";
		this._move(this._baseEl.style, (this._baseX - this._baseEl.width /2), (this._baseY - this._baseEl.height/2));
	}

	this._stickX	= x;
	this._stickY	= y;

	if(this._limitStickTravel === true){
		var deltaX	= this.deltaX();
		var deltaY	= this.deltaY();
		var stickDistance = Math.sqrt( (deltaX * deltaX) + (deltaY * deltaY) );
		if(stickDistance > this._stickRadius){
			var stickNormalizedX = deltaX / stickDistance;
			var stickNormalizedY = deltaY / stickDistance;

			this._stickX = stickNormalizedX * this._stickRadius + this._baseX;
			this._stickY = stickNormalizedY * this._stickRadius + this._baseY;
		}
	}

	this._stickEl.style.display	= "";
	this._move(this._stickEl.style, (this._stickX - this._stickEl.width /2), (this._stickY - this._stickEl.height/2));
}

VirtualJoystick.prototype._onMove	= function(x, y)
{
	if( this._pressed === true ){
		this._stickX	= x;
		this._stickY	= y;

		if(this._limitStickTravel === true){
			var deltaX	= this.deltaX();
			var deltaY	= this.deltaY();
			var stickDistance = Math.sqrt( (deltaX * deltaX) + (deltaY * deltaY) );
			if(stickDistance > this._stickRadius){
				var stickNormalizedX = deltaX / stickDistance;
				var stickNormalizedY = deltaY / stickDistance;

				this._stickX = stickNormalizedX * this._stickRadius + this._baseX;
				this._stickY = stickNormalizedY * this._stickRadius + this._baseY;
			}
		}

        	this._move(this._stickEl.style, (this._stickX - this._stickEl.width /2), (this._stickY - this._stickEl.height/2));
	}
}

//////////////////////////////////////////////////////////////////////////////////
//		bind touch events (and mouse events for debug)			//
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype._onMouseUp	= function(event)
{
	return this._onUp();
}

VirtualJoystick.prototype._onMouseDown	= function(event)
{
	event.preventDefault();
	var x	= event.clientX;
	var y	= event.clientY;
	return this._onDown(x, y);
}

VirtualJoystick.prototype._onMouseMove	= function(event)
{
	var x	= event.clientX;
	var y	= event.clientY;
	return this._onMove(x, y);
}

//////////////////////////////////////////////////////////////////////////////////
//		comment								//
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype._onTouchStart	= function(event)
{
	// if there is already a touch inprogress do nothing
	if( this._touchIdx !== null )	return;

	// notify event for validation
	var isValid	= this.dispatchEvent('touchStartValidation', event);
	if( isValid === false )	return;

	// dispatch touchStart
	this.dispatchEvent('touchStart', event);

	event.preventDefault();
	// get the first who changed
	var touch	= event.changedTouches[0];
	// set the touchIdx of this joystick
	this._touchIdx	= touch.identifier;

	// forward the action
	var x		= touch.pageX;
	var y		= touch.pageY;
	return this._onDown(x, y)
}

VirtualJoystick.prototype._onTouchEnd	= function(event)
{
	// if there is no touch in progress, do nothing
	if( this._touchIdx === null )	return;

	// dispatch touchEnd
	this.dispatchEvent('touchEnd', event);

	// try to find our touch event
	var touchList	= event.changedTouches;
	for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++);
	// if touch event isnt found,
	if( i === touchList.length)	return;

	// reset touchIdx - mark it as no-touch-in-progress
	this._touchIdx	= null;

//??????
// no preventDefault to get click event on ios
event.preventDefault();

	return this._onUp()
}

VirtualJoystick.prototype._onTouchMove	= function(event)
{
	// if there is no touch in progress, do nothing
	if( this._touchIdx === null )	return;

	// try to find our touch event
	var touchList	= event.changedTouches;
	for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++ );
	// if touch event with the proper identifier isnt found, do nothing
	if( i === touchList.length)	return;
	var touch	= touchList[i];

	event.preventDefault();

	var x		= touch.pageX;
	var y		= touch.pageY;
	return this._onMove(x, y)
}

//////////////////////////////////////////////////////////////////////////////////
//		build default stickEl and baseEl				//
//////////////////////////////////////////////////////////////////////////////////

/**
 * build the canvas for joystick base
 */
VirtualJoystick.prototype._buildJoystickBase	= function()
{
	var canvas	= document.createElement( 'canvas' );
	canvas.width	= 126;
	canvas.height	= 126;

	var ctx		= canvas.getContext('2d');
	ctx.beginPath();
	ctx.strokeStyle = this._strokeStyle;
	ctx.lineWidth	= 6;
	ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);
	ctx.stroke();

	ctx.beginPath();
	ctx.strokeStyle	= this._strokeStyle;
	ctx.lineWidth	= 2;
	ctx.arc( canvas.width/2, canvas.width/2, 60, 0, Math.PI*2, true);
	ctx.stroke();

	return canvas;
}

/**
 * build the canvas for joystick stick
 */
VirtualJoystick.prototype._buildJoystickStick	= function()
{
	var canvas	= document.createElement( 'canvas' );
	canvas.width	= 86;
	canvas.height	= 86;
	var ctx		= canvas.getContext('2d');
	ctx.beginPath();
	ctx.strokeStyle	= this._strokeStyle;
	ctx.lineWidth	= 6;
	ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);
	ctx.stroke();
	return canvas;
}

//////////////////////////////////////////////////////////////////////////////////
//		move using translate3d method with fallback to translate > 'top' and 'left'
//      modified from https://github.com/component/translate and dependents
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype._move = function(style, x, y)
{
	if (this._transform) {
		if (this._has3d) {
			style[this._transform] = 'translate3d(' + x + 'px,' + y + 'px, 0)';
		} else {
			style[this._transform] = 'translate(' + x + 'px,' + y + 'px)';
		}
	} else {
		style.left = x + 'px';
		style.top = y + 'px';
	}
}

VirtualJoystick.prototype._getTransformProperty = function()
{
	var styles = [
		'webkitTransform',
		'MozTransform',
		'msTransform',
		'OTransform',
		'transform'
	];

	var el = document.createElement('p');
	var style;

	for (var i = 0; i < styles.length; i++) {
		style = styles[i];
		if (null != el.style[style]) {
			return style;
		}
	}
}

VirtualJoystick.prototype._check3D = function()
{
	var prop = this._getTransformProperty();
	// IE8<= doesn't have `getComputedStyle`
	if (!prop || !window.getComputedStyle) return module.exports = false;

	var map = {
		webkitTransform: '-webkit-transform',
		OTransform: '-o-transform',
		msTransform: '-ms-transform',
		MozTransform: '-moz-transform',
		transform: 'transform'
	};

	// from: https://gist.github.com/lorenzopolidori/3794226
	var el = document.createElement('div');
	el.style[prop] = 'translate3d(1px,1px,1px)';
	document.body.insertBefore(el, null);
	var val = getComputedStyle(el).getPropertyValue(map[prop]);
	document.body.removeChild(el);
	var exports = null != val && val.length && 'none' != val;
	return exports;
}
<commit_msg>Delete virtualjoystick.js<commit_after><|endoftext|>


<commit_before>
/* !
 * matrix2
 * JavaScript math library for 2d matrix
 * Copyright (c) 2012 Enrico Marino (http://onirame.no.de)
 * MIT License
 */

 !(function (exports) {

  /**
   * Library namespace.
   */

  var matrix2 = exports.matrix2 = {};

  /**
   * Library version.
   */

  matrix2.version = '0.0.0';

  /**
   * create
   * Create a 2d matrix.
   *
   * @param {Float32Array} values values
   * @return {Float32Array} 2d matrix
   * @api public
   */

  matrix2.create = function (values) {
    return new Float32Array(values || [1.0, 0.0, 0.0, 1.0]);
  };

  /**
   * copy
   * Copy a 2d matrix.
   *
   * @param {Float32Array} self destination matrix
   * @param {Float32Array} m source matrix
   * @return {Float32Array} destination matrix
   * @api public
   */

  matrix2.copy = function (self, m) {
    self[0] = m[0];
    self[1] = m[1];

    self[2] = m[2];
    self[3] = m[3];

    return self;
  };

}(this));<commit_msg>added matrix2.zero<commit_after>
/* !
 * matrix2
 * JavaScript math library for 2d matrix
 * Copyright (c) 2012 Enrico Marino (http://onirame.no.de)
 * MIT License
 */

 !(function (exports) {

  /**
   * Library namespace.
   */

  var matrix2 = exports.matrix2 = {};

  /**
   * Library version.
   */

  matrix2.version = '0.0.0';

  /**
   * create
   * Create a 2d matrix.
   *
   * @param {Float32Array} values values
   * @return {Float32Array} 2d matrix
   * @api public
   */

  matrix2.create = function (values) {
    return new Float32Array(values || [1.0, 0.0, 0.0, 1.0]);
  };

  /**
   * copy
   * Copy a 2d matrix.
   *
   * @param {Float32Array} self destination matrix
   * @param {Float32Array} m source matrix
   * @return {Float32Array} destination matrix
   * @api public
   */

  matrix2.copy = function (self, m) {
    self[0] = m[0];
    self[1] = m[1];

    self[2] = m[2];
    self[3] = m[3];

    return self;
  };

  /**
   * zero
   * Set a 2d matrix to zero.
   *
   * @param {Float32Array} self destination matrix
   * @return {Float32Array} destination matrix
   * @api public
   */

  matrix2.zero = function (self) {
    self[0] = 0.0;
    self[1] = 0.0;

    self[2] = 0.0;
    self[3] = 0.0;

    return self;
  };

}(this));<|endoftext|>


<commit_before>var SERVER_IP = '127.0.0.1';

var port = process.env.PORT    || 3000;
// var ssl  = process.env.SSLPORT || 4000;

// Module dependencies
var http = require('http');
// var https = require('https');

/*
var options = {
  key:  fs.readFileSync('/private/etc/apache2/ssl/ssl.key'),
  cert: fs.readFileSync('/private/etc/apache2/ssl/ssl.crt')
};
*/

var server = require('./dist/examples/app/server/server')(__dirname);

// Start server
module.exports.Server = http.createServer(server).listen(port, SERVER_IP, function() {
  console.log('Listening on port: ' + port);

  // for smoke testing

  var req = http.get({
    host: 'localhost',
    port: 3000,
    path: '/?server=true&client=false&preboot=false&bootstrap=false',
  }, function(res) {
    // console.log('STATUS: ' + res.statusCode);
    // console.log('HEADERS: ' + JSON.stringify(res.headers, null, 2));

    // Buffer the body entirely for processing as a whole.
    var bodyChunks = [];
    res.
      on('data', function(chunk) {
        // You can process streamed parts here...
        bodyChunks.push(chunk);
      }).
      on('end', function() {
        var body = Buffer.concat(bodyChunks);
        // console.log('GOOD' /*, body.toString()*/ );
        // ...and/or process the entire body here.
      })
  });

  req.on('error', function(e) {
    console.error('ERROR: ' + e.message);
  });

});
/*
https.createServer(options, server).listen(ssl, function() {
  console.log('Listening on port: ' + ssl + ' in ' + process.env.NODE_ENV);
});
*/
<commit_msg>feat(index.js): hoist smokeTest<commit_after>var SERVER_IP = '127.0.0.1';

var port = process.env.PORT    || 3000;
// var ssl  = process.env.SSLPORT || 4000;

// Module dependencies
var http = require('http');
// var https = require('https');

/*
var options = {
  key:  fs.readFileSync('/private/etc/apache2/ssl/ssl.key'),
  cert: fs.readFileSync('/private/etc/apache2/ssl/ssl.crt')
};
*/

var server = require('./dist/examples/app/server/server')(__dirname);

// Start server
module.exports.Server = http.createServer(server).listen(port, SERVER_IP, function() {
  console.log('Listening on port: ' + port);
  // for smoke testing
  smokeTest();
});
/*
https.createServer(options, server).listen(ssl, function() {
  console.log('Listening on port: ' + ssl + ' in ' + process.env.NODE_ENV);
});
*/

function smokeTest() {
  var req = http.get({
    host: 'localhost',
    port: 3000,
    path: '/?server=true&client=false&preboot=false&bootstrap=false',
  }, function(res) {
    // console.log('STATUS: ' + res.statusCode);
    // console.log('HEADERS: ' + JSON.stringify(res.headers, null, 2));

    // Buffer the body entirely for processing as a whole.
    var bodyChunks = [];
    res.
      on('data', function(chunk) {
        // You can process streamed parts here...
        bodyChunks.push(chunk);
      }).
      on('end', function() {
        var body = Buffer.concat(bodyChunks);
        // console.log('GOOD' /*, body.toString()*/ );
        // ...and/or process the entire body here.
      })
  });

  req.on('error', function(e) {
    console.error('ERROR: ' + e.message);
  });
}
<|endoftext|>


<commit_before>VERSION = 'development';
System.import('app').catch(function(err) { console.error(err); });<commit_msg>fix version in strict mode<commit_after>var VERSION = 'development';
System.import('app').catch(function(err) { console.error(err); });<|endoftext|>


<commit_before>#!/usr/bin/env node
var npm = require("npm");
var argv = process.argv;

if (argv.length < 4) {
  console.log('Usage: pkg [command] [package]');
  process.exit(0);
}

var command = argv[2];
var packages = [];

for (var index = 3, total = argv.length; index !== total; ++index) {
  packages.push(argv[index]);
}

var installPkg = function (pkgs) {
  'use strict';
  npm.load(npm.config, function (err) {
    if (err) {
      console.error(err);
      return;
    }

    npm.commands.install(pkgs, function (er, data) {
      if (er) {
        console.error(er);
      }
      console.log(data);
    });

    npm.on("log", function (message) {
      // log the progress of the installation
      console.log(message);
    });
  });
};

var uninstallPkg = function (pkgs) {
  'use strict';
  npm.load(npm.config, function (err) {
    if (err) {
      console.error(err);
      return;
    }

    npm.commands.uninstall(pkgs, function (er, data) {
      if (er) {
        console.error(er);
      }
      console.log(data);
    });

    npm.on("log", function (message) {
      // log the progress of the uninstallation
      console.log(message);
    });
  });
};

if (command === 'install') {
  installPkg(packages);
}
else if (command === 'uninstall' || command === 'remove') {
  uninstallPkg(packages);
}

<commit_msg>Error fixed by removing npm.config<commit_after>#!/usr/bin/env node
var npm = require("npm");
var argv = process.argv;

if (argv.length < 4) {
  console.log('Usage: pkg [command] [package]');
  process.exit(0);
}

var command = argv[2];
var packages = [];

for (var index = 3, total = argv.length; index !== total; ++index) {
  packages.push(argv[index]);
}

var installPkg = function (pkgs) {
  'use strict';
  npm.load({}, function (err) {
    if (err) {
      console.error(err);
      return;
    }

    npm.commands.install(pkgs, function (er, data) {
      if (er) {
        console.error(er);
      }
      console.log(data);
    });

    npm.on("log", function (message) {
      // log the progress of the installation
      console.log(message);
    });
  });
};

var uninstallPkg = function (pkgs) {
  'use strict';
  npm.load({}, function (err) {
    if (err) {
      console.error(err);
      return;
    }

    npm.commands.uninstall(pkgs, function (er, data) {
      if (er) {
        console.error(er);
      }
      console.log(data);
    });

    npm.on("log", function (message) {
      // log the progress of the uninstallation
      console.log(message);
    });
  });
};

if (command === 'install') {
  installPkg(packages);
}
else if (command === 'uninstall' || command === 'remove') {
  uninstallPkg(packages);
}

<|endoftext|>


<commit_before>"use strict";

/**
 * This file is part of the Violin package.
 *
 * (c) Jonathan ARNAULT <contact@jonathanarnault.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

var fs = require("fs"),
    path = require("path");

var Namespace = require("./Namespace.js");

class Autoloader {

    constructor() {

        /**
         * Autoloader namespaces to register
         * @type {Map<string, Namespace>}
         */
        this._namespaces = new Map();

        /**
         * Cached proxies
         * @private
         * @type {Map}
         */
        this._cache = new Map();

        /**
         * Whether this autoloader is registered
         * @type {boolean}
         */
        this._registered = false;
    }

    /**
     * Load a file or a directory
     * This method will require all files and directories
     * @public
     * @param  {String} file - The file or directory to load
     * @param  {Function=} callback - This function is called for each file loaded
     * @throws {Error} If the file or directory cannot be loaded
     */
    static load(file, callback) {
        try {
            let stats = fs.statSync(file);
            if (stats.isDirectory()) {
                let files = fs.readdirSync(file);
                for (let f of files) {
                    Autoloader.load(path.resolve(file, f), callback);
                }
            } else if (file.endsWith(".js")) { // Only load javascript files
                let r = require(file);
                callback && callback(r);
           }
        } catch (err) {
            return new Error(`Autoloader cannot load ${file}`, err);
        }
    }

    /**
     * Register autoloader
     * This method add registered namespaces to global context
     * @public
     * @throws {Error} If an autoloader is already registered
     */
    register() {
        if (Autoloader._registered) {
            throw new Error("An autoloader is already registered");
        }
        Autoloader._registered = true;
        this._registered = true;
        for (let name of this._namespaces.keys()) {
            global[name] = this._createProxy(this._namespaces.get(name));
        }
    }

    /**
     * Unregister autoloader
     * @public
     * @throws {Error} If the autoloader is not registered
     */
    unregister() {
        if (!this._registered) {
            throw new Error("Autoloader is not registered");
        }
        for (let name of this._namespaces.keys()) {
            delete global[name];
        }
        this._registered = false;
        Autoloader._registered = false;
    }

    /**
     * Register a namespace
     * @public
     * @param  {string} namespace - Namespace name
     * @param  {string=} directory - Namespace directory
     * @return {Namespace}
     */
    namespace(namespace, directory) {
        if (this._registered) {
            throw new Error("Autoloader is registered");
        }
        let namespaces = namespace.split("."),
            ns;

        for (let i = 0; i < namespaces.length; i++) {
            if (0 === i) { // Root namespace
                if (this._namespaces.has(namespaces[0])) {
                    ns = this._namespaces.get(namespaces[0]);
                } else {
                    ns = new Namespace(namespaces[0], null, null);
                    this._namespaces.set(namespaces[0], ns);
                }
            } else { // Child namespace
                try {
                    ns = ns.child(namespaces[i]);
                } catch (err) {
                    ns = new Namespace(namespaces[i], ns, null);
                }
            }
            if ((namespaces.length - 1) === i) {
                try {
                    ns.directory = directory;
                } catch (err) {}
            }
        }
        return ns;
    }

    /**
     * Load a binding
     * @public
     * @param  {string} namespace - The namespace of the binding
     * @param  {string} binding - Binding path
     * @throws {Error} - If the binding cannot be loaded
     */
    binding(namespace, binding) {
        let ns = this.namespace(namespace, null),
            paths = [
                "build/Release",
                "out/Release",
                "Release",
                "build",
                "out",
                ".",
                "build/Debug",
                "out/Debug",
                "Debug"
            ];

        for (let p of paths) {
            try {
                p = path.resolve(binding, p);
                let stats = fs.statSync(p);
                if (stats.isDirectory()) {
                    let files = fs.readdirSync(p).filter((file) => {
                        return file.endsWith(".node");
                    });

                    if (files.length == 0) {
                        continue;
                    }

                    let r = require(path.resolve(p, files[0]));

                    for (let k in r) {
                        ns.child(k, r[k]);
                    }
                    return;
                }
            } catch (err) {
                continue;
            }
        }
        throw new Error(`Autoloader cannot load "${binding} binding`);
    }

    /**
     * Load a module
     * @public
     * @param {string} name - The module name
     * @throw {Error} If the module cannot be loaded
     */
    module(name) {
        let loaded = new Set(),
            modules = [name];
        try {
            while (modules.length > 0) {
                let n = modules.pop(),
                    mod = require(`${n}/autoload.js`);

                if (mod.hasOwnProperty("namespaces")) {
                    for (let ns in mod.namespaces) {
                        this.namespace(ns, mod.namespaces[ns]);
                    }
                }

                if (mod.hasOwnProperty("bindings")) {
                    for (let b in mod.bindings) {
                        this.binding(b, mod.bindings[b]);
                    }
                }

                if (mod.hasOwnProperty("loads")) {
                    for (let l of mod.loads) {
                        Autoloader.load(l);
                    }
                }

                if (mod.hasOwnProperty("modules")) {
                    for (let m of mod.modules) {
                        if (!loaded.has(m)) {
                            modules.push(m);
                            loaded.add(m);
                        }
                    }
                }
            }
        } catch (err) {
            throw new Error(`Autoloader cannot load "${name}" module`, err);
        }
    }

    /**
     * Create a proxy for a namespace
     * @private
     * @param  {Namespace} n - The namespace
     * @return {Namespace}
     */
    _createProxy(n) {
        if (!this._cache.has(n)) {
            let self = this,
                proto = Object.getPrototypeOf(n);

            this._cache.set(n, Proxy.create({
                getOwnPropertyDescriptor() {
                    return Object.getOwnPropertyDescriptor(n)
                },
                getOwnPropertyNames() {
                    return n.children;
                },
                keys() {
                    return n.children;
                },
                hasOwn(key) {
                    return -1 !== n.children.indexOf(key);
                },
                get(receiver, key) {
                    if (Autoloader.NAMESPACE_ACCESSOR_KEY == key) {
                        return n;
                    }

                    let child = n.child(key);
                    if (!(child instanceof Namespace)) {
                        return child;
                    }
                    return self._createProxy(child);
                }
            }, proto));
        }
        return this._cache.get(n);
    }
}

/**
 * Provide access to namespace object through proxy
 * @private
 * @type {string}
 */
Autoloader.NAMESPACE_ACCESSOR_KEY = "__NAMESPACE_ACCESSOR_KEY__";

/**
 * Whether an autoloader has been registered
 * @type {boolean}
 */
Autoloader._registered = false;

module.exports = Autoloader;
<commit_msg>Avoided special case in for loop in namespace() function<commit_after>"use strict";

/**
 * This file is part of the Violin package.
 *
 * (c) Jonathan ARNAULT <contact@jonathanarnault.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

var fs = require("fs"),
    path = require("path");

var Namespace = require("./Namespace.js");

class Autoloader {

    constructor() {

        /**
         * Autoloader namespaces to register
         * @type {Map<string, Namespace>}
         */
        this._namespaces = new Map();

        /**
         * Cached proxies
         * @private
         * @type {Map}
         */
        this._cache = new Map();

        /**
         * Whether this autoloader is registered
         * @type {boolean}
         */
        this._registered = false;
    }

    /**
     * Load a file or a directory
     * This method will require all files and directories
     * @public
     * @param  {String} file - The file or directory to load
     * @param  {Function=} callback - This function is called for each file loaded
     * @throws {Error} If the file or directory cannot be loaded
     */
    static load(file, callback) {
        try {
            let stats = fs.statSync(file);
            if (stats.isDirectory()) {
                let files = fs.readdirSync(file);
                for (let f of files) {
                    Autoloader.load(path.resolve(file, f), callback);
                }
            } else if (file.endsWith(".js")) { // Only load javascript files
                let r = require(file);
                callback && callback(r);
           }
        } catch (err) {
            return new Error(`Autoloader cannot load ${file}`, err);
        }
    }

    /**
     * Register autoloader
     * This method add registered namespaces to global context
     * @public
     * @throws {Error} If an autoloader is already registered
     */
    register() {
        if (Autoloader._registered) {
            throw new Error("An autoloader is already registered");
        }
        Autoloader._registered = true;
        this._registered = true;
        for (let name of this._namespaces.keys()) {
            global[name] = this._createProxy(this._namespaces.get(name));
        }
    }

    /**
     * Unregister autoloader
     * @public
     * @throws {Error} If the autoloader is not registered
     */
    unregister() {
        if (!this._registered) {
            throw new Error("Autoloader is not registered");
        }
        for (let name of this._namespaces.keys()) {
            delete global[name];
        }
        this._registered = false;
        Autoloader._registered = false;
    }

    /**
     * Register a namespace
     * @public
     * @param  {string} namespace - Namespace name
     * @param  {string=} directory - Namespace directory
     * @return {Namespace}
     */
    namespace(namespace, directory) {
        if (this._registered) {
            throw new Error("Autoloader is registered");
        }
        let namespaces = namespace.split("."),
            ns;

        // Root namespace
        if (this._namespaces.has(namespaces[0])) {
            ns = this._namespaces.get(namespaces[0]);
        } else {
            ns = new Namespace(namespaces[0], null, null);
            this._namespaces.set(namespaces[0], ns);
        }

        // Children namespaces
        for (let i = 1; i < namespaces.length; i++) {
            try {
                ns = ns.child(namespaces[i]);
            } catch (err) {
                ns = new Namespace(namespaces[i], ns, null);
            }
        }

        try {
            ns.directory = directory;
        } catch (err) {}
        return ns;
    }

    /**
     * Load a binding
     * @public
     * @param  {string} namespace - The namespace of the binding
     * @param  {string} binding - Binding path
     * @throws {Error} - If the binding cannot be loaded
     */
    binding(namespace, binding) {
        let ns = this.namespace(namespace, null),
            paths = [
                "build/Release",
                "out/Release",
                "Release",
                "build",
                "out",
                ".",
                "build/Debug",
                "out/Debug",
                "Debug"
            ];

        for (let p of paths) {
            try {
                p = path.resolve(binding, p);
                let stats = fs.statSync(p);
                if (stats.isDirectory()) {
                    let files = fs.readdirSync(p).filter((file) => {
                        return file.endsWith(".node");
                    });

                    if (files.length == 0) {
                        continue;
                    }

                    let r = require(path.resolve(p, files[0]));

                    for (let k in r) {
                        ns.child(k, r[k]);
                    }
                    return;
                }
            } catch (err) {
                continue;
            }
        }
        throw new Error(`Autoloader cannot load "${binding} binding`);
    }

    /**
     * Load a module
     * @public
     * @param {string} name - The module name
     * @throw {Error} If the module cannot be loaded
     */
    module(name) {
        let loaded = new Set(),
            modules = [name];
        try {
            while (modules.length > 0) {
                let n = modules.pop(),
                    mod = require(`${n}/autoload.js`);

                if (mod.hasOwnProperty("namespaces")) {
                    for (let ns in mod.namespaces) {
                        this.namespace(ns, mod.namespaces[ns]);
                    }
                }

                if (mod.hasOwnProperty("bindings")) {
                    for (let b in mod.bindings) {
                        this.binding(b, mod.bindings[b]);
                    }
                }

                if (mod.hasOwnProperty("loads")) {
                    for (let l of mod.loads) {
                        Autoloader.load(l);
                    }
                }

                if (mod.hasOwnProperty("modules")) {
                    for (let m of mod.modules) {
                        if (!loaded.has(m)) {
                            modules.push(m);
                            loaded.add(m);
                        }
                    }
                }
            }
        } catch (err) {
            throw new Error(`Autoloader cannot load "${name}" module`, err);
        }
    }

    /**
     * Create a proxy for a namespace
     * @private
     * @param  {Namespace} n - The namespace
     * @return {Namespace}
     */
    _createProxy(n) {
        if (!this._cache.has(n)) {
            let self = this,
                proto = Object.getPrototypeOf(n);

            this._cache.set(n, Proxy.create({
                getOwnPropertyDescriptor() {
                    return Object.getOwnPropertyDescriptor(n)
                },
                getOwnPropertyNames() {
                    return n.children;
                },
                keys() {
                    return n.children;
                },
                hasOwn(key) {
                    return -1 !== n.children.indexOf(key);
                },
                get(receiver, key) {
                    if (Autoloader.NAMESPACE_ACCESSOR_KEY == key) {
                        return n;
                    }

                    let child = n.child(key);
                    if (!(child instanceof Namespace)) {
                        return child;
                    }
                    return self._createProxy(child);
                }
            }, proto));
        }
        return this._cache.get(n);
    }
}

/**
 * Provide access to namespace object through proxy
 * @private
 * @type {string}
 */
Autoloader.NAMESPACE_ACCESSOR_KEY = "__NAMESPACE_ACCESSOR_KEY__";

/**
 * Whether an autoloader has been registered
 * @type {boolean}
 */
Autoloader._registered = false;

module.exports = Autoloader;
<|endoftext|>


<commit_before>Suggns = {
    '$list': null,
    '$toggleLink': null,
    '$submitButton': null,
    '$suggestionsToHide': null,
    '$terms': null,
    '$queryField': null,
    'allSuggestionsVisible': true,
    'init': function() {

        // Initialize variables that store jQuery objects.
        Suggns.$list = $('form#suggested_searches ul');
        Suggns.$toggleLink = $('#toggle-more-suggestions');
        Suggns.$submitButton = $('form#suggested_searches input:submit');
        Suggns.$terms = $('form#suggested_searches li');
        Suggns.$queryField = $('#q');

        Suggns.updateSuggestionsToHide();
        Suggns.toggler();

        // Bind event handlers.
        Suggns.bindToggler();
        Suggns.bindQueryManipulators();
        Suggns.bindCheckboxUpdater();
        Suggns.bindCheckboxLabelEmphasisToggler();

        // The submit button's only for when Javascript isn't happening.
        Suggns.$submitButton.hide();
    },
    'updateSuggestionsToHide': function() {
        // At first, prepare to conceal *all* suggestions.
        Suggns.$suggestionsToHide = $('#suggested_searches li');

        var keepMeVisible = function() {
            // Call this function on a jQuery object that
            // stands in for a single checkbox.
            Suggns.$suggestionsToHide =
                Suggns.$suggestionsToHide.not($(this).parent());
        };

        var $checkboxen = Suggns.$terms.find('input:checkbox');

        // Don't conceal the checked suggestions.
        $checkboxen.filter(':checked').each(keepMeVisible);

        // Don't conceal the first four unchecked suggestions.
        $checkboxen.not(':checked').slice(0,4).each(keepMeVisible);
    },
    'bindToggler': function() {
        Suggns.$toggleLink.click(Suggns.toggler);
    },
    'toggler': function() {
        Suggns.updateSuggestionsToHide();
        if (Suggns.allSuggestionsVisible) {
            Suggns.$suggestionsToHide.hide();
            Suggns.allSuggestionsVisible = false;
        }
        else {
            Suggns.$suggestionsToHide.show();
            Suggns.allSuggestionsVisible = true;
        }
        var determiner = Suggns.allSuggestionsVisible ? 'fewer' : 'more';
        Suggns.$toggleLink.find('span').text(determiner);
        return false;
    },
    'bindQueryManipulators': function() {
        Suggns.$terms.find('input:checkbox').change(
                Suggns.queryManipulator);
    },
    'queryManipulator': function() {
        var query = Suggns.$queryField.val()
        if(query == Suggns.$queryField[0].title) {
            query = "";
            Suggns.$queryField.removeClass('default-text-active');
        }
        var term = $.trim($(this).parent().find('label').text());

        // Add quotes to terms with whitespace.
        if (term.match(/\s/) !== null) {
            term = "\"" + term + "\"";
        }

        // Remove all instances of term from query.
        var termRegExp = new RegExp(RegExp.escape(term) + "\\s", "gi");
        query = (query+" ").replace(termRegExp, "");
        console.log(query);

        // Append the term if the checkbox is being turned on.
        if ($(this).is(":checked")) {
            // Add a space if query isn't blank.
            if (query.replace(/\s/g, "") != "") query += " ";
            query += term;
        }
        console.log(query);

        queryCleaned = $.trim(query.replace(/\s+/g, " "));
        Suggns.$queryField.val(queryCleaned);
    },
    'checkboxUpdater': function() {
        var query = Suggns.$queryField.val();
        var termDelimiter = RegExp(/\s/);
        var termsLC = query.toLowerCase().split(termDelimiter);
        Suggns.$terms.each(function() {
            var value = "";
            termLC = $(this).find('label').text().toLowerCase();
            if (termsLC.contains(termLC)) {
                value = "checked";
            }
            $(this).find('input:checkbox')
            .attr('checked', value)
            .each(Suggns.checkboxLabelEmphasisToggler);
        });
    },
    'bindCheckboxUpdater': function() {
        Suggns.$queryField.keyup(Suggns.checkboxUpdater);
    },
    'checkboxLabelEmphasisToggler': function() {
        var isChecked = $(this).is(':checked');
        var method = (isChecked ? "add" : "remove") + "Class";
        $(this).parent().find('label')[method]("on");
    },
    'bindCheckboxLabelEmphasisToggler': function() {
        Suggns.$terms.find('input:checkbox').change(Suggns.checkboxLabelEmphasisToggler);
    }
};
$(Suggns.init);
<commit_msg>suggestions.js: Added one-line patch that makes the checkboxUpdater load on documentReady.<commit_after>Suggns = {
    '$list': null,
    '$toggleLink': null,
    '$submitButton': null,
    '$suggestionsToHide': null,
    '$terms': null,
    '$queryField': null,
    'allSuggestionsVisible': true,
    'init': function() {

        // Initialize variables that store jQuery objects.
        Suggns.$list = $('form#suggested_searches ul');
        Suggns.$toggleLink = $('#toggle-more-suggestions');
        Suggns.$submitButton = $('form#suggested_searches input:submit');
        Suggns.$terms = $('form#suggested_searches li');
        Suggns.$queryField = $('#q');

        Suggns.updateSuggestionsToHide();
        Suggns.toggler();

        // Bind event handlers.
        Suggns.bindToggler();
        Suggns.bindQueryManipulators();
        Suggns.bindCheckboxUpdater();
        Suggns.bindCheckboxLabelEmphasisToggler();

        // The submit button's only for when Javascript isn't happening.
        Suggns.$submitButton.hide();
    },
    'updateSuggestionsToHide': function() {
        // At first, prepare to conceal *all* suggestions.
        Suggns.$suggestionsToHide = $('#suggested_searches li');

        var keepMeVisible = function() {
            // Call this function on a jQuery object that
            // stands in for a single checkbox.
            Suggns.$suggestionsToHide =
                Suggns.$suggestionsToHide.not($(this).parent());
        };

        var $checkboxen = Suggns.$terms.find('input:checkbox');

        // Don't conceal the checked suggestions.
        $checkboxen.filter(':checked').each(keepMeVisible);

        // Don't conceal the first four unchecked suggestions.
        $checkboxen.not(':checked').slice(0,4).each(keepMeVisible);
    },
    'bindToggler': function() {
        Suggns.$toggleLink.click(Suggns.toggler);
    },
    'toggler': function() {
        Suggns.updateSuggestionsToHide();
        if (Suggns.allSuggestionsVisible) {
            Suggns.$suggestionsToHide.hide();
            Suggns.allSuggestionsVisible = false;
        }
        else {
            Suggns.$suggestionsToHide.show();
            Suggns.allSuggestionsVisible = true;
        }
        var determiner = Suggns.allSuggestionsVisible ? 'fewer' : 'more';
        Suggns.$toggleLink.find('span').text(determiner);
        return false;
    },
    'bindQueryManipulators': function() {
        Suggns.$terms.find('input:checkbox').change(
                Suggns.queryManipulator);
    },
    'queryManipulator': function() {
        var query = Suggns.$queryField.val()
        if(query == Suggns.$queryField[0].title) {
            query = "";
            Suggns.$queryField.removeClass('default-text-active');
        }
        var term = $.trim($(this).parent().find('label').text());

        // Add quotes to terms with whitespace.
        if (term.match(/\s/) !== null) {
            term = "\"" + term + "\"";
        }

        // Remove all instances of term from query.
        var termRegExp = new RegExp(RegExp.escape(term) + "\\s", "gi");
        query = (query+" ").replace(termRegExp, "");
        console.log(query);

        // Append the term if the checkbox is being turned on.
        if ($(this).is(":checked")) {
            // Add a space if query isn't blank.
            if (query.replace(/\s/g, "") != "") query += " ";
            query += term;
        }
        console.log(query);

        queryCleaned = $.trim(query.replace(/\s+/g, " "));
        Suggns.$queryField.val(queryCleaned);
    },
    'checkboxUpdater': function() {
        var query = Suggns.$queryField.val();
        var termDelimiter = RegExp(/\s/);
        var termsLC = query.toLowerCase().split(termDelimiter);
        Suggns.$terms.each(function() {
            var value = "";
            termLC = $(this).find('label').text().toLowerCase();
            if (termsLC.contains(termLC)) {
                value = "checked";
            }
            $(this).find('input:checkbox')
            .attr('checked', value)
            .each(Suggns.checkboxLabelEmphasisToggler);
        });
    },
    'bindCheckboxUpdater': function() {
        Suggns.$queryField.keyup(Suggns.checkboxUpdater);
        $(Suggns.checkboxUpdater);
    },
    'checkboxLabelEmphasisToggler': function() {
        var isChecked = $(this).is(':checked');
        var method = (isChecked ? "add" : "remove") + "Class";
        $(this).parent().find('label')[method]("on");
    },
    'bindCheckboxLabelEmphasisToggler': function() {
        Suggns.$terms.find('input:checkbox').change(Suggns.checkboxLabelEmphasisToggler);
    }
};
$(Suggns.init);
<|endoftext|>