<commit_before>var nif = {
  "input-race-class": "Elf Wizard",
  "input-name": "Nif Amakir",
  "input-level": "6",
  "input-size": "Medium",
  "input-alignment": "Lawful Neutral",
  "input-xp": "23,264",
  "input-height": "6'0",
  "input-weight": "136 lbs",
  "input-age": "120 years",
  "input-gender": "Male",
  "input-speed": "30 feet, 6 squares",
  "input-initiative": "3",
  "input-gold": "1,090",
  "input-hero-points": "2",
  "input-stat-str": "8",
  "input-stat-dex": "17",
  "input-stat-con": "14",
  "input-stat-int": "21",
  "input-stat-wis": "12",
  "input-stat-cha": "10",
  "input-stat-int-temp": "23",
  "input-body-slot-headband": "Headband of Vast Intelligence +2",
  "input-body-slot-neck": "Amulet of Natural Armor +1",
  "input-body-slot-ring-left-hand": "Ring of Sustenance",
  "input-body-slot-shoulders": "Cloak of Resistance +2",
  "input-hp": "42",
  "input-current-hp": "42",
  "input-ac-natural": "1",
  "input-fortitude-base": "2",
  "input-fortitude-misc": "5",
  "input-reflex-base": "2",
  "input-reflex-misc": "2",
  "input-will-base": "5",
  "input-will-misc": "2",
  "input-base-attack": "3",
  "input-concentration": "11",
  "input-skill-appraise-ranks": "4",
  "input-skill-appraise-misc": "3",
  "input-skill-knowledge-arcana-ranks": "3",
  "input-skill-knowledge-arcana-misc": "3",
  "input-skill-knowledge-dungeoneering-ranks": "2",
  "input-skill-knowledge-dungeoneering-misc": "3",
  "input-skill-knowledge-engineering-ranks": "1",
  "input-skill-knowledge-engineering-misc": "3",
  "input-skill-knowledge-geography-ranks": "1",
  "input-skill-knowledge-geography-misc": "3",
  "input-skill-knowledge-history-ranks": "1",
  "input-skill-knowledge-history-misc": "3",
  "input-skill-knowledge-local-ranks": "1",
  "input-skill-knowledge-local-misc": "3",
  "input-skill-knowledge-nature-ranks": "1",
  "input-skill-knowledge-nature-misc": "3",
  "input-skill-knowledge-nobility-ranks": "1",
  "input-skill-knowledge-nobility-misc": "3",
  "input-skill-knowledge-planes-ranks": "3",
  "input-skill-knowledge-planes-misc": "3",
  "input-skill-knowledge-religion-ranks": "3",
  "input-skill-knowledge-religion-misc": "3",
  "input-skill-linguistics-ranks": "3",
  "input-skill-linguistics-misc": "3",
  "input-skill-perception-ranks": "6",
  "input-skill-perception-misc": "4",
  "input-skill-sense-motive-ranks": "6",
  "input-skill-sense-motive-misc": "2",
  "input-skill-spellcraft-ranks": "6",
  "input-skill-spellcraft-misc": "3",
  "input-skill-use-magic-device-ranks": "6",
  "input-spells-daily-level-0": "4",
  "input-spell-dc-level-0": "16",
  "input-spells-daily-level-1": "5",
  "input-spell-dc-level-1": "17",
  "input-spells-daily-level-2": "4",
  "input-spell-dc-level-2": "18",
  "input-spells-daily-level-3": "3",
  "input-spell-dc-level-3": "19",
  "spell-saved-bleed": "{\"name\":\"Bleed\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-erase": "{\"name\":\"Erase\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-daze": "{\"name\":\"Daze\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-disrupt-undead": "{\"name\":\"Disrupt Undead\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-touch-of-fatigue": "{\"name\":\"Touch of Fatigue\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-prestidigitation": "{\"name\":\"Prestidigitation\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-light": "{\"name\":\"Light\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-ghost-sound": "{\"name\":\"Ghost Sound\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-spark": "{\"name\":\"Spark\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-acid-splash": "{\"name\":\"Acid Splash\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-mage-hand": "{\"name\":\"Mage Hand\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-flare": "{\"name\":\"Flare\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-detect-magic": "{\"name\":\"Detect Magic\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-detect-poison": "{\"name\":\"Detect Poison\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-dancing-lights": "{\"name\":\"Dancing Lights\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-mending": "{\"name\":\"Mending\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-arcane-mark": "{\"name\":\"Arcane Mark\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-message": "{\"name\":\"Message\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-ray-of-frost": "{\"name\":\"Ray of Frost\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-read-magic": "{\"name\":\"Read Magic\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-open-close": "{\"name\":\"Open Close\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-resistance": "{\"name\":\"Resistance\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-comprehend-languages": "{\"name\":\"Comprehend Languages\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-enlarge-person": "{\"name\":\"Enlarge Person\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-feather-fall": "{\"name\":\"Feather Fall\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-grease": "{\"name\":\"Grease\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-mage-armor": "{\"name\":\"Mage Armor\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-mount": "{\"name\":\"Mount\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-obscuring-mist": "{\"name\":\"Obscuring Mist\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-protection-from-chaos": "{\"name\":\"Protection from Chaos\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-protection-from-evil": "{\"name\":\"Protection from Evil\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-shield": "{\"name\":\"Shield\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-summon-monster-i": "{\"name\":\"Summon Monster I\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-unseen-servant": "{\"name\":\"Unseen Servant\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-blur": "{\"name\":\"Blur\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-create-pit": "{\"name\":\"Create Pit\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-flaming-sphere": "{\"name\":\"Flaming Sphere\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-glitterdust": "{\"name\":\"Glitterdust\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-invisibility": "{\"name\":\"Invisibility\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-levitate": "{\"name\":\"Levitate\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-mirror-image": "{\"name\":\"Mirror Image\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-resist-energy": "{\"name\":\"Resist Energy\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-stone-call": "{\"name\":\"Stone Call\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-summon-monster-ii": "{\"name\":\"Summon Monster II\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-web": "{\"name\":\"Web\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-stinking-cloud": "{\"name\":\"Stinking Cloud\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-summon-monster-iii": "{\"name\":\"Summon Monster III\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-spiked-pit": "{\"name\":\"Spiked Pit\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-aqueous-orb": "{\"name\":\"Aqueous Orb\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-fly": "{\"name\":\"Fly\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "spell-saved-sleet-storm": "{\"name\":\"Sleet Storm\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
  "textarea-feats": "Alertness, Augment Summoning, Craft Wondrous Item, Greater Spell Focus (Conjuration), Scribe Scroll, Spell Focus (Conjuration)",
  "textarea-traits": "Resilient (+1 trait bonus on Fortitude saves)\n ",
  "textarea-languages": "Celestial, Common, Draconic, Dwarven, Elven, Giant, Gnome, Goblin, Orc, Sylvan, Undercommon",
  "textarea-special-abilities": "Arcane bond (Su) Rat (Bower, +2 Fortitude save),\n Bonus feats,\n Cantrips,\n Arcane schools (Conjuration),\n Teleportation sub school,\n Opposition arcane school (Enchantment, Necromancy),\n Elven Immunities (Ex) (+2 against enchantment spells and effects),\n Elven Magic (Ex) (+2 caster level checks made to overcome SR. +2 Spellcraft check to identify properties of magic items),\n Keen Senses (Ex) (+2 Perception checks),\n Low-Light Vision (Ex) (see x2 as far as humans in low illumination),\n Headband of Intellect Skill (Use Magic Device),\n Linguistics Skill (Dwarven, Giant, Undercommon),\n Shift (Su) (Teleport 15 feet 9 times per day),\n Summoner's Charm (Su) (+2 rounds duration for Conjuration [summoning] spells),\n Weapon Familiarity (Ex) (Proficient with longbows [including composite longbows], longswords, rapiers, and shortbows [including composite shortbows], treat weapon with \"elven\" in name as a martial weapon)\n ",
  "textarea-gear": "Spell component pouch, Spellbook, Backpack, Flask of Oil x3, Pouch (belt), Sack, Candle, Flint and Steel, Tindertwig, Rations (5 days), Waterskin, Bedroll, Blanket, Bloodblock, Healer's Kik, Rope (silk), Mirror, Compass, Ink, Inkpen, Paper sheets, Case for maps/scrolls, Scroll Case, Combat trained horse",
  "textarea-magic-gear": "Pearl of Power (1st Level), Potion of CLW x1, Potion of Aid, Vile of Antitoxin, Vile of Holy Water, Scroll of Acid Pit x1, Scroll of Summon Monster III x5, Scroll of Invisibility x2, Scroll of Create Pit x1, Scroll of Web x4, Scroll of Stinking Cloud x2, Scroll of Grease x2, Scroll of Mirror Image x3, Scroll of Spiked Pit x3 Scroll of Fly x2",
  "textarea-defense-notes": "+2 against enchantment spells and effects",
  "clone-attack-count": 1,
  "input-weapon-1": "Dagger MW",
  "input-attack-1": "3",
  "input-damage-1": "1d6-1",
  "input-critical-1": "19–20/×2",
  "input-ammo-1": "-",
  "input-range-1": "-",
  "clone-consumable-count": 3,
  "input-consumable-1": "Wand of Infernal Healing",
  "input-consumable-total-1": "50",
  "input-consumable-used-1": "48",
  "input-consumable-2": "Wand of Lightning Bolt",
  "input-consumable-total-2": "50",
  "input-consumable-used-2": "38",
  "input-consumable-3": "Shift",
  "input-consumable-total-3": "9",
  "input-consumable-used-3": ""
}<commit_msg>[refactor] enclosing character<commit_after>(function() {
  var nif = {
    "input-race-class": "Elf Wizard",
    "input-name": "Nif Amakir",
    "input-level": "6",
    "input-size": "Medium",
    "input-alignment": "Lawful Neutral",
    "input-xp": "23,264",
    "input-height": "6'0",
    "input-weight": "136 lbs",
    "input-age": "120 years",
    "input-gender": "Male",
    "input-speed": "30 feet, 6 squares",
    "input-initiative": "3",
    "input-gold": "1,090",
    "input-hero-points": "2",
    "input-stat-str": "8",
    "input-stat-dex": "17",
    "input-stat-con": "14",
    "input-stat-int": "21",
    "input-stat-wis": "12",
    "input-stat-cha": "10",
    "input-stat-int-temp": "23",
    "input-body-slot-headband": "Headband of Vast Intelligence +2",
    "input-body-slot-neck": "Amulet of Natural Armor +1",
    "input-body-slot-ring-left-hand": "Ring of Sustenance",
    "input-body-slot-shoulders": "Cloak of Resistance +2",
    "input-hp": "42",
    "input-current-hp": "42",
    "input-ac-natural": "1",
    "input-fortitude-base": "2",
    "input-fortitude-misc": "5",
    "input-reflex-base": "2",
    "input-reflex-misc": "2",
    "input-will-base": "5",
    "input-will-misc": "2",
    "input-base-attack": "3",
    "input-concentration": "11",
    "input-skill-appraise-ranks": "4",
    "input-skill-appraise-misc": "3",
    "input-skill-knowledge-arcana-ranks": "3",
    "input-skill-knowledge-arcana-misc": "3",
    "input-skill-knowledge-dungeoneering-ranks": "2",
    "input-skill-knowledge-dungeoneering-misc": "3",
    "input-skill-knowledge-engineering-ranks": "1",
    "input-skill-knowledge-engineering-misc": "3",
    "input-skill-knowledge-geography-ranks": "1",
    "input-skill-knowledge-geography-misc": "3",
    "input-skill-knowledge-history-ranks": "1",
    "input-skill-knowledge-history-misc": "3",
    "input-skill-knowledge-local-ranks": "1",
    "input-skill-knowledge-local-misc": "3",
    "input-skill-knowledge-nature-ranks": "1",
    "input-skill-knowledge-nature-misc": "3",
    "input-skill-knowledge-nobility-ranks": "1",
    "input-skill-knowledge-nobility-misc": "3",
    "input-skill-knowledge-planes-ranks": "3",
    "input-skill-knowledge-planes-misc": "3",
    "input-skill-knowledge-religion-ranks": "3",
    "input-skill-knowledge-religion-misc": "3",
    "input-skill-linguistics-ranks": "3",
    "input-skill-linguistics-misc": "3",
    "input-skill-perception-ranks": "6",
    "input-skill-perception-misc": "4",
    "input-skill-sense-motive-ranks": "6",
    "input-skill-sense-motive-misc": "2",
    "input-skill-spellcraft-ranks": "6",
    "input-skill-spellcraft-misc": "3",
    "input-skill-use-magic-device-ranks": "6",
    "input-spells-daily-level-0": "4",
    "input-spell-dc-level-0": "16",
    "input-spells-daily-level-1": "5",
    "input-spell-dc-level-1": "17",
    "input-spells-daily-level-2": "4",
    "input-spell-dc-level-2": "18",
    "input-spells-daily-level-3": "3",
    "input-spell-dc-level-3": "19",
    "spell-saved-bleed": "{\"name\":\"Bleed\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-erase": "{\"name\":\"Erase\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-daze": "{\"name\":\"Daze\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-disrupt-undead": "{\"name\":\"Disrupt Undead\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-touch-of-fatigue": "{\"name\":\"Touch of Fatigue\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-prestidigitation": "{\"name\":\"Prestidigitation\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-light": "{\"name\":\"Light\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-ghost-sound": "{\"name\":\"Ghost Sound\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-spark": "{\"name\":\"Spark\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-acid-splash": "{\"name\":\"Acid Splash\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-mage-hand": "{\"name\":\"Mage Hand\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-flare": "{\"name\":\"Flare\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-detect-magic": "{\"name\":\"Detect Magic\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-detect-poison": "{\"name\":\"Detect Poison\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-dancing-lights": "{\"name\":\"Dancing Lights\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-mending": "{\"name\":\"Mending\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-arcane-mark": "{\"name\":\"Arcane Mark\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-message": "{\"name\":\"Message\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-ray-of-frost": "{\"name\":\"Ray of Frost\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-read-magic": "{\"name\":\"Read Magic\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-open-close": "{\"name\":\"Open Close\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-resistance": "{\"name\":\"Resistance\",\"level\":\"0\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-comprehend-languages": "{\"name\":\"Comprehend Languages\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-enlarge-person": "{\"name\":\"Enlarge Person\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-feather-fall": "{\"name\":\"Feather Fall\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-grease": "{\"name\":\"Grease\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-mage-armor": "{\"name\":\"Mage Armor\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-mount": "{\"name\":\"Mount\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-obscuring-mist": "{\"name\":\"Obscuring Mist\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-protection-from-chaos": "{\"name\":\"Protection from Chaos\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-protection-from-evil": "{\"name\":\"Protection from Evil\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-shield": "{\"name\":\"Shield\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-summon-monster-i": "{\"name\":\"Summon Monster I\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-unseen-servant": "{\"name\":\"Unseen Servant\",\"level\":\"1\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-blur": "{\"name\":\"Blur\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-create-pit": "{\"name\":\"Create Pit\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-flaming-sphere": "{\"name\":\"Flaming Sphere\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-glitterdust": "{\"name\":\"Glitterdust\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-invisibility": "{\"name\":\"Invisibility\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-levitate": "{\"name\":\"Levitate\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-mirror-image": "{\"name\":\"Mirror Image\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-resist-energy": "{\"name\":\"Resist Energy\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-stone-call": "{\"name\":\"Stone Call\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-summon-monster-ii": "{\"name\":\"Summon Monster II\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-web": "{\"name\":\"Web\",\"level\":\"2\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-stinking-cloud": "{\"name\":\"Stinking Cloud\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-summon-monster-iii": "{\"name\":\"Summon Monster III\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-spiked-pit": "{\"name\":\"Spiked Pit\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-aqueous-orb": "{\"name\":\"Aqueous Orb\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-fly": "{\"name\":\"Fly\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "spell-saved-sleet-storm": "{\"name\":\"Sleet Storm\",\"level\":\"3\",\"prepared\":0,\"active\":false,\"cast\":0}",
    "textarea-feats": "Alertness, Augment Summoning, Craft Wondrous Item, Greater Spell Focus (Conjuration), Scribe Scroll, Spell Focus (Conjuration)",
    "textarea-traits": "Resilient (+1 trait bonus on Fortitude saves)\n ",
    "textarea-languages": "Celestial, Common, Draconic, Dwarven, Elven, Giant, Gnome, Goblin, Orc, Sylvan, Undercommon",
    "textarea-special-abilities": "Arcane bond (Su) Rat (Bower, +2 Fortitude save),\n Bonus feats,\n Cantrips,\n Arcane schools (Conjuration),\n Teleportation sub school,\n Opposition arcane school (Enchantment, Necromancy),\n Elven Immunities (Ex) (+2 against enchantment spells and effects),\n Elven Magic (Ex) (+2 caster level checks made to overcome SR. +2 Spellcraft check to identify properties of magic items),\n Keen Senses (Ex) (+2 Perception checks),\n Low-Light Vision (Ex) (see x2 as far as humans in low illumination),\n Headband of Intellect Skill (Use Magic Device),\n Linguistics Skill (Dwarven, Giant, Undercommon),\n Shift (Su) (Teleport 15 feet 9 times per day),\n Summoner's Charm (Su) (+2 rounds duration for Conjuration [summoning] spells),\n Weapon Familiarity (Ex) (Proficient with longbows [including composite longbows], longswords, rapiers, and shortbows [including composite shortbows], treat weapon with \"elven\" in name as a martial weapon)\n ",
    "textarea-gear": "Spell component pouch, Spellbook, Backpack, Flask of Oil x3, Pouch (belt), Sack, Candle, Flint and Steel, Tindertwig, Rations (5 days), Waterskin, Bedroll, Blanket, Bloodblock, Healer's Kik, Rope (silk), Mirror, Compass, Ink, Inkpen, Paper sheets, Case for maps/scrolls, Scroll Case, Combat trained horse",
    "textarea-magic-gear": "Pearl of Power (1st Level), Potion of CLW x1, Potion of Aid, Vile of Antitoxin, Vile of Holy Water, Scroll of Acid Pit x1, Scroll of Summon Monster III x5, Scroll of Invisibility x2, Scroll of Create Pit x1, Scroll of Web x4, Scroll of Stinking Cloud x2, Scroll of Grease x2, Scroll of Mirror Image x3, Scroll of Spiked Pit x3 Scroll of Fly x2",
    "textarea-defense-notes": "+2 against enchantment spells and effects",
    "clone-attack-count": 1,
    "input-weapon-1": "Dagger MW",
    "input-attack-1": "3",
    "input-damage-1": "1d6-1",
    "input-critical-1": "19–20/×2",
    "input-ammo-1": "-",
    "input-range-1": "-",
    "clone-consumable-count": 3,
    "input-consumable-1": "Wand of Infernal Healing",
    "input-consumable-total-1": "50",
    "input-consumable-used-1": "48",
    "input-consumable-2": "Wand of Lightning Bolt",
    "input-consumable-total-2": "50",
    "input-consumable-used-2": "38",
    "input-consumable-3": "Shift",
    "input-consumable-total-3": "9",
    "input-consumable-used-3": ""
  }
  window.nif = nif;
})();<|endoftext|>


<commit_before>var ReqManager = (function () {
	"use strict";

	// @see http://vk.com/dev/api_requests
	var AVAILABLE_LANGUAGES = ["ru", "ua", "be", "en", "es", "fi", "de", "it"];
	var REQUESTS_TIMEOUT_MS = 350;

	var currentLocale = chrome.i18n.getMessage("@@ui_locale").split("_")[0];
	var requestsLanguage = (AVAILABLE_LANGUAGES.indexOf(currentLocale) === -1) ? "ru" : currentLocale;
	var requestsQueue = [];
	var queuePromise = Promise.resolve();

	var isTokenExpired;
	var callbacksOnSuccess = {};
	var callbacksOnFail = {};
	var timeoutIds = {};
	var xhrs = {};
	var boundCallbacks = null;
	var statSendFn = null;

	function notifyTokenStatus() {
		return _.debounce(function () {
			chrome.runtime.sendMessage({
				action: "tokenStatus",
				expired: isTokenExpired
			});
		}, 1000);
	}

	/**
	 * @param {Object} params объект с ключами {String} url, {String} method, {Integer} timeout, {FormData} data
	 * @param {Function} fnSuccess
	 * @param {Function} fnFail принимает {Integer} код ошибки 1 (нет соединения), 2 (not json), 3 (response.error !== undefined, not auth problem), 4 (timeout), 5 (abort), 6 (oauth revoke)
	 */
	function runRequest(params, fnSuccess, fnFail) {
		if (params.url.indexOf("a_check") === -1) {
			var requestsLog = StorageManager.get("requests", {constructor: Object, strict: true, create: true});
			requestsLog[params.url] = requestsLog[params.url] || 0;
			requestsLog[params.url] += 1;
			StorageManager.set("requests", requestsLog);
		}

		var xhrId = params.url.replace(/[^a-z0-9]/g, "") + "_" + Math.random(),
			url = params.url,
			timeout = 25,
			formData;

		// убираем timeout из параметров
		if (params.timeout !== undefined) {
			timeout = params.timeout;
			delete params.timeout;
		}

		// устанавливаем обработчики
		callbacksOnSuccess[xhrId] = fnSuccess || null;
		callbacksOnFail[xhrId] = fnFail || null;

		// создаем XHR и добавляем ему уникальный идентификатор
		// responseType json : http://code.google.com/p/chromium/issues/detail?id=119256
		// FIXME: issue is fixed in M31, check out error behaviour and switch to responseType json
		var xhr = new XMLHttpRequest();
		xhr.urid = xhrId;
		xhrs[xhrId] = xhr;

		// привязываем обработчики намертво
		if (boundCallbacks === null) {
			boundCallbacks = [onLoad.bind(this), onError.bind(this)];
		}

		xhr.addEventListener("load", boundCallbacks[0], false);
		xhr.addEventListener("error", boundCallbacks[1], false);
		xhr.addEventListener("abort", boundCallbacks[1], false);

		queuePromise = queuePromise.then(function () {
			xhr.open(params.method, url, true);

			if (params.data) {
				formData = new FormData();
				for (var prop in params.data) {
					formData.append(prop, params.data[prop]);
				}

				xhr.send(formData);
			} else {
				xhr.send();
			}

			// таймаут запроса
			// http://code.google.com/p/chromium/issues/detail?id=119500
			timeoutIds[xhrId] = window.setTimeout(boundCallbacks[1], timeout * 1000, xhrId);

			return new Promise(function (resolve) {
				setTimeout(resolve, REQUESTS_TIMEOUT_MS);
			});
		});

		return xhrId;
	}

	function onError(e) {
		var errorCode,
			xhrId;

		if (typeof e === "object") {
			xhrId = e.target.urid;
			errorCode = (e.type === "abort") ? this.ABORT : this.NO_INTERNET;
		} else {
			xhrId = e;
			errorCode = this.TIMEOUT;

			// сбрасываем подвисший запрос, чтобы он больше не висел в памяти
			xhrs[xhrId].removeEventListener("abort", boundCallbacks[1], false);
			xhrs[xhrId].abort();
		}

		if (errorCode === this.NO_INTERNET || errorCode === this.TIMEOUT) {
			// уведомление о работе сети
			chrome.runtime.sendMessage({"action" : "networkDown"});
		}

		if (typeof callbacksOnFail[xhrId] === "function") {
			callbacksOnFail[xhrId](errorCode);
		}

		finalizeRequest(xhrId);
	}

	function onLoad(e) {
		var res,
			xhr = e.target,
			xhrId = e.target.urid,
			errDataParams = {},
			errMethod = "";

		try {
			res = JSON.parse(xhr.responseText.replace(/[\x00-\x1f]/, ""));
		} catch (e) {
			statSendFn("Custom-Errors", "Exception error", e.message);
			LogManager.error("[" + xhrId + "] Not a JSON response: " + xhr.responseText + "");

			if (typeof callbacksOnFail[xhrId] === "function") {
				callbacksOnFail[xhrId](this.NOT_JSON);
			}

			finalizeRequest(xhrId);
			return;
		}

		if (res.error !== undefined) {
			// вычленяем данные запроса
			res.error.request_params.forEach(function(paramData) {
				if (paramData.key === "access_token" || paramData.key === "oauth") {
					return;
				}

				if (paramData.key === "method") {
					errMethod = paramData.value;
				}

				errDataParams[paramData.key] = paramData.value;
			});

			// уведомляем в GA
			statSendFn("Custom-Errors", "Request error", {
				"method" : errMethod,
				"code" : res.error.error_code
			});

			// @see http://vk.com/dev/errors
			switch (res.error.error_code) {
				// case 6:
					// re-add request to queue

				case 5 :
					LogManager.error("Access denied for request with params: " + JSON.stringify(errDataParams));

					isTokenExpired = true;
					notifyTokenStatus();

					if (typeof callbacksOnFail[xhrId] === "function") {
						callbacksOnFail[xhrId](this.ACCESS_DENIED);
					}

					break;

				case 14 :
					LogManager.warn("XHR response has error code 14 (captcha). Params: " + JSON.stringify(errDataParams));

					isTokenExpired = false;
					notifyTokenStatus();

					if (typeof callbacksOnFail[xhrId] === "function") {
						callbacksOnFail[xhrId](this.CAPTCHA, {
							"sid" : res.error.captcha_sid,
							"img" : res.error.captcha_img
						});
					}

					break;

				default :
					LogManager.warn("XHR response has error field with code " + res.error.error_code + ". Params: " + JSON.stringify(errDataParams));

					isTokenExpired = false;
					notifyTokenStatus();

					if (typeof callbacksOnFail[xhrId] === "function") {
						callbacksOnFail[xhrId](this.RESPONSE_ERROR, {
							"code" : res.error.error_code,
							"msg" : res.error.error_msg
						});
					}

					break;
			}
		} else {
			isTokenExpired = false;
			notifyTokenStatus();

			if (typeof callbacksOnSuccess[xhrId] === "function") {
				callbacksOnSuccess[xhrId](res);
			}
		}

		finalizeRequest(xhrId);
	}

	function finalizeRequest(xhrId) {
		delete xhrs[xhrId];
		delete callbacksOnSuccess[xhrId];
		delete callbacksOnFail[xhrId];

		clearTimeout(timeoutIds[xhrId]);
		delete timeoutIds[xhrId];
	}

	return {
		/**
		 * @param {Function} statSend функция для отправки статистики
		 */
		init: function(statSend) {
			statSendFn = statSend;
		},

		apiMethod: function(method, params, fnSuccess, fnFail) {
			var performParams = {
				method: "POST",
				url: "https://api.vk.com/method/" + method
			};

			if (typeof params === "function") {
				fnFail = fnSuccess;
				fnSuccess = params;
				params = {};
			}

			if (params.access_token === undefined) {
				params.access_token = AccountsManager.current.token;
			} else if (params.access_token === null) {
				delete params.access_token;
			}

			performParams.data = params;
			performParams.data.lang = requestsLanguage;

			return runRequest.call(this, performParams, fnSuccess, fnFail);
		},

		forceUrlGet: function(url, params, fnSuccess, fnFail) {
			var getParams = [];
			var performParams = {
				method: "GET",
				url: url
			};

			if (typeof params === "function") {
				fnFail = fnSuccess;
				fnSuccess = params;
				params = {};
			}

			if (params.timeout !== undefined) {
				performParams.timeout = params.timeout;
				delete params.timeout;
			}

			for (var prop in params)
				getParams.push(encodeURIComponent(prop) + "=" + encodeURIComponent(params[prop]));

			if (getParams.length)
				performParams.url += "?" + getParams.join("&");

			return runRequest.call(this, performParams, fnSuccess, fnFail);
		},

		abort: function(xhrId) {
			if (xhrs[xhrId] === undefined) {
				throw new ReferenceError("No such request: " + xhrId);
			}

			xhrs[xhrId].abort();
			finalizeRequest(xhrId);
		},

		abortAll: function () {
			for (var xhrId in xhrs) {
				xhrs[xhrId].abort();
				finalizeRequest(xhrId);
			}
		},

		NO_INTERNET: 1,
		NOT_JSON: 2,
		RESPONSE_ERROR: 3,
		TIMEOUT: 4,
		ABORT: 5,
		ACCESS_DENIED: 6,
		CAPTCHA: 7
	};
})();
<commit_msg>Support already aborted requests<commit_after>var ReqManager = (function () {
	"use strict";

	// @see http://vk.com/dev/api_requests
	var AVAILABLE_LANGUAGES = ["ru", "ua", "be", "en", "es", "fi", "de", "it"];
	var REQUESTS_TIMEOUT_MS = 350;

	var currentLocale = chrome.i18n.getMessage("@@ui_locale").split("_")[0];
	var requestsLanguage = (AVAILABLE_LANGUAGES.indexOf(currentLocale) === -1) ? "ru" : currentLocale;
	var requestsQueue = [];
	var queuePromise = Promise.resolve();

	var isTokenExpired;
	var callbacksOnSuccess = {};
	var callbacksOnFail = {};
	var timeoutIds = {};
	var xhrs = {};
	var boundCallbacks = null;
	var statSendFn = null;

	function notifyTokenStatus() {
		return _.debounce(function () {
			chrome.runtime.sendMessage({
				action: "tokenStatus",
				expired: isTokenExpired
			});
		}, 1000);
	}

	/**
	 * @param {Object} params объект с ключами {String} url, {String} method, {Integer} timeout, {FormData} data
	 * @param {Function} fnSuccess
	 * @param {Function} fnFail принимает {Integer} код ошибки 1 (нет соединения), 2 (not json), 3 (response.error !== undefined, not auth problem), 4 (timeout), 5 (abort), 6 (oauth revoke)
	 */
	function runRequest(params, fnSuccess, fnFail) {
		if (params.url.indexOf("a_check") === -1) {
			var requestsLog = StorageManager.get("requests", {constructor: Object, strict: true, create: true});
			requestsLog[params.url] = requestsLog[params.url] || 0;
			requestsLog[params.url] += 1;
			StorageManager.set("requests", requestsLog);
		}

		var xhrId = params.url.replace(/[^a-z0-9]/g, "") + "_" + Math.random(),
			url = params.url,
			timeout = 25,
			formData;

		// убираем timeout из параметров
		if (params.timeout !== undefined) {
			timeout = params.timeout;
			delete params.timeout;
		}

		// устанавливаем обработчики
		callbacksOnSuccess[xhrId] = fnSuccess || null;
		callbacksOnFail[xhrId] = fnFail || null;

		// создаем XHR и добавляем ему уникальный идентификатор
		// responseType json : http://code.google.com/p/chromium/issues/detail?id=119256
		// FIXME: issue is fixed in M31, check out error behaviour and switch to responseType json
		var xhr = new XMLHttpRequest();
		xhr.urid = xhrId;
		xhrs[xhrId] = xhr;

		// привязываем обработчики намертво
		if (boundCallbacks === null) {
			boundCallbacks = [onLoad.bind(this), onError.bind(this)];
		}

		xhr.addEventListener("load", boundCallbacks[0], false);
		xhr.addEventListener("error", boundCallbacks[1], false);
		xhr.addEventListener("abort", boundCallbacks[1], false);

		queuePromise = queuePromise.then(function () {
			// XHR has already been aborted
			if (!xhrs[xhrId]) {
				return;
			}

			xhr.open(params.method, url, true);

			if (params.data) {
				formData = new FormData();
				for (var prop in params.data) {
					formData.append(prop, params.data[prop]);
				}

				xhr.send(formData);
			} else {
				xhr.send();
			}

			// таймаут запроса
			// http://code.google.com/p/chromium/issues/detail?id=119500
			timeoutIds[xhrId] = window.setTimeout(boundCallbacks[1], timeout * 1000, xhrId);

			return new Promise(function (resolve) {
				setTimeout(resolve, REQUESTS_TIMEOUT_MS);
			});
		});

		return xhrId;
	}

	function onError(e) {
		var errorCode,
			xhrId;

		if (typeof e === "object") {
			xhrId = e.target.urid;
			errorCode = (e.type === "abort") ? this.ABORT : this.NO_INTERNET;
		} else {
			xhrId = e;
			errorCode = this.TIMEOUT;

			// сбрасываем подвисший запрос, чтобы он больше не висел в памяти
			xhrs[xhrId].removeEventListener("abort", boundCallbacks[1], false);
			xhrs[xhrId].abort();
		}

		if (errorCode === this.NO_INTERNET || errorCode === this.TIMEOUT) {
			// уведомление о работе сети
			chrome.runtime.sendMessage({"action" : "networkDown"});
		}

		if (typeof callbacksOnFail[xhrId] === "function") {
			callbacksOnFail[xhrId](errorCode);
		}

		finalizeRequest(xhrId);
	}

	function onLoad(e) {
		var res,
			xhr = e.target,
			xhrId = e.target.urid,
			errDataParams = {},
			errMethod = "";

		try {
			res = JSON.parse(xhr.responseText.replace(/[\x00-\x1f]/, ""));
		} catch (e) {
			statSendFn("Custom-Errors", "Exception error", e.message);
			LogManager.error("[" + xhrId + "] Not a JSON response: " + xhr.responseText + "");

			if (typeof callbacksOnFail[xhrId] === "function") {
				callbacksOnFail[xhrId](this.NOT_JSON);
			}

			finalizeRequest(xhrId);
			return;
		}

		if (res.error !== undefined) {
			// вычленяем данные запроса
			res.error.request_params.forEach(function(paramData) {
				if (paramData.key === "access_token" || paramData.key === "oauth") {
					return;
				}

				if (paramData.key === "method") {
					errMethod = paramData.value;
				}

				errDataParams[paramData.key] = paramData.value;
			});

			// уведомляем в GA
			statSendFn("Custom-Errors", "Request error", {
				"method" : errMethod,
				"code" : res.error.error_code
			});

			// @see http://vk.com/dev/errors
			switch (res.error.error_code) {
				// case 6:
					// re-add request to queue

				case 5 :
					LogManager.error("Access denied for request with params: " + JSON.stringify(errDataParams));

					isTokenExpired = true;
					notifyTokenStatus();

					if (typeof callbacksOnFail[xhrId] === "function") {
						callbacksOnFail[xhrId](this.ACCESS_DENIED);
					}

					break;

				case 14 :
					LogManager.warn("XHR response has error code 14 (captcha). Params: " + JSON.stringify(errDataParams));

					isTokenExpired = false;
					notifyTokenStatus();

					if (typeof callbacksOnFail[xhrId] === "function") {
						callbacksOnFail[xhrId](this.CAPTCHA, {
							"sid" : res.error.captcha_sid,
							"img" : res.error.captcha_img
						});
					}

					break;

				default :
					LogManager.warn("XHR response has error field with code " + res.error.error_code + ". Params: " + JSON.stringify(errDataParams));

					isTokenExpired = false;
					notifyTokenStatus();

					if (typeof callbacksOnFail[xhrId] === "function") {
						callbacksOnFail[xhrId](this.RESPONSE_ERROR, {
							"code" : res.error.error_code,
							"msg" : res.error.error_msg
						});
					}

					break;
			}
		} else {
			isTokenExpired = false;
			notifyTokenStatus();

			if (typeof callbacksOnSuccess[xhrId] === "function") {
				callbacksOnSuccess[xhrId](res);
			}
		}

		finalizeRequest(xhrId);
	}

	function finalizeRequest(xhrId) {
		delete xhrs[xhrId];
		delete callbacksOnSuccess[xhrId];
		delete callbacksOnFail[xhrId];

		clearTimeout(timeoutIds[xhrId]);
		delete timeoutIds[xhrId];
	}

	return {
		/**
		 * @param {Function} statSend функция для отправки статистики
		 */
		init: function(statSend) {
			statSendFn = statSend;
		},

		apiMethod: function(method, params, fnSuccess, fnFail) {
			var performParams = {
				method: "POST",
				url: "https://api.vk.com/method/" + method
			};

			if (typeof params === "function") {
				fnFail = fnSuccess;
				fnSuccess = params;
				params = {};
			}

			if (params.access_token === undefined) {
				params.access_token = AccountsManager.current.token;
			} else if (params.access_token === null) {
				delete params.access_token;
			}

			performParams.data = params;
			performParams.data.lang = requestsLanguage;

			return runRequest.call(this, performParams, fnSuccess, fnFail);
		},

		forceUrlGet: function(url, params, fnSuccess, fnFail) {
			var getParams = [];
			var performParams = {
				method: "GET",
				url: url
			};

			if (typeof params === "function") {
				fnFail = fnSuccess;
				fnSuccess = params;
				params = {};
			}

			if (params.timeout !== undefined) {
				performParams.timeout = params.timeout;
				delete params.timeout;
			}

			for (var prop in params)
				getParams.push(encodeURIComponent(prop) + "=" + encodeURIComponent(params[prop]));

			if (getParams.length)
				performParams.url += "?" + getParams.join("&");

			return runRequest.call(this, performParams, fnSuccess, fnFail);
		},

		abort: function(xhrId) {
			if (xhrs[xhrId] === undefined) {
				throw new ReferenceError("No such request: " + xhrId);
			}

			xhrs[xhrId].abort();
			finalizeRequest(xhrId);
		},

		abortAll: function () {
			for (var xhrId in xhrs) {
				xhrs[xhrId].abort();
				finalizeRequest(xhrId);
			}
		},

		NO_INTERNET: 1,
		NOT_JSON: 2,
		RESPONSE_ERROR: 3,
		TIMEOUT: 4,
		ABORT: 5,
		ACCESS_DENIED: 6,
		CAPTCHA: 7
	};
})();
<|endoftext|>


<commit_before>import ColorPicker from './pickers/ColorPicker';
import Vec3Picker from './pickers/Vec3Picker';
import Vec2Picker from './pickers/Vec2Picker';
import FloatPicker from './pickers/FloatPicker';

import Color from './pickers/types/Color';

import Modal from './modals/Modal';

// Return all pattern matches with captured groups
RegExp.prototype.execAll = function(string) {
    let match = null;
    let matches = [];
    while (match = this.exec(string)) {
        let matchArray = [];
        for (let i in match) {
            if (parseInt(i) == i) {
                matchArray.push(match[i]);
            }
        }
        matchArray.index = match.index;
        matches.push(matchArray);
    }
    return matches;
};

export default class Helpers {
    constructor (main) {
        this.main = main;
        this.main.debugging = false;

        let style = window.getComputedStyle(main.editor.getWrapperElement(), null);
        let bgColor = new Color(style.background !== '' ? style.background : style.backgroundColor);
        let fgColor = new Color(style.color);

        this.properties = {
            bgColor: bgColor.getString('rgb'),
            fnColor: fgColor.getString('rgb'),
            dimColor: 'rgb(127, 127, 127)',
            selColor: 'rgb(40, 168, 107)',
            linkButton: true
        };

        // EVENTS
        let wrapper = this.main.editor.getWrapperElement();
        wrapper.addEventListener('contextmenu', (event) => {
            let cursor = this.main.editor.getCursor(true);
            let token = this.main.editor.getTokenAt(cursor);
            if (token.type === 'variable') {
                this.main.visualDebugger.debug(token.string, cursor.line);
            }
            else {
                this.main.update();
            }
        });

        wrapper.addEventListener('mouseup', (event) => {
            // bail out if we were doing a selection and not a click
            if (this.main.editor.somethingSelected()) {
                return;
            }

            let cursor = this.main.editor.getCursor(true);

            // see if there is a match on the cursor click
            let match = this.getMatch(cursor);
            let token = this.main.editor.getTokenAt(cursor);
            if (match) {
                this.main.visualDebugger.clean(event);
                this.main.update();

                // Toggles the trackpad to be off if it's already present.
                if (this.activeModal && this.activeModal.isVisible) {
                    this.activeModal.removeModal();
                    return;
                }

                if (match.type === 'color') {
                    this.activeModal = new ColorPicker(match.string, this.properties);
                    this.activeModal.showAt(this.main.editor);
                    this.activeModal.on('changed', (color) => {
                        let newColor = color.getString('vec');
                        let start = { line: cursor.line, ch: match.start };
                        let end = { line: cursor.line, ch: match.end };
                        match.end = match.start + newColor.length;
                        this.main.editor.replaceRange(newColor, start, end);
                    });

                    this.activeModal.on('linkButton', (color) => {
                        this.activeModal = new Vec3Picker(color.getString('vec'), this.properties);
                        this.activeModal.showAt(this.main.editor);
                        this.activeModal.on('changed', (dir) => {
                            let newDir = dir.getString('vec3');
                            let start = { line: cursor.line, ch: match.start };
                            let end = { line: cursor.line, ch: match.end };
                            match.end = match.start + newDir.length;
                            this.main.editor.replaceRange(newDir, start, end);
                        });
                    });
                }
                if (match.type === 'vec3') {
                    this.activeModal = new Vec3Picker(match.string, this.properties);
                    this.activeModal.showAt(this.main.editor);
                    this.activeModal.on('changed', (dir) => {
                        let newDir = dir.getString('vec3');
                        let start = { line: cursor.line, ch: match.start };
                        let end = { line: cursor.line, ch: match.end };
                        match.end = match.start + newDir.length;
                        this.main.editor.replaceRange(newDir, start, end);
                    });
                }
                else if (match.type === 'vec2') {
                    this.activeModal = new Vec2Picker(match.string, this.properties);
                    this.activeModal.showAt(this.main.editor);
                    this.activeModal.on('changed', (pos) => {
                        let newpos = pos.getString();
                        let start = { line: cursor.line, ch: match.start };
                        let end = { line: cursor.line, ch: match.end };
                        match.end = match.start + newpos.length;
                        this.main.editor.replaceRange(newpos, start, end);
                    });
                }
                else if (match.type === 'number') {
                    this.activeModal = new FloatPicker(match.string, this.properties);
                    this.activeModal.showAt(this.main.editor);
                    this.activeModal.on('changed', (number) => {
                        let newNumber = number.getString();
                        let start = { line: cursor.line, ch: match.start };
                        let end = { line: cursor.line, ch: match.end };
                        match.end = match.start + newNumber.length;
                        this.main.editor.replaceRange(newNumber, start, end);
                    });
                }
            }
            else if (this.main.options.tooltips && (token.type === 'builtin' || token.type === 'variable-3')) {
                this.main.visualDebugger.clean(event);
                let html = '
Learn more about: ' + token.string + '
';
                this.activeModal = new Modal('ge_tooltip', { innerHTML: html });
                this.activeModal.showAt(this.main.editor);
            }
            else if (token.type === 'variable') {
                if (this.main.visualDebugger) {
                    this.main.visualDebugger.clean(event);
                    this.main.visualDebugger.iluminate(token.string);
                }
            }
        });
    }

    getMatch (cursor) {
        let types = ['color', 'vec3' ,'vec2', 'number'];
        let rta;
        for (let i in types) {
            rta = this.getTypeMatch(cursor, types[i]);
            if (rta) {
                return rta;
            }
        }
        return;
    }

    getTypeMatch (cursor, type) {
        if (!type) {
            return;
        }
        let re;
        switch(type.toLowerCase()) {
            case 'color':
                re = /vec[3|4]\([\d|.|,\s]*\)/g;
                break;
            case 'vec3':
                re = /vec3\([-|\d|.|,\s]*\)/g;
                break;
            case 'vec2':
                re = /vec2\([-|\d|.|,\s]*\)/g;
                break;
            case 'number':
                re = /[-]?\d+\.\d+|\d+\.|\.\d+/g;
                break;
            default:
                console.error('invalid match selection');
                return;
        }
        let line = this.main.editor.getLine(cursor.line);
        let matches = re.execAll(line);

        if (matches) {
            for (let i = 0; i < matches.length; i++) {
                let val = matches[i][0];
                let len = val.length;
                let start = matches[i].index;
                let end = matches[i].index + len;
                if (cursor.ch >= start && cursor.ch <= end) {
                    return {
                        type: type,
                        start: start,
                        end: end,
                        string: val
                    };
                }
            }
        }
        return;
    }
}
<commit_msg>reduce the number of the history registered (it will be debounced)<commit_after>import ColorPicker from './pickers/ColorPicker';
import Vec3Picker from './pickers/Vec3Picker';
import Vec2Picker from './pickers/Vec2Picker';
import FloatPicker from './pickers/FloatPicker';

import Color from './pickers/types/Color';

import Modal from './modals/Modal';

// Return all pattern matches with captured groups
RegExp.prototype.execAll = function(string) {
    let match = null;
    let matches = [];
    while (match = this.exec(string)) {
        let matchArray = [];
        for (let i in match) {
            if (parseInt(i) == i) {
                matchArray.push(match[i]);
            }
        }
        matchArray.index = match.index;
        matches.push(matchArray);
    }
    return matches;
};

export default class Helpers {
    constructor (main) {
        this.main = main;
        this.main.debugging = false;

        let style = window.getComputedStyle(main.editor.getWrapperElement(), null);
        let bgColor = new Color(style.background !== '' ? style.background : style.backgroundColor);
        let fgColor = new Color(style.color);

        this.properties = {
            bgColor: bgColor.getString('rgb'),
            fnColor: fgColor.getString('rgb'),
            dimColor: 'rgb(127, 127, 127)',
            selColor: 'rgb(40, 168, 107)',
            linkButton: true
        };

        // EVENTS
        let wrapper = this.main.editor.getWrapperElement();
        wrapper.addEventListener('contextmenu', (event) => {
            let cursor = this.main.editor.getCursor(true);
            let token = this.main.editor.getTokenAt(cursor);
            if (token.type === 'variable') {
                this.main.visualDebugger.debug(token.string, cursor.line);
            }
            else {
                this.main.update();
            }
        });

        wrapper.addEventListener('mouseup', (event) => {
            // bail out if we were doing a selection and not a click
            if (this.main.editor.somethingSelected()) {
                return;
            }

            let cursor = this.main.editor.getCursor(true);

            // see if there is a match on the cursor click
            let match = this.getMatch(cursor);
            let token = this.main.editor.getTokenAt(cursor);
            if (match) {
                this.main.visualDebugger.clean(event);
                this.main.update();

                // Toggles the trackpad to be off if it's already present.
                if (this.activeModal && this.activeModal.isVisible) {
                    this.activeModal.removeModal();
                    return;
                }

                if (match.type === 'color') {
                    this.activeModal = new ColorPicker(match.string, this.properties);
                    this.activeModal.showAt(this.main.editor);
                    this.activeModal.on('changed', (color) => {
                        let newColor = color.getString('vec');
                        let start = { line: cursor.line, ch: match.start };
                        let end = { line: cursor.line, ch: match.end };
                        match.end = match.start + newColor.length;
                        this.main.editor.replaceRange(newColor, start, end, `+${match.type}`);
                    });

                    this.activeModal.on('linkButton', (color) => {
                        this.activeModal = new Vec3Picker(color.getString('vec'), this.properties);
                        this.activeModal.showAt(this.main.editor);
                        this.activeModal.on('changed', (dir) => {
                            let newDir = dir.getString('vec3');
                            let start = { line: cursor.line, ch: match.start };
                            let end = { line: cursor.line, ch: match.end };
                            match.end = match.start + newDir.length;
                            this.main.editor.replaceRange(newDir, start, end, `+${match.type}`);
                        });
                    });
                }
                if (match.type === 'vec3') {
                    this.activeModal = new Vec3Picker(match.string, this.properties);
                    this.activeModal.showAt(this.main.editor);
                    this.activeModal.on('changed', (dir) => {
                        let newDir = dir.getString('vec3');
                        let start = { line: cursor.line, ch: match.start };
                        let end = { line: cursor.line, ch: match.end };
                        match.end = match.start + newDir.length;
                        this.main.editor.replaceRange(newDir, start, end,
                        `+${match.type}`);
                    });
                }
                else if (match.type === 'vec2') {
                    this.activeModal = new Vec2Picker(match.string, this.properties);
                    this.activeModal.showAt(this.main.editor);
                    this.activeModal.on('changed', (pos) => {
                        let newpos = pos.getString();
                        let start = { line: cursor.line, ch: match.start };
                        let end = { line: cursor.line, ch: match.end };
                        match.end = match.start + newpos.length;
                        this.main.editor.replaceRange(newpos, start, end, `+${match.type}`);
                    });
                }
                else if (match.type === 'number') {
                    this.activeModal = new FloatPicker(match.string, this.properties);
                    this.activeModal.showAt(this.main.editor);
                    this.activeModal.on('changed', (number) => {
                        let newNumber = number.getString();
                        let start = { line: cursor.line, ch: match.start };
                        let end = { line: cursor.line, ch: match.end };
                        match.end = match.start + newNumber.length;
                        this.main.editor.replaceRange(newNumber, start, end, `+${match.type}`);
                    });
                }
            }
            else if (this.main.options.tooltips && (token.type === 'builtin' || token.type === 'variable-3')) {
                this.main.visualDebugger.clean(event);
                let html = '
Learn more about: ' + token.string + '
';
                this.activeModal = new Modal('ge_tooltip', { innerHTML: html });
                this.activeModal.showAt(this.main.editor);
            }
            else if (token.type === 'variable') {
                if (this.main.visualDebugger) {
                    this.main.visualDebugger.clean(event);
                    this.main.visualDebugger.iluminate(token.string);
                }
            }
        });
    }

    getMatch (cursor) {
        let types = ['color', 'vec3' ,'vec2', 'number'];
        let rta;
        for (let i in types) {
            rta = this.getTypeMatch(cursor, types[i]);
            if (rta) {
                return rta;
            }
        }
        return;
    }

    getTypeMatch (cursor, type) {
        if (!type) {
            return;
        }
        let re;
        switch(type.toLowerCase()) {
            case 'color':
                re = /vec[3|4]\([\d|.|,\s]*\)/g;
                break;
            case 'vec3':
                re = /vec3\([-|\d|.|,\s]*\)/g;
                break;
            case 'vec2':
                re = /vec2\([-|\d|.|,\s]*\)/g;
                break;
            case 'number':
                re = /[-]?\d+\.\d+|\d+\.|\.\d+/g;
                break;
            default:
                console.error('invalid match selection');
                return;
        }
        let line = this.main.editor.getLine(cursor.line);
        let matches = re.execAll(line);

        if (matches) {
            for (let i = 0; i < matches.length; i++) {
                let val = matches[i][0];
                let len = val.length;
                let start = matches[i].index;
                let end = matches[i].index + len;
                if (cursor.ch >= start && cursor.ch <= end) {
                    return {
                        type: type,
                        start: start,
                        end: end,
                        string: val
                    };
                }
            }
        }
        return;
    }
}
<|endoftext|>


<commit_before>import * as ethUtil from 'ethereumjs-util'
import scrypt from 'scryptsy'
import crypto from 'crypto'
import jdenticon from 'jdenticon'

function decipherBuffer(decipher, data) {
  return Buffer.concat([decipher.update(data), decipher.final()])
}

export function addressFromKey(keystring) {
  try {
    var keyObj = JSON.parse(keystring)
    var address = keyObj.address
    if (address == undefined || address == "") {
      throw new Error("Invalid keystore format")
    }
    return "0x" + address
  } catch (e) {
    throw new Error("Invalid keystore format")
  }
}

export function unlock(input, password, nonStrict) {
    var json = (typeof input === 'object') ? input : JSON.parse(nonStrict ? input.toLowerCase() : input)
    if (json.version !== 3) {
        throw new Error('Not a V3 wallet')
    }
    var derivedKey
    var kdfparams
    if (json.crypto.kdf === 'scrypt') {
        kdfparams = json.crypto.kdfparams
        derivedKey = scrypt(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen)
    } else if (json.crypto.kdf === 'pbkdf2') {
        kdfparams = json.crypto.kdfparams
        if (kdfparams.prf !== 'hmac-sha256') {
            throw new Error('Unsupported parameters to PBKDF2')
        }
        derivedKey = crypto.pbkdf2Sync(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.c, kdfparams.dklen, 'sha256')
    } else {
        throw new Error('Unsupported key derivation scheme')
    }
    var ciphertext = new Buffer(json.crypto.ciphertext, 'hex')
    var mac = ethUtil.sha3(Buffer.concat([derivedKey.slice(16, 32), ciphertext]))
    if (mac.toString('hex') !== json.crypto.mac) {
        throw new Error('Key derivation failed - possibly wrong passphrase')
    }
    var decipher = crypto.createDecipheriv(json.crypto.cipher, derivedKey.slice(0, 16), new Buffer(json.crypto.cipherparams.iv, 'hex'))
    var seed = decipherBuffer(decipher, ciphertext, 'hex')
    while (seed.length < 32) {
        var nullBuff = new Buffer([0x00]);
        seed = Buffer.concat([nullBuff, seed]);
    }
    return seed
}

export function getRandomAvatar(addressString) {
  let svg = jdenticon.toSvg(addressString, 45),
  url = 'data:image/svg+xml;base64,' + btoa(svg);
  return url
}<commit_msg>add get address from private key<commit_after>import * as ethUtil from 'ethereumjs-util'
import scrypt from 'scryptsy'
import crypto from 'crypto'
import jdenticon from 'jdenticon'

function decipherBuffer(decipher, data) {
  return Buffer.concat([decipher.update(data), decipher.final()])
}

export function addressFromKey(keystring) {
  try {
    var keyObj = JSON.parse(keystring)
    var address = keyObj.address
    if (address == undefined || address == "") {
      throw new Error("Invalid keystore format")
    }
    return "0x" + address
  } catch (e) {
    throw new Error("Invalid keystore format")
  }
}

export function unlock(input, password, nonStrict) {
    var json = (typeof input === 'object') ? input : JSON.parse(nonStrict ? input.toLowerCase() : input)
    if (json.version !== 3) {
        throw new Error('Not a V3 wallet')
    }
    var derivedKey
    var kdfparams
    if (json.crypto.kdf === 'scrypt') {
        kdfparams = json.crypto.kdfparams
        derivedKey = scrypt(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen)
    } else if (json.crypto.kdf === 'pbkdf2') {
        kdfparams = json.crypto.kdfparams
        if (kdfparams.prf !== 'hmac-sha256') {
            throw new Error('Unsupported parameters to PBKDF2')
        }
        derivedKey = crypto.pbkdf2Sync(new Buffer(password), new Buffer(kdfparams.salt, 'hex'), kdfparams.c, kdfparams.dklen, 'sha256')
    } else {
        throw new Error('Unsupported key derivation scheme')
    }
    var ciphertext = new Buffer(json.crypto.ciphertext, 'hex')
    var mac = ethUtil.sha3(Buffer.concat([derivedKey.slice(16, 32), ciphertext]))
    if (mac.toString('hex') !== json.crypto.mac) {
        throw new Error('Key derivation failed - possibly wrong passphrase')
    }
    var decipher = crypto.createDecipheriv(json.crypto.cipher, derivedKey.slice(0, 16), new Buffer(json.crypto.cipherparams.iv, 'hex'))
    var seed = decipherBuffer(decipher, ciphertext, 'hex')
    while (seed.length < 32) {
        var nullBuff = new Buffer([0x00]);
        seed = Buffer.concat([nullBuff, seed]);
    }
    return seed
}

export function getRandomAvatar(addressString) {
  let svg = jdenticon.toSvg(addressString, 45),
  url = 'data:image/svg+xml;base64,' + btoa(svg);
  return url
}

export function addressFromPrivateKey(privateKey){
    var addBuf = ethUtil.privateToAddress(new Buffer(privateKey, 'hex'))
    var addrString = ethUtil.bufferToHex(addBuf)
    return addrString
}<|endoftext|>


<commit_before>/* *****************************************************************************
 * Virtual objects for jsdoc documentation
 */

// Allow unused variables for demonstration
/*jshint unused:false */

/**
 * Context object passed to events and hook functions.
 * @name EventData
 *
 * @property {Fancytree} tree
 * @property {object} widget
 * @property {FancytreeOptions} options
 * @property {Event} orgEvent
 * @property {FancytreeNode | null} node
 * @property {any} result (output parameter) Event handlers can return values back to the caller. Used by `lazyload, `postProcess`, ...
 * @property {String | undefined} targetType (only for click and dblclick events) 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon'
 * @property {any} response (only for postProcess event) Original ajax response
 */
var EventData = {};

/**
 * Data object passed to FancytreeNode() constructor.
 * @name NodeData
 *
 * @property {String} title node text (may contain HTML tags)
 * @property {String} key unique key for this node (auto-generated if omitted)
 * @property {Boolean} expanded
 * @property {Boolean} active (initialization only, but will not be stored  with the node).
 * @property {Boolean} focus (initialization only, but will not be stored  with the node).
 * @property {Boolean} folder
 * @property {Boolean} hideCheckbox
 * @property {Boolean} lazy
 * @property {Boolean} selected
 * @property {Boolean} unselectable
 * @property {NodeData[]} children optional array of child nodes
 * @property {String} tooltip
 * @property {String} extraClasses class names added to the node markup (separate with space)
 * @property {object} data all properties from will be copied to `node.data`
 * @property {any} OTHER attributes other than listed above will be copied to `node.data`
 *
 */
var NodeData = {};

/**
 * Data object similar to {@link NodeData}, but with additional options.
 * May be passed to {@link FancytreeNode#applyPatch}
 * (Every property that is omitted (or set to undefined) will be ignored)
 * @name NodePatch
 *
 * @property {any} any (see NodeData)
 * @property {NodeData} appendChildren (not yet implemented)
 * @property {NodeData} replaceChildren (not yet implemented)
 * @property {NodeData} insertChildren (not yet implemented)
 */
var NodePatch = {};

/**
 * List of [key, {@link NodePatch}]  tuples.
 * May be passed to {@link Fancytree#applyPatch}.
 * @name TreePatch
 *
 */
var TreePatch = {};

/**
 * @name FancytreeOptions
 *
 * @description
 * Fancytree options (see also example)
 * line 2
 *
 * @example $("#tree").fancytree({source: "/myService"});
 *
 * @property {Boolean} activeVisible Make sure that the active node is always visible, i.e. it's parents are expanded (default: true).
 * @property {object} ajax Default options for ajax requests
 * @property {Boolean} aria (default: false)
 * @property {Boolean} autoActivate Activate a node when focused with the keyboard (default: true)
 * @property {Boolean} autoCollapse Automatically collapse all siblings, when a node is expanded (default: false).
 * @property {Boolean} autoScroll Scroll node into visible area, when focused by keyboard (default: false).
 * @property {Boolean} checkbox Display checkboxes to allow selection  (default: false)
 * @property {Integer} clickFolderMode Defines what happens, when the user click a folder node.
1:activate, 2:expand, 3:activate and expand, 4:activate/dblclick expands  (default: 4)
 * @property {Integer} debugLevel  0..2 (null: use global setting $.ui.fancytree.debugInfo)
 * @property {Boolean} enableAspx Accept passing ajax data in a property named `d (default: true).
 * @property {String[]} extensions List of active extensions (default: [])
 * @property {object} fx Animation options, null:off (default: { height: "toggle", duration: 200 })
 * @property {Boolean} generateIds Add `id="..."` to node markup (default: true).
 * @property {Boolean} icons Display node icons  (default: true)
 * @property {String} idPrefix (default: "ft_")
 * @property {String} imagePath Path to a folder containing icons (default: null, using 'skin/' subdirectory).
 * @property {Boolean} keyboard Support keyboard navigation (default: true).
 * @property {String} keyPathSeparator (default: "/")
 * @property {Integer} minExpandLevel 1: root node is not collapsible (default: 1)
 * @property {Integer} selectMode 1:single, 2:multi, 3:multi-hier (default: 2)
 * @property {any} source Used to Initialize the tree.
 * @property {object} strings Translation table
 * @property {Boolean} tabbable Add tabindex='0' to container, so tree can be reached using TAB
 *
 */
var FancytreeOptions = {};

/** Fancytree events
 * @name FancytreeEvents
 *
 * @description
 * Events are called like this:
 *    CALLBACK_NAME(event, data)
 * where `event` is a {@link http://api.jquery.com/category/events/event-object/|jQuery Event} object and `data` is of type {@link EventData}
 *
 * @see jQuery Event
 * @see EventData
 *
 * @example $("#tree").fancytree({
 *     activate: function(event, data){
 *         var node = data.node;
 *     }
 * });
 *
 * @property {function} activate `data.node` was deactivated
 * @property {function} beforeActivate Return `false` to prevent default processing
 * @property {function} beforeExpand Return `false` to prevent default processing
 * @property {function} beforeSelect Return `false` to prevent default processing
 * @property {function} blur `data.node` lost keyboard focus
 * @property {function} blurTree `data.tree` lost keyboard focus
 * @property {function} click `data.node` was clicked. `data.targetType` contains the region ("title", "expander", ...). Return `false` to prevent default processing, i.e. activating, etc.
 * @property {function} collapse `data.node` was collapsed
 * @property {function} create Widget was created (called only once, even if re-initialized).
 * @property {function} createNode Allow tweaking and binding, after node was created for the first time
 * @property {function} dblclick `data.node` was double-clicked. `data.targetType` contains the region ("title", "expander", ...). Return `false` to prevent default processing, i.e. expanding, etc.
 * @property {function} deactivate `data.node` was deactivated
 * @property {function} expand `data.node` was expanded
 * @property {function} focus `data.node` received keyboard focus
 * @property {function} focusTree `data.tree` received keyboard focus
 * @property {function} init Widget was (re-)initialized.
 * @property {function} keydown `data.node` received key. `event.which` contains the key. Return `false` to prevent default processing, i.e. navigation.
 * @property {function} keypress (currently unused)
 * @property {function} lazyload `data.node` is lazy a lazy node that is expanded for the first time.
 * @property {function} loadChildren Node data was loaded, i.e. `node.nodeLoadChildren()` finished
 * @property {function} postProcess (not yet implemented!) allows to modify the ajax response
 * @property {function} renderColumns (used by table extension)
 * @property {function} renderNode Allow tweaking after node state was rendered
 * @property {function} select `data.node` was selected
 *
 */
var FancytreeEvents = {};
<commit_msg>minor changes<commit_after>/* *****************************************************************************
 * Virtual objects for jsdoc documentation
 */

// Allow unused variables for demonstration
/*jshint unused:false */

/**
 * Context object passed to events and hook functions.
 * @name EventData
 *
 * @property {Fancytree} tree The tree instance
 * @property {object} widget The {@link http://api.jqueryui.com/jQuery.widget/|jQuery UI tree widget}
 * @property {FancytreeOptions} options Shortcut to tree.options
 * @property {Event} orgEvent The {@link http://api.jquery.com/category/events/event-object/|jQuery Event} that initially triggered this call
 * @property {FancytreeNode | null} node The node that this call applies to (`null` for tree events)
 * @property {any} result (output parameter) Event handlers can return values back to the caller. Used by `lazyload`, `postProcess`, ...
 * @property {String | undefined} targetType (only for click and dblclick events) 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon'
 * @property {any} response (only for postProcess event) Original ajax response
 */
var EventData = {};

/**
 * Data object passed to FancytreeNode() constructor.
 * @name NodeData
 *
 * @property {String} title node text (may contain HTML tags)
 * @property {String} key unique key for this node (auto-generated if omitted)
 * @property {Boolean} expanded
 * @property {Boolean} active (initialization only, but will not be stored  with the node).
 * @property {Boolean} focus (initialization only, but will not be stored  with the node).
 * @property {Boolean} folder
 * @property {Boolean} hideCheckbox
 * @property {Boolean} lazy
 * @property {Boolean} selected
 * @property {Boolean} unselectable
 * @property {NodeData[]} children optional array of child nodes
 * @property {String} tooltip
 * @property {String} extraClasses class names added to the node markup (separate with space)
 * @property {object} data all properties from will be copied to `node.data`
 * @property {any} OTHER attributes other than listed above will be copied to `node.data`
 *
 */
var NodeData = {};

/**
 * Data object similar to {@link NodeData}, but with additional options.
 * May be passed to {@link FancytreeNode#applyPatch}
 * (Every property that is omitted (or set to undefined) will be ignored)
 * @name NodePatch
 *
 * @property {any} any (see NodeData)
 * @property {NodeData} appendChildren (not yet implemented)
 * @property {NodeData} replaceChildren (not yet implemented)
 * @property {NodeData} insertChildren (not yet implemented)
 */
var NodePatch = {};

/**
 * List of [key, {@link NodePatch}]  tuples.
 * May be passed to {@link Fancytree#applyPatch}.
 * @name TreePatch
 *
 */
var TreePatch = {};

/**
 * @name FancytreeOptions
 *
 * @description
 * Fancytree options (see also example)
 * line 2
 *
 * @example $("#tree").fancytree({source: "/myService"});
 *
 * @property {Boolean} activeVisible Make sure that the active node is always visible, i.e. it's parents are expanded (default: true).
 * @property {object} ajax Default options for ajax requests
 * @property {Boolean} aria (default: false) Add WAI-ARIA attributes to markup
 * @property {Boolean} autoActivate Activate a node when focused with the keyboard (default: true)
 * @property {Boolean} autoCollapse Automatically collapse all siblings, when a node is expanded (default: false).
 * @property {Boolean} autoScroll Scroll node into visible area, when focused by keyboard (default: false).
 * @property {Boolean} checkbox Display checkboxes to allow selection  (default: false)
 * @property {Integer} clickFolderMode Defines what happens, when the user click a folder node.
1:activate, 2:expand, 3:activate and expand, 4:activate/dblclick expands  (default: 4)
 * @property {Integer} debugLevel  0..2 (null: use global setting $.ui.fancytree.debugInfo)
 * @property {Boolean} enableAspx Accept passing ajax data in a property named `d` (default: true).
 * @property {String[]} extensions List of active extensions (default: [])
 * @property {object} fx Animation options, null:off (default: { height: "toggle", duration: 200 })
 * @property {Boolean} generateIds Add `id="..."` to node markup (default: true).
 * @property {Boolean} icons Display node icons  (default: true)
 * @property {String} idPrefix (default: "ft_")
 * @property {String} imagePath Path to a folder containing icons (default: null, using 'skin/' subdirectory).
 * @property {Boolean} keyboard Support keyboard navigation (default: true).
 * @property {String} keyPathSeparator (default: "/")
 * @property {Integer} minExpandLevel 1: root node is not collapsible (default: 1)
 * @property {Integer} selectMode 1:single, 2:multi, 3:multi-hier (default: 2)
 * @property {any} source Used to Initialize the tree.
 * @property {object} strings Translation table
 * @property {Boolean} tabbable Add tabindex='0' to container, so tree can be reached using TAB
 *
 */
var FancytreeOptions = {};

/** Fancytree events
 * @name FancytreeEvents
 *
 * @description
 * Events are called like this:
 *    CALLBACK_NAME(event, data)
 * where `event` is a {@link http://api.jquery.com/category/events/event-object/|jQuery Event} object and `data` is of type {@link EventData}
 * The `this` context is set to  tree's the HTMLDivElement
 *
 * @see jQuery Event
 * @see EventData
 *
 * @example $("#tree").fancytree({
 *     activate: function(event, data){
 *         var node = data.node;
 *     }
 * });
 *
 * @property {function} activate `data.node` was deactivated
 * @property {function} beforeActivate Return `false` to prevent default processing
 * @property {function} beforeExpand Return `false` to prevent default processing
 * @property {function} beforeSelect Return `false` to prevent default processing
 * @property {function} blur `data.node` lost keyboard focus
 * @property {function} blurTree `data.tree` lost keyboard focus
 * @property {function} click `data.node` was clicked. `data.targetType` contains the region ("title", "expander", ...). Return `false` to prevent default processing, i.e. activating, etc.
 * @property {function} collapse `data.node` was collapsed
 * @property {function} create Widget was created (called only once, even if re-initialized).
 * @property {function} createNode Allow tweaking and binding, after node was created for the first time
 * @property {function} dblclick `data.node` was double-clicked. `data.targetType` contains the region ("title", "expander", ...). Return `false` to prevent default processing, i.e. expanding, etc.
 * @property {function} deactivate `data.node` was deactivated
 * @property {function} expand `data.node` was expanded
 * @property {function} focus `data.node` received keyboard focus
 * @property {function} focusTree `data.tree` received keyboard focus
 * @property {function} init Widget was (re-)initialized.
 * @property {function} keydown `data.node` received key. `event.which` contains the key. Return `false` to prevent default processing, i.e. navigation.
 * @property {function} keypress (currently unused)
 * @property {function} lazyload `data.node` is lazy a lazy node that is expanded for the first time.
 * @property {function} loadChildren Node data was loaded, i.e. `node.nodeLoadChildren()` finished
 * @property {function} postProcess (not yet implemented!) allows to modify the ajax response
 * @property {function} renderColumns (used by table extension)
 * @property {function} renderNode Allow tweaking after node state was rendered
 * @property {function} select `data.node` was selected
 *
 */
var FancytreeEvents = {};
<|endoftext|>


<commit_before>import { Component } from 'substance'

export default class Button extends Component {
  render ($$) {
    let el = $$('button')
      .addClass('sc-button')

    if (this.props.icon) {
      el.append(this.renderIcon($$))
    }
    if (this.props.label) {
      el.append(this.renderLabel($$))
    }

    if (this.props.dropdown) {
      el.append(this.renderDropdownIcon($$))
    }

    if (this.props.active) {
      el.addClass('sm-active')
    }
    if (this.props.theme) {
      el.addClass('sm-theme-' + this.props.theme)
    }

    if (this.props.disabled) {
      // make button inaccessible
      el.attr('tabindex', -1)
        .attr('disabled', true)
    } else {
      // make button accessible for tab-navigation
      el.attr('tabindex', 1)
    }

    // Ability to inject additional elements (should be avoided!)
    el.append(this.props.children)
    return el
  }

  renderIcon ($$) {
    let iconEl = this.context.iconProvider.renderIcon($$, this.props.icon)
    return iconEl
  }

  renderDropdownIcon ($$) {
    let iconEl = this.context.iconProvider.renderIcon($$, 'dropdown')
    iconEl.addClass('se-dropdown')
    return iconEl
  }

  renderLabel ($$) {
    return $$('span').addClass('se-label').append(
      this.getLabel(this.props.label)
    )
  }

  getLabel (name) {
    let labelProvider = this.context.labelProvider
    return labelProvider.getLabel(name, this.props.commandState)
  }
}
<commit_msg>Render tooltip for Buttons.<commit_after>import { Component } from 'substance'

export default class Button extends Component {
  render ($$) {
    let el = $$('button')
      .addClass('sc-button')

    if (this.props.icon) {
      el.append(this.renderIcon($$))
    }
    if (this.props.label) {
      el.append(this.renderLabel($$))
    }
    if (this.props.tooltip) {
      el.append(this.renderTooltip($$))
    }
    if (this.props.dropdown) {
      el.append(this.renderDropdownIcon($$))
    }
    if (this.props.active) {
      el.addClass('sm-active')
    }
    if (this.props.theme) {
      el.addClass('sm-theme-' + this.props.theme)
    }

    if (this.props.disabled) {
      // make button inaccessible
      el.attr('tabindex', -1)
        .attr('disabled', true)
    } else {
      // make button accessible for tab-navigation
      el.attr('tabindex', 1)
    }

    // Ability to inject additional elements (should be avoided!)
    el.append(this.props.children)
    return el
  }

  renderIcon ($$) {
    let iconEl = this.context.iconProvider.renderIcon($$, this.props.icon)
    return iconEl
  }

  renderDropdownIcon ($$) {
    let iconEl = this.context.iconProvider.renderIcon($$, 'dropdown')
    iconEl.addClass('se-dropdown')
    return iconEl
  }

  renderLabel ($$) {
    return $$('span').addClass('se-label').append(
      this.getLabel(this.props.label)
    )
  }

  renderTooltip ($$) {
    return $$('span').addClass('se-tooltip').append(this.props.tooltip)
  }

  getLabel (name) {
    let labelProvider = this.context.labelProvider
    return labelProvider.getLabel(name, this.props.commandState)
  }
}
<|endoftext|>


<commit_before>/*
Language: C++
Author: Ivan Sagalaev <maniac@softwaremaniacs.org>
Contributors: Evgeny Stepanischev <imbolk@gmail.com>, Zaven Muradyan <megalivoithos@gmail.com>, Roel Deckers <admin@codingcat.nl>
Category: common, system
*/

function(hljs) {
  var CPP_PRIMITIVE_TYPES = {
    className: 'keyword',
    begin: '\\b[a-z\\d_]*_t\\b'
  };

  var STRINGS = {
    className: 'string',
    variants: [
      {
        begin: '(u8?|U)?L?"', end: '"',
        illegal: '\\n',
        contains: [hljs.BACKSLASH_ESCAPE]
      },
      {
        begin: '(u8?|U)?R"', end: '"',
        contains: [hljs.BACKSLASH_ESCAPE]
      },
      {
        begin: '\'\\\\?.', end: '\'',
        illegal: '.'
      }
    ]
  };

  var NUMBERS = {
    className: 'number',
    variants: [
      { begin: '\\b(0b[01\'_]+)' },
      { begin: '\\b([\\d\'_]+(\\.[\\d\'_]*)?|\\.[\\d\'_]+)(u|U|l|L|ul|UL|f|F|b|B)' },
      { begin: '(-?)(\\b0[xX][a-fA-F0-9\'_]+|(\\b[\\d\'_]+(\\.[\\d\'_]*)?|\\.[\\d\'_]+)([eE][-+]?[\\d\'_]+)?)' }
    ],
    relevance: 0
  };

  var PREPROCESSOR =       {
    className: 'meta',
    begin: /#\s*[a-z]+\b/, end: /$/,
    keywords: {
      'meta-keyword':
        'if else elif endif define undef warning error line ' +
        'pragma ifdef ifndef include'
    },
    contains: [
      {
        begin: /\\\n/, relevance: 0
      },
      hljs.inherit(STRINGS, {className: 'meta-string'}),
      {
        className: 'meta-string',
        begin: '<', end: '>',
        illegal: '\\n',
      },
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE
    ]
  };

  var FUNCTION_TITLE = hljs.IDENT_RE + '\\s*\\(';

  var CPP_KEYWORDS = {
    keyword: 'int float while private char catch export virtual operator sizeof ' +
      'dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace ' +
      'unsigned long volatile static protected bool template mutable if public friend ' +
      'do goto auto void enum else break extern using class asm case typeid ' +
      'short reinterpret_cast|10 default double register explicit signed typename try this ' +
      'switch continue inline delete alignof constexpr decltype ' +
      'noexcept static_assert thread_local restrict _Bool complex _Complex _Imaginary ' +
      'atomic_bool atomic_char atomic_schar ' +
      'atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong ' +
      'atomic_ullong new throw return',
    built_in: 'std string cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream ' +
      'auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set ' +
      'unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos ' +
      'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp ' +
      'fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper ' +
      'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow ' +
      'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp ' +
      'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan ' +
      'vfprintf vprintf vsprintf endl initializer_list unique_ptr',
    literal: 'true false nullptr NULL'
  };

  var EXPRESSION_CONTAINS = [
    CPP_PRIMITIVE_TYPES,
    hljs.C_LINE_COMMENT_MODE,
    hljs.C_BLOCK_COMMENT_MODE,
    NUMBERS,
    STRINGS
  ];

  return {
    aliases: ['c', 'cc', 'h', 'c++', 'h++', 'hpp'],
    keywords: CPP_KEYWORDS,
    illegal: '</',
    contains: EXPRESSION_CONTAINS.concat([
      PREPROCESSOR,
      {
        begin: '\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<', end: '>',
        keywords: CPP_KEYWORDS,
        contains: ['self', CPP_PRIMITIVE_TYPES]
      },
      {
        begin: hljs.IDENT_RE + '::',
        keywords: CPP_KEYWORDS
      },
      {
        // This mode covers expression context where we can't expect a function
        // definition and shouldn't highlight anything that looks like one:
        // `return some()`, `else if()`, `(x*sum(1, 2))`
        variants: [
          {begin: /=/, end: /;/},
          {begin: /\(/, end: /\)/},
          {beginKeywords: 'new throw return else', end: /;/}
        ],
        keywords: CPP_KEYWORDS,
        contains: EXPRESSION_CONTAINS.concat([
          {
            begin: /\(/, end: /\)/,
            keywords: CPP_KEYWORDS,
            contains: EXPRESSION_CONTAINS.concat(['self']),
            relevance: 0
          }
        ]),
        relevance: 0
      },
      {
        className: 'function',
        begin: '(' + hljs.IDENT_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
        returnBegin: true, end: /[{;=]/,
        excludeEnd: true,
        keywords: CPP_KEYWORDS,
        illegal: /[^\w\s\*&]/,
        contains: [
          {
            begin: FUNCTION_TITLE, returnBegin: true,
            contains: [hljs.TITLE_MODE],
            relevance: 0
          },
          {
            className: 'params',
            begin: /\(/, end: /\)/,
            keywords: CPP_KEYWORDS,
            relevance: 0,
            contains: [
              hljs.C_LINE_COMMENT_MODE,
              hljs.C_BLOCK_COMMENT_MODE,
              STRINGS,
              NUMBERS,
              CPP_PRIMITIVE_TYPES
            ]
          },
          hljs.C_LINE_COMMENT_MODE,
          hljs.C_BLOCK_COMMENT_MODE,
          PREPROCESSOR
        ]
      }
    ]),
    exports: {
      preprocessor: PREPROCESSOR,
      strings: STRINGS,
      keywords: CPP_KEYWORDS
    }
  };
}
<commit_msg>Added C++ Modules<commit_after>/*
Language: C++
Author: Ivan Sagalaev <maniac@softwaremaniacs.org>
Contributors: Evgeny Stepanischev <imbolk@gmail.com>, Zaven Muradyan <megalivoithos@gmail.com>, Roel Deckers <admin@codingcat.nl>
Category: common, system
*/

function(hljs) {
  var CPP_PRIMITIVE_TYPES = {
    className: 'keyword',
    begin: '\\b[a-z\\d_]*_t\\b'
  };

  var STRINGS = {
    className: 'string',
    variants: [
      {
        begin: '(u8?|U)?L?"', end: '"',
        illegal: '\\n',
        contains: [hljs.BACKSLASH_ESCAPE]
      },
      {
        begin: '(u8?|U)?R"', end: '"',
        contains: [hljs.BACKSLASH_ESCAPE]
      },
      {
        begin: '\'\\\\?.', end: '\'',
        illegal: '.'
      }
    ]
  };

  var NUMBERS = {
    className: 'number',
    variants: [
      { begin: '\\b(0b[01\'_]+)' },
      { begin: '\\b([\\d\'_]+(\\.[\\d\'_]*)?|\\.[\\d\'_]+)(u|U|l|L|ul|UL|f|F|b|B)' },
      { begin: '(-?)(\\b0[xX][a-fA-F0-9\'_]+|(\\b[\\d\'_]+(\\.[\\d\'_]*)?|\\.[\\d\'_]+)([eE][-+]?[\\d\'_]+)?)' }
    ],
    relevance: 0
  };

  var PREPROCESSOR =       {
    className: 'meta',
    begin: /#\s*[a-z]+\b/, end: /$/,
    keywords: {
      'meta-keyword':
        'if else elif endif define undef warning error line ' +
        'pragma ifdef ifndef include'
    },
    contains: [
      {
        begin: /\\\n/, relevance: 0
      },
      hljs.inherit(STRINGS, {className: 'meta-string'}),
      {
        className: 'meta-string',
        begin: '<', end: '>',
        illegal: '\\n',
      },
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE
    ]
  };

  var FUNCTION_TITLE = hljs.IDENT_RE + '\\s*\\(';

  var CPP_KEYWORDS = {
    keyword: 'int float while private char catch import module export virtual operator sizeof ' +
      'dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace ' +
      'unsigned long volatile static protected bool template mutable if public friend ' +
      'do goto auto void enum else break extern using class asm case typeid ' +
      'short reinterpret_cast|10 default double register explicit signed typename try this ' +
      'switch continue inline delete alignof constexpr decltype ' +
      'noexcept static_assert thread_local restrict _Bool complex _Complex _Imaginary ' +
      'atomic_bool atomic_char atomic_schar ' +
      'atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong ' +
      'atomic_ullong new throw return',
    built_in: 'std string cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream ' +
      'auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set ' +
      'unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos ' +
      'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp ' +
      'fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper ' +
      'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow ' +
      'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp ' +
      'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan ' +
      'vfprintf vprintf vsprintf endl initializer_list unique_ptr',
    literal: 'true false nullptr NULL'
  };

  var EXPRESSION_CONTAINS = [
    CPP_PRIMITIVE_TYPES,
    hljs.C_LINE_COMMENT_MODE,
    hljs.C_BLOCK_COMMENT_MODE,
    NUMBERS,
    STRINGS
  ];

  return {
    aliases: ['c', 'cc', 'h', 'c++', 'h++', 'hpp'],
    keywords: CPP_KEYWORDS,
    illegal: '</',
    contains: EXPRESSION_CONTAINS.concat([
      PREPROCESSOR,
      {
        begin: '\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<', end: '>',
        keywords: CPP_KEYWORDS,
        contains: ['self', CPP_PRIMITIVE_TYPES]
      },
      {
        begin: hljs.IDENT_RE + '::',
        keywords: CPP_KEYWORDS
      },
      {
        // This mode covers expression context where we can't expect a function
        // definition and shouldn't highlight anything that looks like one:
        // `return some()`, `else if()`, `(x*sum(1, 2))`
        variants: [
          {begin: /=/, end: /;/},
          {begin: /\(/, end: /\)/},
          {beginKeywords: 'new throw return else', end: /;/}
        ],
        keywords: CPP_KEYWORDS,
        contains: EXPRESSION_CONTAINS.concat([
          {
            begin: /\(/, end: /\)/,
            keywords: CPP_KEYWORDS,
            contains: EXPRESSION_CONTAINS.concat(['self']),
            relevance: 0
          }
        ]),
        relevance: 0
      },
      {
        className: 'function',
        begin: '(' + hljs.IDENT_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
        returnBegin: true, end: /[{;=]/,
        excludeEnd: true,
        keywords: CPP_KEYWORDS,
        illegal: /[^\w\s\*&]/,
        contains: [
          {
            begin: FUNCTION_TITLE, returnBegin: true,
            contains: [hljs.TITLE_MODE],
            relevance: 0
          },
          {
            className: 'params',
            begin: /\(/, end: /\)/,
            keywords: CPP_KEYWORDS,
            relevance: 0,
            contains: [
              hljs.C_LINE_COMMENT_MODE,
              hljs.C_BLOCK_COMMENT_MODE,
              STRINGS,
              NUMBERS,
              CPP_PRIMITIVE_TYPES
            ]
          },
          hljs.C_LINE_COMMENT_MODE,
          hljs.C_BLOCK_COMMENT_MODE,
          PREPROCESSOR
        ]
      }
    ]),
    exports: {
      preprocessor: PREPROCESSOR,
      strings: STRINGS,
      keywords: CPP_KEYWORDS
    }
  };
}
<|endoftext|>