Mercurial > hg > ugly-duckling
changeset 331:dcb015c5a845
Merge pull request #37 from LucasThompson/dev/notes-bodge
Dev/notes bodge
author | Lucas Thompson <LucasThompson@users.noreply.github.com> |
---|---|
date | Wed, 17 May 2017 14:13:12 +0100 |
parents | cddc1cc19d8d (current diff) cc8a1e08dd2d (diff) |
children | 6ada6ca40baf |
files | |
diffstat | 6 files changed, 369 insertions(+), 234 deletions(-) [+] |
line wrap: on
line diff
--- a/src/app/feature-extraction-menu/feature-extraction-menu.component.ts Fri May 12 17:20:31 2017 +0100 +++ b/src/app/feature-extraction-menu/feature-extraction-menu.component.ts Wed May 17 14:13:12 2017 +0100 @@ -80,9 +80,9 @@ } ngOnInit() { - this.piperService.list().then(this.populateExtractors); this.librariesUpdatedSubscription = this.piperService.librariesUpdated$.subscribe(this.populateExtractors); + this.piperService.list().then(this.populateExtractors); } extract(combinedKey: string): void { @@ -94,9 +94,7 @@ } load(): void { - this.piperService.updateAvailableLibraries().subscribe(res => { - Object.keys(res).forEach(key => this.piperService.load(key)); - }); + this.piperService.updateAvailableLibraries(); } ngOnDestroy(): void {
--- a/src/app/playback-control/playback-control.component.html Fri May 12 17:20:31 2017 +0100 +++ b/src/app/playback-control/playback-control.component.html Wed May 17 14:13:12 2017 +0100 @@ -1,3 +1,6 @@ +<button md-icon-button (click)="emitFastRewindStart()"> + <md-icon>skip_previous</md-icon> +</button> <button md-icon-button (click)="emitPlayPause()"> <md-icon> <ng-template [ngIf]="isPlaying()">pause</ng-template>
--- a/src/app/services/feature-extraction/FeatureExtractionWorker.ts Fri May 12 17:20:31 2017 +0100 +++ b/src/app/services/feature-extraction/FeatureExtractionWorker.ts Wed May 17 14:13:12 2017 +0100 @@ -2,7 +2,7 @@ * Created by lucas on 01/12/2016. */ -import {PiperVampService, ListRequest, ListResponse} from 'piper'; +import {PiperVampService, ListRequest, ListResponse, Service} from 'piper'; import { SimpleRequest } from 'piper/HigherLevelUtilities'; @@ -30,33 +30,51 @@ type LibraryUri = string; type LibraryKey = string; -type RequireJs = (libs: string[], callback: (...libs: any[]) => void) => void; +type RequireJs = (libs: string[], + callback: (...libs: any[]) => void, + errBack: (...failedLibIds: string[]) => void) => void; +type Factory<T> = () => T; + +function waterfall<T>(tasks: (() => Promise<T>)[]): Promise<T[]> { + const reducer = (running: T[], next: Promise<T>): Promise<T[]> => { + return next.then(response => { + running = running.concat(response); + return running; + }); + }; + + return tasks.reduce((runningResponses, nextResponse) => { + return runningResponses.then(response => { + return reducer(response, nextResponse()); + }); + }, Promise.resolve([])); +} class AggregateStreamingService implements StreamingService { - private services: Map<LibraryKey, PiperStreamingService>; + private services: Map<LibraryKey, Factory<PiperStreamingService>>; constructor() { - this.services = new Map<LibraryKey, PiperStreamingService>(); + this.services = new Map<LibraryKey, Factory<PiperStreamingService>>(); this.services.set( 'vamp-example-plugins', - new PiperStreamingService(new PiperVampService(VampExamplePlugins())) + () => new PiperStreamingService( + new PiperVampService(VampExamplePlugins()) + ) ); } - addService(key: LibraryKey, service: PiperStreamingService): void { + addService(key: LibraryKey, service: Factory<PiperStreamingService>): void { this.services.set(key, service); } list(request: ListRequest): Promise<ListResponse> { - return Promise.all( - [...this.services.values()].map(client => client.list({})) - ).then(allAvailable => ({ - available: allAvailable.reduce( - (all, current) => all.concat(current.available), - [] - ) - }) - ); + const listThunks: (() => Promise<ListResponse>)[] = [ + ...this.services.values() + ].map(createClient => () => createClient().list({})); + + return waterfall(listThunks).then(responses => ({ + available: responses.reduce((flat, res) => flat.concat(res.available), []) + })); } process(request: SimpleRequest): Observable<StreamingResponse> { @@ -66,8 +84,8 @@ protected dispatch(method: 'process', request: SimpleRequest): Observable<StreamingResponse> { const key = request.key.split(':')[0]; - return this.services.has(key) ? - this.services.get(key)[method](request) : Observable.throw('Invalid key'); + return this.services.has(key) ? this.services.get(key)()[method](request) : + Observable.throw('Invalid key'); } } @@ -104,14 +122,12 @@ export default class FeatureExtractionWorker { private workerScope: DedicatedWorkerGlobalScope; - private remoteLibraries: Map<LibraryKey, LibraryUri>; private server: WebWorkerStreamingServer; private service: AggregateStreamingService; constructor(workerScope: DedicatedWorkerGlobalScope, private requireJs: RequireJs) { this.workerScope = workerScope; - this.remoteLibraries = new Map<LibraryKey, LibraryUri>(); this.service = new ThrottledReducingAggregateService(); this.setupImportLibraryListener(); this.server = new WebWorkerStreamingServer( @@ -123,36 +139,47 @@ private setupImportLibraryListener(): void { this.workerScope.onmessage = (ev: MessageEvent) => { - const sendResponse = (result) => { - this.workerScope.postMessage({ - method: ev.data.method, - result: result - }); - }; switch (ev.data.method) { - case 'import': - const key: LibraryKey = ev.data.params; - if (this.remoteLibraries.has(key)) { - this.requireJs([this.remoteLibraries.get(key)], (plugin) => { - // TODO a factory with more logic probably belongs in piper-js - const lib: any | EmscriptenModule = plugin.createLibrary(); - const isEmscriptenModule = typeof lib.cwrap === 'function'; - const service = new PiperStreamingService( - isEmscriptenModule ? new PiperVampService(lib) : lib // TODO - ); - this.service.addService(key, service); - this.service.list({}).then(sendResponse); - }); - } else { - console.error('Non registered library key.'); // TODO handle error - } - break; case 'addRemoteLibraries': // TODO rename const available: AvailableLibraries = ev.data.params; - Object.keys(available).forEach(libraryKey => { - this.remoteLibraries.set(libraryKey, available[libraryKey]); + const importThunks = Object.keys(available).map(libraryKey => { + return () => { + return this.downloadRemoteLibrary( + libraryKey, + available[libraryKey] + ).then(createService => { + this.service.addService(libraryKey, + () => new PiperStreamingService( + createService() + )); + }); + }; }); + waterfall(importThunks) + .then(() => this.service.list({})) + .then(response => { + this.workerScope.postMessage({ + method: 'import', + result: response + }); + }); } }; } + + private downloadRemoteLibrary(key: LibraryKey, + uri: LibraryUri): Promise<Factory<Service>> { + return new Promise((res, rej) => { + this.requireJs([uri], (plugin) => { + res(() => { + // TODO a factory with more logic probably belongs in piper-js + const lib: any | EmscriptenModule = plugin.createLibrary(); + const isEmscriptenModule = typeof lib.cwrap === 'function'; + return isEmscriptenModule ? new PiperVampService(lib) : lib; // TODO + }); + }, (err) => { + rej(`Failed to load ${key} remote module.`); + }); + }); + } }
--- a/src/app/services/feature-extraction/feature-extraction.service.ts Fri May 12 17:20:31 2017 +0100 +++ b/src/app/services/feature-extraction/feature-extraction.service.ts Wed May 17 14:13:12 2017 +0100 @@ -8,7 +8,7 @@ } from 'piper/HigherLevelUtilities'; import {Subject} from 'rxjs/Subject'; import {Observable} from 'rxjs/Observable'; -import {Http, Response} from '@angular/http'; +import {Http} from '@angular/http'; import { countingIdProvider, WebWorkerStreamingClient @@ -87,20 +87,16 @@ }); } - updateAvailableLibraries(): Observable<AvailableLibraries> { - return this.http.get(this.repositoryUri) - .map(res => { - const map = res.json(); + updateAvailableLibraries(): void { + this.http.get(this.repositoryUri) + .toPromise() // just turn into a promise for now to subscribe / execute + .then(res => { this.worker.postMessage({ method: 'addRemoteLibraries', - params: map - }); - return map; + params: res.json() + }) }) - .catch((error: Response | any) => { - console.error(error); - return Observable.throw(error); - }); + .catch(console.error); // TODO Report error to user } load(libraryKey: string): void {
--- a/src/app/waveform/waveform.component.ts Fri May 12 17:20:31 2017 +0100 +++ b/src/app/waveform/waveform.component.ts Wed May 17 14:13:12 2017 +0100 @@ -25,7 +25,7 @@ MatrixFeature, TracksFeature } from 'piper/HigherLevelUtilities'; -import {toSeconds} from 'piper'; +import {toSeconds, OutputDescriptor} from 'piper'; import {FeatureList, Feature} from 'piper/Feature'; import * as Hammer from 'hammerjs'; import {WavesSpectrogramLayer} from '../spectrogram/Spectrogram'; @@ -53,6 +53,15 @@ '#034748' // "deep jungle green" ]); +type HigherLevelFeatureShape = 'regions' | 'instants' | 'notes'; +type NoteLikeUnit = 'midi' | 'hz' ; +interface Note { + time: number; + duration: number; + pitch: number; + velocity?: number; +} + @Component({ selector: 'ugly-waveform', templateUrl: './waveform.component.html', @@ -754,100 +763,55 @@ if (featureData.length === 0) { return; } - // TODO look at output descriptor instead of directly inspecting features - const hasDuration = outputDescriptor.configured.hasDuration; - const isMarker = !hasDuration - && outputDescriptor.configured.binCount === 0 - && featureData[0].featureValues == null; - const isRegion = hasDuration - && featureData[0].timestamp != null; - console.log('Have list features: length ' + featureData.length + - ', isMarker ' + isMarker + ', isRegion ' + isRegion + - ', hasDuration ' + hasDuration); + // TODO refactor, this is incomprehensible - if (isMarker) { - const plotData = featureData.map(feature => ({ - time: toSeconds(feature.timestamp), - label: feature.label - })); - const featureLayer = new wavesUI.helpers.TickLayer(plotData, { - height: height, - color: colour, - labelPosition: 'bottom', - shadeSegments: true - }); - this.addLayer( - featureLayer, - waveTrack, - this.timeline.timeContext + try { + const featureShape = deduceHigherLevelFeatureShape( + featureData, + outputDescriptor ); - } else if (isRegion) { - console.log('Output is of region type'); - const binCount = outputDescriptor.configured.binCount || 0; - const isBarRegion = featureData[0].featureValues.length >= 1 || binCount >= 1 ; - const getSegmentArgs = () => { - if (isBarRegion) { - - // TODO refactor - this is messy - interface FoldsToNumber<T> { - reduce(fn: (previousValue: number, - currentValue: T, - currentIndex: number, - array: ArrayLike<T>) => number, - initialValue?: number): number; - } - - // TODO potentially change impl., i.e avoid reduce - const findMin = <T>(arr: FoldsToNumber<T>, getElement: (x: T) => number): number => { - return arr.reduce((min, val) => Math.min(min, getElement(val)), Infinity); - }; - - const findMax = <T>(arr: FoldsToNumber<T>, getElement: (x: T) => number): number => { - return arr.reduce((min, val) => Math.max(min, getElement(val)), -Infinity); - }; - - const min = findMin<Feature>(featureData, (x: Feature) => { - return findMin<number>(x.featureValues, y => y); + switch (featureShape) { + case 'instants': + const plotData = featureData.map(feature => ({ + time: toSeconds(feature.timestamp), + label: feature.label + })); + const featureLayer = new wavesUI.helpers.TickLayer(plotData, { + height: height, + color: colour, + labelPosition: 'bottom', + shadeSegments: true }); - - const max = findMax<Feature>(featureData, (x: Feature) => { - return findMax<number>(x.featureValues, y => y); - }); - - const barHeight = 1.0 / height; - return [ - featureData.reduce((bars, feature) => { - const staticProperties = { - x: toSeconds(feature.timestamp), - width: toSeconds(feature.duration), - height: min + barHeight, - color: colour, - opacity: 0.8 - }; - // TODO avoid copying Float32Array to an array - map is problematic here - return bars.concat([...feature.featureValues] - .map(val => Object.assign({}, staticProperties, {y: val}))); - }, []), - {yDomain: [min, max + barHeight], height: height} as any - ]; - } else { - return [featureData.map(feature => ({ - x: toSeconds(feature.timestamp), - width: toSeconds(feature.duration), - color: colour, - opacity: 0.8 - })), {height: height}]; - } - }; - - const segmentLayer = new wavesUI.helpers.SegmentLayer( - ...getSegmentArgs() - ); - this.addLayer( - segmentLayer, - waveTrack, - this.timeline.timeContext - ); + this.addLayer( + featureLayer, + waveTrack, + this.timeline.timeContext + ); + break; + case 'regions': + this.renderRegions( + featureData, + outputDescriptor, + waveTrack, + height, + colour + ); + break; + case 'notes': + const pianoRollLayer = new wavesUI.helpers.PianoRollLayer( + mapFeaturesToNotes(featureData, outputDescriptor), + {height: height, color: colour} + ); + this.addLayer( + pianoRollLayer, + waveTrack, + this.timeline.timeContext + ); + break; + } + } catch (e) { + console.warn(e); // TODO display + break; } break; } @@ -947,6 +911,89 @@ }); } + // TODO not sure how much of the logic in here is actually sensible w.r.t + // what it functionally produces + private renderRegions(featureData: FeatureList, + outputDescriptor: OutputDescriptor, + waveTrack: any, + height: number, + colour: Colour) { + console.log('Output is of region type'); + const binCount = outputDescriptor.configured.binCount || 0; + const isBarRegion = featureData[0].featureValues.length >= 1 || binCount >= 1 ; + const getSegmentArgs = () => { + if (isBarRegion) { + + // TODO refactor - this is messy + interface FoldsToNumber<T> { + reduce(fn: (previousValue: number, + currentValue: T, + currentIndex: number, + array: ArrayLike<T>) => number, + initialValue?: number): number; + } + + // TODO potentially change impl., i.e avoid reduce + const findMin = <T>(arr: FoldsToNumber<T>, + getElement: (x: T) => number): number => { + return arr.reduce( + (min, val) => Math.min(min, getElement(val)), + Infinity + ); + }; + + const findMax = <T>(arr: FoldsToNumber<T>, + getElement: (x: T) => number): number => { + return arr.reduce( + (min, val) => Math.max(min, getElement(val)), + -Infinity + ); + }; + + const min = findMin<Feature>(featureData, (x: Feature) => { + return findMin<number>(x.featureValues, y => y); + }); + + const max = findMax<Feature>(featureData, (x: Feature) => { + return findMax<number>(x.featureValues, y => y); + }); + + const barHeight = 1.0 / height; + return [ + featureData.reduce((bars, feature) => { + const staticProperties = { + x: toSeconds(feature.timestamp), + width: toSeconds(feature.duration), + height: min + barHeight, + color: colour, + opacity: 0.8 + }; + // TODO avoid copying Float32Array to an array - map is problematic here + return bars.concat([...feature.featureValues] + .map(val => Object.assign({}, staticProperties, {y: val}))); + }, []), + {yDomain: [min, max + barHeight], height: height} as any + ]; + } else { + return [featureData.map(feature => ({ + x: toSeconds(feature.timestamp), + width: toSeconds(feature.duration), + color: colour, + opacity: 0.8 + })), {height: height}]; + } + }; + + const segmentLayer = new wavesUI.helpers.SegmentLayer( + ...getSegmentArgs() + ); + this.addLayer( + segmentLayer, + waveTrack, + this.timeline.timeContext + ); + } + private addLayer(layer: Layer, track: Track, timeContext: any, isAxis: boolean = false): void { timeContext.zoom = 1.0; if (!layer.timeContext) { @@ -1003,3 +1050,56 @@ } } } + +function deduceHigherLevelFeatureShape(featureData: FeatureList, + descriptor: OutputDescriptor) +: HigherLevelFeatureShape { + // TODO look at output descriptor instead of directly inspecting features + const hasDuration = descriptor.configured.hasDuration; + const binCount = descriptor.configured.binCount; + const isMarker = !hasDuration + && binCount === 0 + && featureData[0].featureValues == null; + + const isMaybeNote = getCanonicalNoteLikeUnit(descriptor.configured.unit) + && [1, 2].find(nBins => nBins === binCount); + + const isRegionLike = hasDuration && featureData[0].timestamp != null; + + const isNote = isMaybeNote && isRegionLike; + const isRegion = !isMaybeNote && isRegionLike; + if (isMarker) { + return 'instants'; + } + if (isNote) { + return 'notes'; + } + if (isRegion) { + return 'regions'; + } + throw 'No shape could be deduced'; +} + +function getCanonicalNoteLikeUnit(unit: string): NoteLikeUnit | null { + const canonicalUnits: NoteLikeUnit[] = ['midi', 'hz']; + return canonicalUnits.find(canonicalUnit => { + return unit.toLowerCase().indexOf(canonicalUnit) >= 0 + }); +} + +function mapFeaturesToNotes(featureData: FeatureList, + descriptor: OutputDescriptor): Note[] { + const canonicalUnit = getCanonicalNoteLikeUnit(descriptor.configured.unit); + const isHz = canonicalUnit === 'hz'; + return featureData.map(feature => ({ + time: toSeconds(feature.timestamp), + duration: toSeconds(feature.duration), + pitch: isHz ? + frequencyToMidiNote(feature.featureValues[0]) : feature.featureValues[0] + })); +} + +function frequencyToMidiNote(frequency: number, + concertA: number = 440.0): number { + return 69 + 12 * Math.log2(frequency / concertA); +}
--- a/yarn.lock Fri May 12 17:20:31 2017 +0100 +++ b/yarn.lock Wed May 17 14:13:12 2017 +0100 @@ -97,8 +97,8 @@ 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" + version "2.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@angular/material/-/material-2.0.0-beta.5.tgz#712141ebfa77e3ace3ec8e32b5953b355e773965" "@angular/platform-browser-dynamic@^4.0.0": version "4.1.2" @@ -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.30000667" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000667.tgz#fb6060dbf349c101df26f421442419802fc6dab1" + version "1.0.30000670" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000670.tgz#90d33b79e3090e25829c311113c56d6b1788bf43" capture-stack-trace@^1.0.0: version "1.0.0" @@ -1064,9 +1064,9 @@ dependencies: chalk "^1.1.3" -clean-css@4.0.x: - version "4.0.13" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.0.13.tgz#feb2a176062d72a6c3e624d9213cac6a0c485e80" +clean-css@4.1.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.2.tgz#6029aea30b1d9520a968a3caee0dabb1184e353a" dependencies: source-map "0.5.x" @@ -1207,7 +1207,7 @@ dependencies: delayed-stream "~1.0.0" -commander@^2.5.0, commander@^2.6.0, commander@2.9.x: +commander@^2.5.0, commander@^2.6.0, commander@~2.9.0, commander@2.9.x: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: @@ -1294,11 +1294,11 @@ resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" connect@^3.3.5: - version "3.6.1" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.1.tgz#b7760693a74f0454face1d9378edb3f885b43227" - dependencies: - debug "2.6.3" - finalhandler "1.0.1" + version "3.6.2" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.2.tgz#694e8d20681bfe490282c8ab886be98f09f42fe7" + dependencies: + debug "2.6.7" + finalhandler "1.0.3" parseurl "~1.3.1" utils-merge "1.0.0" @@ -1565,11 +1565,11 @@ version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@*, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.6.3, debug@2: - version "2.6.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.6.tgz#a9fa6fbe9ca43cf1e79f73b75c0189cbb7d6db5a" - dependencies: - ms "0.7.3" +debug@*, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.6.3, debug@2, debug@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e" + dependencies: + ms "2.0.0" debug@~2.2.0, debug@2.2.0: version "2.2.0" @@ -1589,18 +1589,6 @@ dependencies: ms "0.7.2" -debug@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" - dependencies: - ms "0.7.2" - -debug@2.6.4: - version "2.6.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" - dependencies: - ms "0.7.3" - 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" @@ -1813,8 +1801,8 @@ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" electron-to-chromium@^1.2.7: - version "1.3.10" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.10.tgz#63d62b785471f0d8dda85199d64579de8a449f08" + version "1.3.11" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.11.tgz#744761df1d67b492b322ce9aa0aba5393260eb61" elliptic@^6.0.0: version "6.4.0" @@ -2130,23 +2118,11 @@ repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a" - dependencies: - debug "2.6.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.1" - statuses "~1.3.1" - unpipe "~1.0.0" - -finalhandler@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8" - dependencies: - debug "2.6.3" +finalhandler@~1.0.0, finalhandler@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89" + dependencies: + debug "2.6.7" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" @@ -2529,17 +2505,17 @@ resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" html-minifier@^3.2.3: - version "3.4.4" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.4.4.tgz#616fe3e3ef16da02b393d9a6099eeff468a35df0" + version "3.5.0" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.0.tgz#98be1b18f87443592722f654e67a1541f22018cb" dependencies: camel-case "3.0.x" - clean-css "4.0.x" + clean-css "4.1.x" commander "2.9.x" he "1.1.x" ncname "1.0.x" param-case "2.1.x" relateurl "0.2.x" - uglify-js "~2.8.22" + uglify-js "3.0.x" html-webpack-plugin@^2.19.0: version "2.28.0" @@ -2653,8 +2629,8 @@ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" image-size@~0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.3.tgz#5cbe9fafc8436386ceb7e9e3a9d90c5b71b70ad9" + version "0.5.4" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.4.tgz#94e07beec0659386f1aefb84b2222e88405485cd" img-stats@^0.5.2: version "0.5.2" @@ -3052,7 +3028,7 @@ glob "^7.0.6" jasmine-core "~2.6.0" -jasminewd2@^2.0.0: +jasminewd2@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.1.0.tgz#da595275d1ae631de736ac0a7c7d85c9f73ef652" @@ -3263,8 +3239,8 @@ is-buffer "^1.0.2" kind-of@^3.0.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.0.tgz#b58abe4d5c044ad33726a8c1525b48cf891bff07" + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: is-buffer "^1.1.5" @@ -3546,7 +3522,11 @@ bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: +"mime-db@>= 1.27.0 < 2": + version "1.28.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.28.0.tgz#fedd349be06d2865b7fc57d837c6de4f17d7ac3c" + +mime-db@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" @@ -3641,9 +3621,9 @@ version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" -ms@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" mute-stream@0.0.7: version "0.0.7" @@ -3734,8 +3714,8 @@ tar-pack "^3.4.0" node-sass@^4.3.0, node-sass@^4.5.2: - version "4.5.2" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.5.2.tgz#4012fa2bd129b1d6365117e88d9da0500d99da64" + version "4.5.3" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.5.3.tgz#d09c9d1179641239d1b97ffc6231fdcec53e1568" dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -4428,8 +4408,8 @@ asap "~2.0.3" protractor@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.1.1.tgz#10c4e336571b28875b8acc3ae3e4e1e40ef7e986" + version "5.1.2" + resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.1.2.tgz#9b221741709a4c62d5cd53c6aadd54a71137e95f" dependencies: "@types/node" "^6.0.46" "@types/q" "^0.0.32" @@ -4438,14 +4418,14 @@ chalk "^1.1.3" glob "^7.0.3" jasmine "^2.5.3" - jasminewd2 "^2.0.0" + jasminewd2 "^2.1.0" optimist "~0.6.0" q "1.4.1" saucelabs "~1.3.0" selenium-webdriver "3.0.1" source-map-support "~0.4.0" webdriver-js-extender "^1.0.0" - webdriver-manager "^12.0.1" + webdriver-manager "^12.0.6" proxy-addr@~1.1.3: version "1.1.4" @@ -4899,13 +4879,13 @@ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" sass-graph@^2.1.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.3.tgz#2ba9f170f6cafed5b51665abe13cf319c9269c31" + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" dependencies: glob "^7.0.0" lodash "^4.0.0" scss-tokenizer "^0.2.3" - yargs "^6.6.0" + yargs "^7.0.0" sass-loader@^6.0.3: version "6.0.5" @@ -5650,8 +5630,8 @@ update-notifier "^2.0.0" tsutils@^1.1.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.8.0.tgz#bf8118ed8e80cd5c9fc7d75728c7963d44ed2f52" + version "1.9.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0" tty-browserify@~0.0.0, tty-browserify@0.0.0: version "0.0.0" @@ -5682,9 +5662,9 @@ version "2.2.2" 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.23" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.23.tgz#8230dd9783371232d62a7821e2cf9a817270a8a0" +uglify-js@^2.6, uglify-js@^2.7.5: + version "2.8.26" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.26.tgz#3a1db8ae0a0aba7f92e1ddadadbd0293d549f90e" dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -5699,6 +5679,13 @@ optimist "~0.3.5" source-map "~0.1.7" +uglify-js@3.0.x: + version "3.0.7" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.7.tgz#5cca9c14abae2dd60ceccdf7da3c672cc8069cec" + dependencies: + commander "~2.9.0" + source-map "~0.5.1" + uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" @@ -5892,8 +5879,8 @@ graceful-fs "^4.1.2" waves-ui-piper@piper-audio/waves-ui-piper: - version "0.5.0" - resolved "https://codeload.github.com/piper-audio/waves-ui-piper/tar.gz/b68523895c5ff538a5a82b2012d0482a925b6c87" + version "0.5.2" + resolved "https://codeload.github.com/piper-audio/waves-ui-piper/tar.gz/36af0dd064c209b70744dabb27c575880fa595a1" dependencies: babel-runtime "^5.8.12" @@ -5910,7 +5897,7 @@ "@types/selenium-webdriver" "^2.53.35" selenium-webdriver "^2.53.2" -webdriver-manager@^12.0.1: +webdriver-manager@^12.0.6: version "12.0.6" resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.0.6.tgz#3df1a481977010b4cbf8c9d85c7a577828c0e70b" dependencies: @@ -6063,8 +6050,8 @@ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 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" + version "2.1.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.1.0.tgz#1769f4b551eedce419f0505deae2e26763542d37" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -6146,7 +6133,13 @@ dependencies: camelcase "^3.0.0" -yargs@^6.0.0, yargs@^6.6.0: +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + dependencies: + camelcase "^3.0.0" + +yargs@^6.0.0: version "6.6.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" dependencies: @@ -6164,6 +6157,24 @@ y18n "^3.2.1" yargs-parser "^4.2.0" +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"