浏览代码

all functions working, still need to clean up code base.

Tomislav Cvetic 7 年之前
父节点
当前提交
48f6f4bfe8
共有 8 个文件被更改,包括 343 次插入485 次删除
  1. 2 7
      package.json
  2. 166 109
      src/App.js
  3. 5 3
      src/excel/index.js
  4. 6 5
      src/match/components/match-list.js
  5. 11 3
      src/match/index.js
  6. 5 2
      src/player/components/player-list.js
  7. 9 3
      src/player/index.js
  8. 139 353
      yarn.lock

+ 2 - 7
package.json

@@ -5,16 +5,11 @@
   "dependencies": {
     "blob": "^0.0.4",
     "file-saver": "^1.3.3",
+    "html-inline": "^1.2.0",
     "moment": "^2.18.1",
-    "msexcel-builder": "^0.0.2",
-    "ods": "^1.1.7",
     "react": "^15.5.4",
     "react-dom": "^15.5.4",
-    "rx": "^4.1.0",
-    "workbook": "^1.1.3",
-    "xlsx": "^0.10.4",
-    "xlsx-style": "^0.8.13",
-    "xlsx-workbook": "^1.0.3"
+    "xlsx": "^0.10.4"
   },
   "devDependencies": {
     "react-scripts": "^1.0.7"

+ 166 - 109
src/App.js

@@ -1,27 +1,36 @@
-import React from 'react'
-import XLSX from 'xlsx'
-import player from './player'
-import match from './match'
-import Stats from './stats/stats'
-import { SheetFromArray, Workbook, saveAs } from './excel/excel'
+import React from 'react'           // React to manage the GUI
+import XLSX from 'xlsx'             // xlsx to read and write Excel XLSX Workbooks
+import Player from './player'       // Everything that has to do with players
+import Match from './match'         // Everything that has to do with matches
+import Excel from './excel'         // Helper files to create Excel files
 
+const FILTER_OFF = 'Alle'
+
+/** Main application */
 class App extends React.Component {
+  /** 
+   * Constructor
+   * Defines the state and binds all 'this' in all functions to the object.
+   */
   constructor () {
     super()
+
+    // Define the state
     this.state = {
-      stats: {
-        matchDates: []
-      },
-      players: [],
-      matches: [],
+      player: Player.state,
+      match: Match.state,
       worksheets: {
         'PlayerList': null,
         'Calendar': null
       },
       filters: {
-        date: 'Alle'
+        date: null,
+        place: null,
+        category: null
       }
     }
+
+    // Bind 'this' to functions
     this.handlePlayerList = this.handlePlayerList.bind(this)
     this.handleCalendar = this.handleCalendar.bind(this)
     this.generatePlayerList = this.generatePlayerList.bind(this)
@@ -29,10 +38,27 @@ class App extends React.Component {
     this.filterData = this.filterData.bind(this)
     this.generateSchedule = this.generateSchedule.bind(this)
     this.generatePayTable = this.generatePayTable.bind(this)
+
+    this.unpaid = 'off'
   }
 
-  componentDidMount () {
-    this.generateStats()
+  calculateMatchFilters () {
+    const dates = {}
+    const places = []
+    const categories = []
+    this.state.match.matches.forEach((item) => {
+      if (!!item.DatumString & !dates.hasOwnProperty(item.DatumString)) {
+        dates[item.DatumString] = item.Datum
+      }
+      if (!!item.Ort & !places.includes(item.Ort)) {
+        places.push(item.Ort)
+      }
+      if (!!item.Konkurrenz & !categories.includes(item.Konkurrenz)) {
+        categories.push(item.Konkurrenz)
+      }
+    })
+    const match = { ...this.state.match, dates, places, categories }
+    this.setState({ match })
   }
 
   handlePlayerList (event) {
@@ -50,11 +76,11 @@ class App extends React.Component {
     reader.onload = (e) => {
       const data = e.target.result
       const workbook = XLSX.read(data, {type: 'binary', cellDates: true})
-      console.log(workbook)
+      console.log('Workbook after read:', workbook)
       if (workbook.SheetNames.length !== 1) {
         throw Error(`Expected only one worksheet in the file, but found ${workbook.SheetNames.length}.`)
       }
-      const worksheet = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], { header: 1 })
+      const worksheet = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], { header: 1, raw: true })
       callback(worksheet)
     }
     reader.readAsBinaryString(file)
@@ -69,10 +95,12 @@ class App extends React.Component {
     if (worksheet[4].length !== 32 & worksheet[3][0] !== 'Konkurrenz' & worksheet[3][31] !== 'bezahlt') {
       throw Error('Wrong file structure.')
     }
-    const players = worksheet.slice(4, worksheet.length).map((playerData) => new player.Player(playerData))
-    this.setState({ players })
-    this.generateStats()
-    console.log(this.state)
+    const players = worksheet.slice(4, worksheet.length).map((playerData) => new Player.Player(playerData))
+    const player = { ...this.state.player }
+    player.players = players
+    this.setState({ player })
+    this.filterData()
+    console.log('State after generating player list:', this.state)
   }
 
   generateCalendar (worksheet) {
@@ -84,178 +112,207 @@ class App extends React.Component {
     if (worksheet[2].length !== 8) {
       throw Error('Wrong file structure.')
     }
-    const matches = worksheet.slice(2, worksheet.length).map((matchData) => new match.Match(matchData))
-    this.setState({ matches })
-    this.generateStats()
-    console.log(this.state)
-  }
-
-  generateStats () {
-    const stats = {
-      players: [],
-      playerCategories: [],
-      matchCategories: [],
-      matches: [],
-      matchDates: [],
-      matchPlaces: []
-    }
-
-    stats.players = this.state.players
-
-    this.state.players.forEach((player, key) => {
-      if (!stats.playerCategories.includes(player.Konkurrenz)) {
-        stats.playerCategories.push(player.Konkurrenz)
-      }
-    })
-
-    stats.matches = this.state.matches
-
-    this.state.matches.forEach((match, key) => {
-      if (!!match.Datum & !stats.matchDates.includes(match.DatumString)) {
-        stats.matchDates.push(match.DatumString)
-      }
-      if (!!match.Konkurrenz & !stats.matchCategories.includes(match.Konkurrenz)) {
-        stats.matchCategories.push(match.Konkurrenz)
-      }
-      if (!!match.Ort & !stats.matchPlaces.includes(match.Ort)) {
-        stats.matchPlaces.push(match.Ort)
-      }
-    })
-
-    this.setState({ stats })
+    const matches = worksheet.slice(2, worksheet.length).map((matchData) => new Match.MatchClass(matchData))
+    const match = { ...this.state.match }
+    match.matches = matches
+    this.setState({ match })
+    this.calculateMatchFilters()
+    this.filterData()
+    console.log('State after generating calendar:', this.state)
   }
 
   filterData () {
     const filters = {
-      date: this.date.value
+      date: this.date.value !== FILTER_OFF ? this.date.value : null,
+      place: this.place.value !== FILTER_OFF ? this.place.value : null,
+      category: this.category.value !== FILTER_OFF ? this.category.value : null,
     }
-    this.generateStats()
+    console.log('New filter settings:', filters)
     this.setState({ filters })
+
+    const match = { ...this.state.match }
+    match.filtered = match.matches.filter((match) => {
+      const matchDate = new Date(match.Datum)
+      matchDate.setHours(0, 0, 0, 0)
+      const filtDate = new Date(filters.date)
+      filtDate.setHours(0, 0, 0, 0)
+      return (!filters.date | matchDate.getTime() === filtDate.getTime()) &
+      (!filters.place | filters.place === match.Ort) &
+      (!filters.category | filters.category === match.Konkurrenz)
+    })
+    this.setState({ match })
+
+    const player = { ...this.state.player }
+    player.filtered = player.players
+    this.setState({ player })
   }
 
   generateSchedule (event) {
     event.preventDefault()
 
-    const matchlist = new Workbook()
+    const matchlist = new Excel.Workbook()
     matchlist.SheetNames = []
     matchlist.Sheets = {}
 
     const worksheets = {}
-    const placeArray = this.state.stats.matchPlaces.concat(['Alle'])
+
+    let placeArray = this.state.match.places
+    if (placeArray.length > 1) {
+      placeArray = placeArray.concat([FILTER_OFF])
+    }
+    const date = Object.keys(this.state.match.dates).find((key) =>
+      String(this.state.match.dates[key]) === this.date.value
+    )
 
     placeArray.forEach((place) => {
-      let filter = this.state.filters.date
       let header = [
-        [`Spielplan für den ${filter} (${place})`],
+        [`Spielplan für den ${date} (${place})`],
         [],
         ['Ort', 'Zeit', 'Kategorie', 'Spieler 1', '', 'Spieler 2', '', '1. Satz', '2. Satz', '3. Satz', 'WO Grund']
       ]
-      let matchListPerPlace = this.state.matches.filter((match) => {
-        return (match.DatumString === filter | filter === 'Alle') & (match.Ort === place | place === 'Alle')
-      }).map((match) =>
+      let matchListPerPlace = this.state.match.filtered.filter((match) => (match.Ort === place | place === FILTER_OFF)).map((match) =>
         [match.Ort, match.ZeitString, match.Konkurrenz, match.Spieler1, match.Spieler1Klassierung, match.Spieler2, match.Spieler2Klassierung]
       )
-      console.log(matchListPerPlace)
-      worksheets[place] = SheetFromArray(header.concat(matchListPerPlace))
+      console.log('Generated match list per place:', matchListPerPlace)
+      worksheets[place] = Excel.SheetFromArray(header.concat(matchListPerPlace))
       matchlist.SheetNames.push(place)
       matchlist.Sheets[place] = worksheets[place]
     })
-    console.log(matchlist)
 
-    saveAs(matchlist, 'Spielerliste.xlsx')
+    Excel.saveAs(matchlist, 'Spielliste.xlsx')
   }
 
   generatePayTable (event) {
     event.preventDefault()
 
-    const paylist = new Workbook()
+    const paylist = new Excel.Workbook()
     paylist.SheetNames = []
     paylist.Sheets = {}
 
     const worksheets = {}
-    const placeArray = this.state.stats.matchPlaces.concat(['Alle'])
 
     const payerList = {}
-    this.state.matches.forEach((match) => {
+    this.state.match.matches.forEach((match) => {
       const id1 = `${match.Konkurrenz} ${match.Spieler1}`
       if (!!match.Spieler1 & !payerList.hasOwnProperty(id1)) {
-        let foundPlayer = this.state.players.find((player) =>
+        let foundPlayer = this.state.player.players.find((player) =>
           (player.name() === match.Spieler1) & (player.Konkurrenz === match.Konkurrenz)
         )
         if (!foundPlayer) {
-          console.log(foundPlayer, match)
+          console.log('Debug payerlist:', foundPlayer, match)
           throw Error('Player 1 not found. This is an error!')
         }
-        payerList[id1] = [match.Ort, match.DatumString, match.ZeitString, foundPlayer.bezahlt]
+        payerList[id1] = { ...match, Bezahlt: foundPlayer.Bezahlt }
       }
 
       const id2 = `${match.Konkurrenz} ${match.Spieler2}`
       if (!!match.Spieler2 & !payerList.hasOwnProperty(id2)) {
-        let foundPlayer = this.state.players.find((player) =>
+        let foundPlayer = this.state.player.players.find((player) =>
           (player.name() === match.Spieler2) & (player.Konkurrenz === match.Konkurrenz)
         )
         if (!foundPlayer) {
-          console.log(foundPlayer, match)
+          console.log('Debug payerlist:', foundPlayer, match)
           throw Error('Player 2 not found. This is an error!')
         }
-        payerList[id2] = [match.Ort, match.DatumString, match.ZeitString, foundPlayer.bezahlt]
+        payerList[id2] = { ...match, Bezahlt: foundPlayer.Bezahlt }
       }
     })
-    console.log(payerList)
+    console.log('Generated payerList', payerList)
+
+    let placeArray = this.state.match.places
+    if (placeArray.length > 1) {
+      placeArray = placeArray.concat([FILTER_OFF])
+    }
+    const date = Object.keys(this.state.match.dates).find((key) =>
+      String(this.state.match.dates[key]) === this.date.value
+    )
 
     placeArray.forEach((place) => {
-      let filter = this.state.filters.date
       let header = [
-        [`Zahlliste für den ${filter} (${place})`],
+        [`Zahlliste für den ${date} (${place})`],
         [],
-        ['bereits bez.', 'Kategorie', 'Name', 'Betrag bez.', 'Quittung abgeben']
+        ['bereits bez.', 'Kategorie', 'Zeit', 'Name', 'Betrag bez.', 'Quittung abgeben']
       ]
 
       let payListPerPlace = []
-      this.state.matches.filter((match) => {
-        return (match.DatumString === filter | filter === 'Alle') & (match.Ort === place | place === 'Alle')
-      }).forEach((match) => {
-        if (match.Spieler1) {
-          payListPerPlace.push([match.Ort])
+      this.state.match.filtered.forEach((match) => {
+        if (!!match.Spieler1 & (match.Ort === place | FILTER_OFF === place)) {
+          const id1 = `${match.Konkurrenz} ${match.Spieler1}`
+          const player = payerList[id1]
+          let paid = null
+          if (player.Datum < this.date.value) {
+            paid = player.DatumString
+          }
+          if (player.Bezahlt) {
+            paid = 'OK'
+          }
+          payListPerPlace.push([ paid, match.Konkurrenz, match.ZeitString, match.Spieler1 ])
         }
-        if (match.Spieler2) {
-          payListPerPlace.push([match.Ort])
+        if (!!match.Spieler2 & (match.Ort === place | FILTER_OFF === place)) {
+          const id2 = `${match.Konkurrenz} ${match.Spieler2}`
+          const player = payerList[id2]
+          let paid = null
+          if (player.Datum < this.date.value) {
+            paid = player.Datum
+          }
+          if (player.Bezahlt) {
+            paid = 'OK'
+          }
+          payListPerPlace.push([ paid, match.Konkurrenz, match.ZeitString, match.Spieler2 ])
         }
       })
-      console.log(payListPerPlace)
-      worksheets[place] = SheetFromArray(header.concat(payListPerPlace))
+      console.log('Generated pay list per place:', payListPerPlace)
+      worksheets[place] = Excel.SheetFromArray(header.concat(payListPerPlace))
       paylist.SheetNames.push(place)
       paylist.Sheets[place] = worksheets[place]
     })
-    console.log(paylist)
 
-    saveAs(paylist, 'Zahlliste.xlsx')
+    Excel.saveAs(paylist, 'Zahlliste.xlsx')
   }
 
   render () {
-    const PlayerList = player.components.PlayerList
-    const MatchList = match.components.MatchList
+    const PlayerList = Player.components.PlayerList
+    const MatchList = Match.components.MatchList
 
+    const places = this.state.match.places
+    const dates = this.state.match.dates
+    const categories = this.state.match.categories
+ 
     return (
       <div className='App'>
         <form>
-          <label htmlFor='playerList'>Swisstennis playerList.xls</label>
-          <input type='file' id='PlayerList' ref={(input) => { this.playerList = input }} accept='.xls' placeholder='playerList File' onChange={this.handlePlayerList} />
+          <label htmlFor='PlayerList'>Swisstennis PlayerList.xls</label>
+          <input type='file' id='PlayerList' ref={(input) => { this.playerList = input }} accept='.xls' placeholder='PlayerList File' onChange={this.handlePlayerList} />
           <label htmlFor='Calendar'>Swisstennis Calendar.xls</label>
           <input type='file' id='Calendar' ref={(input) => { this.calendar = input }} accept='.xls' placeholder='Calendar File' onChange={this.handleCalendar} />
           <label htmlFor='Date'>Datum</label>
-          <select ref={(input) => { this.date = input }} onChange={this.filterData}>
-            <option>Alle</option>
-            {this.state.stats.matchDates.map((date, key) => (
-              <option key={key}>{date}</option>
+          <select id='Date' ref={(input) => { this.date = input }} onChange={this.filterData}>
+            <option>{FILTER_OFF}</option>
+            {Object.keys(dates).map((key) => (
+              <option key={key} value={dates[key]}>{key}</option>
+            ))}
+          </select>
+          <label htmlFor='Place'>Ort</label>
+          <select id='Place' ref={(input) => { this.place = input }} onChange={this.filterData}>
+            <option>{FILTER_OFF}</option>
+            {places.map((place, key) => (
+              <option key={key}>{place}</option>
+            ))}
+          </select>
+          <label htmlFor='Category'>Konkurrenz</label>
+          <select id='Category' ref={(input) => { this.category = input }} onChange={this.filterData}>
+            <option>{FILTER_OFF}</option>
+            {categories.map((category, key) => (
+              <option key={key}>{category}</option>
             ))}
           </select>
-          <button onClick={this.generateSchedule} disabled={!this.state.matches.length}>Spielliste generieren</button>
-          <button onClick={this.generatePayTable} disabled={(!this.state.matches.length | !this.state.players.length)}>Zahlliste generieren</button>
+          <label htmlFor='Unpaid'>Nur unbezahlte</label>
+          <input type='checkbox' id='Unpaid' ref={(input) => { this.unpaid = input }} onChange={this.filterDate} />
+          <button onClick={this.generateSchedule} disabled={!this.state.match.filtered.length}>Spielliste generieren</button>
+          <button onClick={this.generatePayTable} disabled={(!this.state.match.filtered.length | !this.state.player.filtered.length)}>Zahlliste generieren</button>
         </form>
-        <Stats stats={this.state.stats} />
-        <PlayerList players={this.state.players} />
-        <MatchList matches={this.state.matches} filters={this.state.filters} />
+        <PlayerList player={this.state.player} />
+        <MatchList match={this.state.match} />
       </div>
     )
   }

+ 5 - 3
src/excel/excel.js → src/excel/index.js

@@ -8,7 +8,7 @@ function datenum (v, date1904) {
   return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
 }
 
-export function SheetFromArray (data, opts) {
+function SheetFromArray (data, opts) {
   var ws = {}
   var range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0 }}
   for (var R = 0; R !== data.length; ++R) {
@@ -35,7 +35,7 @@ export function SheetFromArray (data, opts) {
   return ws
 }
 
-export function Workbook () {
+function Workbook () {
   if (!(this instanceof Workbook)) return new Workbook()
   this.SheetNames = []
   this.Sheets = {}
@@ -48,8 +48,10 @@ function s2ab (s) {
   return buf
 }
 
-export function saveAs (workbook, filename) {
+function saveAs (workbook, filename) {
   const wopts = {bookType: 'xlsx', bookSST: false, type: 'binary'}
   const wbout = XLSX.write(workbook, wopts)
   FileSaver.saveAs(new Blob([s2ab(wbout)], {type: ''}), filename)
 }
+
+export default { Workbook, SheetFromArray, saveAs }

+ 6 - 5
src/match/components/match-list.js

@@ -2,15 +2,16 @@ import React from 'react'
 import MatchDisp from './match-disp'
 
 class MatchList extends React.Component {
+
   render () {
-    const filter = this.props.filters.date
+    const matches = this.props.match.matches
+    const filtered = this.props.match.filtered
+
     return (
       <div>
-        <h2>Matches</h2>
+        <h2>Matches ({filtered.length}/{matches.length})</h2>
         <ul>
-          {this.props.matches.filter((match) =>
-            (filter === 'Alle' | match.DatumString === filter)
-          ).map((match, key) => (
+          {filtered.map((match, key) => (
             <MatchDisp key={key} match={match} />
           ))}
         </ul>

+ 11 - 3
src/match/index.js

@@ -6,7 +6,7 @@ function normalize (item, type) {
 }
 
 /** Class representing a player */
-class Match {
+class MatchClass {
   /**
    * Create a player
    * A player data item in the Swisstennis PlayerList.xlsx file has the following columns
@@ -16,7 +16,7 @@ class Match {
     this.Ort = normalize(data[0])
     this.Datum = data[1]
     this.DatumString = data[1] ? moment(data[1]).format('DD.MM.') : null
-    this.ZeitString = data[1] ? moment(data[1]).format('hh:mm') : null
+    this.ZeitString = data[1] ? moment(data[1]).format('HH:mm') : null
     this.Konkurrenz = normalize(data[3])
     this.Spieler1 = normalize(data[4])
     this.Spieler1Klassierung = normalize(data[5])
@@ -29,4 +29,12 @@ class Match {
   }
 }
 
-export default { Match, components }
+const state = {
+  matches: [],
+  filtered: [],
+  places: [],
+  dates: [],
+  categories: []
+}
+
+export default { MatchClass, components, state }

+ 5 - 2
src/player/components/player-list.js

@@ -2,12 +2,15 @@ import React from 'react'
 import PlayerDisp from './player-disp'
 
 class PlayerList extends React.Component {
+
   render () {
+    const filtered = this.props.player.filtered
+
     return (
       <div>
-        <h2>Spielerliste</h2>
+        <h2>Spielerliste ({filtered.length})</h2>
         <ul>
-          {this.props.players.map((player, key) => (
+          {filtered.map((player, key) => (
             <PlayerDisp key={key} player={player} />
           ))}
         </ul>

+ 9 - 3
src/player/index.js

@@ -4,6 +4,12 @@ function normalize (item, type) {
   return item ? String(item).replace(/\s+/g, ' ').trim() : null
 }
 
+const state = {
+  players: [],
+  filtered: [],
+  categories: []
+}
+
 /** Class representing a player */
 class Player {
   /**
@@ -26,8 +32,8 @@ class Player {
     this.VornameDP = normalize(data[25])
     this.GeburtsdatumDP = data[26]
     this.KlassierungDP = normalize(data[27])
-    this.Bestaetigt = data[29] === 'TRUE'
-    this.Bezahlt = data[31] === 'TRUE'
+    this.Bestaetigt = data[29]
+    this.Bezahlt = data[31]
   }
 
   isDoubles () {
@@ -51,4 +57,4 @@ class Player {
   }
 }
 
-export default { Player, components }
+export default { Player, components, state }

+ 139 - 353
yarn.lock

@@ -17,7 +17,7 @@ abbrev@1:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
 
-accepts@1.3.3, accepts@~1.3.3:
+accepts@~1.3.3:
   version "1.3.3"
   resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
   dependencies:
@@ -58,7 +58,7 @@ address@1.0.1, address@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/address/-/address-1.0.1.tgz#363f5d3f2be26d0655d8afd5a9562e4fc2194537"
 
-adler-32@, adler-32@~1.0.0:
+adler-32@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.0.0.tgz#28728a71756f629666dd1653cd80793a9df18651"
   dependencies:
@@ -66,10 +66,6 @@ adler-32@, adler-32@~1.0.0:
     exit-on-epipe ""
     printj ""
 
-after@0.8.2:
-  version "0.8.2"
-  resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
-
 ajv-keywords@^1.0.0, ajv-keywords@^1.1.1:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
@@ -231,10 +227,6 @@ array-unique@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
 
-arraybuffer.slice@0.0.6:
-  version "0.0.6"
-  resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca"
-
 arrify@^1.0.0, arrify@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
@@ -281,16 +273,12 @@ async@^1.4.0, async@^1.5.2:
   version "1.5.2"
   resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
 
-async@^2.1.2, async@^2.1.4, async@latest:
+async@^2.1.2, async@^2.1.4:
   version "2.4.1"
   resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7"
   dependencies:
     lodash "^4.14.0"
 
-async@~0.2.6:
-  version "0.2.10"
-  resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
-
 asynckit@^0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -964,26 +952,14 @@ babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0, babylon@^6.17.0:
   version "6.17.2"
   resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.2.tgz#201d25ef5f892c41bae49488b08db0dd476e9f5c"
 
-backo2@1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
-
 balanced-match@^0.4.1, balanced-match@^0.4.2:
   version "0.4.2"
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
 
-base64-arraybuffer@0.1.5:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
-
 base64-js@^1.0.2:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
 
-base64id@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
-
 batch@0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
@@ -994,12 +970,6 @@ bcrypt-pbkdf@^1.0.0:
   dependencies:
     tweetnacl "^0.14.3"
 
-better-assert@~1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
-  dependencies:
-    callsite "1.0.0"
-
 big.js@^3.1.3:
   version "3.1.3"
   resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
@@ -1008,7 +978,7 @@ binary-extensions@^1.0.0:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
 
-blob@0.0.4, blob@^0.0.4:
+blob@^0.0.4:
   version "0.0.4"
   resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921"
 
@@ -1182,10 +1152,6 @@ caller-path@^0.1.0:
   dependencies:
     callsites "^0.2.0"
 
-callsite@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
-
 callsites@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
@@ -1256,7 +1222,7 @@ center-align@^0.1.1:
     align-text "^0.1.3"
     lazy-cache "^1.0.3"
 
-cfb@>=0.10.0, cfb@~0.11.0, cfb@~0.11.1:
+cfb@~0.11.1:
   version "0.11.1"
   resolved "https://registry.yarnpkg.com/cfb/-/cfb-0.11.1.tgz#a96db8f272a6c3fb99dbbb23ef41223f48be1ea7"
   dependencies:
@@ -1367,7 +1333,7 @@ code-point-at@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
 
-codepage@, codepage@~1.8.0:
+codepage@~1.8.0:
   version "1.8.1"
   resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.8.1.tgz#f1a009d5261dc2754628bacb6fbbf0e6e2abffaa"
   dependencies:
@@ -1376,14 +1342,6 @@ codepage@, codepage@~1.8.0:
     exit-on-epipe ""
     voc ""
 
-codepage@~1.3.6:
-  version "1.3.8"
-  resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.3.8.tgz#4f2e5d7c0975de28f88498058dcb5afcab6a5f71"
-  dependencies:
-    commander ""
-    concat-stream ""
-    voc ""
-
 color-convert@^1.0.0, color-convert@^1.3.0:
   version "1.9.0"
   resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
@@ -1440,22 +1398,6 @@ commondir@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
 
-component-bind@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
-
-component-emitter@1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3"
-
-component-emitter@1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
-
-component-inherit@0.0.3:
-  version "0.0.3"
-  resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
-
 compressible@~2.0.8:
   version "2.0.10"
   resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd"
@@ -1569,7 +1511,7 @@ cosmiconfig@^2.1.0, cosmiconfig@^2.1.1:
     parse-json "^2.2.0"
     require-from-string "^1.1.0"
 
-crc-32@, crc-32@~1.0.2:
+crc-32@~1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.0.2.tgz#09507984ee9bcce3bd1b8861f0de8ab10ae8187d"
   dependencies:
@@ -1680,6 +1622,12 @@ css-what@2.1:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd"
 
+cssauron@^1.1.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8"
+  dependencies:
+    through X.X.X
+
 cssesc@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
@@ -1770,12 +1718,6 @@ debug@2.2.0, debug@~2.2.0:
   dependencies:
     ms "0.7.1"
 
-debug@2.3.3, debug@^2.1.1, debug@^2.2.0:
-  version "2.3.3"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c"
-  dependencies:
-    ms "0.7.2"
-
 debug@2.6.7:
   version "2.6.7"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e"
@@ -1788,6 +1730,12 @@ debug@2.6.8, debug@^2.6.0, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8:
   dependencies:
     ms "2.0.0"
 
+debug@^2.1.1, debug@^2.2.0:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c"
+  dependencies:
+    ms "0.7.2"
+
 decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -1958,16 +1906,16 @@ duplexer2@^0.1.4:
   dependencies:
     readable-stream "^2.0.2"
 
+duplexer2@~0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"
+  dependencies:
+    readable-stream "~1.1.9"
+
 duplexer@^0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
 
-easy-zip@~0.0.4:
-  version "0.0.4"
-  resolved "https://registry.yarnpkg.com/easy-zip/-/easy-zip-0.0.4.tgz#b2da37d6750221860aaef0168de912ebfe957d93"
-  dependencies:
-    async latest
-
 ecc-jsbn@~0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
@@ -2012,45 +1960,6 @@ encoding@^0.1.11:
   dependencies:
     iconv-lite "~0.4.13"
 
-engine.io-client@~1.8.4:
-  version "1.8.4"
-  resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.4.tgz#9fe85dee25853ca6babe25bd2ad68710863e91c2"
-  dependencies:
-    component-emitter "1.2.1"
-    component-inherit "0.0.3"
-    debug "2.3.3"
-    engine.io-parser "1.3.2"
-    has-cors "1.1.0"
-    indexof "0.0.1"
-    parsejson "0.0.3"
-    parseqs "0.0.5"
-    parseuri "0.0.5"
-    ws "1.1.2"
-    xmlhttprequest-ssl "1.5.3"
-    yeast "0.1.2"
-
-engine.io-parser@1.3.2:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.2.tgz#937b079f0007d0893ec56d46cb220b8cb435220a"
-  dependencies:
-    after "0.8.2"
-    arraybuffer.slice "0.0.6"
-    base64-arraybuffer "0.1.5"
-    blob "0.0.4"
-    has-binary "0.1.7"
-    wtf-8 "1.0.0"
-
-engine.io@~1.8.4:
-  version "1.8.4"
-  resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.4.tgz#77bce12b80e5d60429337fec3b0daf691ebc9003"
-  dependencies:
-    accepts "1.3.3"
-    base64id "1.0.0"
-    cookie "0.3.1"
-    debug "2.3.3"
-    engine.io-parser "1.3.2"
-    ws "1.1.4"
-
 enhanced-resolve@^3.0.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec"
@@ -2632,10 +2541,6 @@ forwarded@~0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363"
 
-frac@0.3.1:
-  version "0.3.1"
-  resolved "https://registry.yarnpkg.com/frac/-/frac-0.3.1.tgz#577677b7fdcbe6faf7c461f1801d34137cda4354"
-
 frac@~1.0.6:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/frac/-/frac-1.0.6.tgz#9a0dfc23956852a8b320623bebcf1be9ea048229"
@@ -2664,15 +2569,6 @@ fs-extra@^0.30.0:
     path-is-absolute "^1.0.0"
     rimraf "^2.2.8"
 
-fs-extra@~0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.5.0.tgz#34646dc62c97fa13b1024946bf4174e8c0f05ca4"
-  dependencies:
-    jsonfile "0.0.x"
-    mkdirp "0.3.x"
-    ncp "0.2.x"
-    rimraf "~2.1.2"
-
 fs.realpath@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -2805,10 +2701,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
   version "4.1.11"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
 
-graceful-fs@~1:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364"
-
 "graceful-readlink@>= 1.0.0":
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
@@ -2854,16 +2746,6 @@ has-ansi@^2.0.0:
   dependencies:
     ansi-regex "^2.0.0"
 
-has-binary@0.1.7:
-  version "0.1.7"
-  resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c"
-  dependencies:
-    isarray "0.0.1"
-
-has-cors@1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
-
 has-flag@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
@@ -2949,6 +2831,14 @@ html-entities@1.2.1, html-entities@^1.2.0:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
 
+html-inline@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/html-inline/-/html-inline-1.2.0.tgz#7854946a6f5c3122b993b81d3d37d6bd0600bec1"
+  dependencies:
+    minimist "~1.1.0"
+    through2 "~0.6.3"
+    trumpet "~1.7.0"
+
 html-minifier@^3.2.3:
   version "3.5.2"
   resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.2.tgz#d73bc3ff448942408818ce609bf3fb0ea7ef4eb7"
@@ -2962,6 +2852,28 @@ html-minifier@^3.2.3:
     relateurl "0.2.x"
     uglify-js "3.0.x"
 
+html-select@^2.3.5:
+  version "2.3.24"
+  resolved "https://registry.yarnpkg.com/html-select/-/html-select-2.3.24.tgz#46ad6d712e732cf31c6739d5d0110a5fabf17585"
+  dependencies:
+    cssauron "^1.1.0"
+    duplexer2 "~0.0.2"
+    inherits "^2.0.1"
+    minimist "~0.0.8"
+    readable-stream "^1.0.27-1"
+    split "~0.3.0"
+    stream-splicer "^1.2.0"
+    through2 "^1.0.0"
+
+html-tokenize@^1.1.1:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/html-tokenize/-/html-tokenize-1.2.5.tgz#7e5ba99ecb51ef906ec9a7fcdee6ca3267c7897e"
+  dependencies:
+    inherits "~2.0.1"
+    minimist "~0.0.8"
+    readable-stream "~1.0.27-1"
+    through2 "~0.4.1"
+
 html-webpack-plugin@2.28.0:
   version "2.28.0"
   resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-2.28.0.tgz#2e7863b57e5fd48fe263303e2ffc934c3064d009"
@@ -3068,7 +2980,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
+inherits@2, inherits@2.0.3, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
 
@@ -3331,7 +3243,7 @@ is-wsl@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
 
-isarray@0.0.1:
+isarray@0.0.1, isarray@~0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
 
@@ -3714,7 +3626,7 @@ json-stringify-safe@~5.0.1:
   version "5.0.1"
   resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
 
-json3@3.3.2, json3@^3.3.2:
+json3@^3.3.2:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
 
@@ -3722,10 +3634,6 @@ json5@^0.5.0, json5@^0.5.1:
   version "0.5.1"
   resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
 
-jsonfile@0.0.x:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-0.0.1.tgz#b5f9f515121b2844f2cbfe14338b55c79800e1d8"
-
 jsonfile@^2.1.0:
   version "2.4.0"
   resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8"
@@ -3759,12 +3667,6 @@ jsx-ast-utils@^1.3.4, jsx-ast-utils@^1.4.0:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"
 
-jszip@2.4.0:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/jszip/-/jszip-2.4.0.tgz#487a93b76c3bffa6cb085cd61eb934eabe2d294f"
-  dependencies:
-    pako "~0.2.5"
-
 kind-of@^3.0.2:
   version "3.2.2"
   resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
@@ -4053,7 +3955,7 @@ minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
   dependencies:
     brace-expansion "^1.1.7"
 
-minimist@0.0.8, minimist@~0.0.1:
+minimist@0.0.8, minimist@~0.0.1, minimist@~0.0.8:
   version "0.0.8"
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
 
@@ -4061,9 +3963,9 @@ minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
 
-mkdirp@0.3.x:
-  version "0.3.5"
-  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7"
+minimist@~1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8"
 
 mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
   version "0.5.1"
@@ -4087,15 +3989,6 @@ ms@2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
 
-msexcel-builder@^0.0.2:
-  version "0.0.2"
-  resolved "https://registry.yarnpkg.com/msexcel-builder/-/msexcel-builder-0.0.2.tgz#dec552f0fb6f3bf368e5bd32bd926535677b03d0"
-  dependencies:
-    async "~0.2.6"
-    easy-zip "~0.0.4"
-    fs-extra "~0.5.0"
-    xmlbuilder ">=0.4.2"
-
 mute-stream@0.0.5:
   version "0.0.5"
   resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
@@ -4118,10 +4011,6 @@ ncname@1.0.x:
   dependencies:
     xml-char-classes "^1.0.0"
 
-ncp@0.2.x:
-  version "0.2.7"
-  resolved "https://registry.yarnpkg.com/ncp/-/ncp-0.2.7.tgz#46fac2b7dda2560a4cb7e628677bd5f64eac5be1"
-
 negotiator@0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
@@ -4264,18 +4153,10 @@ oauth-sign@~0.8.1:
   version "0.8.2"
   resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
 
-object-assign@4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
-
 object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
 
-object-component@0.0.3:
-  version "0.0.3"
-  resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
-
 object-hash@^1.1.4:
   version "1.1.8"
   resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.8.tgz#28a659cf987d96a4dabe7860289f3b5326c4a03c"
@@ -4284,6 +4165,10 @@ object-keys@^1.0.8:
   version "1.0.11"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
 
+object-keys@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336"
+
 object.omit@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
@@ -4295,13 +4180,6 @@ obuf@^1.0.0, obuf@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e"
 
-ods@^1.1.7:
-  version "1.1.7"
-  resolved "https://registry.yarnpkg.com/ods/-/ods-1.1.7.tgz#e5884292ab782c8bcf160f9f940c399795985152"
-  dependencies:
-    socket.io "^1.3.5"
-    typescript-require "^0.2.8"
-
 on-finished@~2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
@@ -4359,10 +4237,6 @@ optionator@^0.8.1, optionator@^0.8.2:
     type-check "~0.3.2"
     wordwrap "~1.0.0"
 
-options@>=0.0.5:
-  version "0.0.6"
-  resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f"
-
 original@>=0.0.5:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b"
@@ -4417,7 +4291,7 @@ package-json@^2.0.0:
     registry-url "^3.0.3"
     semver "^5.1.0"
 
-pako@~0.2.0, pako@~0.2.5:
+pako@~0.2.0:
   version "0.2.9"
   resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
 
@@ -4456,24 +4330,6 @@ parse5@^1.5.1:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
 
-parsejson@0.0.3:
-  version "0.0.3"
-  resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab"
-  dependencies:
-    better-assert "~1.0.0"
-
-parseqs@0.0.5:
-  version "0.0.5"
-  resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
-  dependencies:
-    better-assert "~1.0.0"
-
-parseuri@0.0.5:
-  version "0.0.5"
-  resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
-  dependencies:
-    better-assert "~1.0.0"
-
 parseurl@~1.3.1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56"
@@ -5127,7 +4983,7 @@ read-pkg@^1.0.0:
     normalize-package-data "^2.3.2"
     path-type "^1.0.0"
 
-readable-stream@1.0:
+readable-stream@1.0, "readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@^1.0.27-1, readable-stream@~1.0.17, readable-stream@~1.0.27-1:
   version "1.0.34"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
   dependencies:
@@ -5136,6 +4992,15 @@ readable-stream@1.0:
     isarray "0.0.1"
     string_decoder "~0.10.x"
 
+"readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.1.13-1, readable-stream@~1.1.9:
+  version "1.1.14"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
 readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6, readable-stream@^2.2.9:
   version "2.2.11"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
@@ -5148,6 +5013,12 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable
     string_decoder "~1.0.0"
     util-deprecate "~1.0.1"
 
+readable-wrap@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/readable-wrap/-/readable-wrap-1.0.0.tgz#3b5a211c631e12303a54991c806c17e7ae206bff"
+  dependencies:
+    readable-stream "^1.1.13-1"
+
 readdirp@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
@@ -5382,12 +5253,6 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1:
   dependencies:
     glob "^7.0.5"
 
-rimraf@~2.1.2:
-  version "2.1.4"
-  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2"
-  optionalDependencies:
-    graceful-fs "~1"
-
 ripemd160@^2.0.0, ripemd160@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
@@ -5571,50 +5436,6 @@ sntp@1.x.x:
   dependencies:
     hoek "2.x.x"
 
-socket.io-adapter@0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b"
-  dependencies:
-    debug "2.3.3"
-    socket.io-parser "2.3.1"
-
-socket.io-client@1.7.4:
-  version "1.7.4"
-  resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.4.tgz#ec9f820356ed99ef6d357f0756d648717bdd4281"
-  dependencies:
-    backo2 "1.0.2"
-    component-bind "1.0.0"
-    component-emitter "1.2.1"
-    debug "2.3.3"
-    engine.io-client "~1.8.4"
-    has-binary "0.1.7"
-    indexof "0.0.1"
-    object-component "0.0.3"
-    parseuri "0.0.5"
-    socket.io-parser "2.3.1"
-    to-array "0.1.4"
-
-socket.io-parser@2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0"
-  dependencies:
-    component-emitter "1.1.2"
-    debug "2.2.0"
-    isarray "0.0.1"
-    json3 "3.3.2"
-
-socket.io@^1.3.5:
-  version "1.7.4"
-  resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.4.tgz#2f7ecedc3391bf2d5c73e291fe233e6e34d4dd00"
-  dependencies:
-    debug "2.3.3"
-    engine.io "~1.8.4"
-    has-binary "0.1.7"
-    object-assign "4.1.0"
-    socket.io-adapter "0.5.0"
-    socket.io-client "1.7.4"
-    socket.io-parser "2.3.1"
-
 sockjs-client@1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.2.tgz#f0212a8550e4c9468c8cceaeefd2e3493c033ad5"
@@ -5717,18 +5538,16 @@ spdy@^3.4.1:
     select-hose "^2.0.0"
     spdy-transport "^2.0.18"
 
+split@~0.3.0:
+  version "0.3.3"
+  resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f"
+  dependencies:
+    through "2"
+
 sprintf-js@~1.0.2:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
 
-ssf@~0.8.1:
-  version "0.8.2"
-  resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.8.2.tgz#b9d4dc6a1c1bcf76f8abfa96d7d7656fb2abecd6"
-  dependencies:
-    colors "0.6.2"
-    frac "0.3.1"
-    voc ""
-
 ssf@~0.9.3:
   version "0.9.3"
   resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.9.3.tgz#42da2bdf99fcbde1b62b3ca58f00aa1f097a764e"
@@ -5772,6 +5591,17 @@ stream-http@^2.3.1:
     to-arraybuffer "^1.0.0"
     xtend "^4.0.0"
 
+stream-splicer@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-1.3.2.tgz#3c0441be15b9bf4e226275e6dc83964745546661"
+  dependencies:
+    indexof "0.0.1"
+    inherits "^2.0.1"
+    isarray "~0.0.1"
+    readable-stream "^1.1.13-1"
+    readable-wrap "^1.0.0"
+    through2 "^1.0.0"
+
 strict-uri-encode@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
@@ -5955,7 +5785,28 @@ throat@^3.0.0:
   dependencies:
     double-ended-queue "^2.1.0-0"
 
-through@^2.3.6:
+through2@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545"
+  dependencies:
+    readable-stream ">=1.1.13-1 <1.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+through2@~0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b"
+  dependencies:
+    readable-stream "~1.0.17"
+    xtend "~2.1.1"
+
+through2@~0.6.3:
+  version "0.6.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
+  dependencies:
+    readable-stream ">=1.0.33-1 <1.1.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+through@2, through@X.X.X, through@^2.3.6:
   version "2.3.8"
   resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
 
@@ -5979,10 +5830,6 @@ tmpl@1.0.x:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
 
-to-array@0.1.4:
-  version "0.1.4"
-  resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
-
 to-arraybuffer@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
@@ -6013,6 +5860,17 @@ trim-right@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
 
+trumpet@~1.7.0:
+  version "1.7.2"
+  resolved "https://registry.yarnpkg.com/trumpet/-/trumpet-1.7.2.tgz#b02c69e465d171f55e44924bf9b5bdd20974c830"
+  dependencies:
+    duplexer2 "~0.0.2"
+    html-select "^2.3.5"
+    html-tokenize "^1.1.1"
+    inherits "^2.0.0"
+    readable-stream "^1.0.27-1"
+    through2 "^1.0.0"
+
 tryit@^1.0.1:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
@@ -6048,16 +5906,6 @@ typedarray@^0.0.6:
   version "0.0.6"
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
 
-typescript-require@^0.2.8:
-  version "0.2.9"
-  resolved "https://registry.yarnpkg.com/typescript-require/-/typescript-require-0.2.9.tgz#796e0654d6dcd161a4929bb194659882d5675216"
-  dependencies:
-    typescript ">= 0.8.2"
-
-"typescript@>= 0.8.2":
-  version "2.3.4"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.4.tgz#3d38321828231e434f287514959c37a82b629f42"
-
 ua-parser-js@^0.7.9:
   version "0.7.12"
   resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
@@ -6086,10 +5934,6 @@ uid-number@^0.0.6:
   version "0.0.6"
   resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
 
-ultron@1.0.x:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
-
 uniq@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
@@ -6413,10 +6257,6 @@ wordwrap@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
 
-workbook@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/workbook/-/workbook-1.1.3.tgz#4029c91409351d18c569c46c999eabb1879f58bb"
-
 worker-farm@^1.3.1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
@@ -6449,48 +6289,12 @@ write@^0.2.1:
   dependencies:
     mkdirp "^0.5.1"
 
-ws@1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f"
-  dependencies:
-    options ">=0.0.5"
-    ultron "1.0.x"
-
-ws@1.1.4:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61"
-  dependencies:
-    options ">=0.0.5"
-    ultron "1.0.x"
-
-wtf-8@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a"
-
 xdg-basedir@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2"
   dependencies:
     os-homedir "^1.0.0"
 
-xlsx-style@^0.8.13:
-  version "0.8.13"
-  resolved "https://registry.yarnpkg.com/xlsx-style/-/xlsx-style-0.8.13.tgz#ed238d6b8c0562f9447c2906abbded2d339e0486"
-  dependencies:
-    adler-32 ""
-    cfb ">=0.10.0"
-    codepage "~1.3.6"
-    commander ""
-    crc-32 ""
-    jszip "2.4.0"
-    ssf "~0.8.1"
-
-xlsx-workbook@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/xlsx-workbook/-/xlsx-workbook-1.0.3.tgz#27d9f8390d634f3b3d29eeb317a00d4b18a479bf"
-  dependencies:
-    xlsx "^0.8.0"
-
 xlsx@^0.10.4:
   version "0.10.4"
   resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.10.4.tgz#18a2b54a5ab4a472894416463fcbd02a767c685e"
@@ -6503,18 +6307,6 @@ xlsx@^0.10.4:
     exit-on-epipe "~1.0.0"
     ssf "~0.9.3"
 
-xlsx@^0.8.0:
-  version "0.8.8"
-  resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.8.8.tgz#b92d76e0b5e4f060c9208d4b744756510443853a"
-  dependencies:
-    adler-32 ""
-    cfb "~0.11.0"
-    codepage ""
-    commander ""
-    crc-32 ""
-    exit-on-epipe ""
-    ssf "~0.8.1"
-
 xml-char-classes@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d"
@@ -6523,18 +6315,16 @@ xml-name-validator@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
 
-xmlbuilder@>=0.4.2:
-  version "9.0.0"
-  resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.0.tgz#a9311b3f8509345700c49a8f79be06bcc5988d18"
-
-xmlhttprequest-ssl@1.5.3:
-  version "1.5.3"
-  resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d"
-
 "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
 
+xtend@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b"
+  dependencies:
+    object-keys "~0.4.0"
+
 y18n@^3.2.1:
   version "3.2.1"
   resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
@@ -6599,7 +6389,3 @@ yargs@~3.10.0:
     cliui "^2.1.0"
     decamelize "^1.0.0"
     window-size "0.1.0"
-
-yeast@0.1.2:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"