<commit_before>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013-2018  School of Business and Engineering Vaud, Comem, MEI
 * Licensed under the MIT License
 */
/**
 * @fileOverview
 * @author maxence
 */
YUI.add('wegas-eventlogger', function(Y) {
    "use strict";

    var EventLogger;

    EventLogger = Y.Base.create("wegas-eventlogger", Y.Plugin.Base, [Y.Wegas.Plugin, Y.Wegas.Editable], {
        initializer: function() {
            var i, k;
            var events = [
                "updatedInstance",
                "updatedDescriptor",
                "added",
                "delete",
                "update"
            ];
            this.handlers = [];
            this.ds = {};
            for (k in Y.Wegas.Facade) {
                if (Y.Wegas.Facade.hasOwnProperty(k) && Y.Wegas.Facade[k] instanceof Y.Wegas.DataSource) {
                    if (!this.ds[Y.Wegas.Facade[k]._yuid]) {
                        this.ds[Y.Wegas.Facade[k]._yuid] = k;
                        for (i in events) {
                            Y.log("Bind: " + k + "::" + events[i]);
                            this.handlers.push(Y.Wegas.Facade[k].on(events[i], Y.bind(this.logEvent, this)));
                        }
                    } else {
                        Y.log("Skip duplicata: " + k);
                    }
                }
            }
        },
        _printEntity: function(entity) {
            if (entity instanceof Y.Wegas.persistence.VariableDescriptor) {
                return entity.get("@class") + " " + entity.get("name");
            } else if (entity instanceof Y.Wegas.persistence.VariableInstance) {
                return this._printEntity(entity.getDescriptor()) + " instance for " + entity.get("scopeKey");
            } else {
                return entity.get("@class");
            }
        },
        logEvent: function(e) {
            var msg = this.ds[e.target._yuid] + " fires " + e.type;
            if (e.entity) {
                msg += " with entity: ";
                msg += this._printEntity(e.entity);
            }
            if (e.parent) {
                msg += " with parent: ";
                msg += this._printEntity(e.parent);
            }
            Y.log(msg);
        },
        destructor: function() {
            var k;
            for (k in this.handlers) {
                this.handlers[k].detach();
            }
        }
    }, {
        NS: "eventlogger",
        ATTRS: {
            eventLogger: {
                value: "EventLogger",
                type: "string"
            }
        }
    });
    Y.Plugin.EventLogger = EventLogger;
});
<commit_msg>Remove unused ATTRS<commit_after>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013-2018  School of Business and Engineering Vaud, Comem, MEI
 * Licensed under the MIT License
 */
/**
 * @fileOverview
 * @author maxence
 */
YUI.add('wegas-eventlogger', function(Y) {
    "use strict";

    var EventLogger;

    EventLogger = Y.Base.create("wegas-eventlogger", Y.Plugin.Base, [Y.Wegas.Plugin, Y.Wegas.Editable], {
        initializer: function() {
            var i, k;
            var events = [
                "updatedInstance",
                "updatedDescriptor",
                "added",
                "delete",
                "update"
            ];
            this.handlers = [];
            this.ds = {};
            for (k in Y.Wegas.Facade) {
                if (Y.Wegas.Facade.hasOwnProperty(k) && Y.Wegas.Facade[k] instanceof Y.Wegas.DataSource) {
                    if (!this.ds[Y.Wegas.Facade[k]._yuid]) {
                        this.ds[Y.Wegas.Facade[k]._yuid] = k;
                        for (i in events) {
                            Y.log("Bind: " + k + "::" + events[i]);
                            this.handlers.push(Y.Wegas.Facade[k].on(events[i], Y.bind(this.logEvent, this)));
                        }
                    } else {
                        Y.log("Skip duplicata: " + k);
                    }
                }
            }
        },
        _printEntity: function(entity) {
            if (entity instanceof Y.Wegas.persistence.VariableDescriptor) {
                return entity.get("@class") + " " + entity.get("name");
            } else if (entity instanceof Y.Wegas.persistence.VariableInstance) {
                return this._printEntity(entity.getDescriptor()) + " instance for " + entity.get("scopeKey");
            } else {
                return entity.get("@class");
            }
        },
        logEvent: function(e) {
            var msg = this.ds[e.target._yuid] + " fires " + e.type;
            if (e.entity) {
                msg += " with entity: ";
                msg += this._printEntity(e.entity);
            }
            if (e.parent) {
                msg += " with parent: ";
                msg += this._printEntity(e.parent);
            }
            Y.log(msg);
        },
        destructor: function() {
            var k;
            for (k in this.handlers) {
                this.handlers[k].detach();
            }
        }
    }, {
        NS: "eventlogger",
        ATTRS: {}
    });
    Y.Plugin.EventLogger = EventLogger;
});
<|endoftext|>


<commit_before>var Tasks = require('./tasks');

/**
 * Slack request looks like this:
 *
 * token=TOKEN
 * team_id=T0001
 * team_domain=example
 * channel_id=C2147483705
 * channel_name=test
 * user_id=U2147483697
 * user_name=Steve
 * command=/weather
 * text=94070
 * response_url=https://hooks.slack.com/commands/1234/5678
 */

var helpText = "Help text goes here!";

var main = function (req, res, next) {
  var responseType = "ephemeral";
  var payloadText = "";
  var attachments = [];

  var text = req.body.text;
  var textParts = text.split(" ");

  if(textParts.length <= 0) {
    payloadText = "Looks like you forgot to add commands! Type `/taskbot help` to see how to use taskbot";
  } else if (textParts[0] == "help") {
    payloadText = helpText;
  } else if (textParts[0] === "list") {
    responseType = "in_channel";
    payloadText = "List tasks interface goes here!";
  } else if (textParts[0] === "new") {
    responseType = "in_channel";
    payloadText = "New task interface goes here!";
  } else if (textParts[0] === "assign") {
    responseType = "in_channel";
    payloadText = "Assign task interface goes here!";
  }

  var payload = {
    "response_type": responseType,
    "text": payloadText,
    "attachments": attachments
  };

  // avoid infinite loop
  if (req.body.user_name !== 'slackbot') {
    return res.status(200).json(payload);
  } else {
    return res.status(200).end();
  }
}

module.exports = main;<commit_msg>Add else condition to parser<commit_after>var Tasks = require('./tasks');

/**
 * Slack request looks like this:
 *
 * token=TOKEN
 * team_id=T0001
 * team_domain=example
 * channel_id=C2147483705
 * channel_name=test
 * user_id=U2147483697
 * user_name=Steve
 * command=/weather
 * text=94070
 * response_url=https://hooks.slack.com/commands/1234/5678
 */

var helpText = "Help text goes here!";

var main = function (req, res, next) {
  var responseType = "ephemeral";
  var payloadText = "";
  var attachments = [];

  var text = req.body.text;
  var textParts = text.split(" ");

  if(textParts.length <= 0) {
    payloadText = "Looks like you forgot to add commands! Type `/taskbot help` to see how to use taskbot";
  } else if (textParts[0] == "help") {
    payloadText = helpText;
  } else if (textParts[0] === "list") {
    responseType = "in_channel";
    payloadText = "List tasks interface goes here!";
  } else if (textParts[0] === "new") {
    responseType = "in_channel";
    payloadText = "New task interface goes here!";
  } else if (textParts[0] === "assign") {
    responseType = "in_channel";
    payloadText = "Assign task interface goes here!";
  } else if (textParts[0] === "finish") {
    responseType = "in_channel";
    payloadText = "Finish task interface goes here!";
  } else {
    payloadText = "Sorry, we didn't recognize that command. Try typing `/taskbot help` for options.";
  }

  var payload = {
    "response_type": responseType,
    "text": payloadText,
    "attachments": attachments
  };

  // avoid infinite loop
  if (req.body.user_name !== 'slackbot') {
    return res.status(200).json(payload);
  } else {
    return res.status(200).end();
  }
}

module.exports = main;<|endoftext|>


<commit_before>'use strict';

module.exports.initCombat = _initCombat;

//TODO: Add strings for sanity damage

const util = require('util');
const _    = require('./helpers');

const Random      = require('./random.js').Random;
const LevelUtil   = require('./levels').LevelUtil;
const CommandUtil = require('./command_util').CommandUtil;
const statusUtils = require('./status');
const Commands    = require('./commands').Commands;
const CombatUtil  = require('./combat_util').CombatUtil;
const Type        = require('./type').Type;
const Effects     = require('./effects').Effects;
const Broadcast   = require('./broadcast').Broadcast;

let dualWieldCancel = null;

function _initCombat(l10n, target, player, room, npcs, players, rooms, items, callback) {
  const locale = Type.isPlayer(player) ? 'en' : 'en';
  player.setInCombat(target);
  target.setInCombat(player);

  const broadcastToArea = Broadcast.toArea(player, players, rooms);

  player.sayL10n(l10n, 'ATTACK', target.getShortDesc('en'));

  /*
    Ideas:

    To hit vs. Dodge:
      Dodge = chance of auto-dodge, or does it need to be manual?
              Leave open to potential manual dodging in future.
              (manual dodging = temp. increase to dodge and lowered toHit/attackSpeed)
      ToHit = chance of hitting the enemy
              chance of hitting = attacker.toHit vs. target.dodge

    Damage vs. Defense:
      Defense soaks up damage depending on where the hit lands.
      It is possible for a blow to hit but then do zero damage.
      Defenses should be able to stack.

    Have different messaging for a dodged blow vs. a blow that hits
    yet does no damage.

    Also have different messaging for a near miss and a complete miss,
    as well as varieties of damage done.

    Consider having primary and secondary attacks for each npc, with varying
    amounts of damage.

    Consider allowing npcs to be equipped with armor and such at some point
    (this will be easier to implement with new API)
  */

  /**
   * Create attack round functions, then attach them
   * to the context for the combat round.
   * Sounds circular (and it is), but it works.
   * Then, invoke a timeout for each combatant's round.
   */
  const playerCombatContext = { combatRound: null };
  const targetCombatContext = { combatRound: null };
  const playerCombat = combatRound.bind(playerCombatContext, player, target);
  const targetCombat = combatRound.bind(targetCombatContext, target, player);

  playerCombatContext.combatRound = playerCombat;
  targetCombatContext.combatRound = targetCombat;

  const targetCombatCancel = setTimeout(targetCombat, target.combat.getAttackSpeed());
  const playerCombatCancel = setTimeout(playerCombat, player.combat.getAttackSpeed());

  /**
   * Detect if the attacker is dual wielding.
   * Then, figure out the speed and damage -- since
   * both are decreased depending on the player's skill level in
   * dual-wielding.
   *
   * Then, create another combat round so the attacker can dual-attack.
   * //TODO: Do the same for the defender once NPC dual attacks are a thing.
   * //TODO: Do the same once PvP is a thing, too.
   */

  const dualWieldBaseSpeed   = 2.1;
  const dualWieldSpeedFactor = dualWieldBaseSpeed - (player.getSkills('dual') / 10);

  //TODO: What if they swap weapons mid-fight?
  let isDualWielding = CommandUtil.hasScript(player.combat.getOffhand(), 'wield');
  const getDuelWieldSpeed = ()   => player.combat.getAttackSpeed(isDualWielding) * dualWieldSpeedFactor;
  const dualWieldDamage = damage => Math.round(damage * (0.5 + player.getSkills('dual') / 10));

  if (isDualWielding) {
    util.log("Player is using dual wield!");
    const secondAttack = {
      isSecondAttack: true,
    }
    const dualWieldCombat = combatRound.bind(secondAttack, player, target);
    secondAttack.combatRound = dualWieldCombat;
    dualWieldCancel = setTimeout(dualWieldCombat, getDuelWieldSpeed());
  }

  /**
   * Main combat round
   * Flow:
   * ======
   * Check if already in combat.
   * Determine speeds and effects. (tired, stressed, insane)
   * Set constants for this round. (speeds, descs, starting health, etc.)
   * Determine hit location.
   * See if the attack hits (toHit vs Dodge)
   * If it misses, see if it is parried, dodged, or just misses.
   * If it hits, see how much damage it does.
   * Appy damage to defender & broadcast/emit hitting.
   * See if defender is dead.
   * Apply sanity damage
   * Check for auto-flee.
   * Do combat prompt.
   * Broadcast to surrounding area.
   * Do it all again.
   *
   * @param attacker
   * @param defender
   */

  function combatRound(attacker, defender) {

    // Handle if attacker or defender is already in combat...
    //TODO: Remove this when allowing for multicombat.
    //TODO: Use an array of targets for multicombat.
    if (!defender.isInCombat() || !attacker.isInCombat()) { return; }

    // Assign weapon obj and name.
    const attackerWeapon = this.isSecondAttack ?
      attacker.combat.getOffhand() :
      attacker.combat.getWeapon();
    const attackerWeaponName = this.isSecondAttack ?
      attacker.combat.getSecondaryAttackName() :
      attacker.combat.getPrimaryAttackName();

    // Handle energy costs for attacking.
    const baseEnergyCost = 2;
    const isPlayerWithWeapon = Type.isPlayer(attacker) && attackerWeapon && attackerWeapon.getAttribute;
    const energyCost = isPlayerWithWeapon ?
      attackerWeapon.getAttribute('weight') || baseEnergyCost :
      baseEnergyCost;
    util.log('Attack energy cost for ' + attacker.getShortDesc('en') + ' is ' + energyCost);

    // Handle attacker fatigue
    const slowAttacker = Type.isPlayer(attacker) && !attacker.hasEnergy(energyCost, items);
    if (slowAttacker) {
      attacker.combat.addSpeedMod({
        name: 'fatigue',
        modifier: speed => speed + 1000
      });
      attacker.combat.addDodgeMod({
        name: 'fatigue',
        modifier: dodge => Math.max(dodge - 3, 1)
      });
      attacker.combat.addToHitMod({
        name: 'fatigue',
        modifier: toHit => Math.max(toHit - 3, 1)
      });
    } else {
      attacker.combat.removeAllMods('fatigue');
    }

    //FIXME:
    // // Handle attacker sanity effects...
    // const stressedLimit = 40;
    // const stressedAttacker = Type.isPlayer(attacker) && attacker.getAttribute('sanity') <= stressedLimit;
    // if (stressedAttacker) {
    //   attacker.addEffect('stressed', Effects.stressed, { attacker });

    //   const insanityLimit = 20;
    //   if (attacker.getAttribute('sanity') > insanityLimit) {
    //     attacker.addEffect('insane', Effects.insane, { attacker });
    //   }
    // }

    // Assign constants for this round...
    const attackerSpeed = attacker.combat.getAttackSpeed(this.isSecondAttack);
    const attackerDesc  = attacker.getShortDesc('en');
    const defenderDesc  = defender.getShortDesc('en');
    const attackDesc    = this.isSecondAttack ?
      attacker.combat.getSecondaryAttackName() :
      attacker.combat.getPrimaryAttackName();

    const defenderStartingHealth = defender.getAttribute('health');

    // Log constants for this round...
    util.log(attackerDesc + ' has speed of ' + attackerSpeed + '.');
    util.log(attackerDesc + ' health: ' + attacker.getAttribute('health'));
    util.log(defenderDesc + ' health: ' + defenderStartingHealth + '.\n');
    util.log(attackerDesc + ' is attacking... ');
    this.isSecondAttack ?
      util.log('** Offhand attack: ') :
      util.log('** Primary attack: ')

    // Assign possible sanity damage (for now, only npcs do sanity dmg)...
    const defenderSanity = defender.getAttribute('sanity');
    const sanityDamage = Type.isPlayer(defender) ?
      attacker.combat.getSanityDamage() || 0 :
      0;

    // Decide where the hit lands
    const hitLocation = CombatUtil.decideHitLocation(defender.getBodyParts(), attacker.combat.getTarget(), isPrecise());

    function isPrecise() {
      return Type.isPlayer(attacker) ?
        attacker.checkStance('precise') : false;
    }

    const missed = attacker.combat.getToHitChance() <= defender.combat.getDodgeChance();

    // If their attack misses!
    if (missed) {

      // Do they dodge, parry, or is it just a straight up miss?
      const defenderWeapon = defender.combat.getWeapon();
      const canParry = defenderWeapon ?
        CommandUtil.hasScript(defenderWeapon, 'parry') :
        CommandUtil.hasScript(defender, 'parry');
      const canDodge = CommandUtil.hasScript(defender, 'dodge');

      const parrySkill = Type.isPlayer(defender) ?
        defender.getSkills('parrying') + defender.getAttribute('cleverness') :
        defender.getAttribute('speed') * 2;
      const dodgeSkill = Type.isPlayer(defender) ?
        defender.getSkills('dodging') + defender.getAttribute('quickness') :
        defender.getAttribute('speed') * 2;

      if (canParry && parrySkill > Random.roll()) {
        util.log('The attack is parried!');
        if (defenderWeapon && CommandUtil.hasScript(defenderWeapon, 'parry')) {
          defenderWeapon.emit('parry', room, defender, attacker, players);
        } else {
          defender.emit('parry', attacker, room, players, hitLocation);
        }
      } else if (canDodge && dodgeSkill > Random.roll()) {
        util.log('They dodge!');
        defender.emit('dodge', room, attacker, players, hitLocation);

      // If it is just a regular ole miss...
      //TODO: What if there are no players involved in combat?
      } else {
        if (attackerWeapon && CommandUtil.hasScript(attackerWeapon, 'missedAttack')) {
          attackerWeapon.emit('missedAttack', room, defender, attacker, players, hitLocation);
        } else {
          attacker.emit('missedAttack', room, defender, players, hitLocation);
        }
      }

      util.log(attackerDesc + ' misses ' + defenderDesc);
    }

    if (!missed) {
      util.log('The attack hits!');

      // Begin assigning damage...
      const damage = this.isSecondAttack ?
        dualWieldDamage(attacker.combat.getDamage('offhand')) :
        attacker.combat.getDamage();
      util.log('Base damage for the ' + attackDesc + ': ', damage);

      // Actual damage based on hitLocation and armor...
      // The damage func has side effect of depleting defender's health.
      const damageDealt = defender.damage(damage, hitLocation);

      const attackerWeaponCanEmit = () => attackerWeapon && typeof attackerWeapon === 'object';

      if (attackerWeaponCanEmit()) {
        attackerWeapon.emit('hit', room, attacker, defender, players, hitLocation, damageDealt);
      } else {
        attacker.emit('hit', room, defender, players, hitLocation, damageDealt);
      }
      defender.emit('damaged', room, attacker, players, hitLocation, damageDealt);

      util.log(attackerDesc + ' targeted ' + attacker.combat.getTarget() + ' and hit ' + defenderDesc + ' in the ' + hitLocation + '.');

        // If the defender is dealt a deathblow, end combat...
        if (defenderStartingHealth <= damage) {
          defender.setAttribute('health', 1);
          defender.setAttribute('sanity', 1);
          if (attackerWeaponCanEmit()) {
            attackerWeapon.emit('deathblow', room, attacker, defender, players, hitLocation);
          }
          attacker.emit('deathblow', room, attacker, defender, players, hitLocation);

          return combatEnd(Type.isPlayer(attacker));
        }

    }

    // Do sanity damage if applicable...
    if (sanityDamage && defenderSanity) {
      defender.setAttribute('sanity', Math.max(defenderSanity - sanityDamage, 0));
    }

    // If the player is defending and still alive, see if they auto-flee.
    if (Type.isPlayer(defender)) {
      checkWimpiness(defenderStartingHealth);
    }

    // Display combat prompt.
    const getCondition = entity => {
        //FIXME: In statusUtils: This could be a problem if the combat is between two NPCs or two players.
        const npc    = Type.isPlayer(entity) ? target : false;
        const max    = entity.getAttribute('max_health');
        return statusUtils.getHealthText(max, player, npc);
    };

    if (Type.isPlayer(player)) {
      player.combatPrompt({
        target_condition: statusUtils.getHealthText(
          target.getAttribute('max_health'),
          player, target)(target.getAttribute('health')),
        player_condition: statusUtils.getHealthText(
          player.getAttribute('max_health'),
          player, false)(player.getAttribute('health'))
      });
    }

    // Make those in area aware of nearby combat...
    const nearbyFight = [
      "The sounds of a nearby struggle fill the air.",
      "From the sound of it, a mortal struggle is happening nearby.",
      "A cry from nearby! What could it be?",
      "The sounds of a clash echo nearby.",
      "You hear the sounds of flesh being rent, but you cannot tell from where.",
      "A thud, a muffled groan. Fighting nearby?"
    ];

    if (Random.coinFlip()) { broadcastToArea(Random.fromArray(nearbyFight)); }

    // Do it all over again...
    setTimeout(this.combatRound, attackerSpeed);
  }

  //TODO: Add to utils helper.js file
  function getPercentage(numerator, denominator) {
    return Math.round((numerator / denominator) * 100);
  }

  function combatEnd(success) {

    util.log("*** Combat Over ***");

    player.removeFromCombat(target);
    target.removeFromCombat(player);

    //TODO: Handle PvP or NvN combat ending differently.
    if (success) {
      if (dualWieldCancel) { clearTimeout(dualWieldCancel); }

      const hasKilled = player.hasKilled(target);

      room.removeNpc(target.getUuid());
      npcs.destroy(target);
      player.sayL10n(l10n, 'WIN', target.getShortDesc(locale));
      broadcastExceptPlayer('<bold>'
        + target.getShortDesc(locale) +
        ' dies.</bold>');

      const exp = target.getAttribute('experience') ?
        target.getAttribute('experience') : LevelUtil.mobExp(target.getAttribute('level'));
      util.log("Player wins, exp gain: ", exp);
      player.emit('experience', exp, 'killing and survival');

    } else {
      util.log("** Player death: ", player.getName());
      player.sayL10n(l10n, 'LOSE', target.getShortDesc(locale));
      player.fleeFromCombat();
      player.emit('die');

      broadcastExceptPlayer(player.getName() + ' collapses to the ground, life fleeing their body before your eyes.');

      broadcastExceptPlayer('<blue>A horrible feeling gnaws at the pit of your stomach.</blue>');
      broadcastToArea('The gurgles of a dying ' + statusUtils.getGenderNoun(player) + ' echo from nearby.');

      players.eachIf(
        p => p.getLocation() === room.getLocation(),
        p => p.emit('sanityLoss', 'witnessing gruesome death first-hand', 50)
      );
    }
    player.prompt();
    if (callback) { callback(success); }
  }

  //TODO: Extract this to combat utils.
  //TODO: Make NPCs have fleeing behavior, too.
  //TODO: Emit flee?
  function checkWimpiness(health) {
    var percentage = getPercentage(health, player.getAttribute('max_health'));
    var wimpiness = player.getPreference('wimpy')
    if (percentage < wimpiness) {
      util.log("Player's wimpiness kicks in...");
      util.log("Health: " + percentage + "% || Wimpiness: " + wimpiness + "%");
      player.say('You panic and try to flee.');
      Commands.player_commands.flee(null, player);
    }
  }

  //TODO: Use Broadcast module or extract to the Broadcast file.

  function broadcastExceptPlayer(msg) {
    players.eachExcept(player, p => {
      if (p.getLocation() === player.getLocation()) {
        p.say(msg);
        p.prompt();
      }
    });
  }

}
<commit_msg>That was silly.<commit_after>'use strict';

module.exports.initCombat = _initCombat;

//TODO: Add strings for sanity damage

const util = require('util');
const _    = require('./helpers');

const Random      = require('./random.js').Random;
const LevelUtil   = require('./levels').LevelUtil;
const CommandUtil = require('./command_util').CommandUtil;
const statusUtils = require('./status');
const Commands    = require('./commands').Commands;
const CombatUtil  = require('./combat_util').CombatUtil;
const Type        = require('./type').Type;
const Effects     = require('./effects').Effects;
const Broadcast   = require('./broadcast').Broadcast;

let dualWieldCancel = null;

function _initCombat(l10n, target, player, room, npcs, players, rooms, items, callback) {
  const locale = 'en';
  player.setInCombat(target);
  target.setInCombat(player);

  const broadcastToArea = Broadcast.toArea(player, players, rooms);

  player.sayL10n(l10n, 'ATTACK', target.getShortDesc('en'));

  /*
    Ideas:

    To hit vs. Dodge:
      Dodge = chance of auto-dodge, or does it need to be manual?
              Leave open to potential manual dodging in future.
              (manual dodging = temp. increase to dodge and lowered toHit/attackSpeed)
      ToHit = chance of hitting the enemy
              chance of hitting = attacker.toHit vs. target.dodge

    Damage vs. Defense:
      Defense soaks up damage depending on where the hit lands.
      It is possible for a blow to hit but then do zero damage.
      Defenses should be able to stack.

    Have different messaging for a dodged blow vs. a blow that hits
    yet does no damage.

    Also have different messaging for a near miss and a complete miss,
    as well as varieties of damage done.

    Consider having primary and secondary attacks for each npc, with varying
    amounts of damage.

    Consider allowing npcs to be equipped with armor and such at some point
    (this will be easier to implement with new API)
  */

  /**
   * Create attack round functions, then attach them
   * to the context for the combat round.
   * Sounds circular (and it is), but it works.
   * Then, invoke a timeout for each combatant's round.
   */
  const playerCombatContext = { combatRound: null };
  const targetCombatContext = { combatRound: null };
  const playerCombat = combatRound.bind(playerCombatContext, player, target);
  const targetCombat = combatRound.bind(targetCombatContext, target, player);

  playerCombatContext.combatRound = playerCombat;
  targetCombatContext.combatRound = targetCombat;

  const targetCombatCancel = setTimeout(targetCombat, target.combat.getAttackSpeed());
  const playerCombatCancel = setTimeout(playerCombat, player.combat.getAttackSpeed());

  /**
   * Detect if the attacker is dual wielding.
   * Then, figure out the speed and damage -- since
   * both are decreased depending on the player's skill level in
   * dual-wielding.
   *
   * Then, create another combat round so the attacker can dual-attack.
   * //TODO: Do the same for the defender once NPC dual attacks are a thing.
   * //TODO: Do the same once PvP is a thing, too.
   */

  const dualWieldBaseSpeed   = 2.1;
  const dualWieldSpeedFactor = dualWieldBaseSpeed - (player.getSkills('dual') / 10);

  //TODO: What if they swap weapons mid-fight?
  let isDualWielding = CommandUtil.hasScript(player.combat.getOffhand(), 'wield');
  const getDuelWieldSpeed = ()   => player.combat.getAttackSpeed(isDualWielding) * dualWieldSpeedFactor;
  const dualWieldDamage = damage => Math.round(damage * (0.5 + player.getSkills('dual') / 10));

  if (isDualWielding) {
    util.log("Player is using dual wield!");
    const secondAttack = {
      isSecondAttack: true,
    }
    const dualWieldCombat = combatRound.bind(secondAttack, player, target);
    secondAttack.combatRound = dualWieldCombat;
    dualWieldCancel = setTimeout(dualWieldCombat, getDuelWieldSpeed());
  }

  /**
   * Main combat round
   * Flow:
   * ======
   * Check if already in combat.
   * Determine speeds and effects. (tired, stressed, insane)
   * Set constants for this round. (speeds, descs, starting health, etc.)
   * Determine hit location.
   * See if the attack hits (toHit vs Dodge)
   * If it misses, see if it is parried, dodged, or just misses.
   * If it hits, see how much damage it does.
   * Appy damage to defender & broadcast/emit hitting.
   * See if defender is dead.
   * Apply sanity damage
   * Check for auto-flee.
   * Do combat prompt.
   * Broadcast to surrounding area.
   * Do it all again.
   *
   * @param attacker
   * @param defender
   */

  function combatRound(attacker, defender) {

    // Handle if attacker or defender is already in combat...
    //TODO: Remove this when allowing for multicombat.
    //TODO: Use an array of targets for multicombat.
    if (!defender.isInCombat() || !attacker.isInCombat()) { return; }

    // Assign weapon obj and name.
    const attackerWeapon = this.isSecondAttack ?
      attacker.combat.getOffhand() :
      attacker.combat.getWeapon();
    const attackerWeaponName = this.isSecondAttack ?
      attacker.combat.getSecondaryAttackName() :
      attacker.combat.getPrimaryAttackName();

    // Handle energy costs for attacking.
    const baseEnergyCost = 2;
    const isPlayerWithWeapon = Type.isPlayer(attacker) && attackerWeapon && attackerWeapon.getAttribute;
    const energyCost = isPlayerWithWeapon ?
      attackerWeapon.getAttribute('weight') || baseEnergyCost :
      baseEnergyCost;
    util.log('Attack energy cost for ' + attacker.getShortDesc('en') + ' is ' + energyCost);

    // Handle attacker fatigue
    const slowAttacker = Type.isPlayer(attacker) && !attacker.hasEnergy(energyCost, items);
    if (slowAttacker) {
      attacker.combat.addSpeedMod({
        name: 'fatigue',
        modifier: speed => speed + 1000
      });
      attacker.combat.addDodgeMod({
        name: 'fatigue',
        modifier: dodge => Math.max(dodge - 3, 1)
      });
      attacker.combat.addToHitMod({
        name: 'fatigue',
        modifier: toHit => Math.max(toHit - 3, 1)
      });
    } else {
      attacker.combat.removeAllMods('fatigue');
    }

    //FIXME:
    // // Handle attacker sanity effects...
    // const stressedLimit = 40;
    // const stressedAttacker = Type.isPlayer(attacker) && attacker.getAttribute('sanity') <= stressedLimit;
    // if (stressedAttacker) {
    //   attacker.addEffect('stressed', Effects.stressed, { attacker });

    //   const insanityLimit = 20;
    //   if (attacker.getAttribute('sanity') > insanityLimit) {
    //     attacker.addEffect('insane', Effects.insane, { attacker });
    //   }
    // }

    // Assign constants for this round...
    const attackerSpeed = attacker.combat.getAttackSpeed(this.isSecondAttack);
    const attackerDesc  = attacker.getShortDesc('en');
    const defenderDesc  = defender.getShortDesc('en');
    const attackDesc    = this.isSecondAttack ?
      attacker.combat.getSecondaryAttackName() :
      attacker.combat.getPrimaryAttackName();

    const defenderStartingHealth = defender.getAttribute('health');

    // Log constants for this round...
    util.log(attackerDesc + ' has speed of ' + attackerSpeed + '.');
    util.log(attackerDesc + ' health: ' + attacker.getAttribute('health'));
    util.log(defenderDesc + ' health: ' + defenderStartingHealth + '.\n');
    util.log(attackerDesc + ' is attacking... ');
    this.isSecondAttack ?
      util.log('** Offhand attack: ') :
      util.log('** Primary attack: ')

    // Assign possible sanity damage (for now, only npcs do sanity dmg)...
    const defenderSanity = defender.getAttribute('sanity');
    const sanityDamage = Type.isPlayer(defender) ?
      attacker.combat.getSanityDamage() || 0 :
      0;

    // Decide where the hit lands
    const hitLocation = CombatUtil.decideHitLocation(defender.getBodyParts(), attacker.combat.getTarget(), isPrecise());

    function isPrecise() {
      return Type.isPlayer(attacker) ?
        attacker.checkStance('precise') : false;
    }

    const missed = attacker.combat.getToHitChance() <= defender.combat.getDodgeChance();

    // If their attack misses!
    if (missed) {

      // Do they dodge, parry, or is it just a straight up miss?
      const defenderWeapon = defender.combat.getWeapon();
      const canParry = defenderWeapon ?
        CommandUtil.hasScript(defenderWeapon, 'parry') :
        CommandUtil.hasScript(defender, 'parry');
      const canDodge = CommandUtil.hasScript(defender, 'dodge');

      const parrySkill = Type.isPlayer(defender) ?
        defender.getSkills('parrying') + defender.getAttribute('cleverness') :
        defender.getAttribute('speed') * 2;
      const dodgeSkill = Type.isPlayer(defender) ?
        defender.getSkills('dodging') + defender.getAttribute('quickness') :
        defender.getAttribute('speed') * 2;

      if (canParry && parrySkill > Random.roll()) {
        util.log('The attack is parried!');
        if (defenderWeapon && CommandUtil.hasScript(defenderWeapon, 'parry')) {
          defenderWeapon.emit('parry', room, defender, attacker, players);
        } else {
          defender.emit('parry', attacker, room, players, hitLocation);
        }
      } else if (canDodge && dodgeSkill > Random.roll()) {
        util.log('They dodge!');
        defender.emit('dodge', room, attacker, players, hitLocation);

      // If it is just a regular ole miss...
      //TODO: What if there are no players involved in combat?
      } else {
        if (attackerWeapon && CommandUtil.hasScript(attackerWeapon, 'missedAttack')) {
          attackerWeapon.emit('missedAttack', room, defender, attacker, players, hitLocation);
        } else {
          attacker.emit('missedAttack', room, defender, players, hitLocation);
        }
      }

      util.log(attackerDesc + ' misses ' + defenderDesc);
    }

    if (!missed) {
      util.log('The attack hits!');

      // Begin assigning damage...
      const damage = this.isSecondAttack ?
        dualWieldDamage(attacker.combat.getDamage('offhand')) :
        attacker.combat.getDamage();
      util.log('Base damage for the ' + attackDesc + ': ', damage);

      // Actual damage based on hitLocation and armor...
      // The damage func has side effect of depleting defender's health.
      const damageDealt = defender.damage(damage, hitLocation);

      const attackerWeaponCanEmit = () => attackerWeapon && typeof attackerWeapon === 'object';

      if (attackerWeaponCanEmit()) {
        attackerWeapon.emit('hit', room, attacker, defender, players, hitLocation, damageDealt);
      } else {
        attacker.emit('hit', room, defender, players, hitLocation, damageDealt);
      }
      defender.emit('damaged', room, attacker, players, hitLocation, damageDealt);

      util.log(attackerDesc + ' targeted ' + attacker.combat.getTarget() + ' and hit ' + defenderDesc + ' in the ' + hitLocation + '.');

        // If the defender is dealt a deathblow, end combat...
        if (defenderStartingHealth <= damage) {
          defender.setAttribute('health', 1);
          defender.setAttribute('sanity', 1);
          if (attackerWeaponCanEmit()) {
            attackerWeapon.emit('deathblow', room, attacker, defender, players, hitLocation);
          }
          attacker.emit('deathblow', room, attacker, defender, players, hitLocation);

          return combatEnd(Type.isPlayer(attacker));
        }

    }

    // Do sanity damage if applicable...
    if (sanityDamage && defenderSanity) {
      defender.setAttribute('sanity', Math.max(defenderSanity - sanityDamage, 0));
    }

    // If the player is defending and still alive, see if they auto-flee.
    if (Type.isPlayer(defender)) {
      checkWimpiness(defenderStartingHealth);
    }

    // Display combat prompt.
    const getCondition = entity => {
        //FIXME: In statusUtils: This could be a problem if the combat is between two NPCs or two players.
        const npc    = Type.isPlayer(entity) ? target : false;
        const max    = entity.getAttribute('max_health');
        return statusUtils.getHealthText(max, player, npc);
    };

    if (Type.isPlayer(player)) {
      player.combatPrompt({
        target_condition: statusUtils.getHealthText(
          target.getAttribute('max_health'),
          player, target)(target.getAttribute('health')),
        player_condition: statusUtils.getHealthText(
          player.getAttribute('max_health'),
          player, false)(player.getAttribute('health'))
      });
    }

    // Make those in area aware of nearby combat...
    const nearbyFight = [
      "The sounds of a nearby struggle fill the air.",
      "From the sound of it, a mortal struggle is happening nearby.",
      "A cry from nearby! What could it be?",
      "The sounds of a clash echo nearby.",
      "You hear the sounds of flesh being rent, but you cannot tell from where.",
      "A thud, a muffled groan. Fighting nearby?"
    ];

    if (Random.coinFlip()) { broadcastToArea(Random.fromArray(nearbyFight)); }

    // Do it all over again...
    setTimeout(this.combatRound, attackerSpeed);
  }

  //TODO: Add to utils helper.js file
  function getPercentage(numerator, denominator) {
    return Math.round((numerator / denominator) * 100);
  }

  function combatEnd(success) {

    util.log("*** Combat Over ***");

    player.removeFromCombat(target);
    target.removeFromCombat(player);

    //TODO: Handle PvP or NvN combat ending differently.
    if (success) {
      if (dualWieldCancel) { clearTimeout(dualWieldCancel); }

      const hasKilled = player.hasKilled(target);

      room.removeNpc(target.getUuid());
      npcs.destroy(target);
      player.sayL10n(l10n, 'WIN', target.getShortDesc(locale));
      broadcastExceptPlayer('<bold>'
        + target.getShortDesc(locale) +
        ' dies.</bold>');

      const exp = target.getAttribute('experience') ?
        target.getAttribute('experience') : LevelUtil.mobExp(target.getAttribute('level'));
      util.log("Player wins, exp gain: ", exp);
      player.emit('experience', exp, 'killing and survival');

    } else {
      util.log("** Player death: ", player.getName());
      player.sayL10n(l10n, 'LOSE', target.getShortDesc(locale));
      player.fleeFromCombat();
      player.emit('die');

      broadcastExceptPlayer(player.getName() + ' collapses to the ground, life fleeing their body before your eyes.');

      broadcastExceptPlayer('<blue>A horrible feeling gnaws at the pit of your stomach.</blue>');
      broadcastToArea('The gurgles of a dying ' + statusUtils.getGenderNoun(player) + ' echo from nearby.');

      players.eachIf(
        p => p.getLocation() === room.getLocation(),
        p => p.emit('sanityLoss', 'witnessing gruesome death first-hand', 50)
      );
    }
    player.prompt();
    if (callback) { callback(success); }
  }

  //TODO: Extract this to combat utils.
  //TODO: Make NPCs have fleeing behavior, too.
  //TODO: Emit flee?
  function checkWimpiness(health) {
    var percentage = getPercentage(health, player.getAttribute('max_health'));
    var wimpiness = player.getPreference('wimpy')
    if (percentage < wimpiness) {
      util.log("Player's wimpiness kicks in...");
      util.log("Health: " + percentage + "% || Wimpiness: " + wimpiness + "%");
      player.say('You panic and try to flee.');
      Commands.player_commands.flee(null, player);
    }
  }

  //TODO: Use Broadcast module or extract to the Broadcast file.

  function broadcastExceptPlayer(msg) {
    players.eachExcept(player, p => {
      if (p.getLocation() === player.getLocation()) {
        p.say(msg);
        p.prompt();
      }
    });
  }

}
<|endoftext|>


<commit_before>#!/usr/bin/env node

const koa = require('koa');
const app = koa();

const path = require('path');
const fs = require('fs');
const argument = require('argument.js');

/*
  set argument options
*/
argument.option('port', 'The port your content should be served on.', '3000');
argument.option('maxage', 'Maxage for http caching.', '3600');
argument.option('version', 'Shows the installed version of hekto.', true);
argument.option('v', 'Shows the installed version of hekto.', true);

/*
  set argument command
*/
argument.command('serve', 'Serve the current directory.');

/*
  parse arguments
*/
const args = argument.parse(process.argv.slice(2));

/*
  if -v  of  --version option is passed in log the installed version of hekto
*/
if (args.v || args.version) {
  console.log(require('../package.json').version);
  process.exit();
}

if (args.serve) {
  const port = args.port || 3000;
  const cache = args.maxage || 3600;

  app.use(require('koa-cash')({
    maxAge: cache,
    get (key, maxAge) {
      return cache.get(key)
    },
    set (key, value) {
      cache.set(key, value)
    }
  }))

  app.use(require('koa-compress')());

  app.use(function *(next) {
    try {
      yield next;
    } catch (err) {
      this.status = 500;
      this.body = err;
      this.app.emit('error', err, this);
    }
  });

  app.use(function *() {
    let file = path.join(__dirname, this.request.url);
    const _404 = path.join(__dirname, '404.html');
    const query = this.querystring.length ? '?' + this.querystring : '';

    this.response.set('X-Powered-By', 'Hekto');

    if (fs.existsSync(file)) {
      if (fs.lstatSync(file).isDirectory()) {
        file = path.join(file, 'index.html');

        if (fs.existsSync(file)) {
          if (this.request.url.slice(-1) !== '/') {
            this.status = 307;

            this.redirect(this.request.url + '/' + query);
          } else {
            this.status = 200;

            this.type = 'html';
            this.body = fs.createReadStream(file);
          }
        } else {
          this.status = 404;

          if (fs.existsSync(_404) && fs.lstatSync(_404).isFile() && _404 !== false) {
            this.type = 'html';
            this.body = fs.createReadStream(_404);
          } else {
            this.body = '404 - Not found';
          }
        }

        return ;
      }

      if (fs.lstatSync(file).isFile()) {
        this.status = 200;

        if (path.extname(file) == '.html') {
          this.type = 'html';
        } else {
          this.type = 'text/plain; charset=utf-8';
        }

        this.body = fs.createReadStream(file);

        return ;
      }

      if (!this.body) {
        this.status = 404;

        if (fs.existsSync(_404) && fs.lstatSync(_404).isFile() && _404 !== false) {
          this.type = 'html';
          this.body = fs.createReadStream(_404);
        } else {
          this.body = '404 - Not found';
        }
      }
    } else {
      this.status = 404;

      if (fs.existsSync(_404) && fs.lstatSync(_404).isFile() && _404 !== false) {
        this.type = 'html';
        this.body = fs.createReadStream(_404);
      } else {
        this.body = '404 - Not found';
      }
    }
  });

  app.listen(port);
}
<commit_msg>add comments<commit_after>#!/usr/bin/env node

const koa = require('koa');
const app = koa();

const path = require('path');
const fs = require('fs');
const argument = require('argument.js');

/*
  set argument options
*/
argument.option('port', 'The port your content should be served on.', '3000');
argument.option('maxage', 'Maxage for http caching.', '3600');
argument.option('version', 'Shows the installed version of hekto.', true);
argument.option('v', 'Shows the installed version of hekto.', true);

/*
  set argument command
*/
argument.command('serve', 'Serve the current directory.');

/*
  parse arguments
*/
const args = argument.parse(process.argv.slice(2));

/*
  if -v  or --version option is passed in log the installed version of hekto to the console
*/
if (args.v || args.version) {
  console.log(require('../package.json').version);
  process.exit();
}

/*
  if `serve` command is passed in
*/
if (args.serve) {
  const port = args.port || 3000;
  const cache = args.maxage || 3600;

  // Add caching
  app.use(require('koa-cash')({
    maxAge: cache,
    get (key, maxAge) {
      return cache.get(key)
    },
    set (key, value) {
      cache.set(key, value)
    }
  }))

  // Add compression
  app.use(require('koa-compress')());

  // Add 500 error handling
  app.use(function *(next) {
    try {
      yield next;
    } catch (err) {
      this.status = 500;
      this.body = err;
      this.app.emit('error', err, this);
    }
  });

  // Add main webserver
  app.use(function *() {
    // Set path to requested file
    let file = path.join(__dirname, this.request.url);
    // set 404 file
    const _404 = path.join(__dirname, '404.html');
    // set query eg. my-site.com/test?user=me
    const query = this.querystring.length ? '?' + this.querystring : '';

    this.response.set('X-Powered-By', 'Hekto');

    // if requested file / directory exists
    if (fs.existsSync(file)) {
      // if `file` is a directory
      if (fs.lstatSync(file).isDirectory()) {
        // add `/index.html` to file
        file = path.join(file, 'index.html');

        // if file + `index.html` exists
        if (fs.existsSync(file)) {
          // add trailing slash
          if (this.request.url.slice(-1) !== '/') {
            this.status = 307;

            this.redirect(this.request.url + '/' + query);
          } else {
            this.status = 200;

            this.type = 'html';
            this.body = fs.createReadStream(file);
          }
        } else {
          this.status = 404;

          if (fs.existsSync(_404) && fs.lstatSync(_404).isFile() && _404 !== false) {
            this.type = 'html';
            this.body = fs.createReadStream(_404);
          } else {
            this.body = '404 - Not found';
          }
        }

        return ;
      }

      // if `file` is a file
      if (fs.lstatSync(file).isFile()) {
        this.status = 200;

        // if file extension is `.html`
        if (path.extname(file) == '.html') {
          // set content type to html
          this.type = 'html';
        } else {
          this.type = 'text/plain; charset=utf-8';
        }

        this.body = fs.createReadStream(file);

        return ;
      }

      // if  nothing is served yet
      if (!this.body) {
        this.status = 404;

        if (fs.existsSync(_404) && fs.lstatSync(_404).isFile() && _404 !== false) {
          this.type = 'html';
          this.body = fs.createReadStream(_404);
        } else {
          this.body = '404 - Not found';
        }
      }
    } else {
      // requested file / directory does not exists
      this.status = 404;

      if (fs.existsSync(_404) && fs.lstatSync(_404).isFile() && _404 !== false) {
        this.type = 'html';
        this.body = fs.createReadStream(_404);
      } else {
        this.body = '404 - Not found';
      }
    }
  });

  // serve on `port`
  app.listen(port);
}
<|endoftext|>


<commit_before>/* global browser, window, document, localStorage */
const CONTAINER_HIDE_SRC = '/img/container-hide.svg';
const CONTAINER_UNHIDE_SRC = '/img/container-unhide.svg';

function hideContainerTabs(userContextId) {
  const tabIdsToRemove = [];
  const tabUrlsToSave = [];
  const hideorshowIcon = document.querySelector(`#uci-${userContextId}-hideorshow-icon`);

  browser.runtime.sendMessage({
    method: 'queryTabs',
    userContextId: userContextId
  }).then(tabs=> {
    tabs.forEach(tab=> {
      tabIdsToRemove.push(tab.id);
      tabUrlsToSave.push(tab.url);
    });
    browser.runtime.sendMessage({
      method: 'hideTabs',
      userContextId: userContextId,
      tabUrlsToSave: tabUrlsToSave
    }).then(()=> {
      return browser.runtime.sendMessage({
        method: 'removeTabs',
        tabIds: tabIdsToRemove
      });
    }).then(() => {
      hideorshowIcon.src = CONTAINER_UNHIDE_SRC;
    });
  });
}

function showContainerTabs(userContextId) {
  const hideorshowIcon = document.querySelector(`#uci-${userContextId}-hideorshow-icon`);

  browser.runtime.sendMessage({
    method: 'showTabs',
    userContextId: userContextId
  }).then(hiddenTabUrls=> {
    hiddenTabUrls.forEach(url=> {
      browser.runtime.sendMessage({
        method: 'openTab',
        userContextId: userContextId,
        url: url
      });
    });
  }).then(() => {
    hideorshowIcon.src = CONTAINER_HIDE_SRC;
  });
}

if (localStorage.getItem('onboarded2')) {
  for (const element of document.querySelectorAll('.onboarding')) {
    element.classList.add('hide');
  }
  document.querySelector('#container-panel').classList.remove('hide');
} else if (localStorage.getItem('onboarded1')) {
  document.querySelector('.onboarding-panel-1').classList.add('hide');
  document.querySelector('#container-panel').classList.add('hide');
} else {
  document.querySelector('.onboarding-panel-2').classList.add('hide');
  document.querySelector('#container-panel').classList.add('hide');
}

document.querySelector('#onboarding-next-button').addEventListener('click', ()=> {
  localStorage.setItem('onboarded1', true);
  document.querySelector('.onboarding-panel-2').classList.remove('hide');
  document.querySelector('.onboarding-panel-1').classList.add('hide');
  document.querySelector('#container-panel').classList.add('hide');
});

document.querySelector('#onboarding-done-button').addEventListener('click', ()=> {
  localStorage.setItem('onboarded2', true);
  document.querySelector('.onboarding-panel-1').classList.add('hide');
  document.querySelector('.onboarding-panel-2').classList.add('hide');
  document.querySelector('#container-panel').classList.remove('hide');
});

browser.runtime.sendMessage({method: 'queryIdentities'}).then(identities=> {
  const identitiesListElement = document.querySelector('.identities-list');

  identities.forEach(identity=> {
    let hideOrShowIconSrc = CONTAINER_HIDE_SRC;

    if (identity.hiddenTabUrls.length) {
      hideOrShowIconSrc = CONTAINER_UNHIDE_SRC;
    }
    const identityRow = `

      ${identity.name}

      >

`;

    identitiesListElement.innerHTML += identityRow;
  });

  const rows = identitiesListElement.querySelectorAll('tr');

  rows.forEach(row=> {
    row.addEventListener('click', e=> {
      const userContextId = e.target.parentElement.parentElement.dataset.identityCookieStoreId;

      if (e.target.matches('.hideorshow-icon')) {
        browser.runtime.sendMessage({method: 'getIdentitiesState'}).then(identitiesState=> {
          if (identitiesState[userContextId].hiddenTabUrls.length) {
            showContainerTabs(userContextId);
          } else {
            hideContainerTabs(userContextId);
          }
        });
      } else if (e.target.matches('.newtab-icon')) {
        browser.runtime.sendMessage({
          method: 'openTab',
          userContextId: userContextId})
        .then(() => {
          window.close();
        });
      }
    });
  });
});

document.querySelector('#edit-containers-link').addEventListener('click', ()=> {
  browser.runtime.sendMessage({
    method: 'openTab',
    url: "about:preferences#containers"
  }).then(()=> {
    window.close();
  });
});

document.querySelector('#sort-containers-link').addEventListener('click', ()=> {
  browser.runtime.sendMessage({ method: 'sortTabs' });
});
<commit_msg>Close popup after sorting<commit_after>/* global browser, window, document, localStorage */
const CONTAINER_HIDE_SRC = '/img/container-hide.svg';
const CONTAINER_UNHIDE_SRC = '/img/container-unhide.svg';

function hideContainerTabs(userContextId) {
  const tabIdsToRemove = [];
  const tabUrlsToSave = [];
  const hideorshowIcon = document.querySelector(`#uci-${userContextId}-hideorshow-icon`);

  browser.runtime.sendMessage({
    method: 'queryTabs',
    userContextId: userContextId
  }).then(tabs=> {
    tabs.forEach(tab=> {
      tabIdsToRemove.push(tab.id);
      tabUrlsToSave.push(tab.url);
    });
    browser.runtime.sendMessage({
      method: 'hideTabs',
      userContextId: userContextId,
      tabUrlsToSave: tabUrlsToSave
    }).then(()=> {
      return browser.runtime.sendMessage({
        method: 'removeTabs',
        tabIds: tabIdsToRemove
      });
    }).then(() => {
      hideorshowIcon.src = CONTAINER_UNHIDE_SRC;
    });
  });
}

function showContainerTabs(userContextId) {
  const hideorshowIcon = document.querySelector(`#uci-${userContextId}-hideorshow-icon`);

  browser.runtime.sendMessage({
    method: 'showTabs',
    userContextId: userContextId
  }).then(hiddenTabUrls=> {
    hiddenTabUrls.forEach(url=> {
      browser.runtime.sendMessage({
        method: 'openTab',
        userContextId: userContextId,
        url: url
      });
    });
  }).then(() => {
    hideorshowIcon.src = CONTAINER_HIDE_SRC;
  });
}

if (localStorage.getItem('onboarded2')) {
  for (const element of document.querySelectorAll('.onboarding')) {
    element.classList.add('hide');
  }
  document.querySelector('#container-panel').classList.remove('hide');
} else if (localStorage.getItem('onboarded1')) {
  document.querySelector('.onboarding-panel-1').classList.add('hide');
  document.querySelector('#container-panel').classList.add('hide');
} else {
  document.querySelector('.onboarding-panel-2').classList.add('hide');
  document.querySelector('#container-panel').classList.add('hide');
}

document.querySelector('#onboarding-next-button').addEventListener('click', ()=> {
  localStorage.setItem('onboarded1', true);
  document.querySelector('.onboarding-panel-2').classList.remove('hide');
  document.querySelector('.onboarding-panel-1').classList.add('hide');
  document.querySelector('#container-panel').classList.add('hide');
});

document.querySelector('#onboarding-done-button').addEventListener('click', ()=> {
  localStorage.setItem('onboarded2', true);
  document.querySelector('.onboarding-panel-1').classList.add('hide');
  document.querySelector('.onboarding-panel-2').classList.add('hide');
  document.querySelector('#container-panel').classList.remove('hide');
});

browser.runtime.sendMessage({method: 'queryIdentities'}).then(identities=> {
  const identitiesListElement = document.querySelector('.identities-list');

  identities.forEach(identity=> {
    let hideOrShowIconSrc = CONTAINER_HIDE_SRC;

    if (identity.hiddenTabUrls.length) {
      hideOrShowIconSrc = CONTAINER_UNHIDE_SRC;
    }
    const identityRow = `

      ${identity.name}

      >

`;

    identitiesListElement.innerHTML += identityRow;
  });

  const rows = identitiesListElement.querySelectorAll('tr');

  rows.forEach(row=> {
    row.addEventListener('click', e=> {
      const userContextId = e.target.parentElement.parentElement.dataset.identityCookieStoreId;

      if (e.target.matches('.hideorshow-icon')) {
        browser.runtime.sendMessage({method: 'getIdentitiesState'}).then(identitiesState=> {
          if (identitiesState[userContextId].hiddenTabUrls.length) {
            showContainerTabs(userContextId);
          } else {
            hideContainerTabs(userContextId);
          }
        });
      } else if (e.target.matches('.newtab-icon')) {
        browser.runtime.sendMessage({
          method: 'openTab',
          userContextId: userContextId})
        .then(() => {
          window.close();
        });
      }
    });
  });
});

document.querySelector('#edit-containers-link').addEventListener('click', ()=> {
  browser.runtime.sendMessage({
    method: 'openTab',
    url: "about:preferences#containers"
  }).then(()=> {
    window.close();
  });
});

document.querySelector('#sort-containers-link').addEventListener('click', ()=> {
  browser.runtime.sendMessage({
    method: 'sortTabs'
  }).then(()=> {
    window.close();
  });
});
<|endoftext|>


<commit_before>const t = require('../test-lib/test.js');
const assert = require('assert');
let apos;

describe('Db', function() {
  after(async function () {
    return t.destroy(apos);
  });

  this.timeout(t.timeout);

  it('should exist on the apos object', async function() {
    apos = await require('../index.js')({
      root: module,
      shortName: 'test',
      argv: {
        _: []
      }
    });

    assert(apos.db);
    // Verify a normal, boring connection to localhost without the db option worked
    const doc = await apos.docs.db.findOne();

    assert(doc);
  });

  it('should be able to launch a second instance reusing the connection', async function() {
    const apos2 = await require('../index.js')({
      root: module,
      shortName: 'test2',
      argv: {
        _: []
      },
      modules: {
        'apostrophe-express': {
          port: 7777
        },
        'apostrophe-db': {
          db: apos.db,
          uri: 'mongodb://this-will-not-work-unless-db-successfully-overrides-it/fail'
        }
      }
    });

    const doc = await apos.docs.db.findOne();

    assert(doc);

    return t.destroy(apos2);
  });
});
<commit_msg>db tests pass<commit_after>const t = require('../test-lib/test.js');
const assert = require('assert');
let apos;

describe('Db', function() {
  after(async function () {
    return t.destroy(apos);
  });

  this.timeout(t.timeout);

  it('should exist on the apos object', async function() {
    apos = await require('../index.js')({
      root: module,
      shortName: 'test',
      argv: {
        _: []
      }
    });

    assert(apos.db);
    // Verify a normal, boring connection to localhost without the db option worked
    const doc = await apos.docs.db.findOne();

    assert(doc);
  });

  it('should be able to launch a second instance reusing the connection', async function() {
    const apos2 = await require('../index.js')({
      root: module,
      shortName: 'test2',
      argv: {
        _: []
      },
      modules: {
        'apostrophe-express': {
          options: {
            port: 7777
          }
        },
        'apostrophe-db': {
          db: apos.db,
          uri: 'mongodb://this-will-not-work-unless-db-successfully-overrides-it/fail'
        }
      }
    });

    const doc = await apos.docs.db.findOne();

    assert(doc);

    return t.destroy(apos2);
  });
});
<|endoftext|>


<commit_before>function viewTeams() {

    getTeams(
        success = function (data) {
            populateTeamsTable(data.teams);
        },
        error = function (jqxhr) {
            handleApiError(jqxhr);
        }
    );

    function populateTeamsTable(data) {
        var teamsHtml = templates.teamList(teams);
        $('.section').html(teamsHtml);

        $('.js-selectable-table tbody tr').click(function () {
            var teamId = $(this).attr('data-id');
            viewTeamDetails(teamId, $(this));
        });

        $('.form-create-team').submit(function (e) {
            e.preventDefault();

            var teamName = $('#create-team-name').val();

            if (teamName.length < 1) {
                sweetAlert("Please enter a user name.");
                return;
            }

            teamName = teamName.trim();
            postTeam(teamName);
        });
    }
}

<commit_msg>Fix teams screen throwing error and not loading<commit_after>function viewTeams() {

    getTeams(
        success = function (data) {
            populateTeamsTable(data.teams);
        },
        error = function (jqxhr) {
            handleApiError(jqxhr);
        }
    );

    function populateTeamsTable(data) {
        var teamsHtml = templates.teamList(data);
        $('.section').html(teamsHtml);

        $('.js-selectable-table tbody tr').click(function () {
            var teamId = $(this).attr('data-id');
            viewTeamDetails(teamId, $(this));
        });

        $('.form-create-team').submit(function (e) {
            e.preventDefault();

            var teamName = $('#create-team-name').val();

            if (teamName.length < 1) {
                sweetAlert("Please enter a user name.");
                return;
            }

            teamName = teamName.trim();
            postTeam(teamName);
        });
    }
}

<|endoftext|>


<commit_before>#!/usr/bin/env node

const util = require('util');
const exec = require('child_process').execSync;
const fs = require('fs');
const path = require('path');

const dirs = [
  //Flux
  './app',
  './app/actions',
  './app/constants',
  './app/components',
  './app/dispatcher',
  './app/stores',
  './app/utils',

  //Build
  './public',
  './public/css',
  './public/img',
  './public/js',

  //Jest
  './__tests__'
]

const npms = [
  //Babel
  'npm install --save-dev babel-cli',
  'npm install --save-dev babel-preset-es2015',
  'npm install --save-dev babel-preset-react',

  //React.js
  'npm install --save react',
  'npm install --save react-dom',
  'npm install --save-dev react-addons-css-transition-group',
  'npm install --save-dev react-addons-test-utils',
  'npm install --save-dev react-addons-perf',

  //Flux
  'npm install --save flux',

  //Immutable.js
  'npm install --save immutable',

  //Jest
  'npm install --save-dev jest-cli',
  'npm install --save-dev babel-jest',
  'npm install --save-dev babel-polyfill',

  //WebPack
  'npm install --save-dev webpack',
  'npm install --save-dev webpack-dev-server',
  'npm install --save-dev babel-loader',

  //ESLint
  'npm install --save-dev eslint',
  'npm install --save-dev eslint-plugin-import',
  'npm install --save-dev eslint-plugin-react',
  'npm install --save-dev eslint-plugin-jsx-a11y',
  'npm install --save-dev eslint-config-airbnb'
]

const npms_plus = [
  'npm install --save material-ui',
  'npm install --save react-tap-event-plugin',
  'npm install --save react-router',
  'npm install --save axios'
]

const repository = {
  "type":"git",
  "url":"https://example.com"
};

const jest = {
  "unmockedModulePathPatterns": [
    "<rootDir>/node_modules/react",
    "<rootDir>/node_modules/react-dom",
    "<rootDir>/node_modules/react-addons-test-utils"
  ]
};

const scripts = {
  "start": "webpack-dev-server -d --progress --colors --display-error-details",
  "build": "NODE_ENV=production node_modules/.bin/webpack -p --progress --colors",
  "test": "jest",
  "lint": "eslint app/**"
};

const eslint = {
    "extends": "airbnb",
    "plugins": [
        "react"
    ]
}

const webpackConfig =
`const webpack = require('webpack');

const config = {
  devtool: "inline-source-map",
  entry:  __dirname + "/app/App.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  },
  module: {
    loaders: [{
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loader: "babel",
      query: {
        presets: ["es2015","react"]
      }
    }]
  },
  devServer: {
    contentBase: "./public",
    colors: true,
    historyApiFallback: true,
    inline: true
  },
}

if (process.env.NODE_ENV === 'production') {
  config.devtool = false;
  config.plugins = [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin({comments: false}),
    new webpack.DefinePlugin({
      'process.env': {NODE_ENV: JSON.stringify('production')}
    })
  ];
};

module.exports = config;
`;

const indexHTML =
`<!DOCTYPE html>

    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="styles.css">

`;

const appJS =
`import React, { Component } from 'react';
import { render } from 'react-dom';
import { Container } from 'flux/utils';
import Sample from './components/Sample';

class App extends Component {
  static getStores() {
    return [];
  }

  static calculateState() {
    return null;
  }

  componentDidMount() {
  }

  render() {
    return (
      <Sample title="World" />
    );
  }
}

const AppContainer = Container.create(App);
render(<AppContainer />, document.getElementById('root'));
`;

const appDispatcherJS =
`import { Dispatcher } from 'flux';

class AppDispatcher extends Dispatcher {
  dispatch(action = {}) {
    super.dispatch(action);
  }
}

export default new AppDispatcher();
`;

const appConstantsJS =
`export const ActionTypes = {
  TYPE_001: 'type-001',
  TYPE_002: 'type-002',
};
`;

const componentSample =
`import React from 'react';

const Sample = (props) => (

Hello

{props.title}

);

Sample.propTypes = {
  title: React.PropTypes.string.isRequired,
};

export default Sample;
`;

const containerSample =
`import React from 'react';

const Sample = (props) => (

Hello

{props.title}

);

Sample.propTypes = {
  title: React.PropTypes.string.isRequired,
};

export default Sample;
`;

const sampleTest =
`jest.unmock('../app/components/Sample');

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import Sample from '../app/components/Sample'

describe('<Sample />', () => {
  it('displays "Hello World"', () => {
    const app = TestUtils.renderIntoDocument(

        <Sample title="World" />

    );
    const appNode = ReactDOM.findDOMNode(app);
    expect(appNode.textContent).toEqual('HelloWorld');
  });
});
`;

main();

function main() {
  console.log('*** starter-react-flux ***');
  const args = process.argv;
  switch (args.length) {
    case 3:
      if (args[2] == 'init') {
        setupReact();
        setupReactPlus();
        showComplete();
      } else if (args[2] == 'init-basic'){
        setupReact();
        showUsage();
      }
      break;
    case 4:
      if (args[2] == 'generate' && args[3] == 'test') {
        generateComponentTestFiles();
        showComplete();
      } else {
        showUsage();
      }
      break;
    case 5:
      if (args[2] == 'generate' && args[3] == 'store') {
        generateStoreFile(args[4]);
        showComplete();
      } else if (args[2] == 'generate' && args[3] == 'action') {
        generateActionFile(args[4]);
        showComplete();
      } else {
        showUsage();
      }
      break;
    default:
      showUsage();
      break;
  }
}

function showUsage() {
  console.log('Usage:');
  console.log('starter-react-flux init                             : Setup a React/Flux project.');
  console.log('starter-react-flux init-basic                       : Setup a React/Flux project which is limited for Facebook libraries');
  console.log('starter-react-flux generate test                    : Generate tests of components.');
  console.log('starter-react-flux generate store  [Store]          : Generate the Store. ');
  console.log('starter-react-flux generate action [ActionCreators] : Generate the ActionCreators.');
  process.exit(-1);
}

function showComplete() {
  console.log('Completed!');
}

function setupReact(arg) {
  createDirectories(dirs);
  exec('npm init -y', puts);
  fixJSON('package.json', 'description', 'React template.');
  fixJSON('package.json', 'repository', repository);
  fixJSON('package.json', 'jest', jest);
  fixJSON('package.json', 'scripts', scripts);
  createJSON('.eslintrc', eslint);
  createJSON('.babelrc', {"presets":["react", "es2015"]});
  createFile('./public/index.html', indexHTML);
  createFile('./public/css/style.css', '');
  createFile('webpack.config.js', webpackConfig);
  createFile('./app/App.js', appJS);
  createFile('./app/dispatcher/AppDispatcher.js', appDispatcherJS);
  createFile('./app/constants/AppConstants.js', appConstantsJS);
  createFile('./app/components/Sample.js', componentSample);
  createFile('./__tests__/Sample-test.js', sampleTest);
  npmInstall(npms);
}

function setupReactPlus() {
  npmInstall(npms_plus);
}

function generateComponentTestFiles() {
  const basePath = './app/components/';
  const components = getFileNames(basePath);
  for (const i in components) {
    const component = path.parse(components[i]).name;
    const testFile = './__tests__/' + component + '-test.js';
    createFile(testFile, generateComponentTestCode(component));
  }
}

function generateComponentTestCode(module) {
  const testCode =
`jest.unmock('../app/components/${module}');

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import ${module} from '../app/components/${module}'

describe('<${module} />', () => {
  it('', () => {
    const renderer = TestUtils.createRenderer();
    renderer.render(
      <${module} />
    );
    const dom = renderer.getRenderOutput();
    //expect(dom.props.//PROPS_NAME).toEqual('//TEXT');
  });
});
`
  return testCode;
}

function generateStoreFile(name) {

const code =
`import { ReduceStore } from 'flux/utils';
import { ActionTypes } from '../constants/AppConstants';
import AppDispatcher from '../dispatcher/AppDispatcher';
import Immutable from 'immutable';

class ${name} extends ReduceStore {
  getInitialState() {
    return [];
  }

  reduce(state, action) {
    switch (action.type) {
      case ActionTypes.TYPE_001:
        return state;
      default:
        return state;
    }
  }
}

export default new ${name}(AppDispatcher);
`;

  createFile(`./app/stores/${name}.js`, code);
}

function generateActionFile(name) {

const code =
`import AppDispatcher from '../dispatcher/AppDispatcher';
import { ActionTypes } from '../constants/AppConstants';

const ${name}ActionCreators = {

  action001(arg1) {
    //
    // Do something and pass the result to the data in the dispatch.
    //
    AppDispatcher.dispatch({
      type: ActionTypes.TYPE_001,
      data: 'RESULT OF YOUT ACTION',
    });
  },

  action002(arg1) {
    AppDispatcher.dispatch({
      type: ActionTypes.TYPE_002,
      data: 'RESULT OF YOUT ACTION',
    });
  },

};

export default ${name}ActionCreators;
`;

  createFile(`./app/actions/${name}ActionCreators.js`, code);
}

function getFileNames(dir) {
  if (fs.existsSync(dir)) {
    return fs.readdirSync(dir);
  }
  return [];
}

function createDirectories(dirs) {
  dirs.map(function(dir) {
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir);
      console.log('Create:', dir);
    }
  })
}

function npmInstall(npms) {
  npms.map(command => {
    console.log(command);
    exec(command, puts);
  });
}

function puts(error, stdout, stderr) {
  util.puts(stdout);
  util.puts(stderr);
  util.puts(error);
}

function createFile(file, content) {
  if (!fs.existsSync(file)) {
    fs.writeFileSync(file, content);
    console.log('Create:', file);
  }
}

function createJSON(file, json) {
  if (!fs.existsSync(file)) {
    fs.writeFileSync(file, JSON.stringify(json, null, "  "));
    console.log('Create:', file);
  }
}

function fixJSON(file, key, value) {
  var json = JSON.parse(fs.readFileSync(file));
  json[key] = value;
  fs.writeFileSync(file, JSON.stringify(json, null, "  "));
  console.log('Fix:', file, 'Key:', key);
}

<commit_msg>bug fix<commit_after>#!/usr/bin/env node

const util = require('util');
const exec = require('child_process').execSync;
const fs = require('fs');
const path = require('path');

const dirs = [
  //Flux
  './app',
  './app/actions',
  './app/constants',
  './app/components',
  './app/dispatcher',
  './app/stores',
  './app/utils',

  //Build
  './public',
  './public/css',
  './public/img',
  './public/js',

  //Jest
  './__tests__'
]

const npms = [
  //Babel
  'npm install --save-dev babel-cli',
  'npm install --save-dev babel-preset-es2015',
  'npm install --save-dev babel-preset-react',

  //React.js
  'npm install --save react',
  'npm install --save react-dom',
  'npm install --save-dev react-addons-css-transition-group',
  'npm install --save-dev react-addons-test-utils',
  'npm install --save-dev react-addons-perf',

  //Flux
  'npm install --save flux',

  //Immutable.js
  'npm install --save immutable',

  //Jest
  'npm install --save-dev jest-cli',
  'npm install --save-dev babel-jest',
  'npm install --save-dev babel-polyfill',

  //WebPack
  'npm install --save-dev webpack',
  'npm install --save-dev webpack-dev-server',
  'npm install --save-dev babel-loader',

  //ESLint
  'npm install --save-dev eslint',
  'npm install --save-dev eslint-plugin-import',
  'npm install --save-dev eslint-plugin-react',
  'npm install --save-dev eslint-plugin-jsx-a11y',
  'npm install --save-dev eslint-config-airbnb'
]

const npms_plus = [
  'npm install --save react-tap-event-plugin',
  'npm install --save material-ui',
  'npm install --save react-router',
  'npm install --save axios'
]

const repository = {
  "type":"git",
  "url":"https://example.com"
};

const jest = {
  "unmockedModulePathPatterns": [
    "<rootDir>/node_modules/react",
    "<rootDir>/node_modules/react-dom",
    "<rootDir>/node_modules/react-addons-test-utils"
  ]
};

const scripts = {
  "start": "webpack-dev-server -d --progress --colors --display-error-details",
  "build": "NODE_ENV=production node_modules/.bin/webpack -p --progress --colors",
  "test": "jest",
  "lint": "eslint app/**"
};

const eslint = {
    "extends": "airbnb",
    "plugins": [
        "react"
    ]
}

const webpackConfig =
`const webpack = require('webpack');

const config = {
  devtool: "inline-source-map",
  entry:  __dirname + "/app/App.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  },
  module: {
    loaders: [{
      test: /\.jsx?$/,
      exclude: /node_modules/,
      loader: "babel",
      query: {
        presets: ["es2015","react"]
      }
    }]
  },
  devServer: {
    contentBase: "./public",
    colors: true,
    historyApiFallback: true,
    inline: true
  },
}

if (process.env.NODE_ENV === 'production') {
  config.devtool = false;
  config.plugins = [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin({comments: false}),
    new webpack.DefinePlugin({
      'process.env': {NODE_ENV: JSON.stringify('production')}
    })
  ];
};

module.exports = config;
`;

const indexHTML =
`<!DOCTYPE html>

    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="styles.css">

`;

const appJS =
`import React, { Component } from 'react';
import { render } from 'react-dom';
import { Container } from 'flux/utils';
import Sample from './components/Sample';

class App extends Component {
  static getStores() {
    return [];
  }

  static calculateState() {
    return null;
  }

  componentDidMount() {
  }

  render() {
    return (
      <Sample title="World" />
    );
  }
}

const AppContainer = Container.create(App);
render(<AppContainer />, document.getElementById('root'));
`;

const appDispatcherJS =
`import { Dispatcher } from 'flux';

class AppDispatcher extends Dispatcher {
  dispatch(action = {}) {
    super.dispatch(action);
  }
}

export default new AppDispatcher();
`;

const appConstantsJS =
`export const ActionTypes = {
  TYPE_001: 'type-001',
  TYPE_002: 'type-002',
};
`;

const componentSample =
`import React from 'react';

const Sample = (props) => (

Hello

{props.title}

);

Sample.propTypes = {
  title: React.PropTypes.string.isRequired,
};

export default Sample;
`;

const containerSample =
`import React from 'react';

const Sample = (props) => (

Hello

{props.title}

);

Sample.propTypes = {
  title: React.PropTypes.string.isRequired,
};

export default Sample;
`;

const sampleTest =
`jest.unmock('../app/components/Sample');

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import Sample from '../app/components/Sample'

describe('<Sample />', () => {
  it('displays "Hello World"', () => {
    const app = TestUtils.renderIntoDocument(

        <Sample title="World" />

    );
    const appNode = ReactDOM.findDOMNode(app);
    expect(appNode.textContent).toEqual('HelloWorld');
  });
});
`;

main();

function main() {
  console.log('*** starter-react-flux ***');
  const args = process.argv;
  switch (args.length) {
    case 3:
      if (args[2] == 'init') {
        setupReact();
        setupReactPlus();
        showComplete();
      } else if (args[2] == 'init-basic'){
        setupReact();
        showUsage();
      }
      break;
    case 4:
      if (args[2] == 'generate' && args[3] == 'test') {
        generateComponentTestFiles();
        showComplete();
      } else {
        showUsage();
      }
      break;
    case 5:
      if (args[2] == 'generate' && args[3] == 'store') {
        generateStoreFile(args[4]);
        showComplete();
      } else if (args[2] == 'generate' && args[3] == 'action') {
        generateActionFile(args[4]);
        showComplete();
      } else {
        showUsage();
      }
      break;
    default:
      showUsage();
      break;
  }
}

function showUsage() {
  console.log('Usage:');
  console.log('starter-react-flux init                             : Setup a React/Flux project.');
  console.log('starter-react-flux init-basic                       : Setup a React/Flux project which is limited for Facebook libraries');
  console.log('starter-react-flux generate test                    : Generate tests of components.');
  console.log('starter-react-flux generate store  [Store]          : Generate the Store. ');
  console.log('starter-react-flux generate action [ActionCreators] : Generate the ActionCreators.');
  process.exit(-1);
}

function showComplete() {
  console.log('Completed!');
}

function setupReact(arg) {
  createDirectories(dirs);
  exec('npm init -y', puts);
  fixJSON('package.json', 'description', 'React template.');
  fixJSON('package.json', 'repository', repository);
  fixJSON('package.json', 'jest', jest);
  fixJSON('package.json', 'scripts', scripts);
  createJSON('.eslintrc', eslint);
  createJSON('.babelrc', {"presets":["react", "es2015"]});
  createFile('./public/index.html', indexHTML);
  createFile('./public/css/style.css', '');
  createFile('webpack.config.js', webpackConfig);
  createFile('./app/App.js', appJS);
  createFile('./app/dispatcher/AppDispatcher.js', appDispatcherJS);
  createFile('./app/constants/AppConstants.js', appConstantsJS);
  createFile('./app/components/Sample.js', componentSample);
  createFile('./__tests__/Sample-test.js', sampleTest);
  npmInstall(npms);
}

function setupReactPlus() {
  npmInstall(npms_plus);
}

function generateComponentTestFiles() {
  const basePath = './app/components/';
  const components = getFileNames(basePath);
  for (const i in components) {
    const component = path.parse(components[i]).name;
    const testFile = './__tests__/' + component + '-test.js';
    createFile(testFile, generateComponentTestCode(component));
  }
}

function generateComponentTestCode(module) {
  const testCode =
`jest.unmock('../app/components/${module}');

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import ${module} from '../app/components/${module}'

describe('<${module} />', () => {
  it('', () => {
    const renderer = TestUtils.createRenderer();
    renderer.render(
      <${module} />
    );
    const dom = renderer.getRenderOutput();
    //expect(dom.props.//PROPS_NAME).toEqual('//TEXT');
  });
});
`
  return testCode;
}

function generateStoreFile(name) {

const code =
`import { ReduceStore } from 'flux/utils';
import { ActionTypes } from '../constants/AppConstants';
import AppDispatcher from '../dispatcher/AppDispatcher';
import Immutable from 'immutable';

class ${name} extends ReduceStore {
  getInitialState() {
    return [];
  }

  reduce(state, action) {
    switch (action.type) {
      case ActionTypes.TYPE_001:
        return state;
      default:
        return state;
    }
  }
}

export default new ${name}(AppDispatcher);
`;

  createFile(`./app/stores/${name}.js`, code);
}

function generateActionFile(name) {

const code =
`import AppDispatcher from '../dispatcher/AppDispatcher';
import { ActionTypes } from '../constants/AppConstants';

const ${name}ActionCreators = {

  action001(arg1) {
    //
    // Do something and pass the result to the data in the dispatch.
    //
    AppDispatcher.dispatch({
      type: ActionTypes.TYPE_001,
      data: 'RESULT OF YOUT ACTION',
    });
  },

  action002(arg1) {
    AppDispatcher.dispatch({
      type: ActionTypes.TYPE_002,
      data: 'RESULT OF YOUT ACTION',
    });
  },

};

export default ${name}ActionCreators;
`;

  createFile(`./app/actions/${name}ActionCreators.js`, code);
}

function getFileNames(dir) {
  if (fs.existsSync(dir)) {
    return fs.readdirSync(dir);
  }
  return [];
}

function createDirectories(dirs) {
  dirs.map(function(dir) {
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir);
      console.log('Create:', dir);
    }
  })
}

function npmInstall(npms) {
  npms.map(command => {
    console.log(command);
    exec(command, puts);
  });
}

function puts(error, stdout, stderr) {
  util.puts(stdout);
  util.puts(stderr);
  util.puts(error);
}

function createFile(file, content) {
  if (!fs.existsSync(file)) {
    fs.writeFileSync(file, content);
    console.log('Create:', file);
  }
}

function createJSON(file, json) {
  if (!fs.existsSync(file)) {
    fs.writeFileSync(file, JSON.stringify(json, null, "  "));
    console.log('Create:', file);
  }
}

function fixJSON(file, key, value) {
  var json = JSON.parse(fs.readFileSync(file));
  json[key] = value;
  fs.writeFileSync(file, JSON.stringify(json, null, "  "));
  console.log('Fix:', file, 'Key:', key);
}

<|endoftext|>


<commit_before>/**
 * Created by felix on 09.05.16.
 */

import { Topic } from './topic'
import { Label } from './label'
import { _ } from 'meteor/underscore';

/**
 * A InfoItem is a sub-element of
 * a topic which has a subject,
 * a date when is was created
 * and a list of associated tags.
 */
export class InfoItem {

    constructor(parentTopic, source) {
        if (!parentTopic || !source)
            throw new Meteor.Error("It is not allowed to create a InfoItem without the parentTopicId and the source");

        this._parentTopic = undefined;
        this._infoItemDoc = undefined;

        if (typeof parentTopic === 'object') {   // we have a topic object here.
            this._parentTopic = parentTopic;
        }
        if (!this._parentTopic) {
            throw new Meteor.Error("No parent Topic given!");
        }

        if (typeof source === 'string') {   // we may have an ID here.
            // Caution: findInfoItem returns a InfoItem-Object not the document itself!
            let infoItem = this._parentTopic.findInfoItem(source);
            source = infoItem._infoItemDoc;
        }

        if (!source.hasOwnProperty('createdInMinute')) {
            throw new Meteor.Error('Property createdInMinute of topicDoc required');
        }

        _.defaults(source, {
            itemType: 'infoItem',
            isSticky: false,
            labels: []
        });
        this._infoItemDoc = source;
    }

    // ################### static methods
    static isActionItem(infoItemDoc) {
        return (infoItemDoc.itemType === 'actionItem');
    }

    // ################### object methods
    invalidateIsNewFlag() {
        // a normal info item has no isNew-Flag so it is nothing to do here
    }

    isSticky() {
        return this._infoItemDoc.isSticky;
    }

    toggleSticky() {
        this._infoItemDoc.isSticky = !this.isSticky();
    }

    async save(callback) {
        callback = callback || function () {};

        try {
            let result = await this.saveAsync();
            callback(undefined, result);
        } catch (error) {
            callback(error);
        }
    }

    async saveAsync() {
        // caution: this will update the entire topics array from the parent minutes of the parent topic!
        return this._parentTopic.upsertInfoItem(this._infoItemDoc);
    }

    getParentTopic() {
        return this._parentTopic;
    }

    isActionItem() {
        return InfoItem.isActionItem(this._infoItemDoc);
    }

    getDocument() {
        return this._infoItemDoc;
    }

    getLabels(meetingSeriesId) {
        this._infoItemDoc.labels = this.getLabelsRawArray().filter(labelId => {
            return (null !== Label.createLabelById(meetingSeriesId, labelId));
        });

        return this.getLabelsRawArray().map(labelId => {
            return Label.createLabelById(meetingSeriesId, labelId);

        })
    }

    addLabelByName(labelName, meetingSeriesId) {
        let label = Label.createLabelByName(meetingSeriesId, labelName);
        if (null == label) {
            label = new Label({name: labelName});
            label.save(meetingSeriesId);
        }

        if (!this.hasLabelWithId(label.getId())) {
            this._infoItemDoc.labels.push(label.getId());
        }

        console.log(this._infoItemDoc.labels);
    }

    hasLabelWithId(labelId) {
        let i;
        for (i = 0; i < this._infoItemDoc.labels.length; i++) {
            if (this._infoItemDoc.labels[i] === labelId) {
                return true;
            }
        }
        return false;
    }

    getLabelsRawArray() {
        if (!this._infoItemDoc.labels) {
            return [];
        }
        return this._infoItemDoc.labels;
    }

    toString () {
        return "InfoItem: " + JSON.stringify(this._infoItemDoc, null, 4);
    }

    log () {
        console.log(this.toString());
    }

    extractLabelsFromSubject(meetingSeriesId) {
        const regEx = /(^|[\s.,;])#([^\s.,;]+)/g;
        let match;

        while(match = regEx.exec(this._infoItemDoc.subject)) {
            let labelName = match[2];
            console.log(labelName);
            this.addLabelByName(labelName, meetingSeriesId);
            this._removeLabelFromSubject(labelName);
        }
    }

    _removeLabelFromSubject(labelName) {
        this._infoItemDoc.subject = this._infoItemDoc.subject.replace("#" + labelName + " ", "");
        this._infoItemDoc.subject = this._infoItemDoc.subject.replace(" #" + labelName, "");
        this._infoItemDoc.subject = this._infoItemDoc.subject.replace("#" + labelName, "");
    }

}<commit_msg>Constraint: a label defined within the item subject must start with a letter<commit_after>/**
 * Created by felix on 09.05.16.
 */

import { Topic } from './topic'
import { Label } from './label'
import { _ } from 'meteor/underscore';

/**
 * A InfoItem is a sub-element of
 * a topic which has a subject,
 * a date when is was created
 * and a list of associated tags.
 */
export class InfoItem {

    constructor(parentTopic, source) {
        if (!parentTopic || !source)
            throw new Meteor.Error("It is not allowed to create a InfoItem without the parentTopicId and the source");

        this._parentTopic = undefined;
        this._infoItemDoc = undefined;

        if (typeof parentTopic === 'object') {   // we have a topic object here.
            this._parentTopic = parentTopic;
        }
        if (!this._parentTopic) {
            throw new Meteor.Error("No parent Topic given!");
        }

        if (typeof source === 'string') {   // we may have an ID here.
            // Caution: findInfoItem returns a InfoItem-Object not the document itself!
            let infoItem = this._parentTopic.findInfoItem(source);
            source = infoItem._infoItemDoc;
        }

        if (!source.hasOwnProperty('createdInMinute')) {
            throw new Meteor.Error('Property createdInMinute of topicDoc required');
        }

        _.defaults(source, {
            itemType: 'infoItem',
            isSticky: false,
            labels: []
        });
        this._infoItemDoc = source;
    }

    // ################### static methods
    static isActionItem(infoItemDoc) {
        return (infoItemDoc.itemType === 'actionItem');
    }

    // ################### object methods
    invalidateIsNewFlag() {
        // a normal info item has no isNew-Flag so it is nothing to do here
    }

    isSticky() {
        return this._infoItemDoc.isSticky;
    }

    toggleSticky() {
        this._infoItemDoc.isSticky = !this.isSticky();
    }

    async save(callback) {
        callback = callback || function () {};

        try {
            let result = await this.saveAsync();
            callback(undefined, result);
        } catch (error) {
            callback(error);
        }
    }

    async saveAsync() {
        // caution: this will update the entire topics array from the parent minutes of the parent topic!
        return this._parentTopic.upsertInfoItem(this._infoItemDoc);
    }

    getParentTopic() {
        return this._parentTopic;
    }

    isActionItem() {
        return InfoItem.isActionItem(this._infoItemDoc);
    }

    getDocument() {
        return this._infoItemDoc;
    }

    getLabels(meetingSeriesId) {
        this._infoItemDoc.labels = this.getLabelsRawArray().filter(labelId => {
            return (null !== Label.createLabelById(meetingSeriesId, labelId));
        });

        return this.getLabelsRawArray().map(labelId => {
            return Label.createLabelById(meetingSeriesId, labelId);

        })
    }

    addLabelByName(labelName, meetingSeriesId) {
        let label = Label.createLabelByName(meetingSeriesId, labelName);
        if (null == label) {
            label = new Label({name: labelName});
            label.save(meetingSeriesId);
        }

        if (!this.hasLabelWithId(label.getId())) {
            this._infoItemDoc.labels.push(label.getId());
        }

        console.log(this._infoItemDoc.labels);
    }

    hasLabelWithId(labelId) {
        let i;
        for (i = 0; i < this._infoItemDoc.labels.length; i++) {
            if (this._infoItemDoc.labels[i] === labelId) {
                return true;
            }
        }
        return false;
    }

    getLabelsRawArray() {
        if (!this._infoItemDoc.labels) {
            return [];
        }
        return this._infoItemDoc.labels;
    }

    toString () {
        return "InfoItem: " + JSON.stringify(this._infoItemDoc, null, 4);
    }

    log () {
        console.log(this.toString());
    }

    extractLabelsFromSubject(meetingSeriesId) {
        const regEx = /(^|[\s.,;])#([a-zA-z]+[^\s.,;]*)/g;
        let match;

        while(match = regEx.exec(this._infoItemDoc.subject)) {
            let labelName = match[2];
            console.log(labelName);
            this.addLabelByName(labelName, meetingSeriesId);
            this._removeLabelFromSubject(labelName);
        }
    }

    _removeLabelFromSubject(labelName) {
        this._infoItemDoc.subject = this._infoItemDoc.subject.replace("#" + labelName + " ", "");
        this._infoItemDoc.subject = this._infoItemDoc.subject.replace(" #" + labelName, "");
        this._infoItemDoc.subject = this._infoItemDoc.subject.replace("#" + labelName, "");
    }

}<|endoftext|>


<commit_before>"use strict";
var global = require("./global.js");
var ASSERT = require("./assert.js");
var schedule;
if (typeof process !== "undefined" && process !== null &&
    typeof process.cwd === "function" &&
    typeof process.nextTick === "function" &&
    typeof process.version === "string") {
    schedule = function Promise$_Scheduler(fn) {
        process.nextTick(fn);
    };
}
else if ((typeof global.MutationObserver === "function" ||
        typeof global.WebkitMutationObserver === "function" ||
        typeof global.WebKitMutationObserver === "function") &&
        typeof document !== "undefined" &&
        typeof document.createElement === "function") {

    schedule = (function(){
        var MutationObserver = global.MutationObserver ||
            global.WebKitMutationObserver;
        var div = document.createElement("div");
        var queuedFn = void 0;
        var observer = new MutationObserver(
            function Promise$_Scheduler() {
                ASSERT(queuedFn !== void 0);
                var fn = queuedFn;
                queuedFn = void 0;
                fn();
            }
       );
        observer.observe(div, {
            attributes: true
        });
        return function Promise$_Scheduler(fn) {
            ASSERT(queuedFn === void 0);
            queuedFn = fn;
            div.setAttribute("class", "foo");
        };

    })();
}
else if (global.setTimeout) {
    schedule = function Promise$_Scheduler(fn) {
        setTimeout(fn, 4);
    };
}
else {
    schedule = function Promise$_Scheduler(fn) {
        fn();
    };
}

module.exports = schedule;
<commit_msg>Throw an error if no scheduler is available<commit_after>"use strict";
var global = require("./global.js");
var ASSERT = require("./assert.js");
var schedule;
if (typeof process !== "undefined" && process !== null &&
    typeof process.cwd === "function" &&
    typeof process.nextTick === "function" &&
    typeof process.version === "string") {
    schedule = function Promise$_Scheduler(fn) {
        process.nextTick(fn);
    };
}
else if ((typeof global.MutationObserver === "function" ||
        typeof global.WebkitMutationObserver === "function" ||
        typeof global.WebKitMutationObserver === "function") &&
        typeof document !== "undefined" &&
        typeof document.createElement === "function") {

    schedule = (function(){
        var MutationObserver = global.MutationObserver ||
            global.WebKitMutationObserver;
        var div = document.createElement("div");
        var queuedFn = void 0;
        var observer = new MutationObserver(
            function Promise$_Scheduler() {
                ASSERT(queuedFn !== void 0);
                var fn = queuedFn;
                queuedFn = void 0;
                fn();
            }
       );
        observer.observe(div, {
            attributes: true
        });
        return function Promise$_Scheduler(fn) {
            ASSERT(queuedFn === void 0);
            queuedFn = fn;
            div.setAttribute("class", "foo");
        };

    })();
}
else if (global.setTimeout) {
    schedule = function Promise$_Scheduler(fn) {
        setTimeout(fn, 4);
    };
}
else throw new Error("no async scheduler available");
module.exports = schedule;
<|endoftext|>


<commit_before>import MockAdapter from 'axios-mock-adapter';
import assert from 'assert';
import Chai from 'chai';
import Chatwork from '../index';

const chai = Chai.assert;

describe('/meのテスト', () => {
  it('GET /me', () => {
    const cw = new Chatwork('apiKey');
    const mock = new MockAdapter(cw.instance);

    const mockRes = {
      account_id: 123,
      room_id: 322,
      name: 'John Smith',
      chatwork_id: 'tarochatworkid',
      organization_id: 101,
      organization_name: 'Hello Company',
      department: 'Marketing',
      title: 'CMO',
      url: 'http://mycompany.com',
      introduction: 'Self Introduction',
      mail: 'taro@example.com',
      tel_organization: 'XXX-XXXX-XXXX',
      tel_extension: 'YYY-YYYY-YYYY',
      tel_mobile: 'ZZZ-ZZZZ-ZZZZ',
      skype: 'myskype_id',
      facebook: 'myfacebook_id',
      twitter: 'mytwitter_id',
      avatar_image_url: 'https://example.com/abc.png',
    };

    mock.onGet('/me').reply(200, mockRes);

    return cw.me()
    .then(res => {
      assert(
        JSON.stringify(res.data) === JSON.stringify(mockRes),
      );
    })
    .catch(err => {
      chai.fail(0, 1, err.message);
    });
  });
});
<commit_msg>Modify expression of mocha in me.js<commit_after>import MockAdapter from 'axios-mock-adapter';
import assert from 'assert';
import Chai from 'chai';
import Chatwork from '../index';

const chai = Chai.assert;

describe('/meのテスト', () => {
  describe('GET', () => {
    it('/me', () => {
      const cw = new Chatwork('apiKey');
      const mock = new MockAdapter(cw.instance);

      const mockRes = {
        account_id: 123,
        room_id: 322,
        name: 'John Smith',
        chatwork_id: 'tarochatworkid',
        organization_id: 101,
        organization_name: 'Hello Company',
        department: 'Marketing',
        title: 'CMO',
        url: 'http://mycompany.com',
        introduction: 'Self Introduction',
        mail: 'taro@example.com',
        tel_organization: 'XXX-XXXX-XXXX',
        tel_extension: 'YYY-YYYY-YYYY',
        tel_mobile: 'ZZZ-ZZZZ-ZZZZ',
        skype: 'myskype_id',
        facebook: 'myfacebook_id',
        twitter: 'mytwitter_id',
        avatar_image_url: 'https://example.com/abc.png',
      };

      mock.onGet('/me').reply(200, mockRes);

      return cw.me()
      .then(res => {
        assert(
          JSON.stringify(res.data) === JSON.stringify(mockRes),
        );
      })
      .catch(err => {
        chai.fail(0, 1, err.message);
      });
    });
  });
});
<|endoftext|>