<commit_before>const Discord = require('discord.js');
const utils = require('./utils');
const actions = require('./botActions');
const log = require('./logger').getLogger();
const config = require('./configManager').getConfigManager();

class Bot {
  constructor(commands, token, guildSettings, guildLevels) {
    this.commands = commands.commands;
    this.prefix = commands.prefix;
    this.token = token;
    this.guildSettings = guildSettings;
    this.guildLevels = guildLevels;
    this.configureBot();
    this.resetBot();
  }

// sets all the handlers for bot actions
  configureBot() {
    this.bot = new Discord.Client();
    this.bot.on('ready', () => {
      log.info('Mari bot ready for combat!');
    });

    this.bot.on('message', (msg) => {
      this.handleMessage(msg)
    });

    this.bot.on('guildMemberAdd', (member) => {
      let guildSettings = this.guildSettings[member.guild.name];
      if (guildSettings && guildSettings.welcomeMessage && guildSettings.welcomeChannel) {
        actions.welcomeMember(member, guildSettings);
      }
    });

    this.bot.on('voiceStateUpdate', (newMember, oldMember) => {
      this.newPhoneWhoDis(newMember, oldMember);
    });

    this.bot.on('messageReactionAdd', (reaction, user) => {
      // this means the bot added this reaction
      if (reaction.me) {
        return;
      }
      if (this.guildSettings[reaction.user.guild.name].react) {
        reaction.message.react(reaction.emoji).then(() => {
          log.info('Reacted with ' + reaction.emoji);
        }).catch((e) => {
          log.error('Failed to react to message: ' + e);
        });
      }
    });

    this.bot.on('messageReactionRemove', (reaction, user) => {
      // this means the bot removed this reaction
      if (reaction.me) {
        return;
      }
      if (this.guildSettings[reaction.user.guild.name].react) {
        if (reaction.users.get(this.bot.user.id)) {
          reaction.remove(reaction.emoji).then(() => {
            log.info('Removed reaction ' + reaction.emoji);
          }).catch((e) => {
            log.error('Failed to remove reaction: ' + e);
          });
        }
      }
    });

    // Uh oh
    this.bot.on('error', (e) => {
      log.error('ERROR bot crashed!: ');
      for (let prop of e) {
        log.error(prop);
      }
      try {
        this.resetBot();
      } catch (e) {
        log.error('Could not reset the bot: ' + e);
        process.exit(1);
      }
    });

    this.bot.on('warn', (warning) => {
      log.warn('warning: ' + warning);
    });

    this.bot.on('disconnect', (closeEvent) => {
      log.warn(`Websocket connection failed with error code ${closeEvent.code}! attempting to restart bot`);
      log.warn(closeEvent.reason);
      this.resetBot();
    });

    this.bot.on('debug', (info) => {
      // ignore heartbeats
      if (info.toLowerCase().includes('heartbeat')) {
        return;
      }
      log.info(`debug: ${info}`);
    });
  }

  // NEW PHONE WHO DIS
  // play new phone audio clip when a new user comes into the same channel as the bot
  newPhoneWhoDis(oldMember, newMember) {
    // discord.js docs say to use bot.voiceConnections... BUT IT DOESN'T EXIST
    if (this.bot.voiceConnections.size === 0) {
      return;
    }
    if (oldMember && newMember) {
      if (oldMember.mute !== newMember.mute || oldMember.deaf !== newMember.deaf) {
        return;
      }
    }
    if (newMember && newMember.user.voiceChannel) {
      const voiceConnection = actions.getBotVoiceConnection(newMember.voiceChannel.id, this.bot.voiceConnections);
      if (voiceConnection) {
        actions.playAudioCommand(this.bot.voiceConnections, this.commands['newphone'], newMember.user.voiceChannel.id, voiceConnection);
      }
    }
  }

  // handling of normal commands
  // check if this channel allows the bot and if this user can use the bot in this server.
  // Then, if the message contains a command the bot can understand, handle it.
  // then pass along to the handler function
  handleMessage(msg) {
    // don't respond to your own messages
    if (msg.author.username === 'mari-bot') {
      return;
    }

    // storing memes for later use
    if (msg.channel && msg.channel.name && msg.channel.name.includes('memes')) {
      let words = msg.content.split(' ');
      for (let i = 0; i < words.length; i++) {
        if (utils.isURL(words[i])) {
          if (this.commands.meme.urls.indexOf(words[i]) === -1) {
            this.commands.meme.urls.push(words[i]);
            this.commandsUpdated = true;
            log.info('Added a new meme to my collection: \n' + words[i]);
          } else {
            log.info('Avoided duplicate meme: ' + words[i]);
          }
        }
      }
    }

    // load data for current guild setup and user levels
    // no guild means message is PM, so guild restrictions are not applicable
    let currentGuildSettings = msg.channel.guild ? this.guildSettings[msg.channel.guild.name] : null;
    let currentGuildLevels = msg.channel.guild ? this.guildLevels[msg.channel.guild.name] : null;

    // check if we should level up a user
    if (currentGuildSettings && currentGuildLevels) {
      actions.levelUpUser(currentGuildLevels, currentGuildSettings, msg.author, msg.channel);
    }

    // ignore if message doesn't start with the prefix
    if (!msg.content.startsWith(this.prefix)) {
      return;
    }

    // check if this is a channel that the bot should read
    // if no registered settings assume no restrictions
    if (currentGuildSettings) {
      if (!this.botCanPostToChannel(currentGuildSettings.channels, msg.channel)) { // make sure this channel is ok to use
        msg.author.send('Sorry, you can\'t use mari-bot from ' + msg.channel.name + ' in ' + msg.channel.guild.name);
        return;
      }
      if (!this.userAllowedToUseBot(currentGuildSettings.roles, msg.member.roles)) { // make sure user is allowed to use bot
        msg.author.send("Sorry, you don't have permission to use mari-bot in " + msg.channel.guild.name);
        return;
      }
    }
    // commands can't have spaces, remove anything beyond the first space
    let [importantBit] = msg.content.split(' ');
    // cut out the prefix
    importantBit = importantBit.toLowerCase().slice(1);
    log.info('Received: ' + importantBit);
    for (let command in this.commands) {
      if (!this.commands.hasOwnProperty(command)) {
        continue;
      }
      if (importantBit === command) {
        this.handleCommand(this.commands[command], msg, currentGuildLevels, currentGuildSettings);
      }
    }
  }

  userAllowedToUseBot(allowedRoles, userRoles) {
    // if no options, assume all are allowed
    if (!allowedRoles) {
      return true;
    }
    for (let role of allowedRoles) {
      if (userRoles.filter((userRole) => userRole.name.toLowerCase() === role.toLowerCase()).size) {
        return true;
      }
    }
    return false;
  }

  botCanPostToChannel(allowedChannels, channel) {
    // if no options, assume all are allowed
    if (!allowedChannels) {
      return true;
    }
    return !!allowedChannels.filter((channelName) => channel.name === channelName).length
  }

// Reset the bot (or start it if it's not already running)
// if channel is given, notify that channel when reset is complete
  resetBot(channel) {
    if (this.bot && this.bot.readyTimestamp) {
      this.bot.destroy().then(() => {
        this.bot.login(this.token);
      }).catch((reason) => {
        log.info('Failed to logout: ' + reason);
      });
    } else {
      this.bot.login(this.token).then(() => {
        if (channel) {
          channel.send('Reset complete!');
        }
      });
    }
  }

// breakout command types into their handler functions
  handleCommand(command, msg, guildLevels, guildSettings) {
    let type = command.type.toLowerCase();
    switch (type) {
      case 'audio':
        this.handleAudioCommand(command, msg);
        break;
      case 'stop':
        this.stopTalkingInGuild(msg.guild);
        break;
      case 'text':
        if (command.response) {
          actions.sendMessage(command.response, msg.channel);
        } else {
          let beginning = command.beginning ? command.beginning : "";
          let response = command.responses[Math.floor(Math.random() * command.responses.length)];
          let ending = command.ending ? command.ending : "";
          actions.sendMessage(beginning + response + ending, msg.channel);
        }
        break;
      case 'move':
        actions.joinChannel(this.bot.guilds, msg);
        break;
      case 'leave':
        const connection = actions.activeVoiceInGuild(this.bot.voiceConnections, msg.guild);
        if (connection) {
          connection.disconnect();
        }
        break;
      case 'go':
        const channelName = msg.content.substring(4);
        log.info('Moving to: ' + channelName);
        actions.joinChannel(this.bot.guilds, null, channelName);
        break;
      case 'meme':
        const urls = command.urls;
        let url = urls[Math.floor(Math.random() * urls.length)];
        actions.sendMessage(url, msg.channel);
        break;
      case 'help':
        this.sendHelpMessage(msg);
        break;
      case 'level':
        const userName = msg.content.substring(7);
        const level = actions.getLevelOfUser(guildLevels, guildSettings, msg.channel.guild.members, userName);
        if (level) {
          actions.sendMessage(`${userName} is level ${level}`, msg.channel);
        } else {
          actions.sendMessage(`${userName} is not a user in this discord server`, msg.channel);
        }
        break;
      case 'reset':
        config.readCommands().then((commands) => {
          this.setConfigAndReset(commands, msg.channel);
        });
        break;
      default:
        actions.sendMessage('Something\'s fucked. Yell at Taylor to fix it.', msg.channel);
        break;
    }
  }

  stopTalkingInGuild(guild) {
    let dispatcher = actions.activeVoiceInGuild(this.bot.voiceConnections, guild).dispatcher;
    if (dispatcher) {
      try {
        dispatcher.end();
      } catch (e) {
        log.warn('uncaught exception in stop: ' + e);
        // nothing to do here, just an unfulfilled promise
      }
    }
  }

  sendHelpMessage(msg) {
    let audio = '';
    let texts = '';
    let general = '';
    for (let command in this.commands) {
      if (!this.commands.hasOwnProperty(command)) {
        continue;
      }
      let type = this.commands[command].type;
      if (type === 'audio') {
        audio += command + ', ';
      } else if (type === 'text') {
        texts += command + ', ';
      } else {
        if (!(type === 'meme' || type === 'broken')) {
          general += command + ', ';
        }
      }
    }
    audio = audio.substr(0, audio.length - 2);
    texts = texts.substr(0, texts.length - 2);
    general = general.substr(0, general.length - 2);
    actions.sendMessage('Commands:\n\nGeneral:\n' + general + '\n\nAudio:\n' + audio + '\n\nText:\n' + texts + '\n\nMemes:\nmeme', msg.channel);
  }

  handleAudioCommand(command, msg) {
    if (!msg.guild) {
      msg.channel.send('You can\'t send voice commands from a PM');
      return;
    }

    const connection = actions.activeVoiceInGuild(this.bot.voiceConnections, msg.guild);
    const callback = () => {
      actions.playAudioCommand(this.bot.voiceConnections, command, null, connection);
    };
    if (!connection) {
      actions.joinChannel(this.bot.guilds, msg, null, callback);
    } else {
      try {
        let userVoiceChannelId = actions.getMessageVoiceChannelId(msg);
        if (userVoiceChannelId) {
          if (!actions.activeVoiceInGuild(this.bot.voiceConnections, msg.guild)) {
            actions.joinChannel(this.bot.guilds, msg, null, callback);
            return;
          }
          actions.playAudioCommand(this.bot.voiceConnections, command, userVoiceChannelId);
        } else {
          msg.channel.send('You must be in a voice channel to use voice commands');
        }
      } catch (e) {
        msg.channel.send('Failed to play audio command.');
        console.error('handleAudioCommand error: ' + e);
      }
    }
  }

  sendSubMessage(streamer) {
    let msg = (streamer.message ? streamer.message : streamer.name + ' is now live on twitch! https://www.twitch.tv/' + streamer.name);
    for (let server of streamer.servers) {
      actions.sendMessage(msg, this.bot.guilds.get(server.id).channels.get(server.channel));
    }
  }

  setConfigAndReset(data, channel, memes) {
    this.prefix = data.prefix;
    let tempMemes = this.commands.meme;
    this.commands = data.commands;
    if (memes) {
      this.commands.meme = memes;
    } else {
      this.commands.meme = tempMemes;
    }
    // start your engines!
    this.resetBot(channel);
  }
}

module.exports = Bot;<commit_msg>Reactions work now<commit_after>const Discord = require('discord.js');
const utils = require('./utils');
const actions = require('./botActions');
const log = require('./logger').getLogger();
const config = require('./configManager').getConfigManager();

class Bot {
  constructor(commands, token, guildSettings, guildLevels) {
    this.commands = commands.commands;
    this.prefix = commands.prefix;
    this.token = token;
    this.guildSettings = guildSettings;
    this.guildLevels = guildLevels;
    this.configureBot();
    this.resetBot();
  }

// sets all the handlers for bot actions
  configureBot() {
    this.bot = new Discord.Client();
    this.bot.on('ready', () => {
      log.info('Mari bot ready for combat!');
    });

    this.bot.on('message', (msg) => {
      this.handleMessage(msg)
    });

    this.bot.on('guildMemberAdd', (member) => {
      let guildSettings = this.guildSettings[member.guild.name];
      if (guildSettings && guildSettings.welcomeMessage && guildSettings.welcomeChannel) {
        actions.welcomeMember(member, guildSettings);
      }
    });

    this.bot.on('voiceStateUpdate', (newMember, oldMember) => {
      this.newPhoneWhoDis(newMember, oldMember);
    });

    this.bot.on('messageReactionAdd', (reaction, user) => {
      // this means the bot has already added this reaction
      if (reaction.me) {
        return;
      }
      if (this.guildSettings[reaction.message.channel.guild.name].react) {
        reaction.message.react(reaction.emoji).then(() => {
          log.info('Reacted with ' + reaction.emoji);
        }).catch((e) => {
          log.error('Failed to react to message: ' + e);
        });
      }
    });

    this.bot.on('messageReactionRemove', (reaction, user) => {
      // don't remove until the bot is the only one left who's reacted
      if (reaction.users.length > 1) {
        return;
      }
      if (this.guildSettings[reaction.message.channel.guild.name].react) {
        if (reaction.users.get(this.bot.user.id)) {
          reaction.remove(this.bot.user).then(() => {
            log.info('Removed reaction ' + reaction.emoji);
          }).catch((e) => {
            log.error('Failed to remove reaction: ' + e);
          });
        }
      }
    });

    // Uh oh
    this.bot.on('error', (e) => {
      log.error('ERROR bot crashed!: ');
      for (let prop of e) {
        log.error(prop);
      }
      try {
        this.resetBot();
      } catch (e) {
        log.error('Could not reset the bot: ' + e);
        process.exit(1);
      }
    });

    this.bot.on('warn', (warning) => {
      log.warn('warning: ' + warning);
    });

    this.bot.on('disconnect', (closeEvent) => {
      log.warn(`Websocket connection failed with error code ${closeEvent.code}! attempting to restart bot`);
      log.warn(closeEvent.reason);
      this.resetBot();
    });

    this.bot.on('debug', (info) => {
      // ignore heartbeats
      if (info.toLowerCase().includes('heartbeat')) {
        return;
      }
      log.info(`debug: ${info}`);
    });
  }

  // NEW PHONE WHO DIS
  // play new phone audio clip when a new user comes into the same channel as the bot
  newPhoneWhoDis(oldMember, newMember) {
    // discord.js docs say to use bot.voiceConnections... BUT IT DOESN'T EXIST
    if (this.bot.voiceConnections.size === 0) {
      return;
    }
    if (oldMember && newMember) {
      if (oldMember.mute !== newMember.mute || oldMember.deaf !== newMember.deaf) {
        return;
      }
    }
    if (newMember && newMember.user.voiceChannel) {
      const voiceConnection = actions.getBotVoiceConnection(newMember.voiceChannel.id, this.bot.voiceConnections);
      if (voiceConnection) {
        actions.playAudioCommand(this.bot.voiceConnections, this.commands['newphone'], newMember.user.voiceChannel.id, voiceConnection);
      }
    }
  }

  // handling of normal commands
  // check if this channel allows the bot and if this user can use the bot in this server.
  // Then, if the message contains a command the bot can understand, handle it.
  // then pass along to the handler function
  handleMessage(msg) {
    // don't respond to your own messages
    if (msg.author.username === 'mari-bot') {
      return;
    }

    // storing memes for later use
    if (msg.channel && msg.channel.name && msg.channel.name.includes('memes')) {
      let words = msg.content.split(' ');
      for (let i = 0; i < words.length; i++) {
        if (utils.isURL(words[i])) {
          if (this.commands.meme.urls.indexOf(words[i]) === -1) {
            this.commands.meme.urls.push(words[i]);
            this.commandsUpdated = true;
            log.info('Added a new meme to my collection: \n' + words[i]);
          } else {
            log.info('Avoided duplicate meme: ' + words[i]);
          }
        }
      }
    }

    // load data for current guild setup and user levels
    // no guild means message is PM, so guild restrictions are not applicable
    let currentGuildSettings = msg.channel.guild ? this.guildSettings[msg.channel.guild.name] : null;
    let currentGuildLevels = msg.channel.guild ? this.guildLevels[msg.channel.guild.name] : null;

    // check if we should level up a user
    if (currentGuildSettings && currentGuildLevels) {
      actions.levelUpUser(currentGuildLevels, currentGuildSettings, msg.author, msg.channel);
    }

    // ignore if message doesn't start with the prefix
    if (!msg.content.startsWith(this.prefix)) {
      return;
    }

    // check if this is a channel that the bot should read
    // if no registered settings assume no restrictions
    if (currentGuildSettings) {
      if (!this.botCanPostToChannel(currentGuildSettings.channels, msg.channel)) { // make sure this channel is ok to use
        msg.author.send('Sorry, you can\'t use mari-bot from ' + msg.channel.name + ' in ' + msg.channel.guild.name);
        return;
      }
      if (!this.userAllowedToUseBot(currentGuildSettings.roles, msg.member.roles)) { // make sure user is allowed to use bot
        msg.author.send("Sorry, you don't have permission to use mari-bot in " + msg.channel.guild.name);
        return;
      }
    }
    // commands can't have spaces, remove anything beyond the first space
    let [importantBit] = msg.content.split(' ');
    // cut out the prefix
    importantBit = importantBit.toLowerCase().slice(1);
    log.info('Received: ' + importantBit);
    for (let command in this.commands) {
      if (!this.commands.hasOwnProperty(command)) {
        continue;
      }
      if (importantBit === command) {
        this.handleCommand(this.commands[command], msg, currentGuildLevels, currentGuildSettings);
      }
    }
  }

  userAllowedToUseBot(allowedRoles, userRoles) {
    // if no options, assume all are allowed
    if (!allowedRoles) {
      return true;
    }
    for (let role of allowedRoles) {
      if (userRoles.filter((userRole) => userRole.name.toLowerCase() === role.toLowerCase()).size) {
        return true;
      }
    }
    return false;
  }

  botCanPostToChannel(allowedChannels, channel) {
    // if no options, assume all are allowed
    if (!allowedChannels) {
      return true;
    }
    return !!allowedChannels.filter((channelName) => channel.name === channelName).length
  }

// Reset the bot (or start it if it's not already running)
// if channel is given, notify that channel when reset is complete
  resetBot(channel) {
    if (this.bot && this.bot.readyTimestamp) {
      this.bot.destroy().then(() => {
        this.bot.login(this.token);
      }).catch((reason) => {
        log.info('Failed to logout: ' + reason);
      });
    } else {
      this.bot.login(this.token).then(() => {
        if (channel) {
          channel.send('Reset complete!');
        }
      });
    }
  }

// breakout command types into their handler functions
  handleCommand(command, msg, guildLevels, guildSettings) {
    let type = command.type.toLowerCase();
    switch (type) {
      case 'audio':
        this.handleAudioCommand(command, msg);
        break;
      case 'stop':
        this.stopTalkingInGuild(msg.guild);
        break;
      case 'text':
        if (command.response) {
          actions.sendMessage(command.response, msg.channel);
        } else {
          let beginning = command.beginning ? command.beginning : "";
          let response = command.responses[Math.floor(Math.random() * command.responses.length)];
          let ending = command.ending ? command.ending : "";
          actions.sendMessage(beginning + response + ending, msg.channel);
        }
        break;
      case 'move':
        actions.joinChannel(this.bot.guilds, msg);
        break;
      case 'leave':
        const connection = actions.activeVoiceInGuild(this.bot.voiceConnections, msg.guild);
        if (connection) {
          connection.disconnect();
        }
        break;
      case 'go':
        const channelName = msg.content.substring(4);
        log.info('Moving to: ' + channelName);
        actions.joinChannel(this.bot.guilds, null, channelName);
        break;
      case 'meme':
        const urls = command.urls;
        let url = urls[Math.floor(Math.random() * urls.length)];
        actions.sendMessage(url, msg.channel);
        break;
      case 'help':
        this.sendHelpMessage(msg);
        break;
      case 'level':
        const userName = msg.content.substring(7);
        const level = actions.getLevelOfUser(guildLevels, guildSettings, msg.channel.guild.members, userName);
        if (level) {
          actions.sendMessage(`${userName} is level ${level}`, msg.channel);
        } else {
          actions.sendMessage(`${userName} is not a user in this discord server`, msg.channel);
        }
        break;
      case 'reset':
        config.readCommands().then((commands) => {
          this.setConfigAndReset(commands, msg.channel);
        });
        break;
      default:
        actions.sendMessage('Something\'s fucked. Yell at Taylor to fix it.', msg.channel);
        break;
    }
  }

  stopTalkingInGuild(guild) {
    let dispatcher = actions.activeVoiceInGuild(this.bot.voiceConnections, guild).dispatcher;
    if (dispatcher) {
      try {
        dispatcher.end();
      } catch (e) {
        log.warn('uncaught exception in stop: ' + e);
        // nothing to do here, just an unfulfilled promise
      }
    }
  }

  sendHelpMessage(msg) {
    let audio = '';
    let texts = '';
    let general = '';
    for (let command in this.commands) {
      if (!this.commands.hasOwnProperty(command)) {
        continue;
      }
      let type = this.commands[command].type;
      if (type === 'audio') {
        audio += command + ', ';
      } else if (type === 'text') {
        texts += command + ', ';
      } else {
        if (!(type === 'meme' || type === 'broken')) {
          general += command + ', ';
        }
      }
    }
    audio = audio.substr(0, audio.length - 2);
    texts = texts.substr(0, texts.length - 2);
    general = general.substr(0, general.length - 2);
    actions.sendMessage('Commands:\n\nGeneral:\n' + general + '\n\nAudio:\n' + audio + '\n\nText:\n' + texts + '\n\nMemes:\nmeme', msg.channel);
  }

  handleAudioCommand(command, msg) {
    if (!msg.guild) {
      msg.channel.send('You can\'t send voice commands from a PM');
      return;
    }

    const connection = actions.activeVoiceInGuild(this.bot.voiceConnections, msg.guild);
    const callback = () => {
      actions.playAudioCommand(this.bot.voiceConnections, command, null, connection);
    };
    if (!connection) {
      actions.joinChannel(this.bot.guilds, msg, null, callback);
    } else {
      try {
        let userVoiceChannelId = actions.getMessageVoiceChannelId(msg);
        if (userVoiceChannelId) {
          if (!actions.activeVoiceInGuild(this.bot.voiceConnections, msg.guild)) {
            actions.joinChannel(this.bot.guilds, msg, null, callback);
            return;
          }
          actions.playAudioCommand(this.bot.voiceConnections, command, userVoiceChannelId);
        } else {
          msg.channel.send('You must be in a voice channel to use voice commands');
        }
      } catch (e) {
        msg.channel.send('Failed to play audio command.');
        console.error('handleAudioCommand error: ' + e);
      }
    }
  }

  sendSubMessage(streamer) {
    let msg = (streamer.message ? streamer.message : streamer.name + ' is now live on twitch! https://www.twitch.tv/' + streamer.name);
    for (let server of streamer.servers) {
      actions.sendMessage(msg, this.bot.guilds.get(server.id).channels.get(server.channel));
    }
  }

  setConfigAndReset(data, channel, memes) {
    this.prefix = data.prefix;
    let tempMemes = this.commands.meme;
    this.commands = data.commands;
    if (memes) {
      this.commands.meme = memes;
    } else {
      this.commands.meme = tempMemes;
    }
    // start your engines!
    this.resetBot(channel);
  }
}

module.exports = Bot;<|endoftext|>


<commit_before>var auto_refresh = setInterval(
function()
{
$('#reff').fadeOut('slow').load('ref.php').fadeIn("slow");
}, 10000);
$(document).ready(function(){
	$(".box").hide();
	$(".click").click(function(){
    $(".box").slideToggle("slow");
  });
});<commit_msg>changed file<commit_after>$(document).ready(function(){
	$(".box").hide();
	$(".click").click(function(){
    $(".box").slideToggle("slow");
  });
});<|endoftext|>


<commit_before>//!     jQuery.rut.js
//		Permission is hereby granted, free of charge, to any person obtaining a copy
//		of this software and associated documentation files (the "Software"), to deal
//		in the Software without restriction, including without limitation the rights
//		to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//		copies of the Software, and to permit persons to whom the Software is
//		furnished to do so, subject to the following conditions:

//		The above copyright notice and this permission notice shall be included in
//		all copies or substantial portions of the Software.

//		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//		IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//		FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//		AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//		LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//		OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//		THE SOFTWARE.

//		Para obtener este programa bajo otra licencia, póngase en
//		contacto con @pablomarambio en Twitter.
;(function($){
	var defaults = {
		validateOn: 'blur',
		formatOn: 'blur',
		ignoreControlKeys: true,
		useThousandsSeparator: true,
		minimumLength: 2
	};

	//private methods
	function clearFormat(value) {
		return value.replace(/[\.\-]/g, "");
	}

	function format(value, useThousandsSeparator) {
		var rutAndDv = splitRutAndDv(value);
		var cRut = rutAndDv[0]; var cDv = rutAndDv[1];
		if(!(cRut && cDv)) { return cRut || value; }
		var rutF = "";
		var thousandsSeparator = useThousandsSeparator ? "." : "";
		while(cRut.length > 3) {
			rutF = thousandsSeparator + cRut.substr(cRut.length - 3) + rutF;
			cRut = cRut.substring(0, cRut.length - 3);
		}
		return cRut + rutF + "-" + cDv;
	}

	function isControlKey(e) {
		return e.type && e.type.match(/^key(up|down|press)/) &&
			(
				e.keyCode ===  8 || // del
				e.keyCode === 16 || // shift
				e.keyCode === 17 || // ctrl
				e.keyCode === 18 || // alt
				e.keyCode === 20 || // caps lock
				e.keyCode === 27 || // esc
				e.keyCode === 37 || // arrow
				e.keyCode === 38 || // arrow
				e.keyCode === 39 || // arrow
				e.keyCode === 40 || // arrow
				e.keyCode === 91    // command
			);
	}

	function isValidRut(rut, options) {
		if(typeof(rut) !== 'string') { return false; }
		var cRut = clearFormat(rut);
		// validar por largo mínimo, sin guiones ni puntos:
		// x.xxx.xxx-x
		if ( typeof options.minimumLength === 'boolean' ) {
			if ( options.minimumLength && cRut.length < defaults.minimumLength ) {
				return false;
			}
		} else {
			var minLength = parseInt( options.minimumLength, 10 );
			if ( cRut.length < minLength ) {
				return false;
			}
		}
		var cDv = cRut.charAt(cRut.length - 1).toUpperCase();
		var nRut = parseInt(cRut.substr(0, cRut.length - 1));
		if(isNaN(nRut)){ return false; }
		return computeDv(nRut).toString().toUpperCase() === cDv;
	}

	function computeDv(rut) {
		var suma	= 0;
		var mul		= 2;
		if(typeof(rut) !== 'number') return;
		rut = rut.toString();
		for(var i=rut.length -1;i >= 0;i--) {
			suma = suma + rut.charAt(i) * mul;
			mul = ( mul + 1 ) % 8 || 2;
		}
		switch(suma % 11) {
			case 1	: return 'k';
			case 0	: return 0;
			default	: return 11 - (suma % 11);
		}
	}

	function formatInput($input, useThousandsSeparator) {
		$input.val(format($input.val(), useThousandsSeparator));
	}

	function validateInput($input) {
		if(isValidRut($input.val(), $input.opts)) {
			$input.trigger('rutValido', splitRutAndDv($input.val()));
		} else {
			$input.trigger('rutInvalido');
		}
	}

	function splitRutAndDv(rut) {
		var cValue = clearFormat(rut);
		if(cValue.length === 0) { return [null, null]; }
		if(cValue.length === 1) { return [cValue, null]; }
		var cDv = cValue.charAt(cValue.length - 1);
		var cRut = cValue.substring(0, cValue.length - 1);
		return [cRut, cDv];
	}

	// public methods
	var methods = {
		init: function(options) {
			if (this.length > 1) {
				/* Valida multiples objetos a la vez */
				for (var i = 0; i < this.length; i++) {
					console.log(this[i]);
					$(this[i]).rut(options);
				};
			} else {
				var that = this;
				that.opts = $.extend({}, defaults, options);
				that.opts.formatOn && that.on(that.opts.formatOn, function(e) {
					if(that.opts.ignoreControlKeys && isControlKey(e)) { return; }
					formatInput(that, that.opts.useThousandsSeparator);
				});
				that.opts.validateOn && that.on(that.opts.validateOn, function(e) {
					validateInput(that);
				});
			}
			return this;
		}
	}

	$.fn.rut = function(methodOrOptions) {
		if(methods[methodOrOptions]) {
			return methods[methodOrOptions].apply(this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error("El método " + methodOrOptions + " no existe en jQuery.rut");
		}
	}

	$.formatRut = function (rut, useThousandsSeparator) {
		if(useThousandsSeparator===undefined) useThousandsSeparator = true;
		return format(rut, useThousandsSeparator);
	}

	$.computeDv = function(rut){
		var cleanRut = clearFormat(rut);
		return computeDv( parseInt(cleanRut, 10) );
	}

	$.validateRut = function(rut, fn, options) {
		var options = options || {};
		if(isValidRut(rut, options)) {
			var rd = splitRutAndDv(rut);
			$.isFunction(fn) && fn(rd[0], rd[1]);
			return true;
		} else {
			return false;
		}
	}
})(jQuery);
<commit_msg>Caracter inválido<commit_after>//!     jQuery.rut.js
//		Permission is hereby granted, free of charge, to any person obtaining a copy
//		of this software and associated documentation files (the "Software"), to deal
//		in the Software without restriction, including without limitation the rights
//		to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//		copies of the Software, and to permit persons to whom the Software is
//		furnished to do so, subject to the following conditions:

//		The above copyright notice and this permission notice shall be included in
//		all copies or substantial portions of the Software.

//		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//		IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//		FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//		AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//		LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//		OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//		THE SOFTWARE.

//		Para obtener este programa bajo otra licencia, póngase en
//		contacto con @pablomarambio en Twitter.
;(function($){
	var defaults = {
		validateOn: 'blur',
		formatOn: 'blur',
		ignoreControlKeys: true,
		useThousandsSeparator: true,
		minimumLength: 2
	};

	//private methods
	function clearFormat(value) {
		return value.replace(/[\.\-]/g, "");
	}

	function format(value, useThousandsSeparator) {
		var rutAndDv = splitRutAndDv(value);
		var cRut = rutAndDv[0]; var cDv = rutAndDv[1];
		if(!(cRut && cDv)) { return cRut || value; }
		var rutF = "";
		var thousandsSeparator = useThousandsSeparator ? "." : "";
		while(cRut.length > 3) {
			rutF = thousandsSeparator + cRut.substr(cRut.length - 3) + rutF;
			cRut = cRut.substring(0, cRut.length - 3);
		}
		return cRut + rutF + "-" + cDv;
	}

	function isControlKey(e) {
		return e.type && e.type.match(/^key(up|down|press)/) &&
			(
				e.keyCode ===  8 || // del
				e.keyCode === 16 || // shift
				e.keyCode === 17 || // ctrl
				e.keyCode === 18 || // alt
				e.keyCode === 20 || // caps lock
				e.keyCode === 27 || // esc
				e.keyCode === 37 || // arrow
				e.keyCode === 38 || // arrow
				e.keyCode === 39 || // arrow
				e.keyCode === 40 || // arrow
				e.keyCode === 91    // command
			);
	}

	function isValidRut(rut, options) {
		if(typeof(rut) !== 'string') { return false; }
		var cRut = clearFormat(rut);
		// validar por largo mínimo, sin guiones ni puntos:
		// x.xxx.xxx-x
		if ( typeof options.minimumLength === 'boolean' ) {
			if ( options.minimumLength && cRut.length < defaults.minimumLength ) {
				return false;
			}
		} else {
			var minLength = parseInt( options.minimumLength, 10 );
			if ( cRut.length < minLength ) {
				return false;
			}
		}
		var cDv = cRut.charAt(cRut.length - 1).toUpperCase();
		var nRut = parseInt(cRut.substr(0, cRut.length - 1));
		if(isNaN(nRut)){ return false; }
		return computeDv(nRut).toString().toUpperCase() === cDv;
	}

	function computeDv(rut) {
		var suma	= 0;
		var mul		= 2;
		if(typeof(rut) !== 'number') return;
		rut = rut.toString();
		for(var i=rut.length -1;i >= 0;i--) {
			suma = suma + rut.charAt(i) * mul;
			mul = ( mul + 1 ) % 8 || 2;
		}
		switch(suma % 11) {
			case 1	: return 'k';
			case 0	: return 0;
			default	: return 11 - (suma % 11);
		}
	}

	function formatInput($input, useThousandsSeparator) {
		$input.val(format($input.val(), useThousandsSeparator));
	}

	function validateInput($input) {
		if(isValidRut($input.val(), $input.opts)) {
			$input.trigger('rutValido', splitRutAndDv($input.val()));
		} else {
			$input.trigger('rutInvalido');
		}
	}

	function splitRutAndDv(rut) {
		var cValue = clearFormat(rut);
		if(cValue.length === 0) { return [null, null]; }
		if(cValue.length === 1) { return [cValue, null]; }
		var cDv = cValue.charAt(cValue.length - 1);
		var cRut = cValue.substring(0, cValue.length - 1);
		return [cRut, cDv];
	}

	// public methods
	var methods = {
		init: function(options) {
			if (this.length > 1) {
				/* Valida multiples objetos a la vez */
				for (var i = 0; i < this.length; i++) {
					console.log(this[i]);
					$(this[i]).rut(options);
				}
			} else {
				var that = this;
				that.opts = $.extend({}, defaults, options);
				that.opts.formatOn && that.on(that.opts.formatOn, function(e) {
					if(that.opts.ignoreControlKeys && isControlKey(e)) { return; }
					formatInput(that, that.opts.useThousandsSeparator);
				});
				that.opts.validateOn && that.on(that.opts.validateOn, function(e) {
					validateInput(that);
				});
			}
			return this;
		}
	}

	$.fn.rut = function(methodOrOptions) {
		if(methods[methodOrOptions]) {
			return methods[methodOrOptions].apply(this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error("El método " + methodOrOptions + " no existe en jQuery.rut");
		}
	}

	$.formatRut = function (rut, useThousandsSeparator) {
		if(useThousandsSeparator===undefined) useThousandsSeparator = true;
		return format(rut, useThousandsSeparator);
	}

	$.computeDv = function(rut){
		var cleanRut = clearFormat(rut);
		return computeDv( parseInt(cleanRut, 10) );
	}

	$.validateRut = function(rut, fn, options) {
		var options = options || {};
		if(isValidRut(rut, options)) {
			var rd = splitRutAndDv(rut);
			$.isFunction(fn) && fn(rd[0], rd[1]);
			return true;
		} else {
			return false;
		}
	}
})(jQuery);
<|endoftext|>


<commit_before>/**
 * Before building, files must be copied or symlinked into src/themes/_active
 * The default theme (src/themes/default) is always copied first, and then another
 * theme named by the TOB_THEME environment variable can add to or replace these files.
 **/

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

THEME_NAME = process.env.TOB_THEME || 'bcgov';
if (THEME_NAME === '_active')
    throw 'Invalid theme name';
TARGET_DIR = 'src/themes/_active';
THEMES_ROOT = 'src/themes';
LANG_ROOT = 'assets/i18n';
RESOLVE_LINKS = ['favicon.ico', 'styles.scss', LANG_ROOT];

if(! fs.copyFileSync) {
    // add stub for node.js versions before 8.5.0
    // NB: flags not implemented
    fs.copyFileSync = function(source, target, flags) {
        return fs.writeFileSync(target, fs.readFileSync(source));
    }
}

function unlinkRecursiveSync(dir) {
    if (fs.existsSync(dir)) {
        fs.readdirSync(dir).forEach(function(file, index) {
            var target_path = path.join(dir, file);
            if (fs.lstatSync(target_path).isDirectory()) {
                unlinkRecursiveSync(target_path);
            } else {
                fs.unlinkSync(target_path);
            }
        });
        fs.rmdirSync(dir);
    }
}

function populateLinksSync(source_dir, target_dir) {
    fs.readdirSync(source_dir).forEach(function(file, index) {
        var source_path = path.join(source_dir, file);
        var target_path = path.join(target_dir, file);
        var source_stats = fs.lstatSync(source_path);
        var target_stats = null;
        try {
            target_stats = fs.lstatSync(target_path);
        } catch (err) { }
        if (target_stats && target_stats.isSymbolicLink()) {
            var sync_target_stats = fs.statSync(target_path);
            var resolved_source_path = fs.realpathSync(target_path);
            fs.unlinkSync(target_path);
            if (sync_target_stats.isDirectory()) {
                fs.mkdirSync(target_path);
                populateLinksSync(resolved_source_path, target_path);
                target_stats = fs.lstatSync(target_path);
            } else {
                target_stats = null;
            }
        }
        if (target_stats) {
            if (target_stats.isDirectory() && source_stats.isDirectory()) {
                populateLinksSync(source_path, target_path);
                return;
            } else if (target_stats.isDirectory()) {
                unlinkRecursiveSync(target_path);
            } else {
                fs.unlinkSync(target_path);
            }
        }
        // must change to the target directory to create the relative symlink properly
        link_path = path.relative(target_dir, source_path);
        return_dir = path.relative(target_dir, process.cwd());
        process.chdir(target_dir);
        fs.symlinkSync(link_path, file);
        process.chdir(return_dir);
    });
}

function copyThemeDir(theme_name, target_dir) {
    var theme_dir = path.join(THEMES_ROOT, theme_name)
    try {
        fs.accessSync(theme_dir, fs.constants.R_OK);
    } catch (err) {
        throw 'Theme directory not found or not readable: ' + theme_dir
    }
    if (! fs.statSync(theme_dir).isDirectory()) {
        throw 'Theme path is not a directory: ' + theme_dir
    }
    populateLinksSync(theme_dir, target_dir);
}

function cleanTargetDir(target_dir, root, depth) {
    if (!depth) depth = 0;
    try {
        fs.mkdirSync(target_dir);
    } catch (err) {
        if (err.code !== 'EEXIST') {
            throw err;
        }
    }
    fs.readdirSync(target_dir).forEach(function(file, index) {
        var target_path = path.join(root || '.', target_dir, file);
        var stat = fs.lstatSync(target_path);
        if (stat.isDirectory()) {
            cleanTargetDir(target_path, root, depth+1);
            fs.rmdirSync(target_path);
        } else if(stat.isSymbolicLink()) {
            fs.unlinkSync(target_path);
        } else {
            var del = false;
            if (!depth && ~RESOLVE_LINKS.indexOf(file)) {
                del = true;
            } else {
                var lang_path = path.join(TARGET_DIR, LANG_ROOT);
                if (target_path.startsWith(lang_path) && target_path.endsWith('.json')) {
                    del = true;
                }
            }
            if (del) {
                fs.unlinkSync(target_path);
            } else {
                throw 'Non-symlinked file found in deployment directory, ' +
                    'please move to themes directory or remove: ' + target_path;
            }
        }
    });
}

function resolveLinks(target_dir, paths) {
    // replace particular files that need to be copied, not symlinked
    if (!paths) return;
    for (var file of paths) {
        var target_path = path.join(target_dir, file);
        try {
            target_stats = fs.lstatSync(target_path);
        } catch (err) {
            return;
        }
        if (target_stats.isSymbolicLink()) {
            real_path = fs.realpathSync(target_path);
            fs.unlinkSync(target_path);
            fs.copyFileSync(real_path, target_path);
        }
    }
}

function findLanguages(target_dir) {
    var ret = [];
    var lang_path = path.join(target_dir, LANG_ROOT);
    if (fs.existsSync(lang_path)) {
      fs.readdirSync(lang_path).forEach(function(file, index) {
          if(file.endsWith('.json')) {
              ret.push(file.substring(0, file.length - 5));
          }
      });
    }
    return ret;
}

function resolveLangPaths(theme_name, language) {
    var ret = [];
    var lang_path = path.join(THEMES_ROOT, theme_name, LANG_ROOT, language + '.json');
    if (fs.existsSync(lang_path)) {
        ret.push(lang_path);
    }
    if (theme_name !== 'default') {
        var def_path = path.join(THEMES_ROOT, 'default', LANG_ROOT, language + '.json');
        if (fs.existsSync(def_path)) {
            ret.push(def_path);
        }
    }
    if (language !== 'en') {
        ret = ret.concat(resolveLangPaths(theme_name, 'en'));
    }
    return ret;
}

function mergeDeep(target, ...sources) {
    if (!sources.length) return target;
    const source = sources.shift();
    if (typeof(target) === 'object' && typeof(source) === 'object') {
        for (const key in source) {
            if (typeof(source[key]) === 'object') {
                if (!target[key]) Object.assign(target, { [key]: {} });
                mergeDeep(target[key], source[key]);
            } else {
                Object.assign(target, { [key]: source[key] });
            }
        }
    }
    return mergeDeep(target, ...sources);
}

function combineLanguage(theme_name, target_dir) {
    var langs = findLanguages(path.join(THEMES_ROOT, theme_name));
    if (theme_name !== 'default')
        langs = langs.concat(findLanguages(path.join(THEMES_ROOT, 'default')));
    var lang_dir = path.join(target_dir, LANG_ROOT);
    for (var lang of new Set(langs)) {
        var paths = resolveLangPaths(theme_name, lang);
        if (paths.length) {
            paths.reverse();
            var input = [];
            for (var lang_path of paths) {
                input.push(require('./' + lang_path));
            }
            var data = mergeDeep(...input);
            var target_path = path.join(lang_dir, lang + '.json');
            try {
                target_stats = fs.lstatSync(target_path);
            } catch (err) {
                target_stats = null;
            }
            if (target_stats && target_stats.isSymbolicLink()) {
                fs.unlinkSync(target_path);
            }
            fs.writeFileSync(target_path, JSON.stringify(data));
        }
    }
}

console.log('Copying theme files to ' + TARGET_DIR);
console.log('Theme selected: ' + THEME_NAME);

cleanTargetDir(TARGET_DIR);

copyThemeDir('default', TARGET_DIR)
if (THEME_NAME !== 'default') {
    copyThemeDir(THEME_NAME, TARGET_DIR)
}

resolveLinks(TARGET_DIR, RESOLVE_LINKS);
combineLanguage(THEME_NAME, TARGET_DIR);

console.log('Done.\n');
<commit_msg>fix preinstall issue with language directory<commit_after>/**
 * Before building, files must be copied or symlinked into src/themes/_active
 * The default theme (src/themes/default) is always copied first, and then another
 * theme named by the TOB_THEME environment variable can add to or replace these files.
 **/

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

THEME_NAME = process.env.TOB_THEME || 'bcgov';
if (THEME_NAME === '_active')
    throw 'Invalid theme name';
TARGET_DIR = 'src/themes/_active';
THEMES_ROOT = 'src/themes';
LANG_ROOT = 'assets/i18n';
RESOLVE_LINKS = ['favicon.ico', 'styles.scss', LANG_ROOT];

if(! fs.copyFileSync) {
    // add stub for node.js versions before 8.5.0
    // NB: flags not implemented
    fs.copyFileSync = function(source, target, flags) {
        return fs.writeFileSync(target, fs.readFileSync(source));
    }
}

function unlinkRecursiveSync(dir) {
    if (fs.existsSync(dir)) {
        fs.readdirSync(dir).forEach(function(file, index) {
            var target_path = path.join(dir, file);
            if (fs.lstatSync(target_path).isDirectory()) {
                unlinkRecursiveSync(target_path);
            } else {
                fs.unlinkSync(target_path);
            }
        });
        fs.rmdirSync(dir);
    }
}

function populateLinksSync(source_dir, target_dir) {
    fs.readdirSync(source_dir).forEach(function(file, index) {
        var source_path = path.join(source_dir, file);
        var target_path = path.join(target_dir, file);
        var source_stats = fs.lstatSync(source_path);
        var target_stats = null;
        try {
            target_stats = fs.lstatSync(target_path);
        } catch (err) { }
        if (target_stats && target_stats.isSymbolicLink()) {
            var sync_target_stats = fs.statSync(target_path);
            var resolved_source_path = fs.realpathSync(target_path);
            fs.unlinkSync(target_path);
            if (sync_target_stats.isDirectory()) {
                fs.mkdirSync(target_path);
                populateLinksSync(resolved_source_path, target_path);
                target_stats = fs.lstatSync(target_path);
            } else {
                target_stats = null;
            }
        }
        if (target_stats) {
            if (target_stats.isDirectory() && source_stats.isDirectory()) {
                populateLinksSync(source_path, target_path);
                return;
            } else if (target_stats.isDirectory()) {
                unlinkRecursiveSync(target_path);
            } else {
                fs.unlinkSync(target_path);
            }
        }
        // must change to the target directory to create the relative symlink properly
        link_path = path.relative(target_dir, source_path);
        return_dir = path.relative(target_dir, process.cwd());
        process.chdir(target_dir);
        fs.symlinkSync(link_path, file);
        process.chdir(return_dir);
    });
}

function copyThemeDir(theme_name, target_dir) {
    var theme_dir = path.join(THEMES_ROOT, theme_name)
    try {
        fs.accessSync(theme_dir, fs.constants.R_OK);
    } catch (err) {
        throw 'Theme directory not found or not readable: ' + theme_dir
    }
    if (! fs.statSync(theme_dir).isDirectory()) {
        throw 'Theme path is not a directory: ' + theme_dir
    }
    populateLinksSync(theme_dir, target_dir);
}

function cleanTargetDir(target_dir, root, depth) {
    if (!depth) depth = 0;
    try {
        fs.mkdirSync(target_dir);
    } catch (err) {
        if (err.code !== 'EEXIST') {
            throw err;
        }
    }
    fs.readdirSync(target_dir).forEach(function(file, index) {
        var target_path = path.join(root || '.', target_dir, file);
        var stat = fs.lstatSync(target_path);
        if (stat.isDirectory()) {
            cleanTargetDir(target_path, root, depth+1);
            fs.rmdirSync(target_path);
        } else if(stat.isSymbolicLink()) {
            fs.unlinkSync(target_path);
        } else {
            var del = false;
            if (!depth && ~RESOLVE_LINKS.indexOf(file)) {
                del = true;
            } else {
                var lang_path = path.join(TARGET_DIR, LANG_ROOT);
                if (target_path.startsWith(lang_path) && target_path.endsWith('.json')) {
                    del = true;
                }
            }
            if (del) {
                fs.unlinkSync(target_path);
            } else {
                throw 'Non-symlinked file found in deployment directory, ' +
                    'please move to themes directory or remove: ' + target_path;
            }
        }
    });
}

function resolveLinks(target_dir, paths) {
    // replace particular files that need to be copied, not symlinked
    if (!paths) return;
    for (var file of paths) {
        var target_path = path.join(target_dir, file);
        try {
            target_stats = fs.lstatSync(target_path);
        } catch (err) {
            continue;
        }
        if (target_stats.isSymbolicLink()) {
            real_path = fs.realpathSync(target_path);
            fs.unlinkSync(target_path);
            try {
                real_stats = fs.lstatSync(real_path);
            } catch (err) {
                continue;
            }
            if(real_stats.isDirectory())
                fs.mkdirSync(target_path);
            else
                fs.copyFileSync(real_path, target_path);
        }
    }
}

function findLanguages(target_dir) {
    var ret = [];
    var lang_path = path.join(target_dir, LANG_ROOT);
    if (fs.existsSync(lang_path)) {
      fs.readdirSync(lang_path).forEach(function(file, index) {
          if(file.endsWith('.json')) {
              ret.push(file.substring(0, file.length - 5));
          }
      });
    }
    return ret;
}

function resolveLangPaths(theme_name, language) {
    var ret = [];
    var lang_path = path.join(THEMES_ROOT, theme_name, LANG_ROOT, language + '.json');
    if (fs.existsSync(lang_path)) {
        ret.push(lang_path);
    }
    if (theme_name !== 'default') {
        var def_path = path.join(THEMES_ROOT, 'default', LANG_ROOT, language + '.json');
        if (fs.existsSync(def_path)) {
            ret.push(def_path);
        }
    }
    if (language !== 'en') {
        ret = ret.concat(resolveLangPaths(theme_name, 'en'));
    }
    return ret;
}

function mergeDeep(target, ...sources) {
    if (!sources.length) return target;
    const source = sources.shift();
    if (typeof(target) === 'object' && typeof(source) === 'object') {
        for (const key in source) {
            if (typeof(source[key]) === 'object') {
                if (!target[key]) Object.assign(target, { [key]: {} });
                mergeDeep(target[key], source[key]);
            } else {
                Object.assign(target, { [key]: source[key] });
            }
        }
    }
    return mergeDeep(target, ...sources);
}

function combineLanguage(theme_name, target_dir) {
    var langs = findLanguages(path.join(THEMES_ROOT, theme_name));
    if (theme_name !== 'default')
        langs = langs.concat(findLanguages(path.join(THEMES_ROOT, 'default')));
    var lang_dir = path.join(target_dir, LANG_ROOT);
    for (var lang of new Set(langs)) {
        var paths = resolveLangPaths(theme_name, lang);
        if (paths.length) {
            paths.reverse();
            var input = [];
            for (var lang_path of paths) {
                input.push(require('./' + lang_path));
            }
            var data = mergeDeep(...input);
            var target_path = path.join(lang_dir, lang + '.json');
            try {
                target_stats = fs.lstatSync(target_path);
            } catch (err) {
                target_stats = null;
            }
            if (target_stats && target_stats.isSymbolicLink()) {
                fs.unlinkSync(target_path);
            }
            fs.writeFileSync(target_path, JSON.stringify(data));
        }
    }
}

console.log('Copying theme files to ' + TARGET_DIR);
console.log('Theme selected: ' + THEME_NAME);

cleanTargetDir(TARGET_DIR);

copyThemeDir('default', TARGET_DIR)
if (THEME_NAME !== 'default') {
    copyThemeDir(THEME_NAME, TARGET_DIR)
}

resolveLinks(TARGET_DIR, RESOLVE_LINKS);
combineLanguage(THEME_NAME, TARGET_DIR);

console.log('Done.\n');
<|endoftext|>


<commit_before>let fs = require('fs');
let path = require('path');
let yaml = require('js-yaml');
import * as log from './logger';
import theme from './theme';

/**
 * See both `pre` and `post`.
 *
 * @param {String} file
 * @param {Logger} logger
 * @return {Object}
 */
export default function (file, logger = log.empty) {
  return post(pre(file, logger));
}

/**
 * Get the configuration object from given file of `.sassdocrc` if not
 * found.
 *
 * The `dir` property will be the directory of the given file or the CWD
 * if no file is given. The configuration paths should be relative to
 * it.
 *
 * The given logger will be injected in the configuration object for
 * further usage.
 *
 * @param {String} file
 * @param {Logger} logger
 * @return {Object}
 */
export function pre(file, logger = log.empty) {
  file = resolve(process.cwd(), file);

  let config = maybe(file, () => {
    if (file !== undefined) {
      logger.error(`Config file "${file}" not found.`);
      logger.warn('Falling back to ".sassdocrc".');
    }

    return maybe('.sassdocrc', () => {
      return {logger};
    });
  });

  config.logger = logger;

  if (file === undefined) {
    config.dir = process.cwd();
  } else {
    config.dir = path.resolve(path.dirname(file));
  }

  return config;
}

/**
 * Post process given configuration object to ensure `package` and
 * `theme` are uniform values.
 *
 * The `package` key is ensured to be an object. If it's a string, it's
 * required as JSON, relative to the configuration file directory.
 *
 * The `theme` key, if present and not already a function, will be resolved to
 * the actual theme function.
 *
 * @param {Object} config
 * @return {Object}
 */
export function post(config) {
  if (typeof config.package !== 'object') {
    let file = resolve(config.dir, config.package);

    config.package = maybe(file, () => {
      if (config.package !== undefined) {
        config.logger.error(`Package file "${file}" not found.`);
        config.logger.warn('Falling back to "package.json".');
      }

      let file = path.resolve(config.dir, 'package.json');

      return maybe(file, () => {
        config.logger.warn('No package information.');
      });
    });
  }

  if (typeof config.theme !== 'function') {
    config.theme = theme(config.theme, config.dir, config.logger);
  }

}

/**
 * If given file is not undefined, resolve it to given directory.
 *
 * @param {String} dir
 * @param {String} file
 * @return {String}
 */
function resolve(dir, file) {
  if (file !== undefined) {
    return path.resolve(dir, file);
  }
}

/**
 * Try `load` for given file but call given fallback if an exception
 * with `ENOENT` code is thrown, or if the file is undefined.
 *
 * Other exceptions are not muted.
 *
 * @param {Function} loader
 * @param {String} file
 * @param {Function} fallback
 * @return {Object}
 */
function maybe(file, fallback=() => {}) {
  if (file === undefined) {
    return fallback();
  }

  try {
    return load(file);
  } catch (e) {
    if (e.code !== 'ENOENT') {
      throw e;
    }
  }

  return fallback();
}

/**
 * Load YAML or JSON from given file path.
 *
 * @param {String} path
 * @return {Object}
 */
function load(path) {
  return yaml.safeLoad(fs.readFileSync(path, 'utf-8'));
}
<commit_msg>Keep track of theme name<commit_after>let fs = require('fs');
let path = require('path');
let yaml = require('js-yaml');
import * as log from './logger';
import theme from './theme';

/**
 * See both `pre` and `post`.
 *
 * @param {String} file
 * @param {Logger} logger
 * @return {Object}
 */
export default function (file, logger = log.empty) {
  return post(pre(file, logger));
}

/**
 * Get the configuration object from given file of `.sassdocrc` if not
 * found.
 *
 * The `dir` property will be the directory of the given file or the CWD
 * if no file is given. The configuration paths should be relative to
 * it.
 *
 * The given logger will be injected in the configuration object for
 * further usage.
 *
 * @param {String} file
 * @param {Logger} logger
 * @return {Object}
 */
export function pre(file, logger = log.empty) {
  file = resolve(process.cwd(), file);

  let config = maybe(file, () => {
    if (file !== undefined) {
      logger.error(`Config file "${file}" not found.`);
      logger.warn('Falling back to ".sassdocrc".');
    }

    return maybe('.sassdocrc', () => {
      return {logger};
    });
  });

  config.logger = logger;

  if (file === undefined) {
    config.dir = process.cwd();
  } else {
    config.dir = path.resolve(path.dirname(file));
  }

  return config;
}

/**
 * Post process given configuration object to ensure `package` and
 * `theme` are uniform values.
 *
 * The `package` key is ensured to be an object. If it's a string, it's
 * required as JSON, relative to the configuration file directory.
 *
 * The `theme` key, if present and not already a function, will be resolved to
 * the actual theme function.
 *
 * @param {Object} config
 * @return {Object}
 */
export function post(config) {
  if (typeof config.package !== 'object') {
    let file = resolve(config.dir, config.package);

    config.package = maybe(file, () => {
      if (config.package !== undefined) {
        config.logger.error(`Package file "${file}" not found.`);
        config.logger.warn('Falling back to "package.json".');
      }

      let file = path.resolve(config.dir, 'package.json');

      return maybe(file, () => {
        config.logger.warn('No package information.');
      });
    });
  }

  if (typeof config.theme !== 'function') {
    config.themeName = config.theme || 'default';
    config.theme = theme(config.theme, config.dir, config.logger);
  }

}

/**
 * If given file is not undefined, resolve it to given directory.
 *
 * @param {String} dir
 * @param {String} file
 * @return {String}
 */
function resolve(dir, file) {
  if (file !== undefined) {
    return path.resolve(dir, file);
  }
}

/**
 * Try `load` for given file but call given fallback if an exception
 * with `ENOENT` code is thrown, or if the file is undefined.
 *
 * Other exceptions are not muted.
 *
 * @param {Function} loader
 * @param {String} file
 * @param {Function} fallback
 * @return {Object}
 */
function maybe(file, fallback=() => {}) {
  if (file === undefined) {
    return fallback();
  }

  try {
    return load(file);
  } catch (e) {
    if (e.code !== 'ENOENT') {
      throw e;
    }
  }

  return fallback();
}

/**
 * Load YAML or JSON from given file path.
 *
 * @param {String} path
 * @return {Object}
 */
function load(path) {
  return yaml.safeLoad(fs.readFileSync(path, 'utf-8'));
}
<|endoftext|>


<commit_before>module.exports = {
    parser: {
        isRoute: function(node) {
            function recursiveSearch(node) {
                return (node && node.callee) &&
                    (
                    (node.callee.type === 'MemberExpression' &&
                    node.callee.object.name === '$stateProvider' &&
                    node.callee.property.name === 'state' &&
                    node.arguments.length === 2 &&
                    node.arguments[1].type === 'ObjectExpression')
                    ||
                    recursiveSearch(node.callee.object)
                    )
            }

            return recursiveSearch(node);
        },
        extractRoute: function(node) {
            return node.arguments[1].properties
                .filter(function(property) {
                    return property.key.name === 'url';
                })
                .map(function(property) {
                    return property.value.value
                })
                .pop();

        }
    }
};
<commit_msg>fix(configuration/angular-ui-router): add support for a single object argument<commit_after>module.exports = {
    parser: {
        isRoute: function(node) {
            function recursiveSearch(node) {
                return (node && node.callee) &&
                    (
                    (node.callee.type === 'MemberExpression' &&
                    node.callee.object.name === '$stateProvider' &&
                    node.callee.property.name === 'state' &&
                    node.arguments.length && [1, 2].indexOf(node.arguments.length) !== -1 &&
                    node.arguments[node.arguments.length - 1].type === 'ObjectExpression')
                    ||
                    recursiveSearch(node.callee.object)
                    )
            }

            return recursiveSearch(node);
        },
        extractRoute: function(node) {
            return node.arguments[node.arguments.length - 1].properties
                .filter(function(property) {
                    return property.key.name === 'url';
                })
                .map(function(property) {
                    return property.value.value
                })
                .pop();

        }
    }
};
<|endoftext|>


<commit_before>var exec = require('child_process').exec;
var colors = require('colors/safe');

var io = function(error, stdout, stderr) {
  console.log(colors.green(stdout));
  console.log(colors.red(stderr));
};

var ADB = function(data) {
  if (!(this instanceof ADB)) {
    return new ADB(data);
  }
  exec("adb devices", io);
};

ADB.prototype.sms = function(recipient, message) {
  exec("adb shell am start -a android.intent.action.SENDTO -d sms:" + recipient +  " --es sms_body '" + message + "' --ez exit_on_sent true", io);
  exec("adb shell input keyevent 22");
  exec("adb shell input keyevent 66");
  //exec("adb shell input keyevent 82 && adb shell am start -n com.nolanlawson.android.simpletalker/.MainActivity -e text 'Omerxi a dit : SMS envoyé'", io);
};

module.exports = {
  getInstance: function(data) {
    return new ADB(data);
  }
};
<commit_msg>fixed keyevent calls<commit_after>var exec = require('child_process').exec;
var colors = require('colors/safe');

var io = function(error, stdout, stderr) {
  console.log(colors.green(stdout));
  console.log(colors.red(stderr));
};

var ADB = function(data) {
  if (!(this instanceof ADB)) {
    return new ADB(data);
  }
  exec("adb devices", io);
};

ADB.prototype.sms = function(recipient, message) {
  exec("adb shell am start -a android.intent.action.SENDTO -d sms:" + recipient +  " --es sms_body '" + message + "' --ez exit_on_sent true", io);
  exec("adb shell input keyevent 22", io);
  exec("adb shell input keyevent 66", io);
  exec("adb shell input keyevent 82 && adb shell am start -n com.nolanlawson.android.simpletalker/.MainActivity -e text 'Omerxi a dit : SMS envoyé'", io);
};

module.exports = {
  getInstance: function(data) {
    return new ADB(data);
  }
};
<|endoftext|>


<commit_before>{
	"en-US": "ja",
	"Ukiyo-e Search": "浮世絵検索",
	"Japanese Woodblock Print Search": "浮世絵検索",
	"Search Japanese Woodblock Prints": "浮世絵検索",
	"Switch Language": "English",
	"Language Notice": "You're viewing the Japanese version of this page.",
	"Language Redirect": "View the English version.",
	"Blog": "ブログ",
	"Search": "検索",
	"Image Search": "画像検索",
	"Search by Image:": "画像で検索:",
	"Search by Image": "画像で検索",
	"Search %s prints:": "検索 %s 浮世絵:",
	"Uploaded Print": "アップロードさプリント",
	"Uh oh!": "あああー！",
	"No other copies of this print have been found.": "この印刷物のいかなるその他のコピーが発見されていない。",
	"Upload a picture of a print to find similar prints across multiple collections.": "テキストの代わりに画像で浮世を検索します。",
	"Upload an Image": "画像のアップロード",
	"Paste image URL": "画像の URL を貼り付け",
	"About": "このサイトについて",
	"%s prints found.": "%s 件",
	"Viewing prints %s to %s.": "浮世絵 %s-%s",
	"Previous": "前へ",
	"Next": "次へ",
	"Title:": "作品名:",
	"Artist:": "絵師:",
	"Date:": "年月日:",
	"Description:": "画題等:",
	"Source:": "源:",
	"Details:": "詳細について:",
	"More information...": "詳細情報...",
	"Learn More": "詳細について",
	"Other Copies": "同じ",
	"Compare Prints...": "比較する浮世絵...",
	"Reset Zoom": "ズームアウトする",
	"Close": "閉じる",
	"Discuss This Print": "話し合う",
	"Share:": "分け合う:",
	"Ukiyo-e Search provides an incredible resource: The ability to both search for Japanese woodblock prints by simply taking a picture of an existing print AND the ability to see similar prints across multiple collections of prints. Below is an example print, click to see it in action.": "検索 浮世絵, 錦絵, 明治, 新版画, 創作版画。",
	"Japanese Woodblock print search engine. Searches thousands of Ukiyo-e, Meiji, Shin Hanga, and Sosaku Hanga prints.": "検索 浮世絵, 錦絵, 明治, 新版画, 創作版画。",
	"Japanese Woodblock prints by %s.": "%s 浮世絵",
	"Japanese Woodblock prints at the %s.": "%s 浮世絵",
	"Results for '%s'": "検索 '%s'",
	"Japanese Woodblock prints matching '%s'.": "浮世絵検索 '%s'.",
	"Early Ukiyo-e (Early-Mid 1700s)": "1700-1740",
	"Birth of Full-Color Printing (1740s to 1780s)": "錦絵 (1740-1780)",
	"Golden Age of Ukiyo-e (1780 to 1804)": "歌麿 (1780-1804)",
	"Popularization of Woodblock Printing (1804 to 1868)": "1804-1868",
	"Meiji Period (1868 to 1912)": "明治 (1868-1912)",
	"Shin Hanga and Sosaku Hanga Movements (1915 to 1940s)": " 新版画,  創作版画 (1915-1940)",
	"Modern and Contemporary (1950s to Now)": "1950+",
	"Browse all %s prints...": "ブラウズ %s 浮世絵...",
	"There is no way to link to this print on the source site. Please visit the source and search for the print there.": "ソースサイトでこの印刷にリンクする方法はありません。そこにプリントするためのソースを検索してご覧ください。",
	"Details & Prices:": "詳細と価格:",
	"Unfortunately the source of this print no longer exists.": "残念ながら、このプリントのソースはもはや存在しません。",
	"Sources": "源",
	"Sources of Japanese Woodblock Prints": "浮世絵源",
	"Sources in the Database (%s images)": "源 (%s 画像)",
	"Other Sources (est. %s images)": "その他のソース (~%s 画像)",
	"These sources of Japanese Woodblock prints have been integrated into the database and are searchable.": "これらのソースは、データベースに統合され、検索されています。",
	"These are other sources available on the Internet that have not yet been integrated into the database.": "これらは、まだデータベースに統合されていないインターネット上で利用可能な他の情報源です。",
	"All of these sources are estimated to have at least 100 Japanese woodblock print images online.": "これらの情報源のすべてがオンラインで少なくとも100日本版画のイメージを持っていると推定されている。",
	"If you know of any other sources please contact me.": "あなたが他の情報源を発見された場合は、コンタクトをしてください私を参照してください。",
	"Browse all %s images...": "ブラウズ %s 浮世絵...",
	"est. %s print images.": "~%s 浮世絵...",
	"Museums": "博物館",
	"Universities": "大学",
	"Libraries": "ライブラリー",
	"Databases": "データベース",
	"Private Collections": "個人コレクション",
	"Auction Houses": "オークション",
	"Dealers": "ディーラー",
	"United States: California": "米国: カリフォルニア",
	"United States: Colorado": "米国: コロラド州",
	"United States: Connecticut": "米国: コネチカット",
	"United States: Hawaii": "米国: ハワイ",
	"United States: Illinois": "米国: イリノイ州",
	"United States: Indiana": "米国: インディアナ州",
	"United States: Kansas": "米国: カンザス",
	"United States: Maryland": "米国: メリーランド州",
	"United States: Massachusetts": "米国: マサチューセッツ州",
	"United States: Michigan": "米国: ミシガン州",
	"United States: Minnesota": "米国: ミネソタ州",
	"United States: Missouri": "米国: ミズーリ州",
	"United States: New Hampshire": "米国: ニューハンプシャー州",
	"United States: New Jersey": "米国: ニュージャージー州",
	"United States: New York": "米国: ニューヨーク",
	"United States: North Carolina": "米国: ノースカロライナ州",
	"United States: Ohio": "米国: オハイオ州",
	"United States: Oregon": "米国: オレゴン州",
	"United States: Pennsylvania": "米国: ペンシルベニア州",
	"United States: Utah": "米国: ユタ州",
	"United States: Washington": "米国: ワシントン",
	"United States: Washington D.C.": "米国: ワシントンD.C.",
	"United States: Wisconsin": "米国: ウィスコンシン州",
	"Australia": "オーストラリア",
	"Austria": "オーストリア",
	"Canada": "カナダ",
	"Finland": "フィンランド",
	"France": "フランス",
	"Germany": "ドイツ",
	"Israel": "イスラエル",
	"Italy": "イタリア",
	"Japan": "日本",
	"Netherlands": "オランダ",
	"New Zealand": "ニュージーランド",
	"Online": "オンライン",
	"Russia": "ロシア",
	"Spain": "スペイン",
	"Switzerland": "スイス",
	"United Kingdom": "イギリス",
	"Aliases:": "Aliases:",
	"Bios:": "Bios:",
	"Born:": "Born:",
	"Died:": "Died:"
}<commit_msg>Bring in better JA translations from @mitcho.<commit_after>{
	"en-US": "ja",
	"Ukiyo-e Search": "浮世絵検索",
	"Japanese Woodblock Print Search": "浮世絵検索",
	"Search Japanese Woodblock Prints": "浮世絵検索",
	"Switch Language": "English",
	"Language Notice": "You're viewing the Japanese version of this page.",
	"Language Redirect": "View the English version.",
	"Blog": "ブログ",
	"Search": "検索",
	"Image Search": "画像検索",
	"Search by Image:": "画像で検索:",
	"Search by Image": "画像で検索",
	"Search %s prints:": "浮世絵（全 %s 件）を検索:",
	"Uploaded Print": "アップロードされた版画",
	"Uh oh!": "おっと！",
	"No other copies of this print have been found.": "同じ絵柄の浮世絵は見つかっていません。",
	"Upload a picture of a print to find similar prints across multiple collections.": "テキストの代わりに画像で浮世絵を検索します。",
	"Upload an Image": "画像のアップロード",
	"Paste image URL": "画像の URL を貼り付け",
	"About": "このサイトについて",
	"%s prints found.": "%s 件",
	"Viewing prints %s to %s.": "%s-%s 件",
	"Previous": "前へ",
	"Next": "次へ",
	"Title:": "作品名:",
	"Artist:": "絵師:",
	"Date:": "日付:",
	"Description:": "画題等:",
	"Source:": "情報源:",
	"Details:": "詳細:",
	"More information...": "詳細情報...",
	"Learn More": "詳細について",
	"Other Copies": "同じ絵柄のもの",
	"Compare Prints...": "版画を比較する...",
	"Reset Zoom": "ズームアウトする",
	"Close": "閉じる",
	"Discuss This Print": "話し合う",
	"Share:": "シェア:",
	"Ukiyo-e Search provides an incredible resource: The ability to both search for Japanese woodblock prints by simply taking a picture of an existing print AND the ability to see similar prints across multiple collections of prints. Below is an example print, click to see it in action.": "浮世絵、錦絵、明治、新版画、創作版画を検索。",
	"Japanese Woodblock print search engine. Searches thousands of Ukiyo-e, Meiji, Shin Hanga, and Sosaku Hanga prints.": "浮世絵、錦絵、明治、新版画、創作版画を検索。",
	"Japanese Woodblock prints by %s.": "%s 浮世絵",
	"Japanese Woodblock prints at the %s.": "%s 浮世絵",
	"Results for '%s'": "検索結果: '%s'",
	"Japanese Woodblock prints matching '%s'.": "'%s'で見つかった浮世絵",
	"Early Ukiyo-e (Early-Mid 1700s)": "初期 (1700-1740)",
	"Birth of Full-Color Printing (1740s to 1780s)": "錦絵 (1740-1780)",
	"Golden Age of Ukiyo-e (1780 to 1804)": "歌麿 (1780-1804)",
	"Popularization of Woodblock Printing (1804 to 1868)": "1804-1868",
	"Meiji Period (1868 to 1912)": "明治 (1868-1912)",
	"Shin Hanga and Sosaku Hanga Movements (1915 to 1940s)": "新版画、創作版画 (1915-1940)",
	"Modern and Contemporary (1950s to Now)": "1950年以降",
	"Browse all %s prints...": "浮世絵（全 %s 件）を表示...",
	"There is no way to link to this print on the source site. Please visit the source and search for the print there.": "情報源のサイトでこの浮世絵に直接リンクする方法はありません。情報源サイトで検索してください。",
	"Details & Prices:": "詳細と価格:",
	"Unfortunately the source of this print no longer exists.": "残念ながら、このプリントの情報源はもはや存在しません。",
	"Sources": "情報源",
	"Sources of Japanese Woodblock Prints": "浮世絵源",
	"Sources in the Database (%s images)": "情報源 (%s 画像)",
	"Other Sources (est. %s images)": "その他の情報源 (~%s 画像)",
	"These sources of Japanese Woodblock prints have been integrated into the database and are searchable.": "こちらの情報源は、本サイトのデータベースと統合され、検索ができます。",
	"These are other sources available on the Internet that have not yet been integrated into the database.": "これらは、まだデータベースに統合されていないインターネット上で利用可能な他の情報源です。",
	"All of these sources are estimated to have at least 100 Japanese woodblock print images online.": "これらの情報源のすべてがオンラインで少なくとも100件のイメージを持っていると推定されています。",
	"If you know of any other sources please contact me.": "他の情報源を発見された場合は、是非本サイトの管理人に連絡ください。",
	"Browse all %s images...": "浮世絵（全 %s 件）を表示...",
	"est. %s print images.": "浮世絵約 %s 件...",
	"Museums": "博物館",
	"Universities": "大学",
	"Libraries": "図書館",
	"Databases": "データベース",
	"Private Collections": "個人コレクション",
	"Auction Houses": "オークション",
	"Dealers": "ディーラー",
	"United States: California": "米国: カリフォルニア州",
	"United States: Colorado": "米国: コロラド州",
	"United States: Connecticut": "米国: コネチカット州",
	"United States: Hawaii": "米国: ハワイ州",
	"United States: Illinois": "米国: イリノイ州",
	"United States: Indiana": "米国: インディアナ州",
	"United States: Kansas": "米国: カンザス州",
	"United States: Maryland": "米国: メリーランド州",
	"United States: Massachusetts": "米国: マサチューセッツ州",
	"United States: Michigan": "米国: ミシガン州",
	"United States: Minnesota": "米国: ミネソタ州",
	"United States: Missouri": "米国: ミズーリ州",
	"United States: New Hampshire": "米国: ニューハンプシャー州",
	"United States: New Jersey": "米国: ニュージャージー州",
	"United States: New York": "米国: ニューヨーク州",
	"United States: North Carolina": "米国: ノースカロライナ州",
	"United States: Ohio": "米国: オハイオ州",
	"United States: Oregon": "米国: オレゴン州",
	"United States: Pennsylvania": "米国: ペンシルベニア州",
	"United States: Utah": "米国: ユタ州",
	"United States: Washington": "米国: ワシントン州",
	"United States: Washington D.C.": "米国: ワシントンD.C.",
	"United States: Wisconsin": "米国: ウィスコンシン州",
	"Australia": "オーストラリア",
	"Austria": "オーストリア",
	"Canada": "カナダ",
	"Finland": "フィンランド",
	"France": "フランス",
	"Germany": "ドイツ",
	"Israel": "イスラエル",
	"Italy": "イタリア",
	"Japan": "日本",
	"Netherlands": "オランダ",
	"New Zealand": "ニュージーランド",
	"Online": "オンライン",
	"Russia": "ロシア",
	"Spain": "スペイン",
	"Switzerland": "スイス",
	"United Kingdom": "イギリス"
}
<|endoftext|>


<commit_before>// Just for information of this snippet.
var ASCopyVersion = '1.1.0';

// TESTED ON BROWSERS:
// * Chrome 56.0.2924.87
// * Firefox 52.0 - Use Scratchpad in devtools.
//                  Copying from scratchpad doesn't work, use generated button after versions table.
// * Safari 10.0.3 - Just run snippet from console.

// CHANGELOG
// 1.1.0 (March 7, 2017)
// * Added: usage `copy` method from chrome devtools api.
//
// 1.0.0 (March 7, 2017)
// * First version (added main functionality, button, logs).

// Clear previous elements
var logs = document.querySelectorAll('._clipboard_log_');
logs.forEach(function(log) {
  log.parentNode.removeChild(log);
});
var copyButtonId = '_mycustom-clipboard-button-id_'
var isButtonExist = document.getElementById(copyButtonId);
if (isButtonExist) {
  document.getElementById(copyButtonId).remove();
}

var versionsTable = document.querySelector('.Version_table');
// Markdown view
var md = '';
var headSeparator = '||';
var bodySeparator = '|';

function isTableHead(iter) {
  return iter == 0;
}

function add(string) {
  md = md + string;
}

function addSeparator(iter) {
  isTableHead(iter) ? add(headSeparator) : add(bodySeparator);
}

for (var i = 0; i < versionsTable.childNodes.length; i++) {
  var tr = versionsTable.childNodes[i].childNodes[0];

  addSeparator(i);
  tr.childNodes.forEach(function(td){
    add(td.innerText);
    addSeparator(i);
  });

  // Add line break
  md = md + '\n';
}

if (md != '') {
  var button = document.createElement('button');
  button.id = copyButtonId;
  button.innerText = 'Click me to copy versions';
  button.style = `
        margin: 20px 0px;
        height: 60px;
        width: 540px;
        font-size: 20pt;
    `;
  versionsTable.parentElement.appendChild(button);
  button.addEventListener('click', function() {
    copyToClipboard(md);
  });

  copy(md);
  console.log(md);
  console.log('Copied to clipboard!');
  log("Copied to clipboard!");
}

// ||Component||Version||Date||
// |UI|2.1.0-34-gb4d27a6|2017-03-06T10:03:51±10|
// |appservices|2.1.0-start-298-g01ddc8|2017-03-06T16:50:05.816-0500|
// |authservice|1.1.0-start-126-gcf045e|2017-02-28T11:15:04.436-0500|
// |discountservice|1.1.0-start-126-gcf045e|2017-02-28T11:16:44.286-0500|
// |notificationservice|1.1.0-start-126-gcf045e|2017-02-28T11:15:32.974-0500|
// |profileservice|1.1.0-start-126-gcf045e|2017-02-28T11:16:00.802-0500|
// |roleservice|1.1.0-start-126-gcf045e|2017-02-28T11:16:24.693-0500|

function copyToClipboard(text){
  var textarea = document.createElement("textarea");
  textarea.id = "mycustom-clipboard-textarea-hidden-id";
  // Place in top-left corner of screen regardless of scroll position.
  textarea.style.position = 'absolute';
  textarea.style.top = 0;
  textarea.style.left = 0;

  // Ensure it has a small width and height. Setting to 1px / 1em
  // doesn't work as this gives a negative w/h on some browsers.
  textarea.style.width = '1px';
  textarea.style.height = '1px';

  // We don't need padding, reducing the size if it does flash render.
  textarea.style.padding = 0;

  // Clean up any borders.
  textarea.style.border = 'none';
  textarea.style.outline = 'none';
  textarea.style.boxShadow = 'none';

  // Avoid flash of white box if rendered for any reason.
  textarea.style.background = 'transparent';
  document.querySelector("body").appendChild(textarea);

  textarea.value = text;
  textarea.select();

  try {
    var status = document.execCommand('copy');
    if (!status){
      error("Cannot copy text. See snippet code.");
    } else {
      log("Copied to clipboard!");
    }
  } catch (err) {
    log('Unable to copy. See snippet code.');
  }

  textarea.remove();
}

function log(text) {
  var textElement = document.createElement("div");
  textElement.innerText = text;
  textElement.className = '_clipboard_log_';
  textElement.style = `
        width: 540px;
        text-align: center;
    `;

  versionsTable.parentElement.appendChild(textElement);
}
<commit_msg>move changelog to separate file<commit_after>// Just for information of this snippet.
var ASCopyVersion = '1.1.0';

// TESTED ON BROWSERS:
// * Chrome 56.0.2924.87
// * Firefox 52.0 - Use Scratchpad in devtools.
//                  Copying from scratchpad doesn't work, use generated button after versions table.
// * Safari 10.0.3 - Just run snippet from console.

// Clear previous elements
var logs = document.querySelectorAll('._clipboard_log_');
logs.forEach(function(log) {
  log.parentNode.removeChild(log);
});
var copyButtonId = '_mycustom-clipboard-button-id_'
var isButtonExist = document.getElementById(copyButtonId);
if (isButtonExist) {
  document.getElementById(copyButtonId).remove();
}

var versionsTable = document.querySelector('.Version_table');
// Markdown view
var md = '';
var headSeparator = '||';
var bodySeparator = '|';

function isTableHead(iter) {
  return iter == 0;
}

function add(string) {
  md = md + string;
}

function addSeparator(iter) {
  isTableHead(iter) ? add(headSeparator) : add(bodySeparator);
}

for (var i = 0; i < versionsTable.childNodes.length; i++) {
  var tr = versionsTable.childNodes[i].childNodes[0];

  addSeparator(i);
  tr.childNodes.forEach(function(td){
    add(td.innerText);
    addSeparator(i);
  });

  // Add line break
  md = md + '\n';
}

if (md != '') {
  var button = document.createElement('button');
  button.id = copyButtonId;
  button.innerText = 'Click me to copy versions';
  button.style = `
        margin: 20px 0px;
        height: 60px;
        width: 540px;
        font-size: 20pt;
    `;
  versionsTable.parentElement.appendChild(button);
  button.addEventListener('click', function() {
    copyToClipboard(md);
  });

  copy(md);
  console.log(md);
  console.log('Copied to clipboard!');
  log("Copied to clipboard!");
}

// ||Component||Version||Date||
// |UI|2.1.0-34-gb4d27a6|2017-03-06T10:03:51±10|
// |appservices|2.1.0-start-298-g01ddc8|2017-03-06T16:50:05.816-0500|
// |authservice|1.1.0-start-126-gcf045e|2017-02-28T11:15:04.436-0500|
// |discountservice|1.1.0-start-126-gcf045e|2017-02-28T11:16:44.286-0500|
// |notificationservice|1.1.0-start-126-gcf045e|2017-02-28T11:15:32.974-0500|
// |profileservice|1.1.0-start-126-gcf045e|2017-02-28T11:16:00.802-0500|
// |roleservice|1.1.0-start-126-gcf045e|2017-02-28T11:16:24.693-0500|

function copyToClipboard(text){
  var textarea = document.createElement("textarea");
  textarea.id = "mycustom-clipboard-textarea-hidden-id";
  // Place in top-left corner of screen regardless of scroll position.
  textarea.style.position = 'absolute';
  textarea.style.top = 0;
  textarea.style.left = 0;

  // Ensure it has a small width and height. Setting to 1px / 1em
  // doesn't work as this gives a negative w/h on some browsers.
  textarea.style.width = '1px';
  textarea.style.height = '1px';

  // We don't need padding, reducing the size if it does flash render.
  textarea.style.padding = 0;

  // Clean up any borders.
  textarea.style.border = 'none';
  textarea.style.outline = 'none';
  textarea.style.boxShadow = 'none';

  // Avoid flash of white box if rendered for any reason.
  textarea.style.background = 'transparent';
  document.querySelector("body").appendChild(textarea);

  textarea.value = text;
  textarea.select();

  try {
    var status = document.execCommand('copy');
    if (!status){
      error("Cannot copy text. See snippet code.");
    } else {
      log("Copied to clipboard!");
    }
  } catch (err) {
    log('Unable to copy. See snippet code.');
  }

  textarea.remove();
}

function log(text) {
  var textElement = document.createElement("div");
  textElement.innerText = text;
  textElement.className = '_clipboard_log_';
  textElement.style = `
        width: 540px;
        text-align: center;
    `;

  versionsTable.parentElement.appendChild(textElement);
}
<|endoftext|>


<commit_before><commit_msg>Changed data load timing to msec = 0 and remove tailing 3 digits from keys in localstorage<commit_after><|endoftext|>


<commit_before>var app = require('app');
var autoUpdater = require('auto-updater');
var BrowserWindow = require('browser-window');
var fs = require('fs');
var os = require('os');
var ipc = require('ipc');
var path = require('path');
var child_process = require('child_process');

process.env.NODE_PATH = path.join(__dirname, 'node_modules');
process.env.RESOURCES_PATH = path.join(__dirname, '/../resources');
process.env.PATH = '/usr/local/bin:' + process.env.PATH;

var size = {}, settingsjson = {};
try {
  size = JSON.parse(fs.readFileSync(path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], 'Library', 'Application\ Support', 'Kitematic', 'size')));
} catch (err) {}
try {
  settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, 'settings.json'), 'utf8'));
} catch (err) {}

let updateCmd = (args, cb) => {
  let updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
  let child = child_process.spawn(updateExe, args, {detached: true});
  child.on('close', cb);
};

if (process.platform === 'win32') {
  var squirrelCommand = process.argv[1];
  let target = path.basename(process.execPath);
  switch (squirrelCommand) {
    case '--squirrel-install':
    case '--squirrel-updated':
      updateCmd(['--createShortcut', target], app.quit);
      break;
    case '--squirrel-uninstall':
      updateCmd(['--removeShortcut', target], app.quit);
      break;
    case '--squirrel-obsolete':
      app.quit();
      break;
  }
}

var openURL = null;
app.on('open-url', function (event, url) {
  event.preventDefault();
  openURL = url;
});

app.on('ready', function () {
  var mainWindow = new BrowserWindow({
    width: size.width || 800,
    height: size.height || 600,
    'min-width': 700,
    'min-height': 500,
    'standard-window': false,
    resizable: true,
    frame: false,
    show: false
  });

  mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, 'index.html')));

  app.on('activate-with-no-open-windows', function () {
    if (mainWindow) {
      mainWindow.show();
    }
    return false;
  });

  var updating = false;
  ipc.on('application:quit-install', function () {
    updating = true;
    autoUpdater.quitAndInstall();
  });

  if (os.platform() === 'win32') {
    mainWindow.on('close', function () {
      mainWindow.webContents.send('application:quitting');
      return true;
    });
    app.on('window-all-closed', function() {
      app.quit();
    });
  } else if (os.platform() === 'darwin') {
    app.on('before-quit', function () {
      if (!updating) {
        mainWindow.webContents.send('application:quitting');
      }
    });
  }

  mainWindow.webContents.on('new-window', function (e) {
    e.preventDefault();
  });

  mainWindow.webContents.on('will-navigate', function (e, url) {
    if (url.indexOf('build/index.html#') < 0) {
      e.preventDefault();
    }
  });

  mainWindow.webContents.on('did-finish-load', function() {
    mainWindow.setTitle('Kitematic');
    mainWindow.show();
    mainWindow.focus();

    if (openURL) {
      mainWindow.webContents.send('application:open-url', {
        url: openURL
      });
    }
    app.on('open-url', function (event, url) {
      event.preventDefault();
      mainWindow.webContents.send('application:open-url', {
        url: url
      });
    });

    if (process.env.NODE_ENV !== 'development') {
      autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion() + '&beta=' + !!settingsjson.beta + '&platform=' + os.platform());
    }
  });

  autoUpdater.on('checking-for-update', function () {
    console.log('Checking for update...');
  });

  autoUpdater.on('update-available', function () {
    console.log('Update available.');
  });

  autoUpdater.on('update-not-available', function () {
    console.log('Update not available.');
  });

  autoUpdater.on('update-downloaded', function (e, releaseNotes, releaseName, releaseDate, updateURL) {
    console.log('Update downloaded.');
    console.log(releaseNotes, releaseName, releaseDate, updateURL);
    mainWindow.webContents.send('application:update-available');
  });

  autoUpdater.on('error', function (e, error) {
    console.log('An error occured while checking for updates.');
    console.log(error);
  });
});
<commit_msg>Fix bug where Kitematic window would be too large on Windows<commit_after>var app = require('app');
var autoUpdater = require('auto-updater');
var BrowserWindow = require('browser-window');
var fs = require('fs');
var os = require('os');
var ipc = require('ipc');
var path = require('path');
var child_process = require('child_process');

process.env.NODE_PATH = path.join(__dirname, 'node_modules');
process.env.RESOURCES_PATH = path.join(__dirname, '/../resources');
process.env.PATH = '/usr/local/bin:' + process.env.PATH;

var size = {}, settingsjson = {};
try {
  size = JSON.parse(fs.readFileSync(path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], 'Library', 'Application\ Support', 'Kitematic', 'size')));
} catch (err) {}
try {
  settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, 'settings.json'), 'utf8'));
} catch (err) {}

let updateCmd = (args, cb) => {
  let updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
  let child = child_process.spawn(updateExe, args, {detached: true});
  child.on('close', cb);
};

if (process.platform === 'win32') {
  var squirrelCommand = process.argv[1];
  let target = path.basename(process.execPath);
  switch (squirrelCommand) {
    case '--squirrel-install':
    case '--squirrel-updated':
      updateCmd(['--createShortcut', target], app.quit);
      break;
    case '--squirrel-uninstall':
      updateCmd(['--removeShortcut', target], app.quit);
      break;
    case '--squirrel-obsolete':
      app.quit();
      break;
  }
}

var openURL = null;
app.on('open-url', function (event, url) {
  event.preventDefault();
  openURL = url;
});

app.on('ready', function () {
  var mainWindow = new BrowserWindow({
    width: size.width || 800,
    height: size.height || 600,
    'min-width': os.platform() === 'win32' ? 450 : 700,
    'min-height': os.platform() === 'win32' ? 290 : 500,
    'standard-window': false,
    resizable: true,
    frame: false,
    show: false
  });

  mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, 'index.html')));

  app.on('activate-with-no-open-windows', function () {
    if (mainWindow) {
      mainWindow.show();
    }
    return false;
  });

  var updating = false;
  ipc.on('application:quit-install', function () {
    updating = true;
    autoUpdater.quitAndInstall();
  });

  if (os.platform() === 'win32') {
    mainWindow.on('close', function () {
      mainWindow.webContents.send('application:quitting');
      return true;
    });
    app.on('window-all-closed', function() {
      app.quit();
    });
  } else if (os.platform() === 'darwin') {
    app.on('before-quit', function () {
      if (!updating) {
        mainWindow.webContents.send('application:quitting');
      }
    });
  }

  mainWindow.webContents.on('new-window', function (e) {
    e.preventDefault();
  });

  mainWindow.webContents.on('will-navigate', function (e, url) {
    if (url.indexOf('build/index.html#') < 0) {
      e.preventDefault();
    }
  });

  mainWindow.webContents.on('did-finish-load', function() {
    mainWindow.setTitle('Kitematic');
    mainWindow.show();
    mainWindow.focus();

    if (openURL) {
      mainWindow.webContents.send('application:open-url', {
        url: openURL
      });
    }
    app.on('open-url', function (event, url) {
      event.preventDefault();
      mainWindow.webContents.send('application:open-url', {
        url: url
      });
    });

    if (process.env.NODE_ENV !== 'development') {
      autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion() + '&beta=' + !!settingsjson.beta + '&platform=' + os.platform());
    }
  });

  autoUpdater.on('checking-for-update', function () {
    console.log('Checking for update...');
  });

  autoUpdater.on('update-available', function () {
    console.log('Update available.');
  });

  autoUpdater.on('update-not-available', function () {
    console.log('Update not available.');
  });

  autoUpdater.on('update-downloaded', function (e, releaseNotes, releaseName, releaseDate, updateURL) {
    console.log('Update downloaded.');
    console.log(releaseNotes, releaseName, releaseDate, updateURL);
    mainWindow.webContents.send('application:update-available');
  });

  autoUpdater.on('error', function (e, error) {
    console.log('An error occured while checking for updates.');
    console.log(error);
  });
});
<|endoftext|>


<commit_before>const rotation = require('./rotation')
const argv = require('minimist')(process.argv.slice(2))
console.log(rotation(argv))
<commit_msg>Add shebang<commit_after>#!/usr/bin/env node
const rotation = require('./rotation')
const argv = require('minimist')(process.argv.slice(2))
console.log(rotation(argv))
<|endoftext|>


<commit_before><commit_msg>Update app.js<commit_after><|endoftext|>


<commit_before>/*
Usage: sassdoc <src> <dest> [options]

Arguments:
  <src>   Path to your Sass folder.
  <dest>  Path to the destination folder.

Options:
  -h, --help            Bring help.
  --version             Show version.
  -v, --verbose         Enable verbose mode.
  -i, --interactive     Prompt to remove an existing destination directory.
  -f, --force           Always remove an existing destination directory
                        without asking.
  -c, --config=<path>   Path to JSON/YAML configuration file.
  -t, --theme=<name>    Theme to use.
  --sass-convert        Use if syntax is `.sass`.
  --no-update-notifier  Disable update notifier check.
*/

let docopt = require('fdocopt')();
let pkg = require('../package.json');
import * as cfg from './cfg';
import Logger from './logger';
import notifier from './notifier';
//import convert from './convert';
import sassdoc from './sassdoc';

export default function (argv = process.argv) {
  let options = docopt(__filename, { version: pkg.version, argv: argv });
  let logger = new Logger(options['--verbose']);

  // Load raw configuration
  let config = cfg.pre(options['--config'] || undefined, logger);

  // Ensure CLI options
  ensure(config, options, {
    theme: '--theme',
    interactive: '--interactive',
    force: '--force',
    sassConvert: '--sass-convert',
    noUpdateNotifier: '--no-update-notifier',
  });

  // Post process configuration
  cfg.post(config);

  // Run update notifier if not explicitely disabled
  if (!config.noUpdateNotifier) {
    notifier(pkg);
  }

  // Perform a Sass to SCSS syntax convertion
  //if (config.sassConvert) {
    //sassdoc = convert(sassdoc);
  //}

  sassdoc(options['<src>'], options['<dest>'], config);
}

/**
 * Ensure that CLI options take precedence over configuration values.
 *
 * For each name/option tuple, if the option is set, override configuration
 * value.
 */
function ensure(config, options, names) {
  Object.keys(names).forEach(k => {
    let v = names[k];

    if (options[v]) {
      config[k] = options[v];
    }
  });
}
<commit_msg>Keep `config.view`<commit_after>/*
Usage: sassdoc <src> <dest> [options]

Arguments:
  <src>   Path to your Sass folder.
  <dest>  Path to the destination folder.

Options:
  -h, --help            Bring help.
  --version             Show version.
  -v, --verbose         Enable verbose mode.
  -i, --interactive     Prompt to remove an existing destination directory.
  -f, --force           Always remove an existing destination directory
                        without asking.
  -c, --config=<path>   Path to JSON/YAML configuration file.
  -t, --theme=<name>    Theme to use.
  --sass-convert        Use if syntax is `.sass`.
  --no-update-notifier  Disable update notifier check.
*/

let docopt = require('fdocopt')();
let pkg = require('../package.json');
import * as cfg from './cfg';
import Logger from './logger';
import notifier from './notifier';
//import convert from './convert';
import sassdoc from './sassdoc';

export default function (argv = process.argv) {
  let options = docopt(__filename, { version: pkg.version, argv: argv });
  let logger = new Logger(options['--verbose']);

  // Load raw configuration
  let config = cfg.pre(options['--config'] || undefined, logger);

  // Ensure CLI options
  ensure(config, options, {
    theme: '--theme',
    interactive: '--interactive',
    force: '--force',
    sassConvert: '--sass-convert',
    noUpdateNotifier: '--no-update-notifier',
  });

  // Post process configuration
  cfg.post(config);

  config.view = config; // Backward compatibility

  // Run update notifier if not explicitely disabled
  if (!config.noUpdateNotifier) {
    notifier(pkg);
  }

  // Perform a Sass to SCSS syntax convertion
  //if (config.sassConvert) {
    //sassdoc = convert(sassdoc);
  //}

  sassdoc(options['<src>'], options['<dest>'], config);
}

/**
 * Ensure that CLI options take precedence over configuration values.
 *
 * For each name/option tuple, if the option is set, override configuration
 * value.
 */
function ensure(config, options, names) {
  Object.keys(names).forEach(k => {
    let v = names[k];

    if (options[v]) {
      config[k] = options[v];
    }
  });
}
<|endoftext|>


<commit_before>"use strict";

const noop = () => {};

require("./res/stylesheet.css");

module.exports = setup => {

    window.addEventListener("load", () => {
        let
            touchDisabled = true,
            touchEvent;
        const
            mapping = setup(),
            coords = e => e.touches
                ? {x: e.touches[0].clientX, y: e.touches[0].clientY}
                : {x: e.clientX, y: e.clientY},
            click = e => {
                const {x, y} = coords(e);
                if (Object.keys(mapping).every(id => {
                    if ("undefined" === id) {
                        return true; // skip
                    }
                    const rect = document.getElementById(id).getBoundingClientRect();
                    if (!(x < rect.left || x > rect.right || y < rect.top || y > rect.bottom)) {
                        mapping[id]();
                        return false;
                    }
                    return true;

                })) {
                    (mapping["undefined"] || noop)();
                }
            };

        window.addEventListener("click", e => touchDisabled ? click(e) : 0, true);
        window.addEventListener("touchstart", e => {
            touchDisabled = false;
            touchEvent = e;
        }, false);
        window.addEventListener("touchmove", () => {
            touchEvent = null;
        }, false);
        window.addEventListener("touchend", () => {
            if (null !== touchEvent) {
                click(touchEvent);
                touchEvent = null;
            }
        }, false);
    });

};
<commit_msg>One page to run them all<commit_after>"use strict";

let
    _mapping = {};

const
    noop = require("./noop"),

    coords = e => e.touches
        ? {x: e.touches[0].clientX, y: e.touches[0].clientY}
        : {x: e.clientX, y: e.clientY},

    click = e => {
        const {x, y} = coords(e);
        if (Object.keys(_mapping).filter(id => id !== "undefined").every(id => {
            const rect = document.getElementById(id).getBoundingClientRect();
            if (!(x < rect.left || x > rect.right || y < rect.top || y > rect.bottom)) {
                _mapping[id]();
                return false;
            }
            return true;

        })) {
            (_mapping["undefined"] || noop)();
        }
    };

require("./res/stylesheet.css");

window.addEventListener("load", () => {
    let
        touchDisabled = true,
        touchEvent;

    window.addEventListener("click", e => touchDisabled ? click(e) : 0, true);
    window.addEventListener("touchstart", e => {
        touchDisabled = false;
        touchEvent = e;
    }, false);
    window.addEventListener("touchmove", () => {
        touchEvent = null;
    }, false);
    window.addEventListener("touchend", () => {
        if (null !== touchEvent) {
            click(touchEvent);
            touchEvent = null;
        }
    }, false);

});

module.exports = {

    setMapping: mapping => {
        _mapping = mapping;
    }

};
<|endoftext|>