<commit_before>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellLink from 'common/SpellLink';
import ITEMS from 'common/ITEMS';
import ItemLink from 'common/ItemLink';

import CoreChecklist, { Rule, Requirement } from 'Parser/Core/Modules/Features/Checklist';
import Abilities from 'Parser/Core/Modules/Abilities';
import { PreparationRule } from 'Parser/Core/Modules/Features/Checklist/Rules';
import { GenericCastEfficiencyRequirement } from 'Parser/Core/Modules/Features/Checklist/Requirements';
import CastEfficiency from 'Parser/Core/Modules/CastEfficiency';
import LegendaryUpgradeChecker from 'Parser/Core/Modules/Items/LegendaryUpgradeChecker';
import LegendaryCountChecker from 'Parser/Core/Modules/Items/LegendaryCountChecker';
import PrePotion from 'Parser/Core/Modules/Items/PrePotion';
import EnchantChecker from 'Parser/Core/Modules/Items/EnchantChecker';
import AbilityTracker from 'Parser/Core/Modules/AbilityTracker';

import AlwaysBeCasting from './AlwaysBeCasting';
import HolyPowerDetails from '../HolyPower/HolyPowerDetails';
import ArtOfWar from '../PaladinCore/ArtOfWar';
import Judgment from '../PaladinCore/Judgment';
import Liadrins from '../Items/LiadrinsFuryUnleashed';
import Whisper from '../Items/WhisperOfTheNathrezim';
import SoulOfTheHighlord from '../Items/SoulOfTheHighlord';
import Crusade from '../Talents/Crusade';
import Inquisition from '../Talents/Inquisition';

class Checklist extends CoreChecklist {
	static dependencies = {
    abilities: Abilities,
		castEfficiency: CastEfficiency,
    alwaysBeCasting: AlwaysBeCasting,
    legendaryUpgradeChecker: LegendaryUpgradeChecker,
    legendaryCountChecker: LegendaryCountChecker,
    prePotion: PrePotion,
    enchantChecker: EnchantChecker,
    abilityTracker: AbilityTracker,

    holyPowerDetails: HolyPowerDetails,
    artOfWar: ArtOfWar,
    judgment: Judgment,
    liadrins: Liadrins,
    soulOfTheHighlord: SoulOfTheHighlord,
    whisper: Whisper,
    crusade: Crusade,
    inquisition: Inquisition,
	};

  rules = [
    new Rule({
      name: 'Always be casting',
      description: <React.Fragment>You should try to avoid doing nothing during the fight. If you have to move, use your <SpellLink id={SPELLS.DIVINE_STEED.id} icon /> to minimize downtime. Also use ranged abilities like <SpellLink id={SPELLS.JUDGMENT_CAST.id} icon /> or <SpellLink id={SPELLS.BLADE_OF_JUSTICE.id} icon /> if out of melee range for extended periods.</React.Fragment>,
      requirements: () => {
        return [
          new Requirement({
            name: 'Downtime',
            check: () => this.alwaysBeCasting.suggestionThresholds,
          }),
        ];
      },
    }),
    new Rule({
      name: 'Use core abilities as often as possible',
      description: <React.Fragment>Spells with short cooldowns like <SpellLink id={SPELLS.JUDGMENT_CAST.id} icon />, <SpellLink id={SPELLS.BLADE_OF_JUSTICE.id} icon />, and <SpellLink id={SPELLS.CRUSADER_STRIKE.id} icon /> should be used as often as possible.</React.Fragment>,
      requirements: () => {
        const combatant = this.selectedCombatant;
        return [
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.CRUSADER_STRIKE,
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.JUDGMENT_CAST,
            onlyWithSuggestion: false,
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.BLADE_OF_JUSTICE,
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.CONSECRATION_TALENT,
            when: combatant.hasTalent(SPELLS.CONSECRATION_TALENT.id),
          }),
        ];
      },
    }),
    new Rule({
      name: 'Use your cooldowns',
      description: <React.Fragment>Retribution Paladin is a very cooldown dependant spec. Make sure you are keeping spells like <SpellLink id={this.selectedCombatant.hasTalent(SPELLS.CRUSADE_TALENT.id) ? SPELLS.CRUSADE_TALENT.id : SPELLS.AVENGING_WRATH.id} icon /> and <SpellLink id={SPELLS.WAKE_OF_ASHES_TALENT.id} /> on cooldown.</React.Fragment>,
      requirements: () => {
        const combatant = this.selectedCombatant;
        return [
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.CRUSADE_TALENT,
            when: combatant.hasTalent(SPELLS.CRUSADE_TALENT.id),
          }),
          new Requirement({
            name: <React.Fragment>Good first global with <SpellLink id={SPELLS.CRUSADE_TALENT.id} icon /> buff</React.Fragment>,
            check: () => this.crusade.suggestionThresholds,
            when: this.crusade.active,
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.AVENGING_WRATH,
            when: !combatant.hasTalent(SPELLS.CRUSADE_TALENT.id),
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.WAKE_OF_ASHES_TALENT,
            when: combatant.hasTalent(SPELLS.WAKE_OF_ASHES_TALENT.id),
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.EXECUTION_SENTENCE_TALENT,
            when: combatant.hasTalent(SPELLS.EXECUTION_SENTENCE_TALENT.id),
          }),
        ];
      },
    }),
    new Rule({
      name: 'Use procs and buffs efficiently',
      description: <React.Fragment>Buffs and procs like <SpellLink id={SPELLS.INQUISITION_TALENT.id} icon />, <SpellLink id={SPELLS.ART_OF_WAR.id} icon /> and <SpellLink id={SPELLS.RIGHTEOUS_VERDICT_TALENT.id} icon /> have a significant impact on your damage, use them well</React.Fragment>,
      requirements: () => {
        const combatant = this.selectedCombatant;
        return [
          new Requirement({
            name: <React.Fragment><SpellLink id={SPELLS.ART_OF_WAR.id} icon /> procs used</React.Fragment>,
            check: () => this.artOfWar.suggestionThresholds,
          }),
          new Requirement({
            name: <React.Fragment><SpellLink id={SPELLS.JUDGMENT_CAST.id} icon /> debuffs consumed</React.Fragment>,
            check: () => this.judgment.suggestionThresholds,
          }),
          new Requirement({
            name: <React.Fragment>Damage empowered by <SpellLink id={SPELLS.INQUISITION_TALENT.id} icon /></React.Fragment>,
            check: () => this.inquisition.suggestionThresholds,
            when: combatant.hasTalent(SPELLS.INQUISITION_TALENT.id),
          }),
        ];
      },
    }),
  	new Rule({
  		name: 'Use your Holy Power efficently',
  		description: "Holy Power is your main resource, it's very important not to not waste it.",
  		requirements: () => {
  			return [
  				new Requirement({
  					name: 'Holy Power efficiency',
  					check: () => this.holyPowerDetails.suggestionThresholds,
  				}),
  			];
  		},
  	}),
    new Rule({
      name: 'Pick the right tools for the fight',
      description: 'The throughput gain of some legendaries might vary greatly. Consider switching to a more reliable alternative if something is underperforming regularly.',
      requirements: () => {
        return [
          new Requirement({
            name: <React.Fragment><ItemLink id={ITEMS.LIADRINS_FURY_UNLEASHED.id} icon /> Holy Power efficiency</React.Fragment>,
            check: () => this.liadrins.suggestionThresholds,
            when: this.liadrins.active,
          }),
          new Requirement({
            name: <React.Fragment>Spenders buffed by <ItemLink id={ITEMS.WHISPER_OF_THE_NATHREZIM.id} icon /></React.Fragment>,
            check: () => this.whisper.suggestionThresholds,
            when: this.whisper.active,
          }),
          new Requirement({
            name: <React.Fragment>Picked the right talent with <ItemLink id={ITEMS.SOUL_OF_THE_HIGHLORD.id} icon /></React.Fragment>,
            check: () => this.soulOfTheHighlord.suggestionThresholds,
            when: this.soulOfTheHighlord.active,
          }),
        ];
      },
    }),
  	new Rule({
      name: 'Use your utility and defensive spells',
      description: <React.Fragment>Use other spells in your toolkit to your advantage. For example, you can use <SpellLink id={SPELLS.SHIELD_OF_VENGEANCE.id} icon /> to mitigate some damage and <SpellLink id={SPELLS.LAY_ON_HANDS.id} icon /> to save your own or someone elses life.</React.Fragment>,
      requirements: () => {
        return [
	        new GenericCastEfficiencyRequirement({
	          spell: SPELLS.SHIELD_OF_VENGEANCE,
            onlyWithSuggestion: false,
	        }),
	        new GenericCastEfficiencyRequirement({
            spell: SPELLS.LAY_ON_HANDS,
            onlyWithSuggestion: false,
					}),
        ];
      },
    }),
    new PreparationRule(),
	];
}

export default Checklist;
<commit_msg>[Bfa][Ret] Quick update in ret checklist<commit_after>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellLink from 'common/SpellLink';
import ITEMS from 'common/ITEMS';
import ItemLink from 'common/ItemLink';

import CoreChecklist, { Rule, Requirement } from 'Parser/Core/Modules/Features/Checklist';
import Abilities from 'Parser/Core/Modules/Abilities';
import { PreparationRule } from 'Parser/Core/Modules/Features/Checklist/Rules';
import { GenericCastEfficiencyRequirement } from 'Parser/Core/Modules/Features/Checklist/Requirements';
import CastEfficiency from 'Parser/Core/Modules/CastEfficiency';
import LegendaryUpgradeChecker from 'Parser/Core/Modules/Items/LegendaryUpgradeChecker';
import LegendaryCountChecker from 'Parser/Core/Modules/Items/LegendaryCountChecker';
import PrePotion from 'Parser/Core/Modules/Items/PrePotion';
import EnchantChecker from 'Parser/Core/Modules/Items/EnchantChecker';
import AbilityTracker from 'Parser/Core/Modules/AbilityTracker';

import AlwaysBeCasting from './AlwaysBeCasting';
import HolyPowerDetails from '../HolyPower/HolyPowerDetails';
import ArtOfWar from '../PaladinCore/ArtOfWar';
import Judgment from '../PaladinCore/Judgment';
import Liadrins from '../Items/LiadrinsFuryUnleashed';
import Whisper from '../Items/WhisperOfTheNathrezim';
import SoulOfTheHighlord from '../Items/SoulOfTheHighlord';
import Crusade from '../Talents/Crusade';
import Inquisition from '../Talents/Inquisition';
import RighteousVerdict from '../Talents/RighteousVerdict';

class Checklist extends CoreChecklist {
	static dependencies = {
    abilities: Abilities,
		castEfficiency: CastEfficiency,
    alwaysBeCasting: AlwaysBeCasting,
    legendaryUpgradeChecker: LegendaryUpgradeChecker,
    legendaryCountChecker: LegendaryCountChecker,
    prePotion: PrePotion,
    enchantChecker: EnchantChecker,
    abilityTracker: AbilityTracker,

    holyPowerDetails: HolyPowerDetails,
    artOfWar: ArtOfWar,
    judgment: Judgment,
    liadrins: Liadrins,
    soulOfTheHighlord: SoulOfTheHighlord,
    whisper: Whisper,
    crusade: Crusade,
    inquisition: Inquisition,
    righteousVerdict: RighteousVerdict,
	};

  rules = [
    new Rule({
      name: 'Always be casting',
      description: <React.Fragment>You should try to avoid doing nothing during the fight. If you have to move, use your <SpellLink id={SPELLS.DIVINE_STEED.id} icon /> to minimize downtime. Also use ranged abilities like <SpellLink id={SPELLS.JUDGMENT_CAST.id} icon /> or <SpellLink id={SPELLS.BLADE_OF_JUSTICE.id} icon /> if out of melee range for extended periods.</React.Fragment>,
      requirements: () => {
        return [
          new Requirement({
            name: 'Downtime',
            check: () => this.alwaysBeCasting.suggestionThresholds,
          }),
        ];
      },
    }),
    new Rule({
      name: 'Use core abilities as often as possible',
      description: <React.Fragment>Spells with short cooldowns like <SpellLink id={SPELLS.JUDGMENT_CAST.id} icon />, <SpellLink id={SPELLS.BLADE_OF_JUSTICE.id} icon />, and <SpellLink id={SPELLS.CRUSADER_STRIKE.id} icon /> should be used as often as possible.</React.Fragment>,
      requirements: () => {
        const combatant = this.selectedCombatant;
        return [
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.CRUSADER_STRIKE,
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.JUDGMENT_CAST,
            onlyWithSuggestion: false,
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.BLADE_OF_JUSTICE,
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.CONSECRATION_TALENT,
            when: combatant.hasTalent(SPELLS.CONSECRATION_TALENT.id),
          }),
        ];
      },
    }),
    new Rule({
      name: 'Use your cooldowns',
      description: <React.Fragment>Retribution Paladin is a very cooldown dependant spec. Make sure you are keeping spells like <SpellLink id={this.selectedCombatant.hasTalent(SPELLS.CRUSADE_TALENT.id) ? SPELLS.CRUSADE_TALENT.id : SPELLS.AVENGING_WRATH.id} icon /> and <SpellLink id={SPELLS.WAKE_OF_ASHES_TALENT.id} /> on cooldown.</React.Fragment>,
      requirements: () => {
        const combatant = this.selectedCombatant;
        return [
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.CRUSADE_TALENT,
            when: combatant.hasTalent(SPELLS.CRUSADE_TALENT.id),
          }),
          new Requirement({
            name: <React.Fragment>Good first global with <SpellLink id={SPELLS.CRUSADE_TALENT.id} icon /> buff</React.Fragment>,
            check: () => this.crusade.suggestionThresholds,
            when: this.crusade.active,
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.AVENGING_WRATH,
            when: !combatant.hasTalent(SPELLS.CRUSADE_TALENT.id),
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.WAKE_OF_ASHES_TALENT,
            when: combatant.hasTalent(SPELLS.WAKE_OF_ASHES_TALENT.id),
          }),
          new GenericCastEfficiencyRequirement({
            spell: SPELLS.EXECUTION_SENTENCE_TALENT,
            when: combatant.hasTalent(SPELLS.EXECUTION_SENTENCE_TALENT.id),
          }),
        ];
      },
    }),
    new Rule({
      name: 'Use procs and buffs efficiently',
      description: <React.Fragment>Buffs and procs like <SpellLink id={SPELLS.INQUISITION_TALENT.id} icon />, <SpellLink id={SPELLS.ART_OF_WAR.id} icon /> and <SpellLink id={SPELLS.RIGHTEOUS_VERDICT_TALENT.id} icon /> have a significant impact on your damage, use them well</React.Fragment>,
      requirements: () => {
        const combatant = this.selectedCombatant;
        return [
          new Requirement({
            name: <React.Fragment><SpellLink id={SPELLS.ART_OF_WAR.id} icon /> procs used</React.Fragment>,
            check: () => this.artOfWar.suggestionThresholds,
          }),
          new Requirement({
            name: <React.Fragment><SpellLink id={SPELLS.JUDGMENT_CAST.id} icon /> debuffs consumed</React.Fragment>,
            check: () => this.judgment.suggestionThresholds,
          }),
          new Requirement({
            name: <React.Fragment>Damage empowered by <SpellLink id={SPELLS.INQUISITION_TALENT.id} icon /></React.Fragment>,
            check: () => this.inquisition.suggestionThresholds,
            when: combatant.hasTalent(SPELLS.INQUISITION_TALENT.id),
          }),
          new Requirement({
            name: <React.Fragment></React.Fragment>,
            check: () => this.righteousVerdict.suggestionThresholds,
            when: combatant.hasTalent(SPELLS.RIGHTEOUS_VERDICT_TALENT.id),
          }),
        ];
      },
    }),
  	new Rule({
  		name: 'Use your Holy Power efficently',
  		description: "Holy Power is your main resource, it's very important not to waste it.",
  		requirements: () => {
  			return [
  				new Requirement({
  					name: 'Holy Power efficiency',
  					check: () => this.holyPowerDetails.suggestionThresholds,
  				}),
  			];
  		},
  	}),
    new Rule({
      name: 'Pick the right tools for the fight',
      description: 'The throughput gain of some legendaries might vary greatly. Consider switching to a more reliable alternative if something is underperforming regularly.',
      requirements: () => {
        return [
          new Requirement({
            name: <React.Fragment><ItemLink id={ITEMS.LIADRINS_FURY_UNLEASHED.id} icon /> Holy Power efficiency</React.Fragment>,
            check: () => this.liadrins.suggestionThresholds,
            when: this.liadrins.active,
          }),
          new Requirement({
            name: <React.Fragment>Spenders buffed by <ItemLink id={ITEMS.WHISPER_OF_THE_NATHREZIM.id} icon /></React.Fragment>,
            check: () => this.whisper.suggestionThresholds,
            when: this.whisper.active,
          }),
          new Requirement({
            name: <React.Fragment>Picked the right talent with <ItemLink id={ITEMS.SOUL_OF_THE_HIGHLORD.id} icon /></React.Fragment>,
            check: () => this.soulOfTheHighlord.suggestionThresholds,
            when: this.soulOfTheHighlord.active,
          }),
        ];
      },
    }),
  	new Rule({
      name: 'Use your utility and defensive spells',
      description: <React.Fragment>Use other spells in your toolkit to your advantage. For example, you can use <SpellLink id={SPELLS.SHIELD_OF_VENGEANCE.id} icon /> to mitigate some damage and <SpellLink id={SPELLS.LAY_ON_HANDS.id} icon /> to save your own or someone elses life.</React.Fragment>,
      requirements: () => {
        return [
	        new GenericCastEfficiencyRequirement({
	          spell: SPELLS.SHIELD_OF_VENGEANCE,
            onlyWithSuggestion: false,
	        }),
	        new GenericCastEfficiencyRequirement({
            spell: SPELLS.LAY_ON_HANDS,
            onlyWithSuggestion: false,
					}),
        ];
      },
    }),
    new PreparationRule(),
	];
}

export default Checklist;
<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
  Tiamat is a multi headed forking server.
*/
require.paths.unshift(__dirname + "/../lib");

var Tiamat = require("tiamat/server.js").Tiamat;
var Daemon = require("tiamat/daemon.js");
var Config = require("tiamat/config.js").ConfigLoader;
var opt    = require('getopt');
var path   = require('path');
var fs     = require('fs');

function cli() {
  opt.setopt("vhdc:s:p::");
  var options = {};

  opt.getopt(function (o, p) {
    switch (o) {
      case "h":
        opt.showHelp("tiamat", function (o) {
          switch (o) {
            case "h": return "Show this help menu";
            case "c": return "Server configuration path";
            case "d": return "Daemonize the server";
            default:  return "Option '"+o+"'";
          }
        });
        process.exit(0);
        break;
      case "v":
        var package = JSON.parse(fs.readFileSync(__dirname + "/../package.json"));
        console.log("version: %s", package.version);
        process.exit(0);
        break;
      case "c":
        options['config'] = p[0];
        break;
      case "d":
        options['daemonize'] = true;
        break;
      case "s":
        if (!p[0].match(/^\//)) {
          options['worker_app'] = path.join(process.cwd(),  p[0]);
        }
        else {
          options['worker_app'] = p[0];
        }
        break;
      case "p":
        options['listen_port'] = p[0];
        break;
      default:
        break;
    }
  });
  return options;
}

function verifyConfig(config) {
  if (!config['worker_app']) {
    console.error("Must provide a worker_app in either a referenced configuration file or as -s 'your_app.js'");
    process.exit(1);
  }
}

function applyDefaults(config) {
  if (!config['tcp']) { config['tcp'] = 'tcp4'; }
  if (!config['backlog']) { config['backlog'] = 128; }
  if (!config['listen_sock'] && !config['listen_port']) { config['listen_port'] = 1337; }
  if (!config['listen_sock'] && !config['listen_addr']) { config['listen_addr'] = "127.0.0.1"; }
  if (!config['workers']) { config['workers'] = 1; }
  if (!config['working_directory']) { config['working_directory'] = process.cwd(); }
  if (!config['stderr_path']) { config['stderr_path'] = "/dev/null"; }
  if (!config['stdout_path']) { config['stdout_path'] = "/dev/null"; }
  if (!config['pidfile']) { config['pidfile'] = "/tmp/tiamat-" + process.pid + ".pid"; }
  return config;
}

function runApp(config) {
  if (process.env['__NIX_FD'] || !config.daemonize) { // reexec from old master or just don't daemonize
    Tiamat(config);
  }
  else {
    console.log("running app as a daemon");
    Daemon.daemonize(function() {
      Tiamat(config);
    }, config.working_directory, config.stdout_path, config.stderr_path);
  }
}

var options = cli();

if (options['config']) {
  var config = new Config();
  config.on("loaded", function(config) {
    config = applyDefaults(config);
    verifyConfig(config);
    runApp(config);
  });
  config.load(options['config']);
}
else {
  options = applyDefaults(options);
  verifyConfig(options);
  runApp(options);
}
<commit_msg>handle command line errors<commit_after>#!/usr/bin/env node
/*
  Tiamat is a multi headed forking server.
*/
require.paths.unshift(__dirname + "/../lib");

var Tiamat = require("tiamat/server.js").Tiamat;
var Daemon = require("tiamat/daemon.js");
var Config = require("tiamat/config.js").ConfigLoader;
var opt    = require('getopt');
var path   = require('path');
var fs     = require('fs');

function cli() {
  var options = {};
  var help = function() {
    opt.showHelp("tiamat", function (o) {
      switch (o) {
        case "h": return "Show this help menu";
        case "v": return "Show version string";
        case "c": return "Server configuration path";
        case "d": return "Daemonize the server";
        case "s": return "Worker JS file to load exports.run = function(config, cb)...";
        case "p": return "Change the default port to bind";
        default:  return "Option '"+o+"'";
      }
    });
  }

  try {

    opt.setopt("vhdc:s:p::");

    opt.getopt(function (o, p) {
      switch (o) {
        case "h":
          help();
          process.exit(0);
          break;
        case "v":
          var package = JSON.parse(fs.readFileSync(__dirname + "/../package.json"));
          console.log("version: %s", package.version);
          process.exit(0);
          break;
        case "c":
          options['config'] = p[0];
          break;
        case "d":
          options['daemonize'] = true;
          break;
        case "s":
          if (!p[0].match(/^\//)) {
            options['worker_app'] = path.join(process.cwd(),  p[0]);
          }
          else {
            options['worker_app'] = p[0];
          }
          break;
        case "p":
          options['listen_port'] = p[0];
          break;
        default:
          console.error("unknown option: " + o);
          help();
          process.exit(1);
          break;
      }
    });
    return options;
  } catch(e) {
    console.error(e);
    help();
    process.exit(1);
  }
}

function verifyConfig(config) {
  if (!config['worker_app']) {
    console.error("Must provide a worker_app in either a referenced configuration file or as -s 'your_app.js'");
    process.exit(1);
  }
}

function applyDefaults(config) {
  if (!config['tcp']) { config['tcp'] = 'tcp4'; }
  if (!config['backlog']) { config['backlog'] = 128; }
  if (!config['listen_sock'] && !config['listen_port']) { config['listen_port'] = 1337; }
  if (!config['listen_sock'] && !config['listen_addr']) { config['listen_addr'] = "127.0.0.1"; }
  if (!config['workers']) { config['workers'] = 1; }
  if (!config['working_directory']) { config['working_directory'] = process.cwd(); }
  if (!config['stderr_path']) { config['stderr_path'] = "/dev/null"; }
  if (!config['stdout_path']) { config['stdout_path'] = "/dev/null"; }
  if (!config['pidfile']) { config['pidfile'] = "/tmp/tiamat-" + process.pid + ".pid"; }
  return config;
}

function runApp(config) {
  if (process.env['__NIX_FD'] || !config.daemonize) { // reexec from old master or just don't daemonize
    Tiamat(config);
  }
  else {
    console.log("running app as a daemon");
    Daemon.daemonize(function() {
      Tiamat(config);
    }, config.working_directory, config.stdout_path, config.stderr_path);
  }
}

var options = cli();

if (options['config']) {
  var config = new Config();
  config.on("loaded", function(config) {
    config = applyDefaults(config);
    verifyConfig(config);
    runApp(config);
  });
  config.load(options['config']);
}
else {
  options = applyDefaults(options);
  verifyConfig(options);
  runApp(options);
}
<|endoftext|>


<commit_before>ResLang = {
	'2107' : ['设备回收', '设备回收'],
	'1955' : ['任务配置', '任务配置'],
	'2232' : ['操作记录', '操作记录'],
	'912' : ['增加资费'],
	'911' : ['修改产品'],
	'913' : ['修改资费'],
	'4116' : ['增加费用模板配置', '编辑模板'],
	'70' : ['缴费', '缴费'],
	'65' : ['报开', '报开'],
	'66' : ['套餐订购', '套餐订购'],
	'67' : ['退订', '退订'],
	'29' : ['待处理工单', '待处理工单'],
	'3' : ['修改加入订单日期'],
	'73' : ['调账', '调账'],
	'64' : ['报停', '报停'],
	'1561' : ['在线用户', '在线用户'],
	'4101' : ['项目查询'],
	'3012' : ['账户产品配置', '账户产品配置'],
	'1240' : ['财务配置'],
	'1279' : ['促销配置'],
	'4106' : ['项目失效按钮'],
	'4103' : ['修改项目按钮'],
	'4102' : ['添加项目按钮'],
	'4105' : ['项目生效按钮'],
	'4104' : ['项目小区关联按钮'],
	'14352' : ['变更记录', '变更记录'],
	'1283' : ['套餐缴费', '套餐缴费'],
	'85' : ['修改流水备注', '修改流水备注'],
	'2007' : ['设备盘点', '设备盘点'],
	'154' : ['客户等级修改', '客户等级修改'],
	'2' : ['系统管理', '系统管理'],
	'9' : ['参数配置', '参数配置'],
	'23' : ['费用项配置', '费用项配置'],
	'15' : ['基本配置', '基本配置'],
	'1054' : ['资源管理', '资源管理'],
	'4' : ['角色管理', '角色管理'],
	'8' : ['机构管理', '机构管理'],
	'0' : ['系统根目录', '系统根目录'],
	'1' : ['操作员管理', '操作员管理'],
	'12' : ['业务配置', '业务配置'],
	'13' : ['系统参数配置', '系统参数'],
	'16' : ['模板', '模板'],
	'50' : ['开户', '客户开户'],
	'54' : ['修改', '修改客户'],
	'100' : ['营业子系统', '营业系统菜单'],
	'26060' : ['取消领用'],
	'26541' : ['重打受理单', '重打受理单'],
	'26540' : ['作废发票', '作废发票'],
	'3017' : ['机卡解绑', '机卡解绑'],
	'1160' : ['产品管理', '产品配置'],
	'83' : ['费用修改', '费用修改'],
	'91' : ['修改', '修改发票'],
	'88' : ['打印', '发票打印'],
	'2000' : ['仓库配置', '仓库配置'],
	'1181' : ['不打印标记', '不打印标记'],
	'1182' : ['打开打印标记', '打开打印标记'],
	'26080' : ['手工发票号修改', '手工发票号修改'],
	'112' : ['批量开户', '批量用户开户'],
	'111' : ['批量购买配件', '批量购买配件'],
	'1500' : ['设备查询', '设备查询'],
	'1503' : ['非营业费收取', '非营业费收取'],
	'90' : ['购买配件', '购买配件'],
	'2005' : ['设备查询', '设备查询'],
	'1100' : ['移机', '移机'],
	'1179' : ['产品配置', '产品配置'],
	'60' : ['开户', '用户开户'],
	'61' : ['销户', '用户销户'],
	'51' : ['销户', '客户销户'],
	'58' : ['更换', '更换设备'],
	'3227' : ['发票领用'],
	'24' : ['作废', '作废按钮'],
	'25' : ['提交呼叫', '提交呼叫'],
	'26' : ['回单', '回单按钮'],
	'27' : ['已完成工单', '已完成工单'],
	'1031' : ['修改停机数', '修改停机数'],
	'3206' : ['工单打印', '工单打印'],
	'101' : ['设备挂失', '设备挂失'],
	'2006' : ['详细', '详细查询'],
	'1501' : ['发票查询', '发票查询'],
	'3112' : ['修改状态'],
	'3111' : ['发票结帐'],
	'3113' : ['取消结帐'],
	'3114' : ['取消核销'],
	'3115' : ['发票查询'],
	'3010' : ['发票入库'],
	'3007' : ['发票调拨'],
	'3009' : ['发票核销'],
	'2004' : ['设备调拨', '设备调拨'],
	'3015' : ['灌装', '灌装'],
	'3008' : ['订单管理', '订单管理'],
	'3002' : ['配置', '基本配置'],
	'3005' : ['退库', '设备退库'],
	'3003' : ['设备入库', '设备入库'],
	'3001' : ['差异管理', '差异管理'],
	'3011' : ['设备领用', '设备领用'],
	'3006' : ['设备状态管理', '状态管理'],
	'3116' : ['详细查询'],
	'1155' : ['地区管理', '地区管理'],
	'27040' : ['重置密码', '重置密码'],
	'27041' : ['用户名批量修改', '用户名批量修改'],
	'27042' : ['汇率配置', '汇率配置'],
	'26980' : ['工单管理', '工单管理'],
	'27000' : ['新增工单', '新增工单'],
	'189' : ['高级退订', '高级退订'],
	'113' : ['账户充值', '账户充值'],
	'114' : ['账户退款', '账户退款'],
	'190' : ['超级退订', '超级退订'],
	'28' : ['处理中工单', '处理中工单'],
	'10001' : ['单产品订购', '产品订购'],
	'10002' : ['产品续订', '续订'],
	'10003' : ['产品升级', '升级'],
	'3004' : ['规则配置', '规则配置'],
	'1557' : ['公告配置', '公告配置'],
	'1556' : ['资源组配置', '资源组配置'],
	'1003' : ['取消预报停', '取消预报停'],
	'156' : ['高级修改', '高级修改'],
	'2819' : ['资源管理', '资源管理'],
	'69' : ['指令重发', '指令重发'],
	'1600' : ['单卡指令', '单卡指令'],
	'3110' : ['发票退库']

}<commit_msg>菜单res_id 跟lxr统一<commit_after>ResLang = {
	'2107' : ['设备回收', '设备回收'],
	'1955' : ['任务配置', '任务配置'],
	'2232' : ['操作记录', '操作记录'],
	'912' : ['增加资费'],
	'911' : ['修改产品'],
	'913' : ['修改资费'],
	'4116' : ['增加费用模板配置', '编辑模板'],
	'70' : ['缴费', '缴费'],
	'65' : ['报开', '报开'],
	'66' : ['套餐订购', '套餐订购'],
	'67' : ['退订', '退订'],
	'29' : ['待处理工单', '待处理工单'],
	'3' : ['修改加入订单日期'],
	'73' : ['调账', '调账'],
	'64' : ['报停', '报停'],
	'1561' : ['在线用户', '在线用户'],
	'4101' : ['项目查询'],
	'3012' : ['账户产品配置', '账户产品配置'],
	'1240' : ['财务配置'],
	'1279' : ['促销配置'],
	'4106' : ['项目失效按钮'],
	'4103' : ['修改项目按钮'],
	'4102' : ['添加项目按钮'],
	'4105' : ['项目生效按钮'],
	'4104' : ['项目小区关联按钮'],
	'26541' : ['重打受理单', '重打受理单'],
	'26540' : ['作废发票', '作废发票'],
	'3017' : ['机卡解绑', '机卡解绑'],
	'1160' : ['产品管理', '产品配置'],
	'83' : ['费用修改', '费用修改'],
	'91' : ['修改', '修改发票'],
	'88' : ['打印', '发票打印'],
	'2000' : ['仓库配置', '仓库配置'],
	'1181' : ['不打印标记', '不打印标记'],
	'1182' : ['打开打印标记', '打开打印标记'],
	'26080' : ['手工发票号修改', '手工发票号修改'],
	'112' : ['批量开户', '批量用户开户'],
	'111' : ['批量购买配件', '批量购买配件'],
	'1500' : ['设备查询', '设备查询'],
	'1503' : ['非营业费收取', '非营业费收取'],
	'90' : ['购买配件', '购买配件'],
	'2005' : ['设备查询', '设备查询'],
	'1100' : ['移机', '移机'],
	'1179' : ['产品配置', '产品配置'],
	'60' : ['开户', '用户开户'],
	'61' : ['销户', '用户销户'],
	'51' : ['销户', '客户销户'],
	'58' : ['更换', '更换设备'],
	'3227' : ['发票领用'],
	'24' : ['作废', '作废按钮'],
	'25' : ['提交呼叫', '提交呼叫'],
	'26' : ['回单', '回单按钮'],
	'27' : ['已完成工单', '已完成工单'],
	'14352' : ['变更记录', '变更记录'],
	'1283' : ['套餐缴费', '套餐缴费'],
	'85' : ['修改流水备注', '修改流水备注'],
	'2007' : ['设备盘点', '设备盘点'],
	'154' : ['客户等级修改', '客户等级修改'],
	'2' : ['系统管理', '系统管理'],
	'9' : ['参数配置', '参数配置'],
	'23' : ['费用项配置', '费用项配置'],
	'15' : ['基本配置', '基本配置'],
	'1054' : ['资源管理', '资源管理'],
	'4' : ['角色管理', '角色管理'],
	'8' : ['机构管理', '机构管理'],
	'0' : ['系统根目录', '系统根目录'],
	'1' : ['操作员管理', '操作员管理'],
	'12' : ['业务配置', '业务配置'],
	'13' : ['系统参数配置', '系统参数'],
	'16' : ['模板', '模板'],
	'50' : ['客户开户', '客户开户'],
	'54' : ['修改', '修改客户'],
	'100' : ['营业子系统', '营业系统菜单'],
	'26060' : ['取消领用'],
	'1031' : ['修改停机数', '修改停机数'],
	'3206' : ['工单打印', '工单打印'],
	'101' : ['设备挂失', '设备挂失'],
	'2006' : ['详细', '详细查询'],
	'1501' : ['发票查询', '发票查询'],
	'3112' : ['修改状态'],
	'3111' : ['发票结帐'],
	'3113' : ['取消结帐'],
	'3114' : ['取消核销'],
	'3115' : ['发票查询'],
	'3010' : ['发票入库'],
	'3007' : ['发票调拨'],
	'3009' : ['发票核销'],
	'2004' : ['设备调拨', '设备调拨'],
	'3015' : ['灌装', '灌装'],
	'3008' : ['订单管理', '订单管理'],
	'3002' : ['配置', '基本配置'],
	'3005' : ['退库', '设备退库'],
	'3003' : ['设备入库', '设备入库'],
	'3001' : ['差异管理', '差异管理'],
	'3011' : ['设备领用', '设备领用'],
	'3006' : ['设备状态管理', '状态管理'],
	'3116' : ['详细查询'],
	'1155' : ['地区管理', '地区管理'],
	'28' : ['处理中工单', '处理中工单'],
	'10001' : ['单产品订购', '产品订购'],
	'10002' : ['产品续订', '续订'],
	'10003' : ['产品升级', '升级'],
	'3004' : ['规则配置', '规则配置'],
	'1557' : ['公告配置', '公告配置'],
	'1556' : ['资源组配置', '资源组配置'],
	'1003' : ['取消预报停', '取消预报停'],
	'156' : ['高级修改', '高级修改'],
	'2819' : ['资源管理', '资源管理'],
	'69' : ['指令重发', '指令重发'],
	'1600' : ['单卡指令', '单卡指令'],
	'3110' : ['发票退库'],
	'26980' : ['工单管理', '工单管理'],
	'27000' : ['新增工单', '新增工单'],
	'189' : ['高级退订', '高级退订'],
	'113' : ['账户充值', '账户充值'],
	'114' : ['账户退款', '账户退款'],
	'190' : ['超级退订', '超级退订'],
	'27020' : ['重置密码', '重置密码'],
	'27021' : ['用户名批量修改', '用户名批量修改'],
	'27022' : ['汇率配置', '汇率配置'],
	'79' : ['刷新指令', '刷新指令']

}<|endoftext|>


<commit_before>'use strict';

var d       = require('d')
  , assign  = require('es5-ext/object/assign-multiple')
  , map     = require('es5-ext/object/map')
  , reduce  = require('es5-ext/object/reduce')
  , repeat  = require('es5-ext/string/#/repeat')
  , memoize = require('memoizee')
  , tty     = require('tty')

  , join = Array.prototype.join, defineProperty = Object.defineProperty
  , defineProperties = Object.defineProperties, abs = Math.abs
  , floor = Math.floor, max = Math.max, min = Math.min

  , mods, proto, getFn, getMove, xtermMatch
  , up, down, right, left, getHeight, memoized;

mods = assign({
	// Style
	bold:      { _bold: [1, 22] },
	italic:    { _italic: [3, 23] },
	underline: { _underline: [4, 24] },
	blink:     { _blink: [5, 25] },
	inverse:   { _inverse: [7, 27] },
	strike:    { _strike: [9, 29] }
},

	// Color
	['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white']
		.reduce(function (obj, color, index) {
		// foreground
		obj[color] = { _fg: [30 + index, 39] };
		obj[color + 'Bright'] = { _fg: [90 + index, 39] };

		// background
		obj['bg' + color[0].toUpperCase() + color.slice(1)] =
			{ _bg: [40 + index, 49] };
		obj['bg' + color[0].toUpperCase() + color.slice(1) + 'Bright'] =
			{ _bg: [100 + index, 49] };

		return obj;
	}, {}));

// Some use cli-color as: console.log(clc.red('Error!'));
// Which is inefficient as on each call it configures new clc object
// with memoization we reuse once created object
memoized = memoize(function (scope, mod) {
	return defineProperty(getFn(), '_cliColorData',
		d(assign({}, scope._cliColorData, mod)));
});

proto = Object.create(Function.prototype, assign(map(mods, function (mod) {
	return d.gs(function () { return memoized(this, mod); });
}),
	// xterm (255) color
	memoize(function (code) {
		code = isNaN(code) ? 255 : min(max(code, 0), 255);
		return defineProperty(getFn(), '_cliColorData',
			d(assign({}, this._cliColorData, {
				_fg: [xtermMatch ? xtermMatch[code] : ('38;5;' + code), 39]
			})));
	}, { method: 'xterm' }),
	memoize(function (code) {
		code = isNaN(code) ? 255 : min(max(code, 0), 255);
		return defineProperty(getFn(), '_cliColorData',
			d(assign({}, this._cliColorData, {
				_bg: [xtermMatch ? (xtermMatch[code] + 10) : ('48;5;' + code), 49]
			})));
	}, { method: 'bgXterm' })));

if (process.platform === 'win32') {
	xtermMatch = require('./_xterm-match');
}

getFn = function () {
	var fn = function (/*…msg*/) {
		var data = fn._cliColorData, close = '';
		return reduce(data, function (str, mod) {
			close = '\x1b[' + mod[1] + 'm' + close;
			return str + '\x1b[' + mod[0] + 'm';
		}, '', true) + join.call(arguments, ' ') + close;
	};
	fn.__proto__ = proto;
	return fn;
};

getMove = function (control) {
	return function (num) {
		num = isNaN(num) ? 0 : max(floor(num), 0);
		return num ? ('\x1b[' + num + control) : '';
	};
};

module.exports = defineProperties(getFn(), {
	width: d.gs(process.stdout.getWindowSize ? function () {
		return process.stdout.getWindowSize()[0];
	} : function () {
		return tty.getWindowSize ? tty.getWindowSize()[1] : 0;
	}),
	height: d.gs(getHeight = process.stdout.getWindowSize ? function () {
		return process.stdout.getWindowSize()[1];
	} : function () {
		return tty.getWindowSize ? tty.getWindowSize()[0] : 0;
	}),
	reset: d.gs(function () {
		return repeat.call('\n', getHeight() - 1) + '\x1bc';
	}),
	up: d(up = getMove('A')),
	down: d(down = getMove('B')),
	right: d(right = getMove('C')),
	left: d(left = getMove('D')),
	move: d(function (x, y) {
		x = isNaN(x) ? 0 : floor(x);
		y = isNaN(y) ? 0 : floor(y);
		return ((x > 0) ? right(x) : left(-x)) + ((y > 0) ? down(y) : up(-y));
	}),
	moveTo: d(function (x, y) {
		x = isNaN(x) ? 1 : (max(floor(x), 0) + 1);
		y = isNaN(y) ? 1 : (max(floor(y), 0) + 1);
		return '\x1b[' + y + ';' + x + 'H';
	}),
	bol: d(function (n/*, erase*/) {
		var dir;
		n = isNaN(n) ? 0 : Number(n);
		dir = (n >= 0) ? 'E' : 'F';
		n = floor(abs(n));
		return arguments[1] ?
				(((!n || (dir === 'F')) ? '\x1b[0E\x1bK' : '') +
					repeat.call('\x1b[1' + dir + '\x1b[K', n)) : '\x1b[' + n + dir;
	}),
	beep: d('\x07'),
	xtermSupported: d(!xtermMatch),
	_cliColorData: d({})
});
<commit_msg>Clear obsolete variable<commit_after>'use strict';

var d       = require('d')
  , assign  = require('es5-ext/object/assign-multiple')
  , map     = require('es5-ext/object/map')
  , reduce  = require('es5-ext/object/reduce')
  , repeat  = require('es5-ext/string/#/repeat')
  , memoize = require('memoizee')
  , tty     = require('tty')

  , join = Array.prototype.join, defineProperty = Object.defineProperty
  , defineProperties = Object.defineProperties, abs = Math.abs
  , floor = Math.floor, max = Math.max, min = Math.min

  , mods, proto, getFn, getMove, xtermMatch
  , up, down, right, left, getHeight, memoized;

mods = assign({
	// Style
	bold:      { _bold: [1, 22] },
	italic:    { _italic: [3, 23] },
	underline: { _underline: [4, 24] },
	blink:     { _blink: [5, 25] },
	inverse:   { _inverse: [7, 27] },
	strike:    { _strike: [9, 29] }
},

	// Color
	['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white']
		.reduce(function (obj, color, index) {
		// foreground
		obj[color] = { _fg: [30 + index, 39] };
		obj[color + 'Bright'] = { _fg: [90 + index, 39] };

		// background
		obj['bg' + color[0].toUpperCase() + color.slice(1)] =
			{ _bg: [40 + index, 49] };
		obj['bg' + color[0].toUpperCase() + color.slice(1) + 'Bright'] =
			{ _bg: [100 + index, 49] };

		return obj;
	}, {}));

// Some use cli-color as: console.log(clc.red('Error!'));
// Which is inefficient as on each call it configures new clc object
// with memoization we reuse once created object
memoized = memoize(function (scope, mod) {
	return defineProperty(getFn(), '_cliColorData',
		d(assign({}, scope._cliColorData, mod)));
});

proto = Object.create(Function.prototype, assign(map(mods, function (mod) {
	return d.gs(function () { return memoized(this, mod); });
}),
	// xterm (255) color
	memoize(function (code) {
		code = isNaN(code) ? 255 : min(max(code, 0), 255);
		return defineProperty(getFn(), '_cliColorData',
			d(assign({}, this._cliColorData, {
				_fg: [xtermMatch ? xtermMatch[code] : ('38;5;' + code), 39]
			})));
	}, { method: 'xterm' }),
	memoize(function (code) {
		code = isNaN(code) ? 255 : min(max(code, 0), 255);
		return defineProperty(getFn(), '_cliColorData',
			d(assign({}, this._cliColorData, {
				_bg: [xtermMatch ? (xtermMatch[code] + 10) : ('48;5;' + code), 49]
			})));
	}, { method: 'bgXterm' })));

if (process.platform === 'win32') {
	xtermMatch = require('./_xterm-match');
}

getFn = function () {
	var fn = function (/*…msg*/) {
		var close = '';
		return reduce(fn._cliColorData, function (str, mod) {
			close = '\x1b[' + mod[1] + 'm' + close;
			return str + '\x1b[' + mod[0] + 'm';
		}, '', true) + join.call(arguments, ' ') + close;
	};
	fn.__proto__ = proto;
	return fn;
};

getMove = function (control) {
	return function (num) {
		num = isNaN(num) ? 0 : max(floor(num), 0);
		return num ? ('\x1b[' + num + control) : '';
	};
};

module.exports = defineProperties(getFn(), {
	width: d.gs(process.stdout.getWindowSize ? function () {
		return process.stdout.getWindowSize()[0];
	} : function () {
		return tty.getWindowSize ? tty.getWindowSize()[1] : 0;
	}),
	height: d.gs(getHeight = process.stdout.getWindowSize ? function () {
		return process.stdout.getWindowSize()[1];
	} : function () {
		return tty.getWindowSize ? tty.getWindowSize()[0] : 0;
	}),
	reset: d.gs(function () {
		return repeat.call('\n', getHeight() - 1) + '\x1bc';
	}),
	up: d(up = getMove('A')),
	down: d(down = getMove('B')),
	right: d(right = getMove('C')),
	left: d(left = getMove('D')),
	move: d(function (x, y) {
		x = isNaN(x) ? 0 : floor(x);
		y = isNaN(y) ? 0 : floor(y);
		return ((x > 0) ? right(x) : left(-x)) + ((y > 0) ? down(y) : up(-y));
	}),
	moveTo: d(function (x, y) {
		x = isNaN(x) ? 1 : (max(floor(x), 0) + 1);
		y = isNaN(y) ? 1 : (max(floor(y), 0) + 1);
		return '\x1b[' + y + ';' + x + 'H';
	}),
	bol: d(function (n/*, erase*/) {
		var dir;
		n = isNaN(n) ? 0 : Number(n);
		dir = (n >= 0) ? 'E' : 'F';
		n = floor(abs(n));
		return arguments[1] ?
				(((!n || (dir === 'F')) ? '\x1b[0E\x1bK' : '') +
					repeat.call('\x1b[1' + dir + '\x1b[K', n)) : '\x1b[' + n + dir;
	}),
	beep: d('\x07'),
	xtermSupported: d(!xtermMatch),
	_cliColorData: d({})
});
<|endoftext|>


<commit_before>/*global angular, jQuery*/
(function ($) {
    angular
        .module('shopAdmin.product')
        .controller('ProductFormCtrl', ProductFormCtrl);

    /* @ngInject */
    function ProductFormCtrl($state, $stateParams, $http, categoryService, productService, summerNoteService, brandService) {
        var vm = this;
        // declare shoreDescription and description for summernote
        vm.product = { shortDescription: '', description: '', specification: '' };
        vm.product.categoryIds = [];
        vm.product.options = [];
        vm.product.variations = [];
        vm.product.attributes = [];
        vm.categories = [];
        vm.thumbnailImage = null;
        vm.productImages = [];
        vm.options = [];
        vm.productTemplates = [];
        vm.addingOption = null;
        vm.attributes = [];
        vm.addingAttribute = null;
        vm.productId = $stateParams.id;
        vm.isEditMode = vm.productId > 0;
        vm.addingVariation = { priceOffset: 0 };
        vm.brands = [];

        vm.shortDescUpload = function (files) {
            summerNoteService.upload(files[0])
                .success(function (url) {
                    $(vm.shortDescEditor).summernote('insertImage', url);
                });
        };

        vm.descUpload = function (files) {
            summerNoteService.upload(files[0])
                .success(function (url) {
                    $(vm.descEditor).summernote('insertImage', url);
                });
        };

        vm.specUpload = function (files) {
            summerNoteService.upload(files[0])
                .success(function (url) {
                    $(vm.specEditor).summernote('insertImage', url);
                });
        };

        vm.addOption = function addOption() {
            vm.addingOption.values = [];
            var index = vm.options.indexOf(vm.addingOption);
            vm.product.options.push(vm.addingOption);
            vm.options.splice(index, 1);
            vm.addingOption = null;
        };

        vm.deleteOption = function deleteOption(option) {
            var index = vm.product.options.indexOf(option);
            vm.product.options.splice(index, 1);
            vm.options.push(option);
        };

        vm.generateOptionCombination = function generateOptionCombination() {
            var maxIndexOption = vm.product.options.length - 1;
            vm.product.variations = [];

            function getItemValue(item) {
                return item.value;
            }

            function helper(arr, optionIndex) {
                var j, l, variation, optionCombinations, optionValue;

                for (j = 0, l = vm.product.options[optionIndex].values.length; j < l; j = j + 1) {
                    optionCombinations = arr.slice(0);
                    optionValue = {
                        optionName: vm.product.options[optionIndex].name,
                        optionId: vm.product.options[optionIndex].id,
                        value: vm.product.options[optionIndex].values[j]
                    };
                    optionCombinations.push(optionValue);

                    if (optionIndex === maxIndexOption) {
                        variation = {
                            name: optionCombinations.map(getItemValue).join('-'),
                            optionCombinations: optionCombinations,
                            priceOffset : 0
                        };
                        vm.product.variations.push(variation);
                    } else {
                        helper(optionCombinations, optionIndex + 1);
                    }
                }
            }

            helper([], 0);
        };

        vm.deleteVariation = function deleteVariation(variation) {
            var index = vm.product.variations.indexOf(variation);
            vm.product.variations.splice(index, 1);
        };

        vm.removeMedia = function removeMedia(media) {
            var index = vm.product.productMedias.indexOf(media);
            vm.product.productMedias.splice(index, 1);
            vm.product.deletedMediaIds.push(media.id);
        };

        vm.addVariation = function addVariation() {
            var variation,
                optionCombinations = [];

            vm.product.options.forEach(function (option) {
                var optionValue = {
                    optionName: option.name,
                    optionId: option.id,
                    value: vm.addingVariation[option.name]
                };
                optionCombinations.push(optionValue);
            });

            variation = {
                name: optionCombinations.map(function (item) {
                    return item.value;
                }).join('-'),
                optionCombinations: optionCombinations,
                priceOffset: vm.addingVariation.priceOffset || 0
            };

            if (!vm.product.variations.find(function (item) { return item.name === variation.name; })) {
                vm.product.variations.push(variation);
                vm.addingVariation = { priceOffset: 0 };
            }
        };

        vm.applyTemplate = function applyTemplate() {
            var template, i, index, workingAttr;
            productService.getProductTemplate(vm.product.template.id).success(function (result) {
                template = result;

                for (i = 0; i < vm.product.attributes.length; i = i + 1) {
                    vm.attributes.push(vm.product.attributes[i]);
                }

                vm.product.attributes = [];

                for (i = 0; i < template.attributes.length; i = i + 1) {
                    workingAttr = vm.attributes.find(function (item) { return item.id = template.attributes[i].id; });
                    index = vm.attributes.indexOf(workingAttr);
                    vm.attributes.splice(index, 1);
                    vm.product.attributes.push(workingAttr);
                }
            });
        };

        vm.addAttribute = function addAttribute() {
            var index = vm.attributes.indexOf(vm.addingAttribute);
            vm.product.attributes.push(vm.addingAttribute);
            vm.attributes.splice(index, 1);
            vm.addingAttribute = null;
        };

        vm.deleteAttribute = function deleteAttribute(attribute) {
            var index = vm.product.attributes.indexOf(attribute);
            vm.product.attributes.splice(index, 1);
            vm.attributes.push(attribute);
        };

        vm.toggleCategories = function toggleCategories(categoryId) {
            var index = vm.product.categoryIds.indexOf(categoryId);
            if (index > -1) {
                vm.product.categoryIds.splice(index, 1);
            } else {
                vm.product.categoryIds.push(categoryId);
            }
        };

        vm.filterAddedOptionValue = function filterAddedOptionValue(item) {
            if (vm.product.options.length > 1) {
                return true;
            }
            var optionValueAdded = false;
            vm.product.variations.forEach(function (variation) {
                var optionValues = variation.optionCombinations.map(function (item) {
                    return item.value;
                });
                if (optionValues.indexOf(item) > -1) {
                    optionValueAdded = true;
                }
            });

            return !optionValueAdded;
        };

        vm.save = function save() {
            var promise;
            if (vm.isEditMode) {
                promise = productService.editProduct(vm.product, vm.thumbnailImage, vm.productImages);
            } else {
                promise = productService.createProduct(vm.product, vm.thumbnailImage, vm.productImages);
            }

            promise.success(function (result) {
                    $state.go('product');
                })
                .error(function (error) {
                    vm.validationErrors = [];
                    if (error && angular.isObject(error)) {
                        for (var key in error) {
                            vm.validationErrors.push(error[key][0]);
                        }
                    } else {
                        vm.validationErrors.push('Could not add product.');
                    }
                });
        };

        function getProduct() {
            productService.getProduct($stateParams.id).then(function (result) {
                var i, index, optionIds, attributeIds;
                vm.product = result.data;
                optionIds = vm.options.map(function (item) { return item.id; });
                for (i = 0; i < vm.product.options.length; i = i + 1) {
                    index = optionIds.indexOf(vm.product.options[i].id);
                    optionIds.splice(index, 1);
                    vm.options.splice(index, 1);
                }

                attributeIds = vm.attributes.map(function (item) { return item.id; });
                for (i = 0; i < vm.product.attributes.length; i = i + 1) {
                    index = attributeIds.indexOf(vm.product.attributes[i].id);
                    attributeIds.splice(index, 1);
                    vm.attributes.splice(index, 1);
                }
            });
        }

        function getCategories() {
            categoryService.getCategories().then(function (result) {
                vm.categories = result.data;
            });
        }

        function getProductOptions() {
            productService.getProductOptions().then(function (result) {
                vm.options = result.data;
            });
        }

        function getProductTemplates() {
            productService.getProductTemplates().then(function (result) {
                vm.productTemplates = result.data;
            });
        }

        function getAttributes() {
            productService.getProductAttrs().then(function (result) {
                vm.attributes = result.data;
            });
        }

        function getBrands() {
            brandService.getBrands().then(function (result) {
                vm.brands = result.data;
            });
        }

        function init() {
            if (vm.isEditMode) {
                getProduct();
            }
            getProductOptions();
            getProductTemplates();
            getAttributes();
            getCategories();
            getBrands();
        }

        init();
    }
})(jQuery);<commit_msg>product form: fix loading atributes from template<commit_after>/*global angular, jQuery*/
(function ($) {
    angular
        .module('shopAdmin.product')
        .controller('ProductFormCtrl', ProductFormCtrl);

    /* @ngInject */
    function ProductFormCtrl($state, $stateParams, $http, categoryService, productService, summerNoteService, brandService) {
        var vm = this;
        // declare shoreDescription and description for summernote
        vm.product = { shortDescription: '', description: '', specification: '' };
        vm.product.categoryIds = [];
        vm.product.options = [];
        vm.product.variations = [];
        vm.product.attributes = [];
        vm.categories = [];
        vm.thumbnailImage = null;
        vm.productImages = [];
        vm.options = [];
        vm.productTemplates = [];
        vm.addingOption = null;
        vm.attributes = [];
        vm.addingAttribute = null;
        vm.productId = $stateParams.id;
        vm.isEditMode = vm.productId > 0;
        vm.addingVariation = { priceOffset: 0 };
        vm.brands = [];

        vm.shortDescUpload = function (files) {
            summerNoteService.upload(files[0])
                .success(function (url) {
                    $(vm.shortDescEditor).summernote('insertImage', url);
                });
        };

        vm.descUpload = function (files) {
            summerNoteService.upload(files[0])
                .success(function (url) {
                    $(vm.descEditor).summernote('insertImage', url);
                });
        };

        vm.specUpload = function (files) {
            summerNoteService.upload(files[0])
                .success(function (url) {
                    $(vm.specEditor).summernote('insertImage', url);
                });
        };

        vm.addOption = function addOption() {
            vm.addingOption.values = [];
            var index = vm.options.indexOf(vm.addingOption);
            vm.product.options.push(vm.addingOption);
            vm.options.splice(index, 1);
            vm.addingOption = null;
        };

        vm.deleteOption = function deleteOption(option) {
            var index = vm.product.options.indexOf(option);
            vm.product.options.splice(index, 1);
            vm.options.push(option);
        };

        vm.generateOptionCombination = function generateOptionCombination() {
            var maxIndexOption = vm.product.options.length - 1;
            vm.product.variations = [];

            function getItemValue(item) {
                return item.value;
            }

            function helper(arr, optionIndex) {
                var j, l, variation, optionCombinations, optionValue;

                for (j = 0, l = vm.product.options[optionIndex].values.length; j < l; j = j + 1) {
                    optionCombinations = arr.slice(0);
                    optionValue = {
                        optionName: vm.product.options[optionIndex].name,
                        optionId: vm.product.options[optionIndex].id,
                        value: vm.product.options[optionIndex].values[j]
                    };
                    optionCombinations.push(optionValue);

                    if (optionIndex === maxIndexOption) {
                        variation = {
                            name: optionCombinations.map(getItemValue).join('-'),
                            optionCombinations: optionCombinations,
                            priceOffset : 0
                        };
                        vm.product.variations.push(variation);
                    } else {
                        helper(optionCombinations, optionIndex + 1);
                    }
                }
            }

            helper([], 0);
        };

        vm.deleteVariation = function deleteVariation(variation) {
            var index = vm.product.variations.indexOf(variation);
            vm.product.variations.splice(index, 1);
        };

        vm.removeMedia = function removeMedia(media) {
            var index = vm.product.productMedias.indexOf(media);
            vm.product.productMedias.splice(index, 1);
            vm.product.deletedMediaIds.push(media.id);
        };

        vm.addVariation = function addVariation() {
            var variation,
                optionCombinations = [];

            vm.product.options.forEach(function (option) {
                var optionValue = {
                    optionName: option.name,
                    optionId: option.id,
                    value: vm.addingVariation[option.name]
                };
                optionCombinations.push(optionValue);
            });

            variation = {
                name: optionCombinations.map(function (item) {
                    return item.value;
                }).join('-'),
                optionCombinations: optionCombinations,
                priceOffset: vm.addingVariation.priceOffset || 0
            };

            if (!vm.product.variations.find(function (item) { return item.name === variation.name; })) {
                vm.product.variations.push(variation);
                vm.addingVariation = { priceOffset: 0 };
            }
        };

        // TODO look for a more concise way
        vm.applyTemplate = function applyTemplate() {
            var template, i, index, workingAttr,
                nonTemplateAttrs = [];

            productService.getProductTemplate(vm.product.template.id).success(function (result) {
                template = result;

                for (i = 0; i < template.attributes.length; i = i + 1) {
                    workingAttr = vm.product.attributes.find(function (item) { return item && item.id === template.attributes[i].id; });
                    if (workingAttr) {
                        continue;
                    }
                    workingAttr = vm.attributes.find(function (item) { return item && item.id === template.attributes[i].id; });
                    index = vm.attributes.indexOf(workingAttr);
                    vm.attributes.splice(index, 1);
                    vm.product.attributes.push(workingAttr);
                }

                for (i = 0; i < vm.product.attributes.length; i = i + 1) {
                    workingAttr = template.attributes.find(function (item) { return item && item.id === vm.product.attributes[i].id; });
                    if (!workingAttr) {
                        nonTemplateAttrs.push(vm.product.attributes[i]);
                    }
                }

                for (i = 0; i < nonTemplateAttrs.length; i = i + 1) {
                    workingAttr = vm.product.attributes.find(function (item) { return item && item.id === nonTemplateAttrs[i].id; });
                    index = vm.product.attributes.indexOf(workingAttr);
                    vm.product.attributes.splice(index, 1);
                    vm.attributes.push(workingAttr);
                }
            });
        };

        vm.addAttribute = function addAttribute() {
            var index = vm.attributes.indexOf(vm.addingAttribute);
            vm.product.attributes.push(vm.addingAttribute);
            vm.attributes.splice(index, 1);
            vm.addingAttribute = null;
        };

        vm.deleteAttribute = function deleteAttribute(attribute) {
            var index = vm.product.attributes.indexOf(attribute);
            vm.product.attributes.splice(index, 1);
            vm.attributes.push(attribute);
        };

        vm.toggleCategories = function toggleCategories(categoryId) {
            var index = vm.product.categoryIds.indexOf(categoryId);
            if (index > -1) {
                vm.product.categoryIds.splice(index, 1);
            } else {
                vm.product.categoryIds.push(categoryId);
            }
        };

        vm.filterAddedOptionValue = function filterAddedOptionValue(item) {
            if (vm.product.options.length > 1) {
                return true;
            }
            var optionValueAdded = false;
            vm.product.variations.forEach(function (variation) {
                var optionValues = variation.optionCombinations.map(function (item) {
                    return item.value;
                });
                if (optionValues.indexOf(item) > -1) {
                    optionValueAdded = true;
                }
            });

            return !optionValueAdded;
        };

        vm.save = function save() {
            var promise;
            if (vm.isEditMode) {
                promise = productService.editProduct(vm.product, vm.thumbnailImage, vm.productImages);
            } else {
                promise = productService.createProduct(vm.product, vm.thumbnailImage, vm.productImages);
            }

            promise.success(function (result) {
                    $state.go('product');
                })
                .error(function (error) {
                    vm.validationErrors = [];
                    if (error && angular.isObject(error)) {
                        for (var key in error) {
                            vm.validationErrors.push(error[key][0]);
                        }
                    } else {
                        vm.validationErrors.push('Could not add product.');
                    }
                });
        };

        function getProduct() {
            productService.getProduct($stateParams.id).then(function (result) {
                var i, index, optionIds, attributeIds;
                vm.product = result.data;
                optionIds = vm.options.map(function (item) { return item.id; });
                for (i = 0; i < vm.product.options.length; i = i + 1) {
                    index = optionIds.indexOf(vm.product.options[i].id);
                    optionIds.splice(index, 1);
                    vm.options.splice(index, 1);
                }

                attributeIds = vm.attributes.map(function (item) { return item.id; });
                for (i = 0; i < vm.product.attributes.length; i = i + 1) {
                    index = attributeIds.indexOf(vm.product.attributes[i].id);
                    attributeIds.splice(index, 1);
                    vm.attributes.splice(index, 1);
                }
            });
        }

        function getCategories() {
            categoryService.getCategories().then(function (result) {
                vm.categories = result.data;
            });
        }

        function getProductOptions() {
            productService.getProductOptions().then(function (result) {
                vm.options = result.data;
            });
        }

        function getProductTemplates() {
            productService.getProductTemplates().then(function (result) {
                vm.productTemplates = result.data;
            });
        }

        function getAttributes() {
            productService.getProductAttrs().then(function (result) {
                vm.attributes = result.data;
            });
        }

        function getBrands() {
            brandService.getBrands().then(function (result) {
                vm.brands = result.data;
            });
        }

        function init() {
            if (vm.isEditMode) {
                getProduct();
            }
            getProductOptions();
            getProductTemplates();
            getAttributes();
            getCategories();
            getBrands();
        }

        init();
    }
})(jQuery);<|endoftext|>


<commit_before>import List from './list';
import Area from './area';
import Footer from './footer';
import Bus from './bus';
import Editor from './editor';
import editorButtons from './editorButtons.js';
import lifeCycleHooks, { dispatch, initLifeCycle } from './lifeCycle';

import nodes, { LEYLIM_ROOT } from './constant';

/**
 * Constructor of Leylim
 *
 * @example
 * ```javascript
 * const leylim = new Leylim({
 *   el: '#app',
 *   components,
 *   rowList
 * });
 * ```
 *
 * @export
 * @class Leylim
 */

export default class Leylim {
  constructor(options) {
    /**
     * @todo extends options
     * @todo check is options.el dom element?
     */
    this.options = options;
    const _lifeCycleHooks = Object.assign({}, lifeCycleHooks, this.options);
    initLifeCycle(_lifeCycleHooks);
    dispatch('beforeCreate');
    this.init();
  }
  /**
   * For plugin using
   * @static
   * @memberof Leylim
   */
  static use(plugin, options) {
    this._plugins.push(() => {
      if (!plugin.install) throw new Error('Plugin must have install method');
      plugin.install(this, options);
    });
  }

  static forceUpdate() {
    Bus.fire('forceUpdate');
  }
  /**
   * Save selection text for using after command or anything
   *
   * @static
   * @memberof Leylim
   */
  static saveSelection = function() {
    if (window.getSelection) {
      var sel = window.getSelection();
      if (sel.getRangeAt && sel.rangeCount) {
        this._selection = sel.getRangeAt(0);
        return this._selection;
      }
    } else if (document.selection && document.selection.createRange) {
      this._selection = document.selection.createRange();
      return this._selection;
    }
    return null;
  };

  static restoreSelection = function() {
    if (this._selection) {
      if (window.getSelection) {
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(this._selection);
      } else if (document.selection && this._selection.select) {
        this._selection.select();
      }
    }
  };

  // All static properties of Leylim,  also you can use under plugin install
  static editorButtons = editorButtons;
  static nodes = nodes;
  static _plugins = [];
  static _selection = null;

  /**
   * Public method for get all rowList
   * @public
   * @returns
   * @memberof Leylim
   */
  getRowData() {
    return this._area.getRowData();
  }
  /**
   * init member of leylim for example; List, Area etc
   * @private
   */
  init() {
    const {
      components = [],
      el,
      rowList = [],
      buttons = [],
      thumbnailPath = '',
      customEditorButtons = {
        merge: true,
        buttons: []
      }
    } = this.options;

    if (!components.length)
      throw new Error(
        "Can you give me components? please! If you don't have an idea; https://github.com/abdullah/leylim "
      );

    Leylim._components = components;
    Leylim._rowList = rowList;

    const appNode = document.querySelector(el);
    const leylimNode = document.createElement('div');
    leylimNode.classList.add(LEYLIM_ROOT);
    appNode.appendChild(leylimNode);

    this._list = new List({
      rootNode: `.${LEYLIM_ROOT}`,
      thumbnailPath,
      components
    });

    this._footer = new Footer({
      rootNode: `.${LEYLIM_ROOT}`,
      buttons
    });

    this._area = new Area({
      rootNode: `.${LEYLIM_ROOT}`,
      rowList
    });

    Leylim._plugins.forEach(fn => {
      fn();
    });

    this._editor = new Editor({
      merge: customEditorButtons.merge,
      buttons: customEditorButtons.buttons,
      filter: customEditorButtons.filter
    });

    dispatch('created');
  }
}
<commit_msg>reformat Leylim<commit_after>import List from './list';
import Area from './area';
import Footer from './footer';
import Bus from './bus';
import Editor from './editor';
import editorButtons from './editorButtons.js';
import lifeCycleHooks, { dispatch, initLifeCycle } from './lifeCycle';

import nodes, { LEYLIM_ROOT } from './constant';

/**
 * Constructor of Leylim
 *
 * @example
 * ```javascript
 * const leylim = new Leylim({
 *   el: '#app',
 *   components,
 *   rowList
 * });
 * ```
 *
 * @export
 * @class Leylim
 */

export default class Leylim {
  constructor(options) {
    /**
     * @todo extends options
     * @todo check is options.el dom element?
     */
    this.options = options;
    const _lifeCycleHooks = Object.assign({}, lifeCycleHooks, this.options);
    initLifeCycle(_lifeCycleHooks);
    dispatch('beforeCreate');
    this.init();
  }
  /**
   * Public method for get all rowList
   * @public
   * @returns
   * @memberof Leylim
   */
  getRowData() {
    return this._area.getRowData();
  }
  /**
   * init member of leylim for example; List, Area etc
   * @private
   */
  init() {
    const {
      components = [],
      el,
      rowList = [],
      buttons = [],
      thumbnailPath = '',
      customEditorButtons = {
        merge: true,
        buttons: []
      }
    } = this.options;

    if (!components.length)
      throw new Error(
        "Can you give me components? please! If you don't have an idea; https://github.com/abdullah/leylim "
      );

    Leylim._components = components;
    Leylim._rowList = rowList;

    const appNode = document.querySelector(el);
    const leylimNode = document.createElement('div');
    leylimNode.classList.add(LEYLIM_ROOT);
    appNode.appendChild(leylimNode);

    this._list = new List({
      rootNode: `.${LEYLIM_ROOT}`,
      thumbnailPath,
      components
    });

    this._footer = new Footer({
      rootNode: `.${LEYLIM_ROOT}`,
      buttons
    });

    this._area = new Area({
      rootNode: `.${LEYLIM_ROOT}`,
      rowList
    });

    Leylim._plugins.forEach(fn => {
      fn();
    });

    this._editor = new Editor({
      merge: customEditorButtons.merge,
      buttons: customEditorButtons.buttons,
      filter: customEditorButtons.filter
    });

    dispatch('created');
  }
  /**
   * For plugin using
   * @static
   * @memberof Leylim
   */
  static use(plugin, options) {
    this._plugins.push(() => {
      if (!plugin.install) throw new Error('Plugin must have install method');
      plugin.install(this, options);
    });
  }

  static forceUpdate() {
    Bus.fire('forceUpdate');
  }
  /**
   * Save selection text for using after command or anything
   *
   * @static
   * @memberof Leylim
   */
  static saveSelection = () => {
    if (window.getSelection) {
      var sel = window.getSelection();
      if (sel.getRangeAt && sel.rangeCount) {
        this._selection = sel.getRangeAt(0);
        return this._selection;
      }
    } else if (document.selection && document.selection.createRange) {
      this._selection = document.selection.createRange();
      return this._selection;
    }
    return null;
  };

  static restoreSelection = () => {
    if (this._selection) {
      if (window.getSelection) {
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(this._selection);
      } else if (document.selection && this._selection.select) {
        this._selection.select();
      }
    }
  };

  // All static properties of Leylim,  also you can use under plugin install
  static editorButtons = editorButtons;
  static nodes = nodes;
  static _plugins = [];
  static _selection = null;
}
<|endoftext|>


<commit_before>"use strict";

var async = require("async");
var exec = require("child_process").exec;
var colors = require("colors");
var Spinner = require("cli-spinner").Spinner;
var spinner;

var symbols = {
    ok: "✓",
    err: "✖",
    arrow: "→"
};

if (process.platform === "win32") {
    symbols.ok = "\u221A";
    symbols.err = "\u00D7";
    symbols.arrow = "\u2192";
}

log("Looking for outdated modules... ");
exec("npm outdated --json --long --depth=0", { encoding: "utf8" }, function (err, stdout, stderr) {
    var outdated;
    var tasks;

    function createTask(info, index) {
        index++;
        return function (done) {
            var msg = colors.grey("(" + index + "/" + tasks.length + ")") + "\t" + info.name + "\tupdating ".grey + info.current + " " + symbols.arrow.gray + " " + info.latest + " ... ".grey;

            log(msg);
            async.series({
                updateModule: async.apply(exec, "npm i " + info.name + "@" + info.latest + " " + info.saveCmd),
                updateConsole: function (done) {
                    msg = msg + "tests: ";
                    log(msg);
                    setImmediate(done);
                },
                runTests: async.apply(exec, "npm test")
            }, function (err) {
                if (err) {
                    log(
                        msg = colors.grey("(" + index + "/" + tasks.length + ")") + "\t" + info.name.red + "\tupdating ".grey + info.current + " " + symbols.arrow.gray + " " + info.latest + " ... ".grey +
                        "tests: " + symbols.err.red + " ... ".grey + "rolling back to " + info.current + " ... ".grey
                    );
                    exec("npm i " + info.name + "@" + info.current + " " + info.saveCmd, function () {
                        spinner.stop();
                        clear();
                        process.stdout.write(
                            msg + symbols.ok.grey + "\n"
                        );
                        done();
                    });
                    return;
                }
                spinner.stop();
                clear();
                process.stdout.write(
                    msg + symbols.ok.green + "\n"
                );
                done();
            });
        };
    }

    if (err) {
        throw err;
    }

    if (stdout === "") {
        console.log("No outdated modules found");
        process.exit(0);
        return;
    }

    outdated = JSON.parse(stdout);

    tasks = Object.keys(outdated)
        .map(function (moduleName) {
            var info = outdated[moduleName];

            info.name = moduleName;
            info.saveCmd = info.type === "devDependencies" ? "--save-dev" : "--save";

            return info;
        })
        .filter(function (info) {
            return info.latest !== "git";
        })
        .map(function (info, index, outdatedModules) {
            return createTask(info, index, outdatedModules);
        });

    spinner.stop(true);
    console.log("Found %s outdated module%s", tasks.length, tasks.length === 1 ? "" : "s");
    console.log("");
    console.log("Starting to update your modules...");

    async.series(tasks, function (err) {
        if (err) {
            throw err;
        }
        console.log("");
        console.log("Finished.");
        spinner.stop();
    });
});

function log(message) {
    if (spinner) {
        spinner.stop();
    }
    spinner = new Spinner(message + "%s ");
    spinner.setSpinnerString(10);
    spinner.start();
}

function clear() {
    process.stdout.clearLine();
    process.stdout.cursorTo(0);
}
<commit_msg>Add tabs to console output<commit_after>"use strict";

var async = require("async");
var exec = require("child_process").exec;
var colors = require("colors");
var Spinner = require("cli-spinner").Spinner;
var spinner;

var symbols = {
    ok: "✓",
    err: "✖",
    arrow: "→"
};

if (process.platform === "win32") {
    symbols.ok = "\u221A";
    symbols.err = "\u00D7";
    symbols.arrow = "\u2192";
}

log("Looking for outdated modules... ");
exec("npm outdated --json --long --depth=0", { encoding: "utf8" }, function (err, stdout, stderr) {
    var outdated;
    var tasks;

    function createTask(info, index) {
        index++;
        return function (done) {
            var msg = colors.grey("(" + index + "/" + tasks.length + ")") + "\t" + info.name + "\tupdating ".grey + info.current + " " + symbols.arrow.gray + " " + info.latest + " ... ".grey;

            log(msg);
            async.series({
                updateModule: async.apply(exec, "npm i " + info.name + "@" + info.latest + " " + info.saveCmd),
                updateConsole: function (done) {
                    msg = msg + "\ttests: ";
                    log(msg);
                    setImmediate(done);
                },
                runTests: async.apply(exec, "npm test")
            }, function (err) {
                if (err) {
                    log(
                        msg = colors.grey("(" + index + "/" + tasks.length + ")") + "\t" + info.name.red + "\tupdating ".grey + info.current + " " + symbols.arrow.gray + " " + info.latest + " ... ".grey +
                        "\ttests: " + symbols.err.red + " ... ".grey + "\trolling back to " + info.current + " ... ".grey
                    );
                    exec("npm i " + info.name + "@" + info.current + " " + info.saveCmd, function () {
                        spinner.stop();
                        clear();
                        process.stdout.write(
                            msg + symbols.ok.grey + "\n"
                        );
                        done();
                    });
                    return;
                }
                spinner.stop();
                clear();
                process.stdout.write(
                    msg + symbols.ok.green + "\n"
                );
                done();
            });
        };
    }

    if (err) {
        throw err;
    }

    if (stdout === "") {
        console.log("No outdated modules found");
        process.exit(0);
        return;
    }

    outdated = JSON.parse(stdout);

    tasks = Object.keys(outdated)
        .map(function (moduleName) {
            var info = outdated[moduleName];

            info.name = moduleName;
            info.saveCmd = info.type === "devDependencies" ? "--save-dev" : "--save";

            return info;
        })
        .filter(function (info) {
            return info.latest !== "git";
        })
        .map(function (info, index, outdatedModules) {
            return createTask(info, index, outdatedModules);
        });

    spinner.stop(true);
    console.log("Found %s outdated module%s", tasks.length, tasks.length === 1 ? "" : "s");
    console.log("");
    console.log("Starting to update your modules...");

    async.series(tasks, function (err) {
        if (err) {
            throw err;
        }
        console.log("");
        console.log("Finished.");
        spinner.stop();
    });
});

function log(message) {
    if (spinner) {
        spinner.stop();
    }
    spinner = new Spinner(message + "%s ");
    spinner.setSpinnerString(10);
    spinner.start();
}

function clear() {
    process.stdout.clearLine();
    process.stdout.cursorTo(0);
}
<|endoftext|>


<commit_before>var assert = require('assert')
var crypto = require('crypto')
var networks = require('./networks')

var Address = require('./address')
var HDNode = require('./hdnode')
var Transaction = require('./transaction')
var Script = require('./script')

function Wallet(seed, network, unspents) {
  seed = seed || crypto.randomBytes(32)
  network = network || networks.bitcoin

  // Stored in a closure to make accidental serialization less likely
  var masterKey = HDNode.fromSeedBuffer(seed, network)

  // HD first-level child derivation method should be hardened
  // See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
  var accountZero = masterKey.deriveHardened(0)
  var externalAccount = accountZero.derive(0)
  var internalAccount = accountZero.derive(1)

  this.addresses = []
  this.changeAddresses = []
  this.network = network
  this.outputs = unspents ? processUnspentOutputs(unspents) : {}

  // FIXME: remove in 2.x.y
  var me = this
  this.newMasterKey = function(seed) {
    console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')

    seed = seed || crypto.randomBytes(32)
    masterKey = HDNode.fromSeedBuffer(seed, network)

    accountZero = masterKey.deriveHardened(0)
    externalAccount = accountZero.derive(0)
    internalAccount = accountZero.derive(1)

    me.addresses = []
    me.changeAddresses = []

    me.outputs = {}
  }

  this.getMasterKey = function() { return masterKey }
  this.getAccountZero = function() { return accountZero }
  this.getExternalAccount = function() { return externalAccount }
  this.getInternalAccount = function() { return internalAccount }
}

Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
  assert(value > this.network.dustThreshold, value + ' must be above dust threshold (' + this.network.dustThreshold + ' Satoshis)')

  var utxos = getCandidateOutputs(this.outputs, value)
  var accum = 0
  var subTotal = value
  var addresses = []

  var tx = new Transaction()
  tx.addOutput(to, value)

  for (var i = 0; i < utxos.length; ++i) {
    var utxo = utxos[i]
    addresses.push(utxo.address)

    var outpoint = utxo.from.split(':')
    tx.addInput(outpoint[0], parseInt(outpoint[1]))

    var fee = fixedFee == undefined ? estimatePaddedFee(tx, this.network) : fixedFee

    accum += utxo.value
    subTotal = value + fee
    if (accum >= subTotal) {
      var change = accum - subTotal

      if (change > this.network.dustThreshold) {
        tx.addOutput(changeAddress || this.getChangeAddress(), change)
      }

      break
    }
  }

  assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal)

  this.signWith(tx, addresses)
  return tx
}

Wallet.prototype.processPendingTx = function(tx){
  processTx.bind(this)(tx, true)
}

Wallet.prototype.processConfirmedTx = function(tx){
  processTx.bind(this)(tx, false)
}

Wallet.prototype.generateAddress = function() {
  var k = this.addresses.length
  var address = this.getExternalAccount().derive(k).getAddress()

  this.addresses.push(address.toString())

  return this.getReceiveAddress()
}

Wallet.prototype.generateChangeAddress = function() {
  var k = this.changeAddresses.length
  var address = this.getInternalAccount().derive(k).getAddress()

  this.changeAddresses.push(address.toString())

  return this.getChangeAddress()
}

Wallet.prototype.getBalance = function() {
  return this.getUnspentOutputs().reduce(function(accum, output) {
    return accum + output.value
  }, 0)
}

Wallet.prototype.getChangeAddress = function() {
  if (this.changeAddresses.length === 0) {
    this.generateChangeAddress()
  }

  return this.changeAddresses[this.changeAddresses.length - 1]
}

Wallet.prototype.getInternalPrivateKey = function(index) {
  return this.getInternalAccount().derive(index).privKey
}

Wallet.prototype.getPrivateKey = function(index) {
  return this.getExternalAccount().derive(index).privKey
}

Wallet.prototype.getPrivateKeyForAddress = function(address) {
  if (includeAddress(this.addresses, address)) {
    var index = this.addresses.indexOf(address)

    return this.getPrivateKey(index)
  }

  if (includeAddress(this.changeAddresses, address)) {
    var index = this.changeAddresses.indexOf(address)

    return this.getInternalPrivateKey(index)
  }

  assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated')
}

Wallet.prototype.getReceiveAddress = function() {
  if (this.addresses.length === 0) {
    this.generateAddress()
  }

  return this.addresses[this.addresses.length - 1]
}

Wallet.prototype.getUnspentOutputs = function() {
  var utxo = []

  for(var key in this.outputs){
    var output = this.outputs[key]
    if(!output.to) utxo.push(outputToUnspentOutput(output))
  }

  return utxo
}

Wallet.prototype.setUnspentOutputs = function(utxo) {
  console.warn('setUnspentOutputs is deprecated, please use the constructor option instead')

  this.outputs = processUnspentOutputs(utxo)
}

Wallet.prototype.signWith = function(tx, addresses) {
  assert.equal(tx.ins.length, addresses.length, 'Number of addresses must match number of transaction inputs')

  addresses.forEach(function(address, i) {
    var key = this.getPrivateKeyForAddress(address)

    tx.sign(i, key)
  }, this)

  return tx
}

function outputToUnspentOutput(output){
  var hashAndIndex = output.from.split(":")

  return {
    hash: hashAndIndex[0],
    index: parseInt(hashAndIndex[1]),
    address: output.address,
    value: output.value,
    pending: output.pending
  }
}

function estimatePaddedFee(tx, network) {
  var tmpTx = tx.clone()
  tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)

  return network.estimateFee(tmpTx)
}

function processUnspentOutputs(utxos) {
  var outputs = {}

  utxos.forEach(function(utxo){
    var hash = new Buffer(utxo.hash, 'hex')
    var index = utxo.index
    var address = utxo.address
    var value = utxo.value

    // FIXME: remove alternative in 2.x.y
    if (index === undefined) index = utxo.outputIndex

    assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
    assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
    assert.doesNotThrow(function() { Address.fromBase58Check(address) }, 'Expected Base58 Address, got ' + address)
    assert.equal(typeof value, 'number', 'Expected number value, got ' + value)

    var key = utxo.hash + ':' + utxo.index

    outputs[key] = {
      from: key,
      address: address,
      value: value,
      pending: utxo.pending
    }
  })

  return outputs
}

function getCandidateOutputs(outputs/*, value*/) {
  var unspent = []

  for (var key in outputs) {
    var output = outputs[key]
    if (!output.pending) unspent.push(output)
  }

  var sortByValueDesc = unspent.sort(function(o1, o2){
    return o2.value - o1.value
  })

  return sortByValueDesc
}

function processTx(tx, isPending) {
  var txid = tx.getId()

  tx.outs.forEach(function(txOut, i) {
    var address

    try {
      address = Address.fromOutputScript(txOut.script, this.network).toString()
    } catch(e) {
      if (!(e.message.match(/has no matching Address/))) throw e
    }

    var myAddresses = this.addresses.concat(this.changeAddresses)
    if (includeAddress(myAddresses, address)) {
      var output = txid + ':' + i

      this.outputs[output] = {
        from: output,
        value: txOut.value,
        address: address,
        pending: isPending
      }
    }
  }, this)

  tx.ins.forEach(function(txIn, i) {
    // copy and convert to big-endian hex
    var txinId = new Buffer(txIn.hash)
    Array.prototype.reverse.call(txinId)
    txinId = txinId.toString('hex')

    var output = txinId + ':' + txIn.index

    if (!(output in this.outputs)) return

    if (isPending) {
      this.outputs[output].to = txid + ':' + i
      this.outputs[output].pending = true
    } else {
      delete this.outputs[output]
    }
  }, this)
}

function includeAddress(addresses, address) {
  return addresses.indexOf(address) > -1
}

module.exports = Wallet
<commit_msg>Wallet: use indexOf explicitly over include*<commit_after>var assert = require('assert')
var crypto = require('crypto')
var networks = require('./networks')

var Address = require('./address')
var HDNode = require('./hdnode')
var Transaction = require('./transaction')
var Script = require('./script')

function Wallet(seed, network, unspents) {
  seed = seed || crypto.randomBytes(32)
  network = network || networks.bitcoin

  // Stored in a closure to make accidental serialization less likely
  var masterKey = HDNode.fromSeedBuffer(seed, network)

  // HD first-level child derivation method should be hardened
  // See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
  var accountZero = masterKey.deriveHardened(0)
  var externalAccount = accountZero.derive(0)
  var internalAccount = accountZero.derive(1)

  this.addresses = []
  this.changeAddresses = []
  this.network = network
  this.outputs = unspents ? processUnspentOutputs(unspents) : {}

  // FIXME: remove in 2.x.y
  var me = this
  this.newMasterKey = function(seed) {
    console.warn('newMasterKey is deprecated, please make a new Wallet instance instead')

    seed = seed || crypto.randomBytes(32)
    masterKey = HDNode.fromSeedBuffer(seed, network)

    accountZero = masterKey.deriveHardened(0)
    externalAccount = accountZero.derive(0)
    internalAccount = accountZero.derive(1)

    me.addresses = []
    me.changeAddresses = []

    me.outputs = {}
  }

  this.getMasterKey = function() { return masterKey }
  this.getAccountZero = function() { return accountZero }
  this.getExternalAccount = function() { return externalAccount }
  this.getInternalAccount = function() { return internalAccount }
}

Wallet.prototype.createTx = function(to, value, fixedFee, changeAddress) {
  assert(value > this.network.dustThreshold, value + ' must be above dust threshold (' + this.network.dustThreshold + ' Satoshis)')

  var utxos = getCandidateOutputs(this.outputs, value)
  var accum = 0
  var subTotal = value
  var addresses = []

  var tx = new Transaction()
  tx.addOutput(to, value)

  for (var i = 0; i < utxos.length; ++i) {
    var utxo = utxos[i]
    addresses.push(utxo.address)

    var outpoint = utxo.from.split(':')
    tx.addInput(outpoint[0], parseInt(outpoint[1]))

    var fee = fixedFee == undefined ? estimatePaddedFee(tx, this.network) : fixedFee

    accum += utxo.value
    subTotal = value + fee
    if (accum >= subTotal) {
      var change = accum - subTotal

      if (change > this.network.dustThreshold) {
        tx.addOutput(changeAddress || this.getChangeAddress(), change)
      }

      break
    }
  }

  assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal)

  this.signWith(tx, addresses)
  return tx
}

Wallet.prototype.processPendingTx = function(tx){
  processTx.bind(this)(tx, true)
}

Wallet.prototype.processConfirmedTx = function(tx){
  processTx.bind(this)(tx, false)
}

Wallet.prototype.generateAddress = function() {
  var k = this.addresses.length
  var address = this.getExternalAccount().derive(k).getAddress()

  this.addresses.push(address.toString())

  return this.getReceiveAddress()
}

Wallet.prototype.generateChangeAddress = function() {
  var k = this.changeAddresses.length
  var address = this.getInternalAccount().derive(k).getAddress()

  this.changeAddresses.push(address.toString())

  return this.getChangeAddress()
}

Wallet.prototype.getBalance = function() {
  return this.getUnspentOutputs().reduce(function(accum, output) {
    return accum + output.value
  }, 0)
}

Wallet.prototype.getChangeAddress = function() {
  if (this.changeAddresses.length === 0) {
    this.generateChangeAddress()
  }

  return this.changeAddresses[this.changeAddresses.length - 1]
}

Wallet.prototype.getInternalPrivateKey = function(index) {
  return this.getInternalAccount().derive(index).privKey
}

Wallet.prototype.getPrivateKey = function(index) {
  return this.getExternalAccount().derive(index).privKey
}

Wallet.prototype.getPrivateKeyForAddress = function(address) {
  if (this.addresses.indexOf(address) > -1) {
    var index = this.addresses.indexOf(address)

    return this.getPrivateKey(index)
  }

  if (this.changeAddresses.indexOf(address) > -1) {
    var index = this.changeAddresses.indexOf(address)

    return this.getInternalPrivateKey(index)
  }

  assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated')
}

Wallet.prototype.getReceiveAddress = function() {
  if (this.addresses.length === 0) {
    this.generateAddress()
  }

  return this.addresses[this.addresses.length - 1]
}

Wallet.prototype.getUnspentOutputs = function() {
  var utxo = []

  for(var key in this.outputs){
    var output = this.outputs[key]
    if(!output.to) utxo.push(outputToUnspentOutput(output))
  }

  return utxo
}

Wallet.prototype.setUnspentOutputs = function(utxo) {
  console.warn('setUnspentOutputs is deprecated, please use the constructor option instead')

  this.outputs = processUnspentOutputs(utxo)
}

Wallet.prototype.signWith = function(tx, addresses) {
  assert.equal(tx.ins.length, addresses.length, 'Number of addresses must match number of transaction inputs')

  addresses.forEach(function(address, i) {
    var key = this.getPrivateKeyForAddress(address)

    tx.sign(i, key)
  }, this)

  return tx
}

function outputToUnspentOutput(output){
  var hashAndIndex = output.from.split(":")

  return {
    hash: hashAndIndex[0],
    index: parseInt(hashAndIndex[1]),
    address: output.address,
    value: output.value,
    pending: output.pending
  }
}

function estimatePaddedFee(tx, network) {
  var tmpTx = tx.clone()
  tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0)

  return network.estimateFee(tmpTx)
}

function processUnspentOutputs(utxos) {
  var outputs = {}

  utxos.forEach(function(utxo){
    var hash = new Buffer(utxo.hash, 'hex')
    var index = utxo.index
    var address = utxo.address
    var value = utxo.value

    // FIXME: remove alternative in 2.x.y
    if (index === undefined) index = utxo.outputIndex

    assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length)
    assert.equal(typeof index, 'number', 'Expected number index, got ' + index)
    assert.doesNotThrow(function() { Address.fromBase58Check(address) }, 'Expected Base58 Address, got ' + address)
    assert.equal(typeof value, 'number', 'Expected number value, got ' + value)

    var key = utxo.hash + ':' + utxo.index

    outputs[key] = {
      from: key,
      address: address,
      value: value,
      pending: utxo.pending
    }
  })

  return outputs
}

function getCandidateOutputs(outputs/*, value*/) {
  var unspent = []

  for (var key in outputs) {
    var output = outputs[key]
    if (!output.pending) unspent.push(output)
  }

  var sortByValueDesc = unspent.sort(function(o1, o2){
    return o2.value - o1.value
  })

  return sortByValueDesc
}

function processTx(tx, isPending) {
  var txid = tx.getId()

  tx.outs.forEach(function(txOut, i) {
    var address

    try {
      address = Address.fromOutputScript(txOut.script, this.network).toString()
    } catch(e) {
      if (!(e.message.match(/has no matching Address/))) throw e
    }

    var myAddresses = this.addresses.concat(this.changeAddresses)
    if (myAddresses.indexOf(address) > -1) {
      var output = txid + ':' + i

      this.outputs[output] = {
        from: output,
        value: txOut.value,
        address: address,
        pending: isPending
      }
    }
  }, this)

  tx.ins.forEach(function(txIn, i) {
    // copy and convert to big-endian hex
    var txinId = new Buffer(txIn.hash)
    Array.prototype.reverse.call(txinId)
    txinId = txinId.toString('hex')

    var output = txinId + ':' + txIn.index

    if (!(output in this.outputs)) return

    if (isPending) {
      this.outputs[output].to = txid + ':' + i
      this.outputs[output].pending = true
    } else {
      delete this.outputs[output]
    }
  }, this)
}

module.exports = Wallet
<|endoftext|>