From d90666e34f0dbc007c4c53e2af56082d884fed98 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Thu, 5 Sep 2019 21:20:38 -0700 Subject: [PATCH] HACK to add timidity Not a real solution, just quick and dirty to see it work --- demo/config/webpack.common.js | 2 +- demo/js/config.ts | 126 +------------------- demo/js/index.js | 1 + demo/js/timidity.js | 1 + demo/mp3/Pokemon - Pokemon Center Theme.mid | Bin 0 -> 3147 bytes demo/timidity | 1 + js/media/elementSource.ts | 55 ++++----- package.json | 2 +- yarn.lock | 96 +++++++++++++-- 9 files changed, 113 insertions(+), 171 deletions(-) create mode 100644 demo/js/timidity.js create mode 100644 demo/mp3/Pokemon - Pokemon Center Theme.mid create mode 160000 demo/timidity diff --git a/demo/config/webpack.common.js b/demo/config/webpack.common.js index eb30d9b1..4e5ccfa8 100644 --- a/demo/config/webpack.common.js +++ b/demo/config/webpack.common.js @@ -37,7 +37,7 @@ module.exports = { }, }, { - test: /\.(wsz|wal|mp3|png|ico|jpg|svg)$/, + test: /\.(wsz|wal|mp3|png|ico|jpg|svg|mid)$/, use: [ { loader: "file-loader", diff --git a/demo/js/config.ts b/demo/js/config.ts index 738e5b65..b3fc571d 100644 --- a/demo/js/config.ts +++ b/demo/js/config.ts @@ -2,6 +2,7 @@ import { Track, AppState } from "../../js/types"; // @ts-ignore import llamaAudio from "../mp3/llama-2.91.mp3"; import { DeepPartial } from "redux"; +import pokemonTheme from "../mp3/Pokemon - Pokemon Center Theme.mid"; interface Config { initialTracks?: Track[]; @@ -29,134 +30,13 @@ if (config.audioUrl && !config.initialTracks) { export const skinUrl = config.skinUrl === undefined ? null : config.skinUrl; // https://freemusicarchive.org/music/netBloc_Artists/netBloc_Vol_24_tiuqottigeloot/ -const album = "netBloc Vol. 24: tiuqottigeloot"; export const initialTracks = config.initialTracks || [ { - metaData: { artist: "DJ Mike Llama", title: "Llama Whippin' Intro" }, - url: llamaAudio, + metaData: { artist: "Nintendo", title: "Pokemon Theme" }, + url: pokemonTheme, duration: 5.322286, }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Diablo_Swing_Orchestra_-_01_-_Heroines.mp3", - duration: 322.612245, - metaData: { - title: "Heroines", - artist: "Diablo Swing Orchestra", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Eclectek_-_02_-_We_Are_Going_To_Eclecfunk_Your_Ass.mp3", - duration: 190.093061, - metaData: { - title: "We Are Going To Eclecfunk Your Ass", - artist: "Eclectek", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Auto-Pilot_-_03_-_Seventeen.mp3", - duration: 214.622041, - metaData: { - title: "Seventeen", - artist: "Auto-Pilot", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Muha_-_04_-_Microphone.mp3", - duration: 181.838367, - metaData: { - title: "Microphone", - artist: "Muha", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Just_Plain_Ant_-_05_-_Stumble.mp3", - duration: 86.047347, - metaData: { - title: "Stumble", - artist: "Just Plain Ant", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Sleaze_-_06_-_God_Damn.mp3", - duration: 226.795102, - metaData: { - title: "God Damn", - artist: "Sleaze", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Juanitos_-_07_-_Hola_Hola_Bossa_Nova.mp3", - duration: 207.072653, - metaData: { - title: "Hola Hola Bossa Nova", - artist: "Juanitos", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Entertainment_for_the_Braindead_-_08_-_Resolutions_Chris_Summer_Remix.mp3", - duration: 314.331429, - metaData: { - title: "Resolutions (Chris Summer Remix)", - artist: "Entertainment for the Braindead", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Nobara_Hayakawa_-_09_-_Trail.mp3", - duration: 204.042449, - metaData: { - title: "Trail", - artist: "Nobara Hayakawa", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/Paper_Navy_-_10_-_Tongue_Tied.mp3", - duration: 201.116735, - metaData: { - title: "Tongue Tied", - artist: "Paper Navy", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/60_Tigres_-_11_-_Garage.mp3", - duration: 245.394286, - metaData: { - title: "Garage", - artist: "60 Tigres", - album, - }, - }, - { - url: - "https://raw.githubusercontent.com/captbaritone/webamp-music/4b556fbf/CM_aka_Creative_-_12_-_The_Cycle_Featuring_Mista_Mista.mp3", - duration: 221.44, - metaData: { - title: "The Cycle (Featuring Mista Mista)", - artist: "CM aka Creative", - album, - }, - }, ]; export const disableMarquee = config.disableMarquee || false; diff --git a/demo/js/index.js b/demo/js/index.js index da05fa8a..d3496af2 100644 --- a/demo/js/index.js +++ b/demo/js/index.js @@ -8,6 +8,7 @@ import isButterchurnSupported from "butterchurn/lib/isSupported.min"; import base from "../../skins/base-2.91-png.wsz"; import { WINDOWS } from "../../js/constants"; import * as Selectors from "../../js/selectors"; +import "./timidity"; import WebampLazy from "../../js/webampLazy"; import { diff --git a/demo/js/timidity.js b/demo/js/timidity.js new file mode 100644 index 00000000..6bfa7846 --- /dev/null +++ b/demo/js/timidity.js @@ -0,0 +1 @@ +import pokemonTheme from "../mp3/Pokemon - Pokemon Center Theme.mid"; diff --git a/demo/mp3/Pokemon - Pokemon Center Theme.mid b/demo/mp3/Pokemon - Pokemon Center Theme.mid new file mode 100644 index 0000000000000000000000000000000000000000..4a458e9bec9021f2fe88b8dd0502b6d91b2b844c GIT binary patch literal 3147 zcmZvdF;g2?6osFG*ol)eMM`x^s(2WUG#V0S+0|O!wU7`HjExh^i8X;SMj6J9J7fwM z6qYE{rb-9=0+N4`U!$DwuHF+uDVVvOz4yF(&b{wxeS80vbMCIY%TQO z-d$Q+`07(Pe!8&W+_Z$%p8qBc$CF(srlaVXLmFC8$YRQ$e<^q|BXnhgl*h6O^V3V9K6Mkk&IL zS=l2iJH3&eZwR7+)-RSMrW}IVo^~ck=eh4G6H@dZV@^0unD-AQ);fz-m z#0sKROd80r`9eX{i89#QZqG4!QF)?H%%?3ofP>;C@MU20V?<;>;Y_wG`wdU@}eR`nBB^`#rdsvgL|(VAKutSN}4 z(U4sGHIO%>O#Thz_Nbx34`j_KrAmVzHKeCNB-)TfJr5FninZUy6Y)t6jAD{GDnspEi{@cYWu{ey#xmUmE6-73ayZN6XgsrW;<^xc z*2pn8I07Ws9l2GGQRW6b=7wf6OE`7o;e==E2Cc%J&=@L$2_cAJHaD=2BeGrZ29oV` z0zM@T1?GmIVDNc0(Wh1AL|RuPjA_+Q2cas=qTyAvbO8q1+EEiiE#!!IO(vXnM@?Nk zgIaV?QnI4Jh~{RHQg1ENM?!r>gtFKhoG>V>htaabcpE}!HmXZKRoQbP%#e50#uELY zfKLgdgJ;T24oJ!oFo*3(^N-GuTo<|+FLv5?=p85wuKOw)!}4$;cxJ7t$$ZQq%5BRK zm?1UXnv6cI=}<;MS;md9Qwca@a>Z01=9*G(?K3ly66Rsb{HK7#d@|2q#F$ld*b<-v zB;8G*uJq1aiSuD?#kYo z&v|G1N5A$C5Bu(XS*E;ScJ92Q9eZCeh3UVr( zWjzO7^D1!6a=fb*95cl0s<17yJboo=B->{Ct2gy9isw;>dot1>}!2JidMane* literal 0 HcmV?d00001 diff --git a/demo/timidity b/demo/timidity new file mode 160000 index 00000000..c80a5ca9 --- /dev/null +++ b/demo/timidity @@ -0,0 +1 @@ +Subproject commit c80a5ca9a2cac9f6f75cf6b06099e8597c6c2c56 diff --git a/js/media/elementSource.ts b/js/media/elementSource.ts index 28e4a02f..6212bac1 100644 --- a/js/media/elementSource.ts +++ b/js/media/elementSource.ts @@ -2,6 +2,7 @@ import Emitter from "../emitter"; import { clamp } from "../utils"; import { MEDIA_STATUS } from "../constants"; import { MediaStatus } from "../types"; +import Timidity from "../../demo/timidity/bundle.js"; export default class ElementSource { _emitter: Emitter; @@ -11,6 +12,7 @@ export default class ElementSource { _audio: HTMLAudioElement; _stalled: boolean; _status: MediaStatus; + _player: Timidity; on(eventType: string, cb: (...args: any[]) => void) { return this._emitter.on(eventType, cb); @@ -25,29 +27,29 @@ export default class ElementSource { this._stalled = false; this._status = MEDIA_STATUS.STOPPED; + this._player = new Timidity("/demo/timidity/"); + // TODO: #leak - this._audio.addEventListener("suspend", () => { + this._player.on("unstarted", () => { this._setStalled(true); }); // TODO: #leak - this._audio.addEventListener("durationchange", () => { + this._player.on("playing", () => { this._emitter.trigger("loaded"); this._setStalled(false); }); + this._player.on("timeupdate", () => { + this._emitter.trigger("positionChange"); + }); + // TODO: #leak this._audio.addEventListener("ended", () => { this._emitter.trigger("ended"); this._setStatus(MEDIA_STATUS.STOPPED); }); - // TODO: Throttle to 50 (if needed) - // TODO: #leak - this._audio.addEventListener("timeupdate", () => { - this._emitter.trigger("positionChange"); - }); - // TODO: #leak this._audio.addEventListener("error", e => { switch (this._audio.error!.code) { @@ -95,46 +97,33 @@ export default class ElementSource { // Async for now, for compatibility with BufferAudioSource // TODO: This does not need to be async async loadUrl(url: string) { - this._audio.src = url; + this._player.load(url); + this._emitter.trigger("loaded"); } async play() { - if (this._status !== MEDIA_STATUS.PAUSED) { - this.seekToTime(0); - } - try { - await this._audio.play(); - // TODO #race - } catch (err) { - // - } + this._player.play(); this._setStatus(MEDIA_STATUS.PLAYING); } pause() { - this._audio.pause(); + this._player.pause(); this._setStatus(MEDIA_STATUS.PAUSED); } stop() { - this._audio.pause(); - this._audio.currentTime = 0; + this._player.pause(); + this._player.seek(0); this._setStatus(MEDIA_STATUS.STOPPED); } seekToTime(time: number) { - /* TODO: We could check if this is actually seekable: - const { seekable } = this._audio; - for (let i = 0; i < seekable.length; i++) { - console.log("start", seekable.start(i), "end", seekable.end(i)); - } - */ - this._audio.currentTime = clamp(time, 0, this.getDuration()); + this._player.seek(time); this._emitter.trigger("positionChange"); } getStalled() { - return this._stalled; + return false; } getStatus() { @@ -142,15 +131,11 @@ export default class ElementSource { } getDuration() { - const { duration } = this._audio; - // Safari on iOS currently has a strange behavior where it reports - // the duration as infinity if an Accept-Ranges header is not returned. - // For now, 0 is better even though it's still wrong. - return isNaN(duration) || duration === Infinity ? 0 : duration; + return this._player.duration; } getTimeElapsed() { - return this._audio.currentTime; + return this._player.currentTime; } _setStatus(status: MediaStatus) { diff --git a/package.json b/package.json index 8159b7b0..54a1220e 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "homepage": "https://github.com/captbaritone/webamp/", "devDependencies": { "@babel/core": "^7.0.0", - "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.5.5", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-transform-modules-commonjs": "^7.0.0", diff --git a/yarn.lock b/yarn.lock index bbfba63e..745910ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,6 +9,13 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/code-frame@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" + integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== + dependencies: + "@babel/highlight" "^7.0.0" + "@babel/core@^7.0.0": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687" @@ -67,6 +74,17 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.5.tgz#873a7f936a3c89491b43536d12245b626664e3cf" + integrity sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ== + dependencies: + "@babel/types" "^7.5.5" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" @@ -95,15 +113,17 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-create-class-features-plugin@^7.2.3": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.2.3.tgz#f6e719abb90cb7f4a69591e35fd5eb89047c4a7c" +"@babel/helper-create-class-features-plugin@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.5.tgz#401f302c8ddbc0edd36f7c6b2887d8fa1122e5a4" + integrity sha512-ZsxkyYiRA7Bg+ZTRpPvB6AbOFKTFFK4LrvTet8lInm0V468MWCaSYJE+I7v2z2r8KNLtYiV+K5kTCnR7dvyZjg== dependencies: "@babel/helper-function-name" "^7.1.0" - "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-member-expression-to-functions" "^7.5.5" "@babel/helper-optimise-call-expression" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.2.3" + "@babel/helper-replace-supers" "^7.5.5" + "@babel/helper-split-export-declaration" "^7.4.4" "@babel/helper-define-map@^7.1.0": version "7.1.0" @@ -146,6 +166,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-member-expression-to-functions@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz#1fb5b8ec4453a93c439ee9fe3aeea4a84b76b590" + integrity sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA== + dependencies: + "@babel/types" "^7.5.5" + "@babel/helper-module-imports@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" @@ -189,7 +216,7 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.2.3": +"@babel/helper-replace-supers@^7.1.0": version "7.2.3" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz#19970020cf22677d62b3a689561dbd9644d8c5e5" dependencies: @@ -198,6 +225,16 @@ "@babel/traverse" "^7.2.3" "@babel/types" "^7.0.0" +"@babel/helper-replace-supers@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz#f84ce43df031222d2bad068d2626cb5799c34bc2" + integrity sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.5.5" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.5.5" + "@babel/types" "^7.5.5" + "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" @@ -211,6 +248,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + "@babel/helper-wrap-function@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" @@ -250,6 +294,11 @@ version "7.3.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c" +"@babel/parser@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.5.tgz#02f077ac8817d3df4a832ef59de67565e71cca4b" + integrity sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g== + "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" @@ -258,11 +307,12 @@ "@babel/helper-remap-async-to-generator" "^7.1.0" "@babel/plugin-syntax-async-generators" "^7.2.0" -"@babel/plugin-proposal-class-properties@^7.0.0": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.2.3.tgz#c9e1294363b346cff333007a92080f3203698461" +"@babel/plugin-proposal-class-properties@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz#a974cfae1e37c3110e71f3c6a2e48b8e71958cd4" + integrity sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A== dependencies: - "@babel/helper-create-class-features-plugin" "^7.2.3" + "@babel/helper-create-class-features-plugin" "^7.5.5" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-json-strings@^7.2.0": @@ -687,6 +737,21 @@ globals "^11.1.0" lodash "^4.17.11" +"@babel/traverse@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.5.tgz#f664f8f368ed32988cd648da9f72d5ca70f165bb" + integrity sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.5.5" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.5.5" + "@babel/types" "^7.5.5" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e" @@ -712,6 +777,15 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +"@babel/types@^7.4.4", "@babel/types@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.5.tgz#97b9f728e182785909aa4ab56264f090a028d18a" + integrity sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@cnakazawa/watch@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" @@ -6775,7 +6849,7 @@ lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.3 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA== -lodash@^4.17.14, lodash@^4.17.15: +lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==