changeset 317:cddc1cc19d8d

Merge pull request #36 from LucasThompson/dev/tracks-shape Dev/tracks shape
author Lucas Thompson <LucasThompson@users.noreply.github.com>
date Fri, 12 May 2017 17:20:31 +0100
parents f16705a58887 (current diff) 98490d0ceb77 (diff)
children 2e6f7b2c887f dcb015c5a845
files
diffstat 8 files changed, 367 insertions(+), 289 deletions(-) [+]
line wrap: on
line diff
--- a/package.json	Wed May 10 13:22:30 2017 +0100
+++ b/package.json	Fri May 12 17:20:31 2017 +0100
@@ -24,14 +24,14 @@
     "@angular/router": "^4.0.0",
     "core-js": "^2.4.1",
     "hammerjs": "^2.0.8",
-    "piper": "github:piper-audio/piper-js",
+    "piper": "piper-audio/piper-js",
     "requirejs": "^2.3.3",
-    "rxjs": "^5.1.0",
+    "rxjs": "^5.4.0",
     "waves-ui-piper": "piper-audio/waves-ui-piper",
     "zone.js": "0.8.7"
   },
   "devDependencies": {
-    "@angular/cli": "1.0.1",
+    "@angular/cli": "1.0.3",
     "@angular/compiler-cli": "^4.0.0",
     "@types/hammerjs": "^2.0.34",
     "@types/jasmine": "2.5.38",
--- a/src/app/services/feature-extraction/FeatureExtractionWorker.ts	Wed May 10 13:22:30 2017 +0100
+++ b/src/app/services/feature-extraction/FeatureExtractionWorker.ts	Fri May 12 17:20:31 2017 +0100
@@ -63,11 +63,7 @@
     return this.dispatch('process', request);
   }
 
-  collect(request: SimpleRequest): Observable<StreamingResponse> {
-    return this.dispatch('collect', request);
-  }
-
-  protected dispatch(method: 'process' | 'collect',
+  protected dispatch(method: 'process',
                      request: SimpleRequest): Observable<StreamingResponse> {
     const key = request.key.split(':')[0];
     return this.services.has(key) ?
@@ -80,19 +76,27 @@
     super();
   }
 
-  protected dispatch(method: 'process' | 'collect',
+  protected dispatch(method: 'process',
                      request: SimpleRequest): Observable<StreamingResponse> {
     let lastPercentagePoint = 0;
+    let shouldClear = false;
     return super.dispatch(method, request)
-      .scan(streamingResponseReducer)
+      .scan((acc, value) => {
+        if (shouldClear) {
+          acc.features = [];
+        }
+        return streamingResponseReducer(acc, value);
+      })
       .filter(val => {
+        const progress = val.progress;
         const percentage =
-          100 * (val.processedBlockCount / val.totalBlockCount) | 0;
+          100 * (progress.processedBlockCount / progress.totalBlockCount) | 0;
         const pointDifference = (percentage - lastPercentagePoint);
         const shouldEmit = pointDifference === 1 || percentage === 100;
         if (shouldEmit) {
           lastPercentagePoint = percentage;
         }
+        shouldClear = shouldEmit;
         return shouldEmit;
       });
   }
--- a/src/app/services/feature-extraction/FeatureReducers.ts	Wed May 10 13:22:30 2017 +0100
+++ b/src/app/services/feature-extraction/FeatureReducers.ts	Fri May 12 17:20:31 2017 +0100
@@ -2,11 +2,12 @@
  * Created by lucast on 26/04/2017.
  */
 import {StreamingResponse} from 'piper/StreamingService';
-import {Feature} from 'piper/Feature';
-import {SampleType} from 'piper';
 
 export const arrayReducer = <T>(acc: T[], val: T[]): T[] => {
-  acc.push.apply(acc, val);
+  const len = val.length;
+  for (let i = 0; i < len; ++i) {
+    acc.push(val[i]);
+  }
   return acc;
 };
 
@@ -23,41 +24,12 @@
 };
 
 export const streamingResponseReducer = (acc: StreamingResponse,
-                                         val: StreamingResponse,
-                                         i: number): StreamingResponse => {
-  acc.processedBlockCount = val.processedBlockCount;
-  if (acc.features.data instanceof Array &&
-    val.features.data instanceof Array) {
-    acc.features.data = arrayReducer<Feature>(
-      acc.features.data,
-      val.features.data
-    );
-  } else if (acc.features.data instanceof Float32Array &&
-    val.features.data instanceof Float32Array) {
-    const isOneSamplePerStep = acc.outputDescriptor.configured.sampleType ===
-      SampleType.OneSamplePerStep;
-    if (isOneSamplePerStep) {
-      // for one sample per step vectors we know there will be totalBlockCount
-      // number of samples - so pre-allocate the Float32Array when we know
-      // the totalBlockCount (after receiving the first feature)
-      if ( i === 1  ) {
-        const newBlock = new Float32Array(acc.totalBlockCount);
-        newBlock[0] = acc.features.data[0];
-        acc.features.data = newBlock;
-      }
-      acc.features.data = inPlaceTypedArrayReducer(
-        acc.features.data,
-        val.features.data,
-        i
-      );
-    } else { // if not OneSamplePerStep we have to make a new array each time
-      acc.features.data = typedArrayReducer(
-        acc.features.data,
-        val.features.data
-      );
-    }
-  } else {
-    throw new Error('Invalid feature output. Aborting');
+                                         val: StreamingResponse):
+  StreamingResponse => {
+  acc.progress = val.progress;
+  if (val.configuration) {
+    acc.configuration = val.configuration;
   }
+  arrayReducer(acc.features, val.features);
   return acc;
 };
--- a/src/app/services/feature-extraction/feature-extraction.service.ts	Wed May 10 13:22:30 2017 +0100
+++ b/src/app/services/feature-extraction/feature-extraction.service.ts	Fri May 12 17:20:31 2017 +0100
@@ -14,6 +14,7 @@
   WebWorkerStreamingClient
 } from 'piper/client-stubs/WebWorkerStreamingClient';
 import {RequestId} from 'piper/protocols/WebWorkerProtocol';
+import {collect, StreamingConfiguration} from 'piper/StreamingService';
 
 type RepoUri = string;
 export interface AvailableLibraries {
@@ -66,19 +67,24 @@
   }
 
   extract(analysisItemId: string, request: SimpleRequest): Promise<void> {
-    return this.client.collect(request)
-      .do(val => {
-        if (val.totalBlockCount > 0) {
-          this.progressUpdated.next({
-            id: analysisItemId,
-            value: (val.processedBlockCount / val.totalBlockCount) * 100
-          });
-        }
-      })
-      .toPromise()
-      .then((response) => {
-        this.featuresExtracted.next(response);
+    let config: StreamingConfiguration;
+    return collect(this.client.process(request), val => {
+      if (val.configuration) {
+        config = val.configuration;
+      }
+      const progress = val.progress;
+      if (progress.totalBlockCount > 0) {
+        this.progressUpdated.next({
+          id: analysisItemId,
+          value: (progress.processedBlockCount / progress.totalBlockCount) * 100
+        });
+      }
+    }).then(features => {
+      this.featuresExtracted.next({
+        features: features,
+        outputDescriptor: config.outputDescriptor
       });
+    });
   }
 
   updateAvailableLibraries(): Observable<AvailableLibraries> {
--- a/src/app/waveform/waveform.component.ts	Wed May 10 13:22:30 2017 +0100
+++ b/src/app/waveform/waveform.component.ts	Fri May 12 17:20:31 2017 +0100
@@ -20,8 +20,10 @@
 import {Subscription} from 'rxjs/Subscription';
 import {
   FeatureCollection,
-  FixedSpacedFeatures,
-  SimpleResponse
+  SimpleResponse,
+  VectorFeature,
+  MatrixFeature,
+  TracksFeature
 } from 'piper/HigherLevelUtilities';
 import {toSeconds} from 'piper';
 import {FeatureList, Feature} from 'piper/Feature';
@@ -387,7 +389,7 @@
           isZooming = false;
           zoomGestureJustEnded = true;
         }
-       });
+      });
       element.addEventListener('touchmove', zoom);
     }
     // this.timeline.createTrack(track, height/2, `wave-${this.trackIdPrefix}`);
@@ -423,17 +425,17 @@
     }
     if (sample.length === 0) {
       console.log('WARNING: No samples gathered, even though we hoped for ' +
-                  (m_per * w) + ' of them');
+        (m_per * w) + ' of them');
       return 0.0;
     }
     sample.sort((a, b) => { return a - b; });
     const ix = Math.floor((sample.length * percentile) / 100);
     console.log('Estimating ' + percentile + '-%ile of ' +
-                n + '-sample dataset (' + w + ' x ' + h + ') as value ' + ix +
-                ' of sorted ' + sample.length + '-sample subset');
+      n + '-sample dataset (' + w + ' x ' + h + ') as value ' + ix +
+      ' of sorted ' + sample.length + '-sample subset');
     const estimate = sample[ix];
     console.log('Estimate is: ' + estimate + ' (where min sampled value = ' +
-                sample[0] + ' and max = ' + sample[sample.length - 1] + ')');
+      sample[0] + ' and max = ' + sample[sample.length - 1] + ')');
     return estimate;
   }
 
@@ -441,8 +443,8 @@
     const colours = hexColours.map(n => {
       const i = parseInt(n, 16);
       return [ ((i >> 16) & 255) / 255.0,
-               ((i >> 8) & 255) / 255.0,
-               ((i) & 255) / 255.0 ];
+        ((i >> 8) & 255) / 255.0,
+        ((i) & 255) / 255.0 ];
     });
     const last = colours.length - 1;
     return (value => {
@@ -459,8 +461,8 @@
       const c0 = colours[base];
       const c1 = colours[base + 1];
       return [ c0[0] * prop0 + c1[0] * prop1,
-               c0[1] * prop0 + c1[1] * prop1,
-               c0[2] * prop0 + c1[2] * prop1 ];
+        c0[1] * prop0 + c1[1] * prop1,
+        c0[2] * prop0 + c1[2] * prop1 ];
     });
   }
 
@@ -482,12 +484,12 @@
     const t = v * (1 - (1 - f) * s);
     let r = 0, g = 0, b = 0;
     switch (i % 6) {
-        case 0: r = v; g = t; b = p; break;
-        case 1: r = q; g = v; b = p; break;
-        case 2: r = p; g = v; b = t; break;
-        case 3: r = p; g = q; b = v; break;
-        case 4: r = t; g = p; b = v; break;
-        case 5: r = v; g = p; b = q; break;
+      case 0: r = v; g = t; b = p; break;
+      case 1: r = q; g = v; b = p; break;
+      case 2: r = p; g = v; b = t; break;
+      case 3: r = p; g = q; b = v; break;
+      case 4: r = t; g = p; b = v; break;
+      case 5: r = v; g = p; b = q; break;
     }
     return [ r, g, b ];
   }
@@ -607,6 +609,106 @@
     this.timeline.tracks.update();
   }
 
+  private addLineLayers(features: VectorFeature[],
+                        unit: string,
+                        colour: Colour) {
+
+    // Winnow out empty features
+    features = features.filter(feature => (feature.data.length > 0));
+
+    // First establish a [min,max] range across all of the features
+    let [min, max] = features.reduce((acc, feature) => {
+      return feature.data.reduce((acc, val) => {
+        const [min, max] = acc;
+        return [Math.min (min, val), Math.max (max, val)];
+      }, acc);
+    }, [Infinity, -Infinity]);
+
+    console.log('addLineLayers: ' + features.length + ' non-empty features, overall min = ' + min + ', max = ' + max);
+
+    if (min === Infinity) {
+      min = 0;
+      max = 1;
+    }
+
+    if (min !== min || max !== max) {
+      console.log('WARNING: min or max is NaN');
+      min = 0;
+      max = 1;
+    }
+
+    const height = this.trackDiv.nativeElement.getBoundingClientRect().height;
+    const waveTrack = this.timeline.getTrackById(`wave-${this.trackIdPrefix}`);
+
+    // Now add a line layer for each vector feature
+    const lineLayers = features.map(feature => {
+
+      let duration = 0;
+
+      // Give the plot items positions relative to the start of the
+      // line, rather than relative to absolute time 0. This is
+      // because we'll be setting the layer timeline start property
+      // later on and these will be positioned relative to that
+
+      const plotData = [...feature.data].map((val, i) => {
+        const t = i * feature.stepDuration;
+        duration = t + feature.stepDuration;
+        return {
+          cx: t,
+          cy: val
+        };
+      });
+
+      const lineLayer = new wavesUI.helpers.LineLayer(plotData, {
+        color: colour,
+        height: height,
+        yDomain: [ min, max ]
+      });
+      this.addLayer(
+        lineLayer,
+        waveTrack,
+        this.timeline.timeContext
+      );
+
+      // Set start and duration so that the highlight layer can use
+      // them to determine which line to draw values from
+      lineLayer.start = feature.startTime;
+      lineLayer.duration = duration;
+
+      return lineLayer;
+    });
+
+    // And a single scale layer at left
+    // !!! todo: unit in scale layer
+    const scaleLayer = new wavesUI.helpers.ScaleLayer({
+      tickColor: colour,
+      textColor: colour,
+      height: height,
+      yDomain: [ min, max ]
+    });
+    this.addLayer(
+      scaleLayer,
+      waveTrack,
+      this.timeline.timeContext
+    );
+
+    // And a single highlight layer which uses all of the line layers
+    // as its source material
+    this.highlightLayer = new wavesUI.helpers.HighlightLayer(lineLayers, {
+      opacity: 0.7,
+      height: height,
+      color: '#c33c54',
+      labelOffset: 38,
+      yDomain: [ min, max ],
+      unit
+    });
+    this.addLayer(
+      this.highlightLayer,
+      waveTrack,
+      this.timeline.timeContext
+    );
+  }
+
   // TODO refactor - this doesn't belong here
   private renderFeatures(extracted: SimpleResponse, colour: Colour): void {
     if (this.isOneShotExtractor && !this.hasShot) {
@@ -619,78 +721,36 @@
       return;
     }
     if (!extracted.features.hasOwnProperty('shape')
-      || !extracted.features.hasOwnProperty('data')) {
+      || !extracted.features.hasOwnProperty('collected')) {
       return;
     }
     const features: FeatureCollection = (extracted.features as FeatureCollection);
     const outputDescriptor = extracted.outputDescriptor;
-    // const height = this.trackDiv.nativeElement.getBoundingClientRect().height / 2;
     const height = this.trackDiv.nativeElement.getBoundingClientRect().height;
     const waveTrack = this.timeline.getTrackById(`wave-${this.trackIdPrefix}`);
 
+    let unit = '';
+    if (outputDescriptor.configured.hasOwnProperty('unit')) {
+      unit = outputDescriptor.configured.unit;
+    }
+
     // TODO refactor all of this
     switch (features.shape) {
+
       case 'vector': {
-        const stepDuration = (features as FixedSpacedFeatures).stepDuration;
-        const featureData = (features.data as Float32Array);
-        if (featureData.length === 0) {
-          return;
-        }
-        const plotData = [...featureData].map((feature, i) => {
-          return {
-            cx: i * stepDuration,
-            cy: feature
-          };
-        });
-        let min = featureData.reduce((m, f) => Math.min(m, f), Infinity);
-        let max = featureData.reduce((m, f) => Math.max(m, f), -Infinity);
-        if (min === Infinity) {
-          min = 0;
-          max = 1;
-        }
-	console.log("adding line layer: min = " + min + ", max = " + max);
-	if (min !== min || max !== max) {
-	  console.log("WARNING: min or max is NaN");
-	  min = 0;
-	  max = 1;
-	}
-        const lineLayer = new wavesUI.helpers.LineLayer(plotData, {
-          color: colour,
-          height: height,
-          yDomain: [ min, max ]
-        });
-        this.addLayer(
-          lineLayer,
-          waveTrack,
-          this.timeline.timeContext
-        );
-        const scaleLayer = new wavesUI.helpers.ScaleLayer({
-          tickColor: colour,
-          textColor: colour,
-          height: height,
-          yDomain: [ min, max ]
-        });
-        this.addLayer(
-          scaleLayer,
-          waveTrack,
-          this.timeline.timeContext
-        );
-        this.highlightLayer = new wavesUI.helpers.HighlightLayer(lineLayer, {
-          opacity: 0.7,
-          height: height,
-          color: '#c33c54',
-          labelOffset: 38,
-          yDomain: [ min, max ]
-        });
-        this.addLayer(
-          this.highlightLayer,
-          waveTrack,
-          this.timeline.timeContext
-        );
+        const collected = features.collected as VectorFeature;
+        this.addLineLayers([collected], unit, colour);
         break;
       }
+
+      case 'tracks': {
+        const collected = features.collected as TracksFeature;
+        this.addLineLayers(collected, unit, colour);
+        break;
+      }
+
       case 'list': {
-        const featureData = (features.data as FeatureList);
+        const featureData = features.collected as FeatureList;
         if (featureData.length === 0) {
           return;
         }
@@ -702,8 +762,8 @@
         const isRegion = hasDuration
           && featureData[0].timestamp != null;
         console.log('Have list features: length ' + featureData.length +
-                    ', isMarker ' + isMarker + ', isRegion ' + isRegion +
-                    ', hasDuration ' + hasDuration);
+          ', isMarker ' + isMarker + ', isRegion ' + isRegion +
+          ', hasDuration ' + hasDuration);
         // TODO refactor, this is incomprehensible
         if (isMarker) {
           const plotData = featureData.map(feature => ({
@@ -792,9 +852,10 @@
         break;
       }
       case 'matrix': {
-        const stepDuration = (features as FixedSpacedFeatures).stepDuration;
-        // !!! + start time
-        const matrixData = (features.data as Float32Array[]);
+        const collected = features.collected as MatrixFeature;
+        const startTime = collected.startTime; // !!! + make use of
+        const stepDuration = collected.stepDuration;
+        const matrixData = collected.data;
 
         if (matrixData.length === 0) {
           return;
@@ -807,8 +868,8 @@
         console.log('setting gain to ' + gain);
         const matrixEntity =
           new wavesUI.utils.PrefilledMatrixEntity(matrixData,
-                                                  0, // startTime
-                                                  stepDuration);
+            0, // startTime
+            stepDuration);
         const matrixLayer = new wavesUI.helpers.MatrixLayer(matrixEntity, {
           gain,
           top: 0,
@@ -864,17 +925,17 @@
         if (mustPageForward) {
           const hasSkippedMultiplePages = offsetTimestamp - visibleDuration > visibleDuration;
 
-            this.timeline.timeContext.offset = hasSkippedMultiplePages ?
-                -currentTime +  0.5 * visibleDuration :
-                currentOffset - visibleDuration;
+          this.timeline.timeContext.offset = hasSkippedMultiplePages ?
+            -currentTime +  0.5 * visibleDuration :
+            currentOffset - visibleDuration;
           this.timeline.tracks.update();
         }
 
         if (mustPageBackward) {
           const hasSkippedMultiplePages = currentTime + visibleDuration < -currentOffset;
-            this.timeline.timeContext.offset = hasSkippedMultiplePages ?
-                -currentTime + 0.5 * visibleDuration :
-                currentOffset + visibleDuration;
+          this.timeline.timeContext.offset = hasSkippedMultiplePages ?
+            -currentTime + 0.5 * visibleDuration :
+            currentOffset + visibleDuration;
           this.timeline.tracks.update();
         }
 
--- a/src/bootstrap-feature-extraction-worker.js	Wed May 10 13:22:30 2017 +0100
+++ b/src/bootstrap-feature-extraction-worker.js	Fri May 12 17:20:31 2017 +0100
@@ -5,6 +5,7 @@
 importScripts('/inline.bundle.js'); // provides webpackJsonp
 const webpackJsonp = window['webpackJsonp'];
 importScripts('/scripts.bundle.js'); // needs webpackJsonp, hence above - provides RequireJS
+window = null; // now we have a reference to webpackJsonp, get rid of window
 importScripts('/polyfills.bundle.js'); // provides the compiled FeatureExtractionWorker
 
 new (require('feature-extraction-worker'))(self, requirejs);
--- a/tslint.json	Wed May 10 13:22:30 2017 +0100
+++ b/tslint.json	Fri May 12 17:20:31 2017 +0100
@@ -47,7 +47,7 @@
     "no-empty-interface": true,
     "no-eval": true,
     "no-inferrable-types": [true, "ignore-params"],
-    "no-shadowed-variable": true,
+    "no-shadowed-variable": false,
     "no-string-literal": false,
     "no-string-throw": true,
     "no-switch-case-fall-through": true,
--- a/yarn.lock	Wed May 10 13:22:30 2017 +0100
+++ b/yarn.lock	Fri May 12 17:20:31 2017 +0100
@@ -1,19 +1,19 @@
 # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
 # yarn lockfile v1
 "@angular/animations@^4.0.3":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.1.1.tgz#1000f8b22dc2031a8c36d225eb2dcf5f6c0d0af5"
-
-"@angular/cli@1.0.1":
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-1.0.1.tgz#95bc1e02c564ff2bddc7c6d975fdf355b47216cb"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.1.2.tgz#3371596e736b7d240e200477d0dd8c5929352124"
+
+"@angular/cli@1.0.3":
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-1.0.3.tgz#73a4b43f2ea8e720f52f1041e5e833cae1fb291f"
   dependencies:
     "@ngtools/json-schema" "1.0.9"
     "@ngtools/webpack" "1.3.1"
     autoprefixer "^6.5.3"
     chalk "^1.1.3"
     common-tags "^1.3.1"
-    css-loader "^0.27.3"
+    css-loader "^0.28.1"
     cssnano "^3.10.0"
     debug "^2.1.3"
     denodeify "^1.2.1"
@@ -69,52 +69,52 @@
     node-sass "^4.3.0"
 
 "@angular/common@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.1.1.tgz#088a13a70c5390c5c9613aa05754b74ee18e1afb"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.1.2.tgz#8f6d0496c204210bfe255feb437a72253f06984d"
 
 "@angular/compiler-cli@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-4.1.1.tgz#8cea89ee12129c3f0edb55853e18b37b164f2953"
-  dependencies:
-    "@angular/tsc-wrapped" "4.1.1"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-4.1.2.tgz#b65ba8980330c048702aed242a956daf0251f02a"
+  dependencies:
+    "@angular/tsc-wrapped" "4.1.2"
     minimist "^1.2.0"
     reflect-metadata "^0.1.2"
 
 "@angular/compiler@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.1.1.tgz#fc62459056465f624c3ac6f68dadcc9ba74c4ae0"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.1.2.tgz#09542381162fd8dd962d84559498ce69a05071ea"
 
 "@angular/core@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.1.1.tgz#1230645c842f8a6a050403d4947f982e7ef70c60"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.1.2.tgz#37b5c040b9dd37003499aea04319d699e3870596"
 
 "@angular/forms@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.1.1.tgz#6af39f7c416e9f038c39f7ee5bfa51d9da550bf0"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.1.2.tgz#82983e9ec5d0833e7ae14beb8e47dd357c88f490"
 
 "@angular/http@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/http/-/http-4.1.1.tgz#1e052d02e52aee7b48d1de626abbf067e850a242"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/http/-/http-4.1.2.tgz#fc378c3330c0410e1fb8aac2546329a6887776e4"
 
 "@angular/material@^2.0.0-beta.3":
   version "2.0.0-beta.3"
   resolved "https://registry.yarnpkg.com/@angular/material/-/material-2.0.0-beta.3.tgz#ec31dee61d7300ece28fee476852db236ded1e13"
 
 "@angular/platform-browser-dynamic@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.1.1.tgz#682881035140e22d498abca139907aa8187f6bfa"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.1.2.tgz#d241c61792c794bec627ab64b31a66bea22abb9f"
 
 "@angular/platform-browser@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.1.1.tgz#e2f545b458e7858cc0b20b0ae4cc99237560fb72"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.1.2.tgz#16e50a8f75b4d675c9e2903e499e0fe4c6a125ac"
 
 "@angular/router@^4.0.0":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/router/-/router-4.1.1.tgz#0a7ce03065197982786782cf5429fa6f0c0300fa"
-
-"@angular/tsc-wrapped@4.1.1":
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-4.1.1.tgz#ade793cdbe64c650c5f5946ff424c6a3577b09d8"
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/router/-/router-4.1.2.tgz#31b1b126fec2e1c32f4557ef8eb605536adccb27"
+
+"@angular/tsc-wrapped@4.1.2":
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-4.1.2.tgz#26cb145a67b9b80f5dda7874c4f0b1f1e173927d"
   dependencies:
     tsickle "^0.21.0"
 
@@ -131,7 +131,7 @@
     magic-string "^0.19.0"
     source-map "^0.5.6"
 
-"@types/base64-js@^1.1.4":
+"@types/base64-js@^1.2.5":
   version "1.2.5"
   resolved "https://registry.yarnpkg.com/@types/base64-js/-/base64-js-1.2.5.tgz#582b2476169a6cba460a214d476c744441d873d5"
 
@@ -144,8 +144,8 @@
   resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.5.38.tgz#a4379124c4921d4e21de54ec74669c9e9b356717"
 
 "@types/node@^6.0.46", "@types/node@~6.0.60":
-  version "6.0.72"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.72.tgz#0f19de38555f3c33d733d678991347f7d0eefaff"
+  version "6.0.73"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.73.tgz#85dc4bb6f125377c75ddd2519a1eeb63f0a4ed70"
 
 "@types/q@^0.0.32":
   version "0.0.32"
@@ -228,11 +228,11 @@
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
 
-ansi-align@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba"
-  dependencies:
-    string-width "^1.0.1"
+ansi-align@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
+  dependencies:
+    string-width "^2.0.0"
 
 ansi-escapes@^1.1.0:
   version "1.4.0"
@@ -655,8 +655,8 @@
   resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd"
 
 babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
-  version "6.17.0"
-  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.0.tgz#37da948878488b9c4e3c4038893fa3314b3fc932"
+  version "6.17.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.1.tgz#17f14fddf361b695981fe679385e4f1c01ebd86f"
 
 backo2@1.0.2:
   version "1.0.2"
@@ -756,10 +756,10 @@
     hoek "2.x.x"
 
 boxen@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.0.0.tgz#b2694baf1f605f708ff0177c12193b22f29aaaab"
-  dependencies:
-    ansi-align "^1.1.0"
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.1.0.tgz#b1b69dd522305e807a99deee777dbd6e5167b102"
+  dependencies:
+    ansi-align "^2.0.0"
     camelcase "^4.0.0"
     chalk "^1.1.1"
     cli-boxes "^1.0.0"
@@ -767,7 +767,7 @@
     term-size "^0.1.0"
     widest-line "^1.0.0"
 
-brace-expansion@^1.0.0:
+brace-expansion@^1.0.0, brace-expansion@^1.1.7:
   version "1.1.7"
   resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59"
   dependencies:
@@ -1009,8 +1009,8 @@
     lodash.uniq "^4.5.0"
 
 caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
-  version "1.0.30000665"
-  resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000665.tgz#e84f4277935f295f546f8533cb0b410a8415b972"
+  version "1.0.30000667"
+  resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000667.tgz#fb6060dbf349c101df26f421442419802fc6dab1"
 
 capture-stack-trace@^1.0.0:
   version "1.0.0"
@@ -1038,8 +1038,8 @@
     supports-color "^2.0.0"
 
 chokidar@^1.0.0, chokidar@^1.4.1, chokidar@^1.4.3, chokidar@^1.6.0:
-  version "1.6.1"
-  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2"
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
   dependencies:
     anymatch "^1.3.0"
     async-each "^1.0.0"
@@ -1052,7 +1052,7 @@
   optionalDependencies:
     fsevents "^1.0.0"
 
-cipher-base@^1.0.0, cipher-base@^1.0.1:
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
   dependencies:
@@ -1065,8 +1065,8 @@
     chalk "^1.1.3"
 
 clean-css@4.0.x:
-  version "4.0.12"
-  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.0.12.tgz#a02e61707f1840bd3338f54dbc9acbda4e772fa3"
+  version "4.0.13"
+  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.0.13.tgz#feb2a176062d72a6c3e624d9213cac6a0c485e80"
   dependencies:
     source-map "0.5.x"
 
@@ -1279,14 +1279,14 @@
     typedarray "~0.0.5"
 
 configstore@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.0.0.tgz#e1b8669c1803ccc50b545e92f8e6e79aa80e0196"
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.0.tgz#45df907073e26dfa1cf4b2d52f5b60545eaa11d1"
   dependencies:
     dot-prop "^4.1.0"
     graceful-fs "^4.1.2"
-    mkdirp "^0.5.0"
+    make-dir "^1.0.0"
     unique-string "^1.0.0"
-    write-file-atomic "^1.1.2"
+    write-file-atomic "^2.0.0"
     xdg-basedir "^3.0.0"
 
 connect-history-api-fallback@^1.3.0:
@@ -1377,21 +1377,25 @@
   dependencies:
     capture-stack-trace "^1.0.0"
 
-create-hash@^1.1.0, create-hash@^1.1.1:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.2.tgz#51210062d7bb7479f6c65bb41a92208b1d61abad"
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
   dependencies:
     cipher-base "^1.0.1"
     inherits "^2.0.1"
-    ripemd160 "^1.0.0"
-    sha.js "^2.3.6"
-
-create-hmac@^1.1.0, create-hmac@^1.1.2:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.4.tgz#d3fb4ba253eb8b3f56e39ea2fbcb8af747bd3170"
-  dependencies:
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
     create-hash "^1.1.0"
     inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
 
 cross-spawn-async@^2.1.1:
   version "2.2.5"
@@ -1436,9 +1440,9 @@
   version "0.0.4"
   resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
 
-css-loader@^0.27.3:
-  version "0.27.3"
-  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.27.3.tgz#69ab6f47b69bfb1b5acee61bac2aab14302ff0dc"
+css-loader@^0.28.1:
+  version "0.28.1"
+  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.1.tgz#220325599f8f00452d9ceb4c3ca6c8a66798642d"
   dependencies:
     babel-code-frame "^6.11.0"
     css-selector-tokenizer "^0.7.0"
@@ -1451,6 +1455,7 @@
     postcss-modules-local-by-default "^1.0.1"
     postcss-modules-scope "^1.0.0"
     postcss-modules-values "^1.1.0"
+    postcss-value-parser "^3.3.0"
     source-list-map "^0.1.7"
 
 css-parse@1.7.x:
@@ -1601,8 +1606,8 @@
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
 
 deep-extend@~0.4.0:
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
 
 default-require-extensions@^1.0.0:
   version "1.0.0"
@@ -1808,8 +1813,8 @@
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
 
 electron-to-chromium@^1.2.7:
-  version "1.3.9"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.9.tgz#db1cba2a26aebcca2f7f5b8b034554468609157d"
+  version "1.3.10"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.10.tgz#63d62b785471f0d8dda85199d64579de8a449f08"
 
 elliptic@^6.0.0:
   version "6.4.0"
@@ -2258,7 +2263,7 @@
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
 
-gauge@~2.7.1:
+gauge@~2.7.3:
   version "2.7.4"
   resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
   dependencies:
@@ -2458,6 +2463,12 @@
   dependencies:
     function-bind "^1.0.2"
 
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
 hash.js@^1.0.0, hash.js@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
@@ -2518,8 +2529,8 @@
   resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
 
 html-minifier@^3.2.3:
-  version "3.4.3"
-  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.4.3.tgz#eb3a7297c804611f470454eeebe0aacc427e424a"
+  version "3.4.4"
+  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.4.4.tgz#616fe3e3ef16da02b393d9a6099eeff468a35df0"
   dependencies:
     camel-case "3.0.x"
     clean-css "4.0.x"
@@ -2642,8 +2653,8 @@
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
 
 image-size@~0.5.0:
-  version "0.5.1"
-  resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.1.tgz#28eea8548a4b1443480ddddc1e083ae54652439f"
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.3.tgz#5cbe9fafc8436386ceb7e9e3a9d90c5b71b70ad9"
 
 img-stats@^0.5.2:
   version "0.5.2"
@@ -3042,8 +3053,8 @@
     jasmine-core "~2.6.0"
 
 jasminewd2@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.0.0.tgz#10aacd2c588c1ceb6a0b849f1a7f3f959f777c91"
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.1.0.tgz#da595275d1ae631de736ac0a7c7d85c9f73ef652"
 
 jodid25519@^1.0.0:
   version "1.0.2"
@@ -3064,8 +3075,8 @@
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae"
 
 js-yaml@^3.4.3, js-yaml@^3.7.0:
-  version "3.8.3"
-  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  version "3.8.4"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6"
   dependencies:
     argparse "^1.0.7"
     esprima "^3.1.1"
@@ -3149,8 +3160,8 @@
   resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
 
 jsonparse@^1.2.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.0.tgz#85fc245b1d9259acc6941960b905adf64e7de0e8"
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
 
 JSONStream@^1.0.3:
   version "1.3.1"
@@ -3447,11 +3458,17 @@
   resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
 
 magic-string@^0.19.0:
-  version "0.19.0"
-  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.19.0.tgz#198948217254e3e0b93080e01146b7c73b2a06b2"
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.19.1.tgz#14d768013caf2ec8fdea16a49af82fc377e75201"
   dependencies:
     vlq "^0.2.1"
 
+make-dir@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978"
+  dependencies:
+    pify "^2.3.0"
+
 make-error@^1.1.1:
   version "1.2.3"
   resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.2.3.tgz#6c4402df732e0977ac6faf754a5074b3d2b1d19d"
@@ -3539,7 +3556,11 @@
   dependencies:
     mime-db "~1.27.0"
 
-mime@^1.2.11, mime@^1.3.4, mime@1.3.4, mime@1.3.x:
+mime@^1.2.11, mime@^1.3.4, mime@1.3.x:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0"
+
+mime@1.3.4:
   version "1.3.4"
   resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
 
@@ -3562,10 +3583,10 @@
     brace-expansion "^1.0.0"
 
 minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@~3.0.2, "minimatch@2 || 3":
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
-  dependencies:
-    brace-expansion "^1.0.0"
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  dependencies:
+    brace-expansion "^1.1.7"
 
 minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0:
   version "1.2.0"
@@ -3787,12 +3808,12 @@
     path-key "^1.0.0"
 
 npmlog@^4.0.0, npmlog@^4.0.2, "npmlog@0 || 1 || 2 || 3 || 4":
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f"
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
   dependencies:
     are-we-there-yet "~1.1.2"
     console-control-strings "~1.1.0"
-    gauge "~2.7.1"
+    gauge "~2.7.3"
     set-blocking "~2.0.0"
 
 nth-check@~1.0.1:
@@ -4048,10 +4069,14 @@
     pinkie-promise "^2.0.0"
 
 pbkdf2@^3.0.3:
-  version "3.0.9"
-  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.9.tgz#f2c4b25a600058b3c3773c086c37dbbee1ffe693"
-  dependencies:
-    create-hmac "^1.1.2"
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
 
 performance-now@^0.2.0:
   version "0.2.0"
@@ -4071,13 +4096,13 @@
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
 
-"piper@github:piper-audio/piper-js":
-  version "0.13.0"
-  resolved "https://codeload.github.com/piper-audio/piper-js/tar.gz/97ac6fec27b97cf998117370653e0089bcf9c0d6"
-  dependencies:
-    "@types/base64-js" "^1.1.4"
+piper@piper-audio/piper-js:
+  version "0.16.0"
+  resolved "https://codeload.github.com/piper-audio/piper-js/tar.gz/e42d0165d93794eeade2b09a345b6123d298f13c"
+  dependencies:
+    "@types/base64-js" "^1.2.5"
     base64-js "^1.2.0"
-    rxjs "^5.2.0"
+    rxjs "^5.4.0"
 
 portfinder@^1.0.9, portfinder@~1.0.12:
   version "1.0.13"
@@ -4842,9 +4867,12 @@
   version "2.2.8"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
 
-ripemd160@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e"
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
 
 rsvp@^3.0.17:
   version "3.5.0"
@@ -4860,9 +4888,9 @@
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
 
-rxjs@^5.0.1, rxjs@^5.1.0, rxjs@^5.2.0:
-  version "5.3.1"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.3.1.tgz#9ecc9e722247e4f4490d30a878577a3740fd0cb7"
+rxjs@^5.0.1, rxjs@^5.4.0:
+  version "5.4.0"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.0.tgz#a7db14ab157f9d7aac6a56e655e7a3860d39bf26"
   dependencies:
     symbol-observable "^1.0.1"
 
@@ -4871,17 +4899,17 @@
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
 
 sass-graph@^2.1.1:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.2.tgz#f4d6c95b546ea2a09d14176d0fc1a07ee2b48354"
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.3.tgz#2ba9f170f6cafed5b51665abe13cf319c9269c31"
   dependencies:
     glob "^7.0.0"
     lodash "^4.0.0"
-    scss-tokenizer "^0.2.1"
+    scss-tokenizer "^0.2.3"
     yargs "^6.6.0"
 
 sass-loader@^6.0.3:
-  version "6.0.3"
-  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.3.tgz#33983b1f90d27ddab0e57d0dac403dce9bc7ecfd"
+  version "6.0.5"
+  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.5.tgz#a847910f36442aa56c5985879d54eb519e24a328"
   dependencies:
     async "^2.1.5"
     clone-deep "^0.2.4"
@@ -4913,9 +4941,9 @@
   dependencies:
     raw-loader "~0.5.1"
 
-scss-tokenizer@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.1.tgz#07c0cc577bb7ab4d08fd900185adbf4bc844141d"
+scss-tokenizer@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
   dependencies:
     js-base64 "^2.1.8"
     source-map "^0.4.2"
@@ -5026,7 +5054,7 @@
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
 
-sha.js@^2.3.6, sha.js@~2.4.4:
+sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4:
   version "2.4.8"
   resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
   dependencies:
@@ -5245,7 +5273,11 @@
     select-hose "^2.0.0"
     spdy-transport "^2.0.15"
 
-sprintf-js@^1.0.3, sprintf-js@~1.0.2:
+sprintf-js@^1.0.3:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.0.tgz#cffcaf702daf65ea39bb4e0fa2b299cec1a1be46"
+
+sprintf-js@~1.0.2:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
 
@@ -5293,8 +5325,8 @@
     readable-stream "^2.0.2"
 
 stream-http@^2.0.0, stream-http@^2.3.1:
-  version "2.7.0"
-  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.0.tgz#cec1f4e3b494bc4a81b451808970f8b20b4ed5f6"
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.1.tgz#546a51741ad5a6b07e9e31b0b10441a917df528a"
   dependencies:
     builtin-status-codes "^3.0.0"
     inherits "^2.0.1"
@@ -5651,8 +5683,8 @@
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.2.tgz#606022508479b55ffa368b58fee963a03dfd7b0c"
 
 uglify-js@^2.6, uglify-js@^2.7.5, uglify-js@~2.8.22:
-  version "2.8.22"
-  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0"
+  version "2.8.23"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.23.tgz#8230dd9783371232d62a7821e2cf9a817270a8a0"
   dependencies:
     source-map "~0.5.1"
     yargs "~3.10.0"
@@ -5860,8 +5892,8 @@
     graceful-fs "^4.1.2"
 
 waves-ui-piper@piper-audio/waves-ui-piper:
-  version "0.4.0"
-  resolved "https://codeload.github.com/piper-audio/waves-ui-piper/tar.gz/94dd801c538c74b282d210ba0648a58476f42659"
+  version "0.5.0"
+  resolved "https://codeload.github.com/piper-audio/waves-ui-piper/tar.gz/b68523895c5ff538a5a82b2012d0482a925b6c87"
   dependencies:
     babel-runtime "^5.8.12"
 
@@ -5879,8 +5911,8 @@
     selenium-webdriver "^2.53.2"
 
 webdriver-manager@^12.0.1:
-  version "12.0.5"
-  resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.0.5.tgz#364b8dd0a281720f4eddcc51ae0c3b442a067e3b"
+  version "12.0.6"
+  resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.0.6.tgz#3df1a481977010b4cbf8c9d85c7a577828c0e70b"
   dependencies:
     adm-zip "^0.4.7"
     chalk "^1.1.1"
@@ -5992,10 +6024,10 @@
     isexe "^2.0.0"
 
 wide-align@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad"
-  dependencies:
-    string-width "^1.0.1"
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
 
 widest-line@^1.0.0:
   version "1.0.0"
@@ -6030,9 +6062,9 @@
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
 
-write-file-atomic@^1.1.2:
-  version "1.3.4"
-  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f"
+write-file-atomic@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.0.0.tgz#bb99a5440d0d31dd860a68da392bffeef66251a1"
   dependencies:
     graceful-fs "^4.1.11"
     imurmurhash "^0.1.4"
@@ -6157,8 +6189,10 @@
   resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
 
 yn@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/yn/-/yn-1.2.0.tgz#d237a4c533f279b2b89d3acac2db4b8c795e4a63"
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/yn/-/yn-1.3.0.tgz#1b0812abb8d805d48966f8df385dc9dacc9a19d8"
+  dependencies:
+    object-assign "^4.1.1"
 
 zone.js@^0.8.4:
   version "0.8.10"