diff options
author | Sam Potts <me@sampotts.me> | 2017-11-04 14:25:28 +1100 |
---|---|---|
committer | Sam Potts <me@sampotts.me> | 2017-11-04 14:25:28 +1100 |
commit | 1cc2930dc0b81183bc47442f5ad9b5d8df94cc5f (patch) | |
tree | 349313769a5e3d786a51b45b0a5c849dc7e3211d | |
parent | 3d50936b47fdd691816843de962d5699c3c8f596 (diff) | |
download | plyr-1cc2930dc0b81183bc47442f5ad9b5d8df94cc5f.tar.lz plyr-1cc2930dc0b81183bc47442f5ad9b5d8df94cc5f.tar.xz plyr-1cc2930dc0b81183bc47442f5ad9b5d8df94cc5f.zip |
ES6-ified
38 files changed, 10120 insertions, 11242 deletions
diff --git a/.eslintrc.json b/.eslintrc.json index 3c3c4d7c..6afa5f4c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,9 +1,11 @@ { - "extends": ["eslint:recommended", "prettier"], + "parser": "babel-eslint", + "extends": ["airbnb", "prettier"], "env": { - "browser": true + "browser": true, + "es6": true }, - "globals": {}, + "globals": { "Plyr": true }, "rules": { "no-const-assign": 1, "no-this-before-super": 1, @@ -18,5 +20,8 @@ "eqeqeq": [2, "always"], "one-var": [2, "never"], "comma-dangle": [2, "always-multiline"] + }, + "parserOptions": { + "sourceType": "module" } } diff --git a/bundles.json b/bundles.json index 2cc379c6..ebbaef34 100644 --- a/bundles.json +++ b/bundles.json @@ -16,7 +16,7 @@ "error.css": "demo/src/less/bundles/error.less" }, "js": { - "demo.js": ["demo/src/js/lib/classlist.js", "demo/src/js/lib/tab-focus.js", "demo/src/js/main.js"] + "demo.js": "demo/src/js/demo.js" } } } diff --git a/demo/dist/demo.css b/demo/dist/demo.css index ee3c5e5a..314ee5b2 100644 --- a/demo/dist/demo.css +++ b/demo/dist/demo.css @@ -1 +1 @@ -@-webkit-keyframes fadein{0%{opacity:0}100%{opacity:1}}@keyframes fadein{0%{opacity:0}100%{opacity:1}}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-medium.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-medium.woff) format('woff');font-style:normal;font-weight:500;font-display:swap}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-bold.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-bold.woff) format('woff');font-style:normal;font-weight:700;font-display:swap}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-black.woff2?v=3) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-black.woff?v=3) format('woff');font-style:normal;font-weight:900;font-display:swap}/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}a,button.faux-link{background:0 0}a:focus,button.faux-link:focus{outline:thin dotted}a:active,a:hover,button.faux-link:active,button.faux-link:hover{outline:0}h1{font-size:2em;margin:.67em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:'\201C' '\201D' '\2018' '\2019'}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}html{background:-webkit-gradient(linear,right bottom,left top,from(#67caff),to(#0085cd));background:linear-gradient(to left top,#67caff,#0085cd);background-attachment:fixed}html{height:100%}body{display:-webkit-box;display:-ms-flexbox;display:flex;min-height:100%;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}main{text-align:center}.grid{-webkit-box-flex:1;-ms-flex:1;flex:1}aside{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:100%;padding:15px;background:#fff;text-align:center;color:#55646b;text-shadow:none}aside .icon{margin-right:10px;fill:#4baaf4}aside p{margin:0}aside a,aside button.faux-link{color:#4baaf4}aside a.tab-focus,aside button.faux-link.tab-focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(75,170,244,.35);box-shadow:0 0 0 3px rgba(75,170,244,.35)}.grid{margin:0 auto;padding:20px}@media only screen and (min-width:768px){.grid{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;max-width:1280px}.grid>*{-webkit-box-flex:1;-ms-flex:1;flex:1}}html{font-size:100%}body{font-family:Avenir,'Helvetica Neue',sans-serif;line-height:1.5;color:#fff;font-weight:500;text-shadow:0 1px 1px rgba(0,0,0,.15);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}button,input,select,textarea{font:inherit}p,small{margin:0 0 20px}small{display:block;font-size:14px;font-size:.875rem}h1{margin:0 0 10px;font-weight:900;letter-spacing:-.025em;font-size:64px;font-size:4rem}.button,.button__count{position:relative;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:15px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.1);box-shadow:0 1px 1px rgba(0,0,0,.1);background:#fff;border:0;color:#55646b;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700;text-shadow:none}.button{padding-left:20px;padding-right:20px;-webkit-transition:all .2s ease;transition:all .2s ease}.button:focus,.button:hover{color:#343f4a;outline:0}.button:focus::after,.button:hover::after{display:none}.button.tab-focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(255,255,255,.35);box-shadow:0 0 0 3px rgba(255,255,255,.35)}.button__count{margin-left:10px;-webkit-animation:fadein .2s ease;animation:fadein .2s ease}.button__count::before{content:'';position:absolute;width:0;height:0;right:100%;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:5px solid transparent;border-right-color:#fff;border-left-width:0}header{padding-bottom:20px;text-align:center}header p{margin-bottom:30px;font-size:18px;font-size:1.125rem}@media only screen and (min-width:768px){header{max-width:400px;margin-right:40px;padding-bottom:40px;text-align:left}}.icon{fill:currentColor;width:16px;height:16px}a svg,button svg,button.faux-link svg,label svg{pointer-events:none}.btn .icon,a .icon,button.faux-link .icon{margin-right:10px}button.faux-link{position:relative;margin:0;padding:0;width:auto;border:0;background:0 0;vertical-align:baseline;text-align:inherit;font:inherit;line-height:1.5;cursor:pointer;-moz-user-select:text;text-shadow:inherit;border-radius:0}a,button.faux-link{position:relative;border-bottom:1px dotted currentColor;-webkit-transition:all .2s ease;transition:all .2s ease;text-decoration:none;color:#fff;font-weight:700}a::after,button.faux-link::after{content:'';position:absolute;top:100%;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:0;height:1px;-webkit-transition:width .2s ease;transition:width .2s ease;background:currentColor}a:focus,a:hover,button.faux-link:focus,button.faux-link:hover{border-bottom-color:transparent;outline:0}a:focus::after,a:hover::after,button.faux-link:focus::after,button.faux-link:hover::after{width:100%}a.tab-focus,button.faux-link.tab-focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(255,255,255,.35);box-shadow:0 0 0 3px rgba(255,255,255,.35)}li,ul{list-style:none;margin:0;padding:0}nav{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:20px}video{max-width:100%;vertical-align:middle}.plyr{margin:0 auto;border-radius:4px;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.2);box-shadow:0 2px 5px rgba(0,0,0,.2)}.plyr__video-wrapper::after{content:'';pointer-events:none;position:absolute;top:0;bottom:0;left:0;right:0;border:1px solid rgba(0,0,0,.15);border-radius:inherit}.plyr__cite{display:none;margin-top:20px}.plyr__cite .icon{margin-right:5px}.plyr--audio~ul .plyr__cite--audio,.plyr--video:not(.plyr--youtube):not(.plyr--vimeo)~ul .plyr__cite--video,.plyr--vimeo~ul .plyr__cite--vimeo,.plyr--youtube~ul .plyr__cite--youtube{display:block}
\ No newline at end of file +@-webkit-keyframes fadein{0%{opacity:0}100%{opacity:1}}@keyframes fadein{0%{opacity:0}100%{opacity:1}}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-medium.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-medium.woff) format('woff');font-style:normal;font-weight:500;font-display:swap}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-bold.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-bold.woff) format('woff');font-style:normal;font-weight:700;font-display:swap}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-black.woff2?v=3) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-black.woff?v=3) format('woff');font-style:normal;font-weight:900;font-display:swap}/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}a,button.faux-link{background:0 0}a:focus,button.faux-link:focus{outline:thin dotted}a:active,a:hover,button.faux-link:active,button.faux-link:hover{outline:0}h1{font-size:2em;margin:.67em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:'\201C' '\201D' '\2018' '\2019'}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}*,::after,::before{-webkit-box-sizing:border-box;box-sizing:border-box}body,html{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%}html{background:-webkit-gradient(linear,right bottom,left top,from(#67caff),to(#0085cd));background:linear-gradient(to left top,#67caff,#0085cd);background-attachment:fixed;height:100%}body{display:-webkit-box;display:-ms-flexbox;display:flex;min-height:100%;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}main{text-align:center}.grid{-webkit-box-flex:1;-ms-flex:1;flex:1}aside{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:100%;padding:15px;background:#fff;text-align:center;color:#55646b;text-shadow:none}aside .icon{margin-right:10px;fill:#4baaf4}aside p{margin:0}aside a,aside button.faux-link{color:#4baaf4}aside a.tab-focus,aside button.faux-link.tab-focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(75,170,244,.35);box-shadow:0 0 0 3px rgba(75,170,244,.35)}.grid{margin:0 auto;padding:20px}@media only screen and (min-width:768px){.grid{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;max-width:1280px}.grid>*{-webkit-box-flex:1;-ms-flex:1;flex:1}}html{font-size:100%}body{font-family:Avenir,'Helvetica Neue',sans-serif;line-height:1.5;color:#fff;font-weight:500;text-shadow:0 1px 1px rgba(0,0,0,.15);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}button,input,select,textarea{font:inherit}p,small{margin:0 0 20px}small{display:block;font-size:14px;font-size:.875rem}h1{margin:0 0 10px;font-weight:900;letter-spacing:-.025em;font-size:64px;font-size:4rem}.button,.button__count{position:relative;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:15px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.1);box-shadow:0 1px 1px rgba(0,0,0,.1);background:#fff;border:0;color:#55646b;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700;text-shadow:none}.button{padding-left:20px;padding-right:20px;-webkit-transition:all .2s ease;transition:all .2s ease}.button:focus,.button:hover{color:#343f4a;outline:0}.button:focus::after,.button:hover::after{display:none}.button.tab-focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(255,255,255,.35);box-shadow:0 0 0 3px rgba(255,255,255,.35)}.button__count{margin-left:10px;-webkit-animation:fadein .2s ease;animation:fadein .2s ease}.button__count::before{content:'';position:absolute;width:0;height:0;right:100%;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:5px solid transparent;border-right-color:#fff;border-left-width:0}header{padding-bottom:20px;text-align:center}header p{margin-bottom:30px;font-size:18px;font-size:1.125rem}@media only screen and (min-width:768px){header{max-width:400px;margin-right:40px;padding-bottom:40px;text-align:left}}.icon{fill:currentColor;width:16px;height:16px;vertical-align:-.15em}a svg,button svg,button.faux-link svg,label svg{pointer-events:none}.btn .icon,a .icon,button.faux-link .icon{margin-right:5px}button.faux-link{position:relative;margin:0;padding:0;width:auto;border:0;background:0 0;vertical-align:baseline;text-align:inherit;font:inherit;line-height:1.5;cursor:pointer;-moz-user-select:text;text-shadow:inherit;border-radius:0}a,button.faux-link{position:relative;border-bottom:1px dotted currentColor;-webkit-transition:all .2s ease;transition:all .2s ease;text-decoration:none;color:#fff;font-weight:700}a::after,button.faux-link::after{content:'';position:absolute;top:100%;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:0;height:1px;-webkit-transition:width .2s ease;transition:width .2s ease;background:currentColor}a:focus,a:hover,button.faux-link:focus,button.faux-link:hover{border-bottom-color:transparent;outline:0}a:focus::after,a:hover::after,button.faux-link:focus::after,button.faux-link:hover::after{width:100%}a.tab-focus,button.faux-link.tab-focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(255,255,255,.35);box-shadow:0 0 0 3px rgba(255,255,255,.35)}li,ul{list-style:none;margin:0;padding:0}nav{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:20px}video{max-width:100%;vertical-align:middle}.plyr{margin:0 auto;border-radius:4px;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.2);box-shadow:0 2px 5px rgba(0,0,0,.2)}.plyr__video-wrapper::after{content:'';pointer-events:none;position:absolute;top:0;bottom:0;left:0;right:0;border:1px solid rgba(0,0,0,.15);border-radius:inherit}.plyr__cite{display:none;margin-top:20px}.plyr__cite .icon{margin-right:5px}.plyr--audio~ul .plyr__cite--audio,.plyr--video:not(.plyr--youtube):not(.plyr--vimeo)~ul .plyr__cite--video,.plyr--vimeo~ul .plyr__cite--vimeo,.plyr--youtube~ul .plyr__cite--youtube{display:block}
\ No newline at end of file diff --git a/demo/dist/demo.js b/demo/dist/demo.js index d14d0752..533226ff 100644 --- a/demo/dist/demo.js +++ b/demo/dist/demo.js @@ -1 +1,3 @@ -"document"in self&&("classList"in document.createElement("_")?function(){"use strict";var t=document.createElement("_");if(t.classList.add("c1","c2"),!t.classList.contains("c2")){var e=function(t){var e=DOMTokenList.prototype[t];DOMTokenList.prototype[t]=function(t){var i,o=arguments.length;for(i=0;i<o;i++)t=arguments[i],e.call(this,t)}};e("add"),e("remove")}if(t.classList.toggle("c3",!1),t.classList.contains("c3")){var i=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(t,e){return 1 in arguments&&!this.contains(t)==!e?e:i.call(this,t)}}t=null}():function(t){"use strict";if("Element"in t){var e=t.Element.prototype,i=Object,o=String.prototype.trim||function(){return this.replace(/^\s+|\s+$/g,"")},n=Array.prototype.indexOf||function(t){for(var e=0,i=this.length;e<i;e++)if(e in this&&this[e]===t)return e;return-1},s=function(t,e){this.name=t,this.code=DOMException[t],this.message=e},r=function(t,e){if(""===e)throw new s("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(e))throw new s("INVALID_CHARACTER_ERR","String contains an invalid character");return n.call(t,e)},a=function(t){for(var e=o.call(t.getAttribute("class")||""),i=e?e.split(/\s+/):[],n=0,s=i.length;n<s;n++)this.push(i[n]);this._updateClassName=function(){t.setAttribute("class",this.toString())}},c=a.prototype=[],l=function(){return new a(this)};if(s.prototype=Error.prototype,c.item=function(t){return this[t]||null},c.contains=function(t){return t+="",-1!==r(this,t)},c.add=function(){var t,e=arguments,i=0,o=e.length,n=!1;do{t=e[i]+"",-1===r(this,t)&&(this.push(t),n=!0)}while(++i<o);n&&this._updateClassName()},c.remove=function(){var t,e,i=arguments,o=0,n=i.length,s=!1;do{for(t=i[o]+"",e=r(this,t);-1!==e;)this.splice(e,1),s=!0,e=r(this,t)}while(++o<n);s&&this._updateClassName()},c.toggle=function(t,e){t+="";var i=this.contains(t),o=i?!0!==e&&"remove":!1!==e&&"add";return o&&this[o](t),!0===e||!1===e?e:!i},c.toString=function(){return this.join(" ")},i.defineProperty){var u={get:l,enumerable:!0,configurable:!0};try{i.defineProperty(e,"classList",u)}catch(t){-2146823252===t.number&&(u.enumerable=!1,i.defineProperty(e,"classList",u))}}else i.prototype.__defineGetter__&&e.__defineGetter__("classList",l)}}(self)),document.addEventListener("focusout",function(t){t.target.classList.remove("tab-focus")}),document.addEventListener("keydown",function(t){9===t.keyCode&&window.setTimeout(function(){document.activeElement.classList.add("tab-focus")},0)}),function(){function t(t,e,i){t&&t.classList[i?"add":"remove"](e)}function e(e,r){if(e in n&&(r||e!==s)&&(s.length||e!==n.video)){switch(e){case n.video:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"}],poster:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg",tracks:[{kind:"captions",label:"English",srclang:"en",src:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt",default:!0},{kind:"captions",label:"French",srclang:"fr",src:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt"}]});break;case n.audio:i.source({type:"audio",title:"Kishi Bashi – “It All Began With A Burst”",sources:[{src:"https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]});break;case n.youtube:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://www.youtube.com/watch?v=bTqVqk7FSmY",type:"youtube"}]});break;case n.vimeo:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://vimeo.com/76979871",type:"vimeo"}]})}s=e;for(var a=o.length-1;a>=0;a--)t(o[a].parentElement,"active",!1);t(document.querySelector('[data-source="'+e+'"]'),"active",!0),[].forEach.call(document.querySelectorAll(".plyr__cite"),function(t){t.setAttribute("hidden","")}),document.querySelector(".plyr__cite--"+e).removeAttribute("hidden")}}window.shr&&window.shr.setup({count:{classname:"button__count"}});var i=new Plyr("#player",{debug:!0,title:"View From A Blue Moon",iconUrl:"../dist/plyr.svg",tooltips:{controls:!0},captions:{defaultActive:!0},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","fullscreen","pip","airplay"]});window.player=i;var o=document.querySelectorAll("[data-source]"),n={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},s=window.location.hash.replace("#",""),r=window.history&&window.history.pushState;if([].forEach.call(o,function(t){t.addEventListener("click",function(){var t=this.getAttribute("data-source");e(t),r&&history.pushState({type:t},"","#"+t)})}),window.addEventListener("popstate",function(t){t.state&&"type"in t.state&&e(t.state.type)}),r){var a=!s.length;a&&(s=n.video),s in n&&history.replaceState({type:s},"",a?"":"#"+s),s!==n.video&&e(s,!0)}}(),"plyr.io"===window.location.host&&(!function(t,e,i,o,n,s,r){t.GoogleAnalyticsObject=n,t[n]=t[n]||function(){(t[n].q=t[n].q||[]).push(arguments)},t[n].l=1*new Date,s=e.createElement(i),r=e.getElementsByTagName(i)[0],s.async=1,s.src="//www.google-analytics.com/analytics.js",r.parentNode.insertBefore(s,r)}(window,document,"script",0,"ga"),window.ga("create","UA-40881672-11","auto"),window.ga("send","pageview"));
\ No newline at end of file +document.addEventListener("DOMContentLoaded",function(){function e(e,t,o){e&&e.classList[o?"add":"remove"](t)}function t(t,a){if(t in n&&(a||t!==r)&&(r.length||t!==n.video)){switch(t){case n.video:o.src={type:"video",title:"View From A Blue Moon",sources:[{src:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"}],poster:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg",tracks:[{kind:"captions",label:"English",srclang:"en",src:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt",default:!0},{kind:"captions",label:"French",srclang:"fr",src:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt"}]};break;case n.audio:o.src={type:"audio",title:"Kishi Bashi – “It All Began With A Burst”",sources:[{src:"https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]};break;case n.youtube:o.src={type:"video",title:"View From A Blue Moon",sources:[{src:"https://www.youtube.com/watch?v=bTqVqk7FSmY",type:"youtube"}]};break;case n.vimeo:o.src={type:"video",title:"View From A Blue Moon",sources:[{src:"https://vimeo.com/76979871",type:"vimeo"}]}}r=t,Array.from(i).forEach(function(t){return e(t.parentElement,"active",!1)}),e(document.querySelector('[data-source="'+t+'"]'),"active",!0),Array.from(document.querySelectorAll(".plyr__cite")).forEach(function(e){e.setAttribute("hidden","")}),document.querySelector(".plyr__cite--"+t).removeAttribute("hidden")}}window.shr&&window.shr.setup({count:{classname:"button__count"}});document.addEventListener("focusout",function(e){e.target.classList.remove("tab-focus")}),document.addEventListener("keydown",function(e){9===e.keyCode&&window.setTimeout(function(){document.activeElement.classList.add("tab-focus")},0)});var o=new window.Plyr("#player",{debug:!0,title:"View From A Blue Moon",iconUrl:"../dist/plyr.svg",tooltips:{controls:!0},captions:{active:!0},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","fullscreen","pip","airplay"]});window.player=o;var i=document.querySelectorAll("[data-source]"),n={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},r=window.location.hash.replace("#",""),a=window.history&&window.history.pushState;if(Array.from(i).forEach(function(e){e.addEventListener("click",function(){var o=e.getAttribute("data-source");t(o),a&&window.history.pushState({type:o},"","#"+o)})}),window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),a){var s=!r.length;s&&(r=n.video),r in n&&window.history.replaceState({type:r},"",s?"":"#"+r),r!==n.video&&t(r,!0)}}),"plyr.io"===window.location.host&&(!function(e,t,o,i,n,r,a){e.GoogleAnalyticsObject=n,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,r=t.createElement(o),a=t.getElementsByTagName(o)[0],r.async=1,r.src="//www.google-analytics.com/analytics.js",a.parentNode.insertBefore(r,a)}(window,document,"script",0,"ga"),window.ga("create","UA-40881672-11","auto"),window.ga("send","pageview")); + +//# sourceMappingURL=demo.js.map diff --git a/demo/dist/demo.js.map b/demo/dist/demo.js.map new file mode 100644 index 00000000..0969f4ea --- /dev/null +++ b/demo/dist/demo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"demo.js","sources":["demo/src/js/demo.js"],"sourcesContent":["// ==========================================================================\n// Plyr.io demo\n// This code is purely for the https://plyr.io website\n// Please see readme.md in the root or github.com/sampotts/plyr\n// ==========================================================================\n\ndocument.addEventListener('DOMContentLoaded', () => {\n if (window.shr) {\n window.shr.setup({\n count: {\n classname: 'button__count',\n },\n });\n }\n\n // Setup tab focus\n const tabClassName = 'tab-focus';\n\n // Remove class on blur\n document.addEventListener('focusout', event => {\n event.target.classList.remove(tabClassName);\n });\n\n // Add classname to tabbed elements\n document.addEventListener('keydown', event => {\n if (event.keyCode !== 9) {\n return;\n }\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n window.setTimeout(() => {\n document.activeElement.classList.add(tabClassName);\n }, 0);\n });\n\n /* document.body.addEventListener('ready', function(event) {\n console.log(event);\n }); */\n\n // Setup the player\n const player = new window.Plyr('#player', {\n debug: true,\n title: 'View From A Blue Moon',\n iconUrl: '../dist/plyr.svg',\n tooltips: {\n controls: true,\n },\n captions: {\n active: true,\n },\n controls: [\n 'play-large',\n 'play',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'fullscreen',\n 'pip',\n 'airplay',\n ],\n });\n\n // Expose for testing\n window.player = player;\n\n // Setup type toggle\n const buttons = document.querySelectorAll('[data-source]');\n const types = {\n video: 'video',\n audio: 'audio',\n youtube: 'youtube',\n vimeo: 'vimeo',\n };\n let currentType = window.location.hash.replace('#', '');\n const historySupport = window.history && window.history.pushState;\n\n // Toggle class on an element\n function toggleClass(element, className, state) {\n if (element) {\n element.classList[state ? 'add' : 'remove'](className);\n }\n }\n\n // Set a new source\n function newSource(type, init) {\n // Bail if new type isn't known, it's the current type, or current type is empty (video is default) and new type is video\n if (!(type in types) || (!init && type === currentType) || (!currentType.length && type === types.video)) {\n return;\n }\n\n switch (type) {\n case types.video:\n player.src = {\n type: 'video',\n title: 'View From A Blue Moon',\n sources: [\n {\n src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4',\n type: 'video/mp4',\n },\n ],\n poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg',\n tracks: [\n {\n kind: 'captions',\n label: 'English',\n srclang: 'en',\n src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt',\n default: true,\n },\n {\n kind: 'captions',\n label: 'French',\n srclang: 'fr',\n src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt',\n },\n ],\n };\n\n break;\n\n case types.audio:\n player.src = {\n type: 'audio',\n title: 'Kishi Bashi – “It All Began With A Burst”',\n sources: [\n {\n src: 'https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3',\n type: 'audio/mp3',\n },\n {\n src: 'https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg',\n type: 'audio/ogg',\n },\n ],\n };\n\n break;\n\n case types.youtube:\n player.src = {\n type: 'video',\n title: 'View From A Blue Moon',\n sources: [\n {\n src: 'https://www.youtube.com/watch?v=bTqVqk7FSmY',\n type: 'youtube',\n },\n ],\n };\n\n break;\n\n case types.vimeo:\n player.src = {\n type: 'video',\n title: 'View From A Blue Moon',\n sources: [\n {\n src: 'https://vimeo.com/76979871',\n type: 'vimeo',\n },\n ],\n };\n\n break;\n\n default:\n break;\n }\n\n // Set the current type for next time\n currentType = type;\n\n // Remove active classes\n Array.from(buttons).forEach(button => toggleClass(button.parentElement, 'active', false));\n\n // Set active on parent\n toggleClass(document.querySelector(`[data-source=\"${type}\"]`), 'active', true);\n\n // Show cite\n Array.from(document.querySelectorAll('.plyr__cite')).forEach(cite => {\n cite.setAttribute('hidden', '');\n });\n document.querySelector(`.plyr__cite--${type}`).removeAttribute('hidden');\n }\n\n // Bind to each button\n Array.from(buttons).forEach(button => {\n button.addEventListener('click', () => {\n const type = button.getAttribute('data-source');\n\n newSource(type);\n\n if (historySupport) {\n window.history.pushState({ type }, '', `#${type}`);\n }\n });\n });\n\n // List for backwards/forwards\n window.addEventListener('popstate', event => {\n if (event.state && 'type' in event.state) {\n newSource(event.state.type);\n }\n });\n\n // On load\n if (historySupport) {\n const video = !currentType.length;\n\n // If there's no current type set, assume video\n if (video) {\n currentType = types.video;\n }\n\n // Replace current history state\n if (currentType in types) {\n window.history.replaceState(\n {\n type: currentType,\n },\n '',\n video ? '' : `#${currentType}`\n );\n }\n\n // If it's not video, load the source\n if (currentType !== types.video) {\n newSource(currentType, true);\n }\n }\n});\n\n// Google analytics\n// For demo site (https://plyr.io) only\n/* eslint-disable */\nif (window.location.host === 'plyr.io') {\n (function(i, s, o, g, r, a, m) {\n i.GoogleAnalyticsObject = r;\n i[r] =\n i[r] ||\n function() {\n (i[r].q = i[r].q || []).push(arguments);\n };\n i[r].l = 1 * new Date();\n a = s.createElement(o);\n m = s.getElementsByTagName(o)[0];\n a.async = 1;\n a.src = g;\n m.parentNode.insertBefore(a, m);\n })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');\n window.ga('create', 'UA-40881672-11', 'auto');\n window.ga('send', 'pageview');\n}\n/* eslint-enable */\n"],"names":["document","addEventListener","toggleClass","element","className","state","classList","newSource","type","init","types","currentType","length","video","src","audio","youtube","vimeo","from","buttons","forEach","button","parentElement","querySelector","querySelectorAll","setAttribute","removeAttribute","window","shr","setup","target","remove","event","keyCode","setTimeout","activeElement","add","player","Plyr","location","hash","replace","historySupport","history","pushState","getAttribute","replaceState","host","i","s","o","g","r","a","m","GoogleAnalyticsObject","q","push","arguments","l","Date","createElement","getElementsByTagName","async","parentNode","insertBefore","ga"],"mappings":"AAMAA,SAASC,iBAAiB,mBAAoB,oBA2EjCC,EAAYC,EAASC,EAAWC,GACjCF,KACQG,UAAUD,EAAQ,MAAQ,UAAUD,YAK3CG,EAAUC,EAAMC,MAEfD,KAAQE,IAAYD,GAAQD,IAASG,KAAkBA,EAAYC,QAAUJ,IAASE,EAAMG,eAI1FL,QACCE,EAAMG,QACAC,UACG,cACC,sCAGM,4EACC,qBAGN,qFAGM,iBACC,kBACE,SACJ,mFACI,SAGH,iBACC,iBACE,SACJ,wFAOhBJ,EAAMK,QACAD,UACG,cACC,4EAGM,mFACC,kBAGD,mFACC,0BAOjBJ,EAAMM,UACAF,UACG,cACC,sCAGM,mDACC,wBAOjBJ,EAAMO,QACAH,UACG,cACC,sCAGM,kCACC,aAYZN,QAGRU,KAAKC,GAASC,QAAQ,mBAAUlB,EAAYmB,EAAOC,cAAe,UAAU,OAGtEtB,SAASuB,+BAA+Bf,QAAW,UAAU,SAGnEU,KAAKlB,SAASwB,iBAAiB,gBAAgBJ,QAAQ,cACpDK,aAAa,SAAU,eAEvBF,8BAA8Bf,GAAQkB,gBAAgB,WArL/DC,OAAOC,YACAA,IAAIC,wBAEQ,4BASd5B,iBAAiB,WAAY,cAC5B6B,OAAOxB,UAAUyB,OAJN,wBAQZ9B,iBAAiB,UAAW,YACX,IAAlB+B,EAAMC,gBAMHC,WAAW,oBACLC,cAAc7B,UAAU8B,IAhBpB,cAiBd,SAQDC,EAAS,IAAIV,OAAOW,KAAK,kBACpB,QACA,gCACE,uCAEK,qBAGF,aAGR,aACA,OACA,WACA,eACA,OACA,SACA,WACA,WACA,aACA,MACA,oBAKDD,OAASA,MAGVlB,EAAUnB,SAASwB,iBAAiB,iBACpCd,SACK,cACA,gBACE,gBACF,SAEPC,EAAcgB,OAAOY,SAASC,KAAKC,QAAQ,IAAK,IAC9CC,EAAiBf,OAAOgB,SAAWhB,OAAOgB,QAAQC,mBAkHlD1B,KAAKC,GAASC,QAAQ,cACjBnB,iBAAiB,QAAS,eACvBO,EAAOa,EAAOwB,aAAa,iBAEvBrC,GAENkC,UACOC,QAAQC,WAAYpC,QAAQ,OAAQA,cAMhDP,iBAAiB,WAAY,YAC5B+B,EAAM3B,OAAS,SAAU2B,EAAM3B,SACrB2B,EAAM3B,MAAMG,QAK1BkC,EAAgB,KACV7B,GAASF,EAAYC,OAGvBC,MACcH,EAAMG,OAIpBF,KAAeD,UACRiC,QAAQG,mBAEDnC,GAEV,GACAE,EAAQ,OAASF,GAKrBA,IAAgBD,EAAMG,SACZF,GAAa,MAQN,YAAzBgB,OAAOY,SAASQ,iBACNC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,KACtBC,sBAAwBH,IAC1B,GACIJ,EAAA,IACA,YACKA,EAAA,GAAKQ,EAAIR,EAAA,GAAKQ,OAASC,KAAKC,cAErC,GAAKC,EAAI,EAAI,IAAIC,OACbX,EAAEY,cAAcX,KAChBD,EAAEa,qBAAqBZ,GAAG,KAC5Ba,MAAQ,IACRjD,IAEyB,4CADzBkD,WAAWC,aAAaZ,EAAGC,IAC9B3B,OAAQ3B,SAAU,SAAU,EAA2C,aACnEkE,GAAG,SAAU,iBAAkB,eAC/BA,GAAG,OAAQ"}
\ No newline at end of file diff --git a/demo/dist/demo.svg b/demo/dist/demo.svg deleted file mode 100644 index 6f09b44b..00000000 --- a/demo/dist/demo.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg"><symbol id="icon-github" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 .2c-4.4 0-8 3.6-8 8 0 3.5 2.3 6.5 5.5 7.6.4.1.5-.2.5-.4V14c-2.2.5-2.7-1-2.7-1-.4-.9-.9-1.2-.9-1.2-.7-.5.1-.5.1-.5.8.1 1.2.8 1.2.8.7 1.3 1.9.9 2.3.7.1-.5.3-.9.5-1.1-1.8-.2-3.6-.9-3.6-4 0-.9.3-1.6.8-2.1-.1-.2-.4-1 .1-2.1 0 0 .7-.2 2.2.8.6-.2 1.3-.3 2-.3s1.4.1 2 .3c1.5-1 2.2-.8 2.2-.8.4 1.1.2 1.9.1 2.1.5.6.8 1.3.8 2.1 0 3.1-1.9 3.7-3.7 3.9.3.4.6.9.6 1.6v2.2c0 .2.1.5.6.4 3.2-1.1 5.5-4.1 5.5-7.6-.1-4.4-3.7-8-8.1-8z"/></symbol><symbol id="icon-twitter" viewBox="0 0 16 16"><title>Twitter</title><path d="M16 3c-.6.3-1.2.4-1.9.5.7-.4 1.2-1 1.4-1.8-.6.4-1.3.6-2.1.8-.6-.6-1.5-1-2.4-1-1.7 0-3.2 1.5-3.2 3.3 0 .3 0 .5.1.7-2.7-.1-5.2-1.4-6.8-3.4-.3.5-.4 1-.4 1.7 0 1.1.6 2.1 1.5 2.7-.5 0-1-.2-1.5-.4C.7 7.7 1.8 9 3.3 9.3c-.3.1-.6.1-.9.1-.2 0-.4 0-.6-.1.4 1.3 1.6 2.3 3.1 2.3-1.1.9-2.5 1.4-4.1 1.4H0c1.5.9 3.2 1.5 5 1.5 6 0 9.3-5 9.3-9.3v-.4C15 4.3 15.6 3.7 16 3z"/></symbol><symbol id="icon-vimeo" viewBox="0 0 16 16"><path d="M16 4.3c-.1 1.6-1.2 3.7-3.3 6.4-2.2 2.8-4 4.2-5.5 4.2-.9 0-1.7-.9-2.4-2.6C4 9.9 3.4 5 2 5c-.1 0-.5.3-1.2.8l-.8-1c.8-.7 3.5-3.4 4.7-3.5 1.2-.1 2 .7 2.3 2.5.3 2 .8 6.1 1.8 6.1.9 0 2.5-3.4 2.6-4 .1-.9-.3-1.9-2.3-1.1.8-2.6 2.3-3.8 4.5-3.8 1.7.1 2.5 1.2 2.4 3.3z"/></symbol><symbol id="icon-youtube" viewBox="0 0 16 16"><path d="M15.8 4.8c-.2-1.3-.8-2.2-2.2-2.4C11.4 2 8 2 8 2s-3.4 0-5.6.4C1 2.6.3 3.5.2 4.8 0 6.1 0 8 0 8s0 1.9.2 3.2c.2 1.3.8 2.2 2.2 2.4C4.6 14 8 14 8 14s3.4 0 5.6-.4c1.4-.3 2-1.1 2.2-2.4C16 9.9 16 8 16 8s0-1.9-.2-3.2zM6 11V5l5 3-5 3z"/></symbol></svg>
\ No newline at end of file diff --git a/demo/index.html b/demo/index.html index c9560d02..b2142269 100644 --- a/demo/index.html +++ b/demo/index.html @@ -24,20 +24,26 @@ <div class="grid"> <header> <h1>Plyr</h1> - <p>A simple, accessible HTML5 - <button type="button" class="faux-link" data-source="video">Video</button>, - <button type="button" class="faux-link" data-source="audio">Audio</button>, + <p>A simple, accessible + <button type="button" class="faux-link" data-source="video"> + <svg class="icon" title="HTML5"> + <path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path> + </svg>Video</button>, + <button type="button" class="faux-link" data-source="audio"> + <svg class="icon" title="HTML5"> + <path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path> + </svg>Audio</button>, <button type="button" class="faux-link" data-source="youtube"> - <svg class="icon"> + <svg class="icon" title="YouTube"> <path d="M15.8,4.8c-0.2-1.3-0.8-2.2-2.2-2.4C11.4,2,8,2,8,2S4.6,2,2.4,2.4C1,2.6,0.3,3.5,0.2,4.8C0,6.1,0,8,0,8 s0,1.9,0.2,3.2c0.2,1.3,0.8,2.2,2.2,2.4C4.6,14,8,14,8,14s3.4,0,5.6-0.4c1.4-0.3,2-1.1,2.2-2.4C16,9.9,16,8,16,8S16,6.1,15.8,4.8z - M6,11V5l5,3L6,11z" /> + M6,11V5l5,3L6,11z"></path> </svg>YouTube</button> and <button type="button" class="faux-link" data-source="vimeo"> - <svg class="icon"> + <svg class="icon" title="Vimeo"> <path d="M16,4.3c-0.1,1.6-1.2,3.7-3.3,6.4c-2.2,2.8-4,4.2-5.5,4.2c-0.9,0-1.7-0.9-2.4-2.6C4,9.9,3.4,5,2,5 C1.9,5,1.5,5.3,0.8,5.8L0,4.8c0.8-0.7,3.5-3.4,4.7-3.5C5.9,1.2,6.7,2,7,3.8c0.3,2,0.8,6.1,1.8,6.1c0.9,0,2.5-3.4,2.6-4 - c0.1-0.9-0.3-1.9-2.3-1.1c0.8-2.6,2.3-3.8,4.5-3.8C15.3,1.1,16.1,2.2,16,4.3z" /> + c0.1-0.9-0.3-1.9-2.3-1.1c0.8-2.6,2.3-3.8,4.5-3.8C15.3,1.1,16.1,2.2,16,4.3z"></path> </svg>Vimeo</button> media player. </p> @@ -49,7 +55,7 @@ c0.8,0.1,1.2,0.8,1.2,0.8C4.4,13.4,5.6,13,6,12.8c0.1-0.5,0.3-0.9,0.5-1.1c-1.8-0.2-3.6-0.9-3.6-4c0-0.9,0.3-1.6,0.8-2.1 c-0.1-0.2-0.4-1,0.1-2.1c0,0,0.7-0.2,2.2,0.8c0.6-0.2,1.3-0.3,2-0.3c0.7,0,1.4,0.1,2,0.3c1.5-1,2.2-0.8,2.2-0.8 c0.4,1.1,0.2,1.9,0.1,2.1c0.5,0.6,0.8,1.3,0.8,2.1c0,3.1-1.9,3.7-3.7,3.9C9.7,12,10,12.5,10,13.2c0,1.1,0,1.9,0,2.2 - c0,0.2,0.1,0.5,0.6,0.4c3.2-1.1,5.5-4.1,5.5-7.6C16,3.8,12.4,0.2,8,0.2z" /> + c0,0.2,0.1,0.5,0.6,0.4c3.2-1.1,5.5-4.1,5.5-7.6C16,3.8,12.4,0.2,8,0.2z"></path> </svg> Download on GitHub </a> @@ -72,22 +78,28 @@ <ul> <li class="plyr__cite plyr__cite--video" hidden> <small> - <a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> © Brainfarm + <a href="http://viewfromabluemoon.com/" target="_blank"> + <svg class="icon" title="HTML5"> + <path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path> + </svg>View From A Blue Moon</a> © Brainfarm </small> </li> <li class="plyr__cite plyr__cite--audio" hidden> <small> - <a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi – “It All Began With A Burst”</a> © Kishi Bashi + <a href="http://www.kishibashi.com/" target="_blank"> + <svg class="icon" title="HTML5"> + <path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path> + </svg>Kishi Bashi – “It All Began With A Burst”</a> © Kishi Bashi </small> </li> <li class="plyr__cite plyr__cite--youtube" hidden> <small> <a href="https://www.youtube.com/watch?v=bTqVqk7FSmY" target="_blank">View From A Blue Moon</a> on <span class="color--youtube"> - <svg class="icon"> + <svg class="icon" title="YouTube"> <path d="M15.8,4.8c-0.2-1.3-0.8-2.2-2.2-2.4C11.4,2,8,2,8,2S4.6,2,2.4,2.4C1,2.6,0.3,3.5,0.2,4.8C0,6.1,0,8,0,8 s0,1.9,0.2,3.2c0.2,1.3,0.8,2.2,2.2,2.4C4.6,14,8,14,8,14s3.4,0,5.6-0.4c1.4-0.3,2-1.1,2.2-2.4C16,9.9,16,8,16,8S16,6.1,15.8,4.8z - M6,11V5l5,3L6,11z" /> + M6,11V5l5,3L6,11z"></path> </svg>YouTube </span> </small> @@ -96,10 +108,10 @@ <small> <a href="https://vimeo.com/ondemand/viewfromabluemoon4k" target="_blank">View From A Blue Moon</a> on <span class="color--vimeo"> - <svg class="icon"> + <svg class="icon" title="Vimeo"> <path d="M16,4.3c-0.1,1.6-1.2,3.7-3.3,6.4c-2.2,2.8-4,4.2-5.5,4.2c-0.9,0-1.7-0.9-2.4-2.6C4,9.9,3.4,5,2,5 C1.9,5,1.5,5.3,0.8,5.8L0,4.8c0.8-0.7,3.5-3.4,4.7-3.5C5.9,1.2,6.7,2,7,3.8c0.3,2,0.8,6.1,1.8,6.1c0.9,0,2.5-3.4,2.6-4 - c0.1-0.9-0.3-1.9-2.3-1.1c0.8-2.6,2.3-3.8,4.5-3.8C15.3,1.1,16.1,2.2,16,4.3z" /> + c0.1-0.9-0.3-1.9-2.3-1.1c0.8-2.6,2.3-3.8,4.5-3.8C15.3,1.1,16.1,2.2,16,4.3z"></path> </svg>Vimeo </span> </small> @@ -114,8 +126,7 @@ <path d="M16,3c-0.6,0.3-1.2,0.4-1.9,0.5c0.7-0.4,1.2-1,1.4-1.8c-0.6,0.4-1.3,0.6-2.1,0.8c-0.6-0.6-1.5-1-2.4-1 C9.3,1.5,7.8,3,7.8,4.8c0,0.3,0,0.5,0.1,0.7C5.2,5.4,2.7,4.1,1.1,2.1c-0.3,0.5-0.4,1-0.4,1.7c0,1.1,0.6,2.1,1.5,2.7 c-0.5,0-1-0.2-1.5-0.4c0,0,0,0,0,0c0,1.6,1.1,2.9,2.6,3.2C3,9.4,2.7,9.4,2.4,9.4c-0.2,0-0.4,0-0.6-0.1c0.4,1.3,1.6,2.3,3.1,2.3 - c-1.1,0.9-2.5,1.4-4.1,1.4c-0.3,0-0.5,0-0.8,0c1.5,0.9,3.2,1.5,5,1.5c6,0,9.3-5,9.3-9.3c0-0.1,0-0.3,0-0.4C15,4.3,15.6,3.7,16,3z" - /> + c-1.1,0.9-2.5,1.4-4.1,1.4c-0.3,0-0.5,0-0.8,0c1.5,0.9,3.2,1.5,5,1.5c6,0,9.3-5,9.3-9.3c0-0.1,0-0.3,0-0.4C15,4.3,15.6,3.7,16,3z"></path> </svg> <p>If you think others would like Plyr, <a href="https://twitter.com/intent/tweet?text=A+simple+HTML5+media+player+with+custom+controls+and+WebVTT+captions.&url=http%3A%2F%2Fplyr.io&via=Sam_Potts" @@ -123,8 +134,11 @@ </p> </aside> + <!-- Polyfills --> + <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es6,Array.prototype.includes,CustomEvent"></script> + <!-- Plyr core script --> - <script src="../src/js/plyr.js"></script> + <script src="../dist/plyr.js"></script> <!-- Sharing libary (https://shr.one) --> <script src="https://cdn.shr.one/1.0.1/shr.js"></script> diff --git a/demo/src/js/main.js b/demo/src/js/demo.js index bc2ea0aa..eef49596 100644 --- a/demo/src/js/main.js +++ b/demo/src/js/demo.js @@ -4,9 +4,7 @@ // Please see readme.md in the root or github.com/sampotts/plyr // ========================================================================== -/*global Plyr*/ - -(function() { +document.addEventListener('DOMContentLoaded', () => { if (window.shr) { window.shr.setup({ count: { @@ -15,12 +13,33 @@ }); } - /*document.body.addEventListener('ready', function(event) { + // Setup tab focus + const tabClassName = 'tab-focus'; + + // Remove class on blur + document.addEventListener('focusout', event => { + event.target.classList.remove(tabClassName); + }); + + // Add classname to tabbed elements + document.addEventListener('keydown', event => { + if (event.keyCode !== 9) { + return; + } + + // Delay the adding of classname until the focus has changed + // This event fires before the focusin event + window.setTimeout(() => { + document.activeElement.classList.add(tabClassName); + }, 0); + }); + + /* document.body.addEventListener('ready', function(event) { console.log(event); - });*/ + }); */ // Setup the player - var player = new Plyr('#player', { + const player = new window.Plyr('#player', { debug: true, title: 'View From A Blue Moon', iconUrl: '../dist/plyr.svg', @@ -28,70 +47,36 @@ controls: true, }, captions: { - defaultActive: true, + active: true, }, - controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'fullscreen', 'pip', 'airplay'], + controls: [ + 'play-large', + 'play', + 'progress', + 'current-time', + 'mute', + 'volume', + 'captions', + 'settings', + 'fullscreen', + 'pip', + 'airplay', + ], }); // Expose for testing window.player = player; // Setup type toggle - var buttons = document.querySelectorAll('[data-source]'); - var types = { + const buttons = document.querySelectorAll('[data-source]'); + const types = { video: 'video', audio: 'audio', youtube: 'youtube', vimeo: 'vimeo', }; - var currentType = window.location.hash.replace('#', ''); - var historySupport = window.history && window.history.pushState; - - // Bind to each button - [].forEach.call(buttons, function(button) { - button.addEventListener('click', function() { - var type = this.getAttribute('data-source'); - - newSource(type); - - if (historySupport) { - history.pushState({ type: type }, '', '#' + type); - } - }); - }); - - // List for backwards/forwards - window.addEventListener('popstate', function(event) { - if (event.state && 'type' in event.state) { - newSource(event.state.type); - } - }); - - // On load - if (historySupport) { - var video = !currentType.length; - - // If there's no current type set, assume video - if (video) { - currentType = types.video; - } - - // Replace current history state - if (currentType in types) { - history.replaceState( - { - type: currentType, - }, - '', - video ? '' : '#' + currentType - ); - } - - // If it's not video, load the source - if (currentType !== types.video) { - newSource(currentType, true); - } - } + let currentType = window.location.hash.replace('#', ''); + const historySupport = window.history && window.history.pushState; // Toggle class on an element function toggleClass(element, className, state) { @@ -109,7 +94,7 @@ switch (type) { case types.video: - player.source({ + player.src = { type: 'video', title: 'View From A Blue Moon', sources: [ @@ -134,11 +119,12 @@ src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt', }, ], - }); + }; + break; case types.audio: - player.source({ + player.src = { type: 'audio', title: 'Kishi Bashi – “It All Began With A Burst”', sources: [ @@ -151,11 +137,12 @@ type: 'audio/ogg', }, ], - }); + }; + break; case types.youtube: - player.source({ + player.src = { type: 'video', title: 'View From A Blue Moon', sources: [ @@ -164,11 +151,12 @@ type: 'youtube', }, ], - }); + }; + break; case types.vimeo: - player.source({ + player.src = { type: 'video', title: 'View From A Blue Moon', sources: [ @@ -177,7 +165,11 @@ type: 'vimeo', }, ], - }); + }; + + break; + + default: break; } @@ -185,23 +177,68 @@ currentType = type; // Remove active classes - for (var x = buttons.length - 1; x >= 0; x--) { - toggleClass(buttons[x].parentElement, 'active', false); - } + Array.from(buttons).forEach(button => toggleClass(button.parentElement, 'active', false)); // Set active on parent - toggleClass(document.querySelector('[data-source="' + type + '"]'), 'active', true); + toggleClass(document.querySelector(`[data-source="${type}"]`), 'active', true); // Show cite - [].forEach.call(document.querySelectorAll('.plyr__cite'), function(cite) { + Array.from(document.querySelectorAll('.plyr__cite')).forEach(cite => { cite.setAttribute('hidden', ''); }); - document.querySelector('.plyr__cite--' + type).removeAttribute('hidden'); + document.querySelector(`.plyr__cite--${type}`).removeAttribute('hidden'); + } + + // Bind to each button + Array.from(buttons).forEach(button => { + button.addEventListener('click', () => { + const type = button.getAttribute('data-source'); + + newSource(type); + + if (historySupport) { + window.history.pushState({ type }, '', `#${type}`); + } + }); + }); + + // List for backwards/forwards + window.addEventListener('popstate', event => { + if (event.state && 'type' in event.state) { + newSource(event.state.type); + } + }); + + // On load + if (historySupport) { + const video = !currentType.length; + + // If there's no current type set, assume video + if (video) { + currentType = types.video; + } + + // Replace current history state + if (currentType in types) { + window.history.replaceState( + { + type: currentType, + }, + '', + video ? '' : `#${currentType}` + ); + } + + // If it's not video, load the source + if (currentType !== types.video) { + newSource(currentType, true); + } } -})(); +}); // Google analytics // For demo site (https://plyr.io) only +/* eslint-disable */ if (window.location.host === 'plyr.io') { (function(i, s, o, g, r, a, m) { i.GoogleAnalyticsObject = r; @@ -220,3 +257,4 @@ if (window.location.host === 'plyr.io') { window.ga('create', 'UA-40881672-11', 'auto'); window.ga('send', 'pageview'); } +/* eslint-enable */ diff --git a/demo/src/js/lib/classlist.js b/demo/src/js/lib/classlist.js deleted file mode 100644 index eac1e99e..00000000 --- a/demo/src/js/lib/classlist.js +++ /dev/null @@ -1,237 +0,0 @@ -/* - * classList.js: Cross-browser full element.classList implementation. - * 1.1.20150312 - * - * By Eli Grey, http://eligrey.com - * License: Dedicated to the public domain. - * See https://github.com/eligrey/classList.js/blob/master/LICENSE.md - */ - -/*global self, document, DOMException */ - -/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */ - -if ("document" in self) { - -// Full polyfill for browsers with no classList support -if (!("classList" in document.createElement("_"))) { - -(function (view) { - -"use strict"; - -if (!('Element' in view)) return; - -var - classListProp = "classList" - , protoProp = "prototype" - , elemCtrProto = view.Element[protoProp] - , objCtr = Object - , strTrim = String[protoProp].trim || function () { - return this.replace(/^\s+|\s+$/g, ""); - } - , arrIndexOf = Array[protoProp].indexOf || function (item) { - var - i = 0 - , len = this.length - ; - for (; i < len; i++) { - if (i in this && this[i] === item) { - return i; - } - } - return -1; - } - // Vendors: please allow content code to instantiate DOMExceptions - , DOMEx = function (type, message) { - this.name = type; - this.code = DOMException[type]; - this.message = message; - } - , checkTokenAndGetIndex = function (classList, token) { - if (token === "") { - throw new DOMEx( - "SYNTAX_ERR" - , "An invalid or illegal string was specified" - ); - } - if (/\s/.test(token)) { - throw new DOMEx( - "INVALID_CHARACTER_ERR" - , "String contains an invalid character" - ); - } - return arrIndexOf.call(classList, token); - } - , ClassList = function (elem) { - var - trimmedClasses = strTrim.call(elem.getAttribute("class") || "") - , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] - , i = 0 - , len = classes.length - ; - for (; i < len; i++) { - this.push(classes[i]); - } - this._updateClassName = function () { - elem.setAttribute("class", this.toString()); - }; - } - , classListProto = ClassList[protoProp] = [] - , classListGetter = function () { - return new ClassList(this); - } -; -// Most DOMException implementations don't allow calling DOMException's toString() -// on non-DOMExceptions. Error's toString() is sufficient here. -DOMEx[protoProp] = Error[protoProp]; -classListProto.item = function (i) { - return this[i] || null; -}; -classListProto.contains = function (token) { - token += ""; - return checkTokenAndGetIndex(this, token) !== -1; -}; -classListProto.add = function () { - var - tokens = arguments - , i = 0 - , l = tokens.length - , token - , updated = false - ; - do { - token = tokens[i] + ""; - if (checkTokenAndGetIndex(this, token) === -1) { - this.push(token); - updated = true; - } - } - while (++i < l); - - if (updated) { - this._updateClassName(); - } -}; -classListProto.remove = function () { - var - tokens = arguments - , i = 0 - , l = tokens.length - , token - , updated = false - , index - ; - do { - token = tokens[i] + ""; - index = checkTokenAndGetIndex(this, token); - while (index !== -1) { - this.splice(index, 1); - updated = true; - index = checkTokenAndGetIndex(this, token); - } - } - while (++i < l); - - if (updated) { - this._updateClassName(); - } -}; -classListProto.toggle = function (token, force) { - token += ""; - - var - result = this.contains(token) - , method = result ? - force !== true && "remove" - : - force !== false && "add" - ; - - if (method) { - this[method](token); - } - - if (force === true || force === false) { - return force; - } else { - return !result; - } -}; -classListProto.toString = function () { - return this.join(" "); -}; - -if (objCtr.defineProperty) { - var classListPropDesc = { - get: classListGetter - , enumerable: true - , configurable: true - }; - try { - objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); - } catch (ex) { // IE 8 doesn't support enumerable:true - if (ex.number === -0x7FF5EC54) { - classListPropDesc.enumerable = false; - objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); - } - } -} else if (objCtr[protoProp].__defineGetter__) { - elemCtrProto.__defineGetter__(classListProp, classListGetter); -} - -}(self)); - -} else { -// There is full or partial native classList support, so just check if we need -// to normalize the add/remove and toggle APIs. - -(function () { - "use strict"; - - var testElement = document.createElement("_"); - - testElement.classList.add("c1", "c2"); - - // Polyfill for IE 10/11 and Firefox <26, where classList.add and - // classList.remove exist but support only one argument at a time. - if (!testElement.classList.contains("c2")) { - var createMethod = function(method) { - var original = DOMTokenList.prototype[method]; - - DOMTokenList.prototype[method] = function(token) { - var i, len = arguments.length; - - for (i = 0; i < len; i++) { - token = arguments[i]; - original.call(this, token); - } - }; - }; - createMethod('add'); - createMethod('remove'); - } - - testElement.classList.toggle("c3", false); - - // Polyfill for IE 10 and Firefox <24, where classList.toggle does not - // support the second argument. - if (testElement.classList.contains("c3")) { - var _toggle = DOMTokenList.prototype.toggle; - - DOMTokenList.prototype.toggle = function(token, force) { - if (1 in arguments && !this.contains(token) === !force) { - return force; - } else { - return _toggle.call(this, token); - } - }; - - } - - testElement = null; -}()); - -} - -}
\ No newline at end of file diff --git a/demo/src/js/lib/tab-focus.js b/demo/src/js/lib/tab-focus.js deleted file mode 100644 index 06e51203..00000000 --- a/demo/src/js/lib/tab-focus.js +++ /dev/null @@ -1,26 +0,0 @@ -// ========================================================================== -// tab-focus.js -// Detect keyboard tabbing -// ========================================================================== - -(function() { - var className = 'tab-focus'; - - // Remove class on blur - document.addEventListener('focusout', function(event) { - event.target.classList.remove(className); - }); - - // Add classname to tabbed elements - document.addEventListener('keydown', function(event) { - if (event.keyCode !== 9) { - return; - } - - // Delay the adding of classname until the focus has changed - // This event fires before the focusin event - window.setTimeout(function() { - document.activeElement.classList.add(className); - }, 0); - }); -})(); diff --git a/demo/src/less/components/icons.less b/demo/src/less/components/icons.less index 29f185bd..9180e4b3 100644 --- a/demo/src/less/components/icons.less +++ b/demo/src/less/components/icons.less @@ -7,6 +7,7 @@ fill: currentColor; width: @icon-size; height: @icon-size; + vertical-align: -0.15em; } // Within elements @@ -18,5 +19,5 @@ label svg { a .icon, .btn .icon { - margin-right: (@spacing-base / 2); + margin-right: (@spacing-base / 4); } diff --git a/demo/src/less/layout/core.less b/demo/src/less/layout/core.less index dc177088..7f1a93e4 100644 --- a/demo/src/less/layout/core.less +++ b/demo/src/less/layout/core.less @@ -2,12 +2,21 @@ // Core // ========================================================================== -html { - background: @page-background; - background-attachment: fixed; +*, +*::after, +*::before { + box-sizing: border-box; +} + +html, +body { + display: flex; + width: 100%; } html { + background: @page-background; + background-attachment: fixed; height: 100%; } diff --git a/dist/plyr.css b/dist/plyr.css index 552c4b7a..07dac357 100644 --- a/dist/plyr.css +++ b/dist/plyr.css @@ -1 +1 @@ -@-webkit-keyframes plyr-progress{to{background-position:25px 0}}@keyframes plyr-progress{to{background-position:25px 0}}@-webkit-keyframes plyr-popup{from{-webkit-transform:translateY(10px);transform:translateY(10px);opacity:.5}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes plyr-popup{from{-webkit-transform:translateY(10px);transform:translateY(10px);opacity:.5}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}.plyr{position:relative;max-width:100%;min-width:200px;overflow:hidden;font-family:inherit;font-weight:500;direction:ltr;text-shadow:none}.plyr audio,.plyr video{width:100%;height:auto;vertical-align:middle;border-radius:inherit}.plyr--full-ui,.plyr--full-ui *,.plyr--full-ui ::after,.plyr--full-ui ::before{-webkit-box-sizing:border-box;box-sizing:border-box}.plyr--full-ui a,.plyr--full-ui button,.plyr--full-ui input,.plyr--full-ui label{-ms-touch-action:manipulation;touch-action:manipulation}.plyr__badge{padding:1px 4px;border-radius:2px;background:#565d64;color:rgba(255,255,255,.9);font-size:10px}.plyr__control{position:relative;display:inline-block;-ms-flex-negative:0;flex-shrink:0;overflow:visible;vertical-align:middle;padding:7px;border:0;background:0 0;border-radius:3px;cursor:pointer;-webkit-transition:background .3s ease,color .3s ease,opacity .3s ease;transition:background .3s ease,color .3s ease,opacity .3s ease;color:inherit}.plyr__control svg{width:18px;height:18px;display:block;fill:currentColor;pointer-events:none}.plyr__control .icon--captions-on,.plyr__control .icon--exit-fullscreen,.plyr__control .icon--muted{display:none}.plyr__control:focus{outline:0}.plyr--audio .plyr__control.tab-focus,.plyr--audio .plyr__control:hover,.plyr--audio .plyr__control[aria-expanded=true]{background:#1aafff;color:#fff}.plyr__play-large{display:none;position:absolute;z-index:1;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);padding:13px;background:rgba(26,175,255,.8);border:3px solid currentColor;border-radius:100%;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15);box-shadow:0 1px 1px rgba(0,0,0,.15);color:#fff;-webkit-transition:all .3s ease;transition:all .3s ease}.plyr__play-large svg{position:relative;left:2px;width:20px;height:20px;display:block;fill:currentColor;pointer-events:none}.plyr__play-large:focus,.plyr__play-large:hover{background:#1aafff}.plyr__play-large:focus{outline:1px dotted rgba(255,255,255,.5)}.plyr--full-ui.plyr--video .plyr__play-large{display:inline-block}.plyr--playing .plyr__play-large{opacity:0;visibility:hidden}.plyr--full-ui video::-webkit-media-text-track-container{display:none}.plyr__captions{display:none;position:absolute;bottom:0;left:0;width:100%;padding:10px;-webkit-transform:translateY(-40px);transform:translateY(-40px);-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease;color:#fff;font-size:14px;text-align:center}.plyr__captions span{border-radius:2px;padding:.2em .5em;background:rgba(0,0,0,.8);-webkit-box-decoration-break:clone;box-decoration-break:clone;line-height:170%;white-space:pre-wrap}.plyr__captions span div{display:inline}.plyr__captions span:empty{display:none}@media (min-width:480px){.plyr__captions{padding:20px;font-size:16px}}@media (min-width:768px){.plyr__captions{font-size:20px}}.plyr--captions-active .plyr__captions{display:block}.plyr--hide-controls .plyr__captions{-webkit-transform:translateY(-15px);transform:translateY(-15px)}.plyr ::-webkit-media-controls{display:none}.plyr__controls{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;text-align:center}.plyr__controls .plyr__menu,.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>.plyr__control{margin-left:5px}.plyr__controls .plyr__menu:first-child,.plyr__controls .plyr__menu:first-child+[data-plyr=pause],.plyr__controls .plyr__progress:first-child,.plyr__controls .plyr__progress:first-child+[data-plyr=pause],.plyr__controls .plyr__time:first-child,.plyr__controls .plyr__time:first-child+[data-plyr=pause],.plyr__controls>.plyr__control:first-child,.plyr__controls>.plyr__control:first-child+[data-plyr=pause]{margin-left:0}.plyr__controls .plyr__volume{margin-left:5px}@media (min-width:480px){.plyr__controls .plyr__menu,.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>.plyr__control{margin-left:10px}.plyr__controls .plyr__menu+.plyr__control,.plyr__controls>.plyr__control+.plyr__control,.plyr__controls>.plyr__control+.plyr__menu{margin-left:5px}}.plyr--video .plyr__controls{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:35px 12px 10px;background:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.7)));background:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.7));border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;color:#fff;-webkit-transition:all .4s ease-in-out;transition:all .4s ease-in-out}.plyr--video .plyr__controls .plyr__control svg{-webkit-filter:drop-shadow(0 1px 1px rgba(0, 0, 0, .15));filter:drop-shadow(0 1px 1px rgba(0, 0, 0, .15))}.plyr--video .plyr__controls .plyr__control.tab-focus,.plyr--video .plyr__controls .plyr__control:hover,.plyr--video .plyr__controls .plyr__control[aria-expanded=true]{background:#1aafff;color:#fff}.plyr--video.plyr--hide-controls .plyr__controls{opacity:0;-webkit-transform:translateY(100%);transform:translateY(100%);pointer-events:none}.plyr--audio .plyr__controls{padding:10px;border-radius:inherit;background:#fff;border:1px solid #dbe3e8;color:#565d64}.plyr__controls [data-plyr=pause]{display:none}.plyr--playing .plyr__controls [data-plyr=play]{display:none}.plyr--playing .plyr__controls [data-plyr=pause]{display:inline-block}.plyr--captions-active .plyr__control .icon--captions-on,.plyr--muted .plyr__control .icon--muted{display:block}.plyr--captions-active .plyr__control .icon--captions-on+svg,.plyr--muted .plyr__control .icon--muted+svg{display:none}.plyr [data-plyr=airplay],.plyr [data-plyr=captions],.plyr [data-plyr=fullscreen],.plyr [data-plyr=pip]{display:none}.plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--fullscreen-enabled [data-plyr=fullscreen],.plyr--pip-supported [data-plyr=pip]{display:inline-block}.plyr__video-embed{padding-bottom:56.25%;height:0}.plyr__video-embed iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plyr--full-ui .plyr__video-embed iframe{pointer-events:none}.plyr__menu{position:relative}.plyr__menu .plyr__control svg{-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease}.plyr__menu .plyr__control[aria-expanded=true] svg{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.plyr__menu .plyr__control[aria-expanded=true] .plyr__tooltip{display:none}.plyr__menu__container{position:absolute;z-index:1;bottom:100%;right:-3px;margin-bottom:10px;-webkit-animation:plyr-popup .2s ease;animation:plyr-popup .2s ease;background:rgba(255,255,255,.9);border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.2);box-shadow:0 1px 2px rgba(0,0,0,.2);white-space:nowrap;text-align:left;color:#565d64;font-size:14px}.plyr__menu__container>div{overflow:hidden;-webkit-transition:height .35s cubic-bezier(.4,0,.2,1),width .35s cubic-bezier(.4,0,.2,1);transition:height .35s cubic-bezier(.4,0,.2,1),width .35s cubic-bezier(.4,0,.2,1)}.plyr__menu__container::after{content:'';position:absolute;top:100%;right:15px;height:0;width:0;border:4px solid transparent;border-top-color:rgba(255,255,255,.9)}.plyr__menu__container ul{margin:0;padding:7px;list-style:none;overflow:hidden}.plyr__menu__container .plyr__control{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;padding:4px 14px;color:#565d64;font-weight:600;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plyr__menu__container .plyr__control::after{content:'';position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:4px solid transparent;-webkit-transition:border-color .2s ease;transition:border-color .2s ease}.plyr__menu__container .plyr__control--forward{padding-right:28px}.plyr__menu__container .plyr__control--forward::after{right:5px;border-left-color:rgba(86,93,100,.8)}.plyr__menu__container .plyr__control--forward.tab-focus::after,.plyr__menu__container .plyr__control--forward:hover::after{border-left-color:currentColor}.plyr__menu__container .plyr__control--back{position:relative;width:calc(100% - 14px);margin:7px;margin-bottom:3px;padding-left:28px;font-weight:500}.plyr__menu__container .plyr__control--back::after{left:7px;border-right-color:rgba(86,93,100,.8)}.plyr__menu__container .plyr__control--back::before{content:'';position:absolute;top:100%;left:0;right:0;height:1px;overflow:hidden;margin-top:4px;background:rgba(0,0,0,.15);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.1);box-shadow:0 1px 0 rgba(255,255,255,.1)}.plyr__menu__container .plyr__control--back.tab-focus::after,.plyr__menu__container .plyr__control--back:hover::after{border-right-color:currentColor}.plyr__menu__container label.plyr__control{padding-left:18px}.plyr__menu__container label.plyr__control input[type=radio]{position:relative;left:-7px}.plyr__menu__container .plyr__menu__value{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-left:auto;padding-left:25px;pointer-events:none;overflow:hidden;font-weight:500}.plyr__menu__container .plyr__menu__value .plyr__badge{font-weight:600}.plyr__progress{position:relative;display:none;-webkit-box-flex:1;-ms-flex:1;flex:1}.plyr__progress input[type=range]{position:relative;z-index:2}.plyr__progress .plyr__tooltip{left:0}.plyr .plyr__progress{display:inline-block}.plyr__progress--buffer{position:absolute;left:0;top:50%;width:100%;height:8px;margin:-4px 0 0;padding:0;background:0 0;border:none;border-radius:100px;-webkit-appearance:none}.plyr__progress--buffer::-webkit-progress-bar{background:0 0}.plyr__progress--buffer::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-ms-fill{border-radius:100px}.plyr__progress--buffer::-webkit-progress-value{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr__progress--buffer::-moz-progress-bar{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr__progress--buffer::-ms-fill{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr--video .plyr__progress--buffer{-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15);box-shadow:0 1px 1px rgba(0,0,0,.15);color:rgba(255,255,255,.25)}.plyr--audio .plyr__progress--buffer{color:rgba(198,214,219,.66)}.plyr--loading .plyr__progress--buffer{-webkit-animation:plyr-progress 1s linear infinite;animation:plyr-progress 1s linear infinite;background-size:25px 25px;background-repeat:repeat-x;background-image:linear-gradient(-45deg,rgba(52,63,74,.2) 25%,transparent 25%,transparent 50%,rgba(52,63,74,.2) 50%,rgba(52,63,74,.2) 75%,transparent 75%,transparent);color:transparent}.plyr--video.plyr--loading .plyr__progress--buffer{background-color:rgba(255,255,255,.25)}.plyr--audio.plyr--loading .plyr__progress--buffer{background-color:rgba(198,214,219,.66)}.plyr--full-ui input[type=range]{display:block;height:20px;width:100%;margin:0;padding:0;cursor:pointer;border:none;background:0 0;color:#1aafff;-webkit-appearance:none}.plyr--full-ui input[type=range]::-webkit-slider-runnable-track{height:8px;background:0 0;border:0;border-radius:4px;-webkit-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;margin-top:-4px;position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(52,63,74,.2);box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(52,63,74,.2);-webkit-box-sizing:border-box;box-sizing:border-box}.plyr--full-ui input[type=range]::-moz-range-track{height:8px;background:0 0;border:0;border-radius:4px;-moz-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-moz-range-thumb{position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(52,63,74,.2);box-sizing:border-box}.plyr--full-ui input[type=range]::-moz-range-progress{height:8px;background:currentColor;border-radius:4px}.plyr--full-ui input[type=range]::-ms-track{height:8px;background:0 0;border:0;color:transparent}.plyr--full-ui input[type=range]::-ms-fill-upper{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-lower{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none;background:currentColor}.plyr--full-ui input[type=range]::-ms-thumb{position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(52,63,74,.2);box-sizing:border-box;margin-top:0}.plyr--full-ui input[type=range]::-ms-tooltip{display:none}.plyr--full-ui input[type=range]:focus{outline:0}.plyr--full-ui input[type=range]::-moz-focus-outer{border:0}.plyr--full-ui input[type=range].tab-focus{outline-offset:3px}.plyr--full-ui input[type=range]:active::-webkit-slider-thumb{background:#1aafff;border-color:#fff;-webkit-transform:scale(1.25);transform:scale(1.25)}.plyr--full-ui input[type=range]:active::-moz-range-thumb{background:#1aafff;border-color:#fff;transform:scale(1.25)}.plyr--full-ui input[type=range]:active::-ms-thumb{background:#1aafff;border-color:#fff;transform:scale(1.25)}.plyr--full-ui.plyr--video input[type=range]::-webkit-slider-runnable-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range]::-moz-range-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range]::-ms-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range].tab-focus{outline:1px dotted rgba(255,255,255,.5)}.plyr--full-ui.plyr--audio input[type=range]::-webkit-slider-runnable-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range]::-moz-range-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range]::-ms-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range].tab-focus{outline:1px dotted rgba(86,93,100,.5)}.plyr__time{display:inline-block;vertical-align:middle;font-size:14px}.plyr__time+.plyr__time{display:none}@media (min-width:768px){.plyr__time+.plyr__time{display:inline-block}}.plyr__time+.plyr__time::before{content:'\2044';margin-right:10px}.plyr--video .plyr__time{text-shadow:0 1px 1px rgba(0,0,0,.15)}.plyr__tooltip{position:absolute;z-index:2;bottom:100%;margin-bottom:10px;padding:5px 7.5px;pointer-events:none;opacity:0;background:rgba(255,255,255,.9);border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.1);box-shadow:0 1px 2px rgba(0,0,0,.1);color:#565d64;font-size:14px;font-weight:500;line-height:1.3;-webkit-transform:translate(-50%,10px) scale(.8);transform:translate(-50%,10px) scale(.8);-webkit-transform-origin:50% 100%;transform-origin:50% 100%;-webkit-transition:opacity .2s .1s ease,-webkit-transform .2s .1s ease;transition:opacity .2s .1s ease,-webkit-transform .2s .1s ease;transition:transform .2s .1s ease,opacity .2s .1s ease;transition:transform .2s .1s ease,opacity .2s .1s ease,-webkit-transform .2s .1s ease}.plyr__tooltip::before{content:'';position:absolute;width:0;height:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);bottom:-4px;border-right:4px solid transparent;border-top:4px solid rgba(255,255,255,.9);border-left:4px solid transparent;z-index:2}.plyr .plyr__control.tab-focus .plyr__tooltip,.plyr .plyr__control:hover .plyr__tooltip,.plyr__tooltip--visible{opacity:1;-webkit-transform:translate(-50%,0) scale(1);transform:translate(-50%,0) scale(1)}.plyr .plyr__control:hover .plyr__tooltip{z-index:3}.plyr__controls>.plyr__control:first-child .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip{left:0;-webkit-transform:translate(0,10px) scale(.8);transform:translate(0,10px) scale(.8);-webkit-transform-origin:0 100%;transform-origin:0 100%}.plyr__controls>.plyr__control:first-child .plyr__tooltip::before,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip::before{left:16px}.plyr__controls>.plyr__control:last-child .plyr__tooltip{right:0;-webkit-transform:translate(0,10px) scale(.8);transform:translate(0,10px) scale(.8);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.plyr__controls>.plyr__control:last-child .plyr__tooltip::before{left:auto;right:16px;-webkit-transform:translateX(50%);transform:translateX(50%)}.plyr__controls>.plyr__control:first-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control.tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control:hover .plyr__tooltip,.plyr__controls>.plyr__control:first-child.tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child:hover .plyr__tooltip,.plyr__controls>.plyr__control:last-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:last-child.tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:last-child:hover .plyr__tooltip{-webkit-transform:translate(0,0) scale(1);transform:translate(0,0) scale(1)}.plyr__video-wrapper{position:relative;background:#000;border-radius:inherit;z-index:0;overflow:hidden}.plyr__volume{-webkit-box-flex:1;-ms-flex:1;flex:1;position:relative}.plyr__volume input[type=range]{position:relative;z-index:2}@media (min-width:480px){.plyr__volume{display:block;max-width:60px}}@media (min-width:768px){.plyr__volume{max-width:100px}}.plyr--is-ios .plyr__volume,.plyr--is-ios [data-plyr=mute]{display:none!important}.plyr:-webkit-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-moz-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-ms-fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-webkit-full-screen video{height:100%}.plyr:-moz-full-screen video{height:100%}.plyr:-ms-fullscreen video{height:100%}.plyr:fullscreen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:-webkit-full-screen .plyr__video-embed{overflow:visible}.plyr:-moz-full-screen .plyr__video-embed{overflow:visible}.plyr:-ms-fullscreen .plyr__video-embed{overflow:visible}.plyr:fullscreen .plyr__video-embed{overflow:visible}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:24px}.plyr:-moz-full-screen .plyr__captions{font-size:24px}.plyr:-ms-fullscreen .plyr__captions{font-size:24px}.plyr:fullscreen .plyr__captions{font-size:24px}}.plyr:-webkit-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-webkit-full-screen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-webkit-full-screen .plyr__video-embed{overflow:visible}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:24px}}.plyr:-moz-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-moz-full-screen video{height:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-moz-full-screen .plyr__video-embed{overflow:visible}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-moz-full-screen .plyr__captions{font-size:24px}}.plyr:-ms-fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-ms-fullscreen video{height:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:-ms-fullscreen .plyr__video-embed{overflow:visible}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-ms-fullscreen .plyr__captions{font-size:24px}}.plyr--fullscreen-fallback{height:100%;width:100%;background:#000;border-radius:0!important;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000000}.plyr--fullscreen-fallback video{height:100%}.plyr--fullscreen-fallback .plyr__video-wrapper{height:100%;width:100%}.plyr--fullscreen-fallback .plyr__video-embed{overflow:visible}.plyr--fullscreen-fallback.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen{display:block}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr--fullscreen-fallback .plyr__captions{font-size:24px}}.plyr--full-ui [hidden]{display:none}.plyr--full-ui [aria-hidden=true]{display:none}.plyr__sr-only{clip:rect(1px,1px,1px,1px);overflow:hidden;position:absolute!important;padding:0!important;border:0!important;height:1px!important;width:1px!important}
\ No newline at end of file +@-webkit-keyframes plyr-progress{to{background-position:25px 0}}@keyframes plyr-progress{to{background-position:25px 0}}@-webkit-keyframes plyr-popup{from{-webkit-transform:translateY(10px);transform:translateY(10px);opacity:.5}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes plyr-popup{from{-webkit-transform:translateY(10px);transform:translateY(10px);opacity:.5}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}.plyr{position:relative;max-width:100%;min-width:200px;font-family:inherit;font-weight:500;direction:ltr;text-shadow:none}.plyr audio,.plyr video{width:100%;height:auto;vertical-align:middle;border-radius:inherit}.plyr--full-ui,.plyr--full-ui *,.plyr--full-ui ::after,.plyr--full-ui ::before{-webkit-box-sizing:border-box;box-sizing:border-box}.plyr--full-ui a,.plyr--full-ui button,.plyr--full-ui input,.plyr--full-ui label{-ms-touch-action:manipulation;touch-action:manipulation}.plyr__badge{padding:1px 4px;border-radius:2px;background:#565d64;color:rgba(255,255,255,.9);font-size:10px}.plyr__control{position:relative;display:inline-block;-ms-flex-negative:0;flex-shrink:0;overflow:visible;vertical-align:middle;padding:7px;border:0;background:0 0;border-radius:3px;cursor:pointer;-webkit-transition:background .3s ease,color .3s ease,opacity .3s ease;transition:background .3s ease,color .3s ease,opacity .3s ease;color:inherit}.plyr__control svg{width:18px;height:18px;display:block;fill:currentColor;pointer-events:none}.plyr__control .icon--captions-on,.plyr__control .icon--exit-fullscreen,.plyr__control .icon--muted{display:none}.plyr__control:focus{outline:0}.plyr--audio .plyr__control.tab-focus,.plyr--audio .plyr__control:hover,.plyr--audio .plyr__control[aria-expanded=true]{background:#1aafff;color:#fff}.plyr__play-large{display:none;position:absolute;z-index:1;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);padding:13px;background:rgba(26,175,255,.8);border:3px solid currentColor;border-radius:100%;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15);box-shadow:0 1px 1px rgba(0,0,0,.15);color:#fff;-webkit-transition:all .3s ease;transition:all .3s ease}.plyr__play-large svg{position:relative;left:2px;width:20px;height:20px;display:block;fill:currentColor;pointer-events:none}.plyr__play-large:focus,.plyr__play-large:hover{background:#1aafff}.plyr__play-large:focus{outline:1px dotted rgba(255,255,255,.5)}.plyr--full-ui.plyr--video .plyr__play-large{display:inline-block}.plyr--playing .plyr__play-large{opacity:0;visibility:hidden}.plyr--full-ui video::-webkit-media-text-track-container{display:none}.plyr__captions{display:none;position:absolute;bottom:0;left:0;width:100%;padding:10px;-webkit-transform:translateY(-40px);transform:translateY(-40px);-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease;color:#fff;font-size:14px;text-align:center}.plyr__captions span{border-radius:2px;padding:.2em .5em;background:rgba(0,0,0,.8);-webkit-box-decoration-break:clone;box-decoration-break:clone;line-height:170%;white-space:pre-wrap}.plyr__captions span div{display:inline}.plyr__captions span:empty{display:none}@media (min-width:480px){.plyr__captions{padding:20px;font-size:16px}}@media (min-width:768px){.plyr__captions{font-size:20px}}.plyr--captions-active .plyr__captions{display:block}.plyr--hide-controls .plyr__captions{-webkit-transform:translateY(-15px);transform:translateY(-15px)}.plyr ::-webkit-media-controls{display:none}.plyr__controls{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;text-align:center}.plyr__controls .plyr__menu,.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>.plyr__control{margin-left:5px}.plyr__controls .plyr__menu:first-child,.plyr__controls .plyr__menu:first-child+[data-plyr=pause],.plyr__controls .plyr__progress:first-child,.plyr__controls .plyr__progress:first-child+[data-plyr=pause],.plyr__controls .plyr__time:first-child,.plyr__controls .plyr__time:first-child+[data-plyr=pause],.plyr__controls>.plyr__control:first-child,.plyr__controls>.plyr__control:first-child+[data-plyr=pause]{margin-left:0}.plyr__controls .plyr__volume{margin-left:5px}@media (min-width:480px){.plyr__controls .plyr__menu,.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>.plyr__control{margin-left:10px}.plyr__controls .plyr__menu+.plyr__control,.plyr__controls>.plyr__control+.plyr__control,.plyr__controls>.plyr__control+.plyr__menu{margin-left:5px}}.plyr--video .plyr__controls{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:35px 12px 10px;background:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.7)));background:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.7));border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;color:#fff;-webkit-transition:opacity .4s ease-in-out,-webkit-transform .4s ease-in-out;transition:opacity .4s ease-in-out,-webkit-transform .4s ease-in-out;transition:opacity .4s ease-in-out,transform .4s ease-in-out;transition:opacity .4s ease-in-out,transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.plyr--video .plyr__controls .plyr__control svg{-webkit-filter:drop-shadow(0 1px 1px rgba(0, 0, 0, .15));filter:drop-shadow(0 1px 1px rgba(0, 0, 0, .15))}.plyr--video .plyr__controls .plyr__control.tab-focus,.plyr--video .plyr__controls .plyr__control:hover,.plyr--video .plyr__controls .plyr__control[aria-expanded=true]{background:#1aafff;color:#fff}.plyr--video.plyr--hide-controls .plyr__controls{opacity:0;-webkit-transform:translateY(100%);transform:translateY(100%);pointer-events:none}.plyr--audio .plyr__controls{padding:10px;border-radius:inherit;background:#fff;border:1px solid #dbe3e8;color:#565d64}.plyr__controls [data-plyr=pause]{display:none}.plyr--playing .plyr__controls [data-plyr=play]{display:none}.plyr--playing .plyr__controls [data-plyr=pause]{display:inline-block}.plyr--captions-active .plyr__control .icon--captions-on,.plyr--muted .plyr__control .icon--muted{display:block}.plyr--captions-active .plyr__control .icon--captions-on+svg,.plyr--muted .plyr__control .icon--muted+svg{display:none}.plyr [data-plyr=airplay],.plyr [data-plyr=captions],.plyr [data-plyr=fullscreen],.plyr [data-plyr=pip]{display:none}.plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--fullscreen-enabled [data-plyr=fullscreen],.plyr--pip-supported [data-plyr=pip]{display:inline-block}.plyr__video-embed{padding-bottom:56.25%;height:0}.plyr__video-embed iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plyr__video-embed>div{position:relative;padding-bottom:200%;-webkit-transform:translateY(-35.95%);transform:translateY(-35.95%)}.plyr--full-ui .plyr__video-embed iframe{pointer-events:none}.plyr__menu{position:relative}.plyr__menu .plyr__control svg{-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease}.plyr__menu .plyr__control[aria-expanded=true] svg{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.plyr__menu .plyr__control[aria-expanded=true] .plyr__tooltip{display:none}.plyr__menu__container{position:absolute;z-index:1;bottom:100%;right:-3px;margin-bottom:10px;-webkit-animation:plyr-popup .2s ease;animation:plyr-popup .2s ease;background:rgba(255,255,255,.9);border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.2);box-shadow:0 1px 2px rgba(0,0,0,.2);white-space:nowrap;text-align:left;color:#565d64;font-size:14px}.plyr__menu__container>div{overflow:hidden;-webkit-transition:height .35s cubic-bezier(.4,0,.2,1),width .35s cubic-bezier(.4,0,.2,1);transition:height .35s cubic-bezier(.4,0,.2,1),width .35s cubic-bezier(.4,0,.2,1)}.plyr__menu__container::after{content:'';position:absolute;top:100%;right:15px;height:0;width:0;border:4px solid transparent;border-top-color:rgba(255,255,255,.9)}.plyr__menu__container ul{margin:0;padding:7px;list-style:none;overflow:hidden}.plyr__menu__container .plyr__control{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;padding:4px 14px;color:#565d64;font-weight:600;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plyr__menu__container .plyr__control::after{content:'';position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:4px solid transparent;-webkit-transition:border-color .2s ease;transition:border-color .2s ease}.plyr__menu__container .plyr__control--forward{padding-right:28px}.plyr__menu__container .plyr__control--forward::after{right:5px;border-left-color:rgba(86,93,100,.8)}.plyr__menu__container .plyr__control--forward.tab-focus::after,.plyr__menu__container .plyr__control--forward:hover::after{border-left-color:currentColor}.plyr__menu__container .plyr__control--back{position:relative;width:calc(100% - 14px);margin:7px;margin-bottom:3px;padding-left:28px;font-weight:500}.plyr__menu__container .plyr__control--back::after{left:7px;border-right-color:rgba(86,93,100,.8)}.plyr__menu__container .plyr__control--back::before{content:'';position:absolute;top:100%;left:0;right:0;height:1px;overflow:hidden;margin-top:4px;background:rgba(0,0,0,.15);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.1);box-shadow:0 1px 0 rgba(255,255,255,.1)}.plyr__menu__container .plyr__control--back.tab-focus::after,.plyr__menu__container .plyr__control--back:hover::after{border-right-color:currentColor}.plyr__menu__container label.plyr__control{padding-left:18px}.plyr__menu__container label.plyr__control input[type=radio]{position:relative;left:-7px}.plyr__menu__container .plyr__menu__value{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-left:auto;padding-left:25px;pointer-events:none;overflow:hidden;font-weight:500}.plyr__menu__container .plyr__menu__value .plyr__badge{font-weight:600}.plyr__progress{position:relative;display:none;-webkit-box-flex:1;-ms-flex:1;flex:1}.plyr__progress input[type=range]{position:relative;z-index:2}.plyr__progress .plyr__tooltip{left:0}.plyr .plyr__progress{display:inline-block}.plyr__progress--buffer{position:absolute;left:0;top:50%;width:100%;height:8px;margin:-4px 0 0;padding:0;background:0 0;border:none;border-radius:100px;-webkit-appearance:none}.plyr__progress--buffer::-webkit-progress-bar{background:0 0}.plyr__progress--buffer::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-ms-fill{border-radius:100px}.plyr__progress--buffer::-webkit-progress-value{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr__progress--buffer::-moz-progress-bar{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr__progress--buffer::-ms-fill{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr--video .plyr__progress--buffer{-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15);box-shadow:0 1px 1px rgba(0,0,0,.15);color:rgba(255,255,255,.25)}.plyr--audio .plyr__progress--buffer{color:rgba(198,214,219,.66)}.plyr--loading .plyr__progress--buffer{-webkit-animation:plyr-progress 1s linear infinite;animation:plyr-progress 1s linear infinite;background-size:25px 25px;background-repeat:repeat-x;background-image:linear-gradient(-45deg,rgba(52,63,74,.2) 25%,transparent 25%,transparent 50%,rgba(52,63,74,.2) 50%,rgba(52,63,74,.2) 75%,transparent 75%,transparent);color:transparent}.plyr--video.plyr--loading .plyr__progress--buffer{background-color:rgba(255,255,255,.25)}.plyr--audio.plyr--loading .plyr__progress--buffer{background-color:rgba(198,214,219,.66)}.plyr--full-ui input[type=range]{display:block;height:20px;width:100%;margin:0;padding:0;cursor:pointer;border:none;background:0 0;color:#1aafff;-webkit-appearance:none}.plyr--full-ui input[type=range]::-webkit-slider-runnable-track{height:8px;background:0 0;border:0;border-radius:4px;-webkit-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;margin-top:-4px;position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(52,63,74,.2);box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(52,63,74,.2);-webkit-box-sizing:border-box;box-sizing:border-box}.plyr--full-ui input[type=range]::-moz-range-track{height:8px;background:0 0;border:0;border-radius:4px;-moz-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-moz-range-thumb{position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(52,63,74,.2);box-sizing:border-box}.plyr--full-ui input[type=range]::-moz-range-progress{height:8px;background:currentColor;border-radius:4px}.plyr--full-ui input[type=range]::-ms-track{color:transparent;height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-upper{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-lower{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none;background:currentColor}.plyr--full-ui input[type=range]::-ms-thumb{position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(52,63,74,.2);box-sizing:border-box;margin-top:0}.plyr--full-ui input[type=range]::-ms-tooltip{display:none}.plyr--full-ui input[type=range]:focus{outline:0}.plyr--full-ui input[type=range]::-moz-focus-outer{border:0}.plyr--full-ui input[type=range].tab-focus{outline-offset:3px}.plyr--full-ui input[type=range]:active::-webkit-slider-thumb{background:#1aafff;border-color:#fff;-webkit-transform:scale(1.25);transform:scale(1.25)}.plyr--full-ui input[type=range]:active::-moz-range-thumb{background:#1aafff;border-color:#fff;transform:scale(1.25)}.plyr--full-ui input[type=range]:active::-ms-thumb{background:#1aafff;border-color:#fff;transform:scale(1.25)}.plyr--full-ui.plyr--video input[type=range]::-webkit-slider-runnable-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range]::-moz-range-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range]::-ms-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range].tab-focus{outline:1px dotted rgba(255,255,255,.5)}.plyr--full-ui.plyr--audio input[type=range]::-webkit-slider-runnable-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range]::-moz-range-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range]::-ms-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range].tab-focus{outline:1px dotted rgba(86,93,100,.5)}.plyr__time{display:inline-block;vertical-align:middle;font-size:14px}.plyr__time+.plyr__time{display:none}@media (min-width:768px){.plyr__time+.plyr__time{display:inline-block}}.plyr__time+.plyr__time::before{content:'\2044';margin-right:10px}.plyr--video .plyr__time{text-shadow:0 1px 1px rgba(0,0,0,.15)}.plyr__tooltip{position:absolute;z-index:2;bottom:100%;margin-bottom:10px;padding:5px 7.5px;pointer-events:none;opacity:0;background:rgba(255,255,255,.9);border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.1);box-shadow:0 1px 2px rgba(0,0,0,.1);color:#565d64;font-size:14px;font-weight:500;line-height:1.3;-webkit-transform:translate(-50%,10px) scale(.8);transform:translate(-50%,10px) scale(.8);-webkit-transform-origin:50% 100%;transform-origin:50% 100%;-webkit-transition:opacity .2s .1s ease,-webkit-transform .2s .1s ease;transition:opacity .2s .1s ease,-webkit-transform .2s .1s ease;transition:transform .2s .1s ease,opacity .2s .1s ease;transition:transform .2s .1s ease,opacity .2s .1s ease,-webkit-transform .2s .1s ease}.plyr__tooltip::before{content:'';position:absolute;width:0;height:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);bottom:-4px;border-right:4px solid transparent;border-top:4px solid rgba(255,255,255,.9);border-left:4px solid transparent;z-index:2}.plyr .plyr__control.tab-focus .plyr__tooltip,.plyr .plyr__control:hover .plyr__tooltip,.plyr__tooltip--visible{opacity:1;-webkit-transform:translate(-50%,0) scale(1);transform:translate(-50%,0) scale(1)}.plyr .plyr__control:hover .plyr__tooltip{z-index:3}.plyr__controls>.plyr__control:first-child .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip{left:0;-webkit-transform:translate(0,10px) scale(.8);transform:translate(0,10px) scale(.8);-webkit-transform-origin:0 100%;transform-origin:0 100%}.plyr__controls>.plyr__control:first-child .plyr__tooltip::before,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip::before{left:16px}.plyr__controls>.plyr__control:last-child .plyr__tooltip{right:0;-webkit-transform:translate(0,10px) scale(.8);transform:translate(0,10px) scale(.8);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.plyr__controls>.plyr__control:last-child .plyr__tooltip::before{left:auto;right:16px;-webkit-transform:translateX(50%);transform:translateX(50%)}.plyr__controls>.plyr__control:first-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control.tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control:hover .plyr__tooltip,.plyr__controls>.plyr__control:first-child.tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child:hover .plyr__tooltip,.plyr__controls>.plyr__control:last-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:last-child.tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:last-child:hover .plyr__tooltip{-webkit-transform:translate(0,0) scale(1);transform:translate(0,0) scale(1)}.plyr--video{overflow:hidden}.plyr__video-wrapper{position:relative;background:#000;border-radius:inherit;z-index:0;overflow:hidden}.plyr__volume{-webkit-box-flex:1;-ms-flex:1;flex:1;position:relative}.plyr__volume input[type=range]{position:relative;z-index:2}@media (min-width:480px){.plyr__volume{display:block;max-width:60px}}@media (min-width:768px){.plyr__volume{max-width:100px}}.plyr--is-ios .plyr__volume,.plyr--is-ios [data-plyr=mute]{display:none!important}.plyr:-webkit-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-moz-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-ms-fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-webkit-full-screen video{height:100%}.plyr:-moz-full-screen video{height:100%}.plyr:-ms-fullscreen video{height:100%}.plyr:fullscreen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:-webkit-full-screen .plyr__video-embed{overflow:visible}.plyr:-moz-full-screen .plyr__video-embed{overflow:visible}.plyr:-ms-fullscreen .plyr__video-embed{overflow:visible}.plyr:fullscreen .plyr__video-embed{overflow:visible}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:24px}.plyr:-moz-full-screen .plyr__captions{font-size:24px}.plyr:-ms-fullscreen .plyr__captions{font-size:24px}.plyr:fullscreen .plyr__captions{font-size:24px}}.plyr:-webkit-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-webkit-full-screen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-webkit-full-screen .plyr__video-embed{overflow:visible}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:24px}}.plyr:-moz-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-moz-full-screen video{height:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-moz-full-screen .plyr__video-embed{overflow:visible}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-moz-full-screen .plyr__captions{font-size:24px}}.plyr:-ms-fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-ms-fullscreen video{height:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:-ms-fullscreen .plyr__video-embed{overflow:visible}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-ms-fullscreen .plyr__captions{font-size:24px}}.plyr--fullscreen-fallback{height:100%;width:100%;background:#000;border-radius:0!important;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000000}.plyr--fullscreen-fallback video{height:100%}.plyr--fullscreen-fallback .plyr__video-wrapper{height:100%;width:100%}.plyr--fullscreen-fallback .plyr__video-embed{overflow:visible}.plyr--fullscreen-fallback.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen{display:block}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr--fullscreen-fallback .plyr__captions{font-size:24px}}.plyr--full-ui [hidden]{display:none}.plyr--full-ui [aria-hidden=true]{display:none}.plyr__sr-only{clip:rect(1px,1px,1px,1px);overflow:hidden;position:absolute!important;padding:0!important;border:0!important;height:1px!important;width:1px!important}
\ No newline at end of file diff --git a/dist/plyr.js b/dist/plyr.js index b9c9dee0..742142db 100644 --- a/dist/plyr.js +++ b/dist/plyr.js @@ -1 +1,3 @@ -(function(e,t,n){"use strict";"object"==typeof exports?module.exports=n(require):"function"==typeof define&&define.amd?define(n):t[e]=n()}).call(this,"Plyr",this,function(){"use strict";function e(e,t){function r(e,t,n,i){a.dispatchEvent(e,t,n,a.extend({},i,{plyr:pe}))}function l(){var e=c("input:not([disabled]), button:not([disabled])"),t=e[0],n=e[e.length-1];a.on(pe.elements.container,"keydown",function(e){9===e.which&&pe.fullscreen.active&&(e.target!==n||e.shiftKey?e.target===t&&e.shiftKey&&(e.preventDefault(),n.focus()):(e.preventDefault(),t.focus()))},!1)}function c(e){return pe.elements.container.querySelectorAll(e)}function u(e){return c(e)[0]}function d(e){a.is.string(e)?(a.removeElement(pe.elements[e]),pe.elements[e]=null):a.removeElement(e)}function p(e,t){a.is.string(t)?a.insertElement(e,pe.media,{src:t}):a.is.array(t)&&(fe(t),t.forEach(function(t){a.insertElement(e,pe.media,t)}))}function m(e){if(pe.browser.isWebkit&&(a.is.event(e)&&(e=e.target),a.is.htmlElement(e)&&"range"===e.getAttribute("type"))){a.is.htmlElement(pe.elements.styleSheet)||(pe.elements.styleSheet=a.createElement("style"),pe.elements.container.appendChild(pe.elements.styleSheet));var t=pe.elements.styleSheet.sheet,n=e.value/e.max*100,i="#"+e.id+"::-webkit-slider-runnable-track",o="{ background-image: linear-gradient(to right, currentColor "+n+"%, transparent "+n+"%) }",s=-1;[].some.call(t.rules,function(e,t){if(e.selectorText===i)return s=t,!0})[0],-1!==s&&t.deleteRule(s),t.insertRule([i,o].join(" "))}}function g(){return{url:pe.config.iconUrl,absolute:0===pe.config.iconUrl.indexOf("http")||pe.browser.isIE}}function f(e,t){var n=g(),i=(n.absolute?"":n.url)+"#"+pe.config.iconPrefix,o=document.createElementNS("http://www.w3.org/2000/svg","svg");a.setAttributes(o,a.extend(t,{role:"presentation"}));var s=document.createElementNS("http://www.w3.org/2000/svg","use");return s.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",i+"-"+e),o.appendChild(s),o}function y(e){var t=pe.config.i18n[e];switch(e){case"pip":t="PIP";break;case"airplay":t="AirPlay"}return a.createElement("span",{class:pe.config.classNames.hidden},t)}function b(e){var t=a.createElement("span",{class:pe.config.classNames.menu.value});return t.appendChild(a.createElement("span",{class:pe.config.classNames.menu.badge},e)),t}function v(e,t){var n,i,o,s=a.createElement("button");switch(a.is.object(t)||(t={}),"type"in t||(t.type="button"),"class"in t?-1===t.class.indexOf(pe.config.classNames.control)&&(t.class+=" "+pe.config.classNames.control):t.class=pe.config.classNames.control,e){case"mute":o="toggleMute",n="volume",i="muted";break;case"captions":o="toggleCaptions",n="captions-off",i="captions-on";break;case"fullscreen":o="toggleFullscreen",n="enter-fullscreen",i="exit-fullscreen";break;case"play-large":t.class="plyr__play-large",e="play",o="play",n="play";break;default:o=e,n=e}return a.extend(t,a.getAttributesFromSelector(pe.config.selectors.buttons[e],t)),a.is.string(i)&&s.appendChild(f(i,{class:"icon--"+i})),s.appendChild(f(n)),s.appendChild(y(o)),a.setAttributes(s,t),pe.elements.buttons[e]=s,s}function h(e,t){var n=a.createElement("label",{for:t.id,class:pe.config.classNames.hidden},pe.config.i18n[e]),i=a.createElement("input",a.extend(a.getAttributesFromSelector(pe.config.selectors.inputs[e]),{type:"range",min:0,max:100,step:.01,value:0,autocomplete:"off"},t));return pe.elements.inputs[e]=i,{label:n,input:i}}function w(e,t){var n=a.createElement("progress",a.extend(a.getAttributesFromSelector(pe.config.selectors.display[e]),{min:0,max:100,value:0},t));if("volume"!==e){n.appendChild(a.createElement("span",null,"0"));var i="";switch(e){case"played":i=pe.config.i18n.played;break;case"buffer":i=pe.config.i18n.buffered}n.textContent="% "+i.toLowerCase()}return pe.elements.display[e]=n,n}function k(e){var t=a.createElement("span",{class:"plyr__time"});return t.appendChild(a.createElement("span",{class:pe.config.classNames.hidden},pe.config.i18n[e])),t.appendChild(a.createElement("span",a.getAttributesFromSelector(pe.config.selectors.display[e]),"00:00")),pe.elements.display[e]=t,t}function C(e){if(!a.is.empty(pe.config.controls)){var t=a.createElement("div",a.getAttributesFromSelector(pe.config.selectors.controls.wrapper));if(a.inArray(pe.config.controls,"restart")&&t.appendChild(v("restart")),a.inArray(pe.config.controls,"rewind")&&t.appendChild(v("rewind")),a.inArray(pe.config.controls,"play")&&(t.appendChild(v("play")),t.appendChild(v("pause"))),a.inArray(pe.config.controls,"fast-forward")&&t.appendChild(v("fast-forward")),a.inArray(pe.config.controls,"progress")){var n=a.createElement("span",a.getAttributesFromSelector(pe.config.selectors.progress)),i=h("seek",{id:"plyr-seek-"+e.id});if(n.appendChild(i.label),n.appendChild(i.input),n.appendChild(w("buffer")),pe.config.tooltips.seek){var o=a.createElement("span",{role:"tooltip",class:pe.config.classNames.tooltip},"00:00");n.appendChild(o),pe.elements.display.seekTooltip=o}pe.elements.progress=n,t.appendChild(pe.elements.progress)}if(a.inArray(pe.config.controls,"current-time")&&t.appendChild(k("currentTime")),a.inArray(pe.config.controls,"duration")&&t.appendChild(k("duration")),a.inArray(pe.config.controls,"mute")&&t.appendChild(v("mute")),a.inArray(pe.config.controls,"volume")){var r=a.createElement("span",{class:"plyr__volume"}),l={max:1,step:.05,value:pe.config.volume},c=h("volume",a.extend(l,{id:"plyr-volume-"+e.id}));r.appendChild(c.label),r.appendChild(c.input),t.appendChild(r)}if(a.inArray(pe.config.controls,"captions")&&t.appendChild(v("captions")),a.inArray(pe.config.controls,"settings")&&!a.is.empty(pe.config.settings)){var u=a.createElement("div",{class:"plyr__menu"});u.appendChild(v("settings",{id:"plyr-settings-toggle-"+e.id,"aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id,"aria-expanded":!1}));var d=a.createElement("form",{class:"plyr__menu__container",id:"plyr-settings-"+e.id,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tablist",tabindex:-1}),p=a.createElement("div"),m=a.createElement("div",{id:"plyr-settings-"+e.id+"-home","aria-hidden":!1,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tabpanel"}),g=a.createElement("ul",{role:"tablist"});pe.config.settings.forEach(function(t){var n=a.createElement("li",{role:"tab",hidden:""}),i=a.createElement("button",a.extend(a.getAttributesFromSelector(pe.config.selectors.buttons.settings),{type:"button",class:pe.config.classNames.control+" "+pe.config.classNames.control+"--forward",id:"plyr-settings-"+e.id+"-"+t+"-tab","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-"+t,"aria-expanded":!1}),pe.config.i18n[t]),o=a.createElement("span",{class:pe.config.classNames.menu.value});o.innerHTML=e[t],i.appendChild(o),n.appendChild(i),g.appendChild(n),pe.elements.settings.tabs[t]=n}),m.appendChild(g),p.appendChild(m),pe.config.settings.forEach(function(t){var n=a.createElement("div",{id:"plyr-settings-"+e.id+"-"+t,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-"+e.id+"-"+t+"-tab",role:"tabpanel",tabindex:-1,hidden:""}),i=a.createElement("button",{type:"button",class:pe.config.classNames.control+" "+pe.config.classNames.control+"--back","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-home","aria-expanded":!1},pe.config.i18n[t]);n.appendChild(i);var o=a.createElement("ul");n.appendChild(o),p.appendChild(n),pe.elements.settings.panes[t]=n}),d.appendChild(p),u.appendChild(d),t.appendChild(u),pe.elements.settings.form=d,pe.elements.settings.menu=u}return a.inArray(pe.config.controls,"pip")&&s.pip&&t.appendChild(v("pip")),a.inArray(pe.config.controls,"airplay")&&s.airplay&&t.appendChild(v("airplay")),a.inArray(pe.config.controls,"fullscreen")&&t.appendChild(v("fullscreen")),a.inArray(pe.config.controls,"play-large")&&(pe.elements.buttons.playLarge=v("play-large"),pe.elements.container.appendChild(pe.elements.buttons.playLarge)),pe.elements.controls=t,a.inArray(pe.config.controls,"settings")&&a.inArray(pe.config.settings,"speed")&&N(),t}}function E(e,t){var n=pe.elements.settings.tabs[e],i=pe.elements.settings.panes[e];a.is.htmlElement(n)&&(t?n.removeAttribute("hidden"):n.setAttribute("hidden","")),a.is.htmlElement(i)&&(t?i.removeAttribute("hidden"):i.setAttribute("hidden",""))}function A(e,t){function n(e){var t="";switch(e){case"hd2160":t="4K";break;case"hd1440":t="WQHD";break;case"hd1080":case"hd720":t="HD"}return t.length?b(t):null}var i=pe.elements.settings.panes.quality.querySelector("ul");a.is.array(e)?pe.quality.options=e.filter(function(e){return a.inArray(pe.config.quality.options,e)}):pe.quality.options=pe.config.quality.options,a.is.string(t)&&a.inArray(pe.quality.options,t)&&(pe.quality.selected=t);var o=!a.is.empty(pe.quality.options)&&"youtube"===pe.type;E("quality",o),o&&(a.emptyElement(i),pe.quality.options.forEach(function(e){var t=a.createElement("li"),o=a.createElement("label",{class:pe.config.classNames.control}),s=a.createElement("input",a.extend(a.getAttributesFromSelector(pe.config.selectors.inputs.quality),{type:"radio",name:"plyr-quality",value:e}));o.appendChild(s),o.appendChild(document.createTextNode(S("quality",e)));var r=n(e);a.is.htmlElement(r)&&o.appendChild(r),t.appendChild(o),i.appendChild(t)}),T("quality",i))}function S(e,t){switch(e){case"speed":return 1===t?"Normal":t+"×";case"quality":switch(t){case"hd2160":return"2160P";case"hd1440":return"1440P";case"hd1080":return"1080P";case"hd720":return"720P";case"large":return"480P";case"medium":return"360P";case"small":return"240P";case"tiny":return"Tiny";case"default":return"Auto";default:return t}case"captions":return F()}}function T(e,t){var n=pe.elements.settings.panes[e],i=null;switch(e){case"captions":i=pe.captions.language,pe.captions.enabled||(i="");break;default:if(i=pe[e].selected,a.is.empty(i)&&(i=pe.config[e].default),!a.inArray(pe[e].options,i))return void fe("Unsupported option")}a.is.htmlElement(t)||(t=n&&n.querySelector("ul"));var o=t&&t.querySelector('input[value="'+i+'"]');a.is.htmlElement(o)&&(o.checked=!0,pe.elements.settings.tabs[e].querySelector("."+pe.config.classNames.menu.value).innerHTML=S(e,i))}function x(){var e=pe.elements.settings.panes.captions.querySelector("ul");if(E("captions",!a.is.empty(pe.captions.tracks)),a.emptyElement(e),!a.is.empty(pe.captions.tracks)){var t=[].map.call(pe.captions.tracks,function(e){return{language:e.language,badge:!0,label:a.is.empty(e.label)?e.language.toUpperCase():e.label}});t.unshift({language:"",label:pe.config.i18n.none}),t.forEach(function(t){var n=a.createElement("li"),i=a.createElement("label",{class:pe.config.classNames.control}),o=a.createElement("input",a.extend(a.getAttributesFromSelector(pe.config.selectors.inputs.language),{type:"radio",name:"plyr-language",value:t.language}));t.language.toLowerCase()===pe.captions.language.toLowerCase()&&(o.checked=!0),i.appendChild(o),i.appendChild(document.createTextNode(t.label||t.language)),t.badge&&i.appendChild(b(t.language.toUpperCase())),n.appendChild(i),e.appendChild(n)}),T("captions",e)}}function N(e,t){a.is.array(e)?pe.speed.options=e.filter(function(e){return a.inArray(pe.config.speed.options,e)}):pe.speed.options=pe.config.speed.options,a.is.number(t)&&a.inArray(pe.speed.options,t)&&(pe.speed.selected=t);var n=!a.is.empty(pe.speed.options);if(E("speed",n),n){var i=pe.elements.settings.panes.speed.querySelector("ul");pe.elements.settings.tabs.speed.removeAttribute("hidden"),pe.elements.settings.panes.speed.removeAttribute("hidden"),a.emptyElement(i),pe.speed.options.forEach(function(e){var t=a.createElement("li"),n=a.createElement("label",{class:pe.config.classNames.control}),o=a.createElement("input",a.extend(a.getAttributesFromSelector(pe.config.selectors.inputs.speed),{type:"radio",name:"plyr-speed",value:e}));n.appendChild(o),n.insertAdjacentHTML("beforeend",S("speed",e)),t.appendChild(n),i.appendChild(t)}),T("speed",i)}}function P(){if(pe.supported.ui&&"audio"!==pe.type&&pe.config.fullscreen.enabled){var e=s.fullscreen;e||pe.config.fullscreen.fallback&&!a.inFrame()?(ge((e?"Native":"Fallback")+" fullscreen enabled"),a.toggleClass(pe.elements.container,pe.config.classNames.fullscreen.enabled,!0)):ge("Fullscreen not supported and fallback disabled"),pe.elements.buttons&&pe.elements.buttons.fullscreen&&a.toggleState(pe.elements.buttons.fullscreen,!1),l()}}function q(){function e(){pe.captions.currentTrack=null,[].forEach.call(pe.captions.tracks,function(e){e.language===pe.captions.language.toLowerCase()&&(pe.captions.currentTrack=e)})}if(pe.supported.ui){if(a.is.empty(pe.storage.language)?a.is.empty(pe.captions.language)&&(pe.captions.language=pe.config.captions.language.toLowerCase()):pe.captions.language=pe.storage.language,a.is.boolean(pe.captions.enabled)||(a.is.empty(pe.storage.language)?pe.captions.enabled=pe.config.captions.active:pe.captions.enabled=pe.storage.captions),!a.inArray(["video","vimeo"],pe.type)||"video"===pe.type&&!s.textTracks)return pe.captions.tracks=null,void(a.inArray(pe.config.controls,"settings")&&a.inArray(pe.config.settings,"captions")&&x());if(a.is.htmlElement(pe.elements.captions)||(pe.elements.captions=a.createElement("div",a.getAttributesFromSelector(pe.config.selectors.captions)),a.insertAfter(pe.elements.captions,pe.elements.wrapper)),"video"===pe.type&&(pe.captions.tracks=pe.media.textTracks),a.toggleClass(pe.elements.container,pe.config.classNames.captions.enabled,!a.is.empty(pe.captions.tracks)),!a.is.empty(pe.captions.tracks)){if(L(),e(),!a.is.track(pe.captions.currentTrack)){var t=pe.config.captions.language;pe.captions.language=t,e(),a.is.track(pe.captions.currentTrack)||pe.toggleCaptions(!1),T("captions")}if("video"===pe.type){[].forEach.call(pe.captions.tracks,function(e){a.off(e,"cuechange",I),e.mode="hidden"});var n=a.inArray(["captions","subtitles"],pe.captions.currentTrack&&pe.captions.currentTrack.kind);a.is.track(pe.captions.currentTrack)&&n&&(a.on(pe.captions.currentTrack,"cuechange",I),pe.captions.currentTrack.activeCues&&pe.captions.currentTrack.activeCues.length>0&&I(pe.captions.currentTrack))}else"vimeo"===pe.type&&pe.captions.active&&pe.embed.enableTextTrack(pe.captions.language);a.inArray(pe.config.controls,"settings")&&a.inArray(pe.config.settings,"captions")&&x()}}}function F(){return pe.supported.ui?!s.textTracks||a.is.empty(pe.captions.tracks)?pe.config.i18n.none:pe.captions.enabled?pe.captions.currentTrack.label:pe.config.i18n.disabled:null}function I(e){a.is.event(e)&&(e=e.target);var t=e.activeCues[0];a.is.cue(t)?_(t.getCueAsHTML()):_(),r(pe.media,"cuechange")}function _(e){if(pe.supported.ui)if(a.is.htmlElement(pe.elements.captions)){var t=a.createElement("span");a.emptyElement(pe.elements.captions),a.is.undefined(e)&&(e=""),a.is.string(e)?t.textContent=e.trim():t.appendChild(e),pe.elements.captions.appendChild(t)}else fe("No captions element to render to")}function L(){if(pe.elements.buttons.captions){var e=pe.storage.captions;a.is.boolean(e)?pe.captions.active=e:e=pe.captions.active,e&&(a.toggleClass(pe.elements.container,pe.config.classNames.captions.active,!0),a.toggleState(pe.elements.buttons.captions,!0))}}function M(){if(pe.config.loadSprite){var e=g();e.absolute?(ge("AJAX loading absolute SVG sprite"+(pe.browser.isIE?" (due to IE)":"")),a.loadSprite(e.url,"sprite-plyr")):ge("Sprite will be used as external resource directly")}pe.id=Math.floor(1e4*Math.random());var t=null;t=a.is.string(pe.config.controls)?pe.config.controls:a.is.function(pe.config.controls)?pe.config.controls({id:pe.id,seektime:pe.config.seekTime}):C({id:pe.id,seektime:pe.config.seekTime,speed:"-",quality:"-",captions:F(),loop:"None"});var n;if(a.is.string(pe.config.selectors.controls.container)&&(n=document.querySelector(pe.config.selectors.controls.container)),a.is.htmlElement(n)||(n=pe.elements.container),a.is.htmlElement(t)?n.appendChild(t):n.insertAdjacentHTML("beforeend",t),a.is.htmlElement(pe.elements.controls)&&V(),pe.config.tooltips.controls)for(var i=c([pe.config.selectors.controls.wrapper," ",pe.config.selectors.labels," .",pe.config.classNames.hidden].join("")),o=i.length-1;o>=0;o--){var s=i[o];a.toggleClass(s,pe.config.classNames.hidden,!1),a.toggleClass(s,pe.config.classNames.tooltip,!0)}}function V(){try{return pe.elements.controls=u(pe.config.selectors.controls.wrapper),pe.elements.buttons={play:c(pe.config.selectors.buttons.play),pause:u(pe.config.selectors.buttons.pause),restart:u(pe.config.selectors.buttons.restart),rewind:u(pe.config.selectors.buttons.rewind),forward:u(pe.config.selectors.buttons.forward),mute:u(pe.config.selectors.buttons.mute),pip:u(pe.config.selectors.buttons.pip),airplay:u(pe.config.selectors.buttons.airplay),settings:u(pe.config.selectors.buttons.settings),captions:u(pe.config.selectors.buttons.captions),fullscreen:u(pe.config.selectors.buttons.fullscreen)},pe.elements.progress=u(pe.config.selectors.progress),pe.elements.inputs={seek:u(pe.config.selectors.inputs.seek),volume:u(pe.config.selectors.inputs.volume)},pe.elements.display={buffer:u(pe.config.selectors.display.buffer),duration:u(pe.config.selectors.display.duration),currentTime:u(pe.config.selectors.display.currentTime)},a.is.htmlElement(pe.elements.progress)&&(pe.elements.display.seekTooltip=pe.elements.progress.querySelector("."+pe.config.classNames.tooltip)),!0}catch(e){return fe("It looks like there is a problem with your custom controls HTML",e),j(!0),!1}}function O(){a.toggleClass(pe.elements.container,pe.config.selectors.container.replace(".",""),!0),a.toggleClass(pe.elements.container,pe.config.classNames.uiSupported,pe.supported.ui)}function j(e){e&&a.inArray(i.html5,pe.type)?pe.media.setAttribute("controls",""):pe.media.removeAttribute("controls")}function D(e){var t=pe.config.i18n.play;if(a.is.string(pe.config.title)&&!a.is.empty(pe.config.title)&&(t+=", "+pe.config.title,pe.elements.container.setAttribute("aria-label",pe.config.title)),pe.supported.ui&&(a.is.htmlElement(pe.elements.buttons.play)&&pe.elements.buttons.play.setAttribute("aria-label",t),a.is.htmlElement(pe.elements.buttons.playLarge)&&pe.elements.buttons.playLarge.setAttribute("aria-label",t)),a.is.htmlElement(e)){var n=a.is.string(pe.config.title)&&!a.is.empty(pe.config.title)?pe.config.title:"video";e.setAttribute("title",pe.config.i18n.frameTitle.replace("{title}",n))}}function R(){var e=null;pe.storage={},s.storage&&pe.config.storage.enabled&&(window.localStorage.removeItem("plyr-volume"),(e=window.localStorage.getItem(pe.config.storage.key))&&(/^\d+(\.\d+)?$/.test(e)?B({volume:parseFloat(e)}):pe.storage=JSON.parse(e)))}function B(e){s.storage&&pe.config.storage.enabled&&(a.extend(pe.storage,e),window.localStorage.setItem(pe.config.storage.key,JSON.stringify(pe.storage)))}function H(){pe.media?(a.toggleClass(pe.elements.container,pe.config.classNames.type.replace("{0}",pe.type),!0),a.inArray(i.embed,pe.type)&&a.toggleClass(pe.elements.container,pe.config.classNames.type.replace("{0}","video"),!0),pe.supported.ui&&(a.toggleClass(pe.elements.container,pe.config.classNames.pip.supported,s.pip&&"video"===pe.type),a.toggleClass(pe.elements.container,pe.config.classNames.airplay.supported,s.airplay&&a.inArray(i.html5,pe.type)),a.toggleClass(pe.elements.container,pe.config.classNames.stopped,pe.config.autoplay),a.toggleClass(pe.elements.container,pe.config.classNames.isIos,pe.browser.isIos),a.toggleClass(pe.elements.container,pe.config.classNames.isTouch,s.touch)),a.inArray(["video","youtube","vimeo"],pe.type)&&(pe.elements.wrapper=a.createElement("div",{class:pe.config.classNames.video}),a.wrap(pe.media,pe.elements.wrapper)),a.inArray(i.embed,pe.type)&&W()):fe("No media element found!")}function W(){var e,t=pe.type+"-"+Math.floor(1e4*Math.random());switch(pe.type){case"youtube":e=a.parseYouTubeId(pe.embedId);break;default:e=pe.embedId}for(var n=c('[id^="'+pe.type+'-"]'),i=n.length-1;i>=0;i--)a.removeElement(n[i]);if(a.toggleClass(pe.elements.wrapper,pe.config.classNames.embed,!0),"youtube"===pe.type)pe.media.setAttribute("id",t),a.is.object(window.YT)?Q(e):(a.injectScript(pe.config.urls.youtube.api),window.onYouTubeReadyCallbacks=window.onYouTubeReadyCallbacks||[],window.onYouTubeReadyCallbacks.push(function(){Q(e)}),window.onYouTubeIframeAPIReady=function(){window.onYouTubeReadyCallbacks.forEach(function(e){e()})});else if("vimeo"===pe.type)if(pe.media.setAttribute("id",t),a.is.object(window.Vimeo))U(e);else{a.injectScript(pe.config.urls.vimeo.api);var o=window.setInterval(function(){a.is.object(window.Vimeo)&&(window.clearInterval(o),U(e))},50)}else if("soundcloud"===pe.type){var s=a.createElement("iframe");s.loaded=!1,a.on(s,"load",function(){s.loaded=!0}),a.setAttributes(s,{src:"https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/"+e,id:t}),pe.media.appendChild(s),window.SC||a.injectScript(pe.config.urls.soundcloud.api);var r=window.setInterval(function(){window.SC&&s.loaded&&(window.clearInterval(r),J.call(s))},50)}}function Y(){pe.supported.ui&&(ue(),de()),D(u("iframe"))}function Q(e){pe.embed=new window.YT.Player(pe.media.id,{videoId:e,playerVars:{autoplay:pe.config.autoplay?1:0,controls:pe.supported.ui?0:1,rel:0,showinfo:0,iv_load_policy:3,modestbranding:1,disablekb:1,playsinline:1,origin:window.location.hostname,widget_referrer:window.location.href},events:{onError:function(e){r(pe.elements.container,"error",!0,{code:e.data,embed:e.target})},onPlaybackQualityChange:function(e){var t=e.target;pe.media.quality=t.getPlaybackQuality(),r(pe.media,"qualitychange")},onPlaybackRateChange:function(e){var t=e.target;pe.media.playbackRate=t.getPlaybackRate(),r(pe.media,"ratechange")},onReady:function(e){var t=e.target;pe.media.play=function(){t.playVideo(),pe.media.paused=!1},pe.media.pause=function(){t.pauseVideo(),pe.media.paused=!0},pe.media.stop=function(){t.stopVideo(),pe.media.paused=!0},pe.media.duration=t.getDuration(),pe.media.paused=!0,pe.media.currentTime=0,pe.media.muted=t.isMuted(),a.inArray(pe.config.controls,"settings")&&a.inArray(pe.config.settings,"speed")&&N(t.getAvailablePlaybackRates(),t.getPlaybackRate()),pe.config.title=t.getVideoData().title,pe.supported.ui&&pe.media.setAttribute("tabindex",-1),Y(),r(pe.media,"timeupdate"),r(pe.media,"durationchange"),window.clearInterval(me.buffering),me.buffering=window.setInterval(function(){pe.media.buffered=t.getVideoLoadedFraction(),(null===pe.media.lastBuffered||pe.media.lastBuffered<pe.media.buffered)&&r(pe.media,"progress"),pe.media.lastBuffered=pe.media.buffered,1===pe.media.buffered&&(window.clearInterval(me.buffering),r(pe.media,"canplaythrough"))},200)},onStateChange:function(e){var t=e.target;switch(window.clearInterval(me.playing),e.data){case 0:if(pe.config.loop.active){t.stopVideo(),t.playVideo();break}pe.media.paused=!0,r(pe.media,"ended");break;case 1:pe.media.paused=!1,pe.media.seeking&&r(pe.media,"seeked"),pe.media.seeking=!1,r(pe.media,"play"),r(pe.media,"playing"),me.playing=window.setInterval(function(){pe.media.currentTime=t.getCurrentTime(),r(pe.media,"timeupdate")},100),pe.media.duration!==t.getDuration()&&(pe.media.duration=t.getDuration(),r(pe.media,"durationchange")),A(t.getAvailableQualityLevels(),t.getPlaybackQuality());break;case 2:pe.media.paused=!0,r(pe.media,"pause")}r(pe.elements.container,"statechange",!1,{code:e.data})}}})}function U(e){pe.embed=new window.Vimeo.Player(pe.media,{id:e,loop:pe.config.loop.active,autoplay:pe.config.autoplay,byline:!1,portrait:!1,title:!1}),pe.media.play=function(){pe.embed.play(),pe.media.paused=!1},pe.media.pause=function(){pe.embed.pause(),pe.media.paused=!0},pe.media.stop=function(){pe.embed.stop(),pe.media.paused=!0},pe.media.paused=!0,pe.media.currentTime=0,Y(),pe.embed.getCurrentTime().then(function(e){pe.media.currentTime=e,r(pe.media,"timeupdate")}),pe.embed.getDuration().then(function(e){pe.media.duration=e,r(pe.media,"durationchange")}),pe.embed.getTextTracks().then(function(e){pe.captions.tracks=e,q()}),pe.embed.on("cuechange",function(e){var t=null;e.cues.length&&(t=a.stripHTML(e.cues[0].text)),_(t)}),pe.embed.on("loaded",function(){a.is.htmlElement(pe.embed.element)&&pe.supported.ui&&pe.embed.element.setAttribute("tabindex",-1)}),pe.embed.on("play",function(){pe.media.paused=!1,r(pe.media,"play"),r(pe.media,"playing")}),pe.embed.on("pause",function(){pe.media.paused=!0,r(pe.media,"pause")}),pe.embed.on("timeupdate",function(e){pe.media.seeking=!1,pe.media.currentTime=e.seconds,r(pe.media,"timeupdate")}),pe.embed.on("progress",function(e){pe.media.buffered=e.percent,r(pe.media,"progress"),1===parseInt(e.percent)&&r(pe.media,"canplaythrough")}),pe.embed.on("seeked",function(){pe.media.seeking=!1,r(pe.media,"seeked"),r(pe.media,"play")}),pe.embed.on("ended",function(){pe.media.paused=!0,r(pe.media,"ended")})}function J(){pe.embed=window.SC.Widget(this),pe.embed.bind(window.SC.Widget.Events.READY,function(){pe.media.play=function(){pe.embed.play(),pe.media.paused=!1},pe.media.pause=function(){pe.embed.pause(),pe.media.paused=!0},pe.media.stop=function(){pe.embed.seekTo(0),pe.embed.pause(),pe.media.paused=!0},pe.media.paused=!0,pe.media.currentTime=0,pe.embed.getDuration(function(e){pe.media.duration=e/1e3,Y()}),pe.embed.getPosition(function(e){pe.media.currentTime=e,r(pe.media,"timeupdate")}),pe.embed.bind(window.SC.Widget.Events.PLAY,function(){pe.media.paused=!1,r(pe.media,"play"),r(pe.media,"playing")}),pe.embed.bind(window.SC.Widget.Events.PAUSE,function(){pe.media.paused=!0,r(pe.media,"pause")}),pe.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS,function(e){pe.media.seeking=!1,pe.media.currentTime=e.currentPosition/1e3,r(pe.media,"timeupdate")}),pe.embed.bind(window.SC.Widget.Events.LOAD_PROGRESS,function(e){pe.media.buffered=e.loadProgress,r(pe.media,"progress"),1===parseInt(e.loadProgress)&&r(pe.media,"canplaythrough")}),pe.embed.bind(window.SC.Widget.Events.FINISH,function(){pe.media.paused=!0,r(pe.media,"ended")})})}function X(){a.toggleClass(pe.elements.container,pe.config.classNames.playing,!pe.media.paused),a.toggleClass(pe.elements.container,pe.config.classNames.stopped,pe.media.paused),pe.toggleControls(pe.media.paused)}function z(e){var t=pe.elements.settings.form,n=pe.elements.buttons.settings,i=a.is.boolean(e)?e:t&&"true"===t.getAttribute("aria-hidden");if(a.is.event(e)){var o=t&&t.contains(e.target),s=e.target===pe.elements.buttons.settings;if(o||!o&&!s&&i)return;s&&e.stopPropagation()}n&&n.setAttribute("aria-expanded",i),t&&(t.setAttribute("aria-hidden",!i),i?t.removeAttribute("tabindex"):t.setAttribute("tabindex",-1))}function G(e){var t,n,i=e.cloneNode(!0);return i.style.position="absolute",i.style.opacity=0,i.setAttribute("aria-hidden",!1),[].forEach.call(i.querySelectorAll("input[name]"),function(e){var t=e.getAttribute("name");e.setAttribute("name",t+"-clone")}),e.parentNode.appendChild(i),t=i.scrollWidth,n=i.scrollHeight,a.removeElement(i),{width:t,height:n}}function K(e){var t=pe.elements.settings.menu,n=e.target,i="false"===n.getAttribute("aria-expanded"),o=document.getElementById(n.getAttribute("aria-controls"));if(a.is.htmlElement(o)&&"tabpanel"===o.getAttribute("role")){var r=t.querySelector('[role="tabpanel"][aria-hidden="false"]'),l=r.parentNode;if([].forEach.call(t.querySelectorAll('[aria-controls="'+r.getAttribute("id")+'"]'),function(e){e.setAttribute("aria-expanded",!1)}),s.transitions&&!s.reducedMotion){l.style.width=r.scrollWidth+"px",l.style.height=r.scrollHeight+"px";var c=G(o),u=function(e){e.target===l&&a.inArray(["width","height"],e.propertyName)&&(l.style.width="",l.style.height="",a.off(l,a.transitionEnd,u))};a.on(l,a.transitionEnd,u),l.style.width=c.width+"px",l.style.height=c.height+"px"}r.setAttribute("aria-hidden",!0),r.setAttribute("tabindex",-1),o.setAttribute("aria-hidden",!i),n.setAttribute("aria-expanded",i),o.removeAttribute("tabindex")}}function $(){if(pe.supported.ui){var e=pe.media.muted?0:pe.media.volume;pe.elements.inputs.volume&&ee(pe.elements.inputs.volume,e)}B({volume:pe.media.volume}),a.toggleClass(pe.elements.container,pe.config.classNames.muted,pe.media.muted),pe.supported.ui&&pe.elements.buttons.mute&&a.toggleState(pe.elements.buttons.mute,pe.media.muted)}function Z(e){pe.loading="waiting"===e.type,clearTimeout(me.loading),me.loading=setTimeout(function(){a.toggleClass(pe.elements.container,pe.config.classNames.loading,pe.loading),pe.toggleControls(pe.loading)},pe.loading?250:0)}function ee(e,t){a.is.htmlElement(e)&&(e.value=t,m(e))}function te(e,t){if(a.is.undefined(t)&&(t=0),a.is.undefined(e)&&(e=pe.elements.display.buffer),a.is.htmlElement(e)){e.value=t;var n=e.getElementsByTagName("span")[0];a.is.htmlElement(n)&&(n.childNodes[0].nodeValue=t)}}function ne(e){if(pe.supported.ui){var t=0,n=pe.getDuration();if(e)switch(e.type){case"timeupdate":case"seeking":t=a.getPercentage(pe.media.currentTime,n),"timeupdate"===e.type&&ee(pe.elements.inputs.seek,t);break;case"playing":case"progress":t=function(){var e=pe.media.buffered;return e&&e.length?a.getPercentage(e.end(0),n):a.is.number(e)?100*e:0}(),te(pe.elements.display.buffer,t)}}}function ie(e,t){if(a.is.htmlElement(t)){isNaN(e)&&(e=0);var n=parseInt(e%60),i=parseInt(e/60%60),o=parseInt(e/60/60%60),s=pe.getDuration(),r=parseInt(s/60/60%60)>0;n=("0"+n).slice(-2),i=("0"+i).slice(-2);var l=(r?o+":":"")+i+":"+n;return t.textContent=l,l}}function ae(){if(pe.supported.ui){var e=pe.getDuration()||0;!pe.elements.display.duration&&pe.config.displayDuration&&pe.media.paused&&ie(e,pe.elements.display.currentTime),pe.elements.display.duration&&ie(e,pe.elements.display.duration),se()}}function oe(e){ie(pe.media.currentTime,pe.elements.display.currentTime),e&&"timeupdate"===e.type&&pe.media.seeking||ne(e)}function se(e){var t=pe.getDuration();if(pe.config.tooltips.seek&&a.is.htmlElement(pe.elements.inputs.seek)&&a.is.htmlElement(pe.elements.display.seekTooltip)&&0!==t){var n=pe.elements.inputs.seek.getBoundingClientRect(),i=0,o=pe.config.classNames.tooltip+"--visible";if(a.is.event(e))i=100/n.width*(e.pageX-n.left);else{if(!a.hasClass(pe.elements.display.seekTooltip,o))return;i=pe.elements.display.seekTooltip.style.left.replace("%","")}i<0?i=0:i>100&&(i=100),ie(t/100*i,pe.elements.display.seekTooltip),pe.elements.display.seekTooltip.style.left=i+"%",a.is.event(e)&&a.inArray(["mouseenter","mouseleave"],e.type)&&a.toggleClass(pe.elements.display.seekTooltip,o,"mouseenter"===e.type)}}function re(){function e(){var e=pe.togglePlay(),t=pe.elements.buttons[e?"pause":"play"];a.is.htmlElement(t)&&t.focus()}function t(e){return e.keyCode?e.keyCode:e.which}function n(n){var i=t(n),o="keydown"===n.type,l=o&&i===r;if(a.is.number(i))if(o){if(a.inArray([38,40],i)){var c=a.getFocusElement();if(a.is.htmlElement(c)&&"radio"===a.getFocusElement().type)return}switch(a.inArray([48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67,73,76,79],i)&&(n.preventDefault(),n.stopPropagation()),i){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:l||function(){var e=pe.media.duration;a.is.number(e)&&pe.seek(e/10*(i-48))}();break;case 32:case 75:l||e();break;case 38:pe.increaseVolume(.1);break;case 40:pe.decreaseVolume(.1);break;case 77:l||pe.toggleMute();break;case 39:pe.forward();break;case 37:pe.rewind();break;case 70:pe.toggleFullscreen();break;case 67:l||pe.toggleCaptions();break;case 73:pe.setLoop("start");break;case 76:pe.setLoop();break;case 79:pe.setLoop("end")}!s.fullscreen&&pe.fullscreen.active&&27===i&&pe.toggleFullscreen(),r=i}else r=null}var i=pe.browser.isIE?"change":"input";if(pe.config.keyboard.focused){var r=null;pe.config.keyboard.global&&a.on(window,"keydown keyup",function(e){var i=t(e),o=a.getFocusElement();!a.inArray([48,49,50,51,52,53,54,56,57,75,77,70,67,73,76,79],i)||a.is.htmlElement(o)&&a.matches(o,pe.config.selectors.editable)||n(e)},!1),a.on(pe.elements.container,"keydown keyup",n,!1)}a.on(pe.elements.container,"focusout",function(e){a.toggleClass(e.target,pe.config.classNames.tabFocus,!1)}),a.on(pe.elements.container,"keydown",function(e){9===e.keyCode&&window.setTimeout(function(){a.toggleClass(a.getFocusElement(),pe.config.classNames.tabFocus,!0)},0)});var l=function(e,t,n){a.is.function(t)&&t.call(this,e),a.is.function(n)&&n.call(this,e)};a.proxy(pe.elements.buttons.play,"click",pe.config.listeners.play,e),a.proxy(pe.elements.buttons.playLarge,"click",pe.config.listeners.play,e),a.proxy(pe.elements.buttons.pause,"click",pe.config.listeners.pause,e),a.proxy(pe.elements.buttons.restart,"click",pe.config.listeners.restart,function(){pe.restart()}),a.proxy(pe.elements.buttons.rewind,"click",pe.config.listeners.rewind,function(){pe.rewind()}),a.proxy(pe.elements.buttons.forward,"click",pe.config.listeners.forward,function(){pe.forward()}),a.proxy(pe.elements.buttons.mute,"click",pe.config.listeners.mute,function(){pe.toggleMute()}),a.proxy(pe.elements.buttons.captions,"click",pe.config.listeners.captions,function(){pe.toggleCaptions()}),a.proxy(pe.elements.buttons.fullscreen,"click",pe.config.listeners.fullscreen,function(){pe.toggleFullscreen()}),a.proxy(pe.elements.buttons.pip,"click",pe.config.listeners.pip,function(){pe.togglePictureInPicture()}),a.proxy(pe.elements.buttons.airplay,"click",pe.config.listeners.airplay,function(){pe.airPlay()}),a.on(pe.elements.buttons.settings,"click",z),a.on(document.documentElement,"click",z),a.on(pe.elements.settings.form,"click",function(e){K(e),a.matches(e.target,pe.config.selectors.inputs.language)?l.call(this,e,pe.config.listeners.language,function(){pe.toggleCaptions(!0),pe.setLanguage(e.target.value.toLowerCase())}):a.matches(e.target,pe.config.selectors.inputs.quality)?l.call(this,e,pe.config.listeners.quality,function(){pe.setQuality(e.target.value)}):a.matches(e.target,pe.config.selectors.inputs.speed)?l.call(this,e,pe.config.listeners.speed,function(){pe.setSpeed(parseFloat(e.target.value))}):a.matches(e.target,pe.config.selectors.buttons.loop)&&l.call(this,e,pe.config.listeners.loop,function(){fe("Set loop")})}),a.proxy(pe.elements.inputs.seek,i,pe.config.listeners.seek,function(e){var t=pe.getDuration();pe.seek(e.target.value/e.target.max*t)}),a.proxy(pe.elements.inputs.volume,i,pe.config.listeners.volume,function(){pe.setVolume(event.target.value)}),pe.browser.isWebkit&&a.on(c('input[type="range"]'),"input",m),a.on(pe.elements.progress,"mouseenter mouseleave mousemove",se),pe.config.hideControls&&(a.on(pe.elements.container,"mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen",function(e){pe.toggleControls(e)}),a.on(pe.elements.controls,"mouseenter mouseleave",function(e){pe.elements.controls.hover="mouseenter"===e.type}),a.on(pe.elements.controls,"mousedown mouseup touchstart touchend touchcancel",function(e){pe.elements.controls.pressed=a.inArray(["mousedown","touchstart"],e.type)}),a.on(pe.elements.controls,"focus blur",function(e){pe.toggleControls(e)},!0)),a.proxy(pe.elements.inputs.volume,"wheel",pe.config.listeners.volume,function(e){var t=e.webkitDirectionInvertedFromDevice,n=0;(e.deltaY<0||e.deltaX>0)&&(t?(pe.decreaseVolume(.02),n=-1):(pe.increaseVolume(.02),n=1)),(e.deltaY>0||e.deltaX<0)&&(t?(pe.increaseVolume(.02),n=1):(pe.decreaseVolume(.02),n=-1)),(1===n&&pe.media.volume<1||-1===n&&pe.media.volume>0)&&e.preventDefault()},!1),s.fullscreen&&a.on(document,o.eventType,function(e){pe.toggleFullscreen(e)})}function le(){if(a.on(pe.media,"timeupdate seeking",oe),a.on(pe.media,"durationchange loadedmetadata",ae),a.on(pe.media,"ended",function(){"video"===pe.type&&pe.config.showPosterOnEnd&&("video"===pe.type&&_(),pe.restart(),pe.media.load())}),a.on(pe.media,"progress playing",ne),a.on(pe.media,"volumechange",$),a.on(pe.media,"play pause ended",X),a.on(pe.media,"waiting canplay seeked",Z),pe.supported.ui&&pe.config.clickToPlay&&"audio"!==pe.type){var e=u("."+pe.config.classNames.video);if(!e)return;e.style.cursor="pointer",a.on(e,"click",function(){pe.config.hideControls&&s.touch&&!pe.media.paused||(pe.media.paused?pe.play():pe.media.ended?(pe.restart(),pe.play()):pe.pause())})}pe.config.disableContextMenu&&a.on(pe.media,"contextmenu",function(e){e.preventDefault()},!1),a.on(pe.media,"ratechange",function(){pe.speed.selected=pe.media.playbackRate,T("speed"),B({speed:pe.speed.selected})}),a.on(pe.media,"qualitychange",function(){pe.quality.selected=pe.media.quality,T("quality"),B({quality:pe.quality.selected})}),a.on(pe.media,"captionchange",function(){B({language:pe.captions.language})}),a.on(pe.media,"captionsenabled captionsdisabled",function(){T("captions"),B({captions:pe.captions.enabled})}),a.on(pe.media,pe.config.events.concat(["keyup","keydown"]).join(" "),function(e){r(pe.elements.container,e.type,!0)})}function ce(){if(a.inArray(i.html5,pe.type)){for(var e=pe.media.querySelectorAll("source"),t=0;t<e.length;t++)a.removeElement(e[t]);pe.media.setAttribute("src",pe.config.blankVideo),pe.media.load(),ge("Cancelled network requests")}}function ue(){if(le(),!pe.supported.ui)return fe("Basic support only",pe.type),d("controls"),d("buttons.play"),void j(!0);a.is.htmlElement(pe.elements.controls)||(M(),re()),a.is.htmlElement(pe.elements.controls)&&(j(),P(),q(),pe.setVolume(),$(),pe.setSpeed(),pe.setLoop(),oe(),X())}function de(){pe.ready=!0,window.setTimeout(function(){r(pe.elements.container,"ready",!0)},0),pe.config.autoplay&&pe.play()}var pe=this,me={};pe.ready=!1,pe.media=e,a.is.string(pe.media)&&(pe.media=document.querySelectorAll(pe.media)),(window.jQuery&&pe.media instanceof jQuery||a.is.nodeList(pe.media)||a.is.array(pe.media))&&(pe.media=pe.media[0]),pe.config=a.extend({},n,t,function(){try{return JSON.parse(pe.media.getAttribute("data-plyr"))}catch(e){}}()),pe.elements={container:null,buttons:{},display:{},progress:{},inputs:{},settings:{menu:null,panes:{},tabs:{}},captions:null},pe.captions={enabled:null,tracks:null,currentTrack:null},pe.fullscreen={active:!1},pe.speed={selected:null,options:[]},pe.quality={selected:null,options:[]},pe.loop={indicator:{start:0,end:0}};var ge=function(){},fe=function(){},ye=function(){};pe.config.debug&&"console"in window&&(ge=console.log,fe=console.warn,ye=console.error,ge("Debugging enabled")),ge("Config",pe.config),ge("Support",s),pe.core={getElement:u,getElements:c,trigger:r,setCaption:_,setupCaptions:q,toggleNativeControls:j,updateTimeDisplay:ie,updateSource:function(e){a.is.object(e)&&"sources"in e&&e.sources.length?(ce(),pe.destroy(function(){if(d(pe.media),d("captions"),d("wrapper"),pe.elements.container&&pe.elements.container.removeAttribute("class"),"type"in e&&(pe.type=e.type,"video"===pe.type)){var t=e.sources[0];"type"in t&&a.inArray(i.embed,t.type)&&(pe.type=t.type)}switch(pe.supported=a.checkSupport(pe.type,pe.config.inline),pe.type){case"video":pe.media=a.createElement("video");break;case"audio":pe.media=a.createElement("audio");break;case"youtube":case"vimeo":case"soundcloud":pe.media=a.createElement("div"),pe.embedId=e.sources[0].src}pe.elements.container.appendChild(pe.media),a.is.boolean(e.autoplay)&&(pe.config.autoplay=e.autoplay),a.inArray(i.html5,pe.type)&&(pe.config.crossorigin&&pe.media.setAttribute("crossorigin",""),pe.config.autoplay&&pe.media.setAttribute("autoplay",""),"poster"in e&&pe.media.setAttribute("poster",e.poster),pe.config.loop.active&&pe.media.setAttribute("loop",""),pe.config.muted&&pe.media.setAttribute("muted",""),pe.config.inline&&pe.media.setAttribute("playsinline","")),a.toggleClass(pe.elements.container,pe.config.classNames.captions.active,pe.supported.ui&&pe.captions.enabled),O(),a.inArray(i.html5,pe.type)&&p("source",e.sources),H(),a.inArray(i.html5,pe.type)&&("tracks"in e&&p("track",e.tracks),pe.media.load()),(a.inArray(i.html5,pe.type)||a.inArray(i.embed,pe.type)&&!pe.supported.ui)&&(ue(),de()),pe.config.title=e.title,D()},!1)):fe("Invalid source format")},toggleMenu:z,timers:me,support:s,log:ge,warn:fe,error:ye},function(e){if(null!==e&&!a.is.undefined(e)&&a.is.htmlElement(e)){if(e.plyr)return fe("Target already setup"),void(pe=e.plyr);if(pe.config.enabled)if(a.checkSupport().api){pe.elements.original=e.cloneNode(!0);var t=e.tagName.toLowerCase();switch(t){case"div":if(pe.type=e.getAttribute("data-type"),pe.embedId=e.getAttribute("data-video-id"),a.is.empty(pe.type))return void ye("Setup failed: embed type missing");if(a.is.empty(pe.embedId))return void ye("Setup failed: video id missing");e.removeAttribute("data-type"),e.removeAttribute("data-video-id");break;case"iframe":break;case"video":case"audio":pe.type=t,null!==e.getAttribute("crossorigin")&&(pe.config.crossorigin=!0),null!==e.getAttribute("autoplay")&&(pe.config.autoplay=!0),null!==e.getAttribute("playsinline")&&(pe.config.inline=!0),null!==e.getAttribute("muted")&&(pe.config.muted=!0),null!==e.getAttribute("loop")&&(pe.config.loop.active=!0);break;default:return void ye("Setup failed: unsupported type")}pe.browser=a.getBrowser(),R(),pe.supported=a.checkSupport(pe.type,pe.config.inline),pe.supported.api?(e.plyr=pe,pe.elements.container=a.wrap(e,a.createElement("div")),O(),ge(pe.browser.name+" "+pe.browser.version),H(),pe.config.debug&&a.on(pe.elements.container,pe.config.events.join(" "),function(e){ge("event: "+e.type)}),(a.inArray(i.html5,pe.type)||a.inArray(i.embed,pe.type)&&!pe.supported.ui)&&(ue(),de(),D())):ye("Setup failed: no support")}else ye("Setup failed: no support");else ye("Setup failed: disabled by config")}else ye("Setup failed: no suitable element passed")}(pe.media)}var t={x:0,y:0},n={enabled:!0,title:"",debug:!1,autoplay:!1,seekTime:10,volume:1,muted:!1,displayDuration:!0,clickToPlay:!0,hideControls:!0,showPosterOnEnd:!1,disableContextMenu:!0,loadSprite:!0,iconPrefix:"plyr",iconUrl:"https://cdn.plyr.io/2.0.10/plyr.svg",blankVideo:"https://cdn.plyr.io/static/blank.mp4",duration:null,quality:{default:"default",options:["hd2160","hd1440","hd1080","hd720","large","medium","small","tiny","default"]},loop:{active:!1,start:null,end:null},speed:{default:1,options:[.5,.75,1,1.25,1.5,1.75,2]},keyboard:{focused:!0,global:!1},tooltips:{controls:!1,seek:!0},captions:{active:!1,language:window.navigator.language.split("-")[0]},fullscreen:{enabled:!0,fallback:!0},storage:{enabled:!0,key:"plyr"},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","pip","airplay","fullscreen"],settings:["captions","quality","speed","loop"],i18n:{restart:"Restart",rewind:"Rewind {seektime} secs",play:"Play",pause:"Pause",forward:"Forward {seektime} secs",seek:"Seek",played:"Played",buffered:"Buffered",currentTime:"Current time",duration:"Duration",volume:"Volume",toggleMute:"Toggle Mute",toggleCaptions:"Toggle Captions",toggleFullscreen:"Toggle Fullscreen",frameTitle:"Player for {title}",captions:"Captions",settings:"Settings",speed:"Speed",quality:"Quality",loop:"Loop",start:"Start",end:"End",all:"All",reset:"Reset",none:"None",disabled:"Disabled"},urls:{vimeo:{api:"https://player.vimeo.com/api/player.js"},youtube:{api:"https://www.youtube.com/iframe_api"},soundcloud:{api:"https://w.soundcloud.com/player/api.js"}},listeners:{seek:null,play:null,pause:null,restart:null,rewind:null,forward:null,mute:null,volume:null,captions:null,fullscreen:null,pip:null,airplay:null,speed:null,quality:null,loop:null,language:null},events:["ended","progress","stalled","playing","waiting","canplay","canplaythrough","loadstart","loadeddata","loadedmetadata","timeupdate","volumechange","play","pause","error","seeking","seeked","emptied","ratechange","cuechange","enterfullscreen","exitfullscreen","captionsenabled","captionsdisabled","captionchange","controlshidden","controlsshown","statechange","qualitychange","qualityrequested"],selectors:{editable:"input, textarea, select, [contenteditable]",container:".plyr",controls:{container:null,wrapper:".plyr__controls"},labels:"[data-plyr]",buttons:{play:'[data-plyr="play"]',pause:'[data-plyr="pause"]',restart:'[data-plyr="restart"]',rewind:'[data-plyr="rewind"]',forward:'[data-plyr="fast-forward"]',mute:'[data-plyr="mute"]',captions:'[data-plyr="captions"]',fullscreen:'[data-plyr="fullscreen"]',pip:'[data-plyr="pip"]',airplay:'[data-plyr="airplay"]',settings:'[data-plyr="settings"]',loop:'[data-plyr="loop"]'},inputs:{seek:'[data-plyr="seek"]',volume:'[data-plyr="volume"]',speed:'[data-plyr="speed"]',language:'[data-plyr="language"]',quality:'[data-plyr="quality"]'},display:{currentTime:".plyr__time--current",duration:".plyr__time--duration",buffer:".plyr__progress--buffer",played:".plyr__progress--played",loop:".plyr__progress--loop",volume:".plyr__volume--display"},progress:".plyr__progress",captions:".plyr__captions",menu:{quality:".js-plyr__menu__list--quality"}},classNames:{video:"plyr__video-wrapper",embed:"plyr__video-embed",control:"plyr__control",type:"plyr--{0}",stopped:"plyr--stopped",playing:"plyr--playing",muted:"plyr--muted",loading:"plyr--loading",hover:"plyr--hover",tooltip:"plyr__tooltip",hidden:"plyr__sr-only",hideControls:"plyr--hide-controls",isIos:"plyr--is-ios",isTouch:"plyr--is-touch",uiSupported:"plyr--full-ui",menu:{value:"plyr__menu__value",badge:"plyr__badge"},captions:{enabled:"plyr--captions-enabled",active:"plyr--captions-active"},fullscreen:{enabled:"plyr--fullscreen-enabled",fallback:"plyr--fullscreen-fallback"},pip:{supported:"plyr--pip-supported",active:"plyr--pip-active"},airplay:{supported:"plyr--airplay-supported",active:"plyr--airplay-active"},tabFocus:"tab-focus"}},i={embed:["youtube","vimeo","soundcloud"],html5:["video","audio"]},a={is:{object:function(e){return null!==e&&"object"==typeof e&&e.constructor===Object},array:function(e){return null!==e&&Array.isArray(e)},number:function(e){return null!==e&&("number"==typeof e&&!isNaN(e-0)||"object"==typeof e&&e.constructor===Number)},string:function(e){return null!==e&&("string"==typeof e||"object"==typeof e&&e.constructor===String)},boolean:function(e){return null!==e&&"boolean"==typeof e},nodeList:function(e){return null!==e&&e instanceof NodeList},htmlElement:function(e){return null!==e&&e instanceof HTMLElement},function:function(e){return null!==e&&"function"==typeof e},event:function(e){return null!==e&&e instanceof Event},cue:function(e){this.instanceOf(e,window.TextTrackCue)||this.instanceOf(e,window.VTTCue)},track:function(e){return null!==e&&(this.instanceOf(e,window.TextTrack)||"string"==typeof e.kind)},undefined:function(e){return null!==e&&void 0===e},empty:function(e){return null===e||this.undefined(e)||(this.string(e)||this.array(e)||this.nodeList(e))&&0===e.length||this.object(e)&&0===Object.keys(e).length},instanceOf:function(e,t){return Boolean(e&&t&&e instanceof t)}},getBrowser:function(){var e,t,n,i=navigator.userAgent,a=navigator.appName,o=""+parseFloat(navigator.appVersion),s=parseInt(navigator.appVersion,10),r=!1,l=!1,c=!1,u=!1;return-1!==navigator.appVersion.indexOf("Windows NT")&&-1!==navigator.appVersion.indexOf("rv:11")?(r=!0,a="IE",o="11"):-1!==(t=i.indexOf("MSIE"))?(r=!0,a="IE",o=i.substring(t+5)):-1!==(t=i.indexOf("Chrome"))?(c=!0,a="Chrome",o=i.substring(t+7)):-1!==(t=i.indexOf("Safari"))?(u=!0,a="Safari",o=i.substring(t+7),-1!==(t=i.indexOf("Version"))&&(o=i.substring(t+8))):-1!==(t=i.indexOf("Firefox"))?(l=!0,a="Firefox",o=i.substring(t+8)):(e=i.lastIndexOf(" ")+1)<(t=i.lastIndexOf("/"))&&(a=i.substring(e,t),o=i.substring(t+1),a.toLowerCase()===a.toUpperCase()&&(a=navigator.appName)),-1!==(n=o.indexOf(";"))&&(o=o.substring(0,n)),-1!==(n=o.indexOf(" "))&&(o=o.substring(0,n)),s=parseInt(""+o,10),isNaN(s)&&(o=""+parseFloat(navigator.appVersion),s=parseInt(navigator.appVersion,10)),{name:a,version:s,isIE:r,isFirefox:l,isChrome:c,isSafari:u,isWebkit:"WebkitAppearance"in document.documentElement.style,isIPhone:/(iPhone|iPod)/gi.test(navigator.platform),isIos:/(iPad|iPhone|iPod)/gi.test(navigator.platform),isSupported:!(r&&s<=9)}},checkSupport:function(e,t){var n=!1,i=!1,o=a.getBrowser(),r=o.isIPhone&&t&&s.inline;switch(e){case"video":i=(n=s.video)&&o.isSupported&&(!o.isIPhone||r);break;case"audio":i=(n=s.audio)&&o.isSupported;break;case"youtube":i=(n=!0)&&o.isSupported&&(!o.isIPhone||r);break;case"vimeo":n=!0,i=!1;break;case"soundcloud":n=!0,i=o.isSupported;break;default:i=(n=s.audio&&s.video)&&o.isSupported}return{api:n,ui:i}},injectScript:function(e){if(!document.querySelectorAll('script[src="'+e+'"]').length){var t=document.createElement("script");t.src=e;var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n)}},inFrame:function(){try{return window.self!==window.top}catch(e){return!0}},inArray:function(e,t){return a.is.array(e)&&-1!==e.indexOf(t)},wrap:function(e,t){e.length||(e=[e]);for(var n=e.length-1;n>=0;n--){var i=n>0?t.cloneNode(!0):t,a=e[n],o=a.parentNode,s=a.nextSibling;return i.appendChild(a),s?o.insertBefore(i,s):o.appendChild(i),i}},removeElement:function(e){a.is.htmlElement(e)&&a.is.htmlElement(e.parentNode)&&e.parentNode.removeChild(e)},insertAfter:function(e,t){t.parentNode.insertBefore(e,t.nextSibling)},createElement:function(e,t,n){var i=document.createElement(e);return a.is.object(t)&&a.setAttributes(i,t),a.is.string(n)&&(i.textContent=n),i},insertElement:function(e,t,n,i){t.appendChild(a.createElement(e,n,i))},emptyElement:function(e){for(var t=e.childNodes.length;t--;)e.removeChild(e.lastChild)},setAttributes:function(e,t){for(var n in t)e.setAttribute(n,t[n])},getAttributesFromSelector:function(e,t){if(!a.is.string(e)||a.is.empty(e))return{};var n={};return e.split(",").forEach(function(e){switch((e=e.trim()).charAt(0)){case".":var i=e.replace(".","");a.is.object(t)&&a.is.string(t.class)&&(t.class+=" "+i),n.class=i;break;case"#":n.id=e.replace("#","");break;case"[":var o=(e=e.replace(/[[\]]/g,"")).split("="),s=o[0],r=o.length>1?o[1].replace(/["']/g,""):"";n[s]=r}}),n},toggleClass:function(e,t,n){if(a.is.htmlElement(e)){var i=!1;if(e.classList)i=e.classList.contains(t),e.classList[n?"add":"remove"](t);else{i=a.inArray(e.className.split(" "),t);var o=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=o+(n?" "+t:"")}return n&&!i||!n&&i}return null},hasClass:function(e,t){return!!e&&(e.classList?e.classList.contains(t):new RegExp("(\\s|^)"+t+"(\\s|$)").test(e.className))},matches:function(e,t){var n=Element.prototype;return(n.matches||n.webkitMatchesSelector||n.mozMatchesSelector||n.msMatchesSelector||function(e){return-1!==[].indexOf.call(document.querySelectorAll(e),this)}).call(e,t)},getFocusElement:function(){var e=document.activeElement;return e=e&&e!==document.body?document.querySelector(":focus"):null},proxy:function(e,t,n,i,o,s){a.on(e,t,function(t){n&&n.apply(e,[t]),i.apply(e,[t])},o,s)},toggleListener:function(e,t,n,i,o,r){if(null!==e&&!a.is.undefined(e)){if(t=t.split(" "),a.is.boolean(r)||(r=!1),a.is.boolean(o)||(o=!0),e instanceof NodeList){var l=1===arguments.length?[arguments[0]]:Array.apply(null,arguments);return l.shift(),void[].forEach.call(e,function(e){e instanceof Node&&a.toggleListener.apply(null,[e].concat(l))})}var c=r;s.passiveListeners&&(c={passive:o,capture:r}),t.forEach(function(t){e[i?"addEventListener":"removeEventListener"](t,n,c)})}},on:function(e,t,n,i,o){a.toggleListener(e,t,n,!0,i,o)},off:function(e,t,n,i,o){a.toggleListener(e,t,n,!1,i,o)},dispatchEvent:function(e,t,n,i){if(e&&t){a.is.boolean(n)||(n=!1);var o;a.is.function(window.CustomEvent)?o=window.CustomEvent:(o=function(e,t){t=t||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n}).prototype=window.Event.prototype;var s=new o(t,{bubbles:n,detail:i});e.dispatchEvent(s)}},toggleState:function(e,t){if(e)return t=a.is.boolean(t)?t:!e.getAttribute("aria-pressed"),e.setAttribute("aria-pressed",t),t},getPercentage:function(e,t){return 0===e||0===t||isNaN(e)||isNaN(t)?0:(e/t*100).toFixed(2)},extend:function(){var e=arguments;if(e.length){if(1===e.length)return e[0];var t=Array.prototype.shift.call(e);a.is.object(t)||(t={});for(var n=e.length,i=0;i<n;i++){var o=e[i];a.is.object(o)||(o={});for(var s in o)o[s]&&o[s].constructor&&o[s].constructor===Object?(t[s]=t[s]||{},a.extend(t[s],o[s])):t[s]=o[s]}return t}},parseYouTubeId:function(e){return e.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/)?RegExp.$2:e},stripHTML:function(e){var t=document.createDocumentFragment(),n=document.createElement("div");return t.appendChild(n),n.innerHTML=e,t.firstChild.innerText},loadSprite:function(e,t){function n(e,t){e.innerHTML=t,document.body.insertBefore(e,document.body.childNodes[0])}if("string"==typeof e){var i="string"==typeof t;if(!i||!document.querySelectorAll("#"+t).length){var a=document.createElement("div");if(a.setAttribute("hidden",""),i&&a.setAttribute("id",t),s.storage){var o=window.localStorage.getItem("cache-"+t);if(null!==o){var r=JSON.parse(o);n(a,r.content)}}var l=new XMLHttpRequest;if(!("withCredentials"in l))return;l.open("GET",e,!0),l.onload=function(){s.storage&&window.localStorage.setItem("cache-"+t,JSON.stringify({content:l.responseText})),n(a,l.responseText)},l.send()}}},transitionEnd:function(){var e=document.createElement("span"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var n in t)if(void 0!==e.style[n])return t[n];return!1}()},o=function(){var e=function(){var e=!1;return a.is.function(document.cancelFullScreen)?e="":["webkit","o","moz","ms","khtml"].some(function(t){return a.is.function(document[t+"CancelFullScreen"])?(e=t,!0):a.is.function(document.msExitFullscreen)&&document.msFullscreenEnabled?(e="ms",!0):void 0}),e}();return{prefix:e,eventType:"ms"===e?"MSFullscreenChange":e+"fullscreenchange",isFullScreen:function(t){if(!s.fullscreen)return!1;switch(a.is.undefined(t)&&(t=document.body),e){case"":return document.fullscreenElement===t;case"moz":return document.mozFullScreenElement===t;default:return document[e+"FullscreenElement"]===t}},requestFullScreen:function(t){return!!s.fullscreen&&(a.is.htmlElement(t)||(t=document.body),e.length?t[e+("ms"===e?"RequestFullscreen":"RequestFullScreen")]():t.requestFullScreen())},cancelFullScreen:function(){return!!s.fullscreen&&(e.length?document[e+("ms"===e?"ExitFullscreen":"CancelFullScreen")]():document.cancelFullScreen())},element:function(){return s.fullscreen?e.length?document[e+"FullscreenElement"]:document.fullscreenElement:null}}}(),s={audio:"canPlayType"in document.createElement("audio"),video:"canPlayType"in document.createElement("video"),fullscreen:!1!==o.prefix,storage:function(){if(!("localStorage"in window))return!1;try{return window.localStorage.setItem("___test","___test"),window.localStorage.removeItem("___test"),!0}catch(e){return!1}}(),pip:!a.getBrowser().isIPhone&&a.is.function(a.createElement("video").webkitSetPresentationMode),airplay:a.is.function(window.WebKitPlaybackTargetAvailabilityEvent),inline:"playsInline"in document.createElement("video"),mime:function(e,t){var n=e.media;try{if(!a.is.function(n.canPlayType))return!1;if("video"===e.type)switch(t){case"video/webm":return n.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/,"");case"video/mp4":return n.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/,"");case"video/ogg":return n.canPlayType('video/ogg; codecs="theora"').replace(/no/,"")}else if("audio"===e.type)switch(t){case"audio/mpeg":return n.canPlayType("audio/mpeg;").replace(/no/,"");case"audio/ogg":return n.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/,"");case"audio/wav":return n.canPlayType('audio/wav; codecs="1"').replace(/no/,"")}}catch(e){return!1}return!1},textTracks:"textTracks"in document.createElement("video"),passiveListeners:function(){var e=!1;try{var t=Object.defineProperty({},"passive",{get:function(){e=!0}});window.addEventListener("test",null,t)}catch(e){}return e}(),touch:"ontouchstart"in document.documentElement,transitions:!1!==a.transitionEnd,reducedMotion:"matchMedia"in window&&window.matchMedia("(prefers-reduced-motion)").matches};return e.prototype.play=function(){var e=this;return"play"in e.media&&e.media.play(),e},e.prototype.pause=function(){var e=this;return"pause"in e.media&&e.media.pause(),e},e.prototype.togglePlay=function(e){var t=this;return a.is.boolean(e)||(e=t.media.paused),e?t.play():t.pause(),e},e.prototype.isPlaying=function(){return!this.media.paused},e.prototype.stop=function(){var e=this;return e.restart(),e.pause(),e},e.prototype.restart=function(){var e=this;return e.seek(),e},e.prototype.rewind=function(e){var t=this;return a.is.number(e)||(e=t.config.seekTime),t.seek(t.media.currentTime-e),t},e.prototype.forward=function(e){var t=this;return a.is.number(e)||(e=t.config.seekTime),t.seek(t.media.currentTime+e),t},e.prototype.seek=function(e){var t=this,n=0,o=t.media.paused,s=t.getDuration();if(a.is.number(e)&&(n=e),n<0?n=0:n>s&&(n=s),a.inArray(i.embed,t.type)){switch(t.type){case"youtube":t.embed.seekTo(n);break;case"vimeo":t.embed.setCurrentTime(n);break;case"soundcloud":t.embed.seekTo(1e3*n)}o&&t.pause(),t.media.seeking=!0,t.core.trigger(t.media,"seeking")}else t.media.currentTime=n.toFixed(4);return t.core.log("Seeking to "+t.media.currentTime+" seconds"),t},e.prototype.setVolume=function(e){var t=this,n=!a.is.undefined(e);if(a.is.string(e)&&(e=parseFloat(e)),a.is.number(e)||(e=t.storage.volume),a.is.number(e)||(e=t.config.volume),e>1&&(e=1),e<0&&(e=0),t.media.volume=e,a.inArray(i.embed,t.type)){switch(t.type){case"youtube":t.embed.setVolume(100*t.media.volume);break;case"vimeo":case"soundcloud":t.embed.setVolume(t.media.volume)}t.core.trigger(t.media,"volumechange")}return 0===e?t.toggleMute(!0):t.media.muted&&n&&t.toggleMute(),t},e.prototype.increaseVolume=function(e){var t=this,n=t.media.muted?0:t.media.volume;return a.is.number(e)||(e=1),t.setVolume(n+e),t},e.prototype.decreaseVolume=function(e){var t=this,n=t.media.muted?0:t.media.volume;return a.is.number(e)||(e=1),t.setVolume(n-e),t},e.prototype.toggleMute=function(e){var t=this;if(a.is.boolean(e)||(e=!t.media.muted),a.toggleState(t.elements.buttons.mute,e),t.media.muted=e,t.media.muted||0!==t.media.volume||t.setVolume(t.config.volume),a.inArray(i.embed,t.type)){switch(t.type){case"youtube":t.embed[t.media.muted?"mute":"unMute"]();break;case"vimeo":case"soundcloud":t.embed.setVolume(t.media.muted?0:t.config.volume)}t.core.trigger(t.media,"volumechange")}return t},e.prototype.setSpeed=function(e){var t=this;if(a.is.number(e)||(e=parseFloat(t.storage.speed||t.speed.selected||t.config.speed.default)),e<.1&&(e=.1),e>2&&(e=2),a.inArray(t.config.speed.options,e)){switch(t.type){case"youtube":t.embed.setPlaybackRate(e);break;case"vimeo":e=null,t.core.warn("Vimeo playback rate change is not supported");break;default:t.media.playbackRate=e}return t}t.core.warn("Unsupported speed ("+e+")")},e.prototype.setQuality=function(e){var t=this;a.is.string(e)||(e=parseFloat(t.storage.quality||t.config.quality.selected));{if(a.inArray(t.config.quality.options,e)){switch(t.type){case"youtube":t.core.trigger(t.media,"qualityrequested",!1,{quality:e}),t.embed.setPlaybackQuality(e);break;default:t.core.warn("Quality options are only available for YouTube")}return t}t.core.warn("Unsupported quality option ("+e+")")}},e.prototype.setLoop=function(e){var t=this;a.inArray(["start","end","all","none","toggle"],e)||(e="toggle");var n=Number(t.media.currentTime);switch(e){case"start":t.config.loop.end&&t.config.loop.end<=n&&(t.config.loop.end=null),t.config.loop.start=n;break;case"end":if(t.config.loop.start>=n)return;t.config.loop.end=n;break;case"all":t.config.loop.start=0,t.config.loop.end=t.media.duration-2,t.config.loop.indicator.start=0,t.config.loop.indicator.end=100;break;case"toggle":t.config.loop.active?(t.config.loop.start=0,t.config.loop.end=null):(t.config.loop.start=0,t.config.loop.end=t.media.duration-2);break;default:t.config.loop.start=0,t.config.loop.end=null}return t},e.prototype.source=function(e){var t=this;if(a.is.object(e))return t.core.updateSource(e),t;var n;switch(t.type){case"youtube":n=t.embed.getVideoUrl();break;case"vimeo":t.embed.getVideoUrl.then(function(e){n=e});break;case"soundcloud":t.embed.getCurrentSound(function(e){n=e.permalink_url});break;default:n=t.media.currentSrc}return n},e.prototype.poster=function(e){var t=this;return a.is.string(e)?("video"===t.type?t.media.setAttribute("poster",e):t.core.warn("Poster can only be set on HTML5 video"),t):t.media.getAttribute("poster")},e.prototype.toggleCaptions=function(e){var t=this;if(t.supported.ui&&t.elements.buttons.captions)return a.is.boolean(e)||(e=-1===t.elements.container.className.indexOf(t.config.classNames.captions.active)),t.captions.enabled===e?t:(t.captions.enabled=e,a.toggleState(t.elements.buttons.captions,t.captions.enabled),a.toggleClass(t.elements.container,t.config.classNames.captions.active,t.captions.enabled),t.core.trigger(t.media,t.captions.enabled?"captionsenabled":"captionsdisabled"),t)},e.prototype.setLanguage=function(e){var t=this;return a.is.empty(e)?(t.toggleCaptions(!1),t):(e=e.toLowerCase(),t.captions.language===e?t:(t.toggleCaptions(!0),t.captions.language=e,t.core.trigger(t.media,"captionchange"),t.core.setCaption(),t.core.setupCaptions(),t))},e.prototype.getLanguage=function(){return this.captions.language},e.prototype.toggleFullscreen=function(e){var n=this;if(s.fullscreen){if(!a.is.event(e)||e.type!==o.eventType)return n.fullscreen.active?o.cancelFullScreen():o.requestFullScreen(n.elements.container),void(n.fullscreen.active=o.isFullScreen(n.elements.container));n.fullscreen.active=o.isFullScreen(n.elements.container)}else n.fullscreen.active=!n.fullscreen.active,a.toggleClass(n.elements.container,n.config.classNames.fullscreen.fallback,n.fullscreen.active),n.fullscreen.active?t={x:window.pageXOffset||0,y:window.pageYOffset||0}:window.scrollTo(t.x,t.y),document.body.style.overflow=n.fullscreen.active?"hidden":"";return n.elements.buttons&&n.elements.buttons.fullscreen&&a.toggleState(n.elements.buttons.fullscreen,n.fullscreen.active),n.core.trigger(n.media,n.fullscreen.active?"enterfullscreen":"exitfullscreen"),n},e.prototype.togglePictureInPicture=function(e){var t=this,n={pip:"picture-in-picture",inline:"inline"};if(t.core.support.pip)return a.is.boolean(e)||(e=t.media.webkitPresentationMode===n.inline),t.media.webkitSetPresentationMode(e?n.pip:n.inline),t},e.prototype.airPlay=function(){var e=this;if(e.core.support.airplay)return e.media.webkitShowPlaybackTargetPicker(),e},e.prototype.toggleControls=function(e){var t=this;if(t.supported.ui&&t.config.hideControls&&"audio"!==t.type){var n=0,i=e,o=!1,r=a.hasClass(t.elements.container,t.config.classNames.loading);if(a.is.boolean(e)||(a.is.event(e)?(o="enterfullscreen"===e.type,i=a.inArray(["mousemove","touchstart","mouseenter","focus"],e.type),a.inArray(["mousemove","touchmove"],e.type)&&(n=2e3),"focus"===e.type&&(n=3e3)):i=a.hasClass(t.elements.container,t.config.classNames.hideControls)),window.clearTimeout(t.core.timers.hover),i||t.media.paused||r){if(a.toggleClass(t.elements.container,t.config.classNames.hideControls,!1)&&t.core.trigger(t.media,"controlsshown"),t.media.paused||r)return;s.touch&&(n=3e3)}return i&&t.media.paused||(t.core.timers.hover=window.setTimeout(function(){(!t.elements.controls.pressed&&!t.elements.controls.hover||o)&&a.toggleClass(t.elements.container,t.config.classNames.hideControls,!0)&&(t.core.trigger(t.media,"controlshidden"),a.inArray(t.config.controls,"settings")&&!a.is.empty(t.config.settings)&&t.core.toggleMenu(!1))},n)),t}},e.prototype.on=function(e,t){var n=this;return a.on(n.elements.container,e,t),n},e.prototype.off=function(e,t){var n=this;return a.off(n.elements.container,e,t),n},e.prototype.supports=function(e){return s.mime(this,e)},e.prototype.destroy=function(e,t){function n(){if(null!==i){if(a.is.boolean(t)||(t=!0),document.body.style.overflow="",t){var n=i.elements.container.parentNode;a.is.htmlElement(n)&&n.replaceChild(i.elements.original,i.elements.container)}i.core.trigger(i.elements.original,"destroyed",!0),a.is.function(e)&&e.call(i.elements.original),i=null}}var i=this;switch(i.type){case"youtube":window.clearInterval(i.core.timers.buffering),window.clearInterval(i.core.timers.playing),i.embed.destroy(),n();break;case"vimeo":i.embed.unload().then(n),window.setTimeout(n,200);break;case"video":case"audio":i.core.toggleNativeControls(!0),n()}},e.prototype.getDuration=function(){var e=this,t=parseInt(e.config.duration),n=0;return null===e.media.duration||isNaN(e.media.duration)||(n=e.media.duration),isNaN(t)?n:t},e});
\ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Plyr",t):e.Plyr=t()}(this,function(){"use strict";function e(e){s.storage&&this.config.storage.enabled&&(n.extend(this.storage,e),window.localStorage.setItem(this.config.storage.key,JSON.stringify(this.storage)))}var t={enabled:!0,title:"",debug:!1,autoplay:!1,seekTime:10,volume:1,muted:!1,displayDuration:!0,clickToPlay:!0,hideControls:!0,showPosterOnEnd:!1,disableContextMenu:!0,loadSprite:!0,iconPrefix:"plyr",iconUrl:"https://cdn.plyr.io/2.0.10/plyr.svg",blankVideo:"https://cdn.plyr.io/static/blank.mp4",duration:null,quality:{default:"default",options:["hd2160","hd1440","hd1080","hd720","large","medium","small","tiny","default"]},loop:{active:!1,start:null,end:null},speed:{default:1,options:[.5,.75,1,1.25,1.5,1.75,2]},keyboard:{focused:!0,global:!1},tooltips:{controls:!1,seek:!0},captions:{active:!1,language:window.navigator.language.split("-")[0]},fullscreen:{enabled:!0,fallback:!0},storage:{enabled:!0,key:"plyr"},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","pip","airplay","fullscreen"],settings:["captions","quality","speed","loop"],i18n:{restart:"Restart",rewind:"Rewind {seektime} secs",play:"Play",pause:"Pause",forward:"Forward {seektime} secs",seek:"Seek",played:"Played",buffered:"Buffered",currentTime:"Current time",duration:"Duration",volume:"Volume",toggleMute:"Toggle Mute",toggleCaptions:"Toggle Captions",toggleFullscreen:"Toggle Fullscreen",frameTitle:"Player for {title}",captions:"Captions",settings:"Settings",speed:"Speed",quality:"Quality",loop:"Loop",start:"Start",end:"End",all:"All",reset:"Reset",none:"None",disabled:"Disabled"},urls:{vimeo:{api:"https://player.vimeo.com/api/player.js"},youtube:{api:"https://www.youtube.com/iframe_api"}},listeners:{seek:null,play:null,pause:null,restart:null,rewind:null,forward:null,mute:null,volume:null,captions:null,fullscreen:null,pip:null,airplay:null,speed:null,quality:null,loop:null,language:null},events:["ended","progress","stalled","playing","waiting","canplay","canplaythrough","loadstart","loadeddata","loadedmetadata","timeupdate","volumechange","play","pause","error","seeking","seeked","emptied","ratechange","cuechange","enterfullscreen","exitfullscreen","captionsenabled","captionsdisabled","captionchange","controlshidden","controlsshown","ready","statechange","qualitychange","qualityrequested"],selectors:{editable:"input, textarea, select, [contenteditable]",container:".plyr",controls:{container:null,wrapper:".plyr__controls"},labels:"[data-plyr]",buttons:{play:'[data-plyr="play"]',pause:'[data-plyr="pause"]',restart:'[data-plyr="restart"]',rewind:'[data-plyr="rewind"]',forward:'[data-plyr="fast-forward"]',mute:'[data-plyr="mute"]',captions:'[data-plyr="captions"]',fullscreen:'[data-plyr="fullscreen"]',pip:'[data-plyr="pip"]',airplay:'[data-plyr="airplay"]',settings:'[data-plyr="settings"]',loop:'[data-plyr="loop"]'},inputs:{seek:'[data-plyr="seek"]',volume:'[data-plyr="volume"]',speed:'[data-plyr="speed"]',language:'[data-plyr="language"]',quality:'[data-plyr="quality"]'},display:{currentTime:".plyr__time--current",duration:".plyr__time--duration",buffer:".plyr__progress--buffer",played:".plyr__progress--played",loop:".plyr__progress--loop",volume:".plyr__volume--display"},progress:".plyr__progress",captions:".plyr__captions",menu:{quality:".js-plyr__menu__list--quality"}},classNames:{video:"plyr__video-wrapper",embed:"plyr__video-embed",control:"plyr__control",type:"plyr--{0}",stopped:"plyr--stopped",playing:"plyr--playing",muted:"plyr--muted",loading:"plyr--loading",hover:"plyr--hover",tooltip:"plyr__tooltip",hidden:"plyr__sr-only",hideControls:"plyr--hide-controls",isIos:"plyr--is-ios",isTouch:"plyr--is-touch",uiSupported:"plyr--full-ui",menu:{value:"plyr__menu__value",badge:"plyr__badge"},captions:{enabled:"plyr--captions-enabled",active:"plyr--captions-active"},fullscreen:{enabled:"plyr--fullscreen-enabled",fallback:"plyr--fullscreen-fallback"},pip:{supported:"plyr--pip-supported",active:"plyr--pip-active"},airplay:{supported:"plyr--airplay-supported",active:"plyr--airplay-active"},tabFocus:"tab-focus"}},i={embed:["youtube","vimeo"],html5:["video","audio"]},n={is:{object:function(e){return this.getConstructor(e)===Object},number:function(e){return this.getConstructor(e)===Number&&!Number.isNaN(e)},string:function(e){return this.getConstructor(e)===String},boolean:function(e){return this.getConstructor(e)===Boolean},function:function(e){return this.getConstructor(e)===Function},array:function(e){return!this.undefined(e)&&Array.isArray(e)},nodeList:function(e){return!this.undefined(e)&&e instanceof NodeList},htmlElement:function(e){return!this.undefined(e)&&e instanceof HTMLElement},event:function(e){return!this.undefined(e)&&e instanceof Event},cue:function(e){return this.instanceOf(e,window.TextTrackCue)||this.instanceOf(e,window.VTTCue)},track:function(e){return!this.undefined(e)&&(this.instanceOf(e,window.TextTrack)||"string"==typeof e.kind)},undefined:function(e){return null!==e&&void 0===e},empty:function(e){return null===e||void 0===e||(this.string(e)||this.array(e)||this.nodeList(e))&&0===e.length||this.object(e)&&0===Object.keys(e).length},getConstructor:function(e){return null===e||void 0===e?null:e.constructor},instanceOf:function(e,t){return Boolean(e&&t&&e instanceof t)}},getBrowser:function(){return{isIE:!!document.documentMode,isWebkit:"WebkitAppearance"in document.documentElement.style&&!/Edge/.test(navigator.userAgent),isIPhone:/(iPhone|iPod)/gi.test(navigator.platform),isIos:/(iPad|iPhone|iPod)/gi.test(navigator.platform)}},loadScript:function(e){if(!document.querySelectorAll('script[src="'+e+'"]').length){var t=document.createElement("script");t.src=e;var i=document.getElementsByTagName("script")[0];i.parentNode.insertBefore(t,i)}},generateId:function(e){return e+"-"+Math.floor(1e4*Math.random())},inFrame:function(){try{return window.self!==window.top}catch(e){return!0}},wrap:function(e,t){var i=e.length?e:[e];Array.from(i).reverse().forEach(function(e,i){var n=i>0?t.cloneNode(!0):t,s=e.parentNode,a=e.nextSibling;n.appendChild(e),a?s.insertBefore(n,a):s.appendChild(n)})},removeElement:function(e){return n.is.htmlElement(e)&&n.is.htmlElement(e.parentNode)?(e.parentNode.removeChild(e),e):null},insertAfter:function(e,t){t.parentNode.insertBefore(e,t.nextSibling)},createElement:function(e,t,i){var s=document.createElement(e);return n.is.object(t)&&n.setAttributes(s,t),n.is.string(i)&&(s.textContent=i),s},insertElement:function(e,t,i,s){t.appendChild(n.createElement(e,i,s))},emptyElement:function(e){for(var t=e.childNodes.length;t>0;)e.removeChild(e.lastChild),t-=1},setAttributes:function(e,t){Object.keys(t).forEach(function(i){e.setAttribute(i,t[i])})},getAttributesFromSelector:function(e,t){if(!n.is.string(e)||n.is.empty(e))return{};var i={},s=t;return e.split(",").forEach(function(e){var t=e.trim(),a=t.replace(".",""),l=t.replace(/[[\]]/g,"").split("="),o=l[0],r=l.length>1?l[1].replace(/["']/g,""):"";switch(t.charAt(0)){case".":n.is.object(s)&&n.is.string(s.class)&&(s.class+=" "+a),i.class=a;break;case"#":i.id=t.replace("#","");break;case"[":i[o]=r}}),i},toggleClass:function(e,t,i){if(n.is.htmlElement(e)){var s=e.classList.contains(t);return e.classList[i?"add":"remove"](t),i&&!s||!i&&s}return null},hasClass:function(e,t){return n.is.htmlElement(e)&&e.classList.contains(t)},matches:function(e,t){var i={Element:Element},n=i.matches||i.webkitMatchesSelector||i.mozMatchesSelector||i.msMatchesSelector||function(){return Array.from(document.querySelectorAll(t)).includes(this)};return n.call(e,t)},getElements:function(e){return this.elements.container.querySelectorAll(e)},getElement:function(e){return this.elements.container.querySelector(e)},findElements:function(){try{return this.elements.controls=n.getElement.call(this,this.config.selectors.controls.wrapper),this.elements.buttons={play:n.getElements.call(this,this.config.selectors.buttons.play),pause:n.getElement.call(this,this.config.selectors.buttons.pause),restart:n.getElement.call(this,this.config.selectors.buttons.restart),rewind:n.getElement.call(this,this.config.selectors.buttons.rewind),forward:n.getElement.call(this,this.config.selectors.buttons.forward),mute:n.getElement.call(this,this.config.selectors.buttons.mute),pip:n.getElement.call(this,this.config.selectors.buttons.pip),airplay:n.getElement.call(this,this.config.selectors.buttons.airplay),settings:n.getElement.call(this,this.config.selectors.buttons.settings),captions:n.getElement.call(this,this.config.selectors.buttons.captions),fullscreen:n.getElement.call(this,this.config.selectors.buttons.fullscreen)},this.elements.progress=n.getElement.call(this,this.config.selectors.progress),this.elements.inputs={seek:n.getElement.call(this,this.config.selectors.inputs.seek),volume:n.getElement.call(this,this.config.selectors.inputs.volume)},this.elements.display={buffer:n.getElement.call(this,this.config.selectors.display.buffer),duration:n.getElement.call(this,this.config.selectors.display.duration),currentTime:n.getElement.call(this,this.config.selectors.display.currentTime)},n.is.htmlElement(this.elements.progress)&&(this.elements.display.seekTooltip=this.elements.progress.querySelector("."+this.config.classNames.tooltip)),!0}catch(e){return this.warn("It looks like there is a problem with your custom controls HTML",e),this.toggleNativeControls(!0),!1}},getFocusElement:function(){var e=document.activeElement;return e=e&&e!==document.body?document.querySelector(":focus"):null},trapFocus:function(){var e=this,t=n.getElements.call(this,"input:not([disabled]), button:not([disabled])"),i=t[0],s=t[t.length-1];n.on(this.elements.container,"keydown",function(t){9===t.which&&e.fullscreen.active&&(t.target!==s||t.shiftKey?t.target===i&&t.shiftKey&&(t.preventDefault(),s.focus()):(t.preventDefault(),i.focus()))},!1)},proxy:function(e,t,i,s,a,l){n.on(e,t,function(t){i&&i.apply(e,[t]),s.apply(e,[t])},a,l)},toggleListener:function(e,t,i,a,l,o){if(null!==e&&!n.is.undefined(e))if(e instanceof NodeList)Array.from(e).forEach(function(e){e instanceof Node&&n.toggleListener.call(null,e,t,i,a,l,o)});else{var r=t.split(" "),c=!!n.is.boolean(o)&&o;s.passiveListeners&&(c={passive:!n.is.boolean(l)||l,capture:!!n.is.boolean(o)&&o}),r.forEach(function(t){e[a?"addEventListener":"removeEventListener"](t,i,c)})}},on:function(e,t,i,s,a){n.toggleListener(e,t,i,!0,s,a)},off:function(e,t,i,s,a){n.toggleListener(e,t,i,!1,s,a)},dispatchEvent:function(e,t,i,s){if(e&&t){var a=new CustomEvent(t,{bubbles:!!n.is.boolean(i)&&i,detail:Object.assign({},s,{plyr:this instanceof Plyr?this:null})});e.dispatchEvent(a)}},toggleState:function(e,t){if(!e)return null;var i=n.is.boolean(t)?t:!e.getAttribute("aria-pressed");return e.setAttribute("aria-pressed",i),i},getPercentage:function(e,t){return 0===e||0===t||Number.isNaN(e)||Number.isNaN(t)?0:(e/t*100).toFixed(2)},extend:function(){for(var e=arguments.length,t=Array(e),i=0;i<e;i++)t[i]=arguments[i];var s=t.length;if(!s)return null;if(1===s)return t[0];var a=Array.prototype.shift.call(t);return n.is.object(a)||(a={}),t.forEach(function(e){n.is.object(e)&&Object.keys(e).forEach(function(t){e[t]&&e[t].constructor&&e[t].constructor===Object?(a[t]=a[t]||{},n.extend(a[t],e[t])):a[t]=e[t]})}),a},parseYouTubeId:function(e){return e.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/)?RegExp.$2:e},parseVimeoId:function(e){if(n.is.number(Number(e)))return e;return e.match(/^.*(vimeo.com\/|video\/)(\d+).*/)?RegExp.$2:e},buildUrlParameters:function(e){return n.is.object(e)?Object.keys(e).map(function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])}).join("&"):""},stripHTML:function(e){var t=document.createDocumentFragment(),i=document.createElement("div");return t.appendChild(i),i.innerHTML=e,t.firstChild.innerText},loadSprite:function(e,t){function i(e){this.innerHTML=e,document.body.insertBefore(this,document.body.childNodes[0])}if("string"==typeof e){var n="string"==typeof t;if(!n||!document.querySelectorAll("#"+t).length){var a=document.createElement("div");if(a.setAttribute("hidden",""),n&&a.setAttribute("id",t),s.storage){var l=window.localStorage.getItem("cache-"+t);if(null!==l){var o=JSON.parse(l);i.call(a,o.content)}}var r=new XMLHttpRequest;if(!("withCredentials"in r))return;r.open("GET",e,!0),r.onload=function(){s.storage&&window.localStorage.setItem("cache-"+t,JSON.stringify({content:r.responseText})),i.call(a,r.responseText)},r.send()}}},transitionEnd:function(){var e=document.createElement("span"),t=Object.keys({WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"}).find(function(t){return void 0!==e.style[t]});return"string"==typeof t&&t}()},s={audio:"canPlayType"in document.createElement("audio"),video:"canPlayType"in document.createElement("video"),check:function(e,t){var i=!1,a=!1,l=n.getBrowser(),o=l.isIPhone&&t&&s.inline;switch(e){case"video":a=(i=s.video)&&s.rangeInput&&(!l.isIPhone||o);break;case"audio":a=(i=s.audio)&&s.rangeInput;break;case"youtube":i=!0,a=s.rangeInput&&(!l.isIPhone||o);break;case"vimeo":i=!0,a=s.rangeInput&&!l.isIPhone;break;default:a=(i=s.audio&&s.video)&&s.rangeInput}return{api:i,ui:a}},storage:function(){if(!("localStorage"in window))return!1;try{return window.localStorage.setItem("___test","___test"),window.localStorage.removeItem("___test"),!0}catch(e){return!1}}(),pip:!n.getBrowser().isIPhone&&n.is.function(n.createElement("video").webkitSetPresentationMode),airplay:n.is.function(window.WebKitPlaybackTargetAvailabilityEvent),inline:"playsInline"in document.createElement("video"),mime:function(e,t){var i={player:e};try{if(!n.is.function(i.canPlayType))return!1;if("video"===e.type)switch(t){case"video/webm":return i.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/,"");case"video/mp4":return i.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/,"");case"video/ogg":return i.canPlayType('video/ogg; codecs="theora"').replace(/no/,"");default:return!1}else if("audio"===e.type)switch(t){case"audio/mpeg":return i.canPlayType("audio/mpeg;").replace(/no/,"");case"audio/ogg":return i.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/,"");case"audio/wav":return i.canPlayType('audio/wav; codecs="1"').replace(/no/,"");default:return!1}}catch(e){return!1}return!1},textTracks:"textTracks"in document.createElement("video"),passiveListeners:function(){var e=!1;try{var t=Object.defineProperty({},"passive",{get:function(){return e=!0,null}});window.addEventListener("test",null,t)}catch(e){}return e}(),rangeInput:function(){var e=document.createElement("input");return e.type="range","range"===e.type}(),touch:"ontouchstart"in document.documentElement,transitions:!1!==n.transitionEnd,reducedMotion:"matchMedia"in window&&window.matchMedia("(prefers-reduced-motion)").matches},a={updateRangeFill:function(e){if(this.browser.isWebkit){var t=n.is.event(e)?e.target:e;if(n.is.htmlElement(t)&&"range"===t.getAttribute("type")){n.is.htmlElement(this.elements.styleSheet)||(this.elements.styleSheet=n.createElement("style"),this.elements.container.appendChild(this.elements.styleSheet));var i=this.elements.styleSheet.sheet,s=t.value/t.max*100,a="#"+t.id+"::-webkit-slider-runnable-track",l="{ background-image: linear-gradient(to right, currentColor "+s+"%, transparent "+s+"%) }",o=Array.from(i.rules).findIndex(function(e){return e.selectorText===a});-1!==o&&i.deleteRule(o),i.insertRule([a,l].join(" "))}}},getIconUrl:function(){return{url:this.config.iconUrl,absolute:0===this.config.iconUrl.indexOf("http")||this.browser.isIE}},createIcon:function(e,t){var i=a.getIconUrl.call(this),s=(i.absolute?"":i.url)+"#"+this.config.iconPrefix,l=document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttributes(l,n.extend(t,{role:"presentation"}));var o=document.createElementNS("http://www.w3.org/2000/svg","use");return o.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",s+"-"+e),l.appendChild(o),l},createLabel:function(e){var t=this.config.i18n[e];switch(e){case"pip":t="PIP";break;case"airplay":t="AirPlay"}return n.createElement("span",{class:this.config.classNames.hidden},t)},createBadge:function(e){var t=n.createElement("span",{class:this.config.classNames.menu.value});return t.appendChild(n.createElement("span",{class:this.config.classNames.menu.badge},e)),t},createButton:function(e,t){var i=n.createElement("button"),s=Object.assign({},t),l=e,o=void 0,r=void 0,c=void 0;switch("type"in s||(s.type="button"),"class"in s?-1===s.class.indexOf(this.config.classNames.control)&&(s.class+=" "+this.config.classNames.control):s.class=this.config.classNames.control,l){case"mute":c="toggleMute",o="volume",r="muted";break;case"captions":c="toggleCaptions",o="captions-off",r="captions-on";break;case"fullscreen":c="toggleFullscreen",o="enter-fullscreen",r="exit-fullscreen";break;case"play-large":s.class="plyr__play-large",l="play",c="play",o="play";break;default:c=l,o=l}return n.extend(s,n.getAttributesFromSelector(this.config.selectors.buttons[l],s)),n.is.string(r)&&i.appendChild(a.createIcon.call(this,r,{class:"icon--"+r})),i.appendChild(a.createIcon.call(this,o)),i.appendChild(a.createLabel.call(this,c)),n.setAttributes(i,s),this.elements.buttons[l]=i,i},createRange:function(e,t){var i=n.createElement("label",{for:t.id,class:this.config.classNames.hidden},this.config.i18n[e]),s=n.createElement("input",n.extend(n.getAttributesFromSelector(this.config.selectors.inputs[e]),{type:"range",min:0,max:100,step:.01,value:0,autocomplete:"off"},t));return this.elements.inputs[e]=s,{label:i,input:s}},createProgress:function(e,t){var i=n.createElement("progress",n.extend(n.getAttributesFromSelector(this.config.selectors.display[e]),{min:0,max:100,value:0},t));if("volume"!==e){i.appendChild(n.createElement("span",null,"0"));var s="";switch(e){case"played":s=this.config.i18n.played;break;case"buffer":s=this.config.i18n.buffered}i.textContent="% "+s.toLowerCase()}return this.elements.display[e]=i,i},createTime:function(e){var t=n.createElement("span",{class:"plyr__time"});return t.appendChild(n.createElement("span",{class:this.config.classNames.hidden},this.config.i18n[e])),t.appendChild(n.createElement("span",n.getAttributesFromSelector(this.config.selectors.display[e]),"00:00")),this.elements.display[e]=t,t},toggleTab:function(e,t){var i=this.elements.settings.tabs[e],s=this.elements.settings.panes[e];n.is.htmlElement(i)&&(t?i.removeAttribute("hidden"):i.setAttribute("hidden","")),n.is.htmlElement(s)&&(t?s.removeAttribute("hidden"):s.setAttribute("hidden",""))},setQualityMenu:function(e){var t=this,i=this.elements.settings.panes.quality.querySelector("ul");n.is.array(e)?this.options.quality=e.filter(function(e){return t.config.quality.options.includes(e)}):this.options.quality=this.config.quality.options;var s=!n.is.empty(this.options.quality)&&"youtube"===this.type;if(a.toggleTab.call(this,"quality",s),s){n.emptyElement(i);var l=function(e){var i="";switch(e){case"hd2160":i="4K";break;case"hd1440":i="WQHD";break;case"hd1080":case"hd720":i="HD"}return i.length?a.createBadge.call(t,i):null};this.options.quality.forEach(function(e){var s=n.createElement("li"),o=n.createElement("label",{class:t.config.classNames.control}),r=n.createElement("input",n.extend(n.getAttributesFromSelector(t.config.selectors.inputs.quality),{type:"radio",name:"plyr-quality",value:e}));o.appendChild(r),o.appendChild(document.createTextNode(a.getLabel.call(t,"quality",e)));var c=l(e);n.is.htmlElement(c)&&o.appendChild(c),s.appendChild(o),i.appendChild(s)}),a.updateSetting.call(this,"quality",i)}},getLabel:function(e,t){switch(e){case"speed":return 1===t?"Normal":t+"×";case"quality":switch(t){case"hd2160":return"2160P";case"hd1440":return"1440P";case"hd1080":return"1080P";case"hd720":return"720P";case"large":return"480P";case"medium":return"360P";case"small":return"240P";case"tiny":return"Tiny";case"default":return"Auto";default:return t}case"captions":return a.getLanguage.call(this);default:return null}},updateSetting:function(e,t){var i=this.elements.settings.panes[e],s=null,l=t;switch(e){case"captions":s=this.captions.language,this.captions.enabled||(s="");break;default:if(s=this[e],n.is.empty(s)&&(s=this.config[e].default),!this.options[e].includes(s))return void this.warn("Unsupported value of '"+s+"' for "+e);if(!this.config[e].options.includes(s))return void this.warn("Disabled value of '"+s+"' for "+e)}n.is.htmlElement(l)||(l=i&&i.querySelector("ul"));var o=l&&l.querySelector('input[value="'+s+'"]');n.is.htmlElement(o)&&(o.checked=!0,this.elements.settings.tabs[e].querySelector("."+this.config.classNames.menu.value).innerHTML=a.getLabel.call(this,e,s))},setLoopMenu:function(){var e=this,t=this.elements.settings.panes.loop.querySelector("ul");this.elements.settings.tabs.loop.removeAttribute("hidden"),this.elements.settings.panes.loop.removeAttribute("hidden");var i=!n.is.empty(this.loop.options);a.toggleTab.call(this,"loop",i),n.emptyElement(t),["start","end","all","reset"].forEach(function(i){var s=n.createElement("li"),l=n.createElement("button",n.extend(n.getAttributesFromSelector(e.config.selectors.buttons.loop),{type:"button",class:e.config.classNames.control,"data-plyr-loop-action":i}),e.config.i18n[i]);if(["start","end"].includes(i)){var o=a.createBadge.call(e,"00:00");l.appendChild(o)}s.appendChild(l),t.appendChild(s)})},getLanguage:function(){return this.supported.ui?!s.textTracks||n.is.empty(this.captions.tracks)?this.config.i18n.none:this.captions.enabled?this.captions.currentTrack.label:this.config.i18n.disabled:null},setCaptionsMenu:function(){var e=this,t=this.elements.settings.panes.captions.querySelector("ul"),i=!n.is.empty(this.captions.tracks);if(a.toggleTab.call(this,"captions",i),n.emptyElement(t),!n.is.empty(this.captions.tracks)){var s=Array.from(this.captions.tracks).map(function(e){return{language:e.language,badge:!0,label:n.is.empty(e.label)?e.language.toUpperCase():e.label}});s.unshift({language:"",label:this.config.i18n.none}),s.forEach(function(i){var s=n.createElement("li"),l=n.createElement("label",{class:e.config.classNames.control}),o=n.createElement("input",n.extend(n.getAttributesFromSelector(e.config.selectors.inputs.language),{type:"radio",name:"plyr-language",value:i.language}));i.language.toLowerCase()===e.captions.language.toLowerCase()&&(o.checked=!0),l.appendChild(o),l.appendChild(document.createTextNode(i.label||i.language)),i.badge&&l.appendChild(a.createBadge.call(e,i.language.toUpperCase())),s.appendChild(l),t.appendChild(s)}),a.updateSetting.call(this,"captions",t)}},setSpeedMenu:function(e){var t=this;n.is.array(e)?this.options.speed=e.filter(function(e){return t.config.speed.options.includes(e)}):this.options.speed=this.config.speed.options;var i=!n.is.empty(this.options.speed);if(a.toggleTab.call(this,"speed",i),i){var s=this.elements.settings.panes.speed.querySelector("ul");this.elements.settings.tabs.speed.removeAttribute("hidden"),this.elements.settings.panes.speed.removeAttribute("hidden"),n.emptyElement(s),this.options.speed.forEach(function(e){var i=n.createElement("li"),l=n.createElement("label",{class:t.config.classNames.control}),o=n.createElement("input",n.extend(n.getAttributesFromSelector(t.config.selectors.inputs.speed),{type:"radio",name:"plyr-speed",value:e}));l.appendChild(o),l.insertAdjacentHTML("beforeend",a.getLabel.call(t,"speed",e)),i.appendChild(l),s.appendChild(i)}),a.updateSetting.call(this,"speed",s)}},toggleMenu:function(e){var t=this.elements.settings.form,i=this.elements.buttons.settings,s=n.is.boolean(e)?e:t&&"true"===t.getAttribute("aria-hidden");if(n.is.event(e)){var a=t&&t.contains(e.target),l=e.target===this.elements.buttons.settings;if(a||!a&&!l&&s)return;l&&e.stopPropagation()}i&&i.setAttribute("aria-expanded",s),t&&(t.setAttribute("aria-hidden",!s),s?t.removeAttribute("tabindex"):t.setAttribute("tabindex",-1))},getTabSize:function(e){var t=e.cloneNode(!0);t.style.position="absolute",t.style.opacity=0,t.setAttribute("aria-hidden",!1),Array.from(t.querySelectorAll("input[name]")).forEach(function(e){var t=e.getAttribute("name");e.setAttribute("name",t+"-clone")}),e.parentNode.appendChild(t);var i=t.scrollWidth,s=t.scrollHeight;return n.removeElement(t),{width:i,height:s}},showTab:function(e){var t=this.elements.settings.menu,i=e.target,l="false"===i.getAttribute("aria-expanded"),o=document.getElementById(i.getAttribute("aria-controls"));if(n.is.htmlElement(o)&&"tabpanel"===o.getAttribute("role")){var r=t.querySelector('[role="tabpanel"][aria-hidden="false"]'),c=r.parentNode;if(Array.from(t.querySelectorAll('[aria-controls="'+r.getAttribute("id")+'"]')).forEach(function(e){e.setAttribute("aria-expanded",!1)}),s.transitions&&!s.reducedMotion){c.style.width=r.scrollWidth+"px",c.style.height=r.scrollHeight+"px";var u=a.getTabSize.call(this,o),d=function e(t){t.target===c&&["width","height"].includes(t.propertyName)&&(c.style.width="",c.style.height="",n.off(c,n.transitionEnd,e))};n.on(c,n.transitionEnd,d),c.style.width=u.width+"px",c.style.height=u.height+"px"}r.setAttribute("aria-hidden",!0),r.setAttribute("tabindex",-1),o.setAttribute("aria-hidden",!l),i.setAttribute("aria-expanded",l),o.removeAttribute("tabindex")}},create:function(e){var t=this;if(n.is.empty(this.config.controls))return null;var i=n.createElement("div",n.getAttributesFromSelector(this.config.selectors.controls.wrapper));if(this.config.controls.includes("restart")&&i.appendChild(a.createButton.call(this,"restart")),this.config.controls.includes("rewind")&&i.appendChild(a.createButton.call(this,"rewind")),this.config.controls.includes("play")&&(i.appendChild(a.createButton.call(this,"play")),i.appendChild(a.createButton.call(this,"pause"))),this.config.controls.includes("fast-forward")&&i.appendChild(a.createButton.call(this,"fast-forward")),this.config.controls.includes("progress")){var l=n.createElement("span",n.getAttributesFromSelector(this.config.selectors.progress)),o=a.createRange.call(this,"seek",{id:"plyr-seek-"+e.id});if(l.appendChild(o.label),l.appendChild(o.input),l.appendChild(a.createProgress.call(this,"buffer")),this.config.tooltips.seek){var r=n.createElement("span",{role:"tooltip",class:this.config.classNames.tooltip},"00:00");l.appendChild(r),this.elements.display.seekTooltip=r}this.elements.progress=l,i.appendChild(this.elements.progress)}if(this.config.controls.includes("current-time")&&i.appendChild(a.createTime.call(this,"currentTime")),this.config.controls.includes("duration")&&i.appendChild(a.createTime.call(this,"duration")),this.config.controls.includes("mute")&&i.appendChild(a.createButton.call(this,"mute")),this.config.controls.includes("volume")){var c=n.createElement("span",{class:"plyr__volume"}),u={max:1,step:.05,value:this.config.volume},d=a.createRange.call(this,"volume",n.extend(u,{id:"plyr-volume-"+e.id}));c.appendChild(d.label),c.appendChild(d.input),i.appendChild(c)}if(this.config.controls.includes("captions")&&i.appendChild(a.createButton.call(this,"captions")),this.config.controls.includes("settings")&&!n.is.empty(this.config.settings)){var h=n.createElement("div",{class:"plyr__menu"});h.appendChild(a.createButton.call(this,"settings",{id:"plyr-settings-toggle-"+e.id,"aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id,"aria-expanded":!1}));var p=n.createElement("form",{class:"plyr__menu__container",id:"plyr-settings-"+e.id,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tablist",tabindex:-1}),m=n.createElement("div"),g=n.createElement("div",{id:"plyr-settings-"+e.id+"-home","aria-hidden":!1,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tabpanel"}),f=n.createElement("ul",{role:"tablist"});this.config.settings.forEach(function(i){var s=n.createElement("li",{role:"tab",hidden:""}),a=n.createElement("button",n.extend(n.getAttributesFromSelector(t.config.selectors.buttons.settings),{type:"button",class:t.config.classNames.control+" "+t.config.classNames.control+"--forward",id:"plyr-settings-"+e.id+"-"+i+"-tab","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-"+i,"aria-expanded":!1}),t.config.i18n[i]),l=n.createElement("span",{class:t.config.classNames.menu.value});l.innerHTML=e[i],a.appendChild(l),s.appendChild(a),f.appendChild(s),t.elements.settings.tabs[i]=s}),g.appendChild(f),m.appendChild(g),this.config.settings.forEach(function(i){var s=n.createElement("div",{id:"plyr-settings-"+e.id+"-"+i,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-"+e.id+"-"+i+"-tab",role:"tabpanel",tabindex:-1,hidden:""}),a=n.createElement("button",{type:"button",class:t.config.classNames.control+" "+t.config.classNames.control+"--back","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-home","aria-expanded":!1},t.config.i18n[i]);s.appendChild(a);var l=n.createElement("ul");s.appendChild(l),m.appendChild(s),t.elements.settings.panes[i]=s}),p.appendChild(m),h.appendChild(p),i.appendChild(h),this.elements.settings.form=p,this.elements.settings.menu=h}return this.config.controls.includes("pip")&&s.pip&&i.appendChild(a.createButton.call(this,"pip")),this.config.controls.includes("airplay")&&s.airplay&&i.appendChild(a.createButton.call(this,"airplay")),this.config.controls.includes("fullscreen")&&i.appendChild(a.createButton.call(this,"fullscreen")),this.config.controls.includes("play-large")&&(this.elements.buttons.playLarge=a.createButton.call(this,"play-large"),this.elements.container.appendChild(this.elements.buttons.playLarge)),this.elements.controls=i,this.config.controls.includes("settings")&&this.config.settings.includes("speed")&&a.setSpeedMenu.call(this),i},inject:function(){var e=this;if(this.config.loadSprite){var t=a.getIconUrl.call(this);t.absolute?(this.log("AJAX loading absolute SVG sprite "+(this.browser.isIE?"(due to IE)":"")),n.loadSprite(t.url,"sprite-plyr")):this.log("Sprite will be used as external resource directly")}this.id=Math.floor(1e4*Math.random());var i=null;i=n.is.string(this.config.controls)?this.config.controls:n.is.function(this.config.controls)?this.config.controls({id:this.id,seektime:this.config.seekTime}):a.create.call(this,{id:this.id,seektime:this.config.seekTime,speed:"-",quality:"-",captions:a.getLanguage.call(this),loop:"None"});var s=void 0;if(n.is.string(this.config.selectors.controls.container)&&(s=document.querySelector(this.config.selectors.controls.container)),n.is.htmlElement(s)||(s=this.elements.container),n.is.htmlElement(i)?s.appendChild(i):s.insertAdjacentHTML("beforeend",i),n.is.htmlElement(this.elements.controls)&&n.findElements.call(this),this.config.tooltips.controls){var l=n.getElements.call(this,[this.config.selectors.controls.wrapper," ",this.config.selectors.labels," .",this.config.classNames.hidden].join(""));Array.from(l).forEach(function(t){n.toggleClass(t,e.config.classNames.hidden,!1),n.toggleClass(t,e.config.classNames.tooltip,!0)})}}},l={setup:function(){var e=this;if(this.supported.ui){if(n.is.empty(this.storage.language)?n.is.empty(this.captions.language)&&(this.captions.language=this.config.captions.language.toLowerCase()):this.captions.language=this.storage.language,n.is.boolean(this.captions.enabled)||(n.is.empty(this.storage.language)?this.captions.enabled=this.config.captions.active:this.captions.enabled=this.storage.captions),!["video","vimeo"].includes(this.type)||"video"===this.type&&!s.textTracks)return this.captions.tracks=null,void(this.config.controls.includes("settings")&&this.config.settings.includes("captions")&&a.setCaptionsMenu.call(this));if(n.is.htmlElement(this.elements.captions)||(this.elements.captions=n.createElement("div",n.getAttributesFromSelector(this.config.selectors.captions)),n.insertAfter(this.elements.captions,this.elements.wrapper)),"video"===this.type&&(this.captions.tracks=this.media.textTracks),n.toggleClass(this.elements.container,this.config.classNames.captions.enabled,!n.is.empty(this.captions.tracks)),!n.is.empty(this.captions.tracks)){l.show.call(this);var t=function(){e.captions.currentTrack=null,Array.from(e.captions.tracks).forEach(function(t){t.language===e.captions.language.toLowerCase()&&(e.captions.currentTrack=t)})};if(t(),!n.is.track(this.captions.currentTrack)){var i=this.config.captions.language;this.captions.language=i,t(),n.is.track(this.captions.currentTrack)||this.toggleCaptions(!1),a.updateSetting.call(this,"captions")}if("video"===this.type){Array.from(this.captions.tracks).forEach(function(t){n.off(t,"cuechange",function(t){return l.setCue.call(e,t)}),t.mode="hidden"});var o=this.captions.currentTrack&&["captions","subtitles"].includes(this.captions.currentTrack.kind);n.is.track(this.captions.currentTrack)&&o&&(n.on(this.captions.currentTrack,"cuechange",function(t){return l.setCue.call(e,t)}),this.captions.currentTrack.activeCues&&this.captions.currentTrack.activeCues.length>0&&a.setCue.call(this,this.captions.currentTrack))}else"vimeo"===this.type&&this.captions.active&&this.embed.enableTextTrack(this.captions.language);this.config.controls.includes("settings")&&this.config.settings.includes("captions")&&a.setCaptionsMenu.call(this)}}},setCue:function(e){var t=(n.is.event(e)?e.target:e).activeCues[0];n.is.cue(t)?l.set.call(this,t.getCueAsHTML()):l.set.call(this),n.dispatchEvent.call(this,this.media,"cuechange")},set:function(e){if(this.supported.ui)if(n.is.htmlElement(this.elements.captions)){var t=n.createElement("span");n.emptyElement(this.elements.captions);var i=n.is.undefined(e)?"":e;n.is.string(i)?t.textContent=i.trim():t.appendChild(i),this.elements.captions.appendChild(t)}else this.warn("No captions element to render to")},show:function(){if(this.elements.buttons.captions){var e=this.storage.captions;n.is.boolean(e)?this.captions.active=e:e=this.captions.active,e&&(n.toggleClass(this.elements.container,this.config.classNames.captions.active,!0),n.toggleState(this.elements.buttons.captions,!0))}}},o=function(){var e=!1;return n.is.function(document.cancelFullScreen)?e="":["webkit","o","moz","ms","khtml"].some(function(t){return n.is.function(document[t+"CancelFullScreen"])?(e=t,!0):!(!n.is.function(document.msExitFullscreen)||!document.msFullscreenEnabled)&&(e="ms",!0)}),e}(),r={prefix:o,enabled:document.fullscreenEnabled||document.webkitFullscreenEnabled||document.mozFullScreenEnabled||document.msFullscreenEnabled,eventType:"ms"===o?"MSFullscreenChange":o+"fullscreenchange",isFullScreen:function(e){if(!r.enabled)return!1;var t=n.is.undefined(e)?document.body:e;switch(o){case"":return document.fullscreenElement===t;case"moz":return document.mozFullScreenElement===t;default:return document[o+"FullscreenElement"]===t}},requestFullScreen:function(e){if(!r.enabled)return!1;var t=n.is.undefined(e)?document.body:e;return o.length?t[o+("ms"===o?"RequestFullscreen":"RequestFullScreen")]():t.requestFullScreen()},cancelFullScreen:function(){return!!r.enabled&&(o.length?document[o+("ms"===o?"ExitFullscreen":"CancelFullScreen")]():document.cancelFullScreen())},element:function(){return r.enabled?o.length?document[o+"FullscreenElement"]:document.fullscreenElement:null},setup:function(){if(this.supported.ui&&"audio"!==this.type&&this.config.fullscreen.enabled){var e=r.enabled;e||this.config.fullscreen.fallback&&!n.inFrame()?(this.log((e?"Native":"Fallback")+" fullscreen enabled"),n.toggleClass(this.elements.container,this.config.classNames.fullscreen.enabled,!0)):this.log("Fullscreen not supported and fallback disabled"),this.elements.buttons&&this.elements.buttons.fullscreen&&n.toggleState(this.elements.buttons.fullscreen,!1),n.trapFocus.call(this)}}},c={setup:function(){var t=null,i={};return s.storage&&this.config.storage.enabled?(window.localStorage.removeItem("plyr-volume"),(t=window.localStorage.getItem(this.config.storage.key))&&(/^\d+(\.\d+)?$/.test(t)?e({volume:parseFloat(t)}):i=JSON.parse(t)),i):i},set:e},u={media:function(){var e=this;if(n.on(this.media,"timeupdate seeking",function(t){return d.timeUpdate.call(e,t)}),n.on(this.media,"durationchange loadedmetadata",function(t){return d.displayDuration.call(e,t)}),n.on(this.media,"ended",function(){"video"===e.type&&e.config.showPosterOnEnd&&(e.restart(),e.media.load())}),n.on(this.media,"progress playing",function(t){return d.updateProgress.call(e,t)}),n.on(this.media,"volumechange",function(t){return d.updateVolume.call(e,t)}),n.on(this.media,"play pause ended",function(t){return d.checkPlaying.call(e,t)}),n.on(this.media,"waiting canplay seeked",function(t){return d.checkLoading.call(e,t)}),this.supported.ui&&this.config.clickToPlay&&"audio"!==this.type){var t=n.getElement.call(this,"."+this.config.classNames.video);if(!t)return;t.style.cursor="pointer",n.on(t,"click",function(){e.config.hideControls&&s.touch&&!e.media.paused||(e.media.paused?e.play():e.media.ended?(e.restart(),e.play()):e.pause())})}this.config.disableContextMenu&&n.on(this.media,"contextmenu",function(e){e.preventDefault()},!1),n.on(this.media,"ratechange",function(){a.updateSetting.call(e,"speed"),c.set.call(e,{speed:e.speed})}),n.on(this.media,"qualitychange",function(){a.updateSetting.call(e,"quality"),c.set.call(e,{quality:e.quality})}),n.on(this.media,"captionchange",function(){c.set.call(e,{language:e.captions.language})}),n.on(this.media,"captionsenabled captionsdisabled",function(){a.updateSetting.call(e,"captions"),c.set.call(e,{captions:e.captions.enabled})}),n.on(this.media,this.config.events.concat(["keyup","keydown"]).join(" "),function(t){n.dispatchEvent.call(e,e.elements.container,t.type,!0)})},controls:function(){function e(e){return e.keyCode?e.keyCode:e.which}function t(t){var i=e(t),s="keydown"===t.type,a=s&&i===l;if(n.is.number(i))if(s){var c=[48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67,73,76,79];if([38,40].includes(i)){var u=n.getFocusElement();if(n.is.htmlElement(u)&&"radio"===n.getFocusElement().type)return}switch(c.includes(i)&&(t.preventDefault(),t.stopPropagation()),i){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:a||function(){this.currentTime=this.duration/10*(i-48)}();break;case 32:case 75:a||o();break;case 38:this.increaseVolume(.1);break;case 40:this.decreaseVolume(.1);break;case 77:a||this.toggleMute();break;case 39:this.forward();break;case 37:this.rewind();break;case 70:this.toggleFullscreen();break;case 67:a||this.toggleCaptions();break;case 73:this.setLoop("start");break;case 76:this.setLoop();break;case 79:this.setLoop("end")}!r.enabled&&this.fullscreen.active&&27===i&&this.toggleFullscreen(),l=i}else l=null}var i=this,s=this.browser.isIE?"change":"input",l=null,o=function(){var e=i.togglePlay(),t=i.elements.buttons[e?"pause":"play"];n.is.htmlElement(t)&&t.focus()};this.config.keyboard.focused&&(this.config.keyboard.global&&n.on(window,"keydown keyup",function(s){var a=e(s),l=n.getFocusElement();![48,49,50,51,52,53,54,56,57,75,77,70,67,73,76,79].includes(a)||n.is.htmlElement(l)&&n.matches(l,i.config.selectors.editable)||t(s)},!1),n.on(this.elements.container,"keydown keyup",t,!1)),n.on(this.elements.container,"focusout",function(e){n.toggleClass(e.target,i.config.classNames.tabFocus,!1)}),n.on(this.elements.container,"keydown",function(e){9===e.keyCode&&window.setTimeout(function(){n.toggleClass(n.getFocusElement(),i.config.classNames.tabFocus,!0)},0)});var c=function(e,t,s){n.is.function(t)&&t.call(i,e),n.is.function(s)&&s.call(i,e)};n.proxy(this.elements.buttons.play,"click",this.config.listeners.play,o),n.proxy(this.elements.buttons.playLarge,"click",this.config.listeners.play,o),n.proxy(this.elements.buttons.pause,"click",this.config.listeners.pause,o),n.proxy(this.elements.buttons.restart,"click",this.config.listeners.restart,function(){i.restart()}),n.proxy(this.elements.buttons.rewind,"click",this.config.listeners.rewind,function(){i.rewind()}),n.proxy(this.elements.buttons.forward,"click",this.config.listeners.forward,function(){i.forward()}),n.proxy(this.elements.buttons.mute,"click",this.config.listeners.mute,function(){i.toggleMute()}),n.proxy(this.elements.buttons.captions,"click",this.config.listeners.captions,function(){i.toggleCaptions()}),n.proxy(this.elements.buttons.fullscreen,"click",this.config.listeners.fullscreen,function(){i.toggleFullscreen()}),n.proxy(this.elements.buttons.pip,"click",this.config.listeners.pip,function(){i.togglePictureInPicture()}),n.proxy(this.elements.buttons.airplay,"click",this.config.listeners.airplay,function(){i.airPlay()}),n.on(this.elements.buttons.settings,"click",function(e){a.toggleMenu.call(i,e)}),n.on(document.documentElement,"click",function(e){a.toggleMenu.call(i,e)}),n.on(this.elements.settings.form,"click",function(e){a.showTab.call(i,e),n.matches(e.target,i.config.selectors.inputs.language)?c.call(i,e,i.config.listeners.language,function(){i.toggleCaptions(!0),i.language=e.target.value.toLowerCase()}):n.matches(e.target,i.config.selectors.inputs.quality)?c.call(i,e,i.config.listeners.quality,function(){i.quality=e.target.value}):n.matches(e.target,i.config.selectors.inputs.speed)?c.call(i,e,i.config.listeners.speed,function(){i.speed=parseFloat(e.target.value)}):n.matches(e.target,i.config.selectors.buttons.loop)&&c.call(i,e,i.config.listeners.loop,function(){i.warn("Set loop")})}),n.proxy(this.elements.inputs.seek,s,this.config.listeners.seek,function(e){i.currentTime=e.target.value/e.target.max*i.duration}),n.proxy(this.elements.inputs.volume,s,this.config.listeners.volume,function(e){i.setVolume(e.target.value)}),this.browser.isWebkit&&n.on(n.getElements.call(this,'input[type="range"]'),"input",function(e){a.updateRangeFill.call(i,e.target)}),n.on(this.elements.progress,"mouseenter mouseleave mousemove",function(e){return d.updateSeekTooltip.call(i,e)}),this.config.hideControls&&(n.on(this.elements.container,"mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen",function(e){i.toggleControls(e)}),n.on(this.elements.controls,"mouseenter mouseleave",function(e){i.elements.controls.hover="mouseenter"===e.type}),n.on(this.elements.controls,"mousedown mouseup touchstart touchend touchcancel",function(e){i.elements.controls.pressed=["mousedown","touchstart"].includes(e.type)}),n.on(this.elements.controls,"focus blur",function(e){i.toggleControls(e)},!0)),n.proxy(this.elements.inputs.volume,"wheel",this.config.listeners.volume,function(e){var t=e.webkitDirectionInvertedFromDevice,n=0;(e.deltaY<0||e.deltaX>0)&&(t?(i.decreaseVolume(.02),n=-1):(i.increaseVolume(.02),n=1)),(e.deltaY>0||e.deltaX<0)&&(t?(i.increaseVolume(.02),n=1):(i.decreaseVolume(.02),n=-1)),(1===n&&i.media.volume<1||-1===n&&i.media.volume>0)&&e.preventDefault()},!1),r.enabled&&n.on(document,r.eventType,function(e){i.toggleFullscreen(e)})}},d={addStyleHook:function(){n.toggleClass(this.elements.container,this.config.selectors.container.replace(".",""),!0),n.toggleClass(this.elements.container,this.config.classNames.uiSupported,this.supported.ui)},toggleNativeControls:function(e){e&&this.isHTML5?this.media.setAttribute("controls",""):this.media.removeAttribute("controls")},build:function(){if(u.media.call(this),!this.supported.ui)return this.warn("Basic support only for "+this.type),n.removeElement.call(this,"controls"),n.removeElement.call(this,"buttons.play"),void d.toggleNativeControls.call(this,!0);n.is.htmlElement(this.elements.controls)||(a.inject.call(this),u.controls.call(this)),n.is.htmlElement(this.elements.controls)&&(d.toggleNativeControls.call(this),r.setup.call(this),l.setup.call(this),this.volume=null,d.updateVolume.call(this),this.speed=null,d.timeUpdate.call(this),d.checkPlaying.call(this),this.ready=!0,n.dispatchEvent.call(this,this.media,"ready"),this.config.autoplay&&this.play())},displayDuration:function(){this.supported.ui&&(!this.elements.display.duration&&this.config.displayDuration&&this.media.paused&&d.updateTimeDisplay.call(this,this.duration,this.elements.display.currentTime),this.elements.display.duration&&d.updateTimeDisplay.call(this,this.duration,this.elements.display.duration),d.updateSeekTooltip.call(this))},setTitle:function(){var e=this.config.i18n.play;if(n.is.string(this.config.title)&&!n.is.empty(this.config.title)&&(e+=", "+this.config.title,this.elements.container.setAttribute("aria-label",this.config.title)),this.supported.ui&&(n.is.htmlElement(this.elements.buttons.play)&&this.elements.buttons.play.setAttribute("aria-label",e),n.is.htmlElement(this.elements.buttons.playLarge)&&this.elements.buttons.playLarge.setAttribute("aria-label",e)),this.isEmbed){var t=n.getElement.call(this,"iframe");if(!n.is.htmlElement(t))return;var i=n.is.empty(this.config.title)?"video":this.config.title;t.setAttribute("title",this.config.i18n.frameTitle.replace("{title}",i))}},checkPlaying:function(){n.toggleClass(this.elements.container,this.config.classNames.playing,!this.media.paused),n.toggleClass(this.elements.container,this.config.classNames.stopped,this.media.paused),this.toggleControls(this.media.paused)},updateVolume:function(){if(this.supported.ui){var e=this.media.muted?0:this.media.volume;this.elements.inputs.volume&&d.setRange.call(this,this.elements.inputs.volume,e)}c.set.call(this,{volume:this.media.volume}),n.toggleClass(this.elements.container,this.config.classNames.muted,this.media.muted),this.supported.ui&&this.elements.buttons.mute&&n.toggleState(this.elements.buttons.mute,this.media.muted)},checkLoading:function(e){var t=this;this.loading="waiting"===e.type,clearTimeout(this.timers.loading),this.timers.loading=setTimeout(function(){n.toggleClass(t.elements.container,t.config.classNames.loading,t.loading),t.toggleControls(t.loading)},this.loading?250:0)},setRange:function(e,t){n.is.htmlElement(e)&&(e.value=t,a.updateRangeFill.call(this,e))},setProgress:function(e,t){var i=n.is.undefined(t)?0:t,s=n.is.undefined(e)?this.elements.display.buffer:e;if(n.is.htmlElement(s)){s.value=i;var a=s.getElementsByTagName("span")[0];n.is.htmlElement(a)&&(a.childNodes[0].nodeValue=i)}},updateProgress:function(e){var t=this;if(this.supported.ui){var i=0;if(e)switch(e.type){case"timeupdate":case"seeking":i=n.getPercentage(this.currentTime,this.duration),"timeupdate"===e.type&&d.setRange.call(this,this.elements.inputs.seek,i);break;case"playing":case"progress":i=function(){var e=t.media.buffered;return e&&e.length?n.getPercentage(e.end(0),t.duration):n.is.number(e)?100*e:0}(),d.setProgress.call(this,this.elements.display.buffer,i)}}},updateTimeDisplay:function(e,t){if(!n.is.htmlElement(t))return null;var i=Number.isNaN(e)?0:e,s=parseInt(i%60,10),a=parseInt(i/60%60,10),l=parseInt(i/60/60%60,10),o=parseInt(this.duration/60/60%60,10)>0;s=("0"+s).slice(-2),a=("0"+a).slice(-2);var r=(o?l+":":"")+a+":"+s;return t.textContent=r,r},timeUpdate:function(e){d.updateTimeDisplay.call(this,this.currentTime,this.elements.display.currentTime),e&&"timeupdate"===e.type&&this.media.seeking||d.updateProgress.call(this,e)},updateSeekTooltip:function(e){if(this.config.tooltips.seek&&n.is.htmlElement(this.elements.inputs.seek)&&n.is.htmlElement(this.elements.display.seekTooltip)&&0!==this.duration){var t=this.elements.inputs.seek.getBoundingClientRect(),i=0,s=this.config.classNames.tooltip+"--visible";if(n.is.event(e))i=100/t.width*(e.pageX-t.left);else{if(!n.hasClass(this.elements.display.seekTooltip,s))return;i=this.elements.display.seekTooltip.style.left.replace("%","")}i<0?i=0:i>100&&(i=100),d.updateTimeDisplay.call(this,this.duration/100*i,this.elements.display.seekTooltip),this.elements.display.seekTooltip.style.left=i+"%",n.is.event(e)&&["mouseenter","mouseleave"].includes(e.type)&&n.toggleClass(this.elements.display.seekTooltip,s,"mouseenter"===e.type)}}},h={setup:function(){var e=this,t=n.parseYouTubeId(this.embedId),i=n.getElements.call(this,'[id^="'+this.type+'-"]');Array.from(i).forEach(n.removeElement),n.toggleClass(this.elements.wrapper,this.config.classNames.embed,!0),this.media.setAttribute("id",n.generateId(this.type)),n.is.object(window.YT)?h.ready.call(this,t):(n.loadScript(this.config.urls.youtube.api),window.onYouTubeReadyCallbacks=window.onYouTubeReadyCallbacks||[],window.onYouTubeReadyCallbacks.push(function(){h.ready.call(e,t)}),window.onYouTubeIframeAPIReady=function(){window.onYouTubeReadyCallbacks.forEach(function(e){e()})})},ready:function(e){var t=this;t.embed=new window.YT.Player(t.media.id,{videoId:e,playerVars:{autoplay:t.config.autoplay?1:0,controls:t.supported.ui?0:1,rel:0,showinfo:0,iv_load_policy:3,modestbranding:1,disablekb:1,playsinline:1,origin:window&&window.location.hostname,widget_referrer:window&&window.location.href},events:{onError:function(e){n.dispatchEvent.call(t,t.media,"error",!0,{code:e.data,embed:e.target})},onPlaybackQualityChange:function(e){var i=e.target;t.media.quality=i.getPlaybackQuality(),n.dispatchEvent.call(t,t.media,"qualitychange")},onPlaybackRateChange:function(e){var i=e.target;t.media.playbackRate=i.getPlaybackRate(),n.dispatchEvent.call(t,t.media,"ratechange")},onReady:function(e){var i=e.target;t.media.play=function(){i.playVideo(),t.media.paused=!1},t.media.pause=function(){i.pauseVideo(),t.media.paused=!0},t.media.stop=function(){i.stopVideo(),t.media.paused=!0},t.media.duration=i.getDuration(),t.media.paused=!0,t.media.muted=i.isMuted(),t.media.currentTime=0,t.config.controls.includes("settings")&&t.config.settings.includes("speed")&&a.setSpeedMenu.call(t,i.getAvailablePlaybackRates()),t.config.title=i.getVideoData().title,t.supported.ui&&t.media.setAttribute("tabindex",-1),d.build.call(t),n.dispatchEvent.call(t,t.media,"timeupdate"),n.dispatchEvent.call(t,t.media,"durationchange"),window.clearInterval(t.timers.buffering),t.timers.buffering=window.setInterval(function(){t.media.buffered=i.getVideoLoadedFraction(),(null===t.media.lastBuffered||t.media.lastBuffered<t.media.buffered)&&n.dispatchEvent.call(t,t.media,"progress"),t.media.lastBuffered=t.media.buffered,1===t.media.buffered&&(window.clearInterval(t.timers.buffering),n.dispatchEvent.call(t,t.media,"canplaythrough"))},200)},onStateChange:function(e){var i=e.target;switch(window.clearInterval(t.timers.playing),e.data){case 0:if(t.config.loop.active){i.stopVideo(),i.playVideo();break}t.media.paused=!0,n.dispatchEvent.call(t,t.media,"ended");break;case 1:t.media.paused=!1,t.media.seeking&&n.dispatchEvent.call(t,t.media,"seeked"),t.media.seeking=!1,n.dispatchEvent.call(t,t.media,"play"),n.dispatchEvent.call(t,t.media,"playing"),t.timers.playing=window.setInterval(function(){t.media.currentTime=i.getCurrentTime(),n.dispatchEvent.call(t,t.media,"timeupdate")},100),t.media.duration!==i.getDuration()&&(t.media.duration=i.getDuration(),n.dispatchEvent.call(t,t.media,"durationchange")),a.setQualityMenu.call(t,i.getAvailableQualityLevels());break;case 2:t.media.paused=!0,n.dispatchEvent.call(t,t.media,"pause")}n.dispatchEvent.call(t,t.elements.container,"statechange",!1,{code:e.data})}}})}},p={setup:function(){var e=this,t=n.getElements.call(this,'[id^="'+this.type+'-"]');if(Array.from(t).forEach(n.removeElement),n.toggleClass(this.elements.wrapper,this.config.classNames.embed,!0),this.media.setAttribute("id",n.generateId(this.type)),n.is.object(window.Vimeo))p.ready.call(this);else{n.loadScript(this.config.urls.vimeo.api);var i=window.setInterval(function(){n.is.object(window.Vimeo)&&(window.clearInterval(i),p.ready.call(e))},50)}},ready:function(){var e=this,t=this,i={loop:this.config.loop.active,autoplay:this.config.autoplay,byline:!1,portrait:!1,title:!1,transparent:0},s=n.buildUrlParameters(i),a=n.parseVimeoId(this.embedId),o=n.createElement("iframe"),r="https://player.vimeo.com/video/"+a+"?"+s;o.setAttribute("src",r),o.setAttribute("allowfullscreen",""),t.media.appendChild(o),t.embed=new window.Vimeo.Player(o),t.media.play=function(){t.embed.play(),t.media.paused=!1},t.media.pause=function(){t.embed.pause(),t.media.paused=!0},t.media.stop=function(){t.embed.stop(),t.media.paused=!0},t.media.paused=!0,t.media.currentTime=0,d.build.call(t),t.embed.getCurrentTime().then(function(i){t.media.currentTime=i,n.dispatchEvent.call(e,e.media,"timeupdate")}),t.embed.getDuration().then(function(e){t.media.duration=e,n.dispatchEvent.call(t,t.media,"durationchange")}),t.embed.getTextTracks().then(function(e){t.captions.tracks=e,l.setup.call(t)}),t.embed.on("cuechange",function(e){var i=null;e.cues.length&&(i=n.stripHTML(e.cues[0].text)),l.set.call(t,i)}),t.embed.on("loaded",function(){n.is.htmlElement(t.embed.element)&&t.supported.ui&&t.embed.element.setAttribute("tabindex",-1)}),t.embed.on("play",function(){t.media.paused=!1,n.dispatchEvent.call(t,t.media,"play"),n.dispatchEvent.call(t,t.media,"playing")}),t.embed.on("pause",function(){t.media.paused=!0,n.dispatchEvent.call(t,t.media,"pause")}),this.embed.on("timeupdate",function(t){e.media.seeking=!1,e.media.currentTime=t.seconds,n.dispatchEvent.call(e,e.media,"timeupdate")}),this.embed.on("progress",function(t){e.media.buffered=t.percent,n.dispatchEvent.call(e,e.media,"progress"),1===parseInt(t.percent,10)&&n.dispatchEvent.call(e,e.media,"canplaythrough")}),this.embed.on("seeked",function(){e.media.seeking=!1,n.dispatchEvent.call(e,e.media,"seeked"),n.dispatchEvent.call(e,e.media,"play")}),this.embed.on("ended",function(){e.media.paused=!0,n.dispatchEvent.call(e,e.media,"ended")})}},m={setup:function(){if(this.media){if(n.toggleClass(this.elements.container,this.config.classNames.type.replace("{0}",this.type),!0),this.isEmbed&&n.toggleClass(this.elements.container,this.config.classNames.type.replace("{0}","video"),!0),this.supported.ui&&(n.toggleClass(this.elements.container,this.config.classNames.pip.supported,s.pip&&"video"===this.type),n.toggleClass(this.elements.container,this.config.classNames.airplay.supported,s.airplay&&this.isHTML5),n.toggleClass(this.elements.container,this.config.classNames.stopped,this.config.autoplay),n.toggleClass(this.elements.container,this.config.classNames.isIos,this.browser.isIos),n.toggleClass(this.elements.container,this.config.classNames.isTouch,s.touch)),["video","youtube","vimeo"].includes(this.type)&&(this.elements.wrapper=n.createElement("div",{class:this.config.classNames.video}),n.wrap(this.media,this.elements.wrapper)),this.isEmbed)switch(this.type){case"youtube":h.setup.call(this);break;case"vimeo":p.setup.call(this)}d.setTitle.call(this)}else this.warn("No media element found!")},cancelRequests:function(){this.isHTML5&&(Array.from(this.media.querySelectorAll("source")).forEach(n.removeElement),this.media.setAttribute("src",this.config.blankVideo),this.media.load(),this.log("Cancelled network requests"))}},g={insertElements:function(e,t){var i=this;n.is.string(t)?n.insertElement(e,this.media,{src:t}):n.is.array(t)&&(this.warn(t),t.forEach(function(t){n.insertElement(e,i.media,t)}))},change:function(e){var t=this;n.is.object(e)&&"sources"in e&&e.sources.length?(m.cancelRequests.call(this),this.destroy.call(this,function(){if(n.removeElement(t.media),t.media=null,n.is.htmlElement(t.elements.container)&&t.elements.container.removeAttribute("class"),"type"in e&&(t.type=e.type,"video"===t.type)){var a=e.sources[0];"type"in a&&i.embed.includes(a.type)&&(t.type=a.type)}switch(t.supported=s.check(t.type,t.config.inline),t.type){case"video":t.media=n.createElement("video");break;case"audio":t.media=n.createElement("audio");break;case"youtube":case"vimeo":t.media=n.createElement("div"),t.embedId=e.sources[0].src}t.elements.container.appendChild(t.media),n.is.boolean(e.autoplay)&&(t.config.autoplay=e.autoplay),t.isHTML5&&(t.config.crossorigin&&t.media.setAttribute("crossorigin",""),t.config.autoplay&&t.media.setAttribute("autoplay",""),"poster"in e&&t.media.setAttribute("poster",e.poster),t.config.loop.active&&t.media.setAttribute("loop",""),t.config.muted&&t.media.setAttribute("muted",""),t.config.inline&&t.media.setAttribute("playsinline","")),n.toggleClass(t.elements.container,t.config.classNames.captions.active,t.supported.ui&&t.captions.enabled),d.addStyleHook.call(t),t.isHTML5&&g.insertElements.call(t,"source",e.sources),t.config.title=e.title,m.setup.call(t),t.isHTML5&&("tracks"in e&&g.insertElements.call(t,"track",e.tracks),t.media.load()),(t.isHTML5||t.isEmbed&&!t.supported.ui)&&d.build.call(t)},!0)):this.warn("Invalid source format")}},f=(function(){function e(e){this.value=e}function t(t){function i(s,a){try{var l=t[s](a),o=l.value;o instanceof e?Promise.resolve(o.value).then(function(e){i("next",e)},function(e){i("throw",e)}):n(l.done?"return":"normal",l.value)}catch(e){n("throw",e)}}function n(e,t){switch(e){case"return":s.resolve({value:t,done:!0});break;case"throw":s.reject(t);break;default:s.resolve({value:t,done:!1})}(s=s.next)?i(s.key,s.arg):a=null}var s,a;this._invoke=function(e,t){return new Promise(function(n,l){var o={key:e,arg:t,resolve:n,reject:l,next:null};a?a=a.next=o:(s=a=o,i(e,t))})},"function"!=typeof t.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(t.prototype[Symbol.asyncIterator]=function(){return this}),t.prototype.next=function(e){return this._invoke("next",e)},t.prototype.throw=function(e){return this._invoke("throw",e)},t.prototype.return=function(e){return this._invoke("return",e)}}(),function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}),y=function(){function e(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,i,n){return i&&e(t.prototype,i),n&&e(t,n),t}}(),b={x:0,y:0};return function(){function e(i,a){var l=this;if(f(this,e),this.timers={},this.ready=!1,this.media=i,n.is.string(this.media)&&(this.media=document.querySelectorAll(this.media)),(window.jQuery&&this.media instanceof jQuery||n.is.nodeList(this.media)||n.is.array(this.media))&&(this.media=this.media[0]),this.config=n.extend({},t,a,function(){try{return JSON.parse(l.media.getAttribute("data-plyr"))}catch(e){return null}}()),this.elements={container:null,buttons:{},display:{},progress:{},inputs:{},settings:{menu:null,panes:{},tabs:{}},captions:null},this.captions={enabled:null,tracks:null,currentTrack:null},this.fullscreen={active:!1},this.options={speed:[],quality:[]},this.log=function(){},this.warn=function(){},this.error=function(){},this.config.debug&&"console"in window&&(this.log=console.log,this.warn=console.warn,this.error=console.error,this.log("Debugging enabled")),this.log("Config",this.config),this.log("Support",s),null!==this.media&&!n.is.undefined(this.media)&&n.is.htmlElement(this.media))if(this.media.plyr)this.warn("Target already setup");else if(this.config.enabled)if(s.check().api){this.elements.original=this.media.cloneNode(!0);var o=this.media.tagName.toLowerCase();switch(o){case"div":if(this.type=this.media.getAttribute("data-type"),this.embedId=this.media.getAttribute("data-video-id"),n.is.empty(this.type))return void this.error("Setup failed: embed type missing");if(n.is.empty(this.embedId))return void this.error("Setup failed: video id missing");this.media.removeAttribute("data-type"),this.media.removeAttribute("data-video-id");break;case"video":case"audio":this.type=o,null!==this.media.getAttribute("crossorigin")&&(this.config.crossorigin=!0),null!==this.media.getAttribute("autoplay")&&(this.config.autoplay=!0),null!==this.media.getAttribute("playsinline")&&(this.config.inline=!0),null!==this.media.getAttribute("muted")&&(this.config.muted=!0),null!==this.media.getAttribute("loop")&&(this.config.loop.active=!0);break;default:return void this.error("Setup failed: unsupported type")}this.browser=n.getBrowser(),this.storage=c.setup.call(this),this.supported=s.check(this.type,this.config.inline),this.supported.api?(this.media.plyr=this,this.elements.container=n.createElement("div"),n.wrap(this.media,this.elements.container),d.addStyleHook.call(this),m.setup.call(this),this.config.debug&&n.on(this.elements.container,this.config.events.join(" "),function(e){l.log("event: "+e.type)}),(this.isHTML5||this.isEmbed&&!this.supported.ui)&&d.build.call(this)):this.error("Setup failed: no support")}else this.error("Setup failed: no support");else this.error("Setup failed: disabled by config");else this.error("Setup failed: no suitable element passed")}return y(e,[{key:"play",value:function(){return"play"in this.media&&this.media.play(),this}},{key:"pause",value:function(){return"pause"in this.media&&this.media.pause(),this}},{key:"togglePlay",value:function(e){return!n.is.boolean(e)&&this.media.paused||e?this.play():this.pause()}},{key:"stop",value:function(){return this.restart().pause()}},{key:"restart",value:function(){return this.currentTime=0,this}},{key:"rewind",value:function(e){return this.currentTime=Math.min(this.currentTime-(n.is.number(e)?e:this.config.seekTime),0),this}},{key:"forward",value:function(e){return this.currentTime=Math.max(this.currentTime+(n.is.number(e)?e:this.config.seekTime),this.duration),this}},{key:"increaseVolume",value:function(e){var t=this.media.muted?0:this.media.volume;return this.setVolume(t+n.is.number(e)?e:1)}},{key:"decreaseVolume",value:function(e){var t=this.media.muted?0:this.media.volume;return this.setVolume(t-n.is.number(e)?e:1)}},{key:"toggleMute",value:function(e){var t=n.is.boolean(e)?e:!this.media.muted;if(n.toggleState(this.elements.buttons.mute,t),this.media.muted=t,this.media.muted||0!==this.media.volume||this.setVolume(this.config.volume),this.isEmbed){switch(this.type){case"youtube":this.embed[this.media.muted?"mute":"unMute"]();break;case"vimeo":this.embed.setVolume(this.media.muted?0:this.config.volume)}n.dispatchEvent.call(this,this.media,"volumechange")}return this}},{key:"loop",value:function(e){switch(["start","end","all","none","toggle"].includes(e)?e:"toggle"){case"start":this.config.loop.end&&this.config.loop.end<=this.currentTime&&(this.config.loop.end=null),this.config.loop.start=this.currentTime;break;case"end":if(this.config.loop.start>=this.currentTime)return this;this.config.loop.end=this.currentTime;break;case"all":this.config.loop.start=0,this.config.loop.end=this.duration-2,this.config.loop.indicator.start=0,this.config.loop.indicator.end=100;break;case"toggle":this.config.loop.active?(this.config.loop.start=0,this.config.loop.end=null):(this.config.loop.start=0,this.config.loop.end=this.duration-2);break;default:this.config.loop.start=0,this.config.loop.end=null}return this}},{key:"toggleCaptions",value:function(e){if(!this.supported.ui||!this.elements.buttons.captions)return this;var t=n.is.boolean(e)?e:-1===this.elements.container.className.indexOf(this.config.classNames.captions.active);return this.captions.enabled===t?this:(this.captions.enabled=t,n.toggleState(this.elements.buttons.captions,this.captions.enabled),n.toggleClass(this.elements.container,this.config.classNames.captions.active,this.captions.enabled),n.dispatchEvent.call(this,this.media,this.captions.enabled?"captionsenabled":"captionsdisabled"),this)}},{key:"toggleFullscreen",value:function(e){if(r.enabled){if(!n.is.event(e)||e.type!==r.eventType)return this.fullscreen.active?r.cancelFullScreen():r.requestFullScreen(this.elements.container),this.fullscreen.active=r.isFullScreen(this.elements.container),this;this.fullscreen.active=r.isFullScreen(this.elements.container)}else this.fullscreen.active=!this.fullscreen.active,n.toggleClass(this.elements.container,this.config.classNames.fullscreen.fallback,this.fullscreen.active),this.fullscreen.active?b={x:window.pageXOffset||0,y:window.pageYOffset||0}:window.scrollTo(b.x,b.y),document.body.style.overflow=this.fullscreen.active?"hidden":"";return this.elements.buttons&&this.elements.buttons.fullscreen&&n.toggleState(this.elements.buttons.fullscreen,this.fullscreen.active),n.dispatchEvent.call(this,this.media,this.fullscreen.active?"enterfullscreen":"exitfullscreen"),this}},{key:"togglePictureInPicture",value:function(e){var t=this,i={pip:"picture-in-picture",inline:"inline"};if(!s.pip)return t;var a=n.is.boolean(e)?e:this.media.webkitPresentationMode===i.inline;return this.media.webkitSetPresentationMode(a?i.pip:i.inline),this}},{key:"airPlay",value:function(){return s.airplay?(this.media.webkitShowPlaybackTargetPicker(),this):this}},{key:"toggleControls",value:function(e){var t=this,i=this;if(!n.is.htmlElement(this.elements.controls))return i;if(!this.supported.ui||!this.config.hideControls||"audio"===this.type)return i;var l=0,o=e,r=!1,c=n.hasClass(this.elements.container,this.config.classNames.loading);if(n.is.boolean(e)||(n.is.event(e)?(r="enterfullscreen"===e.type,o=["mousemove","touchstart","mouseenter","focus"].includes(e.type),["mousemove","touchmove"].includes(e.type)&&(l=2e3),"focus"===e.type&&(l=3e3)):o=n.hasClass(this.elements.container,this.config.classNames.hideControls)),window.clearTimeout(this.timers.hover),o||this.media.paused||c){if(n.toggleClass(this.elements.container,this.config.classNames.hideControls,!1)&&n.dispatchEvent.call(this,this.media,"controlsshown"),this.media.paused||c)return i;s.touch&&(l=3e3)}return o&&this.media.paused||(this.timers.hover=window.setTimeout(function(){(!t.elements.controls.pressed&&!t.elements.controls.hover||r)&&n.toggleClass(t.elements.container,t.config.classNames.hideControls,!0)&&(n.dispatchEvent.call(t,t.media,"controlshidden"),t.config.controls.includes("settings")&&!n.is.empty(t.config.settings)&&a.toggleMenu.call(t,!1))},l)),this}},{key:"on",value:function(e,t){return n.on(this.elements.container,e,t),this}},{key:"off",value:function(e,t){return n.off(this.elements.container,e,t),this}},{key:"supports",value:function(e){return s.mime(this,e)}},{key:"destroy",value:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]&&arguments[1],s=function(){if(document.body.style.overflow="",t.embed=null,i)n.removeElement(t.elements.captions),n.removeElement(t.elements.controls),n.removeElement(t.elements.wrapper),t.elements.captions=null,t.elements.controls=null,t.elements.wrapper=null,n.is.function(e)&&e();else{var s=t.elements.container.parentNode;n.is.htmlElement(s)&&s.replaceChild(t.elements.original,t.elements.container),n.dispatchEvent.call(t,t.elements.original,"destroyed",!0),n.is.function(e)&&e.call(t.elements.original),t.elements=null}};switch(this.type){case"youtube":window.clearInterval(this.timers.buffering),window.clearInterval(this.timers.playing),this.embed.destroy(),s();break;case"vimeo":this.embed.unload().then(s),window.setTimeout(s,200);break;case"video":case"audio":d.toggleNativeControls.call(this,!0),s()}}},{key:"isHTML5",get:function(){return i.html5.includes(this.type)}},{key:"isEmbed",get:function(){return i.embed.includes(this.type)}},{key:"currentTime",set:function(e){var t=0;if(n.is.number(e)&&(t=e),t<0?t=0:t>this.duration&&(t=this.duration),this.isEmbed){var i=this.media.paused;switch(this.type){case"youtube":this.embed.seekTo(t);break;case"vimeo":this.embed.setCurrentTime(t)}i&&this.pause(),this.media.seeking=!0,n.dispatchEvent.call(this,this.media,"seeking")}else this.media.currentTime=t.toFixed(4);this.log("Seeking to "+this.currentTime+" seconds")},get:function(){return Number(this.media.currentTime)}},{key:"duration",get:function(){var e=parseInt(this.config.duration,10),t=Number(this.media.duration);return Number.isNaN(e)?t:e}},{key:"volume",set:function(e){var t=e,i=!n.is.undefined(t);if(n.is.string(t)&&(t=parseFloat(t)),n.is.number(t)||(t=this.storage.volume),n.is.number(t)||(t=this.config.volume),t>1&&(t=1),t<0&&(t=0),this.media.volume=t,this.isEmbed){switch(this.type){case"youtube":this.embed.setVolume(100*this.media.volume);break;case"vimeo":this.embed.setVolume(this.media.volume)}n.dispatchEvent.call(this,this.media,"volumechange")}return 0===t?this.toggleMute(!0):this.media.muted&&i&&this.toggleMute(),this},get:function(){return this.media.volume}},{key:"speed",set:function(e){var t=n.is.number(e)?e:parseFloat(this.storage.speed||this.speed.selected||this.config.speed.default);if(t<.1&&(t=.1),t>2&&(t=2),this.config.speed.options.includes(t))switch(this.type){case"youtube":this.embed.setPlaybackRate(t);break;case"vimeo":t=null,this.warn("Vimeo playback rate change is not supported");break;default:this.media.playbackRate=t}else this.warn("Unsupported speed ("+t+")")},get:function(){switch(this.type){case"youtube":return this.embed.getPlaybackRate();case"vimeo":return this.warn("Vimeo playback rate change is not supported"),null;default:return this.media.playbackRate}}},{key:"quality",set:function(e){var t=n.is.string(e)?e:parseFloat(this.storage.quality||this.config.quality.selected);if(this.config.quality.options.includes(t))switch(this.type){case"youtube":this.utils.dispatchEvent.call(this,this.media,"qualityrequested",!1,{quality:t}),this.embed.setPlaybackQuality(t);break;default:this.warn("Quality options are only available for YouTube")}else this.warn("Unsupported quality option ("+t+")")},get:function(){switch(this.type){case"youtube":return this.embed.getPlaybackQuality();default:return this.warn("Quality options are only available for YouTube"),null}}},{key:"src",set:function(e){g.change.call(this,e)},get:function(){var e=void 0;switch(this.type){case"youtube":e=this.embed.getVideoUrl();break;case"vimeo":this.embed.getVideoUrl.then(function(t){e=t});break;default:e=this.media.currentSrc}return e}},{key:"poster",set:function(e){"video"===this.type?n.is.string(e)&&this.media.setAttribute("poster",e):this.warn("Poster can only be set on HTML5 video")},get:function(){return"video"!==this.type?null:this.media.getAttribute("poster")}},{key:"language",set:function(e){var t=this;if(n.is.empty(e))return this.toggleCaptions(!1),t;var i=e.toLowerCase();return this.captions.language===i?t:(this.toggleCaptions(!0),this.captions.language=i,n.dispatchEvent.call(this,this.media,"captionchange"),l.setCaption.call(this),l.setup.call(this),this)},get:function(){return this.captions.language}}]),e}()}); + +//# sourceMappingURL=plyr.js.map diff --git a/dist/plyr.js.map b/dist/plyr.js.map new file mode 100644 index 00000000..3892ea38 --- /dev/null +++ b/dist/plyr.js.map @@ -0,0 +1 @@ +{"version":3,"file":"plyr.js","sources":["src/js/storage.js","src/js/defaults.js","src/js/types.js","src/js/utils.js","src/js/support.js","src/js/controls.js","src/js/captions.js","src/js/fullscreen.js","src/js/listeners.js","src/js/ui.js","src/js/plugins/youtube.js","src/js/plugins/vimeo.js","src/js/media.js","src/js/source.js","src/js/plyr.js"],"sourcesContent":["// ==========================================================================\n// Plyr storage\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\n\n// Save a value back to local storage\nfunction set(value) {\n // Bail if we don't have localStorage support or it's disabled\n if (!support.storage || !this.config.storage.enabled) {\n return;\n }\n\n // Update the working copy of the values\n utils.extend(this.storage, value);\n\n // Update storage\n window.localStorage.setItem(this.config.storage.key, JSON.stringify(this.storage));\n}\n\n// Setup localStorage\nfunction setup() {\n let value = null;\n let storage = {};\n\n // Bail if we don't have localStorage support or it's disabled\n if (!support.storage || !this.config.storage.enabled) {\n return storage;\n }\n\n // Clean up old volume\n // https://github.com/sampotts/plyr/issues/171\n window.localStorage.removeItem('plyr-volume');\n\n // load value from the current key\n value = window.localStorage.getItem(this.config.storage.key);\n\n if (!value) {\n // Key wasn't set (or had been cleared), move along\n } else if (/^\\d+(\\.\\d+)?$/.test(value)) {\n // If value is a number, it's probably volume from an older\n // version of this. See: https://github.com/sampotts/plyr/pull/313\n // Update the key to be JSON\n set({\n volume: parseFloat(value),\n });\n } else {\n // Assume it's JSON from this or a later version of plyr\n storage = JSON.parse(value);\n }\n\n return storage;\n}\n\nexport default { setup, set };\n","// Default config\nconst defaults = {\n // Disable\n enabled: true,\n\n // Custom media title\n title: '',\n\n // Logging to console\n debug: false,\n\n // Auto play (if supported)\n autoplay: false,\n\n // Default time to skip when rewind/fast forward\n seekTime: 10,\n\n // Default volume\n volume: 1,\n muted: false,\n\n // Display the media duration\n displayDuration: true,\n\n // Click video to play\n clickToPlay: true,\n\n // Auto hide the controls\n hideControls: true,\n\n // Revert to poster on finish (HTML5 - will cause reload)\n showPosterOnEnd: false,\n\n // Disable the standard context menu\n disableContextMenu: true,\n\n // Sprite (for icons)\n loadSprite: true,\n iconPrefix: 'plyr',\n iconUrl: 'https://cdn.plyr.io/2.0.10/plyr.svg',\n\n // Blank video (used to prevent errors on source change)\n blankVideo: 'https://cdn.plyr.io/static/blank.mp4',\n\n // Pass a custom duration\n duration: null,\n\n // Quality default\n quality: {\n default: 'default',\n options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'],\n },\n\n // Set loops\n loop: {\n active: false,\n start: null,\n end: null,\n },\n\n // Speed default and options to display\n speed: {\n default: 1,\n options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],\n },\n\n // Keyboard shortcut settings\n keyboard: {\n focused: true,\n global: false,\n },\n\n // Display tooltips\n tooltips: {\n controls: false,\n seek: true,\n },\n\n // Captions settings\n captions: {\n active: false,\n language: window.navigator.language.split('-')[0],\n },\n\n // Fullscreen settings\n fullscreen: {\n enabled: true, // Allow fullscreen?\n fallback: true, // Fallback for vintage browsers\n },\n\n // Local storage\n storage: {\n enabled: true,\n key: 'plyr',\n },\n\n // Default controls\n controls: [\n 'play-large',\n 'play',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'pip',\n 'airplay',\n 'fullscreen',\n ],\n settings: ['captions', 'quality', 'speed', 'loop'],\n\n // Localisation\n i18n: {\n restart: 'Restart',\n rewind: 'Rewind {seektime} secs',\n play: 'Play',\n pause: 'Pause',\n forward: 'Forward {seektime} secs',\n seek: 'Seek',\n played: 'Played',\n buffered: 'Buffered',\n currentTime: 'Current time',\n duration: 'Duration',\n volume: 'Volume',\n toggleMute: 'Toggle Mute',\n toggleCaptions: 'Toggle Captions',\n toggleFullscreen: 'Toggle Fullscreen',\n frameTitle: 'Player for {title}',\n captions: 'Captions',\n settings: 'Settings',\n speed: 'Speed',\n quality: 'Quality',\n loop: 'Loop',\n start: 'Start',\n end: 'End',\n all: 'All',\n reset: 'Reset',\n none: 'None',\n disabled: 'Disabled',\n },\n\n // URLs\n urls: {\n vimeo: {\n api: 'https://player.vimeo.com/api/player.js',\n },\n youtube: {\n api: 'https://www.youtube.com/iframe_api',\n },\n },\n\n // Custom control listeners\n listeners: {\n seek: null,\n play: null,\n pause: null,\n restart: null,\n rewind: null,\n forward: null,\n mute: null,\n volume: null,\n captions: null,\n fullscreen: null,\n pip: null,\n airplay: null,\n speed: null,\n quality: null,\n loop: null,\n language: null,\n },\n\n // Events to watch and bubble\n events: [\n // Events to watch on HTML5 media elements and bubble\n // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events\n 'ended',\n 'progress',\n 'stalled',\n 'playing',\n 'waiting',\n 'canplay',\n 'canplaythrough',\n 'loadstart',\n 'loadeddata',\n 'loadedmetadata',\n 'timeupdate',\n 'volumechange',\n 'play',\n 'pause',\n 'error',\n 'seeking',\n 'seeked',\n 'emptied',\n 'ratechange',\n 'cuechange',\n\n // Custom events\n 'enterfullscreen',\n 'exitfullscreen',\n 'captionsenabled',\n 'captionsdisabled',\n 'captionchange',\n 'controlshidden',\n 'controlsshown',\n 'ready',\n\n // YouTube\n 'statechange',\n 'qualitychange',\n 'qualityrequested',\n ],\n\n // Selectors\n // Change these to match your template if using custom HTML\n selectors: {\n editable: 'input, textarea, select, [contenteditable]',\n container: '.plyr',\n controls: {\n container: null,\n wrapper: '.plyr__controls',\n },\n labels: '[data-plyr]',\n buttons: {\n play: '[data-plyr=\"play\"]',\n pause: '[data-plyr=\"pause\"]',\n restart: '[data-plyr=\"restart\"]',\n rewind: '[data-plyr=\"rewind\"]',\n forward: '[data-plyr=\"fast-forward\"]',\n mute: '[data-plyr=\"mute\"]',\n captions: '[data-plyr=\"captions\"]',\n fullscreen: '[data-plyr=\"fullscreen\"]',\n pip: '[data-plyr=\"pip\"]',\n airplay: '[data-plyr=\"airplay\"]',\n settings: '[data-plyr=\"settings\"]',\n loop: '[data-plyr=\"loop\"]',\n },\n inputs: {\n seek: '[data-plyr=\"seek\"]',\n volume: '[data-plyr=\"volume\"]',\n speed: '[data-plyr=\"speed\"]',\n language: '[data-plyr=\"language\"]',\n quality: '[data-plyr=\"quality\"]',\n },\n display: {\n currentTime: '.plyr__time--current',\n duration: '.plyr__time--duration',\n buffer: '.plyr__progress--buffer',\n played: '.plyr__progress--played',\n loop: '.plyr__progress--loop',\n volume: '.plyr__volume--display',\n },\n progress: '.plyr__progress',\n captions: '.plyr__captions',\n menu: {\n quality: '.js-plyr__menu__list--quality',\n },\n },\n\n // Class hooks added to the player in different states\n classNames: {\n video: 'plyr__video-wrapper',\n embed: 'plyr__video-embed',\n control: 'plyr__control',\n type: 'plyr--{0}',\n stopped: 'plyr--stopped',\n playing: 'plyr--playing',\n muted: 'plyr--muted',\n loading: 'plyr--loading',\n hover: 'plyr--hover',\n tooltip: 'plyr__tooltip',\n hidden: 'plyr__sr-only',\n hideControls: 'plyr--hide-controls',\n isIos: 'plyr--is-ios',\n isTouch: 'plyr--is-touch',\n uiSupported: 'plyr--full-ui',\n menu: {\n value: 'plyr__menu__value',\n badge: 'plyr__badge',\n },\n captions: {\n enabled: 'plyr--captions-enabled',\n active: 'plyr--captions-active',\n },\n fullscreen: {\n enabled: 'plyr--fullscreen-enabled',\n fallback: 'plyr--fullscreen-fallback',\n },\n pip: {\n supported: 'plyr--pip-supported',\n active: 'plyr--pip-active',\n },\n airplay: {\n supported: 'plyr--airplay-supported',\n active: 'plyr--airplay-active',\n },\n tabFocus: 'tab-focus',\n },\n};\n\nexport default defaults;\n","// ==========================================================================\n// Plyr supported types\n// ==========================================================================\n\nconst types = {\n embed: ['youtube', 'vimeo'],\n html5: ['video', 'audio'],\n};\n\nexport default types;\n","// ==========================================================================\n// Plyr utils\n// ==========================================================================\n\nimport support from './support';\n\nconst utils = {\n // Check variable types\n is: {\n object(input) {\n return this.getConstructor(input) === Object;\n },\n number(input) {\n return this.getConstructor(input) === Number && !Number.isNaN(input);\n },\n string(input) {\n return this.getConstructor(input) === String;\n },\n boolean(input) {\n return this.getConstructor(input) === Boolean;\n },\n function(input) {\n return this.getConstructor(input) === Function;\n },\n array(input) {\n return !this.undefined(input) && Array.isArray(input);\n },\n nodeList(input) {\n return !this.undefined(input) && input instanceof NodeList;\n },\n htmlElement(input) {\n return !this.undefined(input) && input instanceof HTMLElement;\n },\n event(input) {\n return !this.undefined(input) && input instanceof Event;\n },\n cue(input) {\n return this.instanceOf(input, window.TextTrackCue) || this.instanceOf(input, window.VTTCue);\n },\n track(input) {\n return (\n !this.undefined(input) && (this.instanceOf(input, window.TextTrack) || typeof input.kind === 'string')\n );\n },\n undefined(input) {\n return input !== null && typeof input === 'undefined';\n },\n empty(input) {\n return (\n input === null ||\n typeof input === 'undefined' ||\n ((this.string(input) || this.array(input) || this.nodeList(input)) && input.length === 0) ||\n (this.object(input) && Object.keys(input).length === 0)\n );\n },\n getConstructor(input) {\n if (input === null || typeof input === 'undefined') {\n return null;\n }\n\n return input.constructor;\n },\n instanceOf(input, constructor) {\n return Boolean(input && constructor && input instanceof constructor);\n },\n },\n\n // Unfortunately, due to mixed support, UA sniffing is required\n getBrowser() {\n return {\n isIE: /* @cc_on!@ */ false || !!document.documentMode,\n isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),\n isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),\n isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform),\n };\n },\n\n // Load an external script\n loadScript(url) {\n // Check script is not already referenced\n if (document.querySelectorAll(`script[src=\"${url}\"]`).length) {\n return;\n }\n\n const tag = document.createElement('script');\n tag.src = url;\n\n const firstScriptTag = document.getElementsByTagName('script')[0];\n firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\n },\n\n // Generate a random ID\n generateId(prefix) {\n return `${prefix}-${Math.floor(Math.random() * 10000)}`;\n },\n\n // Determine if we're in an iframe\n inFrame() {\n try {\n return window.self !== window.top;\n } catch (e) {\n return true;\n }\n },\n\n // Wrap an element\n wrap(elements, wrapper) {\n // Convert `elements` to an array, if necessary.\n const targets = elements.length ? elements : [elements];\n\n // Loops backwards to prevent having to clone the wrapper on the\n // first element (see `child` below).\n Array.from(targets)\n .reverse()\n .forEach((element, index) => {\n const child = index > 0 ? wrapper.cloneNode(true) : wrapper;\n\n // Cache the current parent and sibling.\n const parent = element.parentNode;\n const sibling = element.nextSibling;\n\n // Wrap the element (is automatically removed from its current\n // parent).\n child.appendChild(element);\n\n // If the element had a sibling, insert the wrapper before\n // the sibling to maintain the HTML structure; otherwise, just\n // append it to the parent.\n if (sibling) {\n parent.insertBefore(child, sibling);\n } else {\n parent.appendChild(child);\n }\n });\n },\n\n // Remove an element\n removeElement(element) {\n if (!utils.is.htmlElement(element) || !utils.is.htmlElement(element.parentNode)) {\n return null;\n }\n\n element.parentNode.removeChild(element);\n\n return element;\n },\n\n // Inaert an element after another\n insertAfter(element, target) {\n target.parentNode.insertBefore(element, target.nextSibling);\n },\n\n // Create a DocumentFragment\n createElement(type, attributes, text) {\n // Create a new <element>\n const element = document.createElement(type);\n\n // Set all passed attributes\n if (utils.is.object(attributes)) {\n utils.setAttributes(element, attributes);\n }\n\n // Add text node\n if (utils.is.string(text)) {\n element.textContent = text;\n }\n\n // Return built element\n return element;\n },\n\n // Insert a DocumentFragment\n insertElement(type, parent, attributes, text) {\n // Inject the new <element>\n parent.appendChild(utils.createElement(type, attributes, text));\n },\n\n // Remove all child elements\n emptyElement(element) {\n let { length } = element.childNodes;\n\n while (length > 0) {\n element.removeChild(element.lastChild);\n length -= 1;\n }\n },\n\n // Set attributes\n setAttributes(element, attributes) {\n Object.keys(attributes).forEach(key => {\n element.setAttribute(key, attributes[key]);\n });\n },\n\n // Get an attribute object from a string selector\n getAttributesFromSelector(sel, existingAttributes) {\n // For example:\n // '.test' to { class: 'test' }\n // '#test' to { id: 'test' }\n // '[data-test=\"test\"]' to { 'data-test': 'test' }\n\n if (!utils.is.string(sel) || utils.is.empty(sel)) {\n return {};\n }\n\n const attributes = {};\n const existing = existingAttributes;\n\n sel.split(',').forEach(s => {\n // Remove whitespace\n const selector = s.trim();\n const className = selector.replace('.', '');\n const stripped = selector.replace(/[[\\]]/g, '');\n\n // Get the parts and value\n const parts = stripped.split('=');\n const key = parts[0];\n const value = parts.length > 1 ? parts[1].replace(/[\"']/g, '') : '';\n\n // Get the first character\n const start = selector.charAt(0);\n\n switch (start) {\n case '.':\n // Add to existing classname\n if (utils.is.object(existing) && utils.is.string(existing.class)) {\n existing.class += ` ${className}`;\n }\n\n attributes.class = className;\n break;\n\n case '#':\n // ID selector\n attributes.id = selector.replace('#', '');\n break;\n\n case '[':\n // Attribute selector\n attributes[key] = value;\n\n break;\n\n default:\n break;\n }\n });\n\n return attributes;\n },\n\n // Toggle class on an element\n toggleClass(element, className, toggle) {\n if (utils.is.htmlElement(element)) {\n const contains = element.classList.contains(className);\n\n element.classList[toggle ? 'add' : 'remove'](className);\n\n return (toggle && !contains) || (!toggle && contains);\n }\n\n return null;\n },\n\n // Has class name\n hasClass(element, className) {\n return utils.is.htmlElement(element) && element.classList.contains(className);\n },\n\n // Element matches selector\n matches(element, selector) {\n const prototype = { Element };\n\n function match() {\n return Array.from(document.querySelectorAll(selector)).includes(this);\n }\n\n const matches =\n prototype.matches ||\n prototype.webkitMatchesSelector ||\n prototype.mozMatchesSelector ||\n prototype.msMatchesSelector ||\n match;\n\n return matches.call(element, selector);\n },\n\n // Find all elements\n getElements(selector) {\n return this.elements.container.querySelectorAll(selector);\n },\n\n // Find a single element\n getElement(selector) {\n return this.elements.container.querySelector(selector);\n },\n\n // Find the UI controls and store references in custom controls\n // TODO: Allow settings menus with custom controls\n findElements() {\n try {\n this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper);\n\n // Buttons\n this.elements.buttons = {\n play: utils.getElements.call(this, this.config.selectors.buttons.play),\n pause: utils.getElement.call(this, this.config.selectors.buttons.pause),\n restart: utils.getElement.call(this, this.config.selectors.buttons.restart),\n rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind),\n forward: utils.getElement.call(this, this.config.selectors.buttons.forward),\n mute: utils.getElement.call(this, this.config.selectors.buttons.mute),\n pip: utils.getElement.call(this, this.config.selectors.buttons.pip),\n airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay),\n settings: utils.getElement.call(this, this.config.selectors.buttons.settings),\n captions: utils.getElement.call(this, this.config.selectors.buttons.captions),\n fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen),\n };\n\n // Progress\n this.elements.progress = utils.getElement.call(this, this.config.selectors.progress);\n\n // Inputs\n this.elements.inputs = {\n seek: utils.getElement.call(this, this.config.selectors.inputs.seek),\n volume: utils.getElement.call(this, this.config.selectors.inputs.volume),\n };\n\n // Display\n this.elements.display = {\n buffer: utils.getElement.call(this, this.config.selectors.display.buffer),\n duration: utils.getElement.call(this, this.config.selectors.display.duration),\n currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime),\n };\n\n // Seek tooltip\n if (utils.is.htmlElement(this.elements.progress)) {\n this.elements.display.seekTooltip = this.elements.progress.querySelector(\n `.${this.config.classNames.tooltip}`\n );\n }\n\n return true;\n } catch (error) {\n // Log it\n this.warn('It looks like there is a problem with your custom controls HTML', error);\n\n // Restore native video controls\n this.toggleNativeControls(true);\n\n return false;\n }\n },\n\n // Get the focused element\n getFocusElement() {\n let focused = document.activeElement;\n\n if (!focused || focused === document.body) {\n focused = null;\n } else {\n focused = document.querySelector(':focus');\n }\n\n return focused;\n },\n\n // Trap focus inside container\n trapFocus() {\n const tabbables = utils.getElements.call(this, 'input:not([disabled]), button:not([disabled])');\n const first = tabbables[0];\n const last = tabbables[tabbables.length - 1];\n\n utils.on(\n this.elements.container,\n 'keydown',\n event => {\n // If it is tab\n if (event.which === 9 && this.fullscreen.active) {\n if (event.target === last && !event.shiftKey) {\n // Move focus to first element that can be tabbed if Shift isn't used\n event.preventDefault();\n first.focus();\n } else if (event.target === first && event.shiftKey) {\n // Move focus to last element that can be tabbed if Shift is used\n event.preventDefault();\n last.focus();\n }\n }\n },\n false\n );\n },\n\n // Bind along with custom handler\n proxy(element, eventName, customListener, defaultListener, passive, capture) {\n utils.on(\n element,\n eventName,\n event => {\n if (customListener) {\n customListener.apply(element, [event]);\n }\n defaultListener.apply(element, [event]);\n },\n passive,\n capture\n );\n },\n\n // Toggle event listener\n toggleListener(elements, event, callback, toggle, passive, capture) {\n // Bail if no elements\n if (elements === null || utils.is.undefined(elements)) {\n return;\n }\n\n // If a nodelist is passed, call itself on each node\n if (elements instanceof NodeList) {\n // Create listener for each node\n Array.from(elements).forEach(element => {\n if (element instanceof Node) {\n utils.toggleListener.call(null, element, event, callback, toggle, passive, capture);\n }\n });\n\n return;\n }\n\n // Allow multiple events\n const events = event.split(' ');\n\n // Build options\n // Default to just capture boolean\n let options = utils.is.boolean(capture) ? capture : false;\n\n // If passive events listeners are supported\n if (support.passiveListeners) {\n options = {\n // Whether the listener can be passive (i.e. default never prevented)\n passive: utils.is.boolean(passive) ? passive : true,\n // Whether the listener is a capturing listener or not\n capture: utils.is.boolean(capture) ? capture : false,\n };\n }\n\n // If a single node is passed, bind the event listener\n events.forEach(type => {\n elements[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);\n });\n },\n\n // Bind event handler\n on(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, true, passive, capture);\n },\n\n // Unbind event handler\n off(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, false, passive, capture);\n },\n\n // Trigger event\n dispatchEvent(element, type, bubbles, properties) {\n // Bail if no element\n if (!element || !type) {\n return;\n }\n\n // Create and dispatch the event\n const event = new CustomEvent(type, {\n bubbles: utils.is.boolean(bubbles) ? bubbles : false,\n detail: Object.assign({}, properties, {\n plyr: this instanceof Plyr ? this : null,\n }),\n });\n\n // Dispatch the event\n element.dispatchEvent(event);\n },\n\n // Toggle aria-pressed state on a toggle button\n // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles\n toggleState(target, state) {\n // Bail if no target\n if (!target) {\n return null;\n }\n\n // Get state\n const newState = utils.is.boolean(state) ? state : !target.getAttribute('aria-pressed');\n\n // Set the attribute on target\n target.setAttribute('aria-pressed', newState);\n\n return newState;\n },\n\n // Get percentage\n getPercentage(current, max) {\n if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {\n return 0;\n }\n return (current / max * 100).toFixed(2);\n },\n\n // Deep extend/merge destination object with N more objects\n // http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/\n // Removed call to arguments.callee (used explicit function name instead)\n extend(...objects) {\n const { length } = objects;\n\n // Bail if nothing to merge\n if (!length) {\n return null;\n }\n\n // Return first if specified but nothing to merge\n if (length === 1) {\n return objects[0];\n }\n\n // First object is the destination\n let destination = Array.prototype.shift.call(objects);\n if (!utils.is.object(destination)) {\n destination = {};\n }\n\n // Loop through all objects to merge\n objects.forEach(source => {\n if (!utils.is.object(source)) {\n return;\n }\n\n Object.keys(source).forEach(property => {\n if (source[property] && source[property].constructor && source[property].constructor === Object) {\n destination[property] = destination[property] || {};\n utils.extend(destination[property], source[property]);\n } else {\n destination[property] = source[property];\n }\n });\n });\n\n return destination;\n },\n\n // Parse YouTube ID from URL\n parseYouTubeId(url) {\n const regex = /^.*(youtu.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|&v=)([^#&?]*).*/;\n return url.match(regex) ? RegExp.$2 : url;\n },\n\n // Parse Vimeo ID from URL\n parseVimeoId(url) {\n if (utils.is.number(Number(url))) {\n return url;\n }\n\n const regex = /^.*(vimeo.com\\/|video\\/)(\\d+).*/;\n return url.match(regex) ? RegExp.$2 : url;\n },\n\n // Convert object to URL parameters\n buildUrlParameters(input) {\n if (!utils.is.object(input)) {\n return '';\n }\n\n return Object.keys(input)\n .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(input[key])}`)\n .join('&');\n },\n\n // Remove HTML from a string\n stripHTML(source) {\n const fragment = document.createDocumentFragment();\n const element = document.createElement('div');\n fragment.appendChild(element);\n element.innerHTML = source;\n return fragment.firstChild.innerText;\n },\n\n // Load an SVG sprite\n loadSprite(url, id) {\n if (typeof url !== 'string') {\n return;\n }\n\n const prefix = 'cache-';\n const hasId = typeof id === 'string';\n let isCached = false;\n\n function updateSprite(data) {\n // Inject content\n this.innerHTML = data;\n\n // Inject the SVG to the body\n document.body.insertBefore(this, document.body.childNodes[0]);\n }\n\n // Only load once\n if (!hasId || !document.querySelectorAll(`#${id}`).length) {\n // Create container\n const container = document.createElement('div');\n container.setAttribute('hidden', '');\n\n if (hasId) {\n container.setAttribute('id', id);\n }\n\n // Check in cache\n if (support.storage) {\n const cached = window.localStorage.getItem(prefix + id);\n isCached = cached !== null;\n\n if (isCached) {\n const data = JSON.parse(cached);\n updateSprite.call(container, data.content);\n }\n }\n\n // ReSharper disable once InconsistentNaming\n const xhr = new XMLHttpRequest();\n\n // XHR for Chrome/Firefox/Opera/Safari\n if ('withCredentials' in xhr) {\n xhr.open('GET', url, true);\n } else {\n return;\n }\n\n // Once loaded, inject to container and body\n xhr.onload = () => {\n if (support.storage) {\n window.localStorage.setItem(\n prefix + id,\n JSON.stringify({\n content: xhr.responseText,\n })\n );\n }\n\n updateSprite.call(container, xhr.responseText);\n };\n\n xhr.send();\n }\n },\n\n // Get the transition end event\n transitionEnd: (() => {\n const element = document.createElement('span');\n\n const events = {\n WebkitTransition: 'webkitTransitionEnd',\n MozTransition: 'transitionend',\n OTransition: 'oTransitionEnd otransitionend',\n transition: 'transitionend',\n };\n\n const type = Object.keys(events).find(event => element.style[event] !== undefined);\n\n return typeof type === 'string' ? type : false;\n })(),\n};\n\nexport default utils;\n","// ==========================================================================\n// Plyr support checks\n// ==========================================================================\n\nimport utils from './utils';\n\n// Check for feature support\nconst support = {\n // Basic support\n audio: 'canPlayType' in document.createElement('audio'),\n video: 'canPlayType' in document.createElement('video'),\n\n // Check for support\n // Basic functionality vs full UI\n check(type, inline) {\n let api = false;\n let ui = false;\n const browser = utils.getBrowser();\n const playsInline = browser.isIPhone && inline && support.inline;\n\n switch (type) {\n case 'video':\n api = support.video;\n ui = api && support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'audio':\n api = support.audio;\n ui = api && support.rangeInput;\n break;\n\n case 'youtube':\n api = true;\n ui = support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'vimeo':\n api = true;\n ui = support.rangeInput && !browser.isIPhone;\n break;\n\n default:\n api = support.audio && support.video;\n ui = api && support.rangeInput;\n }\n\n return {\n api,\n ui,\n };\n },\n\n // Local storage\n // We can't assume if local storage is present that we can use it\n storage: (() => {\n if (!('localStorage' in window)) {\n return false;\n }\n\n // Try to use it (it might be disabled, e.g. user is in private/porn mode)\n // see: https://github.com/sampotts/plyr/issues/131\n const test = '___test';\n try {\n window.localStorage.setItem(test, test);\n window.localStorage.removeItem(test);\n return true;\n } catch (e) {\n return false;\n }\n })(),\n\n // Picture-in-picture support\n // Safari only currently\n pip: (() => {\n const browser = utils.getBrowser();\n return !browser.isIPhone && utils.is.function(utils.createElement('video').webkitSetPresentationMode);\n })(),\n\n // Airplay support\n // Safari only currently\n airplay: utils.is.function(window.WebKitPlaybackTargetAvailabilityEvent),\n\n // Inline playback support\n // https://webkit.org/blog/6784/new-video-policies-for-ios/\n inline: 'playsInline' in document.createElement('video'),\n\n // Check for mime type support against a player instance\n // Credits: http://diveintohtml5.info/everything.html\n // Related: http://www.leanbackplayer.com/test/h5mt.html\n mime(player, type) {\n const media = { player };\n\n try {\n // Bail if no checking function\n if (!utils.is.function(media.canPlayType)) {\n return false;\n }\n\n // Type specific checks\n if (player.type === 'video') {\n switch (type) {\n case 'video/webm':\n return media.canPlayType('video/webm; codecs=\"vp8, vorbis\"').replace(/no/, '');\n case 'video/mp4':\n return media.canPlayType('video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"').replace(/no/, '');\n case 'video/ogg':\n return media.canPlayType('video/ogg; codecs=\"theora\"').replace(/no/, '');\n default:\n return false;\n }\n } else if (player.type === 'audio') {\n switch (type) {\n case 'audio/mpeg':\n return media.canPlayType('audio/mpeg;').replace(/no/, '');\n case 'audio/ogg':\n return media.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/no/, '');\n case 'audio/wav':\n return media.canPlayType('audio/wav; codecs=\"1\"').replace(/no/, '');\n default:\n return false;\n }\n }\n } catch (e) {\n return false;\n }\n\n // If we got this far, we're stuffed\n return false;\n },\n\n // Check for textTracks support\n textTracks: 'textTracks' in document.createElement('video'),\n\n // Check for passive event listener support\n // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n // https://www.youtube.com/watch?v=NPM6172J22g\n passiveListeners: (() => {\n // Test via a getter in the options object to see if the passive property is accessed\n let supported = false;\n try {\n const options = Object.defineProperty({}, 'passive', {\n get() {\n supported = true;\n return null;\n },\n });\n window.addEventListener('test', null, options);\n } catch (e) {\n // Do nothing\n }\n\n return supported;\n })(),\n\n // <input type=\"range\"> Sliders\n rangeInput: (() => {\n const range = document.createElement('input');\n range.type = 'range';\n return range.type === 'range';\n })(),\n\n // Touch\n // Remember a device can be moust + touch enabled\n touch: 'ontouchstart' in document.documentElement,\n\n // Detect transitions support\n transitions: utils.transitionEnd !== false,\n\n // Reduced motion iOS & MacOS setting\n // https://webkit.org/blog/7551/responsive-design-for-motion/\n reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches,\n};\n\nexport default support;\n","// ==========================================================================\n// Plyr controls\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\n\nconst controls = {\n // Webkit polyfill for lower fill range\n updateRangeFill(target) {\n // WebKit only\n if (!this.browser.isWebkit) {\n return;\n }\n\n // Get range from event if event passed\n const range = utils.is.event(target) ? target.target : target;\n\n // Needs to be a valid <input type='range'>\n if (!utils.is.htmlElement(range) || range.getAttribute('type') !== 'range') {\n return;\n }\n\n // Inject the stylesheet if needed\n if (!utils.is.htmlElement(this.elements.styleSheet)) {\n this.elements.styleSheet = utils.createElement('style');\n this.elements.container.appendChild(this.elements.styleSheet);\n }\n\n const styleSheet = this.elements.styleSheet.sheet;\n const percentage = range.value / range.max * 100;\n const selector = `#${range.id}::-webkit-slider-runnable-track`;\n const styles = `{ background-image: linear-gradient(to right, currentColor ${percentage}%, transparent ${percentage}%) }`;\n\n // Find old rule if it exists\n const index = Array.from(styleSheet.rules).findIndex(rule => rule.selectorText === selector);\n\n // Remove old rule\n if (index !== -1) {\n styleSheet.deleteRule(index);\n }\n\n // Insert new one\n styleSheet.insertRule([selector, styles].join(' '));\n },\n\n // Get icon URL\n getIconUrl() {\n return {\n url: this.config.iconUrl,\n absolute: this.config.iconUrl.indexOf('http') === 0 || this.browser.isIE,\n };\n },\n\n // Create <svg> icon\n createIcon(type, attributes) {\n const namespace = 'http://www.w3.org/2000/svg';\n const iconUrl = controls.getIconUrl.call(this);\n const iconPath = `${!iconUrl.absolute ? iconUrl.url : ''}#${this.config.iconPrefix}`;\n\n // Create <svg>\n const icon = document.createElementNS(namespace, 'svg');\n utils.setAttributes(\n icon,\n utils.extend(attributes, {\n role: 'presentation',\n })\n );\n\n // Create the <use> to reference sprite\n const use = document.createElementNS(namespace, 'use');\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `${iconPath}-${type}`);\n\n // Add <use> to <svg>\n icon.appendChild(use);\n\n return icon;\n },\n\n // Create hidden text label\n createLabel(type) {\n let text = this.config.i18n[type];\n\n switch (type) {\n case 'pip':\n text = 'PIP';\n break;\n\n case 'airplay':\n text = 'AirPlay';\n break;\n\n default:\n break;\n }\n\n return utils.createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n text\n );\n },\n\n // Create a badge\n createBadge(text) {\n const badge = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n badge.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.menu.badge,\n },\n text\n )\n );\n\n return badge;\n },\n\n // Create a <button>\n createButton(buttonType, attr) {\n const button = utils.createElement('button');\n const attributes = Object.assign({}, attr);\n let type = buttonType;\n let iconDefault;\n let iconToggled;\n let labelKey;\n\n if (!('type' in attributes)) {\n attributes.type = 'button';\n }\n\n if ('class' in attributes) {\n if (attributes.class.indexOf(this.config.classNames.control) === -1) {\n attributes.class += ` ${this.config.classNames.control}`;\n }\n } else {\n attributes.class = this.config.classNames.control;\n }\n\n // Large play button\n switch (type) {\n case 'mute':\n labelKey = 'toggleMute';\n iconDefault = 'volume';\n iconToggled = 'muted';\n break;\n\n case 'captions':\n labelKey = 'toggleCaptions';\n iconDefault = 'captions-off';\n iconToggled = 'captions-on';\n break;\n\n case 'fullscreen':\n labelKey = 'toggleFullscreen';\n iconDefault = 'enter-fullscreen';\n iconToggled = 'exit-fullscreen';\n break;\n\n case 'play-large':\n attributes.class = 'plyr__play-large';\n type = 'play';\n labelKey = 'play';\n iconDefault = 'play';\n break;\n\n default:\n labelKey = type;\n iconDefault = type;\n }\n\n // Merge attributes\n utils.extend(attributes, utils.getAttributesFromSelector(this.config.selectors.buttons[type], attributes));\n\n // Add toggle icon if needed\n if (utils.is.string(iconToggled)) {\n button.appendChild(\n controls.createIcon.call(this, iconToggled, {\n class: `icon--${iconToggled}`,\n })\n );\n }\n\n button.appendChild(controls.createIcon.call(this, iconDefault));\n button.appendChild(controls.createLabel.call(this, labelKey));\n\n utils.setAttributes(button, attributes);\n\n this.elements.buttons[type] = button;\n\n return button;\n },\n\n // Create an <input type='range'>\n createRange(type, attributes) {\n // Seek label\n const label = utils.createElement(\n 'label',\n {\n for: attributes.id,\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n );\n\n // Seek input\n const input = utils.createElement(\n 'input',\n utils.extend(\n utils.getAttributesFromSelector(this.config.selectors.inputs[type]),\n {\n type: 'range',\n min: 0,\n max: 100,\n step: 0.01,\n value: 0,\n autocomplete: 'off',\n },\n attributes\n )\n );\n\n this.elements.inputs[type] = input;\n\n return {\n label,\n input,\n };\n },\n\n // Create a <progress>\n createProgress(type, attributes) {\n const progress = utils.createElement(\n 'progress',\n utils.extend(\n utils.getAttributesFromSelector(this.config.selectors.display[type]),\n {\n min: 0,\n max: 100,\n value: 0,\n },\n attributes\n )\n );\n\n // Create the label inside\n if (type !== 'volume') {\n progress.appendChild(utils.createElement('span', null, '0'));\n\n let suffix = '';\n switch (type) {\n case 'played':\n suffix = this.config.i18n.played;\n break;\n\n case 'buffer':\n suffix = this.config.i18n.buffered;\n break;\n\n default:\n break;\n }\n\n progress.textContent = `% ${suffix.toLowerCase()}`;\n }\n\n this.elements.display[type] = progress;\n\n return progress;\n },\n\n // Create time display\n createTime(type) {\n const container = utils.createElement('span', {\n class: 'plyr__time',\n });\n\n container.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n )\n );\n\n container.appendChild(\n utils.createElement('span', utils.getAttributesFromSelector(this.config.selectors.display[type]), '00:00')\n );\n\n this.elements.display[type] = container;\n\n return container;\n },\n\n // Hide/show a tab\n toggleTab(setting, toggle) {\n const tab = this.elements.settings.tabs[setting];\n const pane = this.elements.settings.panes[setting];\n\n if (utils.is.htmlElement(tab)) {\n if (toggle) {\n tab.removeAttribute('hidden');\n } else {\n tab.setAttribute('hidden', '');\n }\n }\n\n if (utils.is.htmlElement(pane)) {\n if (toggle) {\n pane.removeAttribute('hidden');\n } else {\n pane.setAttribute('hidden', '');\n }\n }\n },\n\n // Set the YouTube quality menu\n // TODO: Support for HTML5\n setQualityMenu(options) {\n const list = this.elements.settings.panes.quality.querySelector('ul');\n\n // Set options if passed and filter based on config\n if (utils.is.array(options)) {\n this.options.quality = options.filter(quality => this.config.quality.options.includes(quality));\n } else {\n this.options.quality = this.config.quality.options;\n }\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.options.quality) && this.type === 'youtube';\n controls.toggleTab.call(this, 'quality', toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Get the badge HTML for HD, 4K etc\n const getBadge = quality => {\n let label = '';\n\n switch (quality) {\n case 'hd2160':\n label = '4K';\n break;\n\n case 'hd1440':\n label = 'WQHD';\n break;\n\n case 'hd1080':\n label = 'HD';\n break;\n\n case 'hd720':\n label = 'HD';\n break;\n\n default:\n break;\n }\n\n if (!label.length) {\n return null;\n }\n\n return controls.createBadge.call(this, label);\n };\n\n this.options.quality.forEach(quality => {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.quality), {\n type: 'radio',\n name: 'plyr-quality',\n value: quality,\n })\n );\n\n label.appendChild(radio);\n label.appendChild(document.createTextNode(controls.getLabel.call(this, 'quality', quality)));\n\n const badge = getBadge(quality);\n if (utils.is.htmlElement(badge)) {\n label.appendChild(badge);\n }\n\n item.appendChild(label);\n list.appendChild(item);\n });\n\n controls.updateSetting.call(this, 'quality', list);\n },\n\n // Translate a value into a nice label\n // TODO: Localisation\n getLabel(setting, value) {\n switch (setting) {\n case 'speed':\n return value === 1 ? 'Normal' : `${value}×`;\n\n case 'quality':\n switch (value) {\n case 'hd2160':\n return '2160P';\n case 'hd1440':\n return '1440P';\n case 'hd1080':\n return '1080P';\n case 'hd720':\n return '720P';\n case 'large':\n return '480P';\n case 'medium':\n return '360P';\n case 'small':\n return '240P';\n case 'tiny':\n return 'Tiny';\n case 'default':\n return 'Auto';\n default:\n return value;\n }\n\n case 'captions':\n return controls.getLanguage.call(this);\n\n default:\n return null;\n }\n },\n\n // Update the selected setting\n updateSetting(setting, container) {\n const pane = this.elements.settings.panes[setting];\n let value = null;\n let list = container;\n\n switch (setting) {\n case 'captions':\n value = this.captions.language;\n\n if (!this.captions.enabled) {\n value = '';\n }\n\n break;\n\n default:\n value = this[setting];\n\n // Get default\n if (utils.is.empty(value)) {\n value = this.config[setting].default;\n }\n\n // Unsupported value\n if (!this.options[setting].includes(value)) {\n this.warn(`Unsupported value of '${value}' for ${setting}`);\n return;\n }\n\n // Disabled value\n if (!this.config[setting].options.includes(value)) {\n this.warn(`Disabled value of '${value}' for ${setting}`);\n return;\n }\n\n break;\n }\n\n // Get the list if we need to\n if (!utils.is.htmlElement(list)) {\n list = pane && pane.querySelector('ul');\n }\n\n // Find the radio option\n const target = list && list.querySelector(`input[value=\"${value}\"]`);\n\n if (!utils.is.htmlElement(target)) {\n return;\n }\n\n // Check it\n target.checked = true;\n\n // Find the label\n const label = this.elements.settings.tabs[setting].querySelector(`.${this.config.classNames.menu.value}`);\n label.innerHTML = controls.getLabel.call(this, setting, value);\n },\n\n // Set the looping options\n setLoopMenu() {\n const options = ['start', 'end', 'all', 'reset'];\n const list = this.elements.settings.panes.loop.querySelector('ul');\n\n // Show the pane and tab\n this.elements.settings.tabs.loop.removeAttribute('hidden');\n this.elements.settings.panes.loop.removeAttribute('hidden');\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.loop.options);\n controls.toggleTab.call(this, 'loop', toggle);\n\n // Empty the menu\n utils.emptyElement(list);\n\n options.forEach(option => {\n const item = utils.createElement('li');\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.loop), {\n type: 'button',\n class: this.config.classNames.control,\n 'data-plyr-loop-action': option,\n }),\n this.config.i18n[option]\n );\n\n if (['start', 'end'].includes(option)) {\n const badge = controls.createBadge.call(this, '00:00');\n button.appendChild(badge);\n }\n\n item.appendChild(button);\n list.appendChild(item);\n });\n },\n\n // Get current selected caption language\n getLanguage() {\n if (!this.supported.ui) {\n return null;\n }\n\n if (!support.textTracks || utils.is.empty(this.captions.tracks)) {\n return this.config.i18n.none;\n }\n\n if (this.captions.enabled) {\n return this.captions.currentTrack.label;\n }\n return this.config.i18n.disabled;\n },\n\n // Set a list of available captions languages\n setCaptionsMenu() {\n const list = this.elements.settings.panes.captions.querySelector('ul');\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.captions.tracks);\n controls.toggleTab.call(this, 'captions', toggle);\n\n // Empty the menu\n utils.emptyElement(list);\n\n // If there's no captions, bail\n if (utils.is.empty(this.captions.tracks)) {\n return;\n }\n\n // Re-map the tracks into just the data we need\n const tracks = Array.from(this.captions.tracks).map(track => ({\n language: track.language,\n badge: true,\n label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(),\n }));\n\n // Add the \"None\" option to turn off captions\n tracks.unshift({\n language: '',\n label: this.config.i18n.none,\n });\n\n // Generate options\n tracks.forEach(track => {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.language), {\n type: 'radio',\n name: 'plyr-language',\n value: track.language,\n })\n );\n\n if (track.language.toLowerCase() === this.captions.language.toLowerCase()) {\n radio.checked = true;\n }\n\n label.appendChild(radio);\n label.appendChild(document.createTextNode(track.label || track.language));\n\n if (track.badge) {\n label.appendChild(controls.createBadge.call(this, track.language.toUpperCase()));\n }\n\n item.appendChild(label);\n list.appendChild(item);\n });\n\n controls.updateSetting.call(this, 'captions', list);\n },\n\n // Set a list of available captions languages\n setSpeedMenu(options) {\n // Set options if passed and filter based on config\n if (utils.is.array(options)) {\n this.options.speed = options.filter(speed => this.config.speed.options.includes(speed));\n } else {\n this.options.speed = this.config.speed.options;\n }\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.options.speed);\n controls.toggleTab.call(this, 'speed', toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Get the list to populate\n const list = this.elements.settings.panes.speed.querySelector('ul');\n\n // Show the pane and tab\n this.elements.settings.tabs.speed.removeAttribute('hidden');\n this.elements.settings.panes.speed.removeAttribute('hidden');\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Create items\n this.options.speed.forEach(speed => {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.speed), {\n type: 'radio',\n name: 'plyr-speed',\n value: speed,\n })\n );\n\n label.appendChild(radio);\n label.insertAdjacentHTML('beforeend', controls.getLabel.call(this, 'speed', speed));\n item.appendChild(label);\n list.appendChild(item);\n });\n\n controls.updateSetting.call(this, 'speed', list);\n },\n\n // Show/hide menu\n toggleMenu(event) {\n const { form } = this.elements.settings;\n const button = this.elements.buttons.settings;\n const show = utils.is.boolean(event) ? event : form && form.getAttribute('aria-hidden') === 'true';\n\n if (utils.is.event(event)) {\n const isMenuItem = form && form.contains(event.target);\n const isButton = event.target === this.elements.buttons.settings;\n\n // If the click was inside the form or if the click\n // wasn't the button or menu item and we're trying to\n // show the menu (a doc click shouldn't show the menu)\n if (isMenuItem || (!isMenuItem && !isButton && show)) {\n return;\n }\n\n // Prevent the toggle being caught by the doc listener\n if (isButton) {\n event.stopPropagation();\n }\n }\n\n // Set form and button attributes\n if (button) {\n button.setAttribute('aria-expanded', show);\n }\n if (form) {\n form.setAttribute('aria-hidden', !show);\n\n if (show) {\n form.removeAttribute('tabindex');\n } else {\n form.setAttribute('tabindex', -1);\n }\n }\n },\n\n // Get the natural size of a tab\n getTabSize(tab) {\n const clone = tab.cloneNode(true);\n clone.style.position = 'absolute';\n clone.style.opacity = 0;\n clone.setAttribute('aria-hidden', false);\n\n // Prevent input's being unchecked due to the name being identical\n Array.from(clone.querySelectorAll('input[name]')).forEach(input => {\n const name = input.getAttribute('name');\n input.setAttribute('name', `${name}-clone`);\n });\n\n // Append to parent so we get the \"real\" size\n tab.parentNode.appendChild(clone);\n\n // Get the sizes before we remove\n const width = clone.scrollWidth;\n const height = clone.scrollHeight;\n\n // Remove from the DOM\n utils.removeElement(clone);\n\n return {\n width,\n height,\n };\n },\n\n // Toggle Menu\n showTab(event) {\n const { menu } = this.elements.settings;\n const tab = event.target;\n const show = tab.getAttribute('aria-expanded') === 'false';\n const pane = document.getElementById(tab.getAttribute('aria-controls'));\n\n // Nothing to show, bail\n if (!utils.is.htmlElement(pane)) {\n return;\n }\n\n // Are we targetting a tab? If not, bail\n const isTab = pane.getAttribute('role') === 'tabpanel';\n if (!isTab) {\n return;\n }\n\n // Hide all other tabs\n // Get other tabs\n const current = menu.querySelector('[role=\"tabpanel\"][aria-hidden=\"false\"]');\n const container = current.parentNode;\n\n // Set other toggles to be expanded false\n Array.from(menu.querySelectorAll(`[aria-controls=\"${current.getAttribute('id')}\"]`)).forEach(toggle => {\n toggle.setAttribute('aria-expanded', false);\n });\n\n // If we can do fancy animations, we'll animate the height/width\n if (support.transitions && !support.reducedMotion) {\n // Set the current width as a base\n container.style.width = `${current.scrollWidth}px`;\n container.style.height = `${current.scrollHeight}px`;\n\n // Get potential sizes\n const size = controls.getTabSize.call(this, pane);\n\n // Restore auto height/width\n const restore = e => {\n // We're only bothered about height and width on the container\n if (e.target !== container || !['width', 'height'].includes(e.propertyName)) {\n return;\n }\n\n // Revert back to auto\n container.style.width = '';\n container.style.height = '';\n\n // Only listen once\n utils.off(container, utils.transitionEnd, restore);\n };\n\n // Listen for the transition finishing and restore auto height/width\n utils.on(container, utils.transitionEnd, restore);\n\n // Set dimensions to target\n container.style.width = `${size.width}px`;\n container.style.height = `${size.height}px`;\n }\n\n // Set attributes on current tab\n current.setAttribute('aria-hidden', true);\n current.setAttribute('tabindex', -1);\n\n // Set attributes on target\n pane.setAttribute('aria-hidden', !show);\n tab.setAttribute('aria-expanded', show);\n pane.removeAttribute('tabindex');\n },\n\n // Build the default HTML\n // TODO: Set order based on order in the config.controls array?\n create(data) {\n // Do nothing if we want no controls\n if (utils.is.empty(this.config.controls)) {\n return null;\n }\n\n // Create the container\n const container = utils.createElement(\n 'div',\n utils.getAttributesFromSelector(this.config.selectors.controls.wrapper)\n );\n\n // Restart button\n if (this.config.controls.includes('restart')) {\n container.appendChild(controls.createButton.call(this, 'restart'));\n }\n\n // Rewind button\n if (this.config.controls.includes('rewind')) {\n container.appendChild(controls.createButton.call(this, 'rewind'));\n }\n\n // Play Pause button\n if (this.config.controls.includes('play')) {\n container.appendChild(controls.createButton.call(this, 'play'));\n container.appendChild(controls.createButton.call(this, 'pause'));\n }\n\n // Fast forward button\n if (this.config.controls.includes('fast-forward')) {\n container.appendChild(controls.createButton.call(this, 'fast-forward'));\n }\n\n // Progress\n if (this.config.controls.includes('progress')) {\n const progress = utils.createElement(\n 'span',\n utils.getAttributesFromSelector(this.config.selectors.progress)\n );\n\n // Seek range slider\n const seek = controls.createRange.call(this, 'seek', {\n id: `plyr-seek-${data.id}`,\n });\n progress.appendChild(seek.label);\n progress.appendChild(seek.input);\n\n // Buffer progress\n progress.appendChild(controls.createProgress.call(this, 'buffer'));\n\n // TODO: Add loop display indicator\n\n // Seek tooltip\n if (this.config.tooltips.seek) {\n const tooltip = utils.createElement(\n 'span',\n {\n role: 'tooltip',\n class: this.config.classNames.tooltip,\n },\n '00:00'\n );\n\n progress.appendChild(tooltip);\n this.elements.display.seekTooltip = tooltip;\n }\n\n this.elements.progress = progress;\n container.appendChild(this.elements.progress);\n }\n\n // Media current time display\n if (this.config.controls.includes('current-time')) {\n container.appendChild(controls.createTime.call(this, 'currentTime'));\n }\n\n // Media duration display\n if (this.config.controls.includes('duration')) {\n container.appendChild(controls.createTime.call(this, 'duration'));\n }\n\n // Toggle mute button\n if (this.config.controls.includes('mute')) {\n container.appendChild(controls.createButton.call(this, 'mute'));\n }\n\n // Volume range control\n if (this.config.controls.includes('volume')) {\n const volume = utils.createElement('span', {\n class: 'plyr__volume',\n });\n\n // Set the attributes\n const attributes = {\n max: 1,\n step: 0.05,\n value: this.config.volume,\n };\n\n // Create the volume range slider\n const range = controls.createRange.call(\n this,\n 'volume',\n utils.extend(attributes, {\n id: `plyr-volume-${data.id}`,\n })\n );\n volume.appendChild(range.label);\n volume.appendChild(range.input);\n\n container.appendChild(volume);\n }\n\n // Toggle captions button\n if (this.config.controls.includes('captions')) {\n container.appendChild(controls.createButton.call(this, 'captions'));\n }\n\n // Settings button / menu\n if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {\n const menu = utils.createElement('div', {\n class: 'plyr__menu',\n });\n\n menu.appendChild(\n controls.createButton.call(this, 'settings', {\n id: `plyr-settings-toggle-${data.id}`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}`,\n 'aria-expanded': false,\n })\n );\n\n const form = utils.createElement('form', {\n class: 'plyr__menu__container',\n id: `plyr-settings-${data.id}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tablist',\n tabindex: -1,\n });\n\n const inner = utils.createElement('div');\n\n const home = utils.createElement('div', {\n id: `plyr-settings-${data.id}-home`,\n 'aria-hidden': false,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tabpanel',\n });\n\n // Create the tab list\n const tabs = utils.createElement('ul', {\n role: 'tablist',\n });\n\n // Build the tabs\n this.config.settings.forEach(type => {\n const tab = utils.createElement('li', {\n role: 'tab',\n hidden: '',\n });\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.settings), {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,\n id: `plyr-settings-${data.id}-${type}-tab`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-${type}`,\n 'aria-expanded': false,\n }),\n this.config.i18n[type]\n );\n\n const value = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n // Speed contains HTML entities\n value.innerHTML = data[type];\n\n button.appendChild(value);\n tab.appendChild(button);\n tabs.appendChild(tab);\n\n this.elements.settings.tabs[type] = tab;\n });\n\n home.appendChild(tabs);\n inner.appendChild(home);\n\n // Build the panes\n this.config.settings.forEach(type => {\n const pane = utils.createElement('div', {\n id: `plyr-settings-${data.id}-${type}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-${data.id}-${type}-tab`,\n role: 'tabpanel',\n tabindex: -1,\n hidden: '',\n });\n\n const back = utils.createElement(\n 'button',\n {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--back`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-home`,\n 'aria-expanded': false,\n },\n this.config.i18n[type]\n );\n\n pane.appendChild(back);\n\n const options = utils.createElement('ul');\n\n pane.appendChild(options);\n inner.appendChild(pane);\n\n this.elements.settings.panes[type] = pane;\n });\n\n form.appendChild(inner);\n menu.appendChild(form);\n container.appendChild(menu);\n\n this.elements.settings.form = form;\n this.elements.settings.menu = menu;\n }\n\n // Picture in picture button\n if (this.config.controls.includes('pip') && support.pip) {\n container.appendChild(controls.createButton.call(this, 'pip'));\n }\n\n // Airplay button\n if (this.config.controls.includes('airplay') && support.airplay) {\n container.appendChild(controls.createButton.call(this, 'airplay'));\n }\n\n // Toggle fullscreen button\n if (this.config.controls.includes('fullscreen')) {\n container.appendChild(controls.createButton.call(this, 'fullscreen'));\n }\n\n // Larger overlaid play button\n if (this.config.controls.includes('play-large')) {\n this.elements.buttons.playLarge = controls.createButton.call(this, 'play-large');\n this.elements.container.appendChild(this.elements.buttons.playLarge);\n }\n\n this.elements.controls = container;\n\n if (this.config.controls.includes('settings') && this.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(this);\n }\n\n return container;\n },\n\n // Insert controls\n inject() {\n // Sprite\n if (this.config.loadSprite) {\n const iconUrl = controls.getIconUrl.call(this);\n\n // Only load external sprite using AJAX\n if (iconUrl.absolute) {\n this.log(`AJAX loading absolute SVG sprite ${this.browser.isIE ? '(due to IE)' : ''}`);\n utils.loadSprite(iconUrl.url, 'sprite-plyr');\n } else {\n this.log('Sprite will be used as external resource directly');\n }\n }\n\n // Create a unique ID\n this.id = Math.floor(Math.random() * 10000);\n\n // Null by default\n let container = null;\n\n // HTML passed as the option\n if (utils.is.string(this.config.controls)) {\n container = this.config.controls;\n } else if (utils.is.function(this.config.controls)) {\n // A custom function to build controls\n // The function can return a HTMLElement or String\n container = this.config.controls({\n id: this.id,\n seektime: this.config.seekTime,\n });\n } else {\n // Create controls\n container = controls.create.call(this, {\n id: this.id,\n seektime: this.config.seekTime,\n speed: '-',\n // TODO: Get current quality\n quality: '-',\n captions: controls.getLanguage.call(this),\n // TODO: Get loop\n loop: 'None',\n });\n }\n\n // Controls container\n let target;\n\n // Inject to custom location\n if (utils.is.string(this.config.selectors.controls.container)) {\n target = document.querySelector(this.config.selectors.controls.container);\n }\n\n // Inject into the container by default\n if (!utils.is.htmlElement(target)) {\n target = this.elements.container;\n }\n\n // Inject controls HTML\n if (utils.is.htmlElement(container)) {\n target.appendChild(container);\n } else {\n target.insertAdjacentHTML('beforeend', container);\n }\n\n // Find the elements if need be\n if (utils.is.htmlElement(this.elements.controls)) {\n utils.findElements.call(this);\n }\n\n // Setup tooltips\n if (this.config.tooltips.controls) {\n const labels = utils.getElements.call(\n this,\n [\n this.config.selectors.controls.wrapper,\n ' ',\n this.config.selectors.labels,\n ' .',\n this.config.classNames.hidden,\n ].join('')\n );\n\n Array.from(labels).forEach(label => {\n utils.toggleClass(label, this.config.classNames.hidden, false);\n utils.toggleClass(label, this.config.classNames.tooltip, true);\n });\n }\n },\n};\n\nexport default controls;\n","// ==========================================================================\n// Plyr Captions\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\n\nconst captions = {\n // Setup captions\n setup() {\n // Requires UI support\n if (!this.supported.ui) {\n return;\n }\n\n // Set default language if not set\n if (!utils.is.empty(this.storage.language)) {\n this.captions.language = this.storage.language;\n } else if (utils.is.empty(this.captions.language)) {\n this.captions.language = this.config.captions.language.toLowerCase();\n }\n\n // Set captions enabled state if not set\n if (!utils.is.boolean(this.captions.enabled)) {\n if (!utils.is.empty(this.storage.language)) {\n this.captions.enabled = this.storage.captions;\n } else {\n this.captions.enabled = this.config.captions.active;\n }\n }\n\n // Only Vimeo and HTML5 video supported at this point\n if (!['video', 'vimeo'].includes(this.type) || (this.type === 'video' && !support.textTracks)) {\n this.captions.tracks = null;\n\n // Clear menu and hide\n if (this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n\n return;\n }\n\n // Inject the container\n if (!utils.is.htmlElement(this.elements.captions)) {\n this.elements.captions = utils.createElement(\n 'div',\n utils.getAttributesFromSelector(this.config.selectors.captions)\n );\n utils.insertAfter(this.elements.captions, this.elements.wrapper);\n }\n\n // Get tracks from HTML5\n if (this.type === 'video') {\n this.captions.tracks = this.media.textTracks;\n }\n\n // Set the class hook\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.captions.enabled,\n !utils.is.empty(this.captions.tracks)\n );\n\n // If no caption file exists, hide container for caption text\n if (utils.is.empty(this.captions.tracks)) {\n return;\n }\n\n // Enable UI\n captions.show.call(this);\n\n // Get a track\n const setCurrentTrack = () => {\n // Reset by default\n this.captions.currentTrack = null;\n\n // Filter doesn't seem to work for a TextTrackList :-(\n Array.from(this.captions.tracks).forEach(track => {\n if (track.language === this.captions.language.toLowerCase()) {\n this.captions.currentTrack = track;\n }\n });\n };\n\n // Get current track\n setCurrentTrack();\n\n // If we couldn't get the requested language, revert to default\n if (!utils.is.track(this.captions.currentTrack)) {\n const { language } = this.config.captions;\n\n // Reset to default\n // We don't update user storage as the selected language could become available\n this.captions.language = language;\n\n // Get fallback track\n setCurrentTrack();\n\n // If no match, disable captions\n if (!utils.is.track(this.captions.currentTrack)) {\n this.toggleCaptions(false);\n }\n\n controls.updateSetting.call(this, 'captions');\n }\n\n // Setup HTML5 track rendering\n if (this.type === 'video') {\n // Turn off native caption rendering to avoid double captions\n Array.from(this.captions.tracks).forEach(track => {\n // Remove previous bindings (if we've changed source or language)\n utils.off(track, 'cuechange', event => captions.setCue.call(this, event));\n\n // Hide captions\n track.mode = 'hidden';\n });\n\n // Check if suported kind\n const supported =\n this.captions.currentTrack && ['captions', 'subtitles'].includes(this.captions.currentTrack.kind);\n\n if (utils.is.track(this.captions.currentTrack) && supported) {\n utils.on(this.captions.currentTrack, 'cuechange', event => captions.setCue.call(this, event));\n\n // If we change the active track while a cue is already displayed we need to update it\n if (this.captions.currentTrack.activeCues && this.captions.currentTrack.activeCues.length > 0) {\n controls.setCue.call(this, this.captions.currentTrack);\n }\n }\n } else if (this.type === 'vimeo' && this.captions.active) {\n this.embed.enableTextTrack(this.captions.language);\n }\n\n // Set available languages in list\n if (this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n },\n\n // Display active caption if it contains text\n setCue(input) {\n // Get the track from the event if needed\n const track = utils.is.event(input) ? input.target : input;\n const active = track.activeCues[0];\n\n // Display a cue, if there is one\n if (utils.is.cue(active)) {\n captions.set.call(this, active.getCueAsHTML());\n } else {\n captions.set.call(this);\n }\n\n utils.dispatchEvent.call(this, this.media, 'cuechange');\n },\n\n // Set the current caption\n set(input) {\n // Requires UI\n if (!this.supported.ui) {\n return;\n }\n\n if (utils.is.htmlElement(this.elements.captions)) {\n const content = utils.createElement('span');\n\n // Empty the container\n utils.emptyElement(this.elements.captions);\n\n // Default to empty\n const caption = !utils.is.undefined(input) ? input : '';\n\n // Set the span content\n if (utils.is.string(caption)) {\n content.textContent = caption.trim();\n } else {\n content.appendChild(caption);\n }\n\n // Set new caption text\n this.elements.captions.appendChild(content);\n } else {\n this.warn('No captions element to render to');\n }\n },\n\n // Display captions container and button (for initialization)\n show() {\n // If there's no caption toggle, bail\n if (!this.elements.buttons.captions) {\n return;\n }\n\n // Try to load the value from storage\n let active = this.storage.captions;\n\n // Otherwise fall back to the default config\n if (!utils.is.boolean(active)) {\n ({ active } = this.captions);\n } else {\n this.captions.active = active;\n }\n\n if (active) {\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true);\n utils.toggleState(this.elements.buttons.captions, true);\n }\n },\n};\n\nexport default captions;\n","// ==========================================================================\n// Plyr fullscreen API\n// ==========================================================================\n\nimport utils from './utils';\n\n// Determine the prefix\nconst prefix = (() => {\n let value = false;\n\n if (utils.is.function(document.cancelFullScreen)) {\n value = '';\n } else {\n // Check for fullscreen support by vendor prefix\n ['webkit', 'o', 'moz', 'ms', 'khtml'].some(pre => {\n if (utils.is.function(document[`${pre}CancelFullScreen`])) {\n value = pre;\n return true;\n } else if (utils.is.function(document.msExitFullscreen) && document.msFullscreenEnabled) {\n // Special case for MS (when isn't it?)\n value = 'ms';\n return true;\n }\n\n return false;\n });\n }\n\n return value;\n})();\n\n// Fullscreen API\nconst fullscreen = {\n // Get the prefix\n prefix,\n\n // Check if we can use it\n enabled:\n document.fullscreenEnabled ||\n document.webkitFullscreenEnabled ||\n document.mozFullScreenEnabled ||\n document.msFullscreenEnabled,\n\n // Yet again Microsoft awesomeness,\n // Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes\n eventType: prefix === 'ms' ? 'MSFullscreenChange' : `${prefix}fullscreenchange`,\n\n // Is an element fullscreen\n isFullScreen(element) {\n if (!fullscreen.enabled) {\n return false;\n }\n\n const target = utils.is.undefined(element) ? document.body : element;\n\n switch (prefix) {\n case '':\n return document.fullscreenElement === target;\n\n case 'moz':\n return document.mozFullScreenElement === target;\n\n default:\n return document[`${prefix}FullscreenElement`] === target;\n }\n },\n\n // Make an element fullscreen\n requestFullScreen(element) {\n if (!fullscreen.enabled) {\n return false;\n }\n\n const target = utils.is.undefined(element) ? document.body : element;\n\n return !prefix.length\n ? target.requestFullScreen()\n : target[prefix + (prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')]();\n },\n\n // Bail from fullscreen\n cancelFullScreen() {\n if (!fullscreen.enabled) {\n return false;\n }\n\n return !prefix.length\n ? document.cancelFullScreen()\n : document[prefix + (prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')]();\n },\n\n // Get the current element\n element() {\n if (!fullscreen.enabled) {\n return null;\n }\n\n return !prefix.length ? document.fullscreenElement : document[`${prefix}FullscreenElement`];\n },\n\n // Setup fullscreen\n setup() {\n if (!this.supported.ui || this.type === 'audio' || !this.config.fullscreen.enabled) {\n return;\n }\n\n // Check for native support\n const nativeSupport = fullscreen.enabled;\n\n if (nativeSupport || (this.config.fullscreen.fallback && !utils.inFrame())) {\n this.log(`${nativeSupport ? 'Native' : 'Fallback'} fullscreen enabled`);\n\n // Add styling hook to show button\n utils.toggleClass(this.elements.container, this.config.classNames.fullscreen.enabled, true);\n } else {\n this.log('Fullscreen not supported and fallback disabled');\n }\n\n // Toggle state\n if (this.elements.buttons && this.elements.buttons.fullscreen) {\n utils.toggleState(this.elements.buttons.fullscreen, false);\n }\n\n // Trap focus in container\n utils.trapFocus.call(this);\n },\n};\n\nexport default fullscreen;\n","// ==========================================================================\n// Plyr Event Listeners\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport storage from './storage';\nimport ui from './ui';\n\nconst listeners = {\n // Listen for media events\n media() {\n // Time change on media\n utils.on(this.media, 'timeupdate seeking', event => ui.timeUpdate.call(this, event));\n\n // Display duration\n utils.on(this.media, 'durationchange loadedmetadata', event => ui.displayDuration.call(this, event));\n\n // Handle the media finishing\n utils.on(this.media, 'ended', () => {\n // Show poster on end\n if (this.type === 'video' && this.config.showPosterOnEnd) {\n // Restart\n this.restart();\n\n // Re-load media\n this.media.load();\n }\n });\n\n // Check for buffer progress\n utils.on(this.media, 'progress playing', event => ui.updateProgress.call(this, event));\n\n // Handle native mute\n utils.on(this.media, 'volumechange', event => ui.updateVolume.call(this, event));\n\n // Handle native play/pause\n utils.on(this.media, 'play pause ended', event => ui.checkPlaying.call(this, event));\n\n // Loading\n utils.on(this.media, 'waiting canplay seeked', event => ui.checkLoading.call(this, event));\n\n // Click video\n if (this.supported.ui && this.config.clickToPlay && this.type !== 'audio') {\n // Re-fetch the wrapper\n const wrapper = utils.getElement.call(this, `.${this.config.classNames.video}`);\n\n // Bail if there's no wrapper (this should never happen)\n if (!wrapper) {\n return;\n }\n\n // Set cursor\n wrapper.style.cursor = 'pointer';\n\n // On click play, pause ore restart\n utils.on(wrapper, 'click', () => {\n // Touch devices will just show controls (if we're hiding controls)\n if (this.config.hideControls && support.touch && !this.media.paused) {\n return;\n }\n\n if (this.media.paused) {\n this.play();\n } else if (this.media.ended) {\n this.restart();\n this.play();\n } else {\n this.pause();\n }\n });\n }\n\n // Disable right click\n if (this.config.disableContextMenu) {\n utils.on(\n this.media,\n 'contextmenu',\n event => {\n event.preventDefault();\n },\n false\n );\n }\n\n // Speed change\n utils.on(this.media, 'ratechange', () => {\n // Update UI\n controls.updateSetting.call(this, 'speed');\n\n // Save speed to localStorage\n storage.set.call(this, {\n speed: this.speed,\n });\n });\n\n // Quality change\n utils.on(this.media, 'qualitychange', () => {\n // Update UI\n controls.updateSetting.call(this, 'quality');\n\n // Save speed to localStorage\n storage.set.call(this, {\n quality: this.quality,\n });\n });\n\n // Caption language change\n utils.on(this.media, 'captionchange', () => {\n // Save speed to localStorage\n storage.set.call(this, {\n language: this.captions.language,\n });\n });\n\n // Captions toggle\n utils.on(this.media, 'captionsenabled captionsdisabled', () => {\n // Update UI\n controls.updateSetting.call(this, 'captions');\n\n // Save speed to localStorage\n storage.set.call(this, {\n captions: this.captions.enabled,\n });\n });\n\n // Proxy events to container\n // Bubble up key events for Edge\n utils.on(this.media, this.config.events.concat(['keyup', 'keydown']).join(' '), event => {\n utils.dispatchEvent.call(this, this.elements.container, event.type, true);\n });\n },\n\n // Listen for control events\n controls() {\n // IE doesn't support input event, so we fallback to change\n const inputEvent = this.browser.isIE ? 'change' : 'input';\n let last = null;\n\n // Click play/pause helper\n const togglePlay = () => {\n const play = this.togglePlay();\n\n // Determine which buttons\n const target = this.elements.buttons[play ? 'pause' : 'play'];\n\n // Transfer focus\n if (utils.is.htmlElement(target)) {\n target.focus();\n }\n };\n\n // Get the key code for an event\n function getKeyCode(event) {\n return event.keyCode ? event.keyCode : event.which;\n }\n\n function handleKey(event) {\n const code = getKeyCode(event);\n const pressed = event.type === 'keydown';\n const held = pressed && code === last;\n\n // If the event is bubbled from the media element\n // Firefox doesn't get the keycode for whatever reason\n if (!utils.is.number(code)) {\n return;\n }\n\n // Seek by the number keys\n function seekByKey() {\n // Divide the max duration into 10th's and times by the number value\n this.currentTime = this.duration / 10 * (code - 48);\n }\n\n // Handle the key on keydown\n // Reset on keyup\n if (pressed) {\n // Which keycodes should we prevent default\n const preventDefault = [\n 48,\n 49,\n 50,\n 51,\n 52,\n 53,\n 54,\n 56,\n 57,\n 32,\n 75,\n 38,\n 40,\n 77,\n 39,\n 37,\n 70,\n 67,\n 73,\n 76,\n 79,\n ];\n const checkFocus = [38, 40];\n\n if (checkFocus.includes(code)) {\n const focused = utils.getFocusElement();\n\n if (utils.is.htmlElement(focused) && utils.getFocusElement().type === 'radio') {\n return;\n }\n }\n\n // If the code is found prevent default (e.g. prevent scrolling for arrows)\n if (preventDefault.includes(code)) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n switch (code) {\n case 48:\n case 49:\n case 50:\n case 51:\n case 52:\n case 53:\n case 54:\n case 55:\n case 56:\n case 57:\n // 0-9\n if (!held) {\n seekByKey();\n }\n break;\n\n case 32:\n case 75:\n // Space and K key\n if (!held) {\n togglePlay();\n }\n break;\n\n case 38:\n // Arrow up\n this.increaseVolume(0.1);\n break;\n\n case 40:\n // Arrow down\n this.decreaseVolume(0.1);\n break;\n\n case 77:\n // M key\n if (!held) {\n this.toggleMute();\n }\n break;\n\n case 39:\n // Arrow forward\n this.forward();\n break;\n\n case 37:\n // Arrow back\n this.rewind();\n break;\n\n case 70:\n // F key\n this.toggleFullscreen();\n break;\n\n case 67:\n // C key\n if (!held) {\n this.toggleCaptions();\n }\n break;\n\n case 73:\n this.setLoop('start');\n break;\n\n case 76:\n this.setLoop();\n break;\n\n case 79:\n this.setLoop('end');\n break;\n\n default:\n break;\n }\n\n // Escape is handle natively when in full screen\n // So we only need to worry about non native\n if (!fullscreen.enabled && this.fullscreen.active && code === 27) {\n this.toggleFullscreen();\n }\n\n // Store last code for next cycle\n last = code;\n } else {\n last = null;\n }\n }\n\n // Keyboard shortcuts\n if (this.config.keyboard.focused) {\n // Handle global presses\n if (this.config.keyboard.global) {\n utils.on(\n window,\n 'keydown keyup',\n event => {\n const code = getKeyCode(event);\n const focused = utils.getFocusElement();\n const allowed = [48, 49, 50, 51, 52, 53, 54, 56, 57, 75, 77, 70, 67, 73, 76, 79];\n\n // Only handle global key press if key is in the allowed keys\n // and if the focused element is not editable (e.g. text input)\n // and any that accept key input http://webaim.org/techniques/keyboard/\n if (\n allowed.includes(code) &&\n (!utils.is.htmlElement(focused) || !utils.matches(focused, this.config.selectors.editable))\n ) {\n handleKey(event);\n }\n },\n false\n );\n }\n\n // Handle presses on focused\n utils.on(this.elements.container, 'keydown keyup', handleKey, false);\n }\n\n // Detect tab focus\n // Remove class on blur/focusout\n utils.on(this.elements.container, 'focusout', event => {\n utils.toggleClass(event.target, this.config.classNames.tabFocus, false);\n });\n\n // Add classname to tabbed elements\n utils.on(this.elements.container, 'keydown', event => {\n if (event.keyCode !== 9) {\n return;\n }\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n window.setTimeout(() => {\n utils.toggleClass(utils.getFocusElement(), this.config.classNames.tabFocus, true);\n }, 0);\n });\n\n // Trigger custom and default handlers\n const handlerProxy = (event, customHandler, defaultHandler) => {\n if (utils.is.function(customHandler)) {\n customHandler.call(this, event);\n }\n if (utils.is.function(defaultHandler)) {\n defaultHandler.call(this, event);\n }\n };\n\n // Play\n utils.proxy(this.elements.buttons.play, 'click', this.config.listeners.play, togglePlay);\n utils.proxy(this.elements.buttons.playLarge, 'click', this.config.listeners.play, togglePlay);\n\n // Pause\n utils.proxy(this.elements.buttons.pause, 'click', this.config.listeners.pause, togglePlay);\n\n // Pause\n utils.proxy(this.elements.buttons.restart, 'click', this.config.listeners.restart, () => {\n this.restart();\n });\n\n // Rewind\n utils.proxy(this.elements.buttons.rewind, 'click', this.config.listeners.rewind, () => {\n this.rewind();\n });\n\n // Rewind\n utils.proxy(this.elements.buttons.forward, 'click', this.config.listeners.forward, () => {\n this.forward();\n });\n\n // Mute\n utils.proxy(this.elements.buttons.mute, 'click', this.config.listeners.mute, () => {\n this.toggleMute();\n });\n\n // Captions\n utils.proxy(this.elements.buttons.captions, 'click', this.config.listeners.captions, () => {\n this.toggleCaptions();\n });\n\n // Fullscreen\n utils.proxy(this.elements.buttons.fullscreen, 'click', this.config.listeners.fullscreen, () => {\n this.toggleFullscreen();\n });\n\n // Picture-in-Picture\n utils.proxy(this.elements.buttons.pip, 'click', this.config.listeners.pip, () => {\n this.togglePictureInPicture();\n });\n\n // Airplay\n utils.proxy(this.elements.buttons.airplay, 'click', this.config.listeners.airplay, () => {\n this.airPlay();\n });\n\n // Settings menu\n utils.on(this.elements.buttons.settings, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Click anywhere closes menu\n utils.on(document.documentElement, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Settings menu\n utils.on(this.elements.settings.form, 'click', event => {\n // Show tab in menu\n controls.showTab.call(this, event);\n\n // Settings menu items - use event delegation as items are added/removed\n // Settings - Language\n if (utils.matches(event.target, this.config.selectors.inputs.language)) {\n handlerProxy.call(this, event, this.config.listeners.language, () => {\n this.toggleCaptions(true);\n this.language = event.target.value.toLowerCase();\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.quality)) {\n // Settings - Quality\n handlerProxy.call(this, event, this.config.listeners.quality, () => {\n this.quality = event.target.value;\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.speed)) {\n // Settings - Speed\n handlerProxy.call(this, event, this.config.listeners.speed, () => {\n this.speed = parseFloat(event.target.value);\n });\n } else if (utils.matches(event.target, this.config.selectors.buttons.loop)) {\n // Settings - Looping\n // TODO: use toggle buttons\n handlerProxy.call(this, event, this.config.listeners.loop, () => {\n // TODO: This should be done in the method itself I think\n // var value = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type');\n\n this.warn('Set loop');\n });\n }\n });\n\n // Seek\n utils.proxy(this.elements.inputs.seek, inputEvent, this.config.listeners.seek, event => {\n this.currentTime = event.target.value / event.target.max * this.duration;\n });\n\n // Volume\n utils.proxy(this.elements.inputs.volume, inputEvent, this.config.listeners.volume, event => {\n this.setVolume(event.target.value);\n });\n\n // Polyfill for lower fill in <input type=\"range\"> for webkit\n if (this.browser.isWebkit) {\n utils.on(utils.getElements.call(this, 'input[type=\"range\"]'), 'input', event => {\n controls.updateRangeFill.call(this, event.target);\n });\n }\n\n // Seek tooltip\n utils.on(this.elements.progress, 'mouseenter mouseleave mousemove', event =>\n ui.updateSeekTooltip.call(this, event)\n );\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Toggle controls on mouse events and entering fullscreen\n utils.on(\n this.elements.container,\n 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen',\n event => {\n this.toggleControls(event);\n }\n );\n\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mouseenter mouseleave', event => {\n this.elements.controls.hover = event.type === 'mouseenter';\n });\n\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {\n this.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);\n });\n\n // Focus in/out on controls\n // TODO: Check we need capture here\n utils.on(\n this.elements.controls,\n 'focus blur',\n event => {\n this.toggleControls(event);\n },\n true\n );\n }\n\n // Mouse wheel for volume\n utils.proxy(\n this.elements.inputs.volume,\n 'wheel',\n this.config.listeners.volume,\n event => {\n // Detect \"natural\" scroll - suppored on OS X Safari only\n // Other browsers on OS X will be inverted until support improves\n const inverted = event.webkitDirectionInvertedFromDevice;\n const step = 1 / 50;\n let direction = 0;\n\n // Scroll down (or up on natural) to decrease\n if (event.deltaY < 0 || event.deltaX > 0) {\n if (inverted) {\n this.decreaseVolume(step);\n direction = -1;\n } else {\n this.increaseVolume(step);\n direction = 1;\n }\n }\n\n // Scroll up (or down on natural) to increase\n if (event.deltaY > 0 || event.deltaX < 0) {\n if (inverted) {\n this.increaseVolume(step);\n direction = 1;\n } else {\n this.decreaseVolume(step);\n direction = -1;\n }\n }\n\n // Don't break page scrolling at max and min\n if ((direction === 1 && this.media.volume < 1) || (direction === -1 && this.media.volume > 0)) {\n event.preventDefault();\n }\n },\n false\n );\n\n // Handle user exiting fullscreen by escaping etc\n if (fullscreen.enabled) {\n utils.on(document, fullscreen.eventType, event => {\n this.toggleFullscreen(event);\n });\n }\n },\n};\n\nexport default listeners;\n","// ==========================================================================\n// Plyr UI\n// ==========================================================================\n\nimport utils from './utils';\nimport captions from './captions';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport listeners from './listeners';\nimport storage from './storage';\n\nconst ui = {\n addStyleHook() {\n utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);\n utils.toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui);\n },\n\n // Toggle native HTML5 media controls\n toggleNativeControls(toggle) {\n if (toggle && this.isHTML5) {\n this.media.setAttribute('controls', '');\n } else {\n this.media.removeAttribute('controls');\n }\n },\n\n // Setup the UI\n build() {\n // Re-attach media element listeners\n // TODO: Use event bubbling\n listeners.media.call(this);\n\n // Don't setup interface if no support\n if (!this.supported.ui) {\n this.warn(`Basic support only for ${this.type}`);\n\n // Remove controls\n utils.removeElement.call(this, 'controls');\n\n // Remove large play\n utils.removeElement.call(this, 'buttons.play');\n\n // Restore native controls\n ui.toggleNativeControls.call(this, true);\n\n // Bail\n return;\n }\n\n // Inject custom controls if not present\n if (!utils.is.htmlElement(this.elements.controls)) {\n // Inject custom controls\n controls.inject.call(this);\n\n // Re-attach control listeners\n listeners.controls.call(this);\n }\n\n // If there's no controls, bail\n if (!utils.is.htmlElement(this.elements.controls)) {\n return;\n }\n\n // Remove native controls\n ui.toggleNativeControls.call(this);\n\n // Setup fullscreen\n fullscreen.setup.call(this);\n\n // Captions\n captions.setup.call(this);\n\n // Set volume\n this.volume = null;\n ui.updateVolume.call(this);\n\n // Set playback speed\n this.speed = null;\n\n // Set loop\n // this.setLoop();\n\n // Reset time display\n ui.timeUpdate.call(this);\n\n // Update the UI\n ui.checkPlaying.call(this);\n\n this.ready = true;\n\n // Ready event at end of execution stack\n utils.dispatchEvent.call(this, this.media, 'ready');\n\n // Autoplay\n if (this.config.autoplay) {\n this.play();\n }\n },\n\n // Show the duration on metadataloaded\n displayDuration() {\n if (!this.supported.ui) {\n return;\n }\n\n // If there's only one time display, display duration there\n if (!this.elements.display.duration && this.config.displayDuration && this.media.paused) {\n ui.updateTimeDisplay.call(this, this.duration, this.elements.display.currentTime);\n }\n\n // If there's a duration element, update content\n if (this.elements.display.duration) {\n ui.updateTimeDisplay.call(this, this.duration, this.elements.display.duration);\n }\n\n // Update the tooltip (if visible)\n ui.updateSeekTooltip.call(this);\n },\n\n // Setup aria attribute for play and iframe title\n setTitle() {\n // Find the current text\n let label = this.config.i18n.play;\n\n // If there's a media title set, use that for the label\n if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) {\n label += `, ${this.config.title}`;\n\n // Set container label\n this.elements.container.setAttribute('aria-label', this.config.title);\n }\n\n // If there's a play button, set label\n if (this.supported.ui) {\n if (utils.is.htmlElement(this.elements.buttons.play)) {\n this.elements.buttons.play.setAttribute('aria-label', label);\n }\n if (utils.is.htmlElement(this.elements.buttons.playLarge)) {\n this.elements.buttons.playLarge.setAttribute('aria-label', label);\n }\n }\n\n // Set iframe title\n // https://github.com/sampotts/plyr/issues/124\n if (this.isEmbed) {\n const iframe = utils.getElement.call(this, 'iframe');\n\n if (!utils.is.htmlElement(iframe)) {\n return;\n }\n\n // Default to media type\n const title = !utils.is.empty(this.config.title) ? this.config.title : 'video';\n\n iframe.setAttribute('title', this.config.i18n.frameTitle.replace('{title}', title));\n }\n },\n\n // Check playing state\n checkPlaying() {\n utils.toggleClass(this.elements.container, this.config.classNames.playing, !this.media.paused);\n\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.media.paused);\n\n this.toggleControls(this.media.paused);\n },\n\n // Update volume UI and storage\n updateVolume() {\n // Update the <input type=\"range\"> if present\n if (this.supported.ui) {\n const value = this.media.muted ? 0 : this.media.volume;\n\n if (this.elements.inputs.volume) {\n ui.setRange.call(this, this.elements.inputs.volume, value);\n }\n }\n\n // Update the volume in storage\n storage.set.call(this, {\n volume: this.media.volume,\n });\n\n // Toggle class if muted\n utils.toggleClass(this.elements.container, this.config.classNames.muted, this.media.muted);\n\n // Update checkbox for mute state\n if (this.supported.ui && this.elements.buttons.mute) {\n utils.toggleState(this.elements.buttons.mute, this.media.muted);\n }\n },\n\n // Check if media is loading\n checkLoading(event) {\n this.loading = event.type === 'waiting';\n\n // Clear timer\n clearTimeout(this.timers.loading);\n\n // Timer to prevent flicker when seeking\n this.timers.loading = setTimeout(() => {\n // Toggle container class hook\n utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Show controls if loading, hide if done\n this.toggleControls(this.loading);\n }, this.loading ? 250 : 0);\n },\n\n // Update seek value and lower fill\n setRange(target, value) {\n if (!utils.is.htmlElement(target)) {\n return;\n }\n\n target.value = value;\n\n // Webkit range fill\n controls.updateRangeFill.call(this, target);\n },\n\n // Set <progress> value\n setProgress(target, input) {\n // Default to 0\n const value = !utils.is.undefined(input) ? input : 0;\n const progress = !utils.is.undefined(target) ? target : this.elements.display.buffer;\n\n // Update value and label\n if (utils.is.htmlElement(progress)) {\n progress.value = value;\n\n // Update text label inside\n const label = progress.getElementsByTagName('span')[0];\n if (utils.is.htmlElement(label)) {\n label.childNodes[0].nodeValue = value;\n }\n }\n },\n\n // Update <progress> elements\n updateProgress(event) {\n if (!this.supported.ui) {\n return;\n }\n\n let value = 0;\n\n if (event) {\n switch (event.type) {\n // Video playing\n case 'timeupdate':\n case 'seeking':\n value = utils.getPercentage(this.currentTime, this.duration);\n\n // Set seek range value only if it's a 'natural' time event\n if (event.type === 'timeupdate') {\n ui.setRange.call(this, this.elements.inputs.seek, value);\n }\n\n break;\n\n // Check buffer status\n case 'playing':\n case 'progress':\n value = (() => {\n const { buffered } = this.media;\n\n if (buffered && buffered.length) {\n // HTML5\n return utils.getPercentage(buffered.end(0), this.duration);\n } else if (utils.is.number(buffered)) {\n // YouTube returns between 0 and 1\n return buffered * 100;\n }\n\n return 0;\n })();\n\n ui.setProgress.call(this, this.elements.display.buffer, value);\n\n break;\n\n default:\n break;\n }\n }\n },\n\n // Update the displayed time\n updateTimeDisplay(value, element) {\n // Bail if there's no duration display\n if (!utils.is.htmlElement(element)) {\n return null;\n }\n\n // Fallback to 0\n const time = !Number.isNaN(value) ? value : 0;\n\n let secs = parseInt(time % 60, 10);\n let mins = parseInt((time / 60) % 60, 10);\n const hours = parseInt((time / 60 / 60) % 60, 10);\n\n // Do we need to display hours?\n const displayHours = parseInt((this.duration / 60 / 60) % 60, 10) > 0;\n\n // Ensure it's two digits. For example, 03 rather than 3.\n secs = `0${secs}`.slice(-2);\n mins = `0${mins}`.slice(-2);\n\n // Generate display\n const display = `${(displayHours ? `${hours}:` : '') + mins}:${secs}`;\n\n // Render\n element.textContent = display;\n\n // Return for looping\n return display;\n },\n\n // Handle time change event\n timeUpdate(event) {\n // Duration\n ui.updateTimeDisplay.call(this, this.currentTime, this.elements.display.currentTime);\n\n // Ignore updates while seeking\n if (event && event.type === 'timeupdate' && this.media.seeking) {\n return;\n }\n\n // Playing progress\n ui.updateProgress.call(this, event);\n },\n\n // Update hover tooltip for seeking\n updateSeekTooltip(event) {\n // Bail if setting not true\n if (\n !this.config.tooltips.seek ||\n !utils.is.htmlElement(this.elements.inputs.seek) ||\n !utils.is.htmlElement(this.elements.display.seekTooltip) ||\n this.duration === 0\n ) {\n return;\n }\n\n // Calculate percentage\n const clientRect = this.elements.inputs.seek.getBoundingClientRect();\n let percent = 0;\n const visible = `${this.config.classNames.tooltip}--visible`;\n\n // Determine percentage, if already visible\n if (utils.is.event(event)) {\n percent = 100 / clientRect.width * (event.pageX - clientRect.left);\n } else if (utils.hasClass(this.elements.display.seekTooltip, visible)) {\n percent = this.elements.display.seekTooltip.style.left.replace('%', '');\n } else {\n return;\n }\n\n // Set bounds\n if (percent < 0) {\n percent = 0;\n } else if (percent > 100) {\n percent = 100;\n }\n\n // Display the time a click would seek to\n ui.updateTimeDisplay.call(this, this.duration / 100 * percent, this.elements.display.seekTooltip);\n\n // Set position\n this.elements.display.seekTooltip.style.left = `${percent}%`;\n\n // Show/hide the tooltip\n // If the event is a moues in/out and percentage is inside bounds\n if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {\n utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter');\n }\n },\n};\n\nexport default ui;\n","// ==========================================================================\n// YouTube plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport controls from './../controls';\nimport ui from './../ui';\n\n/* Object.defineProperty(input, \"value\", {\n get: function() {return this._value;},\n set: function(v) {\n // Do your stuff\n this._value = v;\n }\n}); */\n\nconst youtube = {\n // Setup YouTube\n setup() {\n const videoId = utils.parseYouTubeId(this.embedId);\n\n // Remove old containers\n const containers = utils.getElements.call(this, `[id^=\"${this.type}-\"]`);\n Array.from(containers).forEach(utils.removeElement);\n\n // Add embed class for responsive\n utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set ID\n this.media.setAttribute('id', utils.generateId(this.type));\n\n // Setup API\n if (utils.is.object(window.YT)) {\n youtube.ready.call(this, videoId);\n } else {\n // Load the API\n utils.loadScript(this.config.urls.youtube.api);\n\n // Setup callback for the API\n window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];\n\n // Add to queue\n window.onYouTubeReadyCallbacks.push(() => {\n youtube.ready.call(this, videoId);\n });\n\n // Set callback to process queue\n window.onYouTubeIframeAPIReady = () => {\n window.onYouTubeReadyCallbacks.forEach(callback => {\n callback();\n });\n };\n }\n },\n\n // Handle YouTube API ready\n ready(videoId) {\n const player = this;\n\n // Setup instance\n // https://developers.google.com/youtube/iframe_api_reference\n player.embed = new window.YT.Player(player.media.id, {\n videoId,\n playerVars: {\n autoplay: player.config.autoplay ? 1 : 0, // Autoplay\n controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported\n rel: 0, // No related vids\n showinfo: 0, // Hide info\n iv_load_policy: 3, // Hide annotations\n modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused)\n disablekb: 1, // Disable keyboard as we handle it\n playsinline: 1, // Allow iOS inline playback\n\n // Tracking for stats\n origin: window && window.location.hostname,\n widget_referrer: window && window.location.href,\n\n // Captions is flaky on YouTube\n // cc_load_policy: (this.captions.active ? 1 : 0),\n // cc_lang_pref: 'en',\n },\n events: {\n onError(event) {\n utils.dispatchEvent.call(player, player.media, 'error', true, {\n code: event.data,\n embed: event.target,\n });\n },\n onPlaybackQualityChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current quality\n player.media.quality = instance.getPlaybackQuality();\n\n utils.dispatchEvent.call(player, player.media, 'qualitychange');\n },\n onPlaybackRateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current speed\n player.media.playbackRate = instance.getPlaybackRate();\n\n utils.dispatchEvent.call(player, player.media, 'ratechange');\n },\n onReady(event) {\n // Get the instance\n const instance = event.target;\n\n // Create a faux HTML5 API using the YouTube API\n player.media.play = () => {\n instance.playVideo();\n player.media.paused = false;\n };\n player.media.pause = () => {\n instance.pauseVideo();\n player.media.paused = true;\n };\n player.media.stop = () => {\n instance.stopVideo();\n player.media.paused = true;\n };\n player.media.duration = instance.getDuration();\n player.media.paused = true;\n player.media.muted = instance.isMuted();\n player.media.currentTime = 0;\n\n // Get available speeds\n if (player.config.controls.includes('settings') && player.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(player, instance.getAvailablePlaybackRates());\n }\n\n // Set title\n player.config.title = instance.getVideoData().title;\n\n // Set the tabindex to avoid focus entering iframe\n if (player.supported.ui) {\n player.media.setAttribute('tabindex', -1);\n }\n\n // Rebuild UI\n ui.build.call(player);\n\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n\n // Reset timer\n window.clearInterval(player.timers.buffering);\n\n // Setup buffering\n player.timers.buffering = window.setInterval(() => {\n // Get loaded % from YouTube\n player.media.buffered = instance.getVideoLoadedFraction();\n\n // Trigger progress only when we actually buffer something\n if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {\n utils.dispatchEvent.call(player, player.media, 'progress');\n }\n\n // Set last buffer point\n player.media.lastBuffered = player.media.buffered;\n\n // Bail if we're at 100%\n if (player.media.buffered === 1) {\n window.clearInterval(player.timers.buffering);\n\n // Trigger event\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n }, 200);\n },\n onStateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Reset timer\n window.clearInterval(player.timers.playing);\n\n // Handle events\n // -1 Unstarted\n // 0 Ended\n // 1 Playing\n // 2 Paused\n // 3 Buffering\n // 5 Video cued\n switch (event.data) {\n case 0:\n // YouTube doesn't support loop for a single video, so mimick it.\n if (player.config.loop.active) {\n // YouTube needs a call to `stopVideo` before playing again\n instance.stopVideo();\n instance.playVideo();\n\n break;\n }\n\n player.media.paused = true;\n\n utils.dispatchEvent.call(player, player.media, 'ended');\n\n break;\n\n case 1:\n player.media.paused = false;\n\n // If we were seeking, fire seeked event\n if (player.media.seeking) {\n utils.dispatchEvent.call(player, player.media, 'seeked');\n }\n\n player.media.seeking = false;\n\n utils.dispatchEvent.call(player, player.media, 'play');\n utils.dispatchEvent.call(player, player.media, 'playing');\n\n // Poll to get playback progress\n player.timers.playing = window.setInterval(() => {\n player.media.currentTime = instance.getCurrentTime();\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n }, 100);\n\n // Check duration again due to YouTube bug\n // https://github.com/sampotts/plyr/issues/374\n // https://code.google.com/p/gdata-issues/issues/detail?id=8690\n if (player.media.duration !== instance.getDuration()) {\n player.media.duration = instance.getDuration();\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n }\n\n // Get quality\n controls.setQualityMenu.call(player, instance.getAvailableQualityLevels());\n\n break;\n\n case 2:\n player.media.paused = true;\n\n utils.dispatchEvent.call(player, player.media, 'pause');\n\n break;\n\n default:\n break;\n }\n\n utils.dispatchEvent.call(player, player.elements.container, 'statechange', false, {\n code: event.data,\n });\n },\n },\n });\n },\n};\n\nexport default youtube;\n","// ==========================================================================\n// Vimeo plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport captions from './../captions';\nimport ui from './../ui';\n\nconst vimeo = {\n // Setup YouTube\n setup() {\n // Remove old containers\n const containers = utils.getElements.call(this, `[id^=\"${this.type}-\"]`);\n Array.from(containers).forEach(utils.removeElement);\n\n // Add embed class for responsive\n utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set ID\n this.media.setAttribute('id', utils.generateId(this.type));\n\n // Load the API if not already\n if (!utils.is.object(window.Vimeo)) {\n utils.loadScript(this.config.urls.vimeo.api);\n // Wait for load\n const vimeoTimer = window.setInterval(() => {\n if (utils.is.object(window.Vimeo)) {\n window.clearInterval(vimeoTimer);\n vimeo.ready.call(this);\n }\n }, 50);\n } else {\n vimeo.ready.call(this);\n }\n },\n\n // Ready\n ready() {\n const player = this;\n\n // Get Vimeo params for the iframe\n const options = {\n loop: this.config.loop.active,\n autoplay: this.config.autoplay,\n byline: false,\n portrait: false,\n title: false,\n transparent: 0,\n };\n const params = utils.buildUrlParameters(options);\n const id = utils.parseVimeoId(this.embedId);\n\n // Build an iframe\n const iframe = utils.createElement('iframe');\n const src = `https://player.vimeo.com/video/${id}?${params}`;\n iframe.setAttribute('src', src);\n iframe.setAttribute('allowfullscreen', '');\n player.media.appendChild(iframe);\n\n // Setup instance\n // https://github.com/vimeo/this.js\n player.embed = new window.Vimeo.Player(iframe);\n\n // Create a faux HTML5 API using the Vimeo API\n player.media.play = () => {\n player.embed.play();\n player.media.paused = false;\n };\n player.media.pause = () => {\n player.embed.pause();\n player.media.paused = true;\n };\n player.media.stop = () => {\n player.embed.stop();\n player.media.paused = true;\n };\n\n player.media.paused = true;\n player.media.currentTime = 0;\n\n // Rebuild UI\n ui.build.call(player);\n\n player.embed.getCurrentTime().then(value => {\n player.media.currentTime = value;\n utils.dispatchEvent.call(this, this.media, 'timeupdate');\n });\n\n player.embed.getDuration().then(value => {\n player.media.duration = value;\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n });\n\n // Get captions\n player.embed.getTextTracks().then(tracks => {\n player.captions.tracks = tracks;\n\n captions.setup.call(player);\n });\n\n player.embed.on('cuechange', data => {\n let cue = null;\n\n if (data.cues.length) {\n cue = utils.stripHTML(data.cues[0].text);\n }\n\n captions.set.call(player, cue);\n });\n\n player.embed.on('loaded', () => {\n if (utils.is.htmlElement(player.embed.element) && player.supported.ui) {\n const frame = player.embed.element;\n\n // Fix Vimeo controls issue\n // https://github.com/sampotts/plyr/issues/697\n // frame.src = `${frame.src}&transparent=0`;\n\n // Fix keyboard focus issues\n // https://github.com/sampotts/plyr/issues/317\n frame.setAttribute('tabindex', -1);\n }\n });\n\n player.embed.on('play', () => {\n player.media.paused = false;\n utils.dispatchEvent.call(player, player.media, 'play');\n utils.dispatchEvent.call(player, player.media, 'playing');\n });\n\n player.embed.on('pause', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'pause');\n });\n\n this.embed.on('timeupdate', data => {\n this.media.seeking = false;\n this.media.currentTime = data.seconds;\n utils.dispatchEvent.call(this, this.media, 'timeupdate');\n });\n\n this.embed.on('progress', data => {\n this.media.buffered = data.percent;\n utils.dispatchEvent.call(this, this.media, 'progress');\n\n if (parseInt(data.percent, 10) === 1) {\n // Trigger event\n utils.dispatchEvent.call(this, this.media, 'canplaythrough');\n }\n });\n\n this.embed.on('seeked', () => {\n this.media.seeking = false;\n utils.dispatchEvent.call(this, this.media, 'seeked');\n utils.dispatchEvent.call(this, this.media, 'play');\n });\n\n this.embed.on('ended', () => {\n this.media.paused = true;\n utils.dispatchEvent.call(this, this.media, 'ended');\n });\n },\n};\n\nexport default vimeo;\n","// ==========================================================================\n// Plyr Media\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport youtube from './plugins/youtube';\nimport vimeo from './plugins/vimeo';\nimport ui from './ui';\n\nconst media = {\n // Setup media\n setup() {\n // If there's no media, bail\n if (!this.media) {\n this.warn('No media element found!');\n return;\n }\n\n // Add type class\n utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', this.type), true);\n\n // Add video class for embeds\n // This will require changes if audio embeds are added\n if (this.isEmbed) {\n utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);\n }\n\n if (this.supported.ui) {\n // Check for picture-in-picture support\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.pip.supported,\n support.pip && this.type === 'video'\n );\n\n // Check for airplay support\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.airplay.supported,\n support.airplay && this.isHTML5\n );\n\n // If there's no autoplay attribute, assume the video is stopped and add state class\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.config.autoplay);\n\n // Add iOS class\n utils.toggleClass(this.elements.container, this.config.classNames.isIos, this.browser.isIos);\n\n // Add touch class\n utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch);\n }\n\n // Inject the player wrapper\n if (['video', 'youtube', 'vimeo'].includes(this.type)) {\n // Create the wrapper div\n this.elements.wrapper = utils.createElement('div', {\n class: this.config.classNames.video,\n });\n\n // Wrap the video in a container\n utils.wrap(this.media, this.elements.wrapper);\n }\n\n // Embeds\n if (this.isEmbed) {\n switch (this.type) {\n case 'youtube':\n youtube.setup.call(this);\n break;\n\n case 'vimeo':\n vimeo.setup.call(this);\n break;\n\n default:\n break;\n }\n }\n\n ui.setTitle.call(this);\n },\n\n // Cancel current network requests\n // See https://github.com/sampotts/plyr/issues/174\n cancelRequests() {\n if (!this.isHTML5) {\n return;\n }\n\n // Remove child sources\n Array.from(this.media.querySelectorAll('source')).forEach(utils.removeElement);\n\n // Set blank video src attribute\n // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error\n // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection\n this.media.setAttribute('src', this.config.blankVideo);\n\n // Load the new empty source\n // This will cancel existing requests\n // See https://github.com/sampotts/plyr/issues/174\n this.media.load();\n\n // Debugging\n this.log('Cancelled network requests');\n },\n};\n\nexport default media;\n","// ==========================================================================\n// Plyr source update\n// ==========================================================================\n\nimport types from './types';\nimport utils from './utils';\nimport media from './media';\nimport ui from './ui';\nimport support from './support';\n\nconst source = {\n // Add elements to HTML5 media (source, tracks, etc)\n insertElements(type, attributes) {\n if (utils.is.string(attributes)) {\n utils.insertElement(type, this.media, {\n src: attributes,\n });\n } else if (utils.is.array(attributes)) {\n this.warn(attributes);\n\n attributes.forEach(attribute => {\n utils.insertElement(type, this.media, attribute);\n });\n }\n },\n\n // Update source\n // Sources are not checked for support so be careful\n change(input) {\n if (!utils.is.object(input) || !('sources' in input) || !input.sources.length) {\n this.warn('Invalid source format');\n return;\n }\n\n // Cancel current network requests\n media.cancelRequests.call(this);\n\n // Destroy instance and re-setup\n this.destroy.call(\n this,\n () => {\n // TODO: Reset menus here\n\n // Remove elements\n utils.removeElement(this.media);\n this.media = null;\n\n // Reset class name\n if (utils.is.htmlElement(this.elements.container)) {\n this.elements.container.removeAttribute('class');\n }\n\n // Set the type\n if ('type' in input) {\n this.type = input.type;\n\n // Get child type for video (it might be an embed)\n if (this.type === 'video') {\n const firstSource = input.sources[0];\n\n if ('type' in firstSource && types.embed.includes(firstSource.type)) {\n this.type = firstSource.type;\n }\n }\n }\n\n // Check for support\n this.supported = support.check(this.type, this.config.inline);\n\n // Create new markup\n switch (this.type) {\n case 'video':\n this.media = utils.createElement('video');\n break;\n\n case 'audio':\n this.media = utils.createElement('audio');\n break;\n\n case 'youtube':\n case 'vimeo':\n this.media = utils.createElement('div');\n this.embedId = input.sources[0].src;\n break;\n\n default:\n break;\n }\n\n // Inject the new element\n this.elements.container.appendChild(this.media);\n\n // Autoplay the new source?\n if (utils.is.boolean(input.autoplay)) {\n this.config.autoplay = input.autoplay;\n }\n\n // Set attributes for audio and video\n if (this.isHTML5) {\n if (this.config.crossorigin) {\n this.media.setAttribute('crossorigin', '');\n }\n if (this.config.autoplay) {\n this.media.setAttribute('autoplay', '');\n }\n if ('poster' in input) {\n this.media.setAttribute('poster', input.poster);\n }\n if (this.config.loop.active) {\n this.media.setAttribute('loop', '');\n }\n if (this.config.muted) {\n this.media.setAttribute('muted', '');\n }\n if (this.config.inline) {\n this.media.setAttribute('playsinline', '');\n }\n }\n\n // Restore class hooks\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.captions.active,\n this.supported.ui && this.captions.enabled\n );\n\n ui.addStyleHook.call(this);\n\n // Set new sources for html5\n if (this.isHTML5) {\n source.insertElements.call(this, 'source', input.sources);\n }\n\n // Set video title\n this.config.title = input.title;\n\n // Set up from scratch\n media.setup.call(this);\n\n // HTML5 stuff\n if (this.isHTML5) {\n // Setup captions\n if ('tracks' in input) {\n source.insertElements.call(this, 'track', input.tracks);\n }\n\n // Load HTML5 sources\n this.media.load();\n }\n\n // If HTML5 or embed but not fully supported, setupInterface and call ready now\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n // Setup interface\n ui.build.call(this);\n }\n },\n true\n );\n },\n};\n\nexport default source;\n","// ==========================================================================\n// Plyr\n// plyr.js v3.0.0\n// https://github.com/sampotts/plyr\n// License: The MIT License (MIT)\n// ==========================================================================\n\n/* global jQuery */\n\nimport defaults from './defaults';\nimport types from './types';\nimport support from './support';\nimport utils from './utils';\n\nimport captions from './captions';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport media from './media';\nimport storage from './storage';\nimport source from './source';\nimport ui from './ui';\n\n// Globals\nlet scrollPosition = {\n x: 0,\n y: 0,\n};\n\n// Plyr instance\nclass Plyr {\n constructor(target, options) {\n this.timers = {};\n this.ready = false;\n\n // Set the media element\n this.media = target;\n\n // String selector passed\n if (utils.is.string(this.media)) {\n this.media = document.querySelectorAll(this.media);\n }\n\n // jQuery, NodeList or Array passed, use first element\n if (\n (window.jQuery && this.media instanceof jQuery) ||\n utils.is.nodeList(this.media) ||\n utils.is.array(this.media)\n ) {\n // eslint-disable-next-line\n this.media = this.media[0];\n }\n\n // Set config\n this.config = utils.extend(\n {},\n defaults,\n options,\n (() => {\n try {\n return JSON.parse(this.media.getAttribute('data-plyr'));\n } catch (e) {\n return null;\n }\n })()\n );\n\n // Elements cache\n this.elements = {\n container: null,\n buttons: {},\n display: {},\n progress: {},\n inputs: {},\n settings: {\n menu: null,\n panes: {},\n tabs: {},\n },\n captions: null,\n };\n\n // Captions\n this.captions = {\n enabled: null,\n tracks: null,\n currentTrack: null,\n };\n\n // Fullscreen\n this.fullscreen = {\n active: false,\n };\n\n // Options\n this.options = {\n speed: [],\n quality: [],\n };\n\n // Debugging\n this.log = () => {};\n this.warn = () => {};\n this.error = () => {};\n if (this.config.debug && 'console' in window) {\n this.log = console.log; // eslint-disable-line\n this.warn = console.warn; // eslint-disable-line\n this.error = console.error; // eslint-disable-line\n this.log('Debugging enabled');\n }\n\n // Log config options and support\n this.log('Config', this.config);\n this.log('Support', support);\n\n // We need an element to setup\n if (this.media === null || utils.is.undefined(this.media) || !utils.is.htmlElement(this.media)) {\n this.error('Setup failed: no suitable element passed');\n return;\n }\n\n // Bail if the element is initialized\n if (this.media.plyr) {\n this.warn('Target already setup');\n return;\n }\n\n // Bail if not enabled\n if (!this.config.enabled) {\n this.error('Setup failed: disabled by config');\n return;\n }\n\n // Bail if disabled or no basic support\n // You may want to disable certain UAs etc\n if (!support.check().api) {\n this.error('Setup failed: no support');\n return;\n }\n\n // Cache original element state for .destroy()\n this.elements.original = this.media.cloneNode(true);\n\n // Set media type based on tag or data attribute\n // Supported: video, audio, vimeo, youtube\n const type = this.media.tagName.toLowerCase();\n\n // Different setup based on type\n switch (type) {\n // TODO: Handle passing an iframe for true progressive enhancement\n // case 'iframe':\n case 'div':\n this.type = this.media.getAttribute('data-type');\n this.embedId = this.media.getAttribute('data-video-id');\n\n if (utils.is.empty(this.type)) {\n this.error('Setup failed: embed type missing');\n return;\n }\n\n if (utils.is.empty(this.embedId)) {\n this.error('Setup failed: video id missing');\n return;\n }\n\n // Clean up\n this.media.removeAttribute('data-type');\n this.media.removeAttribute('data-video-id');\n break;\n\n case 'video':\n case 'audio':\n this.type = type;\n\n if (this.media.getAttribute('crossorigin') !== null) {\n this.config.crossorigin = true;\n }\n if (this.media.getAttribute('autoplay') !== null) {\n this.config.autoplay = true;\n }\n if (this.media.getAttribute('playsinline') !== null) {\n this.config.inline = true;\n }\n if (this.media.getAttribute('muted') !== null) {\n this.config.muted = true;\n }\n if (this.media.getAttribute('loop') !== null) {\n this.config.loop.active = true;\n }\n break;\n\n default:\n this.error('Setup failed: unsupported type');\n return;\n }\n\n // Sniff out the browser\n this.browser = utils.getBrowser();\n\n // Load saved settings from localStorage\n this.storage = storage.setup.call(this);\n\n // Check for support again but with type\n this.supported = support.check(this.type, this.config.inline);\n\n // If no support for even API, bail\n if (!this.supported.api) {\n this.error('Setup failed: no support');\n return;\n }\n\n // Store reference\n this.media.plyr = this;\n\n // Wrap media\n this.elements.container = utils.createElement('div');\n utils.wrap(this.media, this.elements.container);\n\n // Add style hook\n ui.addStyleHook.call(this);\n\n // Setup media\n media.setup.call(this);\n\n // Listen for events if debugging\n if (this.config.debug) {\n utils.on(this.elements.container, this.config.events.join(' '), event => {\n this.log(`event: ${event.type}`);\n });\n }\n\n // Setup interface\n // If embed but not fully supported, build interface now to avoid flash of controls\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n ui.build.call(this);\n }\n }\n\n // API\n // ---------------------------------------\n\n get isHTML5() {\n return types.html5.includes(this.type);\n }\n get isEmbed() {\n return types.embed.includes(this.type);\n }\n\n // Play\n play() {\n if ('play' in this.media) {\n this.media.play();\n }\n\n // Allow chaining\n return this;\n }\n\n // Pause\n pause() {\n if ('pause' in this.media) {\n this.media.pause();\n }\n\n // Allow chaining\n return this;\n }\n\n // Toggle playback\n togglePlay(toggle) {\n // True toggle if nothing passed\n if ((!utils.is.boolean(toggle) && this.media.paused) || toggle) {\n return this.play();\n }\n\n return this.pause();\n }\n\n // Stop\n stop() {\n return this.restart().pause();\n }\n\n // Restart\n restart() {\n this.currentTime = 0;\n return this;\n }\n\n // Rewind\n rewind(seekTime) {\n this.currentTime = Math.min(\n this.currentTime - (utils.is.number(seekTime) ? seekTime : this.config.seekTime),\n 0\n );\n return this;\n }\n\n // Fast forward\n forward(seekTime) {\n this.currentTime = Math.max(\n this.currentTime + (utils.is.number(seekTime) ? seekTime : this.config.seekTime),\n this.duration\n );\n return this;\n }\n\n // Seek to time\n // The input parameter can be an event or a number\n set currentTime(input) {\n let targetTime = 0;\n\n if (utils.is.number(input)) {\n targetTime = input;\n }\n\n // Normalise targetTime\n if (targetTime < 0) {\n targetTime = 0;\n } else if (targetTime > this.duration) {\n targetTime = this.duration;\n }\n\n // Set the current time\n // TODO: This should be included in the \"adapters\"\n // Embeds\n if (this.isEmbed) {\n // Get current paused state\n const { paused } = this.media;\n\n switch (this.type) {\n case 'youtube':\n this.embed.seekTo(targetTime);\n break;\n\n case 'vimeo':\n this.embed.setCurrentTime(targetTime);\n break;\n\n default:\n break;\n }\n\n // Restore pause (some will play on seek)\n if (paused) {\n this.pause();\n }\n\n // Set seeking flag\n this.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.call(this, this.media, 'seeking');\n } else {\n this.media.currentTime = targetTime.toFixed(4);\n }\n\n // Logging\n this.log(`Seeking to ${this.currentTime} seconds`);\n }\n\n get currentTime() {\n return Number(this.media.currentTime);\n }\n\n // Get the duration (or custom if set)\n get duration() {\n // Faux duration set via config\n const fauxDuration = parseInt(this.config.duration, 10);\n\n // True duration\n const realDuration = Number(this.media.duration);\n\n // If custom duration is funky, use regular duration\n return !Number.isNaN(fauxDuration) ? fauxDuration : realDuration;\n }\n\n // Set volume\n set volume(value) {\n let volume = value;\n const max = 1;\n const min = 0;\n const isSet = !utils.is.undefined(volume);\n\n if (utils.is.string(volume)) {\n volume = parseFloat(volume);\n }\n\n // Load volume from storage if no value specified\n if (!utils.is.number(volume)) {\n ({ volume } = this.storage);\n }\n\n // Use config if all else fails\n if (!utils.is.number(volume)) {\n ({ volume } = this.config);\n }\n\n // Maximum is volumeMax\n if (volume > max) {\n volume = max;\n }\n // Minimum is volumeMin\n if (volume < min) {\n volume = min;\n }\n\n // Set the player volume\n this.media.volume = volume;\n\n // Trigger volumechange for embeds\n if (this.isEmbed) {\n // Set media volume\n switch (this.type) {\n case 'youtube':\n this.embed.setVolume(this.media.volume * 100);\n break;\n\n case 'vimeo':\n this.embed.setVolume(this.media.volume);\n break;\n\n default:\n break;\n }\n\n utils.dispatchEvent.call(this, this.media, 'volumechange');\n }\n\n // Toggle muted state\n if (volume === 0) {\n this.toggleMute(true);\n } else if (this.media.muted && isSet) {\n this.toggleMute();\n }\n\n return this;\n }\n\n get volume() {\n return this.media.volume;\n }\n\n // Increase volume\n increaseVolume(step) {\n const volume = this.media.muted ? 0 : this.media.volume;\n\n return this.setVolume(volume + utils.is.number(step) ? step : 1);\n }\n\n // Decrease volume\n decreaseVolume(step) {\n const volume = this.media.muted ? 0 : this.media.volume;\n\n return this.setVolume(volume - utils.is.number(step) ? step : 1);\n }\n\n // Toggle mute\n toggleMute(mute) {\n // If the method is called without parameter, toggle based on current value\n const toggle = utils.is.boolean(mute) ? mute : !this.media.muted;\n\n // Set button state\n utils.toggleState(this.elements.buttons.mute, toggle);\n\n // Set mute on the player\n this.media.muted = toggle;\n\n // If volume is 0 after unmuting, restore default volume\n if (!this.media.muted && this.media.volume === 0) {\n this.setVolume(this.config.volume);\n }\n\n // Embeds\n if (this.isEmbed) {\n switch (this.type) {\n case 'youtube':\n this.embed[this.media.muted ? 'mute' : 'unMute']();\n break;\n\n case 'vimeo':\n this.embed.setVolume(this.media.muted ? 0 : this.config.volume);\n break;\n\n default:\n break;\n }\n\n // Trigger volumechange for embeds\n utils.dispatchEvent.call(this, this.media, 'volumechange');\n }\n\n return this;\n }\n\n // Playback speed\n set speed(input) {\n // Load speed from storage or default value\n let speed = utils.is.number(input)\n ? input\n : parseFloat(this.storage.speed || this.speed.selected || this.config.speed.default);\n\n // Set min/max\n if (speed < 0.1) {\n speed = 0.1;\n }\n if (speed > 2.0) {\n speed = 2.0;\n }\n\n if (!this.config.speed.options.includes(speed)) {\n this.warn(`Unsupported speed (${speed})`);\n return;\n }\n\n // Set media speed\n // TODO: Should be in adapter\n switch (this.type) {\n case 'youtube':\n this.embed.setPlaybackRate(speed);\n break;\n\n case 'vimeo':\n speed = null;\n // Vimeo not supported (https://github.com/vimeo/this.js)\n this.warn('Vimeo playback rate change is not supported');\n break;\n\n default:\n this.media.playbackRate = speed;\n break;\n }\n }\n\n get speed() {\n // Set media speed\n // TODO: Should be in adapter\n switch (this.type) {\n case 'youtube':\n return this.embed.getPlaybackRate();\n\n case 'vimeo':\n // Vimeo not supported (https://github.com/vimeo/player.js)\n this.warn('Vimeo playback rate change is not supported');\n return null;\n\n default:\n return this.media.playbackRate;\n }\n }\n\n // Set playback quality\n set quality(input) {\n // Load speed from storage or default value\n const quality = utils.is.string(input)\n ? input\n : parseFloat(this.storage.quality || this.config.quality.selected);\n\n if (!this.config.quality.options.includes(quality)) {\n this.warn(`Unsupported quality option (${quality})`);\n return;\n }\n\n // Set media speed\n switch (this.type) {\n case 'youtube':\n this.utils.dispatchEvent.call(this, this.media, 'qualityrequested', false, {\n quality,\n });\n\n this.embed.setPlaybackQuality(quality);\n\n break;\n\n default:\n this.warn('Quality options are only available for YouTube');\n break;\n }\n }\n\n get quality() {\n // Set media speed\n switch (this.type) {\n case 'youtube':\n return this.embed.getPlaybackQuality();\n\n default:\n this.warn('Quality options are only available for YouTube');\n return null;\n }\n }\n\n // Toggle loop\n // TODO: Finish logic\n // TODO: Set the indicator on load as user may pass loop as config\n loop(input) {\n // Set default to be a true toggle\n const type = ['start', 'end', 'all', 'none', 'toggle'].includes(input) ? input : 'toggle';\n\n switch (type) {\n case 'start':\n if (this.config.loop.end && this.config.loop.end <= this.currentTime) {\n this.config.loop.end = null;\n }\n this.config.loop.start = this.currentTime;\n // this.config.loop.indicator.start = this.elements.display.played.value;\n break;\n\n case 'end':\n if (this.config.loop.start >= this.currentTime) {\n return this;\n }\n this.config.loop.end = this.currentTime;\n // this.config.loop.indicator.end = this.elements.display.played.value;\n break;\n\n case 'all':\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n this.config.loop.indicator.start = 0;\n this.config.loop.indicator.end = 100;\n break;\n\n case 'toggle':\n if (this.config.loop.active) {\n this.config.loop.start = 0;\n this.config.loop.end = null;\n } else {\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n }\n break;\n\n default:\n this.config.loop.start = 0;\n this.config.loop.end = null;\n break;\n }\n\n // Allow chaining\n return this;\n }\n\n // Media source\n set src(input) {\n source.change.call(this, input);\n }\n\n get src() {\n let url;\n\n switch (this.type) {\n case 'youtube':\n url = this.embed.getVideoUrl();\n break;\n\n case 'vimeo':\n this.embed.getVideoUrl.then(value => {\n url = value;\n });\n break;\n\n default:\n url = this.media.currentSrc;\n break;\n }\n\n return url;\n }\n\n // Poster image\n set poster(input) {\n if (this.type !== 'video') {\n this.warn('Poster can only be set on HTML5 video');\n return;\n }\n\n if (utils.is.string(input)) {\n this.media.setAttribute('poster', input);\n }\n }\n\n get poster() {\n if (this.type !== 'video') {\n return null;\n }\n\n return this.media.getAttribute('poster');\n }\n\n // Toggle captions\n toggleCaptions(input) {\n // If there's no full support, or there's no caption toggle\n if (!this.supported.ui || !this.elements.buttons.captions) {\n return this;\n }\n\n // If the method is called without parameter, toggle based on current value\n const show = utils.is.boolean(input)\n ? input\n : this.elements.container.className.indexOf(this.config.classNames.captions.active) === -1;\n\n // Nothing to change...\n if (this.captions.enabled === show) {\n return this;\n }\n\n // Set global\n this.captions.enabled = show;\n\n // Toggle state\n utils.toggleState(this.elements.buttons.captions, this.captions.enabled);\n\n // Add class hook\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.enabled);\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, this.captions.enabled ? 'captionsenabled' : 'captionsdisabled');\n\n // Allow chaining\n return this;\n }\n\n // Caption language\n set language(input) {\n const player = this;\n\n // Nothing specified\n if (utils.is.empty(input)) {\n this.toggleCaptions(false);\n return player;\n }\n\n // Normalize\n const language = input.toLowerCase();\n\n // If nothing to change, bail\n if (this.captions.language === language) {\n return player;\n }\n\n // Reset UI\n this.toggleCaptions(true);\n\n // Update config\n this.captions.language = language;\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, 'captionchange');\n\n // Clear caption\n captions.setCaption.call(this);\n\n // Re-run setup\n captions.setup.call(this);\n\n // Allow chaining\n return this;\n }\n\n get language() {\n return this.captions.language;\n }\n\n // Toggle fullscreen\n // Requires user input event\n toggleFullscreen(event) {\n // Check for native support\n if (fullscreen.enabled) {\n // If it's a fullscreen change event, update the UI\n if (utils.is.event(event) && event.type === fullscreen.eventType) {\n this.fullscreen.active = fullscreen.isFullScreen(this.elements.container);\n } else {\n // Else it's a user request to enter or exit\n if (!this.fullscreen.active) {\n // Request full screen\n fullscreen.requestFullScreen(this.elements.container);\n } else {\n // Bail from fullscreen\n fullscreen.cancelFullScreen();\n }\n\n // Check if we're actually full screen (it could fail)\n this.fullscreen.active = fullscreen.isFullScreen(this.elements.container);\n\n return this;\n }\n } else {\n // Otherwise, it's a simple toggle\n this.fullscreen.active = !this.fullscreen.active;\n\n // Add class hook\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.fullscreen.fallback,\n this.fullscreen.active\n );\n\n // Make sure we don't lose scroll position\n if (this.fullscreen.active) {\n scrollPosition = {\n x: window.pageXOffset || 0,\n y: window.pageYOffset || 0,\n };\n } else {\n window.scrollTo(scrollPosition.x, scrollPosition.y);\n }\n\n // Bind/unbind escape key\n document.body.style.overflow = this.fullscreen.active ? 'hidden' : '';\n }\n\n // Set button state\n if (this.elements.buttons && this.elements.buttons.fullscreen) {\n utils.toggleState(this.elements.buttons.fullscreen, this.fullscreen.active);\n }\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, this.fullscreen.active ? 'enterfullscreen' : 'exitfullscreen');\n\n return this;\n }\n\n // Toggle picture-in-picture\n // TODO: update player with state, support, enabled\n // TODO: detect outside changes\n togglePictureInPicture(input) {\n const player = this;\n const states = {\n pip: 'picture-in-picture',\n inline: 'inline',\n };\n\n // Bail if no support\n if (!support.pip) {\n return player;\n }\n\n // Toggle based on current state if not passed\n const toggle = utils.is.boolean(input) ? input : this.media.webkitPresentationMode === states.inline;\n\n // Toggle based on current state\n this.media.webkitSetPresentationMode(toggle ? states.pip : states.inline);\n\n return this;\n }\n\n // Trigger airplay\n // TODO: update player with state, support, enabled\n airPlay() {\n // Bail if no support\n if (!support.airplay) {\n return this;\n }\n\n // Show dialog\n this.media.webkitShowPlaybackTargetPicker();\n\n return this;\n }\n\n // Show the player controls in fullscreen mode\n toggleControls(toggle) {\n const player = this;\n\n // We need controls of course...\n if (!utils.is.htmlElement(this.elements.controls)) {\n return player;\n }\n\n // Don't hide if config says not to, it's audio, or not ready or loading\n if (!this.supported.ui || !this.config.hideControls || this.type === 'audio') {\n return player;\n }\n\n let delay = 0;\n let show = toggle;\n let isEnterFullscreen = false;\n const loading = utils.hasClass(this.elements.container, this.config.classNames.loading);\n\n // Default to false if no boolean\n if (!utils.is.boolean(toggle)) {\n if (utils.is.event(toggle)) {\n // Is the enter fullscreen event\n isEnterFullscreen = toggle.type === 'enterfullscreen';\n\n // Whether to show controls\n show = ['mousemove', 'touchstart', 'mouseenter', 'focus'].includes(toggle.type);\n\n // Delay hiding on move events\n if (['mousemove', 'touchmove'].includes(toggle.type)) {\n delay = 2000;\n }\n\n // Delay a little more for keyboard users\n if (toggle.type === 'focus') {\n delay = 3000;\n }\n } else {\n show = utils.hasClass(this.elements.container, this.config.classNames.hideControls);\n }\n }\n\n // Clear timer every movement\n window.clearTimeout(this.timers.hover);\n\n // If the mouse is not over the controls, set a timeout to hide them\n if (show || this.media.paused || loading) {\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, false);\n\n // Trigger event\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlsshown');\n }\n\n // Always show controls when paused or if touch\n if (this.media.paused || loading) {\n return player;\n }\n\n // Delay for hiding on touch\n if (support.touch) {\n delay = 3000;\n }\n }\n\n // If toggle is false or if we're playing (regardless of toggle),\n // then set the timer to hide the controls\n if (!show || !this.media.paused) {\n this.timers.hover = window.setTimeout(() => {\n // If the mouse is over the controls (and not entering fullscreen), bail\n if ((this.elements.controls.pressed || this.elements.controls.hover) && !isEnterFullscreen) {\n return;\n }\n\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, true);\n\n // Trigger event and close menu\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlshidden');\n\n if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {\n controls.toggleMenu.call(this, false);\n }\n }\n }, delay);\n }\n\n return this;\n }\n\n // Event listeners\n on(event, callback) {\n utils.on(this.elements.container, event, callback);\n\n return this;\n }\n\n off(event, callback) {\n utils.off(this.elements.container, event, callback);\n\n return this;\n }\n\n // Check for support\n supports(mimeType) {\n return support.mime(this, mimeType);\n }\n\n // Destroy an instance\n // Event listeners are removed when elements are removed\n // http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory\n destroy(callback, soft = false) {\n const done = () => {\n // Reset overflow (incase destroyed while in fullscreen)\n document.body.style.overflow = '';\n\n // GC for embed\n this.embed = null;\n\n // If it's a soft destroy, make minimal changes\n if (soft) {\n utils.removeElement(this.elements.captions);\n utils.removeElement(this.elements.controls);\n utils.removeElement(this.elements.wrapper);\n\n // Clear for GC\n this.elements.captions = null;\n this.elements.controls = null;\n this.elements.wrapper = null;\n\n // Callback\n if (utils.is.function(callback)) {\n callback();\n }\n } else {\n // Replace the container with the original element provided\n const parent = this.elements.container.parentNode;\n\n if (utils.is.htmlElement(parent)) {\n parent.replaceChild(this.elements.original, this.elements.container);\n }\n\n // Event\n utils.dispatchEvent.call(this, this.elements.original, 'destroyed', true);\n\n // Callback\n if (utils.is.function(callback)) {\n callback.call(this.elements.original);\n }\n\n // Clear for GC\n this.elements = null;\n }\n };\n\n // Type specific stuff\n switch (this.type) {\n case 'youtube':\n // Clear timers\n window.clearInterval(this.timers.buffering);\n window.clearInterval(this.timers.playing);\n\n // Destroy YouTube API\n this.embed.destroy();\n\n // Clean up\n done();\n\n break;\n\n case 'vimeo':\n // Destroy Vimeo API\n // then clean up (wait, to prevent postmessage errors)\n this.embed.unload().then(done);\n\n // Vimeo does not always return\n window.setTimeout(done, 200);\n\n break;\n\n case 'video':\n case 'audio':\n // Restore native video controls\n ui.toggleNativeControls.call(this, true);\n\n // Clean up\n done();\n\n break;\n\n default:\n break;\n }\n }\n}\n\nexport default Plyr;\n"],"names":["set","value","support","storage","this","config","enabled","extend","localStorage","setItem","key","JSON","stringify","defaults","window","navigator","language","split","types","utils","input","getConstructor","Object","Number","isNaN","String","Boolean","Function","undefined","Array","isArray","NodeList","HTMLElement","Event","instanceOf","TextTrackCue","VTTCue","TextTrack","kind","string","array","nodeList","length","object","keys","constructor","document","documentMode","documentElement","style","test","userAgent","platform","url","querySelectorAll","tag","createElement","src","firstScriptTag","getElementsByTagName","parentNode","insertBefore","prefix","Math","floor","random","self","top","e","elements","wrapper","targets","from","reverse","forEach","element","index","child","cloneNode","parent","sibling","nextSibling","appendChild","is","htmlElement","removeChild","target","type","attributes","text","setAttributes","textContent","childNodes","lastChild","setAttribute","sel","existingAttributes","empty","existing","selector","s","trim","className","replace","parts","charAt","class","id","toggle","contains","classList","prototype","Element","matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","includes","call","container","querySelector","controls","getElement","selectors","buttons","getElements","play","pause","restart","rewind","forward","mute","pip","airplay","settings","captions","fullscreen","progress","inputs","seek","volume","display","buffer","duration","currentTime","seekTooltip","classNames","tooltip","error","warn","toggleNativeControls","focused","activeElement","body","tabbables","first","last","on","event","which","_this","active","shiftKey","preventDefault","focus","eventName","customListener","defaultListener","passive","capture","apply","callback","Node","toggleListener","events","options","boolean","passiveListeners","bubbles","properties","CustomEvent","assign","Plyr","dispatchEvent","state","newState","getAttribute","current","max","toFixed","objects","destination","shift","source","property","match","RegExp","$2","number","map","encodeURIComponent","join","fragment","createDocumentFragment","innerHTML","firstChild","innerText","updateSprite","data","hasId","cached","getItem","parse","content","xhr","XMLHttpRequest","open","onload","responseText","send","find","inline","api","ui","browser","getBrowser","playsInline","isIPhone","video","rangeInput","audio","removeItem","function","webkitSetPresentationMode","WebKitPlaybackTargetAvailabilityEvent","player","media","canPlayType","supported","defineProperty","addEventListener","range","transitionEnd","matchMedia","isWebkit","styleSheet","sheet","percentage","styles","rules","findIndex","rule","selectorText","deleteRule","insertRule","iconUrl","indexOf","isIE","getIconUrl","iconPath","absolute","iconPrefix","icon","createElementNS","use","setAttributeNS","i18n","hidden","badge","menu","buttonType","attr","button","iconDefault","iconToggled","labelKey","control","getAttributesFromSelector","createIcon","createLabel","label","suffix","played","buffered","toLowerCase","setting","tab","tabs","pane","panes","removeAttribute","list","quality","filter","toggleTab","emptyElement","getBadge","createBadge","item","radio","createTextNode","getLabel","updateSetting","getLanguage","default","checked","loop","_this2","option","textTracks","tracks","none","currentTrack","disabled","track","toUpperCase","unshift","_this3","speed","_this4","insertAdjacentHTML","form","show","isMenuItem","isButton","stopPropagation","clone","position","opacity","name","width","scrollWidth","height","scrollHeight","removeElement","getElementById","transitions","reducedMotion","size","getTabSize","restore","propertyName","off","createButton","createRange","createProgress","tooltips","createTime","inner","home","_this5","back","playLarge","setSpeedMenu","loadSprite","log","seekTime","create","findElements","labels","toggleClass","_this6","setCaptionsMenu","insertAfter","setCurrentTrack","toggleCaptions","setCue","mode","activeCues","embed","enableTextTrack","cue","getCueAsHTML","caption","toggleState","cancelFullScreen","some","pre","msExitFullscreen","msFullscreenEnabled","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","fullscreenElement","mozFullScreenElement","requestFullScreen","nativeSupport","fallback","inFrame","trapFocus","setup","parseFloat","listeners","timeUpdate","displayDuration","showPosterOnEnd","load","updateProgress","updateVolume","checkPlaying","checkLoading","clickToPlay","cursor","hideControls","touch","paused","ended","disableContextMenu","concat","getKeyCode","keyCode","handleKey","code","pressed","held","getFocusElement","increaseVolume","decreaseVolume","toggleMute","toggleFullscreen","setLoop","inputEvent","togglePlay","keyboard","global","editable","tabFocus","setTimeout","handlerProxy","customHandler","defaultHandler","proxy","togglePictureInPicture","airPlay","toggleMenu","showTab","setVolume","updateRangeFill","updateSeekTooltip","toggleControls","hover","inverted","webkitDirectionInvertedFromDevice","direction","deltaY","deltaX","eventType","uiSupported","isHTML5","inject","ready","autoplay","updateTimeDisplay","title","isEmbed","iframe","frameTitle","playing","stopped","muted","setRange","loading","timers","nodeValue","getPercentage","end","setProgress","time","secs","parseInt","mins","hours","displayHours","slice","seeking","clientRect","getBoundingClientRect","percent","visible","pageX","left","hasClass","youtube","videoId","parseYouTubeId","embedId","containers","generateId","YT","loadScript","urls","onYouTubeReadyCallbacks","push","onYouTubeIframeAPIReady","Player","location","hostname","href","instance","getPlaybackQuality","playbackRate","getPlaybackRate","playVideo","pauseVideo","stop","stopVideo","getDuration","isMuted","getAvailablePlaybackRates","getVideoData","build","clearInterval","buffering","setInterval","getVideoLoadedFraction","lastBuffered","getCurrentTime","setQualityMenu","getAvailableQualityLevels","vimeo","Vimeo","vimeoTimer","params","buildUrlParameters","parseVimeoId","then","getTextTracks","cues","stripHTML","seconds","isIos","isTouch","wrap","setTitle","blankVideo","insertElement","attribute","sources","cancelRequests","destroy","firstSource","check","crossorigin","poster","addStyleHook","insertElements","scrollPosition","jQuery","debug","console","plyr","original","tagName","min","step","start","indicator","isFullScreen","pageXOffset","pageYOffset","scrollTo","x","y","overflow","states","webkitPresentationMode","webkitShowPlaybackTargetPicker","delay","isEnterFullscreen","clearTimeout","mimeType","mime","soft","done","replaceChild","unload","html5","targetTime","seekTo","setCurrentTime","fauxDuration","realDuration","isSet","selected","setPlaybackRate","setPlaybackQuality","change","getVideoUrl","currentSrc","setCaption"],"mappings":"uLAIA,SAISA,EAAIC,GAEJC,EAAQC,SAAYC,KAAKC,OAAOF,QAAQG,YAKvCC,OAAOH,KAAKD,QAASF,UAGpBO,aAAaC,QAAQL,KAAKC,OAAOF,QAAQO,IAAKC,KAAKC,UAAUR,KAAKD,WCjB7E,IAAMU,YAEO,QAGF,UAGA,YAGG,WAGA,UAGF,SACD,mBAGU,eAGJ,gBAGC,mBAGG,sBAGG,cAGR,aACA,eACH,iDAGG,gDAGF,sBAIG,mBACC,SAAU,SAAU,SAAU,QAAS,QAAS,SAAU,QAAS,OAAQ,0BAK7E,QACD,SACF,qBAKI,WACC,GAAK,IAAM,EAAG,KAAM,IAAK,KAAM,uBAKhC,UACD,uBAKE,QACJ,qBAKE,WACEC,OAAOC,UAAUC,SAASC,MAAM,KAAK,yBAKtC,YACC,qBAKD,MACJ,kBAKL,aACA,OACA,WACA,eACA,OACA,SACA,WACA,WACA,MACA,UACA,wBAEO,WAAY,UAAW,QAAS,sBAI9B,iBACD,8BACF,aACC,gBACE,+BACH,cACE,kBACE,uBACG,wBACH,kBACF,oBACI,6BACI,mCACE,+BACN,8BACF,oBACA,iBACH,gBACE,eACH,aACC,YACF,UACA,YACE,aACD,gBACI,6BAMD,uDAGA,uDAMH,UACA,WACC,aACE,YACD,aACC,UACH,YACE,cACE,gBACE,SACP,aACI,WACF,aACE,UACH,cACI,sBAQV,WACA,UACA,UACA,UACA,UACA,iBACA,YACA,aACA,iBACA,aACA,eACA,OACA,QACA,QACA,UACA,SACA,UACA,aACA,8BAIA,iBACA,kBACA,mBACA,gBACA,iBACA,gBACA,sBAIA,gBACA,wCAMU,uDACC,4BAEI,aACF,0BAEL,4BAEE,2BACC,8BACE,+BACD,+BACC,kCACH,8BACI,oCACE,+BACP,4BACI,iCACC,8BACJ,mCAGA,4BACE,6BACD,+BACG,iCACD,8CAGI,gCACH,+BACF,iCACA,+BACF,+BACE,mCAEF,2BACA,gCAEG,oDAMN,4BACA,4BACE,qBACH,oBACG,wBACA,sBACF,sBACE,sBACF,sBACE,uBACD,6BACM,4BACP,uBACE,6BACI,4BAEF,0BACA,i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"}
\ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 77c71b1d..a59073ac 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -4,27 +4,34 @@ /* global require, __dirname */ /* eslint no-console: "off" */ -var fs = require('fs'); -var path = require('path'); -var gulp = require('gulp'); -var gutil = require('gulp-util'); -var concat = require('gulp-concat'); -var uglify = require('gulp-uglify'); -var less = require('gulp-less'); -var sass = require('gulp-sass'); -var cleanCSS = require('gulp-clean-css'); -var run = require('run-sequence'); -var prefix = require('gulp-autoprefixer'); -var svgstore = require('gulp-svgstore'); -var svgmin = require('gulp-svgmin'); -var rename = require('gulp-rename'); -var s3 = require('gulp-s3'); -var replace = require('gulp-replace'); -var open = require('gulp-open'); -var size = require('gulp-size'); -var root = __dirname; - -var paths = { +const fs = require('fs'); +const path = require('path'); +const gulp = require('gulp'); +const gutil = require('gulp-util'); +const concat = require('gulp-concat'); +const less = require('gulp-less'); +const sass = require('gulp-sass'); +const cleancss = require('gulp-clean-css'); +const run = require('run-sequence'); +const prefix = require('gulp-autoprefixer'); +const svgstore = require('gulp-svgstore'); +const svgmin = require('gulp-svgmin'); +const rename = require('gulp-rename'); +const s3 = require('gulp-s3'); +const replace = require('gulp-replace'); +const open = require('gulp-open'); +const size = require('gulp-size'); +const rollup = require('gulp-better-rollup'); +const babel = require('rollup-plugin-babel'); +const sourcemaps = require('gulp-sourcemaps'); +const uglify = require('rollup-plugin-uglify'); +const { minify } = require('uglify-es'); +const commonjs = require('rollup-plugin-commonjs'); +const resolve = require('rollup-plugin-node-resolve'); + +const root = __dirname; + +const paths = { plyr: { // Source paths src: { @@ -54,82 +61,117 @@ var paths = { }; // Task arrays -var tasks = { +const tasks = { less: [], scss: [], js: [], sprite: [], }; -// Fetch bundles from JSON -var bundles = loadJSON(path.join(root, 'bundles.json')); -var package = loadJSON(path.join(root, 'package.json')); - // Load json -function loadJSON(path) { +function loadJSON(pathname) { try { - return JSON.parse(fs.readFileSync(path)); + return JSON.parse(fs.readFileSync(pathname)); } catch (err) { return {}; } } -var build = { - js: function(files, bundle) { - Object.keys(files).forEach(function(key) { - var name = 'js-' + key; +// Fetch bundles from JSON +const bundles = loadJSON(path.join(root, 'bundles.json')); +const pkg = loadJSON(path.join(root, 'package.json')); +const sizeOptions = { showFiles: true, gzip: true }; + +// Browserlist +const browsers = ['> 1%', 'last 2 versions']; + +// Babel config +const babelrc = { + presets: [ + [ + 'env', + { + targets: { + browsers, + }, + useBuiltIns: true, + modules: false, + }, + ], + ], + plugins: ['external-helpers'], + babelrc: false, + exclude: 'node_modules/**', +}; + +const build = { + js(files, bundle, options) { + Object.keys(files).forEach(key => { + const name = `js-${key}`; tasks.js.push(name); - gulp.task(name, function() { - return gulp + gulp.task(name, () => + gulp .src(bundles[bundle].js[key]) .pipe(concat(key)) - .pipe(uglify()) - .pipe(gulp.dest(paths[bundle].output)); - }); + .pipe(sourcemaps.init()) + .pipe( + rollup( + { + plugins: [resolve(), commonjs(), babel(babelrc), uglify({}, minify)], + }, + options + ) + ) + .pipe(size(sizeOptions)) + .pipe(sourcemaps.write('')) + .pipe(gulp.dest(paths[bundle].output)) + ); }); }, - less: function(files, bundle) { - Object.keys(files).forEach(function(key) { - var name = 'less-' + key; + less(files, bundle) { + Object.keys(files).forEach(key => { + const name = `less-${key}`; tasks.less.push(name); - gulp.task(name, function() { - return gulp + gulp.task(name, () => + gulp .src(bundles[bundle].less[key]) .pipe(less()) .on('error', gutil.log) .pipe(concat(key)) - .pipe(prefix(['last 2 versions'], { cascade: false })) - .pipe(cleanCSS()) - .pipe(gulp.dest(paths[bundle].output)); - }); + .pipe(prefix(browsers, { cascade: false })) + .pipe(cleancss()) + .pipe(size(sizeOptions)) + .pipe(gulp.dest(paths[bundle].output)) + ); }); }, - scss: function(files, bundle) { - Object.keys(files).forEach(function(key) { - var name = 'scss-' + key; + scss(files, bundle) { + Object.keys(files).forEach(key => { + const name = `scss-${key}`; tasks.scss.push(name); - gulp.task(name, function() { - return gulp + gulp.task(name, () => + gulp .src(bundles[bundle].scss[key]) .pipe(sass()) .on('error', gutil.log) .pipe(concat(key)) - .pipe(prefix(['last 2 versions'], { cascade: false })) - .pipe(cleanCSS()) - .pipe(gulp.dest(paths[bundle].output)); - }); + .pipe(prefix(browsers, { cascade: false })) + .pipe(cleancss()) + .pipe(size(sizeOptions)) + .pipe(gulp.dest(paths[bundle].output)) + ); }); }, - sprite: function(bundle) { - var name = 'sprite-' + bundle; + sprite(bundle) { + const name = `sprite-${bundle}`; tasks.sprite.push(name); // Process Icons - gulp.task(name, function() { - return gulp + gulp.task(name, () => + gulp .src(paths[bundle].src.sprite) .pipe( svgmin({ @@ -142,33 +184,35 @@ var build = { ) .pipe(svgstore()) .pipe(rename({ basename: bundle })) - .pipe(gulp.dest(paths[bundle].output)); - }); + .pipe(size(sizeOptions)) + .pipe(gulp.dest(paths[bundle].output)) + ); }, }; // Plyr core files -build.js(bundles.plyr.js, 'plyr'); +build.js(bundles.plyr.js, 'plyr', { name: 'Plyr', format: 'umd' }); + build.less(bundles.plyr.less, 'plyr'); build.scss(bundles.plyr.scss, 'plyr'); build.sprite('plyr'); // Demo files build.less(bundles.demo.less, 'demo'); -build.js(bundles.demo.js, 'demo'); +build.js(bundles.demo.js, 'demo', { format: 'es' }); // Build all JS -gulp.task('js', function() { +gulp.task('js', () => { run(tasks.js); }); // Build SCSS (for testing, default is LESS) -gulp.task('scss', function() { +gulp.task('scss', () => { run(tasks.scss); }); // Watch for file changes -gulp.task('watch', function() { +gulp.task('watch', () => { // Plyr core gulp.watch(paths.plyr.src.js, tasks.js); gulp.watch(paths.plyr.src.less, tasks.less); @@ -180,7 +224,7 @@ gulp.task('watch', function() { }); // Default gulp task -gulp.task('default', function() { +gulp.task('default', () => { run(tasks.js, tasks.less, tasks.sprite, 'watch'); }); @@ -188,13 +232,13 @@ gulp.task('default', function() { // -------------------------------------------- // Some options -var aws = loadJSON(path.join(root, 'aws.json')); -var version = package.version; -var maxAge = 31536000; // 1 year -var options = { +const aws = loadJSON(path.join(root, 'aws.json')); +const { version } = pkg; +const maxAge = 31536000; // 1 year +const options = { cdn: { headers: { - 'Cache-Control': 'max-age=' + maxAge, + 'Cache-Control': `max-age=${maxAge}`, Vary: 'Accept-Encoding', }, }, @@ -204,11 +248,11 @@ var options = { Vary: 'Accept-Encoding', }, }, - symlinks: function(version, filename) { + symlinks(ver, filename) { return { headers: { // http://stackoverflow.com/questions/2272835/amazon-s3-object-redirect - 'x-amz-website-redirect-location': '/' + version + '/' + filename, + 'x-amz-website-redirect-location': `/${ver}/${filename}`, 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0', }, }; @@ -217,105 +261,105 @@ var options = { // If aws is setup if ('cdn' in aws) { - var regex = + const regex = '(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*).(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?'; - var cdnpath = new RegExp(aws.cdn.domain + '/' + regex, 'gi'); - var semver = new RegExp('v' + regex, 'gi'); - var localPath = new RegExp('(../)?dist', 'gi'); - var versionPath = 'https://' + aws.cdn.domain + '/' + version; -} - -// Publish version to CDN bucket -gulp.task('cdn', function() { - console.log('Uploading ' + version + ' to ' + aws.cdn.domain + '...'); - - // Upload to CDN - return gulp - .src(paths.upload) - .pipe( - size({ - showFiles: true, - gzip: true, - }) - ) - .pipe( - rename(function(path) { - path.dirname = path.dirname.replace('.', version); + const cdnpath = new RegExp(`${aws.cdn.domain}/${regex}`, 'gi'); + const semver = new RegExp(`v${regex}`, 'gi'); + const localPath = new RegExp('(../)?dist', 'gi'); + const versionPath = `https://${aws.cdn.domain}/${version}`; + + // Publish version to CDN bucket + gulp.task('cdn', () => { + console.log(`Uploading ${version} to ${aws.cdn.domain}...`); + + // Upload to CDN + return gulp + .src(paths.upload) + .pipe( + size({ + showFiles: true, + gzip: true, + }) + ) + .pipe( + rename(p => { + p.dirname = path.dirname.replace('.', version); + }) + ) + .pipe(replace(localPath, versionPath)) + .pipe(s3(aws.cdn, options.cdn)); + }); + + // Publish to demo bucket + gulp.task('demo', () => { + console.log(`Uploading ${version} demo to ${aws.demo.domain}...`); + + // Replace versioned files in readme.md + gulp + .src([`${root}/readme.md`]) + .pipe(replace(cdnpath, `${aws.cdn.domain}/${version}`)) + .pipe(gulp.dest(root)); + + // Replace versioned files in plyr.js + gulp + .src(path.join(root, 'src/js/plyr.js')) + .pipe(replace(semver, `v${version}`)) + .pipe(replace(cdnpath, `${aws.cdn.domain}/${version}`)) + .pipe(gulp.dest(path.join(root, 'src/js/'))); + + // Replace local file paths with remote paths in demo HTML + // e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js" + gulp + .src([`${paths.demo.root}*.html`]) + .pipe(replace(localPath, versionPath)) + .pipe(s3(aws.demo, options.demo)); + + // Upload error.html to cdn (as well as demo site) + return gulp + .src([`${paths.demo.root}error.html`]) + .pipe(replace(localPath, versionPath)) + .pipe(s3(aws.cdn, options.demo)); + }); + + // Update symlinks for latest + /* gulp.task("symlinks", function () { + console.log("Updating symlinks..."); + + return gulp.src(paths.upload) + .pipe(through.obj(function (chunk, enc, callback) { + if (chunk.stat.isFile()) { + // Get the filename + var filename = chunk.path.split("/").reverse()[0]; + + // Create the 0 byte redirect files to upload + createFile(filename, "") + .pipe(rename(function (path) { + path.dirname = path.dirname.replace(".", "latest"); + })) + // Upload to S3 with correct headers + .pipe(s3(aws.cdn, options.symlinks(version, filename))); + } + + callback(null, chunk); + })); + }); */ + + // Open the demo site to check it's sweet + gulp.task('open', () => { + console.log(`Opening ${aws.demo.domain}...`); + + // A file must be specified or gulp will skip the task + // Doesn't matter which file since we set the URL above + // Weird, I know... + return gulp.src([`${paths.demo.root}index.html`]).pipe( + open('', { + url: `http://${aws.demo.domain}`, }) - ) - .pipe(replace(localPath, versionPath)) - .pipe(s3(aws.cdn, options.cdn)); -}); - -// Publish to demo bucket -gulp.task('demo', function() { - console.log('Uploading ' + version + ' demo to ' + aws.demo.domain + '...'); - - // Replace versioned files in readme.md - gulp - .src([root + '/readme.md']) - .pipe(replace(cdnpath, aws.cdn.domain + '/' + version)) - .pipe(gulp.dest(root)); - - // Replace versioned files in plyr.js - gulp - .src(path.join(root, 'src/js/plyr.js')) - .pipe(replace(semver, 'v' + version)) - .pipe(replace(cdnpath, aws.cdn.domain + '/' + version)) - .pipe(gulp.dest(path.join(root, 'src/js/'))); - - // Replace local file paths with remote paths in demo HTML - // e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js" - gulp - .src([paths.demo.root + '*.html']) - .pipe(replace(localPath, versionPath)) - .pipe(s3(aws.demo, options.demo)); - - // Upload error.html to cdn (as well as demo site) - return gulp - .src([paths.demo.root + 'error.html']) - .pipe(replace(localPath, versionPath)) - .pipe(s3(aws.cdn, options.demo)); -}); - -// Open the demo site to check it's sweet -/*gulp.task("symlinks", function () { - console.log("Updating symlinks..."); - - return gulp.src(paths.upload) - .pipe(through.obj(function (chunk, enc, callback) { - if (chunk.stat.isFile()) { - // Get the filename - var filename = chunk.path.split("/").reverse()[0]; - - // Create the 0 byte redirect files to upload - createFile(filename, "") - .pipe(rename(function (path) { - path.dirname = path.dirname.replace(".", "latest"); - })) - // Upload to S3 with correct headers - .pipe(s3(aws.cdn, options.symlinks(version, filename))); - } - - callback(null, chunk); - })); -});*/ - -// Open the demo site to check it's sweet -gulp.task('open', function() { - console.log('Opening ' + aws.demo.domain + '...'); - - // A file must be specified or gulp will skip the task - // Doesn't matter which file since we set the URL above - // Weird, I know... - return gulp.src([paths.demo.root + 'index.html']).pipe( - open('', { - url: 'http://' + aws.demo.domain, - }) - ); -}); + ); + }); -// Do everything -gulp.task('publish', function() { - run(tasks.js, tasks.less, tasks.sprite, 'cdn', 'demo'); -}); + // Do everything + gulp.task('publish', () => { + run(tasks.js, tasks.less, tasks.sprite, 'cdn', 'demo'); + }); +} diff --git a/package-lock.json b/package-lock.json index d6f2d8b2..6671a323 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,65 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@gulp-sourcemaps/identity-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.1.tgz", + "integrity": "sha1-z6I7xYQPkQTOMqZedNt+epdLvuE=", + "dev": true, + "requires": { + "acorn": "5.1.2", + "css": "2.2.1", + "normalize-path": "2.1.1", + "source-map": "0.5.7", + "through2": "2.0.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@gulp-sourcemaps/map-sources": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", + "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", + "dev": true, + "requires": { + "normalize-path": "2.1.1", + "through2": "2.0.3" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accord": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/accord/-/accord-0.27.3.tgz", + "integrity": "sha1-f7kSlwkoXK6oTrNyxOiCAxtxOOg=", + "dev": true, + "requires": { + "convert-source-map": "1.5.0", + "glob": "7.1.2", + "indx": "0.2.3", + "lodash.clone": "4.5.0", + "lodash.defaults": "4.2.0", + "lodash.flatten": "4.4.0", + "lodash.merge": "4.6.0", + "lodash.partialright": "4.2.1", + "lodash.pick": "4.4.0", + "lodash.uniq": "4.5.0", + "resolve": "1.5.0", + "semver": "5.4.1", + "uglify-js": "2.8.29", + "when": "3.7.8" + } + }, "acorn": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", @@ -45,6 +104,23 @@ "integrity": "sha1-opbhf3v658HOT34N5T0pyzIWLfA=", "dev": true }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, "ansi-escapes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", @@ -63,6 +139,28 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "dev": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.3" + } + }, "argparse": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", @@ -72,6 +170,15 @@ "sprintf-js": "1.0.3" } }, + "aria-query": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.7.0.tgz", + "integrity": "sha512-/r2lHl09V3o74+2MLKEdewoj37YZqiQZnfen1O4iNlrOjUgeKuu1U2yF3iKh6HJxqF+OXkLMfQv65Z/cvxD6vA==", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", @@ -87,6 +194,12 @@ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", @@ -99,6 +212,16 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.9.0" + } + }, "array-slice": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.0.0.tgz", @@ -132,6 +255,57 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/atob/-/atob-1.1.3.tgz", + "integrity": "sha1-lfE2KbEsOlGl0hWr3OKqnzL4B3M=", + "dev": true + }, "autoprefixer": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.1.6.tgz", @@ -139,13 +313,34 @@ "dev": true, "requires": { "browserslist": "2.5.1", - "caniuse-lite": "1.0.30000751", + "caniuse-lite": "1.0.30000755", "normalize-range": "0.1.2", "num2fraction": "1.2.2", "postcss": "6.0.13", "postcss-value-parser": "3.3.0" } }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "axobject-query": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz", + "integrity": "sha1-YvWdvFnJ+SQnWco0mWDnov48NsA=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -181,18 +376,986 @@ } } }, + "babel-core": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", + "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.0", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-eslint": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.0.1.tgz", + "integrity": "sha512-h3moF6PCTQE06UjMMG+ydZSBvZ4Q7rqPE/5WAUOvUyHYUTqxm8JVhjZRiG1avI/tGVOK4BnZLDQapyLzh8DeKg==", + "dev": true, + "requires": { + "babel-code-frame": "7.0.0-beta.0", + "babel-traverse": "7.0.0-beta.0", + "babel-types": "7.0.0-beta.0", + "babylon": "7.0.0-beta.22" + }, + "dependencies": { + "babel-code-frame": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-7.0.0-beta.0.tgz", + "integrity": "sha512-/xr1ADm5bnTjjN+xwoXb7lF4v2rnxMzNZzFU7h8SxB+qB6+IqSTOOqVcpaPTUC2Non/MbQxS3OIZnJpQ2X21aQ==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-messages": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-7.0.0-beta.0.tgz", + "integrity": "sha512-eXdShsm9ZTh9AQhlIaAn6HR3xWpxCnK9ZwIDA9QyjnwTgMctGxHHflw4b4RJ3/ZjTL0Vrmvm0tQXPkp49mTAUw==", + "dev": true + }, + "babel-traverse": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-7.0.0-beta.0.tgz", + "integrity": "sha512-IKzuTqUcQtMRZ0Vv5RjIrGGj33eBKmNTNeRexWSyjPPuAciyNkva1rt7WXPfHfkb+dX7coRAIUhzeTUEzhnwdA==", + "dev": true, + "requires": { + "babel-code-frame": "7.0.0-beta.0", + "babel-helper-function-name": "7.0.0-beta.0", + "babel-messages": "7.0.0-beta.0", + "babel-types": "7.0.0-beta.0", + "babylon": "7.0.0-beta.22", + "debug": "3.1.0", + "globals": "10.1.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "babel-types": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-7.0.0-beta.0.tgz", + "integrity": "sha512-rJc2kV9iPJGLlqIY71AM3nPcdkoeLRCDuR07GFgfd3lFl4TsBQq76TxYQQIZ2MONg1HpsqmuoCXr9aZ1Oa4wYw==", + "dev": true, + "requires": { + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "2.0.0" + } + }, + "babylon": { + "version": "7.0.0-beta.22", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.22.tgz", + "integrity": "sha512-Yl7iT8QGrS8OfR7p6R12AJexQm+brKwrryai4VWZ7NHUbPoZ5al3+klhvl/14shXZiLa7uK//OIFuZ1/RKHgoA==", + "dev": true + }, + "globals": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-10.1.0.tgz", + "integrity": "sha1-RCWhiBvg0za0qCOoKnvnJdXdmHw=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + }, + "dependencies": { + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + } + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-function-name": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-7.0.0-beta.0.tgz", + "integrity": "sha512-DaQccFBBWBEzMdqbKmNXamY0m1yLHJGOdbbEsNoGdJrrU7wAF3wwowtDDPzF0ZT3SqJXPgZW/P2kgBX9moMuAA==", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "7.0.0-beta.0", + "babel-template": "7.0.0-beta.0", + "babel-traverse": "7.0.0-beta.0", + "babel-types": "7.0.0-beta.0" + }, + "dependencies": { + "babel-code-frame": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-7.0.0-beta.0.tgz", + "integrity": "sha512-/xr1ADm5bnTjjN+xwoXb7lF4v2rnxMzNZzFU7h8SxB+qB6+IqSTOOqVcpaPTUC2Non/MbQxS3OIZnJpQ2X21aQ==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-messages": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-7.0.0-beta.0.tgz", + "integrity": "sha512-eXdShsm9ZTh9AQhlIaAn6HR3xWpxCnK9ZwIDA9QyjnwTgMctGxHHflw4b4RJ3/ZjTL0Vrmvm0tQXPkp49mTAUw==", + "dev": true + }, + "babel-template": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-7.0.0-beta.0.tgz", + "integrity": "sha512-tmdH+MmmU0F6Ur8humpevSmFzYKbrN3Oru0g5Qyg4R6+sxjnzZmnvzUbsP0aKMr7tB0Ua6xhEb9arKTOsEMkyA==", + "dev": true, + "requires": { + "babel-traverse": "7.0.0-beta.0", + "babel-types": "7.0.0-beta.0", + "babylon": "7.0.0-beta.22", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-7.0.0-beta.0.tgz", + "integrity": "sha512-IKzuTqUcQtMRZ0Vv5RjIrGGj33eBKmNTNeRexWSyjPPuAciyNkva1rt7WXPfHfkb+dX7coRAIUhzeTUEzhnwdA==", + "dev": true, + "requires": { + "babel-code-frame": "7.0.0-beta.0", + "babel-helper-function-name": "7.0.0-beta.0", + "babel-messages": "7.0.0-beta.0", + "babel-types": "7.0.0-beta.0", + "babylon": "7.0.0-beta.22", + "debug": "3.1.0", + "globals": "10.1.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "babel-types": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-7.0.0-beta.0.tgz", + "integrity": "sha512-rJc2kV9iPJGLlqIY71AM3nPcdkoeLRCDuR07GFgfd3lFl4TsBQq76TxYQQIZ2MONg1HpsqmuoCXr9aZ1Oa4wYw==", + "dev": true, + "requires": { + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "2.0.0" + } + }, + "babylon": { + "version": "7.0.0-beta.22", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.22.tgz", + "integrity": "sha512-Yl7iT8QGrS8OfR7p6R12AJexQm+brKwrryai4VWZ7NHUbPoZ5al3+klhvl/14shXZiLa7uK//OIFuZ1/RKHgoA==", + "dev": true + }, + "globals": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-10.1.0.tgz", + "integrity": "sha1-RCWhiBvg0za0qCOoKnvnJdXdmHw=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "babel-helper-get-function-arity": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-7.0.0-beta.0.tgz", + "integrity": "sha512-csqAic15/2Vm1951nJxkkL9K8E6ojyNF/eAOjk7pqJlO8kvgrccGNFCV9eDwcGHDPe5AjvJGwVSAcQ5fit9wuA==", + "dev": true, + "requires": { + "babel-types": "7.0.0-beta.0" + }, + "dependencies": { + "babel-types": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-7.0.0-beta.0.tgz", + "integrity": "sha512-rJc2kV9iPJGLlqIY71AM3nPcdkoeLRCDuR07GFgfd3lFl4TsBQq76TxYQQIZ2MONg1HpsqmuoCXr9aZ1Oa4wYw==", + "dev": true, + "requires": { + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "2.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + }, + "dependencies": { + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + } + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-external-helpers": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz", + "integrity": "sha1-IoX0iwK9Xe3oUXXK+MYuhq3M76E=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "dev": true + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "dev": true + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "6.24.1", + "babel-plugin-syntax-async-functions": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + }, + "dependencies": { + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + } + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + }, + "dependencies": { + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + } + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", + "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + }, + "dependencies": { + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + } + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dev": true, + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", + "babel-plugin-syntax-exponentiation-operator": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-preset-env": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz", + "integrity": "sha512-W6VIyA6Ch9ePMI7VptNn2wBM6dbG0eSz25HEiL40nQXCsXGTGZSTZu1Iap+cj3Q0S5a7T9+529l/5Bkvd+afNA==", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-async-to-generator": "6.24.1", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-exponentiation-operator": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0", + "browserslist": "2.5.1", + "invariant": "2.2.2", + "semver": "5.4.1" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-runtime": "6.26.0", + "core-js": "2.5.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "dev": true + }, + "binaryextensions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.1.tgz", + "integrity": "sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U=", + "dev": true + }, "block-stream": { - "version": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", "dev": true, "requires": { - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" + "inherits": "2.0.3" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" } }, "brace-expansion": { @@ -216,13 +1379,30 @@ "repeat-element": "1.1.2" } }, + "browser-resolve": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", + "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, "browserslist": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.5.1.tgz", "integrity": "sha512-jAvM2ku7YDJ+leAq3bFH1DE0Ylw+F+EQDq4GkqZfgPEqpWYw9ofQH85uKSB9r3Tv7XDbfqVtE+sdvKJW7IlPJA==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000751", + "caniuse-lite": "1.0.30000755", "electron-to-chromium": "1.3.27" } }, @@ -248,9 +1428,9 @@ "dev": true }, "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", "dev": true }, "camelcase-keys": { @@ -261,14 +1441,38 @@ "requires": { "camelcase": "2.1.1", "map-obj": "1.0.1" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + } } }, "caniuse-lite": { - "version": "1.0.30000751", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000751.tgz", - "integrity": "sha1-KYrTQYLKQ1l1e0qTr8aBt7kX41g=", + "version": "1.0.30000755", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000755.tgz", + "integrity": "sha1-nOX24GvXXsggmr6IU8O+7wIkjWU=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, "chalk": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", @@ -300,12 +1504,86 @@ } } }, + "cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-serializer": "0.1.0", + "entities": "1.1.1", + "htmlparser2": "3.9.2", + "lodash.assignin": "4.2.0", + "lodash.bind": "4.2.1", + "lodash.defaults": "4.2.0", + "lodash.filter": "4.6.0", + "lodash.flatten": "4.4.0", + "lodash.foreach": "4.5.0", + "lodash.map": "4.6.0", + "lodash.merge": "4.6.0", + "lodash.pick": "4.4.0", + "lodash.reduce": "4.6.0", + "lodash.reject": "4.6.0", + "lodash.some": "4.6.0" + } + }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, + "clap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", + "dev": true, + "requires": { + "chalk": "1.1.3" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "clean-css": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz", + "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=", + "dev": true, + "requires": { + "source-map": "0.5.7" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -321,6 +1599,37 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + } + } + }, + "clone": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", + "dev": true + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, "clone-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.0.tgz", @@ -331,12 +1640,44 @@ "is-supported-regexp-flag": "1.0.0" } }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "cloneable-readable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.0.0.tgz", + "integrity": "sha1-pikNQT8hemEjL5XkWP84QYz7ARc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "process-nextick-args": "1.0.7", + "through2": "2.0.3" + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, + "coa": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", + "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", + "dev": true, + "requires": { + "q": "1.5.1" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, "color-convert": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", @@ -352,6 +1693,27 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -367,16 +1729,49 @@ "inherits": "2.0.3", "readable-stream": "2.3.3", "typedarray": "0.0.6" + } + }, + "concat-with-sourcemaps": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz", + "integrity": "sha1-9Vs74q60dgGxCi1SWcz7cP0vHdY=", + "dev": true, + "requires": { + "source-map": "0.5.7" }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } } }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -393,6 +1788,17 @@ "js-yaml": "3.10.0", "parse-json": "3.0.0", "require-from-string": "2.0.1" + }, + "dependencies": { + "parse-json": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-3.0.0.tgz", + "integrity": "sha1-+m9HsY4jgm6tMvJj50TQ4ehH+xM=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + } } }, "cross-spawn": { @@ -406,6 +1812,74 @@ "which": "1.3.0" } }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "css": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.1.tgz", + "integrity": "sha1-c6TIHehdtmTU7mdPfUcIXjstVdw=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "source-map": "0.1.43", + "source-map-resolve": "0.3.1", + "urix": "0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "1.0.0", + "css-what": "2.1.0", + "domutils": "1.5.1", + "nth-check": "1.0.1" + } + }, + "css-what": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, + "csso": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", + "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", + "dev": true, + "requires": { + "clap": "1.2.3", + "source-map": "0.5.7" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -415,6 +1889,44 @@ "array-find-index": "1.0.2" } }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "0.10.35" + } + }, + "damerau-levenshtein": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", + "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "dateformat": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "dev": true + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -424,6 +1936,17 @@ "ms": "2.0.0" } }, + "debug-fabulous": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-0.2.1.tgz", + "integrity": "sha512-u0TV6HcfLsZ03xLBhdhSViQMldaiQ2o+8/nSILaXkuNSWvxkx66vYJUAam0Eu7gAilJRX/69J4kKdqajQPaPyw==", + "dev": true, + "requires": { + "debug": "3.1.0", + "memoizee": "0.4.11", + "object-assign": "4.1.1" + } + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -436,6 +1959,25 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "1.0.2" + } + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, "del": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", @@ -451,6 +1993,48 @@ "rimraf": "2.6.2" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "deprecated": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", + "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", + "dev": true + }, + "detect-file": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz", + "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=", + "dev": true, + "requires": { + "fs-exists-sync": "0.1.0" + } + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, "doctrine": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", @@ -461,17 +2045,157 @@ "isarray": "1.0.0" } }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", + "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, "duplexer": { - "version": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "1.1.14" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, "electron-to-chromium": { "version": "1.3.27", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz", "integrity": "sha1-eOy4o5kGYYe7N07t412ccFZagD0=", "dev": true }, + "emoji-regex": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", + "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "0.4.19" + } + }, + "end-of-stream": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", + "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "dev": true, + "requires": { + "once": "1.3.3" + }, + "dependencies": { + "once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + } + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "errno": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", + "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", + "dev": true, + "optional": true, + "requires": { + "prr": "0.0.0" + } + }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", @@ -481,6 +2205,73 @@ "is-arrayish": "0.2.1" } }, + "es-abstract": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz", + "integrity": "sha512-kk3IJoKo7A3pWJc0OV8yZ/VEX2oSUytfekrJiqoxBlKJMFAJVJVpGdHClCCTdv+Fn2zHfpDHHIelMFhZVfef3Q==", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "es5-ext": { + "version": "0.10.35", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.35.tgz", + "integrity": "sha1-GO6FjOajxFx9eekcFfzKnsVoSU8=", + "dev": true, + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.35", + "es6-symbol": "3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.35" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.35", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -488,9 +2279,9 @@ "dev": true }, "eslint": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.9.0.tgz", - "integrity": "sha1-doedJ0BoJhsZH+Dy9Wx0wvQgjos=", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.10.0.tgz", + "integrity": "sha512-MMVl8P/dYUFZEvolL8PYt7qc5LNdS2lwheq9BYa5Y07FblhcZqFyaUqlS8TW5QITGex21tV4Lk0a3fK8lsJIkA==", "dev": true, "requires": { "ajv": "5.3.0", @@ -532,15 +2323,215 @@ "text-table": "0.2.0" } }, + "eslint-config-airbnb": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz", + "integrity": "sha512-zLyOhVWhzB/jwbz7IPSbkUuj7X2ox4PHXTcZkEmDqTvd0baJmJyuxlFPDlZOE/Y5bC+HQRaEkT3FoHo9wIdRiw==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "12.1.0" + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "dev": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, "eslint-config-prettier": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-2.6.0.tgz", - "integrity": "sha1-8h2w67Q4rWePuYlGCXxLsZi+/Mw=", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-2.7.0.tgz", + "integrity": "sha1-e7/vZq14MneDb06lVuaLm8ydpNA=", "dev": true, "requires": { "get-stdin": "5.0.1" } }, + "eslint-import-resolver-node": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz", + "integrity": "sha512-yUtXS15gIcij68NmXmP9Ni77AQuCN0itXbCc/jWd8C6/yKZaSNXicpC8cgvjnxVdmfsosIXrjpzFq7GcDryb6A==", + "dev": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz", + "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz", + "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==", + "dev": true, + "requires": { + "builtin-modules": "1.1.1", + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.1", + "eslint-module-utils": "2.1.1", + "has": "1.0.1", + "lodash.cond": "4.5.2", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.2.tgz", + "integrity": "sha1-ZZJ3p1iwNsMFp+ShMFfDAc075z8=", + "dev": true, + "requires": { + "aria-query": "0.7.0", + "array-includes": "3.0.3", + "ast-types-flow": "0.0.7", + "axobject-query": "0.1.0", + "damerau-levenshtein": "1.0.4", + "emoji-regex": "6.5.1", + "jsx-ast-utils": "1.4.1" + } + }, + "eslint-plugin-react": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.4.0.tgz", + "integrity": "sha512-tvjU9u3VqmW2vVuYnE8Qptq+6ji4JltjOjJ9u7VAOxVYkUkyBZWRvNYKbDv5fN+L6wiA+4we9+qQahZ0m63XEA==", + "dev": true, + "requires": { + "doctrine": "2.0.0", + "has": "1.0.1", + "jsx-ast-utils": "2.0.1", + "prop-types": "15.6.0" + }, + "dependencies": { + "jsx-ast-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", + "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", + "dev": true, + "requires": { + "array-includes": "3.0.3" + } + } + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + }, "eslint-scope": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", @@ -592,24 +2583,41 @@ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "dev": true }, + "estree-walker": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz", + "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=", + "dev": true + }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.35" + } + }, "event-stream": { - "version": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { - "duplexer": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "from": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "map-stream": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "pause-stream": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "split": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "stream-combiner": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + "duplexer": "0.1.1", + "from": "0.1.7", + "map-stream": "0.1.0", + "pause-stream": "0.0.11", + "split": "0.3.3", + "stream-combiner": "0.0.4", + "through": "2.3.8" } }, "execall": { @@ -639,6 +2647,21 @@ "fill-range": "2.2.3" } }, + "expand-tilde": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", + "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, "external-editor": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.5.tgz", @@ -646,7 +2669,7 @@ "dev": true, "requires": { "iconv-lite": "0.4.19", - "jschardet": "1.5.1", + "jschardet": "1.6.0", "tmp": "0.0.33" } }, @@ -659,6 +2682,46 @@ "is-extglob": "1.0.0" } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fancy-log": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz", + "integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "time-stamp": "1.1.0" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, "fast-deep-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", @@ -677,6 +2740,29 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fbjs": { + "version": "0.8.16", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", + "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", + "dev": true, + "requires": { + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.17" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "dev": true + } + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -715,6 +2801,12 @@ "repeat-string": "1.6.1" } }, + "find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", + "dev": true + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", @@ -725,6 +2817,54 @@ "pinkie-promise": "2.0.1" } }, + "findup-sync": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz", + "integrity": "sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=", + "dev": true, + "requires": { + "detect-file": "0.1.0", + "is-glob": "2.0.1", + "micromatch": "2.3.11", + "resolve-dir": "0.1.1" + } + }, + "fined": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", + "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", + "dev": true, + "requires": { + "expand-tilde": "2.0.2", + "is-plain-object": "2.0.4", + "object.defaults": "1.1.0", + "object.pick": "1.3.0", + "parse-filepath": "1.0.1" + }, + "dependencies": { + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "1.0.1" + } + } + } + }, + "first-chunk-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", + "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", + "dev": true + }, + "flagged-respawn": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-0.3.2.tgz", + "integrity": "sha1-/xke3c1wiKZ1smEP/8l2vpuAdLU=", + "dev": true + }, "flat-cache": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", @@ -758,29 +2898,156 @@ "for-in": "1.0.2" } }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, "from": { - "version": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", "dev": true }, + "fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "gaze": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", + "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "dev": true, + "requires": { + "globule": "0.1.0" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, "get-stdin": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", "dev": true }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -793,14 +3060,6 @@ "minimatch": "3.0.4", "once": "1.4.0", "path-is-absolute": "1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "glob-base": { @@ -822,6 +3081,117 @@ "is-glob": "2.0.1" } }, + "glob-stream": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", + "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", + "dev": true, + "requires": { + "glob": "4.5.3", + "glob2base": "0.0.12", + "minimatch": "2.0.10", + "ordered-read-streams": "0.1.0", + "through2": "0.6.5", + "unique-stream": "1.0.0" + }, + "dependencies": { + "glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + } + } + } + }, + "glob-watcher": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", + "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "dev": true, + "requires": { + "gaze": "0.5.2" + } + }, + "glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "dev": true, + "requires": { + "find-index": "0.1.1" + } + }, + "global-modules": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", + "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", + "dev": true, + "requires": { + "global-prefix": "0.1.5", + "is-windows": "0.2.0" + } + }, + "global-prefix": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", + "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=", + "dev": true, + "requires": { + "homedir-polyfill": "1.0.1", + "ini": "1.3.4", + "is-windows": "0.2.0", + "which": "1.3.0" + } + }, "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", @@ -848,6 +3218,73 @@ "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=", "dev": true }, + "globule": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", + "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", + "dev": true, + "requires": { + "glob": "3.1.21", + "lodash": "1.0.2", + "minimatch": "0.2.14" + }, + "dependencies": { + "glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "dev": true, + "requires": { + "graceful-fs": "1.2.3", + "inherits": "1.0.2", + "minimatch": "0.2.14" + } + }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "dev": true + }, + "inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "dev": true + }, + "lodash": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "dev": true, + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + } + } + } + }, + "glogg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", + "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", + "dev": true, + "requires": { + "sparkles": "1.0.0" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -875,72 +3312,6 @@ "vinyl-fs": "0.3.14" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "1.1.0" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" - } - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -954,904 +3325,18 @@ "supports-color": "2.0.0" } }, - "clone": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", - "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "requires": { - "clone": "1.0.2" - } - }, - "deprecated": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true - }, - "detect-file": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz", - "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=", - "dev": true, - "requires": { - "fs-exists-sync": "0.1.0" - } - }, - "end-of-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", - "dev": true, - "requires": { - "once": "1.3.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "0.1.1" - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "2.2.3" - } - }, - "expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", - "dev": true, - "requires": { - "os-homedir": "1.0.2" - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "1.0.0" - } - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true, - "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" - } - }, - "find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", - "dev": true - }, - "findup-sync": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz", - "integrity": "sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=", - "dev": true, - "requires": { - "detect-file": "0.1.0", - "is-glob": "2.0.1", - "micromatch": "2.3.11", - "resolve-dir": "0.1.1" - } - }, - "fined": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", - "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "is-plain-object": "2.0.4", - "object.defaults": "1.1.0", - "object.pick": "1.3.0", - "parse-filepath": "1.0.1" - }, - "dependencies": { - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "1.0.1" - } - } - } - }, - "first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true - }, - "flagged-respawn": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-0.3.2.tgz", - "integrity": "sha1-/xke3c1wiKZ1smEP/8l2vpuAdLU=", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } - }, - "fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", - "dev": true - }, - "gaze": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", - "dev": true, - "requires": { - "globule": "0.1.0" - } - }, - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", - "dev": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.3.3" - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "2.0.1" - } - }, - "glob-stream": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", - "dev": true, - "requires": { - "glob": "4.5.3", - "glob2base": "0.0.12", - "minimatch": "2.0.10", - "ordered-read-streams": "0.1.0", - "through2": "0.6.5", - "unique-stream": "1.0.0" - } - }, - "glob-watcher": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", - "dev": true, - "requires": { - "gaze": "0.5.2" - } - }, - "glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", - "dev": true, - "requires": { - "find-index": "0.1.1" - } - }, - "global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", - "dev": true, - "requires": { - "global-prefix": "0.1.5", - "is-windows": "0.2.0" - } - }, - "global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=", - "dev": true, - "requires": { - "homedir-polyfill": "1.0.1", - "ini": "1.3.4", - "is-windows": "0.2.0", - "which": "1.3.0" - } - }, - "globule": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", - "dev": true, - "requires": { - "glob": "3.1.21", - "lodash": "1.0.2", - "minimatch": "0.2.14" - }, - "dependencies": { - "glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "1.2.3", - "inherits": "1.0.2", - "minimatch": "0.2.14" - } - }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" - } - } - } - }, - "graceful-fs": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", - "dev": true, - "requires": { - "natives": "1.1.0" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", - "dev": true, - "requires": { - "parse-passwd": "1.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.3.3", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", - "dev": true - }, - "interpret": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", - "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=", - "dev": true - }, - "is-absolute": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.6.tgz", - "integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=", - "dev": true, - "requires": { - "is-relative": "0.2.1", - "is-windows": "0.2.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "1.0.0" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "is-relative": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.2.1.tgz", - "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", - "dev": true, - "requires": { - "is-unc-path": "0.1.2" - } - }, - "is-unc-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-0.1.2.tgz", - "integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=", - "dev": true, - "requires": { - "unc-path-regex": "0.1.2" - } - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - }, - "liftoff": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.3.0.tgz", - "integrity": "sha1-qY8v9nGD2Lp8+soQVIvX/wVQs4U=", - "dev": true, - "requires": { - "extend": "3.0.1", - "findup-sync": "0.4.3", - "fined": "1.1.0", - "flagged-respawn": "0.3.2", - "lodash.isplainobject": "4.0.6", - "lodash.isstring": "4.0.1", - "lodash.mapvalues": "4.6.0", - "rechoir": "0.6.2", - "resolve": "1.5.0" - } - }, - "lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", - "dev": true - }, - "lodash.mapvalues": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", - "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" - } - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "natives": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz", - "integrity": "sha1-6f+EFBimsux6SV6TmYT3jxY+bjE=", - "dev": true - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.1.0" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" - } - }, - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "orchestrator": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", - "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", - "dev": true, - "requires": { - "end-of-stream": "0.1.5", - "sequencify": "0.0.7", - "stream-consume": "0.1.0" - } - }, - "ordered-read-streams": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "parse-filepath": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.1.tgz", - "integrity": "sha1-FZ1hVdQ5BNFsEO9piRHaHpGWm3M=", - "dev": true, - "requires": { - "is-absolute": "0.2.6", - "map-cache": "0.2.2", - "path-root": "0.1.1" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "dev": true, - "requires": { - "path-root-regex": "0.1.2" - } - }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true - }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", - "dev": true, - "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "1.5.0" - } - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "requires": { - "is-equal-shallow": "0.1.3" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", - "dev": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", - "dev": true, - "requires": { - "expand-tilde": "1.2.2", - "global-modules": "0.2.3" - } - }, "semver": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", "dev": true }, - "sequencify": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", - "dev": true - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "stream-consume": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", - "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", - "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -1860,123 +3345,6 @@ "requires": { "ansi-regex": "2.1.1" } - }, - "strip-bom": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", - "dev": true, - "requires": { - "first-chunk-stream": "1.0.0", - "is-utf8": "0.2.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" - } - }, - "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", - "dev": true, - "requires": { - "os-homedir": "1.0.2" - } - }, - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true - }, - "unique-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", - "dev": true - }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true - }, - "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", - "dev": true, - "requires": { - "user-home": "1.1.1" - } - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "0.2.0", - "clone-stats": "0.0.1" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - } - } - }, - "vinyl-fs": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", - "dev": true, - "requires": { - "defaults": "1.0.3", - "glob-stream": "3.1.18", - "glob-watcher": "0.0.6", - "graceful-fs": "3.0.11", - "mkdirp": "0.5.1", - "strip-bom": "1.0.0", - "through2": "0.6.5", - "vinyl": "0.4.6" - } - }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", - "dev": true, - "requires": { - "isexe": "2.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true } } }, @@ -1991,152 +3359,18 @@ "postcss": "6.0.13", "through2": "2.0.3", "vinyl-sourcemaps-apply": "0.2.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "1.9.0" - } - }, - "autoprefixer": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.1.6.tgz", - "integrity": "sha512-C9yv/UF3X+eJTi/zvfxuyfxmLibYrntpF3qoJYrMeQwgUJOZrZvpJiMG2FMQ3qnhWtF/be4pYONBBw95ZGe3vA==", - "dev": true, - "requires": { - "browserslist": "2.5.1", - "caniuse-lite": "1.0.30000751", - "normalize-range": "0.1.2", - "num2fraction": "1.2.2", - "postcss": "6.0.13", - "postcss-value-parser": "3.3.0" - } - }, - "browserslist": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.5.1.tgz", - "integrity": "sha512-jAvM2ku7YDJ+leAq3bFH1DE0Ylw+F+EQDq4GkqZfgPEqpWYw9ofQH85uKSB9r3Tv7XDbfqVtE+sdvKJW7IlPJA==", - "dev": true, - "requires": { - "caniuse-lite": "1.0.30000751", - "electron-to-chromium": "1.3.27" - } - }, - "caniuse-lite": { - "version": "1.0.30000751", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000751.tgz", - "integrity": "sha1-KYrTQYLKQ1l1e0qTr8aBt7kX41g=", - "dev": true - }, - "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", - "dev": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "color-convert": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", - "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.27", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz", - "integrity": "sha1-eOy4o5kGYYe7N07t412ccFZagD0=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "postcss": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", - "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", - "dev": true, - "requires": { - "chalk": "2.3.0", - "source-map": "0.6.1", - "supports-color": "4.5.0" - } - }, - "postcss-value-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", - "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "2.0.0" - } - }, - "vinyl-sourcemaps-apply": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", - "dev": true, - "requires": { - "source-map": "0.5.7" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - } + } + }, + "gulp-better-rollup": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gulp-better-rollup/-/gulp-better-rollup-2.0.0.tgz", + "integrity": "sha512-CmK3LYY9RTXliAtptVisaGLP5XG3m3y5k0TV7bA9ksYgDSwPtHjnc0IzIZvYwRXfhWL1Uoscz5FZ7a4ieXHPcQ==", + "dev": true, + "requires": { + "gulp-util": "3.0.8", + "lodash.camelcase": "4.3.0", + "rollup": "0.50.0", + "vinyl-sourcemaps-apply": "0.2.1" } }, "gulp-clean-css": { @@ -2149,32 +3383,6 @@ "gulp-util": "3.0.8", "through2": "2.0.3", "vinyl-sourcemaps-apply": "0.2.1" - }, - "dependencies": { - "clean-css": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz", - "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "vinyl-sourcemaps-apply": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - } } }, "gulp-concat": { @@ -2194,68 +3402,18 @@ "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", "dev": true }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", - "dev": true - }, "clone-stats": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", "dev": true }, - "cloneable-readable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.0.0.tgz", - "integrity": "sha1-pikNQT8hemEjL5XkWP84QYz7ARc=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "process-nextick-args": "1.0.7", - "through2": "2.0.3" - } - }, - "concat-with-sourcemaps": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz", - "integrity": "sha1-9Vs74q60dgGxCi1SWcz7cP0vHdY=", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, "replace-ext": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", "dev": true }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, "vinyl": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", @@ -2284,928 +3442,6 @@ "object-assign": "4.1.1", "through2": "2.0.3", "vinyl-sourcemaps-apply": "0.2.1" - }, - "dependencies": { - "accord": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/accord/-/accord-0.27.3.tgz", - "integrity": "sha1-f7kSlwkoXK6oTrNyxOiCAxtxOOg=", - "dev": true, - "requires": { - "convert-source-map": "1.5.0", - "glob": "7.1.2", - "indx": "0.2.3", - "lodash.clone": "4.5.0", - "lodash.defaults": "4.2.0", - "lodash.flatten": "4.4.0", - "lodash.merge": "4.6.0", - "lodash.partialright": "4.2.1", - "lodash.pick": "4.4.0", - "lodash.uniq": "4.5.0", - "resolve": "1.5.0", - "semver": "5.4.1", - "uglify-js": "2.8.29", - "when": "3.7.8" - } - }, - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true, - "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" - } - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true, - "optional": true - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true, - "optional": true - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" - } - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", - "wordwrap": "0.0.2" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true, - "optional": true - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "convert-source-map": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", - "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true, - "optional": true - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "errno": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", - "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", - "dev": true, - "optional": true, - "requires": { - "prr": "0.0.0" - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true, - "optional": true - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" - } - }, - "image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", - "dev": true, - "optional": true - }, - "indx": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/indx/-/indx-0.2.3.tgz", - "integrity": "sha1-Fdz1bunPZcAjTFE8J/vVgOcPvFA=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true, - "optional": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true, - "optional": true - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true - }, - "less": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", - "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", - "dev": true, - "requires": { - "errno": "0.1.4", - "graceful-fs": "4.1.11", - "image-size": "0.5.5", - "mime": "1.4.1", - "mkdirp": "0.5.1", - "promise": "7.3.1", - "request": "2.81.0", - "source-map": "0.5.7" - } - }, - "lodash.clone": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", - "dev": true - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", - "dev": true - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz", - "integrity": "sha1-aYhLoUSsM/5plzemCG3v+t0PicU=", - "dev": true - }, - "lodash.partialright": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.partialright/-/lodash.partialright-4.2.1.tgz", - "integrity": "sha1-ATDYDoM2MmTUAHTzKbij56ihzEs=", - "dev": true - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true - }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true, - "optional": true - }, - "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", - "dev": true - }, - "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "dev": true, - "requires": { - "mime-db": "1.30.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true, - "optional": true - }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dev": true, - "optional": true, - "requires": { - "asap": "2.0.6" - } - }, - "prr": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", - "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", - "dev": true, - "optional": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true, - "optional": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - } - }, - "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", - "dev": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "requires": { - "align-text": "0.1.4" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "optional": true, - "requires": { - "hoek": "2.16.3" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true, - "optional": true - }, - "tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dev": true, - "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true, - "optional": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "1.3.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "optional": true - } - } - }, - "vinyl-sourcemaps-apply": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - }, - "when": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", - "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", - "dev": true - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", - "window-size": "0.1.0" - } - } } }, "gulp-open": { @@ -3218,20 +3454,6 @@ "gulp-util": "3.0.8", "open": "0.0.5", "through2": "2.0.3" - }, - "dependencies": { - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true - }, - "open": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz", - "integrity": "sha1-QsPhjslUZra/DcQvOilFw/DK2Pw=", - "dev": true - } } }, "gulp-rename": { @@ -3249,113 +3471,6 @@ "istextorbinary": "1.0.2", "readable-stream": "2.3.3", "replacestream": "4.0.3" - }, - "dependencies": { - "binaryextensions": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.1.tgz", - "integrity": "sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "istextorbinary": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz", - "integrity": "sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8=", - "dev": true, - "requires": { - "binaryextensions": "1.0.1", - "textextensions": "1.0.2" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "replacestream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", - "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", - "dev": true, - "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1", - "readable-stream": "2.3.3" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "textextensions": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz", - "integrity": "sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI=", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - } } }, "gulp-s3": { @@ -3365,7 +3480,7 @@ "dev": true, "requires": { "async": "2.5.0", - "event-stream": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "event-stream": "3.3.4", "gulp-util": "2.2.20", "knox": "0.9.2", "mime": "1.2.11" @@ -3383,43 +3498,6 @@ "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", "dev": true }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "async": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", - "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", - "dev": true, - "requires": { - "lodash": "4.17.4" - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" - } - }, "chalk": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", @@ -3433,27 +3511,6 @@ "supports-color": "0.2.0" } }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "1.0.2" - } - }, "dateformat": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", @@ -3464,67 +3521,12 @@ "meow": "3.7.0" } }, - "debug": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.5.tgz", - "integrity": "sha1-9yQSF0MPmd7EwrRz6rkiKOh0wqw=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "requires": { - "readable-stream": "1.1.14" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, "gulp-util": { "version": "2.2.20", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz", @@ -3550,153 +3552,18 @@ "ansi-regex": "0.2.1" } }, - "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "2.0.1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, - "knox": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/knox/-/knox-0.9.2.tgz", - "integrity": "sha1-NzZZNmniTwJP2vcjtqHcSv2DmnE=", - "dev": true, - "requires": { - "debug": "1.0.5", - "mime": "1.2.11", - "once": "1.4.0", - "stream-counter": "1.0.0", - "xml2js": "0.4.19" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - } - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true - }, - "lodash._escapehtmlchar": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz", - "integrity": "sha1-32fDu2t+jh6DGrSL+geVuSr+iZ0=", - "dev": true, - "requires": { - "lodash._htmlescapes": "2.4.1" - } - }, - "lodash._escapestringchar": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz", - "integrity": "sha1-7P4iYYoq3lC/7qQ5N+Ud9m8O23I=", - "dev": true - }, - "lodash._htmlescapes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz", - "integrity": "sha1-MtFL8IRLbeb4tioFG09nwii2JMs=", - "dev": true - }, - "lodash._isnative": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", - "integrity": "sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw=", - "dev": true - }, - "lodash._objecttypes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", - "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", - "dev": true - }, "lodash._reinterpolate": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz", "integrity": "sha1-TxInqlqHEfxjL1sHofRgequLMiI=", "dev": true }, - "lodash._reunescapedhtml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz", - "integrity": "sha1-dHxPxAED6zu4oJduVx96JlnpO6c=", - "dev": true, - "requires": { - "lodash._htmlescapes": "2.4.1", - "lodash.keys": "2.4.1" - } - }, - "lodash._shimkeys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", - "integrity": "sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=", - "dev": true, - "requires": { - "lodash._objecttypes": "2.4.1" - } - }, "lodash.defaults": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.4.1.tgz", @@ -3718,15 +3585,6 @@ "lodash.keys": "2.4.1" } }, - "lodash.isobject": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", - "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", - "dev": true, - "requires": { - "lodash._objecttypes": "2.4.1" - } - }, "lodash.keys": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", @@ -3763,57 +3621,6 @@ "lodash.escape": "2.4.1" } }, - "lodash.values": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-2.4.1.tgz", - "integrity": "sha1-q/UUQ2s8twUAFieXjLzzCxKA7qQ=", - "dev": true, - "requires": { - "lodash.keys": "2.4.1" - } - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.2" - } - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.4.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, "mime": { "version": "1.2.11", "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", @@ -3826,129 +3633,10 @@ "integrity": "sha1-Tf/lJdriuGTGbC4jxicdev3s784=", "dev": true }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "requires": { - "duplexer2": "0.0.2" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.1" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "1.3.1" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - } - }, "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { "core-util-is": "1.0.2", @@ -3957,70 +3645,6 @@ "string_decoder": "0.10.31" } }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" - } - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "1.0.2" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "dev": true, - "requires": { - "spdx-license-ids": "1.2.2" - } - }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", - "dev": true - }, - "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", - "dev": true - }, - "stream-counter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-1.0.0.tgz", - "integrity": "sha1-kc8lac5NxQYf6816yyY5SloRR1E=", - "dev": true - }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -4036,24 +3660,6 @@ "ansi-regex": "0.2.1" } }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "0.2.1" - } - }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "4.0.1" - } - }, "supports-color": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", @@ -4068,36 +3674,6 @@ "requires": { "readable-stream": "1.0.34", "xtend": "3.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - } - } - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "dev": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" } }, "vinyl": { @@ -4109,28 +3685,6 @@ "clone-stats": "0.0.1" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dev": true, - "requires": { - "sax": "1.2.4", - "xmlbuilder": "9.0.4" - } - }, - "xmlbuilder": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", - "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=", - "dev": true - }, "xtend": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", @@ -4150,1496 +3704,6 @@ "node-sass": "4.5.3", "through2": "2.0.3", "vinyl-sourcemaps-apply": "0.2.1" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "ajv": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", - "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", - "dev": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", - "dev": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.3" - } - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "async-foreach": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", - "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "dev": true, - "requires": { - "hoek": "4.2.0" - } - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cross-spawn": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", - "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", - "dev": true, - "requires": { - "lru-cache": "4.1.1", - "which": "1.3.0" - } - }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "dev": true, - "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "dev": true, - "requires": { - "hoek": "4.2.0" - } - } - } - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "1.0.2" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "1.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.2" - } - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "gaze": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", - "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", - "dev": true, - "requires": { - "globule": "1.2.0" - } - }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", - "dev": true - }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "1.0.0" - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "globule": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", - "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", - "dev": true, - "requires": { - "glob": "7.1.2", - "lodash": "4.17.4", - "minimatch": "3.0.4" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "dev": true, - "requires": { - "ajv": "5.3.0", - "har-schema": "2.0.0" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "dev": true, - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.0", - "sntp": "2.1.0" - } - }, - "hoek": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", - "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", - "dev": true - }, - "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", - "dev": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" - } - }, - "in-publish": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", - "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "2.0.1" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "js-base64": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz", - "integrity": "sha512-Y2/+DnfJJXT1/FCwUebUhLWb3QihxiSC42+ctHLGogmW2jPY6LCapMdFZXRvVP2z6qyKW7s6qncE/9gSqZiArw==", - "dev": true - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "1.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - } - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true - }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.mergewith": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz", - "integrity": "sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=", - "dev": true - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.2" - } - }, - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.4.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" - } - }, - "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", - "dev": true - }, - "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "dev": true, - "requires": { - "mime-db": "1.30.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "nan": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", - "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", - "dev": true - }, - "node-gyp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", - "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", - "dev": true, - "requires": { - "fstream": "1.0.11", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "npmlog": "4.1.2", - "osenv": "0.1.4", - "request": "2.83.0", - "rimraf": "2.6.2", - "semver": "5.3.0", - "tar": "2.2.1", - "which": "1.3.0" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true - } - } - }, - "node-sass": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.5.3.tgz", - "integrity": "sha1-0JydEXlkEjnRuX/8YjH9zsU+FWg=", - "dev": true, - "requires": { - "async-foreach": "0.1.3", - "chalk": "1.1.3", - "cross-spawn": "3.0.1", - "gaze": "1.1.2", - "get-stdin": "4.0.1", - "glob": "7.1.2", - "in-publish": "2.0.0", - "lodash.assign": "4.2.0", - "lodash.clonedeep": "4.5.0", - "lodash.mergewith": "4.6.0", - "meow": "3.7.0", - "mkdirp": "0.5.1", - "nan": "2.7.0", - "node-gyp": "3.6.2", - "npmlog": "4.1.2", - "request": "2.83.0", - "sass-graph": "2.2.4", - "stdout-stream": "1.4.0" - } - }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "1.1.1" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "requires": { - "lcid": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "osenv": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", - "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", - "dev": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "1.3.1" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - } - }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" - } - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "1.0.2" - } - }, - "request": { - "version": "2.83.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", - "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", - "dev": true, - "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.1", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "sass-graph": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", - "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", - "dev": true, - "requires": { - "glob": "7.1.2", - "lodash": "4.17.4", - "scss-tokenizer": "0.2.3", - "yargs": "7.1.0" - } - }, - "scss-tokenizer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", - "dev": true, - "requires": { - "js-base64": "2.3.2", - "source-map": "0.4.4" - } - }, - "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "dev": true, - "requires": { - "hoek": "4.2.0" - } - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": "1.0.1" - } - }, - "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "dev": true, - "requires": { - "spdx-license-ids": "1.2.2" - } - }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", - "dev": true - }, - "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", - "dev": true - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "dev": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - } - }, - "stdout-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", - "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", - "dev": true, - "requires": { - "readable-stream": "2.3.3" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "0.2.1" - } - }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "4.0.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", - "dev": true, - "requires": { - "block-stream": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", - "dev": true, - "requires": { - "punycode": "1.4.1" - } - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "dev": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "1.3.0" - } - }, - "vinyl-sourcemaps-apply": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", - "dev": true, - "requires": { - "source-map": "0.5.7" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", - "dev": true, - "requires": { - "isexe": "2.0.0" - } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, - "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", - "dev": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "dev": true, - "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "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" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - } - } - }, - "yargs-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", - "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "dev": true, - "requires": { - "camelcase": "3.0.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - } - } - } } }, "gulp-size": { @@ -5657,18 +3721,6 @@ "through2": "2.0.3" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -5682,63 +3734,6 @@ "supports-color": "2.0.0" } }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "gzip-size": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", - "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", - "dev": true, - "requires": { - "duplexer": "0.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "pretty-bytes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", - "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "stream-counter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-1.0.0.tgz", - "integrity": "sha1-kc8lac5NxQYf6816yyY5SloRR1E=", - "dev": true - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -5747,201 +3742,58 @@ "requires": { "ansi-regex": "2.1.1" } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true } } }, - "gulp-svgmin": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/gulp-svgmin/-/gulp-svgmin-1.2.4.tgz", - "integrity": "sha1-pKqeJhXPEQXvVVrqhuhilswg4nM=", + "gulp-sourcemaps": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.1.tgz", + "integrity": "sha512-1qHCI3hdmsMdq/SUotxwUh/L8YzlI6J9zQ5ifNOtx4Y6KV5y5sGuORv1KZzWhuKtz/mXNh5xLESUtwC4EndCjA==", "dev": true, "requires": { - "gulp-util": "3.0.8", - "svgo": "0.7.2" + "@gulp-sourcemaps/identity-map": "1.0.1", + "@gulp-sourcemaps/map-sources": "1.0.0", + "acorn": "4.0.13", + "convert-source-map": "1.5.0", + "css": "2.2.1", + "debug-fabulous": "0.2.1", + "detect-newline": "2.1.0", + "graceful-fs": "4.1.11", + "source-map": "0.6.1", + "strip-bom-string": "1.0.0", + "through2": "2.0.3", + "vinyl": "1.2.0" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "argparse": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "dev": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "clap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", - "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", - "dev": true, - "requires": { - "chalk": "1.1.3" - } - }, - "coa": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", - "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", - "dev": true, - "requires": { - "q": "1.5.1" - } - }, - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true - }, - "csso": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", - "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", - "dev": true, - "requires": { - "clap": "1.2.3", - "source-map": "0.5.7" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "js-yaml": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", - "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", - "dev": true, - "requires": { - "argparse": "1.0.9", - "esprima": "2.7.3" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", "dev": true }, - "svgo": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", - "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, "requires": { - "coa": "1.0.4", - "colors": "1.1.2", - "csso": "2.3.2", - "js-yaml": "3.7.0", - "mkdirp": "0.5.1", - "sax": "1.2.4", - "whet.extend": "0.9.9" + "clone": "1.0.2", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" } - }, - "whet.extend": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", - "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", - "dev": true } } }, + "gulp-svgmin": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/gulp-svgmin/-/gulp-svgmin-1.2.4.tgz", + "integrity": "sha1-pKqeJhXPEQXvVVrqhuhilswg4nM=", + "dev": true, + "requires": { + "gulp-util": "3.0.8", + "svgo": "0.7.2" + } + }, "gulp-svgstore": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/gulp-svgstore/-/gulp-svgstore-6.1.0.tgz", @@ -5950,370 +3802,6 @@ "requires": { "cheerio": "0.22.0", "gulp-util": "3.0.8" - }, - "dependencies": { - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", - "dev": true, - "requires": { - "css-select": "1.2.0", - "dom-serializer": "0.1.0", - "entities": "1.1.1", - "htmlparser2": "3.9.2", - "lodash.assignin": "4.2.0", - "lodash.bind": "4.2.1", - "lodash.defaults": "4.2.0", - "lodash.filter": "4.6.0", - "lodash.flatten": "4.4.0", - "lodash.foreach": "4.5.0", - "lodash.map": "4.6.0", - "lodash.merge": "4.6.0", - "lodash.pick": "4.4.0", - "lodash.reduce": "4.6.0", - "lodash.reject": "4.6.0", - "lodash.some": "4.6.0" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "dev": true, - "requires": { - "boolbase": "1.0.0", - "css-what": "2.1.0", - "domutils": "1.5.1", - "nth-check": "1.0.1" - } - }, - "css-what": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", - "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", - "dev": true - }, - "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", - "dev": true, - "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - } - } - }, - "domelementtype": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", - "dev": true - }, - "domhandler": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", - "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", - "dev": true, - "requires": { - "domelementtype": "1.3.0" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" - } - }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", - "dev": true - }, - "htmlparser2": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", - "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", - "dev": true, - "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.4.1", - "domutils": "1.5.1", - "entities": "1.1.1", - "inherits": "2.0.3", - "readable-stream": "2.3.3" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=", - "dev": true - }, - "lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=", - "dev": true - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", - "dev": true - }, - "lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=", - "dev": true - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", - "dev": true - }, - "lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=", - "dev": true - }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz", - "integrity": "sha1-aYhLoUSsM/5plzemCG3v+t0PicU=", - "dev": true - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", - "dev": true - }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=", - "dev": true - }, - "lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=", - "dev": true - }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", - "dev": true - }, - "nth-check": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", - "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", - "dev": true, - "requires": { - "boolbase": "1.0.0" - } - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - } - } - }, - "gulp-uglify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.0.tgz", - "integrity": "sha1-DfAzHXKg0wLj434QlIXd3zPG0co=", - "dev": true, - "requires": { - "gulplog": "1.0.0", - "has-gulplog": "0.1.0", - "lodash": "4.17.4", - "make-error-cause": "1.2.2", - "through2": "2.0.3", - "uglify-js": "3.1.5", - "vinyl-sourcemaps-apply": "0.2.1" - }, - "dependencies": { - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true - }, - "glogg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", - "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", - "dev": true, - "requires": { - "sparkles": "1.0.0" - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "requires": { - "glogg": "1.0.0" - } - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "dev": true, - "requires": { - "sparkles": "1.0.0" - } - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true - }, - "make-error": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz", - "integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y=", - "dev": true - }, - "make-error-cause": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz", - "integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=", - "dev": true, - "requires": { - "make-error": "1.3.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "sparkles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", - "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=", - "dev": true - }, - "uglify-js": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.5.tgz", - "integrity": "sha512-tSqlO7/GZHAVSw6mbtJt2kz0ZcUrKUH7Xg92o52aE+gL0r6cXiASZY4dpHqQ7RVGXmoQuPA2qAkG4TkP59f8XA==", - "dev": true, - "requires": { - "commander": "2.11.0", - "source-map": "0.6.1" - } - }, - "vinyl-sourcemaps-apply": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", - "dev": true, - "requires": { - "source-map": "0.5.7" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - } } }, "gulp-util": { @@ -6342,36 +3830,6 @@ "vinyl": "0.5.3" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -6385,273 +3843,18 @@ "supports-color": "2.0.0" } }, - "clone": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", - "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true - }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "requires": { - "readable-stream": "1.1.14" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "fancy-log": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz", - "integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "time-stamp": "1.1.0" - } - }, - "glogg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", - "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", - "dev": true, - "requires": { - "sparkles": "1.0.0" - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "requires": { - "glogg": "1.0.0" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "dev": true, - "requires": { - "sparkles": "1.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "requires": { - "lodash._root": "3.0.1" - } - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" - } - }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "3.0.1", - "lodash._basetostring": "3.0.1", - "lodash._basevalues": "3.0.0", - "lodash._isiterateecall": "3.0.9", - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0", - "lodash.keys": "3.1.2", - "lodash.restparam": "3.6.1", - "lodash.templatesettings": "3.1.1" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "requires": { - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0" - } - }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "requires": { - "duplexer2": "0.0.2" - } - }, "object-assign": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", "dev": true }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true - }, - "sparkles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", - "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=", - "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -6660,32 +3863,64 @@ "requires": { "ansi-regex": "2.1.1" } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true - }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "requires": { + "glogg": "1.0.0" + } + }, + "gzip-size": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", + "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", + "dev": true, + "requires": { + "duplexer": "0.1.1" + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "dev": true, "requires": { - "clone": "1.0.2", - "clone-stats": "0.0.1", - "replace-ext": "0.0.1" + "co": "4.6.0", + "json-stable-stringify": "1.0.1" } } } }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -6701,6 +3936,58 @@ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, + "has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "dev": true, + "requires": { + "sparkles": "1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "1.0.0" + } + }, "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", @@ -6713,6 +4000,31 @@ "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", "dev": true }, + "htmlparser2": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.4.1", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", @@ -6725,12 +4037,25 @@ "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", "dev": true }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "dev": true + }, "indent-string": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", @@ -6746,6 +4071,12 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, + "indx": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/indx/-/indx-0.2.3.tgz", + "integrity": "sha1-Fdz1bunPZcAjTFE8J/vVgOcPvFA=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -6757,10 +4088,17 @@ } }, "inherits": { - "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "dev": true + }, "inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", @@ -6781,14 +4119,37 @@ "string-width": "2.1.1", "strip-ansi": "4.0.0", "through": "2.3.8" - }, - "dependencies": { - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - } + } + }, + "interpret": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", + "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=", + "dev": true + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-absolute": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.6.tgz", + "integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=", + "dev": true, + "requires": { + "is-relative": "0.2.1", + "is-windows": "0.2.0" } }, "is-arrayish": { @@ -6812,6 +4173,18 @@ "builtin-modules": "1.1.1" } }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", @@ -6869,6 +4242,12 @@ "is-extglob": "1.0.0" } }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", @@ -6937,12 +4316,30 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.1" + } + }, "is-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", "dev": true }, + "is-relative": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.2.1.tgz", + "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", + "dev": true, + "requires": { + "is-unc-path": "0.1.2" + } + }, "is-resolvable": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", @@ -6952,18 +4349,51 @@ "tryit": "1.0.3" } }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, "is-supported-regexp-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.0.tgz", "integrity": "sha1-i1IMhfrnolM4LUsCZS4EVXbhO7g=", "dev": true }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-unc-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-0.1.2.tgz", + "integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=", + "dev": true, + "requires": { + "unc-path-regex": "0.1.2" + } + }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, + "is-windows": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", + "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -6985,6 +4415,32 @@ "isarray": "1.0.0" } }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "dev": true, + "requires": { + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.3" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istextorbinary": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz", + "integrity": "sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8=", + "dev": true, + "requires": { + "binaryextensions": "1.0.1", + "textextensions": "1.0.2" + } + }, "js-base64": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz", @@ -7007,10 +4463,29 @@ "esprima": "4.0.0" } }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, "jschardet": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz", - "integrity": "sha512-vE2hT1D0HLZCLLclfBSfkfTTedhVj0fubHpJBHKwwUWX0nSbhPAfk+SG9rTX95BYNmau8rGFfCeaT6T5OW1C2A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.6.0.tgz", + "integrity": "sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ==", + "dev": true + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, "json-schema-traverse": { @@ -7028,12 +4503,50 @@ "jsonify": "0.0.0" } }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "dev": true }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -7049,6 +4562,70 @@ "integrity": "sha512-n+ThoCKhyMFKkMfksdLMP5ndp+VzwDRzQdH6JlmZ2GTpUenYB2EeEKjOue2SErAAG/MmBSUISpwvawDhydWQdQ==", "dev": true }, + "knox": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/knox/-/knox-0.9.2.tgz", + "integrity": "sha1-NzZZNmniTwJP2vcjtqHcSv2DmnE=", + "dev": true, + "requires": { + "debug": "1.0.5", + "mime": "1.4.1", + "once": "1.4.0", + "stream-counter": "1.0.0", + "xml2js": "0.4.19" + }, + "dependencies": { + "debug": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.5.tgz", + "integrity": "sha1-9yQSF0MPmd7EwrRz6rkiKOh0wqw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "less": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", + "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", + "dev": true, + "requires": { + "errno": "0.1.4", + "graceful-fs": "4.1.11", + "image-size": "0.5.5", + "mime": "1.4.1", + "mkdirp": "0.5.1", + "promise": "7.3.1", + "request": "2.81.0", + "source-map": "0.5.7" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -7059,6 +4636,23 @@ "type-check": "0.3.2" } }, + "liftoff": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.3.0.tgz", + "integrity": "sha1-qY8v9nGD2Lp8+soQVIvX/wVQs4U=", + "dev": true, + "requires": { + "extend": "3.0.1", + "findup-sync": "0.4.3", + "fined": "1.1.0", + "flagged-respawn": "0.3.2", + "lodash.isplainobject": "4.0.6", + "lodash.isstring": "4.0.1", + "lodash.mapvalues": "4.6.0", + "rechoir": "0.6.2", + "resolve": "1.5.0" + } + }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -7072,23 +4666,394 @@ "strip-bom": "2.0.0" }, "dependencies": { - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "error-ex": "1.3.1" + "is-utf8": "0.2.1" } } } }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", "dev": true }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", + "dev": true + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "dev": true + }, + "lodash._escapehtmlchar": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz", + "integrity": "sha1-32fDu2t+jh6DGrSL+geVuSr+iZ0=", + "dev": true, + "requires": { + "lodash._htmlescapes": "2.4.1" + } + }, + "lodash._escapestringchar": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz", + "integrity": "sha1-7P4iYYoq3lC/7qQ5N+Ud9m8O23I=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._htmlescapes": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz", + "integrity": "sha1-MtFL8IRLbeb4tioFG09nwii2JMs=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash._isnative": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", + "integrity": "sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw=", + "dev": true + }, + "lodash._objecttypes": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", + "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", + "dev": true + }, + "lodash._reescape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "dev": true + }, + "lodash._reevaluate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash._reunescapedhtml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz", + "integrity": "sha1-dHxPxAED6zu4oJduVx96JlnpO6c=", + "dev": true, + "requires": { + "lodash._htmlescapes": "2.4.1", + "lodash.keys": "2.4.1" + }, + "dependencies": { + "lodash.keys": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", + "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", + "dev": true, + "requires": { + "lodash._isnative": "2.4.1", + "lodash._shimkeys": "2.4.1", + "lodash.isobject": "2.4.1" + } + } + } + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "dev": true + }, + "lodash._shimkeys": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", + "integrity": "sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=", + "dev": true, + "requires": { + "lodash._objecttypes": "2.4.1" + } + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=", + "dev": true + }, + "lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.clone": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", + "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", + "dev": true + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "dev": true, + "requires": { + "lodash._root": "3.0.1" + } + }, + "lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=", + "dev": true + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.isobject": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", + "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", + "dev": true, + "requires": { + "lodash._objecttypes": "2.4.1" + } + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "dev": true + }, + "lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz", + "integrity": "sha1-aYhLoUSsM/5plzemCG3v+t0PicU=", + "dev": true + }, + "lodash.mergewith": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz", + "integrity": "sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=", + "dev": true + }, + "lodash.partialright": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.partialright/-/lodash.partialright-4.2.1.tgz", + "integrity": "sha1-ATDYDoM2MmTUAHTzKbij56ihzEs=", + "dev": true + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", + "dev": true + }, + "lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=", + "dev": true + }, + "lodash.reject": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=", + "dev": true + }, + "lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "dev": true + }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "dev": true + }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash._basetostring": "3.0.1", + "lodash._basevalues": "3.0.0", + "lodash._isiterateecall": "3.0.9", + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0", + "lodash.keys": "3.1.2", + "lodash.restparam": "3.6.1", + "lodash.templatesettings": "3.1.1" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "dev": true, + "requires": { + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "lodash.values": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-2.4.1.tgz", + "integrity": "sha1-q/UUQ2s8twUAFieXjLzzCxKA7qQ=", + "dev": true, + "requires": { + "lodash.keys": "2.4.1" + }, + "dependencies": { + "lodash.keys": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", + "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", + "dev": true, + "requires": { + "lodash._isnative": "2.4.1", + "lodash._shimkeys": "2.4.1", + "lodash.isobject": "2.4.1" + } + } + } + }, "log-symbols": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.1.0.tgz", @@ -7098,6 +5063,21 @@ "chalk": "2.3.0" } }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -7118,6 +5098,30 @@ "yallist": "2.1.2" } }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "dev": true, + "requires": { + "es5-ext": "0.10.35" + } + }, + "magic-string": { + "version": "0.22.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.4.tgz", + "integrity": "sha512-kxBL06p6iO2qPBHsqGK2b3cRwiRGpnmSuVWNhwHcMX7qJOUr1HvricYP1LZOCdkQBUp0jiWg2d6WJwR3vYgByw==", + "dev": true, + "requires": { + "vlq": "0.2.3" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -7125,7 +5129,8 @@ "dev": true }, "map-stream": { - "version": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", "dev": true }, @@ -7135,6 +5140,22 @@ "integrity": "sha1-jUEmgWi/htEQK5gQnijlMeejRXg=", "dev": true }, + "memoizee": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.11.tgz", + "integrity": "sha1-vemBdmPJ5A/bKk6hw2cpYIeujI8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.35", + "es6-weak-map": "2.0.2", + "event-emitter": "0.3.5", + "is-promise": "2.1.0", + "lru-queue": "0.1.0", + "next-tick": "1.0.0", + "timers-ext": "0.1.2" + } + }, "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -7182,6 +5203,27 @@ "regex-cache": "0.4.4" } }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, "mimic-fn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", @@ -7218,18 +5260,179 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "dev": true, + "requires": { + "duplexer2": "0.0.2" + } + }, "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "nan": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", + "dev": true + }, + "natives": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz", + "integrity": "sha1-6f+EFBimsux6SV6TmYT3jxY+bjE=", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dev": true, + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "node-gyp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", + "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", + "dev": true, + "requires": { + "fstream": "1.0.11", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.1.2", + "osenv": "0.1.4", + "request": "2.81.0", + "rimraf": "2.6.2", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "node-sass": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.5.3.tgz", + "integrity": "sha1-0JydEXlkEjnRuX/8YjH9zsU+FWg=", + "dev": true, + "requires": { + "async-foreach": "0.1.3", + "chalk": "1.1.3", + "cross-spawn": "3.0.1", + "gaze": "1.1.2", + "get-stdin": "4.0.1", + "glob": "7.1.2", + "in-publish": "2.0.0", + "lodash.assign": "4.2.0", + "lodash.clonedeep": "4.5.0", + "lodash.mergewith": "4.6.0", + "meow": "3.7.0", + "mkdirp": "0.5.1", + "nan": "2.7.0", + "node-gyp": "3.6.2", + "npmlog": "4.1.2", + "request": "2.81.0", + "sass-graph": "2.2.4", + "stdout-stream": "1.4.0" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "which": "1.3.0" + } + }, + "gaze": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "dev": true, + "requires": { + "globule": "1.2.0" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "globule": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", + "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", + "dev": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.4", + "minimatch": "3.0.4" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1.1.1" + } + }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -7263,6 +5466,27 @@ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", "dev": true }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "1.0.0" + } + }, "num2fraction": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", @@ -7275,12 +5499,24 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, "object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", @@ -7293,12 +5529,6 @@ "isobject": "3.0.1" }, "dependencies": { - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, "for-own": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", @@ -7361,6 +5591,12 @@ "mimic-fn": "1.1.0" } }, + "open": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz", + "integrity": "sha1-QsPhjslUZra/DcQvOilFw/DK2Pw=", + "dev": true + }, "optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", @@ -7375,12 +5611,80 @@ "wordwrap": "1.0.0" } }, + "orchestrator": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", + "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "dev": true, + "requires": { + "end-of-stream": "0.1.5", + "sequencify": "0.0.7", + "stream-consume": "0.1.0" + } + }, + "ordered-read-streams": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", + "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "1.0.0" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "osenv": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.1.0" + } + }, + "parse-filepath": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.1.tgz", + "integrity": "sha1-FZ1hVdQ5BNFsEO9piRHaHpGWm3M=", + "dev": true, + "requires": { + "is-absolute": "0.2.6", + "map-cache": "0.2.2", + "path-root": "0.1.1" + } + }, "parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", @@ -7394,14 +5698,20 @@ } }, "parse-json": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-3.0.0.tgz", - "integrity": "sha1-+m9HsY4jgm6tMvJj50TQ4ehH+xM=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { "error-ex": "1.3.1" } }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -7423,6 +5733,27 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "requires": { + "path-root-regex": "0.1.2" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true + }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", @@ -7435,13 +5766,20 @@ } }, "pause-stream": { - "version": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { - "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + "through": "2.3.8" } }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -7463,6 +5801,15 @@ "pinkie": "2.0.4" } }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -7636,6 +5983,27 @@ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "dev": true }, + "pretty-bytes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", + "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", @@ -7648,12 +6016,57 @@ "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", "dev": true }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "requires": { + "asap": "2.0.6" + } + }, + "prop-types": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz", + "integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=", + "dev": true, + "requires": { + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" + } + }, + "prr": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "dev": true, + "optional": true + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true + }, "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", @@ -7729,14 +6142,15 @@ "safe-buffer": "5.1.1", "string_decoder": "1.0.3", "util-deprecate": "1.0.2" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "1.5.0" } }, "redent": { @@ -7749,6 +6163,29 @@ "strip-indent": "1.0.1" } }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.8" + } + }, "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", @@ -7758,6 +6195,40 @@ "is-equal-shallow": "0.1.3" } }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "1.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -7785,12 +6256,71 @@ "is-finite": "1.0.2" } }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, + "replacestream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", + "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1", + "readable-stream": "2.3.3" + } + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, "require-from-string": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.1.tgz", "integrity": "sha1-xUUjPp19pmFunVmt+zn8n1iGdv8=", "dev": true }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, "require-uncached": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", @@ -7801,12 +6331,37 @@ "resolve-from": "1.0.1" } }, + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", + "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", + "dev": true, + "requires": { + "expand-tilde": "1.2.2", + "global-modules": "0.2.3" + } + }, "resolve-from": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", "dev": true }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -7817,6 +6372,15 @@ "signal-exit": "3.0.2" } }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "0.1.4" + } + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -7826,6 +6390,109 @@ "glob": "7.1.2" } }, + "rollup": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.50.0.tgz", + "integrity": "sha512-7RqCBQ9iwsOBPkjYgoIaeUij606mSkDMExP0NT7QDI3bqkHYQHrQ83uoNIXwPcQm/vP2VbsUz3kiyZZ1qPlLTQ==", + "dev": true + }, + "rollup-plugin-babel": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-3.0.2.tgz", + "integrity": "sha512-ALGPBFtwJZcYHsNPM6RGJlEncTzAARPvZOGjNPZgDe5hS5t6sJGjiOWibEFVEz5LQN7S7spvCBILaS4N1Cql2w==", + "dev": true, + "requires": { + "rollup-pluginutils": "1.5.2" + } + }, + "rollup-plugin-commonjs": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-8.2.6.tgz", + "integrity": "sha512-qK0+uhktmnAgZkHkqFuajNmPw93fjrO7+CysDaxWE5jrUR9XSlSvuao5ZJP+XizxA8weakhgYYBtbVz9SGBpjA==", + "dev": true, + "requires": { + "acorn": "5.2.1", + "estree-walker": "0.5.0", + "magic-string": "0.22.4", + "resolve": "1.5.0", + "rollup-pluginutils": "2.0.1" + }, + "dependencies": { + "acorn": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", + "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==", + "dev": true + }, + "estree-walker": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.0.tgz", + "integrity": "sha512-/bEAy+yKAZQrEWUhGmS3H9XpGqSDBtRzX0I2PgMw9kA2n1jN22uV5B5p7MFdZdvWdXCRJztXAfx6ZeRfgkEETg==", + "dev": true + }, + "rollup-pluginutils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.0.1.tgz", + "integrity": "sha1-fslbNXP2VDpGpkYb2afFRFJdD8A=", + "dev": true, + "requires": { + "estree-walker": "0.3.1", + "micromatch": "2.3.11" + }, + "dependencies": { + "estree-walker": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.3.1.tgz", + "integrity": "sha1-5rGlHPcpJSTnI3wxLl/mZgwc4ao=", + "dev": true + } + } + } + } + }, + "rollup-plugin-node-resolve": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.0.0.tgz", + "integrity": "sha1-i4l8TDAw1QASd7BRSyXSygloPuA=", + "dev": true, + "requires": { + "browser-resolve": "1.11.2", + "builtin-modules": "1.1.1", + "is-module": "1.0.0", + "resolve": "1.5.0" + } + }, + "rollup-plugin-uglify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-uglify/-/rollup-plugin-uglify-2.0.1.tgz", + "integrity": "sha1-Z7N60e/a+9g69MNrQMGJ7khmyWk=", + "dev": true, + "requires": { + "uglify-js": "3.1.6" + }, + "dependencies": { + "uglify-js": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.6.tgz", + "integrity": "sha512-/rseyxEKEVMBo8279lqpoJgD6C/i/CIi+9TJDvWmb+Xo6mqMKwjA8Io3IMHlcXQzj99feR6zrN8m3wqqvm/nYA==", + "dev": true, + "requires": { + "commander": "2.11.0", + "source-map": "0.6.1" + } + } + } + }, + "rollup-pluginutils": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz", + "integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=", + "dev": true, + "requires": { + "estree-walker": "0.2.1", + "minimatch": "3.0.4" + } + }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", @@ -7845,18 +6512,6 @@ "gulp-util": "3.0.8" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -7870,21 +6525,6 @@ "supports-color": "2.0.0" } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -7893,12 +6533,6 @@ "requires": { "ansi-regex": "2.1.1" } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true } } }, @@ -7923,12 +6557,138 @@ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "dev": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.4", + "scss-tokenizer": "0.2.3", + "yargs": "7.1.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "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" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "requires": { + "js-base64": "2.3.2", + "source-map": "0.4.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", "dev": true }, + "sequencify": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", + "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -7944,12 +6704,24 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", @@ -7959,12 +6731,62 @@ "is-fullwidth-code-point": "2.0.0" } }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "source-map-resolve": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.3.1.tgz", + "integrity": "sha1-YQ9hIqRFuN1RU1oqcbeD38Ekh2E=", + "dev": true, + "requires": { + "atob": "1.1.3", + "resolve-url": "0.2.1", + "source-map-url": "0.3.0", + "urix": "0.1.0" + } + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz", + "integrity": "sha1-fsrxO1e80J2opAxdJp2zN5nUqvk=", + "dev": true + }, + "sparkles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", + "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=", + "dev": true + }, "spdx-correct": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", @@ -7993,11 +6815,12 @@ "dev": true }, "split": { - "version": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "dev": true, "requires": { - "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + "through": "2.3.8" } }, "sprintf-js": { @@ -8006,14 +6829,60 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "stdout-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", + "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "dev": true, + "requires": { + "readable-stream": "2.3.3" + } + }, "stream-combiner": { - "version": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", "dev": true, "requires": { - "duplexer": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz" + "duplexer": "0.1.1" } }, + "stream-consume": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", + "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", + "dev": true + }, + "stream-counter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-1.0.0.tgz", + "integrity": "sha1-kc8lac5NxQYf6816yyY5SloRR1E=", + "dev": true + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -8033,6 +6902,12 @@ "safe-buffer": "5.1.1" } }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -8051,14 +6926,21 @@ } }, "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", + "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", "dev": true, "requires": { + "first-chunk-stream": "1.0.0", "is-utf8": "0.2.1" } }, + "strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", + "dev": true + }, "strip-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", @@ -8210,6 +7092,39 @@ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", "dev": true }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "dev": true, + "requires": { + "coa": "1.0.4", + "colors": "1.1.2", + "csso": "2.3.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "sax": "1.2.4", + "whet.extend": "0.9.9" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "2.7.3" + } + } + } + }, "table": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", @@ -8224,14 +7139,32 @@ "string-width": "2.1.1" } }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "textextensions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz", + "integrity": "sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI=", + "dev": true + }, "through": { - "version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -8243,74 +7176,31 @@ "requires": { "readable-stream": "2.3.3", "xtend": "4.0.1" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - } + } + }, + "tildify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", + "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "timers-ext": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.2.tgz", + "integrity": "sha1-YcxHp2wavTGV8UUn+XjViulMUgQ=", + "dev": true, + "requires": { + "es5-ext": "0.10.35", + "next-tick": "1.0.0" } }, "tmp": { @@ -8322,18 +7212,55 @@ "os-tmpdir": "1.0.2" } }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, "tryit": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", "dev": true }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -8349,18 +7276,99 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "ua-parser-js": { + "version": "0.7.17", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz", + "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g==", + "dev": true + }, + "uglify-es": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.1.6.tgz", + "integrity": "sha512-7zyH8T4rT3/iLVzNI7Oa8hVQSlv280S8y2/a2EmvEObft3067rdUJJKjBspc70d0HUk1Og1V5Ny4UgZOlZ0hSg==", + "dev": true, + "requires": { + "commander": "2.11.0", + "source-map": "0.6.1" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true + }, "uniq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", "dev": true }, + "unique-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", + "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", + "dev": true + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "dev": true + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "dev": true, + "requires": { + "user-home": "1.1.1" + } + }, "validate-npm-package-license": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", @@ -8371,6 +7379,154 @@ "spdx-expression-parse": "1.0.4" } }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "dev": true, + "requires": { + "clone": "1.0.2", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + }, + "vinyl-fs": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", + "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", + "dev": true, + "requires": { + "defaults": "1.0.3", + "glob-stream": "3.1.18", + "glob-watcher": "0.0.6", + "graceful-fs": "3.0.11", + "mkdirp": "0.5.1", + "strip-bom": "1.0.0", + "through2": "0.6.5", + "vinyl": "0.4.6" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "dev": true + }, + "graceful-fs": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "dev": true, + "requires": { + "natives": "1.1.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + } + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "dev": true, + "requires": { + "clone": "0.2.0", + "clone-stats": "0.0.1" + } + } + } + }, + "vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "dev": true, + "requires": { + "source-map": "0.5.7" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true + }, + "whatwg-fetch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", + "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=", + "dev": true + }, + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "dev": true + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", + "dev": true + }, "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", @@ -8380,12 +7536,105 @@ "isexe": "2.0.0" } }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "dev": true, + "requires": { + "string-width": "1.0.2" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -8401,11 +7650,68 @@ "mkdirp": "0.5.1" } }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.4" + } + }, + "xmlbuilder": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", + "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "requires": { + "camelcase": "3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + } + } } } } diff --git a/package.json b/package.json index 0b5da538..87c35600 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,20 @@ "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player", "homepage": "http://plyr.io", "main": "src/js/plyr.js", - "dependencies": {}, "devDependencies": { - "eslint": "^4.9.0", - "eslint-config-prettier": "^2.6.0", + "babel-core": "^6.26.0", + "babel-eslint": "^8.0.1", + "babel-plugin-external-helpers": "^6.22.0", + "babel-preset-env": "^1.6.1", + "eslint": "^4.10.0", + "eslint-config-airbnb": "^16.1.0", + "eslint-config-prettier": "^2.7.0", + "eslint-plugin-import": "^2.8.0", + "eslint-plugin-jsx-a11y": "^6.0.2", + "eslint-plugin-react": "^7.4.0", "gulp": "^3.9.1", "gulp-autoprefixer": "^4.0.0", + "gulp-better-rollup": "^2.0.0", "gulp-clean-css": "^3.9.0", "gulp-concat": "^2.6.1", "gulp-less": "^3.3.2", @@ -19,15 +27,20 @@ "gulp-s3": "^0.11.0", "gulp-sass": "^3.1.0", "gulp-size": "^2.1.0", + "gulp-sourcemaps": "^2.6.1", "gulp-svgmin": "^1.2.4", "gulp-svgstore": "^6.1.0", - "gulp-uglify": "^3.0.0", "gulp-util": "^3.0.8", + "rollup-plugin-babel": "^3.0.2", + "rollup-plugin-commonjs": "^8.2.6", + "rollup-plugin-node-resolve": "^3.0.0", + "rollup-plugin-uglify": "^2.0.1", "run-sequence": "^2.2.0", "stylelint": "^8.2.0", "stylelint-config-prettier": "^1.0.2", "stylelint-config-standard": "^17.0.0", - "through2": "^2.0.3" + "through2": "^2.0.3", + "uglify-es": "^3.1.6" }, "keywords": [ "HTML5 Video", diff --git a/src/js/captions.js b/src/js/captions.js new file mode 100644 index 00000000..ed175530 --- /dev/null +++ b/src/js/captions.js @@ -0,0 +1,212 @@ +// ========================================================================== +// Plyr Captions +// ========================================================================== + +import support from './support'; +import utils from './utils'; +import controls from './controls'; + +const captions = { + // Setup captions + setup() { + // Requires UI support + if (!this.supported.ui) { + return; + } + + // Set default language if not set + if (!utils.is.empty(this.storage.language)) { + this.captions.language = this.storage.language; + } else if (utils.is.empty(this.captions.language)) { + this.captions.language = this.config.captions.language.toLowerCase(); + } + + // Set captions enabled state if not set + if (!utils.is.boolean(this.captions.enabled)) { + if (!utils.is.empty(this.storage.language)) { + this.captions.enabled = this.storage.captions; + } else { + this.captions.enabled = this.config.captions.active; + } + } + + // Only Vimeo and HTML5 video supported at this point + if (!['video', 'vimeo'].includes(this.type) || (this.type === 'video' && !support.textTracks)) { + this.captions.tracks = null; + + // Clear menu and hide + if (this.config.controls.includes('settings') && this.config.settings.includes('captions')) { + controls.setCaptionsMenu.call(this); + } + + return; + } + + // Inject the container + if (!utils.is.htmlElement(this.elements.captions)) { + this.elements.captions = utils.createElement( + 'div', + utils.getAttributesFromSelector(this.config.selectors.captions) + ); + utils.insertAfter(this.elements.captions, this.elements.wrapper); + } + + // Get tracks from HTML5 + if (this.type === 'video') { + this.captions.tracks = this.media.textTracks; + } + + // Set the class hook + utils.toggleClass( + this.elements.container, + this.config.classNames.captions.enabled, + !utils.is.empty(this.captions.tracks) + ); + + // If no caption file exists, hide container for caption text + if (utils.is.empty(this.captions.tracks)) { + return; + } + + // Enable UI + captions.show.call(this); + + // Get a track + const setCurrentTrack = () => { + // Reset by default + this.captions.currentTrack = null; + + // Filter doesn't seem to work for a TextTrackList :-( + Array.from(this.captions.tracks).forEach(track => { + if (track.language === this.captions.language.toLowerCase()) { + this.captions.currentTrack = track; + } + }); + }; + + // Get current track + setCurrentTrack(); + + // If we couldn't get the requested language, revert to default + if (!utils.is.track(this.captions.currentTrack)) { + const { language } = this.config.captions; + + // Reset to default + // We don't update user storage as the selected language could become available + this.captions.language = language; + + // Get fallback track + setCurrentTrack(); + + // If no match, disable captions + if (!utils.is.track(this.captions.currentTrack)) { + this.toggleCaptions(false); + } + + controls.updateSetting.call(this, 'captions'); + } + + // Setup HTML5 track rendering + if (this.type === 'video') { + // Turn off native caption rendering to avoid double captions + Array.from(this.captions.tracks).forEach(track => { + // Remove previous bindings (if we've changed source or language) + utils.off(track, 'cuechange', event => captions.setCue.call(this, event)); + + // Hide captions + track.mode = 'hidden'; + }); + + // Check if suported kind + const supported = + this.captions.currentTrack && ['captions', 'subtitles'].includes(this.captions.currentTrack.kind); + + if (utils.is.track(this.captions.currentTrack) && supported) { + utils.on(this.captions.currentTrack, 'cuechange', event => captions.setCue.call(this, event)); + + // If we change the active track while a cue is already displayed we need to update it + if (this.captions.currentTrack.activeCues && this.captions.currentTrack.activeCues.length > 0) { + controls.setCue.call(this, this.captions.currentTrack); + } + } + } else if (this.type === 'vimeo' && this.captions.active) { + this.embed.enableTextTrack(this.captions.language); + } + + // Set available languages in list + if (this.config.controls.includes('settings') && this.config.settings.includes('captions')) { + controls.setCaptionsMenu.call(this); + } + }, + + // Display active caption if it contains text + setCue(input) { + // Get the track from the event if needed + const track = utils.is.event(input) ? input.target : input; + const active = track.activeCues[0]; + + // Display a cue, if there is one + if (utils.is.cue(active)) { + captions.set.call(this, active.getCueAsHTML()); + } else { + captions.set.call(this); + } + + utils.dispatchEvent.call(this, this.media, 'cuechange'); + }, + + // Set the current caption + set(input) { + // Requires UI + if (!this.supported.ui) { + return; + } + + if (utils.is.htmlElement(this.elements.captions)) { + const content = utils.createElement('span'); + + // Empty the container + utils.emptyElement(this.elements.captions); + + // Default to empty + const caption = !utils.is.undefined(input) ? input : ''; + + // Set the span content + if (utils.is.string(caption)) { + content.textContent = caption.trim(); + } else { + content.appendChild(caption); + } + + // Set new caption text + this.elements.captions.appendChild(content); + } else { + this.warn('No captions element to render to'); + } + }, + + // Display captions container and button (for initialization) + show() { + // If there's no caption toggle, bail + if (!this.elements.buttons.captions) { + return; + } + + // Try to load the value from storage + let active = this.storage.captions; + + // Otherwise fall back to the default config + if (!utils.is.boolean(active)) { + ({ active } = this.captions); + } else { + this.captions.active = active; + } + + if (active) { + utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true); + utils.toggleState(this.elements.buttons.captions, true); + } + }, +}; + +export default captions; diff --git a/src/js/controls.js b/src/js/controls.js new file mode 100644 index 00000000..1e10f2f2 --- /dev/null +++ b/src/js/controls.js @@ -0,0 +1,1177 @@ +// ========================================================================== +// Plyr controls +// ========================================================================== + +import support from './support'; +import utils from './utils'; + +const controls = { + // Webkit polyfill for lower fill range + updateRangeFill(target) { + // WebKit only + if (!this.browser.isWebkit) { + return; + } + + // Get range from event if event passed + const range = utils.is.event(target) ? target.target : target; + + // Needs to be a valid <input type='range'> + if (!utils.is.htmlElement(range) || range.getAttribute('type') !== 'range') { + return; + } + + // Inject the stylesheet if needed + if (!utils.is.htmlElement(this.elements.styleSheet)) { + this.elements.styleSheet = utils.createElement('style'); + this.elements.container.appendChild(this.elements.styleSheet); + } + + const styleSheet = this.elements.styleSheet.sheet; + const percentage = range.value / range.max * 100; + const selector = `#${range.id}::-webkit-slider-runnable-track`; + const styles = `{ background-image: linear-gradient(to right, currentColor ${percentage}%, transparent ${percentage}%) }`; + + // Find old rule if it exists + const index = Array.from(styleSheet.rules).findIndex(rule => rule.selectorText === selector); + + // Remove old rule + if (index !== -1) { + styleSheet.deleteRule(index); + } + + // Insert new one + styleSheet.insertRule([selector, styles].join(' ')); + }, + + // Get icon URL + getIconUrl() { + return { + url: this.config.iconUrl, + absolute: this.config.iconUrl.indexOf('http') === 0 || this.browser.isIE, + }; + }, + + // Create <svg> icon + createIcon(type, attributes) { + const namespace = 'http://www.w3.org/2000/svg'; + const iconUrl = controls.getIconUrl.call(this); + const iconPath = `${!iconUrl.absolute ? iconUrl.url : ''}#${this.config.iconPrefix}`; + + // Create <svg> + const icon = document.createElementNS(namespace, 'svg'); + utils.setAttributes( + icon, + utils.extend(attributes, { + role: 'presentation', + }) + ); + + // Create the <use> to reference sprite + const use = document.createElementNS(namespace, 'use'); + use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `${iconPath}-${type}`); + + // Add <use> to <svg> + icon.appendChild(use); + + return icon; + }, + + // Create hidden text label + createLabel(type) { + let text = this.config.i18n[type]; + + switch (type) { + case 'pip': + text = 'PIP'; + break; + + case 'airplay': + text = 'AirPlay'; + break; + + default: + break; + } + + return utils.createElement( + 'span', + { + class: this.config.classNames.hidden, + }, + text + ); + }, + + // Create a badge + createBadge(text) { + const badge = utils.createElement('span', { + class: this.config.classNames.menu.value, + }); + + badge.appendChild( + utils.createElement( + 'span', + { + class: this.config.classNames.menu.badge, + }, + text + ) + ); + + return badge; + }, + + // Create a <button> + createButton(buttonType, attr) { + const button = utils.createElement('button'); + const attributes = Object.assign({}, attr); + let type = buttonType; + let iconDefault; + let iconToggled; + let labelKey; + + if (!('type' in attributes)) { + attributes.type = 'button'; + } + + if ('class' in attributes) { + if (attributes.class.indexOf(this.config.classNames.control) === -1) { + attributes.class += ` ${this.config.classNames.control}`; + } + } else { + attributes.class = this.config.classNames.control; + } + + // Large play button + switch (type) { + case 'mute': + labelKey = 'toggleMute'; + iconDefault = 'volume'; + iconToggled = 'muted'; + break; + + case 'captions': + labelKey = 'toggleCaptions'; + iconDefault = 'captions-off'; + iconToggled = 'captions-on'; + break; + + case 'fullscreen': + labelKey = 'toggleFullscreen'; + iconDefault = 'enter-fullscreen'; + iconToggled = 'exit-fullscreen'; + break; + + case 'play-large': + attributes.class = 'plyr__play-large'; + type = 'play'; + labelKey = 'play'; + iconDefault = 'play'; + break; + + default: + labelKey = type; + iconDefault = type; + } + + // Merge attributes + utils.extend(attributes, utils.getAttributesFromSelector(this.config.selectors.buttons[type], attributes)); + + // Add toggle icon if needed + if (utils.is.string(iconToggled)) { + button.appendChild( + controls.createIcon.call(this, iconToggled, { + class: `icon--${iconToggled}`, + }) + ); + } + + button.appendChild(controls.createIcon.call(this, iconDefault)); + button.appendChild(controls.createLabel.call(this, labelKey)); + + utils.setAttributes(button, attributes); + + this.elements.buttons[type] = button; + + return button; + }, + + // Create an <input type='range'> + createRange(type, attributes) { + // Seek label + const label = utils.createElement( + 'label', + { + for: attributes.id, + class: this.config.classNames.hidden, + }, + this.config.i18n[type] + ); + + // Seek input + const input = utils.createElement( + 'input', + utils.extend( + utils.getAttributesFromSelector(this.config.selectors.inputs[type]), + { + type: 'range', + min: 0, + max: 100, + step: 0.01, + value: 0, + autocomplete: 'off', + }, + attributes + ) + ); + + this.elements.inputs[type] = input; + + return { + label, + input, + }; + }, + + // Create a <progress> + createProgress(type, attributes) { + const progress = utils.createElement( + 'progress', + utils.extend( + utils.getAttributesFromSelector(this.config.selectors.display[type]), + { + min: 0, + max: 100, + value: 0, + }, + attributes + ) + ); + + // Create the label inside + if (type !== 'volume') { + progress.appendChild(utils.createElement('span', null, '0')); + + let suffix = ''; + switch (type) { + case 'played': + suffix = this.config.i18n.played; + break; + + case 'buffer': + suffix = this.config.i18n.buffered; + break; + + default: + break; + } + + progress.textContent = `% ${suffix.toLowerCase()}`; + } + + this.elements.display[type] = progress; + + return progress; + }, + + // Create time display + createTime(type) { + const container = utils.createElement('span', { + class: 'plyr__time', + }); + + container.appendChild( + utils.createElement( + 'span', + { + class: this.config.classNames.hidden, + }, + this.config.i18n[type] + ) + ); + + container.appendChild( + utils.createElement('span', utils.getAttributesFromSelector(this.config.selectors.display[type]), '00:00') + ); + + this.elements.display[type] = container; + + return container; + }, + + // Hide/show a tab + toggleTab(setting, toggle) { + const tab = this.elements.settings.tabs[setting]; + const pane = this.elements.settings.panes[setting]; + + if (utils.is.htmlElement(tab)) { + if (toggle) { + tab.removeAttribute('hidden'); + } else { + tab.setAttribute('hidden', ''); + } + } + + if (utils.is.htmlElement(pane)) { + if (toggle) { + pane.removeAttribute('hidden'); + } else { + pane.setAttribute('hidden', ''); + } + } + }, + + // Set the YouTube quality menu + // TODO: Support for HTML5 + setQualityMenu(options) { + const list = this.elements.settings.panes.quality.querySelector('ul'); + + // Set options if passed and filter based on config + if (utils.is.array(options)) { + this.options.quality = options.filter(quality => this.config.quality.options.includes(quality)); + } else { + this.options.quality = this.config.quality.options; + } + + // Toggle the pane and tab + const toggle = !utils.is.empty(this.options.quality) && this.type === 'youtube'; + controls.toggleTab.call(this, 'quality', toggle); + + // If we're hiding, nothing more to do + if (!toggle) { + return; + } + + // Empty the menu + utils.emptyElement(list); + + // Get the badge HTML for HD, 4K etc + const getBadge = quality => { + let label = ''; + + switch (quality) { + case 'hd2160': + label = '4K'; + break; + + case 'hd1440': + label = 'WQHD'; + break; + + case 'hd1080': + label = 'HD'; + break; + + case 'hd720': + label = 'HD'; + break; + + default: + break; + } + + if (!label.length) { + return null; + } + + return controls.createBadge.call(this, label); + }; + + this.options.quality.forEach(quality => { + const item = utils.createElement('li'); + + const label = utils.createElement('label', { + class: this.config.classNames.control, + }); + + const radio = utils.createElement( + 'input', + utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.quality), { + type: 'radio', + name: 'plyr-quality', + value: quality, + }) + ); + + label.appendChild(radio); + label.appendChild(document.createTextNode(controls.getLabel.call(this, 'quality', quality))); + + const badge = getBadge(quality); + if (utils.is.htmlElement(badge)) { + label.appendChild(badge); + } + + item.appendChild(label); + list.appendChild(item); + }); + + controls.updateSetting.call(this, 'quality', list); + }, + + // Translate a value into a nice label + // TODO: Localisation + getLabel(setting, value) { + switch (setting) { + case 'speed': + return value === 1 ? 'Normal' : `${value}×`; + + case 'quality': + switch (value) { + case 'hd2160': + return '2160P'; + case 'hd1440': + return '1440P'; + case 'hd1080': + return '1080P'; + case 'hd720': + return '720P'; + case 'large': + return '480P'; + case 'medium': + return '360P'; + case 'small': + return '240P'; + case 'tiny': + return 'Tiny'; + case 'default': + return 'Auto'; + default: + return value; + } + + case 'captions': + return controls.getLanguage.call(this); + + default: + return null; + } + }, + + // Update the selected setting + updateSetting(setting, container) { + const pane = this.elements.settings.panes[setting]; + let value = null; + let list = container; + + switch (setting) { + case 'captions': + value = this.captions.language; + + if (!this.captions.enabled) { + value = ''; + } + + break; + + default: + value = this[setting]; + + // Get default + if (utils.is.empty(value)) { + value = this.config[setting].default; + } + + // Unsupported value + if (!this.options[setting].includes(value)) { + this.warn(`Unsupported value of '${value}' for ${setting}`); + return; + } + + // Disabled value + if (!this.config[setting].options.includes(value)) { + this.warn(`Disabled value of '${value}' for ${setting}`); + return; + } + + break; + } + + // Get the list if we need to + if (!utils.is.htmlElement(list)) { + list = pane && pane.querySelector('ul'); + } + + // Find the radio option + const target = list && list.querySelector(`input[value="${value}"]`); + + if (!utils.is.htmlElement(target)) { + return; + } + + // Check it + target.checked = true; + + // Find the label + const label = this.elements.settings.tabs[setting].querySelector(`.${this.config.classNames.menu.value}`); + label.innerHTML = controls.getLabel.call(this, setting, value); + }, + + // Set the looping options + setLoopMenu() { + const options = ['start', 'end', 'all', 'reset']; + const list = this.elements.settings.panes.loop.querySelector('ul'); + + // Show the pane and tab + this.elements.settings.tabs.loop.removeAttribute('hidden'); + this.elements.settings.panes.loop.removeAttribute('hidden'); + + // Toggle the pane and tab + const toggle = !utils.is.empty(this.loop.options); + controls.toggleTab.call(this, 'loop', toggle); + + // Empty the menu + utils.emptyElement(list); + + options.forEach(option => { + const item = utils.createElement('li'); + + const button = utils.createElement( + 'button', + utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.loop), { + type: 'button', + class: this.config.classNames.control, + 'data-plyr-loop-action': option, + }), + this.config.i18n[option] + ); + + if (['start', 'end'].includes(option)) { + const badge = controls.createBadge.call(this, '00:00'); + button.appendChild(badge); + } + + item.appendChild(button); + list.appendChild(item); + }); + }, + + // Get current selected caption language + getLanguage() { + if (!this.supported.ui) { + return null; + } + + if (!support.textTracks || utils.is.empty(this.captions.tracks)) { + return this.config.i18n.none; + } + + if (this.captions.enabled) { + return this.captions.currentTrack.label; + } + return this.config.i18n.disabled; + }, + + // Set a list of available captions languages + setCaptionsMenu() { + const list = this.elements.settings.panes.captions.querySelector('ul'); + + // Toggle the pane and tab + const toggle = !utils.is.empty(this.captions.tracks); + controls.toggleTab.call(this, 'captions', toggle); + + // Empty the menu + utils.emptyElement(list); + + // If there's no captions, bail + if (utils.is.empty(this.captions.tracks)) { + return; + } + + // Re-map the tracks into just the data we need + const tracks = Array.from(this.captions.tracks).map(track => ({ + language: track.language, + badge: true, + label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(), + })); + + // Add the "None" option to turn off captions + tracks.unshift({ + language: '', + label: this.config.i18n.none, + }); + + // Generate options + tracks.forEach(track => { + const item = utils.createElement('li'); + + const label = utils.createElement('label', { + class: this.config.classNames.control, + }); + + const radio = utils.createElement( + 'input', + utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.language), { + type: 'radio', + name: 'plyr-language', + value: track.language, + }) + ); + + if (track.language.toLowerCase() === this.captions.language.toLowerCase()) { + radio.checked = true; + } + + label.appendChild(radio); + label.appendChild(document.createTextNode(track.label || track.language)); + + if (track.badge) { + label.appendChild(controls.createBadge.call(this, track.language.toUpperCase())); + } + + item.appendChild(label); + list.appendChild(item); + }); + + controls.updateSetting.call(this, 'captions', list); + }, + + // Set a list of available captions languages + setSpeedMenu(options) { + // Set options if passed and filter based on config + if (utils.is.array(options)) { + this.options.speed = options.filter(speed => this.config.speed.options.includes(speed)); + } else { + this.options.speed = this.config.speed.options; + } + + // Toggle the pane and tab + const toggle = !utils.is.empty(this.options.speed); + controls.toggleTab.call(this, 'speed', toggle); + + // If we're hiding, nothing more to do + if (!toggle) { + return; + } + + // Get the list to populate + const list = this.elements.settings.panes.speed.querySelector('ul'); + + // Show the pane and tab + this.elements.settings.tabs.speed.removeAttribute('hidden'); + this.elements.settings.panes.speed.removeAttribute('hidden'); + + // Empty the menu + utils.emptyElement(list); + + // Create items + this.options.speed.forEach(speed => { + const item = utils.createElement('li'); + + const label = utils.createElement('label', { + class: this.config.classNames.control, + }); + + const radio = utils.createElement( + 'input', + utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.speed), { + type: 'radio', + name: 'plyr-speed', + value: speed, + }) + ); + + label.appendChild(radio); + label.insertAdjacentHTML('beforeend', controls.getLabel.call(this, 'speed', speed)); + item.appendChild(label); + list.appendChild(item); + }); + + controls.updateSetting.call(this, 'speed', list); + }, + + // Show/hide menu + toggleMenu(event) { + const { form } = this.elements.settings; + const button = this.elements.buttons.settings; + const show = utils.is.boolean(event) ? event : form && form.getAttribute('aria-hidden') === 'true'; + + if (utils.is.event(event)) { + const isMenuItem = form && form.contains(event.target); + const isButton = event.target === this.elements.buttons.settings; + + // If the click was inside the form or if the click + // wasn't the button or menu item and we're trying to + // show the menu (a doc click shouldn't show the menu) + if (isMenuItem || (!isMenuItem && !isButton && show)) { + return; + } + + // Prevent the toggle being caught by the doc listener + if (isButton) { + event.stopPropagation(); + } + } + + // Set form and button attributes + if (button) { + button.setAttribute('aria-expanded', show); + } + if (form) { + form.setAttribute('aria-hidden', !show); + + if (show) { + form.removeAttribute('tabindex'); + } else { + form.setAttribute('tabindex', -1); + } + } + }, + + // Get the natural size of a tab + getTabSize(tab) { + const clone = tab.cloneNode(true); + clone.style.position = 'absolute'; + clone.style.opacity = 0; + clone.setAttribute('aria-hidden', false); + + // Prevent input's being unchecked due to the name being identical + Array.from(clone.querySelectorAll('input[name]')).forEach(input => { + const name = input.getAttribute('name'); + input.setAttribute('name', `${name}-clone`); + }); + + // Append to parent so we get the "real" size + tab.parentNode.appendChild(clone); + + // Get the sizes before we remove + const width = clone.scrollWidth; + const height = clone.scrollHeight; + + // Remove from the DOM + utils.removeElement(clone); + + return { + width, + height, + }; + }, + + // Toggle Menu + showTab(event) { + const { menu } = this.elements.settings; + const tab = event.target; + const show = tab.getAttribute('aria-expanded') === 'false'; + const pane = document.getElementById(tab.getAttribute('aria-controls')); + + // Nothing to show, bail + if (!utils.is.htmlElement(pane)) { + return; + } + + // Are we targetting a tab? If not, bail + const isTab = pane.getAttribute('role') === 'tabpanel'; + if (!isTab) { + return; + } + + // Hide all other tabs + // Get other tabs + const current = menu.querySelector('[role="tabpanel"][aria-hidden="false"]'); + const container = current.parentNode; + + // Set other toggles to be expanded false + Array.from(menu.querySelectorAll(`[aria-controls="${current.getAttribute('id')}"]`)).forEach(toggle => { + toggle.setAttribute('aria-expanded', false); + }); + + // If we can do fancy animations, we'll animate the height/width + if (support.transitions && !support.reducedMotion) { + // Set the current width as a base + container.style.width = `${current.scrollWidth}px`; + container.style.height = `${current.scrollHeight}px`; + + // Get potential sizes + const size = controls.getTabSize.call(this, pane); + + // Restore auto height/width + const restore = e => { + // We're only bothered about height and width on the container + if (e.target !== container || !['width', 'height'].includes(e.propertyName)) { + return; + } + + // Revert back to auto + container.style.width = ''; + container.style.height = ''; + + // Only listen once + utils.off(container, utils.transitionEnd, restore); + }; + + // Listen for the transition finishing and restore auto height/width + utils.on(container, utils.transitionEnd, restore); + + // Set dimensions to target + container.style.width = `${size.width}px`; + container.style.height = `${size.height}px`; + } + + // Set attributes on current tab + current.setAttribute('aria-hidden', true); + current.setAttribute('tabindex', -1); + + // Set attributes on target + pane.setAttribute('aria-hidden', !show); + tab.setAttribute('aria-expanded', show); + pane.removeAttribute('tabindex'); + }, + + // Build the default HTML + // TODO: Set order based on order in the config.controls array? + create(data) { + // Do nothing if we want no controls + if (utils.is.empty(this.config.controls)) { + return null; + } + + // Create the container + const container = utils.createElement( + 'div', + utils.getAttributesFromSelector(this.config.selectors.controls.wrapper) + ); + + // Restart button + if (this.config.controls.includes('restart')) { + container.appendChild(controls.createButton.call(this, 'restart')); + } + + // Rewind button + if (this.config.controls.includes('rewind')) { + container.appendChild(controls.createButton.call(this, 'rewind')); + } + + // Play Pause button + if (this.config.controls.includes('play')) { + container.appendChild(controls.createButton.call(this, 'play')); + container.appendChild(controls.createButton.call(this, 'pause')); + } + + // Fast forward button + if (this.config.controls.includes('fast-forward')) { + container.appendChild(controls.createButton.call(this, 'fast-forward')); + } + + // Progress + if (this.config.controls.includes('progress')) { + const progress = utils.createElement( + 'span', + utils.getAttributesFromSelector(this.config.selectors.progress) + ); + + // Seek range slider + const seek = controls.createRange.call(this, 'seek', { + id: `plyr-seek-${data.id}`, + }); + progress.appendChild(seek.label); + progress.appendChild(seek.input); + + // Buffer progress + progress.appendChild(controls.createProgress.call(this, 'buffer')); + + // TODO: Add loop display indicator + + // Seek tooltip + if (this.config.tooltips.seek) { + const tooltip = utils.createElement( + 'span', + { + role: 'tooltip', + class: this.config.classNames.tooltip, + }, + '00:00' + ); + + progress.appendChild(tooltip); + this.elements.display.seekTooltip = tooltip; + } + + this.elements.progress = progress; + container.appendChild(this.elements.progress); + } + + // Media current time display + if (this.config.controls.includes('current-time')) { + container.appendChild(controls.createTime.call(this, 'currentTime')); + } + + // Media duration display + if (this.config.controls.includes('duration')) { + container.appendChild(controls.createTime.call(this, 'duration')); + } + + // Toggle mute button + if (this.config.controls.includes('mute')) { + container.appendChild(controls.createButton.call(this, 'mute')); + } + + // Volume range control + if (this.config.controls.includes('volume')) { + const volume = utils.createElement('span', { + class: 'plyr__volume', + }); + + // Set the attributes + const attributes = { + max: 1, + step: 0.05, + value: this.config.volume, + }; + + // Create the volume range slider + const range = controls.createRange.call( + this, + 'volume', + utils.extend(attributes, { + id: `plyr-volume-${data.id}`, + }) + ); + volume.appendChild(range.label); + volume.appendChild(range.input); + + container.appendChild(volume); + } + + // Toggle captions button + if (this.config.controls.includes('captions')) { + container.appendChild(controls.createButton.call(this, 'captions')); + } + + // Settings button / menu + if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) { + const menu = utils.createElement('div', { + class: 'plyr__menu', + }); + + menu.appendChild( + controls.createButton.call(this, 'settings', { + id: `plyr-settings-toggle-${data.id}`, + 'aria-haspopup': true, + 'aria-controls': `plyr-settings-${data.id}`, + 'aria-expanded': false, + }) + ); + + const form = utils.createElement('form', { + class: 'plyr__menu__container', + id: `plyr-settings-${data.id}`, + 'aria-hidden': true, + 'aria-labelled-by': `plyr-settings-toggle-${data.id}`, + role: 'tablist', + tabindex: -1, + }); + + const inner = utils.createElement('div'); + + const home = utils.createElement('div', { + id: `plyr-settings-${data.id}-home`, + 'aria-hidden': false, + 'aria-labelled-by': `plyr-settings-toggle-${data.id}`, + role: 'tabpanel', + }); + + // Create the tab list + const tabs = utils.createElement('ul', { + role: 'tablist', + }); + + // Build the tabs + this.config.settings.forEach(type => { + const tab = utils.createElement('li', { + role: 'tab', + hidden: '', + }); + + const button = utils.createElement( + 'button', + utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.settings), { + type: 'button', + class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`, + id: `plyr-settings-${data.id}-${type}-tab`, + 'aria-haspopup': true, + 'aria-controls': `plyr-settings-${data.id}-${type}`, + 'aria-expanded': false, + }), + this.config.i18n[type] + ); + + const value = utils.createElement('span', { + class: this.config.classNames.menu.value, + }); + + // Speed contains HTML entities + value.innerHTML = data[type]; + + button.appendChild(value); + tab.appendChild(button); + tabs.appendChild(tab); + + this.elements.settings.tabs[type] = tab; + }); + + home.appendChild(tabs); + inner.appendChild(home); + + // Build the panes + this.config.settings.forEach(type => { + const pane = utils.createElement('div', { + id: `plyr-settings-${data.id}-${type}`, + 'aria-hidden': true, + 'aria-labelled-by': `plyr-settings-${data.id}-${type}-tab`, + role: 'tabpanel', + tabindex: -1, + hidden: '', + }); + + const back = utils.createElement( + 'button', + { + type: 'button', + class: `${this.config.classNames.control} ${this.config.classNames.control}--back`, + 'aria-haspopup': true, + 'aria-controls': `plyr-settings-${data.id}-home`, + 'aria-expanded': false, + }, + this.config.i18n[type] + ); + + pane.appendChild(back); + + const options = utils.createElement('ul'); + + pane.appendChild(options); + inner.appendChild(pane); + + this.elements.settings.panes[type] = pane; + }); + + form.appendChild(inner); + menu.appendChild(form); + container.appendChild(menu); + + this.elements.settings.form = form; + this.elements.settings.menu = menu; + } + + // Picture in picture button + if (this.config.controls.includes('pip') && support.pip) { + container.appendChild(controls.createButton.call(this, 'pip')); + } + + // Airplay button + if (this.config.controls.includes('airplay') && support.airplay) { + container.appendChild(controls.createButton.call(this, 'airplay')); + } + + // Toggle fullscreen button + if (this.config.controls.includes('fullscreen')) { + container.appendChild(controls.createButton.call(this, 'fullscreen')); + } + + // Larger overlaid play button + if (this.config.controls.includes('play-large')) { + this.elements.buttons.playLarge = controls.createButton.call(this, 'play-large'); + this.elements.container.appendChild(this.elements.buttons.playLarge); + } + + this.elements.controls = container; + + if (this.config.controls.includes('settings') && this.config.settings.includes('speed')) { + controls.setSpeedMenu.call(this); + } + + return container; + }, + + // Insert controls + inject() { + // Sprite + if (this.config.loadSprite) { + const iconUrl = controls.getIconUrl.call(this); + + // Only load external sprite using AJAX + if (iconUrl.absolute) { + this.log(`AJAX loading absolute SVG sprite ${this.browser.isIE ? '(due to IE)' : ''}`); + utils.loadSprite(iconUrl.url, 'sprite-plyr'); + } else { + this.log('Sprite will be used as external resource directly'); + } + } + + // Create a unique ID + this.id = Math.floor(Math.random() * 10000); + + // Null by default + let container = null; + + // HTML passed as the option + if (utils.is.string(this.config.controls)) { + container = this.config.controls; + } else if (utils.is.function(this.config.controls)) { + // A custom function to build controls + // The function can return a HTMLElement or String + container = this.config.controls({ + id: this.id, + seektime: this.config.seekTime, + }); + } else { + // Create controls + container = controls.create.call(this, { + id: this.id, + seektime: this.config.seekTime, + speed: '-', + // TODO: Get current quality + quality: '-', + captions: controls.getLanguage.call(this), + // TODO: Get loop + loop: 'None', + }); + } + + // Controls container + let target; + + // Inject to custom location + if (utils.is.string(this.config.selectors.controls.container)) { + target = document.querySelector(this.config.selectors.controls.container); + } + + // Inject into the container by default + if (!utils.is.htmlElement(target)) { + target = this.elements.container; + } + + // Inject controls HTML + if (utils.is.htmlElement(container)) { + target.appendChild(container); + } else { + target.insertAdjacentHTML('beforeend', container); + } + + // Find the elements if need be + if (utils.is.htmlElement(this.elements.controls)) { + utils.findElements.call(this); + } + + // Setup tooltips + if (this.config.tooltips.controls) { + const labels = utils.getElements.call( + this, + [ + this.config.selectors.controls.wrapper, + ' ', + this.config.selectors.labels, + ' .', + this.config.classNames.hidden, + ].join('') + ); + + Array.from(labels).forEach(label => { + utils.toggleClass(label, this.config.classNames.hidden, false); + utils.toggleClass(label, this.config.classNames.tooltip, true); + }); + } + }, +}; + +export default controls; diff --git a/src/js/defaults.js b/src/js/defaults.js new file mode 100644 index 00000000..2d1319b7 --- /dev/null +++ b/src/js/defaults.js @@ -0,0 +1,301 @@ +// Default config +const defaults = { + // Disable + enabled: true, + + // Custom media title + title: '', + + // Logging to console + debug: false, + + // Auto play (if supported) + autoplay: false, + + // Default time to skip when rewind/fast forward + seekTime: 10, + + // Default volume + volume: 1, + muted: false, + + // Display the media duration + displayDuration: true, + + // Click video to play + clickToPlay: true, + + // Auto hide the controls + hideControls: true, + + // Revert to poster on finish (HTML5 - will cause reload) + showPosterOnEnd: false, + + // Disable the standard context menu + disableContextMenu: true, + + // Sprite (for icons) + loadSprite: true, + iconPrefix: 'plyr', + iconUrl: 'https://cdn.plyr.io/2.0.10/plyr.svg', + + // Blank video (used to prevent errors on source change) + blankVideo: 'https://cdn.plyr.io/static/blank.mp4', + + // Pass a custom duration + duration: null, + + // Quality default + quality: { + default: 'default', + options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'], + }, + + // Set loops + loop: { + active: false, + start: null, + end: null, + }, + + // Speed default and options to display + speed: { + default: 1, + options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], + }, + + // Keyboard shortcut settings + keyboard: { + focused: true, + global: false, + }, + + // Display tooltips + tooltips: { + controls: false, + seek: true, + }, + + // Captions settings + captions: { + active: false, + language: window.navigator.language.split('-')[0], + }, + + // Fullscreen settings + fullscreen: { + enabled: true, // Allow fullscreen? + fallback: true, // Fallback for vintage browsers + }, + + // Local storage + storage: { + enabled: true, + key: 'plyr', + }, + + // Default controls + controls: [ + 'play-large', + 'play', + 'progress', + 'current-time', + 'mute', + 'volume', + 'captions', + 'settings', + 'pip', + 'airplay', + 'fullscreen', + ], + settings: ['captions', 'quality', 'speed', 'loop'], + + // Localisation + i18n: { + restart: 'Restart', + rewind: 'Rewind {seektime} secs', + play: 'Play', + pause: 'Pause', + forward: 'Forward {seektime} secs', + seek: 'Seek', + played: 'Played', + buffered: 'Buffered', + currentTime: 'Current time', + duration: 'Duration', + volume: 'Volume', + toggleMute: 'Toggle Mute', + toggleCaptions: 'Toggle Captions', + toggleFullscreen: 'Toggle Fullscreen', + frameTitle: 'Player for {title}', + captions: 'Captions', + settings: 'Settings', + speed: 'Speed', + quality: 'Quality', + loop: 'Loop', + start: 'Start', + end: 'End', + all: 'All', + reset: 'Reset', + none: 'None', + disabled: 'Disabled', + }, + + // URLs + urls: { + vimeo: { + api: 'https://player.vimeo.com/api/player.js', + }, + youtube: { + api: 'https://www.youtube.com/iframe_api', + }, + }, + + // Custom control listeners + listeners: { + seek: null, + play: null, + pause: null, + restart: null, + rewind: null, + forward: null, + mute: null, + volume: null, + captions: null, + fullscreen: null, + pip: null, + airplay: null, + speed: null, + quality: null, + loop: null, + language: null, + }, + + // Events to watch and bubble + events: [ + // Events to watch on HTML5 media elements and bubble + // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events + 'ended', + 'progress', + 'stalled', + 'playing', + 'waiting', + 'canplay', + 'canplaythrough', + 'loadstart', + 'loadeddata', + 'loadedmetadata', + 'timeupdate', + 'volumechange', + 'play', + 'pause', + 'error', + 'seeking', + 'seeked', + 'emptied', + 'ratechange', + 'cuechange', + + // Custom events + 'enterfullscreen', + 'exitfullscreen', + 'captionsenabled', + 'captionsdisabled', + 'captionchange', + 'controlshidden', + 'controlsshown', + 'ready', + + // YouTube + 'statechange', + 'qualitychange', + 'qualityrequested', + ], + + // Selectors + // Change these to match your template if using custom HTML + selectors: { + editable: 'input, textarea, select, [contenteditable]', + container: '.plyr', + controls: { + container: null, + wrapper: '.plyr__controls', + }, + labels: '[data-plyr]', + buttons: { + play: '[data-plyr="play"]', + pause: '[data-plyr="pause"]', + restart: '[data-plyr="restart"]', + rewind: '[data-plyr="rewind"]', + forward: '[data-plyr="fast-forward"]', + mute: '[data-plyr="mute"]', + captions: '[data-plyr="captions"]', + fullscreen: '[data-plyr="fullscreen"]', + pip: '[data-plyr="pip"]', + airplay: '[data-plyr="airplay"]', + settings: '[data-plyr="settings"]', + loop: '[data-plyr="loop"]', + }, + inputs: { + seek: '[data-plyr="seek"]', + volume: '[data-plyr="volume"]', + speed: '[data-plyr="speed"]', + language: '[data-plyr="language"]', + quality: '[data-plyr="quality"]', + }, + display: { + currentTime: '.plyr__time--current', + duration: '.plyr__time--duration', + buffer: '.plyr__progress--buffer', + played: '.plyr__progress--played', + loop: '.plyr__progress--loop', + volume: '.plyr__volume--display', + }, + progress: '.plyr__progress', + captions: '.plyr__captions', + menu: { + quality: '.js-plyr__menu__list--quality', + }, + }, + + // Class hooks added to the player in different states + classNames: { + video: 'plyr__video-wrapper', + embed: 'plyr__video-embed', + control: 'plyr__control', + type: 'plyr--{0}', + stopped: 'plyr--stopped', + playing: 'plyr--playing', + muted: 'plyr--muted', + loading: 'plyr--loading', + hover: 'plyr--hover', + tooltip: 'plyr__tooltip', + hidden: 'plyr__sr-only', + hideControls: 'plyr--hide-controls', + isIos: 'plyr--is-ios', + isTouch: 'plyr--is-touch', + uiSupported: 'plyr--full-ui', + menu: { + value: 'plyr__menu__value', + badge: 'plyr__badge', + }, + captions: { + enabled: 'plyr--captions-enabled', + active: 'plyr--captions-active', + }, + fullscreen: { + enabled: 'plyr--fullscreen-enabled', + fallback: 'plyr--fullscreen-fallback', + }, + pip: { + supported: 'plyr--pip-supported', + active: 'plyr--pip-active', + }, + airplay: { + supported: 'plyr--airplay-supported', + active: 'plyr--airplay-active', + }, + tabFocus: 'tab-focus', + }, +}; + +export default defaults; diff --git a/src/js/fullscreen.js b/src/js/fullscreen.js new file mode 100644 index 00000000..3e46150d --- /dev/null +++ b/src/js/fullscreen.js @@ -0,0 +1,129 @@ +// ========================================================================== +// Plyr fullscreen API +// ========================================================================== + +import utils from './utils'; + +// Determine the prefix +const prefix = (() => { + let value = false; + + if (utils.is.function(document.cancelFullScreen)) { + value = ''; + } else { + // Check for fullscreen support by vendor prefix + ['webkit', 'o', 'moz', 'ms', 'khtml'].some(pre => { + if (utils.is.function(document[`${pre}CancelFullScreen`])) { + value = pre; + return true; + } else if (utils.is.function(document.msExitFullscreen) && document.msFullscreenEnabled) { + // Special case for MS (when isn't it?) + value = 'ms'; + return true; + } + + return false; + }); + } + + return value; +})(); + +// Fullscreen API +const fullscreen = { + // Get the prefix + prefix, + + // Check if we can use it + enabled: + document.fullscreenEnabled || + document.webkitFullscreenEnabled || + document.mozFullScreenEnabled || + document.msFullscreenEnabled, + + // Yet again Microsoft awesomeness, + // Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes + eventType: prefix === 'ms' ? 'MSFullscreenChange' : `${prefix}fullscreenchange`, + + // Is an element fullscreen + isFullScreen(element) { + if (!fullscreen.enabled) { + return false; + } + + const target = utils.is.undefined(element) ? document.body : element; + + switch (prefix) { + case '': + return document.fullscreenElement === target; + + case 'moz': + return document.mozFullScreenElement === target; + + default: + return document[`${prefix}FullscreenElement`] === target; + } + }, + + // Make an element fullscreen + requestFullScreen(element) { + if (!fullscreen.enabled) { + return false; + } + + const target = utils.is.undefined(element) ? document.body : element; + + return !prefix.length + ? target.requestFullScreen() + : target[prefix + (prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')](); + }, + + // Bail from fullscreen + cancelFullScreen() { + if (!fullscreen.enabled) { + return false; + } + + return !prefix.length + ? document.cancelFullScreen() + : document[prefix + (prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')](); + }, + + // Get the current element + element() { + if (!fullscreen.enabled) { + return null; + } + + return !prefix.length ? document.fullscreenElement : document[`${prefix}FullscreenElement`]; + }, + + // Setup fullscreen + setup() { + if (!this.supported.ui || this.type === 'audio' || !this.config.fullscreen.enabled) { + return; + } + + // Check for native support + const nativeSupport = fullscreen.enabled; + + if (nativeSupport || (this.config.fullscreen.fallback && !utils.inFrame())) { + this.log(`${nativeSupport ? 'Native' : 'Fallback'} fullscreen enabled`); + + // Add styling hook to show button + utils.toggleClass(this.elements.container, this.config.classNames.fullscreen.enabled, true); + } else { + this.log('Fullscreen not supported and fallback disabled'); + } + + // Toggle state + if (this.elements.buttons && this.elements.buttons.fullscreen) { + utils.toggleState(this.elements.buttons.fullscreen, false); + } + + // Trap focus in container + utils.trapFocus.call(this); + }, +}; + +export default fullscreen; diff --git a/src/js/listeners.js b/src/js/listeners.js new file mode 100644 index 00000000..4349e35e --- /dev/null +++ b/src/js/listeners.js @@ -0,0 +1,569 @@ +// ========================================================================== +// Plyr Event Listeners +// ========================================================================== + +import support from './support'; +import utils from './utils'; +import controls from './controls'; +import fullscreen from './fullscreen'; +import storage from './storage'; +import ui from './ui'; + +const listeners = { + // Listen for media events + media() { + // Time change on media + utils.on(this.media, 'timeupdate seeking', event => ui.timeUpdate.call(this, event)); + + // Display duration + utils.on(this.media, 'durationchange loadedmetadata', event => ui.displayDuration.call(this, event)); + + // Handle the media finishing + utils.on(this.media, 'ended', () => { + // Show poster on end + if (this.type === 'video' && this.config.showPosterOnEnd) { + // Restart + this.restart(); + + // Re-load media + this.media.load(); + } + }); + + // Check for buffer progress + utils.on(this.media, 'progress playing', event => ui.updateProgress.call(this, event)); + + // Handle native mute + utils.on(this.media, 'volumechange', event => ui.updateVolume.call(this, event)); + + // Handle native play/pause + utils.on(this.media, 'play pause ended', event => ui.checkPlaying.call(this, event)); + + // Loading + utils.on(this.media, 'waiting canplay seeked', event => ui.checkLoading.call(this, event)); + + // Click video + if (this.supported.ui && this.config.clickToPlay && this.type !== 'audio') { + // Re-fetch the wrapper + const wrapper = utils.getElement.call(this, `.${this.config.classNames.video}`); + + // Bail if there's no wrapper (this should never happen) + if (!wrapper) { + return; + } + + // Set cursor + wrapper.style.cursor = 'pointer'; + + // On click play, pause ore restart + utils.on(wrapper, 'click', () => { + // Touch devices will just show controls (if we're hiding controls) + if (this.config.hideControls && support.touch && !this.media.paused) { + return; + } + + if (this.media.paused) { + this.play(); + } else if (this.media.ended) { + this.restart(); + this.play(); + } else { + this.pause(); + } + }); + } + + // Disable right click + if (this.config.disableContextMenu) { + utils.on( + this.media, + 'contextmenu', + event => { + event.preventDefault(); + }, + false + ); + } + + // Speed change + utils.on(this.media, 'ratechange', () => { + // Update UI + controls.updateSetting.call(this, 'speed'); + + // Save speed to localStorage + storage.set.call(this, { + speed: this.speed, + }); + }); + + // Quality change + utils.on(this.media, 'qualitychange', () => { + // Update UI + controls.updateSetting.call(this, 'quality'); + + // Save speed to localStorage + storage.set.call(this, { + quality: this.quality, + }); + }); + + // Caption language change + utils.on(this.media, 'captionchange', () => { + // Save speed to localStorage + storage.set.call(this, { + language: this.captions.language, + }); + }); + + // Captions toggle + utils.on(this.media, 'captionsenabled captionsdisabled', () => { + // Update UI + controls.updateSetting.call(this, 'captions'); + + // Save speed to localStorage + storage.set.call(this, { + captions: this.captions.enabled, + }); + }); + + // Proxy events to container + // Bubble up key events for Edge + utils.on(this.media, this.config.events.concat(['keyup', 'keydown']).join(' '), event => { + utils.dispatchEvent.call(this, this.elements.container, event.type, true); + }); + }, + + // Listen for control events + controls() { + // IE doesn't support input event, so we fallback to change + const inputEvent = this.browser.isIE ? 'change' : 'input'; + let last = null; + + // Click play/pause helper + const togglePlay = () => { + const play = this.togglePlay(); + + // Determine which buttons + const target = this.elements.buttons[play ? 'pause' : 'play']; + + // Transfer focus + if (utils.is.htmlElement(target)) { + target.focus(); + } + }; + + // Get the key code for an event + function getKeyCode(event) { + return event.keyCode ? event.keyCode : event.which; + } + + function handleKey(event) { + const code = getKeyCode(event); + const pressed = event.type === 'keydown'; + const held = pressed && code === last; + + // If the event is bubbled from the media element + // Firefox doesn't get the keycode for whatever reason + if (!utils.is.number(code)) { + return; + } + + // Seek by the number keys + function seekByKey() { + // Divide the max duration into 10th's and times by the number value + this.currentTime = this.duration / 10 * (code - 48); + } + + // Handle the key on keydown + // Reset on keyup + if (pressed) { + // Which keycodes should we prevent default + const preventDefault = [ + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 56, + 57, + 32, + 75, + 38, + 40, + 77, + 39, + 37, + 70, + 67, + 73, + 76, + 79, + ]; + const checkFocus = [38, 40]; + + if (checkFocus.includes(code)) { + const focused = utils.getFocusElement(); + + if (utils.is.htmlElement(focused) && utils.getFocusElement().type === 'radio') { + return; + } + } + + // If the code is found prevent default (e.g. prevent scrolling for arrows) + if (preventDefault.includes(code)) { + event.preventDefault(); + event.stopPropagation(); + } + + switch (code) { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + // 0-9 + if (!held) { + seekByKey(); + } + break; + + case 32: + case 75: + // Space and K key + if (!held) { + togglePlay(); + } + break; + + case 38: + // Arrow up + this.increaseVolume(0.1); + break; + + case 40: + // Arrow down + this.decreaseVolume(0.1); + break; + + case 77: + // M key + if (!held) { + this.toggleMute(); + } + break; + + case 39: + // Arrow forward + this.forward(); + break; + + case 37: + // Arrow back + this.rewind(); + break; + + case 70: + // F key + this.toggleFullscreen(); + break; + + case 67: + // C key + if (!held) { + this.toggleCaptions(); + } + break; + + case 73: + this.setLoop('start'); + break; + + case 76: + this.setLoop(); + break; + + case 79: + this.setLoop('end'); + break; + + default: + break; + } + + // Escape is handle natively when in full screen + // So we only need to worry about non native + if (!fullscreen.enabled && this.fullscreen.active && code === 27) { + this.toggleFullscreen(); + } + + // Store last code for next cycle + last = code; + } else { + last = null; + } + } + + // Keyboard shortcuts + if (this.config.keyboard.focused) { + // Handle global presses + if (this.config.keyboard.global) { + utils.on( + window, + 'keydown keyup', + event => { + const code = getKeyCode(event); + const focused = utils.getFocusElement(); + const allowed = [48, 49, 50, 51, 52, 53, 54, 56, 57, 75, 77, 70, 67, 73, 76, 79]; + + // Only handle global key press if key is in the allowed keys + // and if the focused element is not editable (e.g. text input) + // and any that accept key input http://webaim.org/techniques/keyboard/ + if ( + allowed.includes(code) && + (!utils.is.htmlElement(focused) || !utils.matches(focused, this.config.selectors.editable)) + ) { + handleKey(event); + } + }, + false + ); + } + + // Handle presses on focused + utils.on(this.elements.container, 'keydown keyup', handleKey, false); + } + + // Detect tab focus + // Remove class on blur/focusout + utils.on(this.elements.container, 'focusout', event => { + utils.toggleClass(event.target, this.config.classNames.tabFocus, false); + }); + + // Add classname to tabbed elements + utils.on(this.elements.container, 'keydown', event => { + if (event.keyCode !== 9) { + return; + } + + // Delay the adding of classname until the focus has changed + // This event fires before the focusin event + window.setTimeout(() => { + utils.toggleClass(utils.getFocusElement(), this.config.classNames.tabFocus, true); + }, 0); + }); + + // Trigger custom and default handlers + const handlerProxy = (event, customHandler, defaultHandler) => { + if (utils.is.function(customHandler)) { + customHandler.call(this, event); + } + if (utils.is.function(defaultHandler)) { + defaultHandler.call(this, event); + } + }; + + // Play + utils.proxy(this.elements.buttons.play, 'click', this.config.listeners.play, togglePlay); + utils.proxy(this.elements.buttons.playLarge, 'click', this.config.listeners.play, togglePlay); + + // Pause + utils.proxy(this.elements.buttons.pause, 'click', this.config.listeners.pause, togglePlay); + + // Pause + utils.proxy(this.elements.buttons.restart, 'click', this.config.listeners.restart, () => { + this.restart(); + }); + + // Rewind + utils.proxy(this.elements.buttons.rewind, 'click', this.config.listeners.rewind, () => { + this.rewind(); + }); + + // Rewind + utils.proxy(this.elements.buttons.forward, 'click', this.config.listeners.forward, () => { + this.forward(); + }); + + // Mute + utils.proxy(this.elements.buttons.mute, 'click', this.config.listeners.mute, () => { + this.toggleMute(); + }); + + // Captions + utils.proxy(this.elements.buttons.captions, 'click', this.config.listeners.captions, () => { + this.toggleCaptions(); + }); + + // Fullscreen + utils.proxy(this.elements.buttons.fullscreen, 'click', this.config.listeners.fullscreen, () => { + this.toggleFullscreen(); + }); + + // Picture-in-Picture + utils.proxy(this.elements.buttons.pip, 'click', this.config.listeners.pip, () => { + this.togglePictureInPicture(); + }); + + // Airplay + utils.proxy(this.elements.buttons.airplay, 'click', this.config.listeners.airplay, () => { + this.airPlay(); + }); + + // Settings menu + utils.on(this.elements.buttons.settings, 'click', event => { + controls.toggleMenu.call(this, event); + }); + + // Click anywhere closes menu + utils.on(document.documentElement, 'click', event => { + controls.toggleMenu.call(this, event); + }); + + // Settings menu + utils.on(this.elements.settings.form, 'click', event => { + // Show tab in menu + controls.showTab.call(this, event); + + // Settings menu items - use event delegation as items are added/removed + // Settings - Language + if (utils.matches(event.target, this.config.selectors.inputs.language)) { + handlerProxy.call(this, event, this.config.listeners.language, () => { + this.toggleCaptions(true); + this.language = event.target.value.toLowerCase(); + }); + } else if (utils.matches(event.target, this.config.selectors.inputs.quality)) { + // Settings - Quality + handlerProxy.call(this, event, this.config.listeners.quality, () => { + this.quality = event.target.value; + }); + } else if (utils.matches(event.target, this.config.selectors.inputs.speed)) { + // Settings - Speed + handlerProxy.call(this, event, this.config.listeners.speed, () => { + this.speed = parseFloat(event.target.value); + }); + } else if (utils.matches(event.target, this.config.selectors.buttons.loop)) { + // Settings - Looping + // TODO: use toggle buttons + handlerProxy.call(this, event, this.config.listeners.loop, () => { + // TODO: This should be done in the method itself I think + // var value = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type'); + + this.warn('Set loop'); + }); + } + }); + + // Seek + utils.proxy(this.elements.inputs.seek, inputEvent, this.config.listeners.seek, event => { + this.currentTime = event.target.value / event.target.max * this.duration; + }); + + // Volume + utils.proxy(this.elements.inputs.volume, inputEvent, this.config.listeners.volume, event => { + this.setVolume(event.target.value); + }); + + // Polyfill for lower fill in <input type="range"> for webkit + if (this.browser.isWebkit) { + utils.on(utils.getElements.call(this, 'input[type="range"]'), 'input', event => { + controls.updateRangeFill.call(this, event.target); + }); + } + + // Seek tooltip + utils.on(this.elements.progress, 'mouseenter mouseleave mousemove', event => + ui.updateSeekTooltip.call(this, event) + ); + + // Toggle controls visibility based on mouse movement + if (this.config.hideControls) { + // Toggle controls on mouse events and entering fullscreen + utils.on( + this.elements.container, + 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', + event => { + this.toggleControls(event); + } + ); + + // Watch for cursor over controls so they don't hide when trying to interact + utils.on(this.elements.controls, 'mouseenter mouseleave', event => { + this.elements.controls.hover = event.type === 'mouseenter'; + }); + + // Watch for cursor over controls so they don't hide when trying to interact + utils.on(this.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => { + this.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type); + }); + + // Focus in/out on controls + // TODO: Check we need capture here + utils.on( + this.elements.controls, + 'focus blur', + event => { + this.toggleControls(event); + }, + true + ); + } + + // Mouse wheel for volume + utils.proxy( + this.elements.inputs.volume, + 'wheel', + this.config.listeners.volume, + event => { + // Detect "natural" scroll - suppored on OS X Safari only + // Other browsers on OS X will be inverted until support improves + const inverted = event.webkitDirectionInvertedFromDevice; + const step = 1 / 50; + let direction = 0; + + // Scroll down (or up on natural) to decrease + if (event.deltaY < 0 || event.deltaX > 0) { + if (inverted) { + this.decreaseVolume(step); + direction = -1; + } else { + this.increaseVolume(step); + direction = 1; + } + } + + // Scroll up (or down on natural) to increase + if (event.deltaY > 0 || event.deltaX < 0) { + if (inverted) { + this.increaseVolume(step); + direction = 1; + } else { + this.decreaseVolume(step); + direction = -1; + } + } + + // Don't break page scrolling at max and min + if ((direction === 1 && this.media.volume < 1) || (direction === -1 && this.media.volume > 0)) { + event.preventDefault(); + } + }, + false + ); + + // Handle user exiting fullscreen by escaping etc + if (fullscreen.enabled) { + utils.on(document, fullscreen.eventType, event => { + this.toggleFullscreen(event); + }); + } + }, +}; + +export default listeners; diff --git a/src/js/media.js b/src/js/media.js new file mode 100644 index 00000000..9e53f5fc --- /dev/null +++ b/src/js/media.js @@ -0,0 +1,109 @@ +// ========================================================================== +// Plyr Media +// ========================================================================== + +import support from './support'; +import utils from './utils'; +import youtube from './plugins/youtube'; +import vimeo from './plugins/vimeo'; +import ui from './ui'; + +const media = { + // Setup media + setup() { + // If there's no media, bail + if (!this.media) { + this.warn('No media element found!'); + return; + } + + // Add type class + utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', this.type), true); + + // Add video class for embeds + // This will require changes if audio embeds are added + if (this.isEmbed) { + utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true); + } + + if (this.supported.ui) { + // Check for picture-in-picture support + utils.toggleClass( + this.elements.container, + this.config.classNames.pip.supported, + support.pip && this.type === 'video' + ); + + // Check for airplay support + utils.toggleClass( + this.elements.container, + this.config.classNames.airplay.supported, + support.airplay && this.isHTML5 + ); + + // If there's no autoplay attribute, assume the video is stopped and add state class + utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.config.autoplay); + + // Add iOS class + utils.toggleClass(this.elements.container, this.config.classNames.isIos, this.browser.isIos); + + // Add touch class + utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch); + } + + // Inject the player wrapper + if (['video', 'youtube', 'vimeo'].includes(this.type)) { + // Create the wrapper div + this.elements.wrapper = utils.createElement('div', { + class: this.config.classNames.video, + }); + + // Wrap the video in a container + utils.wrap(this.media, this.elements.wrapper); + } + + // Embeds + if (this.isEmbed) { + switch (this.type) { + case 'youtube': + youtube.setup.call(this); + break; + + case 'vimeo': + vimeo.setup.call(this); + break; + + default: + break; + } + } + + ui.setTitle.call(this); + }, + + // Cancel current network requests + // See https://github.com/sampotts/plyr/issues/174 + cancelRequests() { + if (!this.isHTML5) { + return; + } + + // Remove child sources + Array.from(this.media.querySelectorAll('source')).forEach(utils.removeElement); + + // Set blank video src attribute + // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error + // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection + this.media.setAttribute('src', this.config.blankVideo); + + // Load the new empty source + // This will cancel existing requests + // See https://github.com/sampotts/plyr/issues/174 + this.media.load(); + + // Debugging + this.log('Cancelled network requests'); + }, +}; + +export default media; diff --git a/src/js/plugins/vimeo.js b/src/js/plugins/vimeo.js new file mode 100644 index 00000000..99b55e32 --- /dev/null +++ b/src/js/plugins/vimeo.js @@ -0,0 +1,165 @@ +// ========================================================================== +// Vimeo plugin +// ========================================================================== + +import utils from './../utils'; +import captions from './../captions'; +import ui from './../ui'; + +const vimeo = { + // Setup YouTube + setup() { + // Remove old containers + const containers = utils.getElements.call(this, `[id^="${this.type}-"]`); + Array.from(containers).forEach(utils.removeElement); + + // Add embed class for responsive + utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true); + + // Set ID + this.media.setAttribute('id', utils.generateId(this.type)); + + // Load the API if not already + if (!utils.is.object(window.Vimeo)) { + utils.loadScript(this.config.urls.vimeo.api); + // Wait for load + const vimeoTimer = window.setInterval(() => { + if (utils.is.object(window.Vimeo)) { + window.clearInterval(vimeoTimer); + vimeo.ready.call(this); + } + }, 50); + } else { + vimeo.ready.call(this); + } + }, + + // Ready + ready() { + const player = this; + + // Get Vimeo params for the iframe + const options = { + loop: this.config.loop.active, + autoplay: this.config.autoplay, + byline: false, + portrait: false, + title: false, + transparent: 0, + }; + const params = utils.buildUrlParameters(options); + const id = utils.parseVimeoId(this.embedId); + + // Build an iframe + const iframe = utils.createElement('iframe'); + const src = `https://player.vimeo.com/video/${id}?${params}`; + iframe.setAttribute('src', src); + iframe.setAttribute('allowfullscreen', ''); + player.media.appendChild(iframe); + + // Setup instance + // https://github.com/vimeo/this.js + player.embed = new window.Vimeo.Player(iframe); + + // Create a faux HTML5 API using the Vimeo API + player.media.play = () => { + player.embed.play(); + player.media.paused = false; + }; + player.media.pause = () => { + player.embed.pause(); + player.media.paused = true; + }; + player.media.stop = () => { + player.embed.stop(); + player.media.paused = true; + }; + + player.media.paused = true; + player.media.currentTime = 0; + + // Rebuild UI + ui.build.call(player); + + player.embed.getCurrentTime().then(value => { + player.media.currentTime = value; + utils.dispatchEvent.call(this, this.media, 'timeupdate'); + }); + + player.embed.getDuration().then(value => { + player.media.duration = value; + utils.dispatchEvent.call(player, player.media, 'durationchange'); + }); + + // Get captions + player.embed.getTextTracks().then(tracks => { + player.captions.tracks = tracks; + + captions.setup.call(player); + }); + + player.embed.on('cuechange', data => { + let cue = null; + + if (data.cues.length) { + cue = utils.stripHTML(data.cues[0].text); + } + + captions.set.call(player, cue); + }); + + player.embed.on('loaded', () => { + if (utils.is.htmlElement(player.embed.element) && player.supported.ui) { + const frame = player.embed.element; + + // Fix Vimeo controls issue + // https://github.com/sampotts/plyr/issues/697 + // frame.src = `${frame.src}&transparent=0`; + + // Fix keyboard focus issues + // https://github.com/sampotts/plyr/issues/317 + frame.setAttribute('tabindex', -1); + } + }); + + player.embed.on('play', () => { + player.media.paused = false; + utils.dispatchEvent.call(player, player.media, 'play'); + utils.dispatchEvent.call(player, player.media, 'playing'); + }); + + player.embed.on('pause', () => { + player.media.paused = true; + utils.dispatchEvent.call(player, player.media, 'pause'); + }); + + this.embed.on('timeupdate', data => { + this.media.seeking = false; + this.media.currentTime = data.seconds; + utils.dispatchEvent.call(this, this.media, 'timeupdate'); + }); + + this.embed.on('progress', data => { + this.media.buffered = data.percent; + utils.dispatchEvent.call(this, this.media, 'progress'); + + if (parseInt(data.percent, 10) === 1) { + // Trigger event + utils.dispatchEvent.call(this, this.media, 'canplaythrough'); + } + }); + + this.embed.on('seeked', () => { + this.media.seeking = false; + utils.dispatchEvent.call(this, this.media, 'seeked'); + utils.dispatchEvent.call(this, this.media, 'play'); + }); + + this.embed.on('ended', () => { + this.media.paused = true; + utils.dispatchEvent.call(this, this.media, 'ended'); + }); + }, +}; + +export default vimeo; diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js new file mode 100644 index 00000000..61e7adce --- /dev/null +++ b/src/js/plugins/youtube.js @@ -0,0 +1,256 @@ +// ========================================================================== +// YouTube plugin +// ========================================================================== + +import utils from './../utils'; +import controls from './../controls'; +import ui from './../ui'; + +/* Object.defineProperty(input, "value", { + get: function() {return this._value;}, + set: function(v) { + // Do your stuff + this._value = v; + } +}); */ + +const youtube = { + // Setup YouTube + setup() { + const videoId = utils.parseYouTubeId(this.embedId); + + // Remove old containers + const containers = utils.getElements.call(this, `[id^="${this.type}-"]`); + Array.from(containers).forEach(utils.removeElement); + + // Add embed class for responsive + utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true); + + // Set ID + this.media.setAttribute('id', utils.generateId(this.type)); + + // Setup API + if (utils.is.object(window.YT)) { + youtube.ready.call(this, videoId); + } else { + // Load the API + utils.loadScript(this.config.urls.youtube.api); + + // Setup callback for the API + window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || []; + + // Add to queue + window.onYouTubeReadyCallbacks.push(() => { + youtube.ready.call(this, videoId); + }); + + // Set callback to process queue + window.onYouTubeIframeAPIReady = () => { + window.onYouTubeReadyCallbacks.forEach(callback => { + callback(); + }); + }; + } + }, + + // Handle YouTube API ready + ready(videoId) { + const player = this; + + // Setup instance + // https://developers.google.com/youtube/iframe_api_reference + player.embed = new window.YT.Player(player.media.id, { + videoId, + playerVars: { + autoplay: player.config.autoplay ? 1 : 0, // Autoplay + controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported + rel: 0, // No related vids + showinfo: 0, // Hide info + iv_load_policy: 3, // Hide annotations + modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused) + disablekb: 1, // Disable keyboard as we handle it + playsinline: 1, // Allow iOS inline playback + + // Tracking for stats + origin: window && window.location.hostname, + widget_referrer: window && window.location.href, + + // Captions is flaky on YouTube + // cc_load_policy: (this.captions.active ? 1 : 0), + // cc_lang_pref: 'en', + }, + events: { + onError(event) { + utils.dispatchEvent.call(player, player.media, 'error', true, { + code: event.data, + embed: event.target, + }); + }, + onPlaybackQualityChange(event) { + // Get the instance + const instance = event.target; + + // Get current quality + player.media.quality = instance.getPlaybackQuality(); + + utils.dispatchEvent.call(player, player.media, 'qualitychange'); + }, + onPlaybackRateChange(event) { + // Get the instance + const instance = event.target; + + // Get current speed + player.media.playbackRate = instance.getPlaybackRate(); + + utils.dispatchEvent.call(player, player.media, 'ratechange'); + }, + onReady(event) { + // Get the instance + const instance = event.target; + + // Create a faux HTML5 API using the YouTube API + player.media.play = () => { + instance.playVideo(); + player.media.paused = false; + }; + player.media.pause = () => { + instance.pauseVideo(); + player.media.paused = true; + }; + player.media.stop = () => { + instance.stopVideo(); + player.media.paused = true; + }; + player.media.duration = instance.getDuration(); + player.media.paused = true; + player.media.muted = instance.isMuted(); + player.media.currentTime = 0; + + // Get available speeds + if (player.config.controls.includes('settings') && player.config.settings.includes('speed')) { + controls.setSpeedMenu.call(player, instance.getAvailablePlaybackRates()); + } + + // Set title + player.config.title = instance.getVideoData().title; + + // Set the tabindex to avoid focus entering iframe + if (player.supported.ui) { + player.media.setAttribute('tabindex', -1); + } + + // Rebuild UI + ui.build.call(player); + + utils.dispatchEvent.call(player, player.media, 'timeupdate'); + utils.dispatchEvent.call(player, player.media, 'durationchange'); + + // Reset timer + window.clearInterval(player.timers.buffering); + + // Setup buffering + player.timers.buffering = window.setInterval(() => { + // Get loaded % from YouTube + player.media.buffered = instance.getVideoLoadedFraction(); + + // Trigger progress only when we actually buffer something + if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) { + utils.dispatchEvent.call(player, player.media, 'progress'); + } + + // Set last buffer point + player.media.lastBuffered = player.media.buffered; + + // Bail if we're at 100% + if (player.media.buffered === 1) { + window.clearInterval(player.timers.buffering); + + // Trigger event + utils.dispatchEvent.call(player, player.media, 'canplaythrough'); + } + }, 200); + }, + onStateChange(event) { + // Get the instance + const instance = event.target; + + // Reset timer + window.clearInterval(player.timers.playing); + + // Handle events + // -1 Unstarted + // 0 Ended + // 1 Playing + // 2 Paused + // 3 Buffering + // 5 Video cued + switch (event.data) { + case 0: + // YouTube doesn't support loop for a single video, so mimick it. + if (player.config.loop.active) { + // YouTube needs a call to `stopVideo` before playing again + instance.stopVideo(); + instance.playVideo(); + + break; + } + + player.media.paused = true; + + utils.dispatchEvent.call(player, player.media, 'ended'); + + break; + + case 1: + player.media.paused = false; + + // If we were seeking, fire seeked event + if (player.media.seeking) { + utils.dispatchEvent.call(player, player.media, 'seeked'); + } + + player.media.seeking = false; + + utils.dispatchEvent.call(player, player.media, 'play'); + utils.dispatchEvent.call(player, player.media, 'playing'); + + // Poll to get playback progress + player.timers.playing = window.setInterval(() => { + player.media.currentTime = instance.getCurrentTime(); + utils.dispatchEvent.call(player, player.media, 'timeupdate'); + }, 100); + + // Check duration again due to YouTube bug + // https://github.com/sampotts/plyr/issues/374 + // https://code.google.com/p/gdata-issues/issues/detail?id=8690 + if (player.media.duration !== instance.getDuration()) { + player.media.duration = instance.getDuration(); + utils.dispatchEvent.call(player, player.media, 'durationchange'); + } + + // Get quality + controls.setQualityMenu.call(player, instance.getAvailableQualityLevels()); + + break; + + case 2: + player.media.paused = true; + + utils.dispatchEvent.call(player, player.media, 'pause'); + + break; + + default: + break; + } + + utils.dispatchEvent.call(player, player.elements.container, 'statechange', false, { + code: event.data, + }); + }, + }, + }); + }, +}; + +export default youtube; diff --git a/src/js/plyr.js b/src/js/plyr.js index 3968162a..50b437c1 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -5,1304 +5,67 @@ // License: The MIT License (MIT) // ========================================================================== -// UMD-Inspired JS Module from https://gist.github.com/wilmoore/3880415 -(function(name, context, definition) { - /* global define,module,require */ - 'use strict'; - - if (typeof exports === 'object') { - module.exports = definition(require); - } else if (typeof define === 'function' && define.amd) { - define(definition); - } else { - context[name] = definition(); - } -}.call(this, 'Plyr', this, function() { - 'use strict'; - /* global jQuery */ - - // Globals - var scroll = { - x: 0, - y: 0, - }; - - // Default config - var defaults = { - // Disable - enabled: true, - - // Custom media title - title: '', - - // Logging to console - debug: false, - - // Auto play (if supported) - autoplay: false, - - // Default time to skip when rewind/fast forward - seekTime: 10, - - // Default volume - volume: 1, - muted: false, - - // Display the media duration - displayDuration: true, - - // Click video to play - clickToPlay: true, - - // Auto hide the controls - hideControls: true, - - // Revert to poster on finish (HTML5 - will cause reload) - showPosterOnEnd: false, - - // Disable the standard context menu - disableContextMenu: true, - - // Sprite (for icons) - loadSprite: true, - iconPrefix: 'plyr', - iconUrl: 'https://cdn.plyr.io/2.0.10/plyr.svg', - - // Blank video (used to prevent errors on source change) - blankVideo: 'https://cdn.plyr.io/static/blank.mp4', - - // Pass a custom duration - duration: null, - - // Quality default - quality: { - default: 'default', - options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'], - }, - - // Set loops - loop: { - active: false, - start: null, - end: null, - }, - - // Speed default and options to display - speed: { - default: 1, - options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], - }, - - // Keyboard shortcut settings - keyboard: { - focused: true, - global: false, - }, - - // Display tooltips - tooltips: { - controls: false, - seek: true, - }, - - // Captions settings - captions: { - active: false, - language: window.navigator.language.split('-')[0], - }, - - // Fullscreen settings - fullscreen: { - enabled: true, // Allow fullscreen? - fallback: true, // Fallback for vintage browsers - }, - - // Local storage - storage: { - enabled: true, - key: 'plyr', - }, - - // Default controls - controls: [ - 'play-large', - 'play', - 'progress', - 'current-time', - 'mute', - 'volume', - 'captions', - 'settings', - 'pip', - 'airplay', - 'fullscreen', - ], - settings: ['captions', 'quality', 'speed', 'loop'], - - // Localisation - i18n: { - restart: 'Restart', - rewind: 'Rewind {seektime} secs', - play: 'Play', - pause: 'Pause', - forward: 'Forward {seektime} secs', - seek: 'Seek', - played: 'Played', - buffered: 'Buffered', - currentTime: 'Current time', - duration: 'Duration', - volume: 'Volume', - toggleMute: 'Toggle Mute', - toggleCaptions: 'Toggle Captions', - toggleFullscreen: 'Toggle Fullscreen', - frameTitle: 'Player for {title}', - captions: 'Captions', - settings: 'Settings', - speed: 'Speed', - quality: 'Quality', - loop: 'Loop', - start: 'Start', - end: 'End', - all: 'All', - reset: 'Reset', - none: 'None', - disabled: 'Disabled', - }, - - // URLs - urls: { - vimeo: { - api: 'https://player.vimeo.com/api/player.js', - }, - youtube: { - api: 'https://www.youtube.com/iframe_api', - }, - soundcloud: { - api: 'https://w.soundcloud.com/player/api.js', - }, - }, - - // Custom control listeners - listeners: { - seek: null, - play: null, - pause: null, - restart: null, - rewind: null, - forward: null, - mute: null, - volume: null, - captions: null, - fullscreen: null, - pip: null, - airplay: null, - speed: null, - quality: null, - loop: null, - language: null, - }, - - // Events to watch and bubble - events: [ - // Events to watch on HTML5 media elements and bubble - // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events - 'ended', - 'progress', - 'stalled', - 'playing', - 'waiting', - 'canplay', - 'canplaythrough', - 'loadstart', - 'loadeddata', - 'loadedmetadata', - 'timeupdate', - 'volumechange', - 'play', - 'pause', - 'error', - 'seeking', - 'seeked', - 'emptied', - 'ratechange', - 'cuechange', - - // Custom events - 'enterfullscreen', - 'exitfullscreen', - 'captionsenabled', - 'captionsdisabled', - 'captionchange', - 'controlshidden', - 'controlsshown', - - // YouTube - 'statechange', - 'qualitychange', - 'qualityrequested', - ], - - // Selectors - // Change these to match your template if using custom HTML - selectors: { - editable: 'input, textarea, select, [contenteditable]', - container: '.plyr', - controls: { - container: null, - wrapper: '.plyr__controls', - }, - labels: '[data-plyr]', - buttons: { - play: '[data-plyr="play"]', - pause: '[data-plyr="pause"]', - restart: '[data-plyr="restart"]', - rewind: '[data-plyr="rewind"]', - forward: '[data-plyr="fast-forward"]', - mute: '[data-plyr="mute"]', - captions: '[data-plyr="captions"]', - fullscreen: '[data-plyr="fullscreen"]', - pip: '[data-plyr="pip"]', - airplay: '[data-plyr="airplay"]', - settings: '[data-plyr="settings"]', - loop: '[data-plyr="loop"]', - }, - inputs: { - seek: '[data-plyr="seek"]', - volume: '[data-plyr="volume"]', - speed: '[data-plyr="speed"]', - language: '[data-plyr="language"]', - quality: '[data-plyr="quality"]', - }, - display: { - currentTime: '.plyr__time--current', - duration: '.plyr__time--duration', - buffer: '.plyr__progress--buffer', - played: '.plyr__progress--played', - loop: '.plyr__progress--loop', - volume: '.plyr__volume--display', - }, - progress: '.plyr__progress', - captions: '.plyr__captions', - menu: { - quality: '.js-plyr__menu__list--quality', - }, - }, - - // Class hooks added to the player in different states - classNames: { - video: 'plyr__video-wrapper', - embed: 'plyr__video-embed', - control: 'plyr__control', - type: 'plyr--{0}', - stopped: 'plyr--stopped', - playing: 'plyr--playing', - muted: 'plyr--muted', - loading: 'plyr--loading', - hover: 'plyr--hover', - tooltip: 'plyr__tooltip', - hidden: 'plyr__sr-only', - hideControls: 'plyr--hide-controls', - isIos: 'plyr--is-ios', - isTouch: 'plyr--is-touch', - uiSupported: 'plyr--full-ui', - menu: { - value: 'plyr__menu__value', - badge: 'plyr__badge', - }, - captions: { - enabled: 'plyr--captions-enabled', - active: 'plyr--captions-active', - }, - fullscreen: { - enabled: 'plyr--fullscreen-enabled', - fallback: 'plyr--fullscreen-fallback', - }, - pip: { - supported: 'plyr--pip-supported', - active: 'plyr--pip-active', - }, - airplay: { - supported: 'plyr--airplay-supported', - active: 'plyr--airplay-active', - }, - tabFocus: 'tab-focus', - }, - }; - - // Types - var types = { - embed: ['youtube', 'vimeo', 'soundcloud'], - html5: ['video', 'audio'], - }; - - // Utilities - var utils = { - // Check variable types - is: { - object: function(input) { - return input !== null && typeof input === 'object' && input.constructor === Object; - }, - array: function(input) { - return input !== null && Array.isArray(input); - }, - number: function(input) { - return ( - input !== null && - ((typeof input === 'number' && !isNaN(input - 0)) || - (typeof input === 'object' && input.constructor === Number)) - ); - }, - string: function(input) { - return ( - input !== null && - (typeof input === 'string' || (typeof input === 'object' && input.constructor === String)) - ); - }, - boolean: function(input) { - return input !== null && typeof input === 'boolean'; - }, - nodeList: function(input) { - return input !== null && input instanceof NodeList; - }, - htmlElement: function(input) { - return input !== null && input instanceof HTMLElement; - }, - function: function(input) { - return input !== null && typeof input === 'function'; - }, - event: function(input) { - return input !== null && input instanceof Event; - }, - cue: function(input) { - this.instanceOf(input, window.TextTrackCue) || this.instanceOf(input, window.VTTCue); - }, - track: function(input) { - return input !== null && (this.instanceOf(input, window.TextTrack) || typeof input.kind === 'string'); - }, - undefined: function(input) { - return input !== null && typeof input === 'undefined'; - }, - empty: function(input) { - return ( - input === null || - this.undefined(input) || - ((this.string(input) || this.array(input) || this.nodeList(input)) && input.length === 0) || - (this.object(input) && Object.keys(input).length === 0) - ); - }, - instanceOf: function(input, constructor) { - return Boolean(input && constructor && input instanceof constructor); - }, - }, - - // Credits: http://paypal.github.io/accessible-html5-video-player/ - // Unfortunately, due to mixed support, UA sniffing is required - getBrowser: function() { - var ua = navigator.userAgent; - var name = navigator.appName; - var fullVersion = '' + parseFloat(navigator.appVersion); - var majorVersion = parseInt(navigator.appVersion, 10); - var nameOffset; - var verOffset; - var ix; - var isIE = false; - var isFirefox = false; - var isChrome = false; - var isSafari = false; - - if (navigator.appVersion.indexOf('Windows NT') !== -1 && navigator.appVersion.indexOf('rv:11') !== -1) { - // MSIE 11 - isIE = true; - name = 'IE'; - fullVersion = '11'; - } else if ((verOffset = ua.indexOf('MSIE')) !== -1) { - // MSIE - isIE = true; - name = 'IE'; - fullVersion = ua.substring(verOffset + 5); - } else if ((verOffset = ua.indexOf('Chrome')) !== -1) { - // Chrome - isChrome = true; - name = 'Chrome'; - fullVersion = ua.substring(verOffset + 7); - } else if ((verOffset = ua.indexOf('Safari')) !== -1) { - // Safari - isSafari = true; - name = 'Safari'; - fullVersion = ua.substring(verOffset + 7); - - if ((verOffset = ua.indexOf('Version')) !== -1) { - fullVersion = ua.substring(verOffset + 8); - } - } else if ((verOffset = ua.indexOf('Firefox')) !== -1) { - // Firefox - isFirefox = true; - name = 'Firefox'; - fullVersion = ua.substring(verOffset + 8); - } else if ((nameOffset = ua.lastIndexOf(' ') + 1) < (verOffset = ua.lastIndexOf('/'))) { - // In most other browsers, 'name/version' is at the end of userAgent - name = ua.substring(nameOffset, verOffset); - fullVersion = ua.substring(verOffset + 1); - - if (name.toLowerCase() === name.toUpperCase()) { - name = navigator.appName; - } - } - - // Trim the fullVersion string at semicolon/space if present - if ((ix = fullVersion.indexOf(';')) !== -1) { - fullVersion = fullVersion.substring(0, ix); - } - if ((ix = fullVersion.indexOf(' ')) !== -1) { - fullVersion = fullVersion.substring(0, ix); - } - - // Get major version - majorVersion = parseInt('' + fullVersion, 10); - if (isNaN(majorVersion)) { - fullVersion = '' + parseFloat(navigator.appVersion); - majorVersion = parseInt(navigator.appVersion, 10); - } - - // Return data - return { - name: name, - version: majorVersion, - isIE: isIE, - isFirefox: isFirefox, - isChrome: isChrome, - isSafari: isSafari, - isWebkit: 'WebkitAppearance' in document.documentElement.style, - isIPhone: /(iPhone|iPod)/gi.test(navigator.platform), - isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform), - isSupported: !(isIE && majorVersion <= 9), - }; - }, - - // Check for support - // Basic functionality vs full UI - checkSupport: function(type, inline) { - var api = false; - var ui = false; - var browser = utils.getBrowser(); - var playsInline = browser.isIPhone && inline && support.inline; - - switch (type) { - case 'video': - api = support.video; - ui = api && browser.isSupported && (!browser.isIPhone || playsInline); - break; - - case 'audio': - api = support.audio; - ui = api && browser.isSupported; - break; - - case 'youtube': - api = true; - ui = api && browser.isSupported && (!browser.isIPhone || playsInline); - break; - - case 'vimeo': - api = true; - ui = false; - break; - - case 'soundcloud': - api = true; - ui = browser.isSupported; - break; - - default: - api = support.audio && support.video; - ui = api && browser.isSupported; - } - - return { - api: api, - ui: ui, - }; - }, - - // Inject a script - injectScript: function(url) { - // Check script is not already referenced - if (document.querySelectorAll('script[src="' + url + '"]').length) { - return; - } - - var tag = document.createElement('script'); - tag.src = url; - - var firstScriptTag = document.getElementsByTagName('script')[0]; - firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); - }, - - // Determine if we're in an iframe - inFrame: function() { - try { - return window.self !== window.top; - } catch (e) { - return true; - } - }, - - // Element exists in an array - inArray: function(haystack, needle) { - return utils.is.array(haystack) && haystack.indexOf(needle) !== -1; - }, - - // Wrap an element - wrap: function(elements, wrapper) { - // Convert `elements` to an array, if necessary. - if (!elements.length) { - elements = [elements]; - } - - // Loops backwards to prevent having to clone the wrapper on the - // first element (see `child` below). - for (var i = elements.length - 1; i >= 0; i--) { - var child = i > 0 ? wrapper.cloneNode(true) : wrapper; - var element = elements[i]; - - // Cache the current parent and sibling. - var parent = element.parentNode; - var sibling = element.nextSibling; - - // Wrap the element (is automatically removed from its current - // parent). - child.appendChild(element); - - // If the element had a sibling, insert the wrapper before - // the sibling to maintain the HTML structure; otherwise, just - // append it to the parent. - if (sibling) { - parent.insertBefore(child, sibling); - } else { - parent.appendChild(child); - } - - return child; - } - }, - - // Remove an element - removeElement: function(element) { - if (!utils.is.htmlElement(element) || !utils.is.htmlElement(element.parentNode)) { - return; - } - - element.parentNode.removeChild(element); - }, - - // Inaert an element after another - insertAfter: function(element, target) { - target.parentNode.insertBefore(element, target.nextSibling); - }, - - // Create a DocumentFragment - createElement: function(type, attributes, text) { - // Create a new <element> - var element = document.createElement(type); - - // Set all passed attributes - if (utils.is.object(attributes)) { - utils.setAttributes(element, attributes); - } - - // Add text node - if (utils.is.string(text)) { - element.textContent = text; - } - - // Return built element - return element; - }, - - // Insert a DocumentFragment - insertElement: function(type, parent, attributes, text) { - // Inject the new <element> - parent.appendChild(utils.createElement(type, attributes, text)); - }, - - // Remove all child elements - emptyElement: function(element) { - var length = element.childNodes.length; - - while (length--) { - element.removeChild(element.lastChild); - } - }, - - // Set attributes - setAttributes: function(element, attributes) { - for (var key in attributes) { - element.setAttribute(key, attributes[key]); - } - }, - - // Get an attribute object from a string selector - getAttributesFromSelector: function(selector, existingAttributes) { - // For example: - // '.test' to { class: 'test' } - // '#test' to { id: 'test' } - // '[data-test="test"]' to { 'data-test': 'test' } - - if (!utils.is.string(selector) || utils.is.empty(selector)) { - return {}; - } - - var attributes = {}; - - selector.split(',').forEach(function(selector) { - // Remove whitespace - selector = selector.trim(); - - // Get the first character - var start = selector.charAt(0); - - switch (start) { - case '.': - // Classname selector - var className = selector.replace('.', ''); - - // Add to existing classname - if (utils.is.object(existingAttributes) && utils.is.string(existingAttributes.class)) { - existingAttributes.class += ' ' + className; - } - - attributes.class = className; - break; - - case '#': - // ID selector - attributes.id = selector.replace('#', ''); - break; - - case '[': - // Strip the [] - selector = selector.replace(/[[\]]/g, ''); - - // Get the parts if - var parts = selector.split('='); - var key = parts[0]; - - // Get the value if provided - var value = parts.length > 1 ? parts[1].replace(/["']/g, '') : ''; - - // Attribute selector - attributes[key] = value; - - break; - } - }); - - return attributes; - }, - - // Toggle class on an element - toggleClass: function(element, className, toggle) { - if (utils.is.htmlElement(element)) { - var contains = false; - - if (element.classList) { - contains = element.classList.contains(className); - element.classList[toggle ? 'add' : 'remove'](className); - } else { - contains = utils.inArray(element.className.split(' '), className); - var name = (' ' + element.className + ' ').replace(/\s+/g, ' ').replace(' ' + className + ' ', ''); - element.className = name + (toggle ? ' ' + className : ''); - } - - return (toggle && !contains) || (!toggle && contains); - } - - return null; - }, - - // Has class name - hasClass: function(element, className) { - if (element) { - if (element.classList) { - return element.classList.contains(className); - } else { - return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className); - } - } - return false; - }, - - // Element matches selector - matches: function(element, selector) { - var prototype = Element.prototype; - - var matches = - prototype.matches || - prototype.webkitMatchesSelector || - prototype.mozMatchesSelector || - prototype.msMatchesSelector || - function(selector) { - return [].indexOf.call(document.querySelectorAll(selector), this) !== -1; - }; - - return matches.call(element, selector); - }, - - // Get the focused element - getFocusElement: function() { - var focused = document.activeElement; - - if (!focused || focused === document.body) { - focused = null; - } else { - focused = document.querySelector(':focus'); - } - - return focused; - }, - - // Bind along with custom handler - proxy: function(element, eventName, customListener, defaultListener, passive, capture) { - utils.on( - element, - eventName, - function(event) { - if (customListener) { - customListener.apply(element, [event]); - } - defaultListener.apply(element, [event]); - }, - passive, - capture - ); - }, - - // Toggle event listener - toggleListener: function(elements, events, callback, toggle, passive, capture) { - // Bail if no elements - if (elements === null || utils.is.undefined(elements)) { - return; - } - - // Allow multiple events - events = events.split(' '); - - // Whether the listener is a capturing listener or not - // Default to false - if (!utils.is.boolean(capture)) { - capture = false; - } - - // Whether the listener can be passive (i.e. default never prevented) - // Default to true - if (!utils.is.boolean(passive)) { - passive = true; - } - - // If a nodelist is passed, call itself on each node - if (elements instanceof NodeList) { - // Convert arguments to Array - // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/arguments - var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments); - - // Remove the first argument (elements) as we replace it - args.shift(); - - // Create listener for each node - [].forEach.call(elements, function(element) { - if (element instanceof Node) { - utils.toggleListener.apply(null, [element].concat(args)); - } - }); - - return; - } - - // Build options - // Default to just capture boolean - var options = capture; - - // If passive events listeners are supported - if (support.passiveListeners) { - options = { - passive: passive, - capture: capture, - }; - } - - // If a single node is passed, bind the event listener - events.forEach(function(event) { - elements[toggle ? 'addEventListener' : 'removeEventListener'](event, callback, options); - }); - }, - - // Bind event handler - on: function(element, events, callback, passive, capture) { - utils.toggleListener(element, events, callback, true, passive, capture); - }, - - // Unbind event handler - off: function(element, events, callback, passive, capture) { - utils.toggleListener(element, events, callback, false, passive, capture); - }, - - // Trigger event - dispatchEvent: function(element, type, bubbles, properties) { - // Bail if no element - if (!element || !type) { - return; - } - - // Default bubbles to false - if (!utils.is.boolean(bubbles)) { - bubbles = false; - } - - // Create CustomEvent constructor - var CustomEvent; - if (utils.is.function(window.CustomEvent)) { - CustomEvent = window.CustomEvent; - } else { - // Polyfill CustomEvent - // https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill - CustomEvent = function(event, params) { - params = params || { - bubbles: false, - cancelable: false, - detail: undefined, - }; - var custom = document.createEvent('CustomEvent'); - custom.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); - return custom; - }; - CustomEvent.prototype = window.Event.prototype; - } - - // Create and dispatch the event - var event = new CustomEvent(type, { - bubbles: bubbles, - detail: properties, - }); - - // Dispatch the event - element.dispatchEvent(event); - }, - - // Toggle aria-pressed state on a toggle button - // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles - toggleState: function(target, state) { - // Bail if no target - if (!target) { - return; - } - - // Get state - state = utils.is.boolean(state) ? state : !target.getAttribute('aria-pressed'); - - // Set the attribute on target - target.setAttribute('aria-pressed', state); - - return state; - }, - - // Get percentage - getPercentage: function(current, max) { - if (current === 0 || max === 0 || isNaN(current) || isNaN(max)) { - return 0; - } - return (current / max * 100).toFixed(2); - }, - - // Deep extend/merge destination object with N more objects - // http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/ - // Removed call to arguments.callee (used explicit function name instead) - extend: function() { - // Get arguments - var objects = arguments; - - // Bail if nothing to merge - if (!objects.length) { - return; - } - - // Return first if specified but nothing to merge - if (objects.length === 1) { - return objects[0]; - } - - // First object is the destination - var destination = Array.prototype.shift.call(objects); - if (!utils.is.object(destination)) { - destination = {}; - } - - var length = objects.length; - - // Loop through all objects to merge - for (var i = 0; i < length; i++) { - var source = objects[i]; - - if (!utils.is.object(source)) { - source = {}; - } - - for (var property in source) { - if (source[property] && source[property].constructor && source[property].constructor === Object) { - destination[property] = destination[property] || {}; - utils.extend(destination[property], source[property]); - } else { - destination[property] = source[property]; - } - } - } - - return destination; - }, - - // Parse YouTube ID from url - parseYouTubeId: function(url) { - var regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; - return url.match(regex) ? RegExp.$2 : url; - }, - - // Remove HTML from a string - stripHTML: function(source) { - var fragment = document.createDocumentFragment(); - var element = document.createElement('div'); - fragment.appendChild(element); - element.innerHTML = source; - return fragment.firstChild.innerText; - }, - - // Load an SVG sprite - loadSprite: function(url, id) { - if (typeof url !== 'string') { - return; - } - - var prefix = 'cache-'; - var hasId = typeof id === 'string'; - var isCached = false; - - function updateSprite(container, data) { - // Inject content - container.innerHTML = data; - - // Inject the SVG to the body - document.body.insertBefore(container, document.body.childNodes[0]); - } - - // Only load once - if (!hasId || !document.querySelectorAll('#' + id).length) { - // Create container - var container = document.createElement('div'); - container.setAttribute('hidden', ''); - - if (hasId) { - container.setAttribute('id', id); - } - - // Check in cache - if (support.storage) { - var cached = window.localStorage.getItem(prefix + id); - isCached = cached !== null; - - if (isCached) { - var data = JSON.parse(cached); - updateSprite(container, data.content); - } - } - - // ReSharper disable once InconsistentNaming - var xhr = new XMLHttpRequest(); - - // XHR for Chrome/Firefox/Opera/Safari - if ('withCredentials' in xhr) { - xhr.open('GET', url, true); - } else { - return; - } - - // Once loaded, inject to container and body - xhr.onload = function() { - if (support.storage) { - window.localStorage.setItem( - prefix + id, - JSON.stringify({ - content: xhr.responseText, - }) - ); - } - - updateSprite(container, xhr.responseText); - }; - - xhr.send(); - } - }, - - // Get the transition end event - transitionEnd: (function() { - var element = document.createElement('span'); - - var events = { - WebkitTransition: 'webkitTransitionEnd', - MozTransition: 'transitionend', - OTransition: 'oTransitionEnd otransitionend', - transition: 'transitionend', - }; - - for (var type in events) { - if (element.style[type] !== undefined) { - return events[type]; - } - } - - return false; - })(), - }; - - // Fullscreen API - var fullscreen = (function() { - // Determine the prefix - var prefix = (function() { - var value = false; - - if (utils.is.function(document.cancelFullScreen)) { - value = ''; - } else { - // Check for fullscreen support by vendor prefix - ['webkit', 'o', 'moz', 'ms', 'khtml'].some(function(prefix) { - if (utils.is.function(document[prefix + 'CancelFullScreen'])) { - value = prefix; - return true; - } else if (utils.is.function(document.msExitFullscreen) && document.msFullscreenEnabled) { - // Special case for MS (when isn't it?) - value = 'ms'; - return true; - } - }); - } - - return value; - })(); - - return { - prefix: prefix, - // Yet again Microsoft awesomeness, - // Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes - eventType: prefix === 'ms' ? 'MSFullscreenChange' : prefix + 'fullscreenchange', - - // Is an element fullscreen - isFullScreen: function(element) { - if (!support.fullscreen) { - return false; - } - - if (utils.is.undefined(element)) { - element = document.body; - } - - switch (prefix) { - case '': - return document.fullscreenElement === element; - - case 'moz': - return document.mozFullScreenElement === element; - - default: - return document[prefix + 'FullscreenElement'] === element; - } - }, - requestFullScreen: function(element) { - if (!support.fullscreen) { - return false; - } - - if (!utils.is.htmlElement(element)) { - element = document.body; - } - - return !prefix.length - ? element.requestFullScreen() - : element[prefix + (prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')](); - }, - cancelFullScreen: function() { - if (!support.fullscreen) { - return false; - } - - return !prefix.length - ? document.cancelFullScreen() - : document[prefix + (prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')](); - }, - element: function() { - if (!support.fullscreen) { - return null; - } - - return !prefix.length ? document.fullscreenElement : document[prefix + 'FullscreenElement']; - }, - }; - })(); - - // Check for feature support - var support = { - // Basic support - audio: 'canPlayType' in document.createElement('audio'), - video: 'canPlayType' in document.createElement('video'), - - // Fullscreen support and set prefix - fullscreen: fullscreen.prefix !== false, - - // Local storage - // We can't assume if local storage is present that we can use it - storage: (function() { - if (!('localStorage' in window)) { - return false; - } - - // Try to use it (it might be disabled, e.g. user is in private/porn mode) - // see: https://github.com/sampotts/plyr/issues/131 - var test = '___test'; - try { - window.localStorage.setItem(test, test); - window.localStorage.removeItem(test); - return true; - } catch (e) { - return false; - } - })(), - - // Picture-in-picture support - // Safari only currently - pip: (function() { - var browser = utils.getBrowser(); - return !browser.isIPhone && utils.is.function(utils.createElement('video').webkitSetPresentationMode); - })(), - - // Airplay support - // Safari only currently - airplay: utils.is.function(window.WebKitPlaybackTargetAvailabilityEvent), - - // Inline playback support - // https://webkit.org/blog/6784/new-video-policies-for-ios/ - inline: 'playsInline' in document.createElement('video'), - - // Check for mime type support against a player instance - // Credits: http://diveintohtml5.info/everything.html - // Related: http://www.leanbackplayer.com/test/h5mt.html - mime: function(player, type) { - var media = player.media; - - try { - // Bail if no checking function - if (!utils.is.function(media.canPlayType)) { - return false; - } - - // Type specific checks - if (player.type === 'video') { - switch (type) { - case 'video/webm': - return media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, ''); - case 'video/mp4': - return media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''); - case 'video/ogg': - return media.canPlayType('video/ogg; codecs="theora"').replace(/no/, ''); - } - } else if (player.type === 'audio') { - switch (type) { - case 'audio/mpeg': - return media.canPlayType('audio/mpeg;').replace(/no/, ''); - case 'audio/ogg': - return media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''); - case 'audio/wav': - return media.canPlayType('audio/wav; codecs="1"').replace(/no/, ''); - } - } - } catch (e) { - return false; - } - - // If we got this far, we're stuffed - return false; - }, - - // Check for textTracks support - textTracks: 'textTracks' in document.createElement('video'), - - // Check for passive event listener support - // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md - // https://www.youtube.com/watch?v=NPM6172J22g - passiveListeners: (function() { - // Test via a getter in the options object to see if the passive property is accessed - var supported = false; - try { - var options = Object.defineProperty({}, 'passive', { - get: function() { - supported = true; - }, - }); - window.addEventListener('test', null, options); - } catch (e) { - // Do nothing - } - - return supported; - })(), - - // Touch - // Remember a device can be moust + touch enabled - touch: 'ontouchstart' in document.documentElement, - - // Detect transitions support - transitions: utils.transitionEnd !== false, - - // Reduced motion iOS & MacOS setting - // https://webkit.org/blog/7551/responsive-design-for-motion/ - reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches, - }; - - // Plyr instance - function Plyr(media, options) { - var player = this; - var timers = {}; - player.ready = false; - - // Get the media element - player.media = media; +/* global jQuery */ + +import defaults from './defaults'; +import types from './types'; +import support from './support'; +import utils from './utils'; + +import captions from './captions'; +import controls from './controls'; +import fullscreen from './fullscreen'; +import media from './media'; +import storage from './storage'; +import source from './source'; +import ui from './ui'; + +// Globals +let scrollPosition = { + x: 0, + y: 0, +}; + +// Plyr instance +class Plyr { + constructor(target, options) { + this.timers = {}; + this.ready = false; + + // Set the media element + this.media = target; // String selector passed - if (utils.is.string(player.media)) { - player.media = document.querySelectorAll(player.media); + if (utils.is.string(this.media)) { + this.media = document.querySelectorAll(this.media); } // jQuery, NodeList or Array passed, use first element if ( - (window.jQuery && player.media instanceof jQuery) || - utils.is.nodeList(player.media) || - utils.is.array(player.media) + (window.jQuery && this.media instanceof jQuery) || + utils.is.nodeList(this.media) || + utils.is.array(this.media) ) { - player.media = player.media[0]; + // eslint-disable-next-line + this.media = this.media[0]; } // Set config - player.config = utils.extend( + this.config = utils.extend( {}, defaults, options, - (function() { + (() => { try { - return JSON.parse(player.media.getAttribute('data-plyr')); + return JSON.parse(this.media.getAttribute('data-plyr')); } catch (e) { - // Do nothing + return null; } })() ); // Elements cache - player.elements = { + this.elements = { container: null, buttons: {}, display: {}, @@ -1317,3624 +80,234 @@ }; // Captions - player.captions = { + this.captions = { enabled: null, tracks: null, currentTrack: null, }; // Fullscreen - player.fullscreen = { + this.fullscreen = { active: false, }; - // Speed - player.speed = { - selected: null, - options: [], - }; - - // Quality - player.quality = { - selected: null, - options: [], - }; - - // Loop - player.loop = { - indicator: { - start: 0, - end: 0, - }, + // Options + this.options = { + speed: [], + quality: [], }; // Debugging - var log = function() {}; - var warn = function() {}; - var error = function() {}; - if (player.config.debug && 'console' in window) { - log = console.log; // eslint-disable-line - warn = console.warn; // eslint-disable-line - error = console.error; // eslint-disable-line - log('Debugging enabled'); + this.log = () => {}; + this.warn = () => {}; + this.error = () => {}; + if (this.config.debug && 'console' in window) { + this.log = console.log; // eslint-disable-line + this.warn = console.warn; // eslint-disable-line + this.error = console.error; // eslint-disable-line + this.log('Debugging enabled'); } // Log config options and support - log('Config', player.config); - log('Support', support); - - // Trigger events, with plyr instance passed - function trigger(element, type, bubbles, properties) { - utils.dispatchEvent( - element, - type, - bubbles, - utils.extend({}, properties, { - plyr: player, - }) - ); - } - - // Trap focus inside container - function trapFocus() { - var tabbables = getElements('input:not([disabled]), button:not([disabled])'); - var first = tabbables[0]; - var last = tabbables[tabbables.length - 1]; - - function checkFocus(event) { - // If it is tab - if (event.which === 9 && player.fullscreen.active) { - if (event.target === last && !event.shiftKey) { - // Move focus to first element that can be tabbed if Shift isn't used - event.preventDefault(); - first.focus(); - } else if (event.target === first && event.shiftKey) { - // Move focus to last element that can be tabbed if Shift is used - event.preventDefault(); - last.focus(); - } - } - } - - // Bind the handler - utils.on(player.elements.container, 'keydown', checkFocus, false); - } - - // Find all elements - function getElements(selector) { - return player.elements.container.querySelectorAll(selector); - } - - // Find a single element - function getElement(selector) { - return getElements(selector)[0]; - } - - // Remove an element - function removeElement(element) { - // Remove reference from player.elements cache - if (utils.is.string(element)) { - utils.removeElement(player.elements[element]); - player.elements[element] = null; - } else { - utils.removeElement(element); - } - } - - // Add elements to HTML5 media (source, tracks, etc) - function insertElements(type, attributes) { - if (utils.is.string(attributes)) { - utils.insertElement(type, player.media, { - src: attributes, - }); - } else if (utils.is.array(attributes)) { - warn(attributes); - - attributes.forEach(function(attribute) { - utils.insertElement(type, player.media, attribute); - }); - } - } - - // Webkit polyfill for lower fill range - function updateRangeFill(range) { - // WebKit only - if (!player.browser.isWebkit) { - return; - } - - // Get target from event - if (utils.is.event(range)) { - range = range.target; - } - - // Needs to be a valid <input type='range'> - if (!utils.is.htmlElement(range) || range.getAttribute('type') !== 'range') { - return; - } - - // Inject the stylesheet if needed - if (!utils.is.htmlElement(player.elements.styleSheet)) { - player.elements.styleSheet = utils.createElement('style'); - player.elements.container.appendChild(player.elements.styleSheet); - } - - var styleSheet = player.elements.styleSheet.sheet; - var percentage = range.value / range.max * 100; - var selector = '#' + range.id + '::-webkit-slider-runnable-track'; - var styles = - '{ background-image: linear-gradient(to right, currentColor ' + - percentage + - '%, transparent ' + - percentage + - '%) }'; - var index = -1; - - // Find old rule if it exists - [].some.call(styleSheet.rules, function(rule, i) { - if (rule.selectorText === selector) { - index = i; - return true; - } - })[0]; - - // Remove old rule - if (index !== -1) { - styleSheet.deleteRule(index); - } - - // Insert new one - styleSheet.insertRule([selector, styles].join(' ')); - } - - // Get icon URL - function getIconUrl() { - return { - url: player.config.iconUrl, - absolute: player.config.iconUrl.indexOf('http') === 0 || player.browser.isIE, - }; - } - - // Create <svg> icon - function createIcon(type, attributes) { - var namespace = 'http://www.w3.org/2000/svg'; - var iconUrl = getIconUrl(); - var iconPath = (!iconUrl.absolute ? iconUrl.url : '') + '#' + player.config.iconPrefix; - - // Create <svg> - var icon = document.createElementNS(namespace, 'svg'); - utils.setAttributes( - icon, - utils.extend(attributes, { - role: 'presentation', - }) - ); - - // Create the <use> to reference sprite - var use = document.createElementNS(namespace, 'use'); - use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', iconPath + '-' + type); - - // Add <use> to <svg> - icon.appendChild(use); - - return icon; - } - - // Create hidden text label - function createLabel(type) { - var text = player.config.i18n[type]; - - switch (type) { - case 'pip': - text = 'PIP'; - break; - - case 'airplay': - text = 'AirPlay'; - break; - } - - return utils.createElement( - 'span', - { - class: player.config.classNames.hidden, - }, - text - ); - } - - // Create a badge - function createBadge(text) { - var badge = utils.createElement('span', { - class: player.config.classNames.menu.value, - }); - - badge.appendChild( - utils.createElement( - 'span', - { - class: player.config.classNames.menu.badge, - }, - text - ) - ); - - return badge; - } - - // Create a <button> - function createButton(type, attributes) { - var button = utils.createElement('button'); - var iconDefault; - var iconToggled; - var labelKey; - - if (!utils.is.object(attributes)) { - attributes = {}; - } - - if (!('type' in attributes)) { - attributes.type = 'button'; - } - - if ('class' in attributes) { - if (attributes.class.indexOf(player.config.classNames.control) === -1) { - attributes.class += ' ' + player.config.classNames.control; - } - } else { - attributes.class = player.config.classNames.control; - } - - // Large play button - switch (type) { - case 'mute': - labelKey = 'toggleMute'; - iconDefault = 'volume'; - iconToggled = 'muted'; - break; - - case 'captions': - labelKey = 'toggleCaptions'; - iconDefault = 'captions-off'; - iconToggled = 'captions-on'; - break; - - case 'fullscreen': - labelKey = 'toggleFullscreen'; - iconDefault = 'enter-fullscreen'; - iconToggled = 'exit-fullscreen'; - break; - - case 'play-large': - attributes.class = 'plyr__play-large'; - type = 'play'; - labelKey = 'play'; - iconDefault = 'play'; - break; - - default: - labelKey = type; - iconDefault = type; - } - - // Merge attributes - utils.extend( - attributes, - utils.getAttributesFromSelector(player.config.selectors.buttons[type], attributes) - ); - - // Add toggle icon if needed - if (utils.is.string(iconToggled)) { - button.appendChild( - createIcon(iconToggled, { - class: 'icon--' + iconToggled, - }) - ); - } - - button.appendChild(createIcon(iconDefault)); - button.appendChild(createLabel(labelKey)); - - utils.setAttributes(button, attributes); - - player.elements.buttons[type] = button; - - return button; - } - - // Create an <input type='range'> - function createRange(type, attributes) { - // Seek label - var label = utils.createElement( - 'label', - { - for: attributes.id, - class: player.config.classNames.hidden, - }, - player.config.i18n[type] - ); - - // Seek input - var input = utils.createElement( - 'input', - utils.extend( - utils.getAttributesFromSelector(player.config.selectors.inputs[type]), - { - type: 'range', - min: 0, - max: 100, - step: 0.01, - value: 0, - autocomplete: 'off', - }, - attributes - ) - ); - - player.elements.inputs[type] = input; - - return { - label: label, - input: input, - }; - } - - // Create a <progress> - function createProgress(type, attributes) { - var progress = utils.createElement( - 'progress', - utils.extend( - utils.getAttributesFromSelector(player.config.selectors.display[type]), - { - min: 0, - max: 100, - value: 0, - }, - attributes - ) - ); - - // Create the label inside - if (type !== 'volume') { - progress.appendChild(utils.createElement('span', null, '0')); - - var suffix = ''; - switch (type) { - case 'played': - suffix = player.config.i18n.played; - break; - - case 'buffer': - suffix = player.config.i18n.buffered; - break; - } - - progress.textContent = '% ' + suffix.toLowerCase(); - } - - player.elements.display[type] = progress; - - return progress; - } - - // Create time display - function createTime(type) { - var container = utils.createElement('span', { - class: 'plyr__time', - }); - - container.appendChild( - utils.createElement( - 'span', - { - class: player.config.classNames.hidden, - }, - player.config.i18n[type] - ) - ); - - container.appendChild( - utils.createElement( - 'span', - utils.getAttributesFromSelector(player.config.selectors.display[type]), - '00:00' - ) - ); - - player.elements.display[type] = container; - - return container; - } - - // Build the default HTML - // TODO: Set order based on order in the config.controls array? - function createControls(data) { - // Do nothing if we want no controls - if (utils.is.empty(player.config.controls)) { - return; - } - - // Create the container - var controls = utils.createElement( - 'div', - utils.getAttributesFromSelector(player.config.selectors.controls.wrapper) - ); - - // Restart button - if (utils.inArray(player.config.controls, 'restart')) { - controls.appendChild(createButton('restart')); - } - - // Rewind button - if (utils.inArray(player.config.controls, 'rewind')) { - controls.appendChild(createButton('rewind')); - } - - // Play Pause button - if (utils.inArray(player.config.controls, 'play')) { - controls.appendChild(createButton('play')); - controls.appendChild(createButton('pause')); - } - - // Fast forward button - if (utils.inArray(player.config.controls, 'fast-forward')) { - controls.appendChild(createButton('fast-forward')); - } - - // Progress - if (utils.inArray(player.config.controls, 'progress')) { - var container = utils.createElement( - 'span', - utils.getAttributesFromSelector(player.config.selectors.progress) - ); - - // Seek range slider - var seek = createRange('seek', { - id: 'plyr-seek-' + data.id, - }); - container.appendChild(seek.label); - container.appendChild(seek.input); - - // Buffer progress - container.appendChild(createProgress('buffer')); - - // TODO: Add loop display indicator - - // Seek tooltip - if (player.config.tooltips.seek) { - var tooltip = utils.createElement( - 'span', - { - role: 'tooltip', - class: player.config.classNames.tooltip, - }, - '00:00' - ); - - container.appendChild(tooltip); - player.elements.display.seekTooltip = tooltip; - } - - player.elements.progress = container; - controls.appendChild(player.elements.progress); - } - - // Media current time display - if (utils.inArray(player.config.controls, 'current-time')) { - controls.appendChild(createTime('currentTime')); - } - - // Media duration display - if (utils.inArray(player.config.controls, 'duration')) { - controls.appendChild(createTime('duration')); - } - - // Toggle mute button - if (utils.inArray(player.config.controls, 'mute')) { - controls.appendChild(createButton('mute')); - } - - // Volume range control - if (utils.inArray(player.config.controls, 'volume')) { - var volume = utils.createElement('span', { - class: 'plyr__volume', - }); - - // Set the attributes - var attributes = { - max: 1, - step: 0.05, - value: player.config.volume, - }; - - // Create the volume range slider - var range = createRange( - 'volume', - utils.extend(attributes, { - id: 'plyr-volume-' + data.id, - }) - ); - volume.appendChild(range.label); - volume.appendChild(range.input); - - controls.appendChild(volume); - } - - // Toggle captions button - if (utils.inArray(player.config.controls, 'captions')) { - controls.appendChild(createButton('captions')); - } - - // Settings button / menu - if (utils.inArray(player.config.controls, 'settings') && !utils.is.empty(player.config.settings)) { - var menu = utils.createElement('div', { - class: 'plyr__menu', - }); - - menu.appendChild( - createButton('settings', { - id: 'plyr-settings-toggle-' + data.id, - 'aria-haspopup': true, - 'aria-controls': 'plyr-settings-' + data.id, - 'aria-expanded': false, - }) - ); - - var form = utils.createElement('form', { - class: 'plyr__menu__container', - id: 'plyr-settings-' + data.id, - 'aria-hidden': true, - 'aria-labelled-by': 'plyr-settings-toggle-' + data.id, - role: 'tablist', - tabindex: -1, - }); - - var inner = utils.createElement('div'); - - var home = utils.createElement('div', { - id: 'plyr-settings-' + data.id + '-home', - 'aria-hidden': false, - 'aria-labelled-by': 'plyr-settings-toggle-' + data.id, - role: 'tabpanel', - }); - - // Create the tab list - var tabs = utils.createElement('ul', { - role: 'tablist', - }); - - // Build the tabs - player.config.settings.forEach(function(type) { - var tab = utils.createElement('li', { - role: 'tab', - hidden: '', - }); - - var button = utils.createElement( - 'button', - utils.extend(utils.getAttributesFromSelector(player.config.selectors.buttons.settings), { - type: 'button', - class: - player.config.classNames.control + ' ' + player.config.classNames.control + '--forward', - id: 'plyr-settings-' + data.id + '-' + type + '-tab', - 'aria-haspopup': true, - 'aria-controls': 'plyr-settings-' + data.id + '-' + type, - 'aria-expanded': false, - }), - player.config.i18n[type] - ); - - var value = utils.createElement('span', { - class: player.config.classNames.menu.value, - }); - - // Speed contains HTML entities - value.innerHTML = data[type]; - - button.appendChild(value); - tab.appendChild(button); - tabs.appendChild(tab); - - player.elements.settings.tabs[type] = tab; - }); - - home.appendChild(tabs); - inner.appendChild(home); - - // Build the panes - player.config.settings.forEach(function(type) { - var pane = utils.createElement('div', { - id: 'plyr-settings-' + data.id + '-' + type, - 'aria-hidden': true, - 'aria-labelled-by': 'plyr-settings-' + data.id + '-' + type + '-tab', - role: 'tabpanel', - tabindex: -1, - hidden: '', - }); - - var back = utils.createElement( - 'button', - { - type: 'button', - class: player.config.classNames.control + ' ' + player.config.classNames.control + '--back', - 'aria-haspopup': true, - 'aria-controls': 'plyr-settings-' + data.id + '-home', - 'aria-expanded': false, - }, - player.config.i18n[type] - ); - - pane.appendChild(back); - - var options = utils.createElement('ul'); - - pane.appendChild(options); - inner.appendChild(pane); - - player.elements.settings.panes[type] = pane; - }); - - form.appendChild(inner); - menu.appendChild(form); - controls.appendChild(menu); - - player.elements.settings.form = form; - player.elements.settings.menu = menu; - } - - // Picture in picture button - if (utils.inArray(player.config.controls, 'pip') && support.pip) { - controls.appendChild(createButton('pip')); - } - - // Airplay button - if (utils.inArray(player.config.controls, 'airplay') && support.airplay) { - controls.appendChild(createButton('airplay')); - } - - // Toggle fullscreen button - if (utils.inArray(player.config.controls, 'fullscreen')) { - controls.appendChild(createButton('fullscreen')); - } - - // Larger overlaid play button - if (utils.inArray(player.config.controls, 'play-large')) { - player.elements.buttons.playLarge = createButton('play-large'); - player.elements.container.appendChild(player.elements.buttons.playLarge); - } - - player.elements.controls = controls; - - //setLoopMenu(); - if (utils.inArray(player.config.controls, 'settings') && utils.inArray(player.config.settings, 'speed')) { - setSpeedMenu(); - } - - return controls; - } - - // Hide/show a tab - function toggleTab(setting, toggle) { - var tab = player.elements.settings.tabs[setting]; - var pane = player.elements.settings.panes[setting]; - - if (utils.is.htmlElement(tab)) { - if (toggle) { - tab.removeAttribute('hidden'); - } else { - tab.setAttribute('hidden', ''); - } - } - - if (utils.is.htmlElement(pane)) { - if (toggle) { - pane.removeAttribute('hidden'); - } else { - pane.setAttribute('hidden', ''); - } - } - } - - // Set the YouTube quality menu - // TODO: Support for HTML5 - function setQualityMenu(options, selected) { - var list = player.elements.settings.panes.quality.querySelector('ul'); - - // Set options if passed and filter based on config - if (utils.is.array(options)) { - player.quality.options = options.filter(function(quality) { - return utils.inArray(player.config.quality.options, quality); - }); - } else { - player.quality.options = player.config.quality.options; - } - - // Set selected if passed - if (utils.is.string(selected) && utils.inArray(player.quality.options, selected)) { - player.quality.selected = selected; - } - - // Toggle the pane and tab - var toggle = !utils.is.empty(player.quality.options) && player.type === 'youtube'; - toggleTab('quality', toggle); - - // If we're hiding, nothing more to do - if (!toggle) { - return; - } - - // Empty the menu - utils.emptyElement(list); - - // Get the badge HTML for HD, 4K etc - function getBadge(quality) { - var label = ''; - - switch (quality) { - case 'hd2160': - label = '4K'; - break; - case 'hd1440': - label = 'WQHD'; - break; - case 'hd1080': - label = 'HD'; - break; - case 'hd720': - label = 'HD'; - break; - } - - if (!label.length) { - return null; - } - - return createBadge(label); - } - - player.quality.options.forEach(function(quality) { - var item = utils.createElement('li'); - - var label = utils.createElement('label', { - class: player.config.classNames.control, - }); - - var radio = utils.createElement( - 'input', - utils.extend(utils.getAttributesFromSelector(player.config.selectors.inputs.quality), { - type: 'radio', - name: 'plyr-quality', - value: quality, - }) - ); - - label.appendChild(radio); - label.appendChild(document.createTextNode(getLabel('quality', quality))); - - var badge = getBadge(quality); - if (utils.is.htmlElement(badge)) { - label.appendChild(badge); - } - - item.appendChild(label); - list.appendChild(item); - }); - - updateSetting('quality', list); - } - - // Translate a value into a nice label - // TODO: Localisation - function getLabel(setting, value) { - switch (setting) { - case 'speed': - return value === 1 ? 'Normal' : value + '×'; - - case 'quality': - switch (value) { - case 'hd2160': - return '2160P'; - case 'hd1440': - return '1440P'; - case 'hd1080': - return '1080P'; - case 'hd720': - return '720P'; - case 'large': - return '480P'; - case 'medium': - return '360P'; - case 'small': - return '240P'; - case 'tiny': - return 'Tiny'; - case 'default': - return 'Auto'; - default: - return value; - } - - case 'captions': - return getLanguage(); - } - } - - // Update the selected setting - function updateSetting(setting, list) { - var pane = player.elements.settings.panes[setting]; - var value = null; - - switch (setting) { - case 'captions': - value = player.captions.language; - - if (!player.captions.enabled) { - value = ''; - } - - break; - - default: - value = player[setting].selected; - - if (utils.is.empty(value)) { - value = player.config[setting].default; - } - - // Unsupported value - if (!utils.inArray(player[setting].options, value)) { - warn('Unsupported option'); - return; - } - - break; - } - - // Get the list if we need to - if (!utils.is.htmlElement(list)) { - list = pane && pane.querySelector('ul'); - } - - // Find the radio option - var target = list && list.querySelector('input[value="' + value + '"]'); - - if (!utils.is.htmlElement(target)) { - return; - } - - // Check it - target.checked = true; - - // Find the label - var label = player.elements.settings.tabs[setting].querySelector('.' + player.config.classNames.menu.value); - label.innerHTML = getLabel(setting, value); - } - - // Set the looping options - /*function setLoopMenu() { - var options = ['start', 'end', 'all', 'reset']; - var list = player.elements.settings.panes.loop.querySelector('ul'); - - // Show the pane and tab - player.elements.settings.tabs.loop.removeAttribute('hidden'); - player.elements.settings.panes.loop.removeAttribute('hidden'); - - // Toggle the pane and tab - var toggle = !utils.is.empty(player.loop.options); - toggleTab('loop', toggle); - - // Empty the menu - utils.emptyElement(list); - - options.forEach(function(option) { - var item = utils.createElement('li'); - - var button = utils.createElement( - 'button', - utils.extend(utils.getAttributesFromSelector(player.config.selectors.buttons.loop), { - type: 'button', - class: player.config.classNames.control, - 'data-plyr-loop-action': option - }), - player.config.i18n[option] - ); - - if (utils.inArray(['start', 'end'], option)) { - var badge = createBadge('00:00'); - button.appendChild(badge); - } - - item.appendChild(button); - list.appendChild(item); - }); - }*/ - - // Set a list of available captions languages - function setCaptionsMenu() { - var list = player.elements.settings.panes.captions.querySelector('ul'); - - // Toggle the pane and tab - var toggle = !utils.is.empty(player.captions.tracks); - toggleTab('captions', toggle); - - // Empty the menu - utils.emptyElement(list); - - // If there's no captions, bail - if (utils.is.empty(player.captions.tracks)) { - return; - } - - // Re-map the tracks into just the data we need - var tracks = [].map.call(player.captions.tracks, function(track) { - return { - language: track.language, - badge: true, - label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(), - }; - }); - - // Add the "None" option to turn off captions - tracks.unshift({ - language: '', - label: player.config.i18n.none, - }); - - // Generate options - tracks.forEach(function(track) { - var item = utils.createElement('li'); - - var label = utils.createElement('label', { - class: player.config.classNames.control, - }); - - var radio = utils.createElement( - 'input', - utils.extend(utils.getAttributesFromSelector(player.config.selectors.inputs.language), { - type: 'radio', - name: 'plyr-language', - value: track.language, - }) - ); - - if (track.language.toLowerCase() === player.captions.language.toLowerCase()) { - radio.checked = true; - } - - label.appendChild(radio); - label.appendChild(document.createTextNode(track.label || track.language)); - - if (track.badge) { - label.appendChild(createBadge(track.language.toUpperCase())); - } - - item.appendChild(label); - list.appendChild(item); - }); - - updateSetting('captions', list); - } - - // Set a list of available captions languages - function setSpeedMenu(options, selected) { - // Set options if passed and filter based on config - if (utils.is.array(options)) { - player.speed.options = options.filter(function(speed) { - return utils.inArray(player.config.speed.options, speed); - }); - } else { - player.speed.options = player.config.speed.options; - } - - // Set selected if passed - if (utils.is.number(selected) && utils.inArray(player.speed.options, selected)) { - player.speed.selected = selected; - } - - // Toggle the pane and tab - var toggle = !utils.is.empty(player.speed.options); - toggleTab('speed', toggle); - - // If we're hiding, nothing more to do - if (!toggle) { - return; - } - - // Get the list to populate - var list = player.elements.settings.panes.speed.querySelector('ul'); - - // Show the pane and tab - player.elements.settings.tabs.speed.removeAttribute('hidden'); - player.elements.settings.panes.speed.removeAttribute('hidden'); - - // Empty the menu - utils.emptyElement(list); - - // Create items - player.speed.options.forEach(function(speed) { - var item = utils.createElement('li'); - - var label = utils.createElement('label', { - class: player.config.classNames.control, - }); - - var radio = utils.createElement( - 'input', - utils.extend(utils.getAttributesFromSelector(player.config.selectors.inputs.speed), { - type: 'radio', - name: 'plyr-speed', - value: speed, - }) - ); - - label.appendChild(radio); - label.insertAdjacentHTML('beforeend', getLabel('speed', speed)); - item.appendChild(label); - list.appendChild(item); - }); - - updateSetting('speed', list); - } - - // Setup fullscreen - function setupFullscreen() { - if (!player.supported.ui || player.type === 'audio' || !player.config.fullscreen.enabled) { - return; - } - - // Check for native support - var nativeSupport = support.fullscreen; - - if (nativeSupport || (player.config.fullscreen.fallback && !utils.inFrame())) { - log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled'); - - // Add styling hook to show button - utils.toggleClass(player.elements.container, player.config.classNames.fullscreen.enabled, true); - } else { - log('Fullscreen not supported and fallback disabled'); - } - - // Toggle state - if (player.elements.buttons && player.elements.buttons.fullscreen) { - utils.toggleState(player.elements.buttons.fullscreen, false); - } - - // Trap focus in container - trapFocus(); - } - - // Setup captions - function setupCaptions() { - // Requires UI support - if (!player.supported.ui) { - return; - } - - // Set default language if not set - if (!utils.is.empty(player.storage.language)) { - player.captions.language = player.storage.language; - } else if (utils.is.empty(player.captions.language)) { - player.captions.language = player.config.captions.language.toLowerCase(); - } - - // Set captions enabled state if not set - if (!utils.is.boolean(player.captions.enabled)) { - if (!utils.is.empty(player.storage.language)) { - player.captions.enabled = player.storage.captions; - } else { - player.captions.enabled = player.config.captions.active; - } - } - - // Only Vimeo and HTML5 video supported at this point - if (!utils.inArray(['video', 'vimeo'], player.type) || (player.type === 'video' && !support.textTracks)) { - player.captions.tracks = null; - - // Clear menu and hide - if ( - utils.inArray(player.config.controls, 'settings') && - utils.inArray(player.config.settings, 'captions') - ) { - setCaptionsMenu(); - } - - return; - } - - // Inject the container - if (!utils.is.htmlElement(player.elements.captions)) { - player.elements.captions = utils.createElement( - 'div', - utils.getAttributesFromSelector(player.config.selectors.captions) - ); - utils.insertAfter(player.elements.captions, player.elements.wrapper); - } - - // Get tracks - if (player.type === 'video') { - player.captions.tracks = player.media.textTracks; - } - - // Set the class hook - utils.toggleClass( - player.elements.container, - player.config.classNames.captions.enabled, - !utils.is.empty(player.captions.tracks) - ); - - // If no caption file exists, hide container for caption text - if (utils.is.empty(player.captions.tracks)) { - return; - } - - // Enable UI - showCaptions(); - - // Get a track - function setCurrentTrack() { - // Reset by default - player.captions.currentTrack = null; - - // Filter doesn't seem to work for a TextTrackList :-( - [].forEach.call(player.captions.tracks, function(track) { - if (track.language === player.captions.language.toLowerCase()) { - player.captions.currentTrack = track; - } - }); - } - - // Get current track - setCurrentTrack(); - - // If we couldn't get the requested language, revert to default - if (!utils.is.track(player.captions.currentTrack)) { - var language = player.config.captions.language; - - // Reset to default - // We don't update user storage as the selected language could become available - player.captions.language = language; - - // Get fallback track - setCurrentTrack(); - - // If no match, disable captions - if (!utils.is.track(player.captions.currentTrack)) { - player.toggleCaptions(false); - } - - updateSetting('captions'); - } - - // Setup HTML5 track rendering - if (player.type === 'video') { - // Turn off native caption rendering to avoid double captions - [].forEach.call(player.captions.tracks, function(track) { - // Remove previous bindings (if we've changed source or language) - utils.off(track, 'cuechange', setActiveCue); - - // Hide captions - track.mode = 'hidden'; - }); - - // Check if suported kind - var supported = utils.inArray( - ['captions', 'subtitles'], - player.captions.currentTrack && player.captions.currentTrack.kind - ); - - if (utils.is.track(player.captions.currentTrack) && supported) { - utils.on(player.captions.currentTrack, 'cuechange', setActiveCue); - - // If we change the active track while a cue is already displayed we need to update it - if (player.captions.currentTrack.activeCues && player.captions.currentTrack.activeCues.length > 0) { - setActiveCue(player.captions.currentTrack); - } - } - } else if (player.type === 'vimeo' && player.captions.active) { - player.embed.enableTextTrack(player.captions.language); - } - - // Set available languages in list - if ( - utils.inArray(player.config.controls, 'settings') && - utils.inArray(player.config.settings, 'captions') - ) { - setCaptionsMenu(); - } - } - - // Get current selected caption language - function getLanguage() { - if (!player.supported.ui) { - return null; - } - - if (!support.textTracks || utils.is.empty(player.captions.tracks)) { - return player.config.i18n.none; - } - - if (player.captions.enabled) { - return player.captions.currentTrack.label; - } else { - return player.config.i18n.disabled; - } - } - - // Display active caption if it contains text - function setActiveCue(track) { - // Get the track from the event if needed - if (utils.is.event(track)) { - track = track.target; - } - - var active = track.activeCues[0]; - - // Display a cue, if there is one - if (utils.is.cue(active)) { - setCaption(active.getCueAsHTML()); - } else { - setCaption(); - } - - trigger(player.media, 'cuechange'); - } - - // Set the current caption - function setCaption(caption) { - // Requires UI - if (!player.supported.ui) { - return; - } - - if (utils.is.htmlElement(player.elements.captions)) { - var content = utils.createElement('span'); - - // Empty the container - utils.emptyElement(player.elements.captions); - - // Default to empty - if (utils.is.undefined(caption)) { - caption = ''; - } - - // Set the span content - if (utils.is.string(caption)) { - content.textContent = caption.trim(); - } else { - content.appendChild(caption); - } - - // Set new caption text - player.elements.captions.appendChild(content); - } else { - warn('No captions element to render to'); - } - } - - // Display captions container and button (for initialization) - function showCaptions() { - // If there's no caption toggle, bail - if (!player.elements.buttons.captions) { - return; - } - - // Try to load the value from storage - var active = player.storage.captions; - - // Otherwise fall back to the default config - if (!utils.is.boolean(active)) { - active = player.captions.active; - } else { - player.captions.active = active; - } - - if (active) { - utils.toggleClass(player.elements.container, player.config.classNames.captions.active, true); - utils.toggleState(player.elements.buttons.captions, true); - } - } - - // Insert controls - function injectControls() { - // Sprite - if (player.config.loadSprite) { - var iconUrl = getIconUrl(); - - // Only load external sprite using AJAX - if (iconUrl.absolute) { - log('AJAX loading absolute SVG sprite' + (player.browser.isIE ? ' (due to IE)' : '')); - utils.loadSprite(iconUrl.url, 'sprite-plyr'); - } else { - log('Sprite will be used as external resource directly'); - } - } - - // Create a unique ID - player.id = Math.floor(Math.random() * 10000); - - // Null by default - var controls = null; - - // HTML passed as the option - if (utils.is.string(player.config.controls)) { - controls = player.config.controls; - } else if (utils.is.function(player.config.controls)) { - // A custom function to build controls - // The function can return a HTMLElement or String - controls = player.config.controls({ - id: player.id, - seektime: player.config.seekTime, - }); - } else { - // Create controls - controls = createControls({ - id: player.id, - seektime: player.config.seekTime, - speed: '-', - // TODO: Get current quality - quality: '-', - captions: getLanguage(), - // TODO: Get loop - loop: 'None', - }); - } - - // Controls container - var target; - - // Inject to custom location - if (utils.is.string(player.config.selectors.controls.container)) { - target = document.querySelector(player.config.selectors.controls.container); - } - - // Inject into the container by default - if (!utils.is.htmlElement(target)) { - target = player.elements.container; - } - - // Inject controls HTML - if (utils.is.htmlElement(controls)) { - target.appendChild(controls); - } else { - target.insertAdjacentHTML('beforeend', controls); - } - - // Find the elements if need be - if (utils.is.htmlElement(player.elements.controls)) { - findElements(); - } - - // Setup tooltips - if (player.config.tooltips.controls) { - var labels = getElements( - [ - player.config.selectors.controls.wrapper, - ' ', - player.config.selectors.labels, - ' .', - player.config.classNames.hidden, - ].join('') - ); - - for (var i = labels.length - 1; i >= 0; i--) { - var label = labels[i]; - - utils.toggleClass(label, player.config.classNames.hidden, false); - utils.toggleClass(label, player.config.classNames.tooltip, true); - } - } - } - - // Find the UI controls and store references in custom controls - // TODO: Allow settings menus with custom controls - function findElements() { - try { - player.elements.controls = getElement(player.config.selectors.controls.wrapper); - - // Buttons - player.elements.buttons = { - play: getElements(player.config.selectors.buttons.play), - pause: getElement(player.config.selectors.buttons.pause), - restart: getElement(player.config.selectors.buttons.restart), - rewind: getElement(player.config.selectors.buttons.rewind), - forward: getElement(player.config.selectors.buttons.forward), - mute: getElement(player.config.selectors.buttons.mute), - pip: getElement(player.config.selectors.buttons.pip), - airplay: getElement(player.config.selectors.buttons.airplay), - settings: getElement(player.config.selectors.buttons.settings), - captions: getElement(player.config.selectors.buttons.captions), - fullscreen: getElement(player.config.selectors.buttons.fullscreen), - }; - - // Progress - player.elements.progress = getElement(player.config.selectors.progress); - - // Inputs - player.elements.inputs = { - seek: getElement(player.config.selectors.inputs.seek), - volume: getElement(player.config.selectors.inputs.volume), - }; - - // Display - player.elements.display = { - buffer: getElement(player.config.selectors.display.buffer), - duration: getElement(player.config.selectors.display.duration), - currentTime: getElement(player.config.selectors.display.currentTime), - }; - - // Seek tooltip - if (utils.is.htmlElement(player.elements.progress)) { - player.elements.display.seekTooltip = player.elements.progress.querySelector( - '.' + player.config.classNames.tooltip - ); - } - - return true; - } catch (error) { - // Log it - warn('It looks like there is a problem with your custom controls HTML', error); - - // Restore native video controls - toggleNativeControls(true); - - return false; - } - } - - // Toggle style hook - function addStyleHook() { - utils.toggleClass( - player.elements.container, - player.config.selectors.container.replace('.', ''), - true - ); - - utils.toggleClass( - player.elements.container, - player.config.classNames.uiSupported, - player.supported.ui - ); - } - - // Toggle native HTML5 media controls - function toggleNativeControls(toggle) { - if (toggle && utils.inArray(types.html5, player.type)) { - player.media.setAttribute('controls', ''); - } else { - player.media.removeAttribute('controls'); - } - } - - // Setup aria attribute for play and iframe title - function setTitle(iframe) { - // Find the current text - var label = player.config.i18n.play; + this.log('Config', this.config); + this.log('Support', support); - // If there's a media title set, use that for the label - if (utils.is.string(player.config.title) && !utils.is.empty(player.config.title)) { - label += ', ' + player.config.title; - - // Set container label - player.elements.container.setAttribute('aria-label', player.config.title); - } - - // If there's a play button, set label - if (player.supported.ui) { - if (utils.is.htmlElement(player.elements.buttons.play)) { - player.elements.buttons.play.setAttribute('aria-label', label); - } - if (utils.is.htmlElement(player.elements.buttons.playLarge)) { - player.elements.buttons.playLarge.setAttribute('aria-label', label); - } - } - - // Set iframe title - // https://github.com/sampotts/plyr/issues/124 - if (utils.is.htmlElement(iframe)) { - var title = - utils.is.string(player.config.title) && !utils.is.empty(player.config.title) - ? player.config.title - : 'video'; - iframe.setAttribute('title', player.config.i18n.frameTitle.replace('{title}', title)); - } - } - - // Setup localStorage - function setupStorage() { - var value = null; - player.storage = {}; - - // Bail if we don't have localStorage support or it's disabled - if (!support.storage || !player.config.storage.enabled) { - return; - } - - // Clean up old volume - // https://github.com/sampotts/plyr/issues/171 - window.localStorage.removeItem('plyr-volume'); - - // load value from the current key - value = window.localStorage.getItem(player.config.storage.key); - - if (!value) { - // Key wasn't set (or had been cleared), move along - return; - } else if (/^\d+(\.\d+)?$/.test(value)) { - // If value is a number, it's probably volume from an older - // version of player. See: https://github.com/sampotts/plyr/pull/313 - // Update the key to be JSON - updateStorage({ - volume: parseFloat(value), - }); - } else { - // Assume it's JSON from this or a later version of plyr - player.storage = JSON.parse(value); - } - } - - // Save a value back to local storage - function updateStorage(value) { - // Bail if we don't have localStorage support or it's disabled - if (!support.storage || !player.config.storage.enabled) { - return; - } - - // Update the working copy of the values - utils.extend(player.storage, value); - - // Update storage - window.localStorage.setItem(player.config.storage.key, JSON.stringify(player.storage)); - } - - // Setup media - function setupMedia() { - // If there's no media, bail - if (!player.media) { - warn('No media element found!'); - return; - } - - // Add type class - utils.toggleClass( - player.elements.container, - player.config.classNames.type.replace('{0}', player.type), - true - ); - - // Add video class for embeds - // This will require changes if audio embeds are added - if (utils.inArray(types.embed, player.type)) { - utils.toggleClass( - player.elements.container, - player.config.classNames.type.replace('{0}', 'video'), - true - ); - } - - if (player.supported.ui) { - // Check for picture-in-picture support - utils.toggleClass( - player.elements.container, - player.config.classNames.pip.supported, - support.pip && player.type === 'video' - ); - - // Check for airplay support - utils.toggleClass( - player.elements.container, - player.config.classNames.airplay.supported, - support.airplay && utils.inArray(types.html5, player.type) - ); - - // If there's no autoplay attribute, assume the video is stopped and add state class - utils.toggleClass(player.elements.container, player.config.classNames.stopped, player.config.autoplay); - - // Add iOS class - utils.toggleClass(player.elements.container, player.config.classNames.isIos, player.browser.isIos); - - // Add touch class - utils.toggleClass(player.elements.container, player.config.classNames.isTouch, support.touch); - } - - // Inject the player wrapper - if (utils.inArray(['video', 'youtube', 'vimeo'], player.type)) { - // Create the wrapper div - player.elements.wrapper = utils.createElement('div', { - class: player.config.classNames.video, - }); - - // Wrap the video in a container - utils.wrap(player.media, player.elements.wrapper); - } - - // Embeds - if (utils.inArray(types.embed, player.type)) { - setupEmbed(); - } - } - - // Setup YouTube/Vimeo - function setupEmbed() { - var mediaId; - var id = player.type + '-' + Math.floor(Math.random() * 10000); - - // Parse IDs from URLs if supplied - switch (player.type) { - case 'youtube': - mediaId = utils.parseYouTubeId(player.embedId); - break; - - default: - mediaId = player.embedId; - } - - // Remove old containers - var containers = getElements('[id^="' + player.type + '-"]'); - for (var i = containers.length - 1; i >= 0; i--) { - utils.removeElement(containers[i]); - } - - // Add embed class for responsive - utils.toggleClass(player.elements.wrapper, player.config.classNames.embed, true); - - if (player.type === 'youtube') { - // Set ID - player.media.setAttribute('id', id); - - // Setup API - if (utils.is.object(window.YT)) { - youTubeReady(mediaId); - } else { - // Load the API - utils.injectScript(player.config.urls.youtube.api); - - // Setup callback for the API - window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || []; - - // Add to queue - window.onYouTubeReadyCallbacks.push(function() { - youTubeReady(mediaId); - }); - - // Set callback to process queue - window.onYouTubeIframeAPIReady = function() { - window.onYouTubeReadyCallbacks.forEach(function(callback) { - callback(); - }); - }; - } - } else if (player.type === 'vimeo') { - // Set ID - player.media.setAttribute('id', id); - - // Load the API if not already - if (!utils.is.object(window.Vimeo)) { - utils.injectScript(player.config.urls.vimeo.api); - - // Wait for fragaloop load - var vimeoTimer = window.setInterval(function() { - if (utils.is.object(window.Vimeo)) { - window.clearInterval(vimeoTimer); - vimeoReady(mediaId); - } - }, 50); - } else { - vimeoReady(mediaId); - } - } else if (player.type === 'soundcloud') { - // TODO: Currently unsupported and undocumented - // Inject the iframe - var soundCloud = utils.createElement('iframe'); - - // Watch for iframe load - soundCloud.loaded = false; - utils.on(soundCloud, 'load', function() { - soundCloud.loaded = true; - }); - - utils.setAttributes(soundCloud, { - src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/' + mediaId, - id: id, - }); - - player.media.appendChild(soundCloud); - - // Load the API if not already - if (!window.SC) { - utils.injectScript(player.config.urls.soundcloud.api); - } - - // Wait for SC load - var soundCloudTimer = window.setInterval(function() { - if (window.SC && soundCloud.loaded) { - window.clearInterval(soundCloudTimer); - soundcloudReady.call(soundCloud); - } - }, 50); - } - } - - // When embeds are ready - function embedReady() { - // Setup the UI and call ready if full support - if (player.supported.ui) { - setupInterface(); - ready(); - } - - // Set title - setTitle(getElement('iframe')); - } - - // Handle YouTube API ready - function youTubeReady(videoId) { - // Setup instance - // https://developers.google.com/youtube/iframe_api_reference - player.embed = new window.YT.Player(player.media.id, { - videoId: videoId, - playerVars: { - autoplay: player.config.autoplay ? 1 : 0, // Autoplay - controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported - rel: 0, // No related vids - showinfo: 0, // Hide info - iv_load_policy: 3, // Hide annotations - modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused) - disablekb: 1, // Disable keyboard as we handle it - playsinline: 1, // Allow iOS inline playback - - // Tracking for stats - origin: window.location.hostname, - widget_referrer: window.location.href, - - // Captions is flaky on YouTube - //cc_load_policy: (player.captions.active ? 1 : 0), - //cc_lang_pref: 'en', - }, - events: { - onError: function(event) { - trigger(player.elements.container, 'error', true, { - code: event.data, - embed: event.target, - }); - }, - onPlaybackQualityChange: function(event) { - // Get the instance - var instance = event.target; - - // Get current quality - player.media.quality = instance.getPlaybackQuality(); - - trigger(player.media, 'qualitychange'); - }, - onPlaybackRateChange: function(event) { - // Get the instance - var instance = event.target; - - // Get current speed - player.media.playbackRate = instance.getPlaybackRate(); - - trigger(player.media, 'ratechange'); - }, - onReady: function(event) { - // Get the instance - var instance = event.target; - - // Create a faux HTML5 API using the YouTube API - player.media.play = function() { - instance.playVideo(); - player.media.paused = false; - }; - player.media.pause = function() { - instance.pauseVideo(); - player.media.paused = true; - }; - player.media.stop = function() { - instance.stopVideo(); - player.media.paused = true; - }; - player.media.duration = instance.getDuration(); - player.media.paused = true; - player.media.currentTime = 0; - player.media.muted = instance.isMuted(); - - // Get available speeds - if ( - utils.inArray(player.config.controls, 'settings') && - utils.inArray(player.config.settings, 'speed') - ) { - setSpeedMenu(instance.getAvailablePlaybackRates(), instance.getPlaybackRate()); - } - - // Set title - player.config.title = instance.getVideoData().title; - - // Set the tabindex - if (player.supported.ui) { - player.media.setAttribute('tabindex', -1); - } - - // Update UI - embedReady(); - - trigger(player.media, 'timeupdate'); - trigger(player.media, 'durationchange'); - - // Reset timer - window.clearInterval(timers.buffering); - - // Setup buffering - timers.buffering = window.setInterval(function() { - // Get loaded % from YouTube - player.media.buffered = instance.getVideoLoadedFraction(); - - // Trigger progress only when we actually buffer something - if ( - player.media.lastBuffered === null || - player.media.lastBuffered < player.media.buffered - ) { - trigger(player.media, 'progress'); - } - - // Set last buffer point - player.media.lastBuffered = player.media.buffered; - - // Bail if we're at 100% - if (player.media.buffered === 1) { - window.clearInterval(timers.buffering); - - // Trigger event - trigger(player.media, 'canplaythrough'); - } - }, 200); - }, - onStateChange: function(event) { - // Get the instance - var instance = event.target; - - // Reset timer - window.clearInterval(timers.playing); - - // Handle events - // -1 Unstarted - // 0 Ended - // 1 Playing - // 2 Paused - // 3 Buffering - // 5 Video cued - switch (event.data) { - case 0: - // YouTube doesn't support loop for a single video, so mimick it. - if (player.config.loop.active) { - // YouTube needs a call to `stopVideo` before playing again - instance.stopVideo(); - instance.playVideo(); - - break; - } - - player.media.paused = true; - - trigger(player.media, 'ended'); - - break; - - case 1: - player.media.paused = false; - - // If we were seeking, fire seeked event - if (player.media.seeking) { - trigger(player.media, 'seeked'); - } - - player.media.seeking = false; - - trigger(player.media, 'play'); - trigger(player.media, 'playing'); - - // Poll to get playback progress - timers.playing = window.setInterval(function() { - player.media.currentTime = instance.getCurrentTime(); - trigger(player.media, 'timeupdate'); - }, 100); - - // Check duration again due to YouTube bug - // https://github.com/sampotts/plyr/issues/374 - // https://code.google.com/p/gdata-issues/issues/detail?id=8690 - if (player.media.duration !== instance.getDuration()) { - player.media.duration = instance.getDuration(); - trigger(player.media, 'durationchange'); - } - - // Get quality - setQualityMenu(instance.getAvailableQualityLevels(), instance.getPlaybackQuality()); - - break; - - case 2: - player.media.paused = true; - - trigger(player.media, 'pause'); - - break; - } - - trigger(player.elements.container, 'statechange', false, { - code: event.data, - }); - }, - }, - }); + // We need an element to setup + if (this.media === null || utils.is.undefined(this.media) || !utils.is.htmlElement(this.media)) { + this.error('Setup failed: no suitable element passed'); + return; } - // Vimeo ready - function vimeoReady(mediaId) { - // Setup instance - // https://github.com/vimeo/player.js - player.embed = new window.Vimeo.Player(player.media, { - id: mediaId, - loop: player.config.loop.active, - autoplay: player.config.autoplay, - byline: false, - portrait: false, - title: false, - }); - - // Create a faux HTML5 API using the Vimeo API - player.media.play = function() { - player.embed.play(); - player.media.paused = false; - }; - player.media.pause = function() { - player.embed.pause(); - player.media.paused = true; - }; - player.media.stop = function() { - player.embed.stop(); - player.media.paused = true; - }; - - player.media.paused = true; - player.media.currentTime = 0; - - // Update UI - embedReady(); - - player.embed.getCurrentTime().then(function(value) { - player.media.currentTime = value; - trigger(player.media, 'timeupdate'); - }); - - player.embed.getDuration().then(function(value) { - player.media.duration = value; - trigger(player.media, 'durationchange'); - }); - - // Get captions - player.embed.getTextTracks().then(function(tracks) { - player.captions.tracks = tracks; - - setupCaptions(); - }); - - player.embed.on('cuechange', function(data) { - var cue = null; - - if (data.cues.length) { - cue = utils.stripHTML(data.cues[0].text); - } - - setCaption(cue); - }); - - player.embed.on('loaded', function() { - // Fix keyboard focus issues - // https://github.com/sampotts/plyr/issues/317 - if (utils.is.htmlElement(player.embed.element) && player.supported.ui) { - player.embed.element.setAttribute('tabindex', -1); - } - }); - - player.embed.on('play', function() { - player.media.paused = false; - trigger(player.media, 'play'); - trigger(player.media, 'playing'); - }); - - player.embed.on('pause', function() { - player.media.paused = true; - trigger(player.media, 'pause'); - }); - - player.embed.on('timeupdate', function(data) { - player.media.seeking = false; - player.media.currentTime = data.seconds; - trigger(player.media, 'timeupdate'); - }); - - player.embed.on('progress', function(data) { - player.media.buffered = data.percent; - trigger(player.media, 'progress'); - - if (parseInt(data.percent) === 1) { - // Trigger event - trigger(player.media, 'canplaythrough'); - } - }); - - player.embed.on('seeked', function() { - player.media.seeking = false; - trigger(player.media, 'seeked'); - trigger(player.media, 'play'); - }); - - player.embed.on('ended', function() { - player.media.paused = true; - trigger(player.media, 'ended'); - }); + // Bail if the element is initialized + if (this.media.plyr) { + this.warn('Target already setup'); + return; } - // Soundcloud ready - // TODO: Document - function soundcloudReady() { - /* jshint validthis: true */ - player.embed = window.SC.Widget(this); - - // Setup on ready - player.embed.bind(window.SC.Widget.Events.READY, function() { - // Create a faux HTML5 API using the Soundcloud API - player.media.play = function() { - player.embed.play(); - player.media.paused = false; - }; - player.media.pause = function() { - player.embed.pause(); - player.media.paused = true; - }; - player.media.stop = function() { - player.embed.seekTo(0); - player.embed.pause(); - player.media.paused = true; - }; - - player.media.paused = true; - player.media.currentTime = 0; - - player.embed.getDuration(function(value) { - player.media.duration = value / 1000; - - // Update UI - embedReady(); - }); - - player.embed.getPosition(function(value) { - player.media.currentTime = value; - trigger(player.media, 'timeupdate'); - }); - - player.embed.bind(window.SC.Widget.Events.PLAY, function() { - player.media.paused = false; - trigger(player.media, 'play'); - trigger(player.media, 'playing'); - }); - - player.embed.bind(window.SC.Widget.Events.PAUSE, function() { - player.media.paused = true; - trigger(player.media, 'pause'); - }); - - player.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS, function(data) { - player.media.seeking = false; - player.media.currentTime = data.currentPosition / 1000; - trigger(player.media, 'timeupdate'); - }); - - player.embed.bind(window.SC.Widget.Events.LOAD_PROGRESS, function(data) { - player.media.buffered = data.loadProgress; - trigger(player.media, 'progress'); - - if (parseInt(data.loadProgress) === 1) { - // Trigger event - trigger(player.media, 'canplaythrough'); - } - }); - - player.embed.bind(window.SC.Widget.Events.FINISH, function() { - player.media.paused = true; - trigger(player.media, 'ended'); - }); - }); + // Bail if not enabled + if (!this.config.enabled) { + this.error('Setup failed: disabled by config'); + return; } - // Check playing state - function checkPlaying() { - utils.toggleClass(player.elements.container, player.config.classNames.playing, !player.media.paused); - - utils.toggleClass(player.elements.container, player.config.classNames.stopped, player.media.paused); - - player.toggleControls(player.media.paused); + // Bail if disabled or no basic support + // You may want to disable certain UAs etc + if (!support.check().api) { + this.error('Setup failed: no support'); + return; } - // Show/hide menu - function toggleMenu(event) { - var form = player.elements.settings.form; - var button = player.elements.buttons.settings; - var show = utils.is.boolean(event) ? event : form && form.getAttribute('aria-hidden') === 'true'; + // Cache original element state for .destroy() + this.elements.original = this.media.cloneNode(true); - if (utils.is.event(event)) { - var isMenuItem = form && form.contains(event.target); - var isButton = event.target === player.elements.buttons.settings; + // Set media type based on tag or data attribute + // Supported: video, audio, vimeo, youtube + const type = this.media.tagName.toLowerCase(); - // If the click was inside the form or if the click - // wasn't the button or menu item and we're trying to - // show the menu (a doc click shouldn't show the menu) - if (isMenuItem || (!isMenuItem && !isButton && show)) { + // Different setup based on type + switch (type) { + // TODO: Handle passing an iframe for true progressive enhancement + // case 'iframe': + case 'div': + this.type = this.media.getAttribute('data-type'); + this.embedId = this.media.getAttribute('data-video-id'); + + if (utils.is.empty(this.type)) { + this.error('Setup failed: embed type missing'); return; } - // Prevent the toggle being caught by the doc listener - if (isButton) { - event.stopPropagation(); - } - } - - // Set form and button attributes - if (button) { - button.setAttribute('aria-expanded', show); - } - if (form) { - form.setAttribute('aria-hidden', !show); - if (show) { - form.removeAttribute('tabindex'); - } else { - form.setAttribute('tabindex', -1); - } - } - } - - // Get the natural size of a tab - function getTabSize(tab) { - var width; - var height; - - var clone = tab.cloneNode(true); - clone.style.position = 'absolute'; - clone.style.opacity = 0; - clone.setAttribute('aria-hidden', false); - - // Prevent input's being unchecked due to the name being identical - [].forEach.call(clone.querySelectorAll('input[name]'), function(input) { - var name = input.getAttribute('name'); - input.setAttribute('name', name + '-clone'); - }); - - // Append to parent so we get the "real" size - tab.parentNode.appendChild(clone); - - // Get the sizes before we remove - width = clone.scrollWidth; - height = clone.scrollHeight; - - // Remove from the DOM - utils.removeElement(clone); - - return { - width: width, - height: height, - }; - } - - // Toggle Menu - function showTab(event) { - var menu = player.elements.settings.menu; - var tab = event.target; - var show = tab.getAttribute('aria-expanded') === 'false'; - var pane = document.getElementById(tab.getAttribute('aria-controls')); - - // Nothing to show, bail - if (!utils.is.htmlElement(pane)) { - return; - } - - // Are we targetting a tab? If not, bail - var isTab = pane.getAttribute('role') === 'tabpanel'; - if (!isTab) { - return; - } - - // Hide all other tabs - // Get other tabs - var current = menu.querySelector('[role="tabpanel"][aria-hidden="false"]'); - var container = current.parentNode; - - // Set other toggles to be expanded false - [].forEach.call(menu.querySelectorAll('[aria-controls="' + current.getAttribute('id') + '"]'), function( - toggle - ) { - toggle.setAttribute('aria-expanded', false); - }); - - // If we can do fancy animations, we'll animate the height/width - if (support.transitions && !support.reducedMotion) { - // Set the current width as a base - container.style.width = current.scrollWidth + 'px'; - container.style.height = current.scrollHeight + 'px'; - - // Get potential sizes - var size = getTabSize(pane); - - // Restore auto height/width - var restore = function(event) { - // We're only bothered about height and width on the container - if (event.target !== container || !utils.inArray(['width', 'height'], event.propertyName)) { - return; - } - - // Revert back to auto - container.style.width = ''; - container.style.height = ''; - - // Only listen once - utils.off(container, utils.transitionEnd, restore); - }; - - // Listen for the transition finishing and restore auto height/width - utils.on(container, utils.transitionEnd, restore); - - // Set dimensions to target - container.style.width = size.width + 'px'; - container.style.height = size.height + 'px'; - } - - // Set attributes on current tab - current.setAttribute('aria-hidden', true); - current.setAttribute('tabindex', -1); - - // Set attributes on target - pane.setAttribute('aria-hidden', !show); - tab.setAttribute('aria-expanded', show); - pane.removeAttribute('tabindex'); - } - - // Update volume UI and storage - function updateVolume() { - // Update the <input type="range"> if present - if (player.supported.ui) { - var value = player.media.muted ? 0 : player.media.volume; - - if (player.elements.inputs.volume) { - setRange(player.elements.inputs.volume, value); - } - } - - // Update the volume in storage - updateStorage({ - volume: player.media.volume, - }); - - // Toggle class if muted - utils.toggleClass(player.elements.container, player.config.classNames.muted, player.media.muted); - - // Update checkbox for mute state - if (player.supported.ui && player.elements.buttons.mute) { - utils.toggleState(player.elements.buttons.mute, player.media.muted); - } - } - - // Check if media is loading - function checkLoading(event) { - player.loading = event.type === 'waiting'; - - // Clear timer - clearTimeout(timers.loading); - - // Timer to prevent flicker when seeking - timers.loading = setTimeout(function() { - // Toggle container class hook - utils.toggleClass(player.elements.container, player.config.classNames.loading, player.loading); - - // Show controls if loading, hide if done - player.toggleControls(player.loading); - }, player.loading ? 250 : 0); - } - - // Update seek value and lower fill - function setRange(range, value) { - if (!utils.is.htmlElement(range)) { - return; - } - - range.value = value; - - // Webkit range fill - updateRangeFill(range); - } - - // Set <progress> value - function setProgress(progress, value) { - // Default to 0 - if (utils.is.undefined(value)) { - value = 0; - } - - // Default to buffer or bail - if (utils.is.undefined(progress)) { - progress = player.elements.display.buffer; - } - - // Update value and label - if (utils.is.htmlElement(progress)) { - progress.value = value; - - // Update text label inside - var label = progress.getElementsByTagName('span')[0]; - if (utils.is.htmlElement(label)) { - label.childNodes[0].nodeValue = value; - } - } - } - - // Update <progress> elements - function updateProgress(event) { - if (!player.supported.ui) { - return; - } - - var value = 0; - var duration = player.getDuration(); - - if (event) { - switch (event.type) { - // Video playing - case 'timeupdate': - case 'seeking': - value = utils.getPercentage(player.media.currentTime, duration); - - // Set seek range value only if it's a 'natural' time event - if (event.type === 'timeupdate') { - setRange(player.elements.inputs.seek, value); - } - - break; - - // Check buffer status - case 'playing': - case 'progress': - value = (function() { - var buffered = player.media.buffered; - - if (buffered && buffered.length) { - // HTML5 - return utils.getPercentage(buffered.end(0), duration); - } else if (utils.is.number(buffered)) { - // YouTube returns between 0 and 1 - return buffered * 100; - } - - return 0; - })(); - - setProgress(player.elements.display.buffer, value); - - break; - } - } - - // TODO: Loop - this shouldn't be here - /*if (utils.is.number(player.config.loop.start) && utils.is.number(player.config.loop.end) && player.media.currentTime >= player.config.loop.end) { - console.warn('Looping'); - player.seek(player.config.loop.start); - }*/ - } - - // Update the displayed time - function updateTimeDisplay(time, element) { - // Bail if there's no duration display - if (!utils.is.htmlElement(element)) { - return; - } - - // Fallback to 0 - if (isNaN(time)) { - time = 0; - } - - var secs = parseInt(time % 60); - var mins = parseInt((time / 60) % 60); - var hours = parseInt((time / 60 / 60) % 60); - var duration = player.getDuration(); - - // Do we need to display hours? - var displayHours = parseInt((duration / 60 / 60) % 60) > 0; - - // Ensure it's two digits. For example, 03 rather than 3. - secs = ('0' + secs).slice(-2); - mins = ('0' + mins).slice(-2); - - // Generate display - var display = (displayHours ? hours + ':' : '') + mins + ':' + secs; - - // Render - element.textContent = display; - - // Return for looping - return display; - } - - // Show the duration on metadataloaded - function displayDuration() { - if (!player.supported.ui) { - return; - } - - // Determine duration - var duration = player.getDuration() || 0; - - // If there's only one time display, display duration there - if (!player.elements.display.duration && player.config.displayDuration && player.media.paused) { - updateTimeDisplay(duration, player.elements.display.currentTime); - } - - // If there's a duration element, update content - if (player.elements.display.duration) { - updateTimeDisplay(duration, player.elements.display.duration); - } - - // Update the tooltip (if visible) - updateSeekTooltip(); - } - - // Handle time change event - function timeUpdate(event) { - // Duration - updateTimeDisplay(player.media.currentTime, player.elements.display.currentTime); - - // Ignore updates while seeking - if (event && event.type === 'timeupdate' && player.media.seeking) { - return; - } - - // Playing progress - updateProgress(event); - } - - // Update hover tooltip for seeking - function updateSeekTooltip(event) { - var duration = player.getDuration(); - - // Bail if setting not true - if ( - !player.config.tooltips.seek || - !utils.is.htmlElement(player.elements.inputs.seek) || - !utils.is.htmlElement(player.elements.display.seekTooltip) || - duration === 0 - ) { - return; - } - - // Calculate percentage - var clientRect = player.elements.inputs.seek.getBoundingClientRect(); - var percent = 0; - var visible = player.config.classNames.tooltip + '--visible'; - - // Determine percentage, if already visible - if (utils.is.event(event)) { - percent = 100 / clientRect.width * (event.pageX - clientRect.left); - } else { - if (utils.hasClass(player.elements.display.seekTooltip, visible)) { - percent = player.elements.display.seekTooltip.style.left.replace('%', ''); - } else { + if (utils.is.empty(this.embedId)) { + this.error('Setup failed: video id missing'); return; } - } - - // Set bounds - if (percent < 0) { - percent = 0; - } else if (percent > 100) { - percent = 100; - } - - // Display the time a click would seek to - updateTimeDisplay(duration / 100 * percent, player.elements.display.seekTooltip); - - // Set position - player.elements.display.seekTooltip.style.left = percent + '%'; - - // Show/hide the tooltip - // If the event is a moues in/out and percentage is inside bounds - if (utils.is.event(event) && utils.inArray(['mouseenter', 'mouseleave'], event.type)) { - utils.toggleClass(player.elements.display.seekTooltip, visible, event.type === 'mouseenter'); - } - } - - // Update source - // Sources are not checked for support so be careful - function updateSource(source) { - if (!utils.is.object(source) || !('sources' in source) || !source.sources.length) { - warn('Invalid source format'); - return; - } - - // Cancel current network requests - cancelRequests(); - - // Destroy instance and re-setup - player.destroy(function() { - // TODO: Reset menus here - - // Remove elements - removeElement(player.media); - removeElement('captions'); - removeElement('wrapper'); - - // Reset class name - if (player.elements.container) { - player.elements.container.removeAttribute('class'); - } - // Set the type - if ('type' in source) { - player.type = source.type; + // Clean up + this.media.removeAttribute('data-type'); + this.media.removeAttribute('data-video-id'); + break; - // Get child type for video (it might be an embed) - if (player.type === 'video') { - var firstSource = source.sources[0]; + case 'video': + case 'audio': + this.type = type; - if ('type' in firstSource && utils.inArray(types.embed, firstSource.type)) { - player.type = firstSource.type; - } - } + if (this.media.getAttribute('crossorigin') !== null) { + this.config.crossorigin = true; } - - // Check for support - player.supported = utils.checkSupport(player.type, player.config.inline); - - // Create new markup - switch (player.type) { - case 'video': - player.media = utils.createElement('video'); - break; - - case 'audio': - player.media = utils.createElement('audio'); - break; - - case 'youtube': - case 'vimeo': - case 'soundcloud': - player.media = utils.createElement('div'); - player.embedId = source.sources[0].src; - break; + if (this.media.getAttribute('autoplay') !== null) { + this.config.autoplay = true; } - - // Inject the new element - player.elements.container.appendChild(player.media); - - // Autoplay the new source? - if (utils.is.boolean(source.autoplay)) { - player.config.autoplay = source.autoplay; + if (this.media.getAttribute('playsinline') !== null) { + this.config.inline = true; } - - // Set attributes for audio and video - if (utils.inArray(types.html5, player.type)) { - if (player.config.crossorigin) { - player.media.setAttribute('crossorigin', ''); - } - if (player.config.autoplay) { - player.media.setAttribute('autoplay', ''); - } - if ('poster' in source) { - player.media.setAttribute('poster', source.poster); - } - if (player.config.loop.active) { - player.media.setAttribute('loop', ''); - } - if (player.config.muted) { - player.media.setAttribute('muted', ''); - } - if (player.config.inline) { - player.media.setAttribute('playsinline', ''); - } + if (this.media.getAttribute('muted') !== null) { + this.config.muted = true; } - - // Restore class hooks - utils.toggleClass( - player.elements.container, - player.config.classNames.captions.active, - player.supported.ui && player.captions.enabled - ); - addStyleHook(); - - // Set new sources for html5 - if (utils.inArray(types.html5, player.type)) { - insertElements('source', source.sources); - } - - // Set up from scratch - setupMedia(); - - // HTML5 stuff - if (utils.inArray(types.html5, player.type)) { - // Setup captions - if ('tracks' in source) { - insertElements('track', source.tracks); - } - - // Load HTML5 sources - player.media.load(); - } - - // If HTML5 or embed but not fully supported, setupInterface and call ready now - if ( - utils.inArray(types.html5, player.type) || - (utils.inArray(types.embed, player.type) && !player.supported.ui) - ) { - // Setup interface - setupInterface(); - - // Call ready - ready(); + if (this.media.getAttribute('loop') !== null) { + this.config.loop.active = true; } + break; - // Set aria title and iframe title - player.config.title = source.title; - setTitle(); - }, false); + default: + this.error('Setup failed: unsupported type'); + return; } - // Listen for control events - function listeners() { - // IE doesn't support input event, so we fallback to change - var inputEvent = player.browser.isIE ? 'change' : 'input'; - - // Click play/pause helper - function togglePlay() { - var play = player.togglePlay(); - - // Determine which buttons - var target = player.elements.buttons[play ? 'pause' : 'play']; - - // Transfer focus - if (utils.is.htmlElement(target)) { - target.focus(); - } - } - - // Get the key code for an event - function getKeyCode(event) { - return event.keyCode ? event.keyCode : event.which; - } - - // Keyboard shortcuts - if (player.config.keyboard.focused) { - var last = null; - - // Handle global presses - if (player.config.keyboard.global) { - utils.on( - window, - 'keydown keyup', - function(event) { - var code = getKeyCode(event); - var focused = utils.getFocusElement(); - var allowed = [48, 49, 50, 51, 52, 53, 54, 56, 57, 75, 77, 70, 67, 73, 76, 79]; - - // Only handle global key press if key is in the allowed keys - // and if the focused element is not editable (e.g. text input) - // and any that accept key input http://webaim.org/techniques/keyboard/ - if ( - utils.inArray(allowed, code) && - (!utils.is.htmlElement(focused) || - !utils.matches(focused, player.config.selectors.editable)) - ) { - handleKey(event); - } - }, - false - ); - } - - // Handle presses on focused - utils.on(player.elements.container, 'keydown keyup', handleKey, false); - } - - function handleKey(event) { - var code = getKeyCode(event); - var pressed = event.type === 'keydown'; - var held = pressed && code === last; - - // If the event is bubbled from the media element - // Firefox doesn't get the keycode for whatever reason - if (!utils.is.number(code)) { - return; - } - - // Seek by the number keys - function seekByKey() { - // Get current duration - var duration = player.media.duration; - - // Bail if we have no duration set - if (!utils.is.number(duration)) { - return; - } - - // Divide the max duration into 10th's and times by the number value - player.seek(duration / 10 * (code - 48)); - } - - // Handle the key on keydown - // Reset on keyup - if (pressed) { - // Which keycodes should we prevent default - var preventDefault = [ - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 56, - 57, - 32, - 75, - 38, - 40, - 77, - 39, - 37, - 70, - 67, - 73, - 76, - 79, - ]; - var checkFocus = [38, 40]; - - if (utils.inArray(checkFocus, code)) { - var focused = utils.getFocusElement(); - - if (utils.is.htmlElement(focused) && utils.getFocusElement().type === 'radio') { - return; - } - } - - // If the code is found prevent default (e.g. prevent scrolling for arrows) - if (utils.inArray(preventDefault, code)) { - event.preventDefault(); - event.stopPropagation(); - } - - switch (code) { - case 48: - case 49: - case 50: - case 51: - case 52: - case 53: - case 54: - case 55: - case 56: - case 57: - // 0-9 - if (!held) { - seekByKey(); - } - break; - - case 32: - case 75: - // Space and K key - if (!held) { - togglePlay(); - } - break; - - case 38: - // Arrow up - player.increaseVolume(0.1); - break; - - case 40: - // Arrow down - player.decreaseVolume(0.1); - break; - - case 77: - // M key - if (!held) { - player.toggleMute(); - } - break; - - case 39: - // Arrow forward - player.forward(); - break; - - case 37: - // Arrow back - player.rewind(); - break; - - case 70: - // F key - player.toggleFullscreen(); - break; - - case 67: - // C key - if (!held) { - player.toggleCaptions(); - } - break; - - case 73: - player.setLoop('start'); - break; - - case 76: - player.setLoop(); - break; - - case 79: - player.setLoop('end'); - break; - } - - // Escape is handle natively when in full screen - // So we only need to worry about non native - if (!support.fullscreen && player.fullscreen.active && code === 27) { - player.toggleFullscreen(); - } + // Sniff out the browser + this.browser = utils.getBrowser(); - // Store last code for next cycle - last = code; - } else { - last = null; - } - } - - // Detect tab focus - // Remove class on blur/focusout - utils.on(player.elements.container, 'focusout', function(event) { - utils.toggleClass(event.target, player.config.classNames.tabFocus, false); - }); - - // Add classname to tabbed elements - utils.on(player.elements.container, 'keydown', function(event) { - if (event.keyCode !== 9) { - return; - } - - // Delay the adding of classname until the focus has changed - // This event fires before the focusin event - window.setTimeout(function() { - utils.toggleClass(utils.getFocusElement(), player.config.classNames.tabFocus, true); - }, 0); - }); - - // Trigger custom and default handlers - var handlerProxy = function(event, customHandler, defaultHandler) { - if (utils.is.function(customHandler)) { - customHandler.call(this, event); - } - if (utils.is.function(defaultHandler)) { - defaultHandler.call(this, event); - } - }; + // Load saved settings from localStorage + this.storage = storage.setup.call(this); - // Play - utils.proxy(player.elements.buttons.play, 'click', player.config.listeners.play, togglePlay); - utils.proxy(player.elements.buttons.playLarge, 'click', player.config.listeners.play, togglePlay); - - // Pause - utils.proxy(player.elements.buttons.pause, 'click', player.config.listeners.pause, togglePlay); - - // Pause - utils.proxy(player.elements.buttons.restart, 'click', player.config.listeners.restart, function() { - player.restart(); - }); - - // Rewind - utils.proxy(player.elements.buttons.rewind, 'click', player.config.listeners.rewind, function() { - player.rewind(); - }); - - // Rewind - utils.proxy(player.elements.buttons.forward, 'click', player.config.listeners.forward, function() { - player.forward(); - }); - - // Mute - utils.proxy(player.elements.buttons.mute, 'click', player.config.listeners.mute, function() { - player.toggleMute(); - }); - - // Captions - utils.proxy(player.elements.buttons.captions, 'click', player.config.listeners.captions, function() { - player.toggleCaptions(); - }); - - // Fullscreen - utils.proxy(player.elements.buttons.fullscreen, 'click', player.config.listeners.fullscreen, function() { - player.toggleFullscreen(); - }); - - // Picture-in-Picture - utils.proxy(player.elements.buttons.pip, 'click', player.config.listeners.pip, function() { - player.togglePictureInPicture(); - }); - - // Airplay - utils.proxy(player.elements.buttons.airplay, 'click', player.config.listeners.airplay, function() { - player.airPlay(); - }); - - // Settings menu - utils.on(player.elements.buttons.settings, 'click', toggleMenu); - - // Click anywhere closes menu - utils.on(document.documentElement, 'click', toggleMenu); - - // Settings menu - utils.on(player.elements.settings.form, 'click', function(event) { - // Show tab in menu - showTab(event); - - // Settings menu items - use event delegation as items are added/removed - // Settings - Language - if (utils.matches(event.target, player.config.selectors.inputs.language)) { - handlerProxy.call(this, event, player.config.listeners.language, function() { - player.toggleCaptions(true); - - player.setLanguage(event.target.value.toLowerCase()); - }); - } else if (utils.matches(event.target, player.config.selectors.inputs.quality)) { - // Settings - Quality - handlerProxy.call(this, event, player.config.listeners.quality, function() { - player.setQuality(event.target.value); - }); - } else if (utils.matches(event.target, player.config.selectors.inputs.speed)) { - // Settings - Speed - handlerProxy.call(this, event, player.config.listeners.speed, function() { - player.setSpeed(parseFloat(event.target.value)); - }); - } else if (utils.matches(event.target, player.config.selectors.buttons.loop)) { - // Settings - Looping - // TODO: use toggle buttons - handlerProxy.call(this, event, player.config.listeners.loop, function() { - // TODO: This should be done in the method itself I think - // var value = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type'); - - warn('Set loop'); - - /*if (utils.inArray(['start', 'end', 'all', 'none'], value)) { - player.setLoop(value); - }*/ - }); - } - }); - - // Seek - utils.proxy(player.elements.inputs.seek, inputEvent, player.config.listeners.seek, function(event) { - var duration = player.getDuration(); - player.seek(event.target.value / event.target.max * duration); - }); + // Check for support again but with type + this.supported = support.check(this.type, this.config.inline); - // Volume - utils.proxy(player.elements.inputs.volume, inputEvent, player.config.listeners.volume, function() { - player.setVolume(event.target.value); - }); - - // Polyfill for lower fill in <input type="range"> for webkit - if (player.browser.isWebkit) { - utils.on(getElements('input[type="range"]'), 'input', updateRangeFill); - } - - // Seek tooltip - utils.on(player.elements.progress, 'mouseenter mouseleave mousemove', updateSeekTooltip); - - // Toggle controls visibility based on mouse movement - if (player.config.hideControls) { - // Toggle controls on mouse events and entering fullscreen - utils.on( - player.elements.container, - 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', - function(event) { - player.toggleControls(event); - } - ); - - // Watch for cursor over controls so they don't hide when trying to interact - utils.on(player.elements.controls, 'mouseenter mouseleave', function(event) { - player.elements.controls.hover = event.type === 'mouseenter'; - }); - - // Watch for cursor over controls so they don't hide when trying to interact - utils.on(player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', function( - event - ) { - player.elements.controls.pressed = utils.inArray(['mousedown', 'touchstart'], event.type); - }); - - // Focus in/out on controls - // TODO: Check we need capture here - utils.on( - player.elements.controls, - 'focus blur', - function(event) { - player.toggleControls(event); - }, - true - ); - } - - // Mouse wheel for volume - utils.proxy( - player.elements.inputs.volume, - 'wheel', - player.config.listeners.volume, - function(event) { - // Detect "natural" scroll - suppored on OS X Safari only - // Other browsers on OS X will be inverted until support improves - var inverted = event.webkitDirectionInvertedFromDevice; - var step = 1 / 50; - var direction = 0; - - // Scroll down (or up on natural) to decrease - if (event.deltaY < 0 || event.deltaX > 0) { - if (inverted) { - player.decreaseVolume(step); - direction = -1; - } else { - player.increaseVolume(step); - direction = 1; - } - } - - // Scroll up (or down on natural) to increase - if (event.deltaY > 0 || event.deltaX < 0) { - if (inverted) { - player.increaseVolume(step); - direction = 1; - } else { - player.decreaseVolume(step); - direction = -1; - } - } - - // Don't break page scrolling at max and min - if ((direction === 1 && player.media.volume < 1) || (direction === -1 && player.media.volume > 0)) { - event.preventDefault(); - } - }, - false - ); - - // Handle user exiting fullscreen by escaping etc - if (support.fullscreen) { - utils.on(document, fullscreen.eventType, function(event) { - player.toggleFullscreen(event); - }); - } + // If no support for even API, bail + if (!this.supported.api) { + this.error('Setup failed: no support'); + return; } - // Listen for media events - function mediaListeners() { - // Time change on media - utils.on(player.media, 'timeupdate seeking', timeUpdate); - - // Display duration - utils.on(player.media, 'durationchange loadedmetadata', displayDuration); - - // Handle the media finishing - utils.on(player.media, 'ended', function() { - // Show poster on end - if (player.type === 'video' && player.config.showPosterOnEnd) { - // Clear - if (player.type === 'video') { - setCaption(); - } - - // Restart - player.restart(); - - // Re-load media - player.media.load(); - } - }); - - // Check for buffer progress - utils.on(player.media, 'progress playing', updateProgress); - - // Handle native mute - utils.on(player.media, 'volumechange', updateVolume); + // Store reference + this.media.plyr = this; - // Handle native play/pause - utils.on(player.media, 'play pause ended', checkPlaying); + // Wrap media + this.elements.container = utils.createElement('div'); + utils.wrap(this.media, this.elements.container); - // Loading - utils.on(player.media, 'waiting canplay seeked', checkLoading); + // Add style hook + ui.addStyleHook.call(this); - // Click video - if (player.supported.ui && player.config.clickToPlay && player.type !== 'audio') { - // Re-fetch the wrapper - var wrapper = getElement('.' + player.config.classNames.video); - - // Bail if there's no wrapper (this should never happen) - if (!wrapper) { - return; - } - - // Set cursor - wrapper.style.cursor = 'pointer'; - - // On click play, pause ore restart - utils.on(wrapper, 'click', function() { - // Touch devices will just show controls (if we're hiding controls) - if (player.config.hideControls && support.touch && !player.media.paused) { - return; - } - - if (player.media.paused) { - player.play(); - } else if (player.media.ended) { - player.restart(); - player.play(); - } else { - player.pause(); - } - }); - } - - // Disable right click - if (player.config.disableContextMenu) { - utils.on( - player.media, - 'contextmenu', - function(event) { - event.preventDefault(); - }, - false - ); - } - - // Speed change - utils.on(player.media, 'ratechange', function() { - // Store current speed - player.speed.selected = player.media.playbackRate; - - // Update UI - updateSetting('speed'); - - // Save speed to localStorage - updateStorage({ - speed: player.speed.selected, - }); - }); - - // Quality change - utils.on(player.media, 'qualitychange', function() { - // Store current quality - player.quality.selected = player.media.quality; - - // Update UI - updateSetting('quality'); - - // Save speed to localStorage - updateStorage({ - quality: player.quality.selected, - }); - }); - - // Caption language change - utils.on(player.media, 'captionchange', function() { - // Save speed to localStorage - updateStorage({ - language: player.captions.language, - }); - }); - - // Captions toggle - utils.on(player.media, 'captionsenabled captionsdisabled', function() { - // Update UI - updateSetting('captions'); - - // Save speed to localStorage - updateStorage({ - captions: player.captions.enabled, - }); - }); + // Setup media + media.setup.call(this); - // Proxy events to container - // Bubble up key events for Edge - utils.on(player.media, player.config.events.concat(['keyup', 'keydown']).join(' '), function(event) { - trigger(player.elements.container, event.type, true); + // Listen for events if debugging + if (this.config.debug) { + utils.on(this.elements.container, this.config.events.join(' '), event => { + this.log(`event: ${event.type}`); }); } - // Cancel current network requests - // See https://github.com/sampotts/plyr/issues/174 - function cancelRequests() { - if (!utils.inArray(types.html5, player.type)) { - return; - } - - // Remove child sources - var sources = player.media.querySelectorAll('source'); - for (var i = 0; i < sources.length; i++) { - utils.removeElement(sources[i]); - } - - // Set blank video src attribute - // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error - // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection - player.media.setAttribute('src', player.config.blankVideo); - - // Load the new empty source - // This will cancel existing requests - // See https://github.com/sampotts/plyr/issues/174 - player.media.load(); - - // Debugging - log('Cancelled network requests'); + // Setup interface + // If embed but not fully supported, build interface now to avoid flash of controls + if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) { + ui.build.call(this); } - - // Setup the UI - function setupInterface() { - // Re-attach media element listeners - // TODO: Use event bubbling - mediaListeners(); - - // Don't setup interface if no support - if (!player.supported.ui) { - warn('Basic support only', player.type); - - // Remove controls - removeElement('controls'); - - // Remove large play - removeElement('buttons.play'); - - // Restore native controls - toggleNativeControls(true); - - // Bail - return; - } - - // Inject custom controls if not present - if (!utils.is.htmlElement(player.elements.controls)) { - // Inject custom controls - injectControls(); - - // Re-attach control listeners - listeners(); - } - - // If there's no controls, bail - if (!utils.is.htmlElement(player.elements.controls)) { - return; - } - - // Remove native controls - toggleNativeControls(); - - // Setup fullscreen - setupFullscreen(); - - // Captions - setupCaptions(); - - // Set volume - player.setVolume(); - updateVolume(); - - // Set playback speed - player.setSpeed(); - - // Set loop - player.setLoop(); - - // Reset time display - timeUpdate(); - - // Update the UI - checkPlaying(); - } - - // Everything done - function ready() { - player.ready = true; - - // Ready event at end of execution stack - window.setTimeout(function() { - trigger(player.elements.container, 'ready', true); - }, 0); - - // Autoplay - if (player.config.autoplay) { - player.play(); - } - } - - // Setup a player - function setup(media) { - // We need an element to setup - if (media === null || utils.is.undefined(media) || !utils.is.htmlElement(media)) { - error('Setup failed: no suitable element passed'); - return; - } - - // Bail if the element is initialized - if (media.plyr) { - warn('Target already setup'); - player = media.plyr; - return; - } - - // Bail if not enabled - if (!player.config.enabled) { - error('Setup failed: disabled by config'); - return; - } - - // Bail if disabled or no basic support - // You may want to disable certain UAs etc - if (!utils.checkSupport().api) { - error('Setup failed: no support'); - return; - } - - // Cache original element state for .destroy() - player.elements.original = media.cloneNode(true); - - // Set media type based on tag or data attribute - // Supported: video, audio, vimeo, youtube - var type = media.tagName.toLowerCase(); - - // Different setup based on type - switch (type) { - case 'div': - player.type = media.getAttribute('data-type'); - player.embedId = media.getAttribute('data-video-id'); - - if (utils.is.empty(player.type)) { - error('Setup failed: embed type missing'); - return; - } - - if (utils.is.empty(player.embedId)) { - error('Setup failed: video id missing'); - return; - } - - // Clean up - media.removeAttribute('data-type'); - media.removeAttribute('data-video-id'); - break; - - case 'iframe': - // TODO: Handle passing an iframe for true progressive enhancement - break; - - case 'video': - case 'audio': - player.type = type; - - if (media.getAttribute('crossorigin') !== null) { - player.config.crossorigin = true; - } - if (media.getAttribute('autoplay') !== null) { - player.config.autoplay = true; - } - if (media.getAttribute('playsinline') !== null) { - player.config.inline = true; - } - if (media.getAttribute('muted') !== null) { - player.config.muted = true; - } - if (media.getAttribute('loop') !== null) { - player.config.loop.active = true; - } - break; - - default: - error('Setup failed: unsupported type'); - return; - } - - // Sniff out the browser - player.browser = utils.getBrowser(); - - // Load saved settings from localStorage - setupStorage(); - - // Check for support again but with type - player.supported = utils.checkSupport(player.type, player.config.inline); - - // If no support for even API, bail - if (!player.supported.api) { - error('Setup failed: no support'); - return; - } - - // Store reference - media.plyr = player; - - // Wrap media - player.elements.container = utils.wrap(media, utils.createElement('div')); - - // Allow focus to be captured - // player.elements.container.setAttribute('tabindex', 0); - - // Add style hook - addStyleHook(); - - // Debug info - log(player.browser.name + ' ' + player.browser.version); - - // Setup media - setupMedia(); - - // Listen for events if debugging - if (player.config.debug) { - utils.on(player.elements.container, player.config.events.join(' '), function(event) { - log('event: ' + event.type); - }); - } - - // Setup interface - // If embed but not fully supported, setupInterface (to avoid flash of controls) and call ready now - if ( - utils.inArray(types.html5, player.type) || - (utils.inArray(types.embed, player.type) && !player.supported.ui) - ) { - // Setup UI - setupInterface(); - - // Call ready - ready(); - - // Set title on button and frame - setTitle(); - } - } - - // Expose some core functions - player.core = { - getElement: getElement, - getElements: getElements, - trigger: trigger, - setCaption: setCaption, - setupCaptions: setupCaptions, - toggleNativeControls: toggleNativeControls, - updateTimeDisplay: updateTimeDisplay, - updateSource: updateSource, - toggleMenu: toggleMenu, - timers: timers, - support: support, - - // Debugging - log: log, - warn: warn, - error: error, - }; - - // Initialize instance - setup(player.media); } // API // --------------------------------------- - // Play - Plyr.prototype.play = function() { - var player = this; - if ('play' in player.media) { - player.media.play(); + get isHTML5() { + return types.html5.includes(this.type); + } + get isEmbed() { + return types.embed.includes(this.type); + } + + // Play + play() { + if ('play' in this.media) { + this.media.play(); } // Allow chaining - return player; - }; + return this; + } // Pause - Plyr.prototype.pause = function() { - var player = this; - - if ('pause' in player.media) { - player.media.pause(); + pause() { + if ('pause' in this.media) { + this.media.pause(); } // Allow chaining - return player; - }; + return this; + } // Toggle playback - Plyr.prototype.togglePlay = function(toggle) { - var player = this; - + togglePlay(toggle) { // True toggle if nothing passed - if (!utils.is.boolean(toggle)) { - toggle = player.media.paused; - } - - if (toggle) { - player.play(); - } else { - player.pause(); + if ((!utils.is.boolean(toggle) && this.media.paused) || toggle) { + return this.play(); } - return toggle; - }; - - // Get playback status - Plyr.prototype.isPlaying = function() { - return !this.media.paused; - }; + return this.pause(); + } // Stop - Plyr.prototype.stop = function() { - var player = this; - - player.restart(); - player.pause(); - - // Allow chaining - return player; - }; + stop() { + return this.restart().pause(); + } // Restart - Plyr.prototype.restart = function() { - var player = this; - - // Seek to 0 - player.seek(); - - // Allow chaining - return player; - }; + restart() { + this.currentTime = 0; + return this; + } // Rewind - Plyr.prototype.rewind = function(seekTime) { - var player = this; - - // Use default if needed - if (!utils.is.number(seekTime)) { - seekTime = player.config.seekTime; - } - - player.seek(player.media.currentTime - seekTime); - - // Allow chaining - return player; - }; + rewind(seekTime) { + this.currentTime = Math.min( + this.currentTime - (utils.is.number(seekTime) ? seekTime : this.config.seekTime), + 0 + ); + return this; + } // Fast forward - Plyr.prototype.forward = function(seekTime) { - var player = this; - - // Use default if needed - if (!utils.is.number(seekTime)) { - seekTime = player.config.seekTime; - } - - player.seek(player.media.currentTime + seekTime); - - // Allow chaining - return player; - }; + forward(seekTime) { + this.currentTime = Math.max( + this.currentTime + (utils.is.number(seekTime) ? seekTime : this.config.seekTime), + this.duration + ); + return this; + } // Seek to time // The input parameter can be an event or a number - Plyr.prototype.seek = function(input) { - var player = this; - var targetTime = 0; - var paused = player.media.paused; - var duration = player.getDuration(); + set currentTime(input) { + let targetTime = 0; if (utils.is.number(input)) { targetTime = input; @@ -4943,53 +316,70 @@ // Normalise targetTime if (targetTime < 0) { targetTime = 0; - } else if (targetTime > duration) { - targetTime = duration; + } else if (targetTime > this.duration) { + targetTime = this.duration; } // Set the current time + // TODO: This should be included in the "adapters" // Embeds - if (utils.inArray(types.embed, player.type)) { - switch (player.type) { + if (this.isEmbed) { + // Get current paused state + const { paused } = this.media; + + switch (this.type) { case 'youtube': - player.embed.seekTo(targetTime); + this.embed.seekTo(targetTime); break; case 'vimeo': - player.embed.setCurrentTime(targetTime); + this.embed.setCurrentTime(targetTime); break; - case 'soundcloud': - player.embed.seekTo(targetTime * 1000); + default: break; } + // Restore pause (some will play on seek) if (paused) { - player.pause(); + this.pause(); } // Set seeking flag - player.media.seeking = true; + this.media.seeking = true; // Trigger seeking - player.core.trigger(player.media, 'seeking'); + utils.dispatchEvent.call(this, this.media, 'seeking'); } else { - player.media.currentTime = targetTime.toFixed(4); + this.media.currentTime = targetTime.toFixed(4); } // Logging - player.core.log('Seeking to ' + player.media.currentTime + ' seconds'); + this.log(`Seeking to ${this.currentTime} seconds`); + } - // Allow chaining - return player; - }; + get currentTime() { + return Number(this.media.currentTime); + } + + // Get the duration (or custom if set) + get duration() { + // Faux duration set via config + const fauxDuration = parseInt(this.config.duration, 10); + + // True duration + const realDuration = Number(this.media.duration); + + // If custom duration is funky, use regular duration + return !Number.isNaN(fauxDuration) ? fauxDuration : realDuration; + } // Set volume - Plyr.prototype.setVolume = function(volume) { - var player = this; - var max = 1; - var min = 0; - var isSet = !utils.is.undefined(volume); + set volume(value) { + let volume = value; + const max = 1; + const min = 0; + const isSet = !utils.is.undefined(volume); if (utils.is.string(volume)) { volume = parseFloat(volume); @@ -4997,12 +387,12 @@ // Load volume from storage if no value specified if (!utils.is.number(volume)) { - volume = player.storage.volume; + ({ volume } = this.storage); } // Use config if all else fails if (!utils.is.number(volume)) { - volume = player.config.volume; + ({ volume } = this.config); } // Maximum is volumeMax @@ -5015,115 +405,99 @@ } // Set the player volume - player.media.volume = volume; + this.media.volume = volume; // Trigger volumechange for embeds - if (utils.inArray(types.embed, player.type)) { + if (this.isEmbed) { // Set media volume - switch (player.type) { + switch (this.type) { case 'youtube': - player.embed.setVolume(player.media.volume * 100); + this.embed.setVolume(this.media.volume * 100); break; case 'vimeo': - case 'soundcloud': - player.embed.setVolume(player.media.volume); + this.embed.setVolume(this.media.volume); + break; + + default: break; } - player.core.trigger(player.media, 'volumechange'); + utils.dispatchEvent.call(this, this.media, 'volumechange'); } // Toggle muted state if (volume === 0) { - player.toggleMute(true); - } else if (player.media.muted && isSet) { - player.toggleMute(); + this.toggleMute(true); + } else if (this.media.muted && isSet) { + this.toggleMute(); } - // Allow chaining - return player; - }; - - // Increase volume - Plyr.prototype.increaseVolume = function(step) { - var player = this; - var volume = player.media.muted ? 0 : player.media.volume; + return this; + } - if (!utils.is.number(step)) { - step = 1; - } + get volume() { + return this.media.volume; + } - player.setVolume(volume + step); + // Increase volume + increaseVolume(step) { + const volume = this.media.muted ? 0 : this.media.volume; - // Allow chaining - return player; - }; + return this.setVolume(volume + utils.is.number(step) ? step : 1); + } // Decrease volume - Plyr.prototype.decreaseVolume = function(step) { - var player = this; - var volume = player.media.muted ? 0 : player.media.volume; - - if (!utils.is.number(step)) { - step = 1; - } - - player.setVolume(volume - step); + decreaseVolume(step) { + const volume = this.media.muted ? 0 : this.media.volume; - // Allow chaining - return player; - }; + return this.setVolume(volume - utils.is.number(step) ? step : 1); + } // Toggle mute - Plyr.prototype.toggleMute = function(muted) { - var player = this; - + toggleMute(mute) { // If the method is called without parameter, toggle based on current value - if (!utils.is.boolean(muted)) { - muted = !player.media.muted; - } + const toggle = utils.is.boolean(mute) ? mute : !this.media.muted; // Set button state - utils.toggleState(player.elements.buttons.mute, muted); + utils.toggleState(this.elements.buttons.mute, toggle); // Set mute on the player - player.media.muted = muted; + this.media.muted = toggle; // If volume is 0 after unmuting, restore default volume - if (!player.media.muted && player.media.volume === 0) { - player.setVolume(player.config.volume); + if (!this.media.muted && this.media.volume === 0) { + this.setVolume(this.config.volume); } // Embeds - if (utils.inArray(types.embed, player.type)) { - switch (player.type) { + if (this.isEmbed) { + switch (this.type) { case 'youtube': - player.embed[player.media.muted ? 'mute' : 'unMute'](); + this.embed[this.media.muted ? 'mute' : 'unMute'](); break; case 'vimeo': - case 'soundcloud': - player.embed.setVolume(player.media.muted ? 0 : player.config.volume); + this.embed.setVolume(this.media.muted ? 0 : this.config.volume); + break; + + default: break; } // Trigger volumechange for embeds - player.core.trigger(player.media, 'volumechange'); + utils.dispatchEvent.call(this, this.media, 'volumechange'); } - // Allow chaining - return player; - }; - - // Set playback speed - Plyr.prototype.setSpeed = function(speed) { - var player = this; + return this; + } + // Playback speed + set speed(input) { // Load speed from storage or default value - if (!utils.is.number(speed)) { - speed = parseFloat(player.storage.speed || player.speed.selected || player.config.speed.default); - } + let speed = utils.is.number(input) + ? input + : parseFloat(this.storage.speed || this.speed.selected || this.config.speed.default); // Set min/max if (speed < 0.1) { @@ -5133,401 +507,375 @@ speed = 2.0; } - if (!utils.inArray(player.config.speed.options, speed)) { - player.core.warn('Unsupported speed (' + speed + ')'); + if (!this.config.speed.options.includes(speed)) { + this.warn(`Unsupported speed (${speed})`); return; } // Set media speed - switch (player.type) { + // TODO: Should be in adapter + switch (this.type) { case 'youtube': - player.embed.setPlaybackRate(speed); + this.embed.setPlaybackRate(speed); break; case 'vimeo': speed = null; - // Vimeo not supported (https://github.com/vimeo/player.js) - player.core.warn('Vimeo playback rate change is not supported'); + // Vimeo not supported (https://github.com/vimeo/this.js) + this.warn('Vimeo playback rate change is not supported'); break; default: - player.media.playbackRate = speed; + this.media.playbackRate = speed; break; } + } - // Allow chaining - return player; - }; + get speed() { + // Set media speed + // TODO: Should be in adapter + switch (this.type) { + case 'youtube': + return this.embed.getPlaybackRate(); - // Set playback quality - Plyr.prototype.setQuality = function(quality) { - var player = this; + case 'vimeo': + // Vimeo not supported (https://github.com/vimeo/player.js) + this.warn('Vimeo playback rate change is not supported'); + return null; - // Load speed from storage or default value - if (!utils.is.string(quality)) { - quality = parseFloat(player.storage.quality || player.config.quality.selected); + default: + return this.media.playbackRate; } + } - if (!utils.inArray(player.config.quality.options, quality)) { - player.core.warn('Unsupported quality option (' + quality + ')'); + // Set playback quality + set quality(input) { + // Load speed from storage or default value + const quality = utils.is.string(input) + ? input + : parseFloat(this.storage.quality || this.config.quality.selected); + + if (!this.config.quality.options.includes(quality)) { + this.warn(`Unsupported quality option (${quality})`); return; } // Set media speed - switch (player.type) { + switch (this.type) { case 'youtube': - player.core.trigger(player.media, 'qualityrequested', false, { - quality: quality, + this.utils.dispatchEvent.call(this, this.media, 'qualityrequested', false, { + quality, }); - player.embed.setPlaybackQuality(quality); + this.embed.setPlaybackQuality(quality); break; default: - player.core.warn('Quality options are only available for YouTube'); + this.warn('Quality options are only available for YouTube'); break; } + } - // Allow chaining - return player; - }; + get quality() { + // Set media speed + switch (this.type) { + case 'youtube': + return this.embed.getPlaybackQuality(); + + default: + this.warn('Quality options are only available for YouTube'); + return null; + } + } // Toggle loop // TODO: Finish logic // TODO: Set the indicator on load as user may pass loop as config - Plyr.prototype.setLoop = function(type) { - var player = this; - + loop(input) { // Set default to be a true toggle - if (!utils.inArray(['start', 'end', 'all', 'none', 'toggle'], type)) { - type = 'toggle'; - } - - var currentTime = Number(player.media.currentTime); + const type = ['start', 'end', 'all', 'none', 'toggle'].includes(input) ? input : 'toggle'; switch (type) { case 'start': - if (player.config.loop.end && player.config.loop.end <= currentTime) { - player.config.loop.end = null; + if (this.config.loop.end && this.config.loop.end <= this.currentTime) { + this.config.loop.end = null; } - player.config.loop.start = currentTime; - //player.config.loop.indicator.start = player.elements.display.played.value; + this.config.loop.start = this.currentTime; + // this.config.loop.indicator.start = this.elements.display.played.value; break; case 'end': - if (player.config.loop.start >= currentTime) { - return; + if (this.config.loop.start >= this.currentTime) { + return this; } - player.config.loop.end = currentTime; - //player.config.loop.indicator.end = player.elements.display.played.value; + this.config.loop.end = this.currentTime; + // this.config.loop.indicator.end = this.elements.display.played.value; break; case 'all': - player.config.loop.start = 0; - player.config.loop.end = player.media.duration - 2; - player.config.loop.indicator.start = 0; - player.config.loop.indicator.end = 100; + this.config.loop.start = 0; + this.config.loop.end = this.duration - 2; + this.config.loop.indicator.start = 0; + this.config.loop.indicator.end = 100; break; case 'toggle': - if (player.config.loop.active) { - player.config.loop.start = 0; - player.config.loop.end = null; + if (this.config.loop.active) { + this.config.loop.start = 0; + this.config.loop.end = null; } else { - player.config.loop.start = 0; - player.config.loop.end = player.media.duration - 2; + this.config.loop.start = 0; + this.config.loop.end = this.duration - 2; } break; default: - player.config.loop.start = 0; - player.config.loop.end = null; + this.config.loop.start = 0; + this.config.loop.end = null; break; } - // Check if can loop - /*player.config.loop.active = utils.is.number(player.config.loop.start) && utils.is.number(player.config.loop.end); - var start = player.core.updateTimeDisplay(player.config.loop.start, player.core.getElement('[data-plyr-loop="start"]')); - var end = null; - - if (utils.is.number(player.config.loop.end)) { - // Find the <span> inside button - end = player.core.updateTimeDisplay(player.config.loop.end, player.core.getElement('[data-loop__value="loopout"]')); - } else { - // Find the <span> inside button - //end = document.querySelector('[data-loop__value="loopout"]').innerHTML = ''; - } - - if (player.config.loop.active) { - // TODO: Improve the design of the loop indicator and put styling in CSS where it's meant to be - //getElement('[data-menu="loop"]').innerHTML = start + ' - ' + end; - //getElement(player.config.selectors.progress.looped).style.position = 'absolute'; - //getElement(player.config.selectors.progress.looped).style.left = player.config.loopinPositionPercentage + '%'; - //getElement(player.config.selectors.progress.looped).style.width = (player.config.loopoutPositionPercentage - player.config.loopinPositionPercentage) + '%'; - //getElement(player.config.selectors.progress.looped).style.background = '#ffbb00'; - //getElement(player.config.selectors.progress.looped).style.height = '3px'; - //getElement(player.config.selectors.progress.looped).style.top = '3px'; - //getElement(player.config.selectors.progress.looped).style['border-radius'] = '100px'; - } else { - //getElement('[data-menu="loop"]').innerHTML = player.config.i18n.loopNone; - //getElement(player.config.selectors.progress.looped).style.width = '0px'; - }*/ - // Allow chaining - return player; - }; - - // Add common function to retrieve media source - Plyr.prototype.source = function(source) { - var player = this; + return this; + } - // If object or string, parse it - if (utils.is.object(source)) { - player.core.updateSource(source); - return player; - } + // Media source + set src(input) { + source.change.call(this, input); + } - // Return the current source - var url; + get src() { + let url; - switch (player.type) { + switch (this.type) { case 'youtube': - url = player.embed.getVideoUrl(); + url = this.embed.getVideoUrl(); break; case 'vimeo': - player.embed.getVideoUrl.then(function(value) { + this.embed.getVideoUrl.then(value => { url = value; }); break; - case 'soundcloud': - player.embed.getCurrentSound(function(object) { - url = object.permalink_url; - }); - break; - default: - url = player.media.currentSrc; + url = this.media.currentSrc; break; } return url; - }; + } - // Set or get poster - Plyr.prototype.poster = function(source) { - var player = this; + // Poster image + set poster(input) { + if (this.type !== 'video') { + this.warn('Poster can only be set on HTML5 video'); + return; + } - if (!utils.is.string(source)) { - return player.media.getAttribute('poster'); - } else if (player.type === 'video') { - player.media.setAttribute('poster', source); - } else { - player.core.warn('Poster can only be set on HTML5 video'); + if (utils.is.string(input)) { + this.media.setAttribute('poster', input); } + } - // Allow chaining - return player; - }; + get poster() { + if (this.type !== 'video') { + return null; + } - // Toggle captions - Plyr.prototype.toggleCaptions = function(show) { - var player = this; + return this.media.getAttribute('poster'); + } + // Toggle captions + toggleCaptions(input) { // If there's no full support, or there's no caption toggle - if (!player.supported.ui || !player.elements.buttons.captions) { - return; + if (!this.supported.ui || !this.elements.buttons.captions) { + return this; } // If the method is called without parameter, toggle based on current value - if (!utils.is.boolean(show)) { - show = player.elements.container.className.indexOf(player.config.classNames.captions.active) === -1; - } + const show = utils.is.boolean(input) + ? input + : this.elements.container.className.indexOf(this.config.classNames.captions.active) === -1; // Nothing to change... - if (player.captions.enabled === show) { - return player; + if (this.captions.enabled === show) { + return this; } // Set global - player.captions.enabled = show; + this.captions.enabled = show; // Toggle state - utils.toggleState(player.elements.buttons.captions, player.captions.enabled); + utils.toggleState(this.elements.buttons.captions, this.captions.enabled); // Add class hook - utils.toggleClass(player.elements.container, player.config.classNames.captions.active, player.captions.enabled); + utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.enabled); // Trigger an event - player.core.trigger(player.media, player.captions.enabled ? 'captionsenabled' : 'captionsdisabled'); + utils.dispatchEvent.call(this, this.media, this.captions.enabled ? 'captionsenabled' : 'captionsdisabled'); // Allow chaining - return player; - }; + return this; + } - // Set caption language - Plyr.prototype.setLanguage = function(language) { - var player = this; + // Caption language + set language(input) { + const player = this; // Nothing specified - if (utils.is.empty(language)) { - player.toggleCaptions(false); + if (utils.is.empty(input)) { + this.toggleCaptions(false); return player; } // Normalize - language = language.toLowerCase(); + const language = input.toLowerCase(); // If nothing to change, bail - if (player.captions.language === language) { + if (this.captions.language === language) { return player; } // Reset UI - player.toggleCaptions(true); + this.toggleCaptions(true); // Update config - player.captions.language = language; + this.captions.language = language; // Trigger an event - player.core.trigger(player.media, 'captionchange'); + utils.dispatchEvent.call(this, this.media, 'captionchange'); // Clear caption - player.core.setCaption(); + captions.setCaption.call(this); // Re-run setup - player.core.setupCaptions(); + captions.setup.call(this); // Allow chaining - return player; - }; + return this; + } - // Get current language - Plyr.prototype.getLanguage = function() { + get language() { return this.captions.language; - }; + } // Toggle fullscreen // Requires user input event - Plyr.prototype.toggleFullscreen = function(event) { - var player = this; - + toggleFullscreen(event) { // Check for native support - if (support.fullscreen) { + if (fullscreen.enabled) { // If it's a fullscreen change event, update the UI if (utils.is.event(event) && event.type === fullscreen.eventType) { - player.fullscreen.active = fullscreen.isFullScreen(player.elements.container); + this.fullscreen.active = fullscreen.isFullScreen(this.elements.container); } else { // Else it's a user request to enter or exit - if (!player.fullscreen.active) { + if (!this.fullscreen.active) { // Request full screen - fullscreen.requestFullScreen(player.elements.container); + fullscreen.requestFullScreen(this.elements.container); } else { // Bail from fullscreen fullscreen.cancelFullScreen(); } // Check if we're actually full screen (it could fail) - player.fullscreen.active = fullscreen.isFullScreen(player.elements.container); + this.fullscreen.active = fullscreen.isFullScreen(this.elements.container); - return; + return this; } } else { // Otherwise, it's a simple toggle - player.fullscreen.active = !player.fullscreen.active; + this.fullscreen.active = !this.fullscreen.active; // Add class hook utils.toggleClass( - player.elements.container, - player.config.classNames.fullscreen.fallback, - player.fullscreen.active + this.elements.container, + this.config.classNames.fullscreen.fallback, + this.fullscreen.active ); // Make sure we don't lose scroll position - if (player.fullscreen.active) { - scroll = { + if (this.fullscreen.active) { + scrollPosition = { x: window.pageXOffset || 0, y: window.pageYOffset || 0, }; } else { - window.scrollTo(scroll.x, scroll.y); + window.scrollTo(scrollPosition.x, scrollPosition.y); } // Bind/unbind escape key - document.body.style.overflow = player.fullscreen.active ? 'hidden' : ''; + document.body.style.overflow = this.fullscreen.active ? 'hidden' : ''; } // Set button state - if (player.elements.buttons && player.elements.buttons.fullscreen) { - utils.toggleState(player.elements.buttons.fullscreen, player.fullscreen.active); + if (this.elements.buttons && this.elements.buttons.fullscreen) { + utils.toggleState(this.elements.buttons.fullscreen, this.fullscreen.active); } // Trigger an event - player.core.trigger(player.media, player.fullscreen.active ? 'enterfullscreen' : 'exitfullscreen'); + utils.dispatchEvent.call(this, this.media, this.fullscreen.active ? 'enterfullscreen' : 'exitfullscreen'); - // Allow chaining - return player; - }; + return this; + } // Toggle picture-in-picture // TODO: update player with state, support, enabled // TODO: detect outside changes - Plyr.prototype.togglePictureInPicture = function(toggle) { - var player = this; - var states = { + togglePictureInPicture(input) { + const player = this; + const states = { pip: 'picture-in-picture', inline: 'inline', }; // Bail if no support - if (!player.core.support.pip) { - return; + if (!support.pip) { + return player; } // Toggle based on current state if not passed - if (!utils.is.boolean(toggle)) { - toggle = player.media.webkitPresentationMode === states.inline; - } + const toggle = utils.is.boolean(input) ? input : this.media.webkitPresentationMode === states.inline; // Toggle based on current state - player.media.webkitSetPresentationMode(toggle ? states.pip : states.inline); + this.media.webkitSetPresentationMode(toggle ? states.pip : states.inline); - // Allow chaining - return player; - }; + return this; + } // Trigger airplay // TODO: update player with state, support, enabled - Plyr.prototype.airPlay = function() { - var player = this; - + airPlay() { // Bail if no support - if (!player.core.support.airplay) { - return; + if (!support.airplay) { + return this; } // Show dialog - player.media.webkitShowPlaybackTargetPicker(); + this.media.webkitShowPlaybackTargetPicker(); - // Allow chaining - return player; - }; + return this; + } // Show the player controls in fullscreen mode - Plyr.prototype.toggleControls = function(toggle) { - var player = this; + toggleControls(toggle) { + const player = this; + + // We need controls of course... + if (!utils.is.htmlElement(this.elements.controls)) { + return player; + } // Don't hide if config says not to, it's audio, or not ready or loading - if (!player.supported.ui || !player.config.hideControls || player.type === 'audio') { - return; + if (!this.supported.ui || !this.config.hideControls || this.type === 'audio') { + return player; } - var delay = 0; - var show = toggle; - var isEnterFullscreen = false; - var loading = utils.hasClass(player.elements.container, player.config.classNames.loading); + let delay = 0; + let show = toggle; + let isEnterFullscreen = false; + const loading = utils.hasClass(this.elements.container, this.config.classNames.loading); // Default to false if no boolean if (!utils.is.boolean(toggle)) { @@ -5536,10 +884,10 @@ isEnterFullscreen = toggle.type === 'enterfullscreen'; // Whether to show controls - show = utils.inArray(['mousemove', 'touchstart', 'mouseenter', 'focus'], toggle.type); + show = ['mousemove', 'touchstart', 'mouseenter', 'focus'].includes(toggle.type); // Delay hiding on move events - if (utils.inArray(['mousemove', 'touchmove'], toggle.type)) { + if (['mousemove', 'touchmove'].includes(toggle.type)) { delay = 2000; } @@ -5548,26 +896,26 @@ delay = 3000; } } else { - show = utils.hasClass(player.elements.container, player.config.classNames.hideControls); + show = utils.hasClass(this.elements.container, this.config.classNames.hideControls); } } // Clear timer every movement - window.clearTimeout(player.core.timers.hover); + window.clearTimeout(this.timers.hover); // If the mouse is not over the controls, set a timeout to hide them - if (show || player.media.paused || loading) { + if (show || this.media.paused || loading) { // Check if controls toggled - var toggled = utils.toggleClass(player.elements.container, player.config.classNames.hideControls, false); + const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, false); // Trigger event if (toggled) { - player.core.trigger(player.media, 'controlsshown'); + utils.dispatchEvent.call(this, this.media, 'controlsshown'); } // Always show controls when paused or if touch - if (player.media.paused || loading) { - return; + if (this.media.paused || loading) { + return player; } // Delay for hiding on touch @@ -5578,71 +926,104 @@ // If toggle is false or if we're playing (regardless of toggle), // then set the timer to hide the controls - if (!show || !player.media.paused) { - player.core.timers.hover = window.setTimeout(function() { + if (!show || !this.media.paused) { + this.timers.hover = window.setTimeout(() => { // If the mouse is over the controls (and not entering fullscreen), bail - if ((player.elements.controls.pressed || player.elements.controls.hover) && !isEnterFullscreen) { + if ((this.elements.controls.pressed || this.elements.controls.hover) && !isEnterFullscreen) { return; } // Check if controls toggled - var toggled = utils.toggleClass(player.elements.container, player.config.classNames.hideControls, true); + const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, true); // Trigger event and close menu if (toggled) { - player.core.trigger(player.media, 'controlshidden'); - if (utils.inArray(player.config.controls, 'settings') && !utils.is.empty(player.config.settings)) { - player.core.toggleMenu(false); + utils.dispatchEvent.call(this, this.media, 'controlshidden'); + + if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) { + controls.toggleMenu.call(this, false); } } }, delay); } - // Allow chaining - return player; - }; + return this; + } // Event listeners - Plyr.prototype.on = function(event, callback) { - var player = this; - - // Listen for events on container - utils.on(player.elements.container, event, callback); - - // Allow chaining - return player; - }; + on(event, callback) { + utils.on(this.elements.container, event, callback); - Plyr.prototype.off = function(event, callback) { - var player = this; + return this; + } - // Listen for events on container - utils.off(player.elements.container, event, callback); + off(event, callback) { + utils.off(this.elements.container, event, callback); - // Allow chaining - return player; - }; + return this; + } // Check for support - Plyr.prototype.supports = function(mimeType) { + supports(mimeType) { return support.mime(this, mimeType); - }; + } // Destroy an instance // Event listeners are removed when elements are removed // http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory - Plyr.prototype.destroy = function(callback, restore) { - var player = this; + destroy(callback, soft = false) { + const done = () => { + // Reset overflow (incase destroyed while in fullscreen) + document.body.style.overflow = ''; + + // GC for embed + this.embed = null; + + // If it's a soft destroy, make minimal changes + if (soft) { + utils.removeElement(this.elements.captions); + utils.removeElement(this.elements.controls); + utils.removeElement(this.elements.wrapper); + + // Clear for GC + this.elements.captions = null; + this.elements.controls = null; + this.elements.wrapper = null; + + // Callback + if (utils.is.function(callback)) { + callback(); + } + } else { + // Replace the container with the original element provided + const parent = this.elements.container.parentNode; + + if (utils.is.htmlElement(parent)) { + parent.replaceChild(this.elements.original, this.elements.container); + } + + // Event + utils.dispatchEvent.call(this, this.elements.original, 'destroyed', true); + + // Callback + if (utils.is.function(callback)) { + callback.call(this.elements.original); + } + + // Clear for GC + this.elements = null; + } + }; // Type specific stuff - switch (player.type) { + switch (this.type) { case 'youtube': // Clear timers - window.clearInterval(player.core.timers.buffering); - window.clearInterval(player.core.timers.playing); + window.clearInterval(this.timers.buffering); + window.clearInterval(this.timers.playing); // Destroy YouTube API - player.embed.destroy(); + this.embed.destroy(); // Clean up done(); @@ -5652,7 +1033,7 @@ case 'vimeo': // Destroy Vimeo API // then clean up (wait, to prevent postmessage errors) - player.embed.unload().then(done); + this.embed.unload().then(done); // Vimeo does not always return window.setTimeout(done, 200); @@ -5662,68 +1043,17 @@ case 'video': case 'audio': // Restore native video controls - player.core.toggleNativeControls(true); + ui.toggleNativeControls.call(this, true); // Clean up done(); break; - } - function done() { - // Bail if already destroyed - if (player === null) { - return; - } - - // Default to restore original element - if (!utils.is.boolean(restore)) { - restore = true; - } - - // Reset overflow (incase destroyed while in fullscreen) - document.body.style.overflow = ''; - - // Replace the container with the original element provided - if (restore) { - var parent = player.elements.container.parentNode; - - if (utils.is.htmlElement(parent)) { - parent.replaceChild(player.elements.original, player.elements.container); - } - } - - // Event - player.core.trigger(player.elements.original, 'destroyed', true); - - // Callback - if (utils.is.function(callback)) { - callback.call(player.elements.original); - } - - // Allow chaining - player = null; - } - }; - - // Get the duration (or custom if set) - Plyr.prototype.getDuration = function() { - var player = this; - - // It should be a number, but parse it just incase - var duration = parseInt(player.config.duration); - - // True duration - var mediaDuration = 0; - - // Only if duration available - if (player.media.duration !== null && !isNaN(player.media.duration)) { - mediaDuration = player.media.duration; + default: + break; } + } +} - // If custom duration is funky, use regular duration - return isNaN(duration) ? mediaDuration : duration; - }; - - return Plyr; -})); +export default Plyr; diff --git a/src/js/source.js b/src/js/source.js new file mode 100644 index 00000000..d2d5f61a --- /dev/null +++ b/src/js/source.js @@ -0,0 +1,162 @@ +// ========================================================================== +// Plyr source update +// ========================================================================== + +import types from './types'; +import utils from './utils'; +import media from './media'; +import ui from './ui'; +import support from './support'; + +const source = { + // Add elements to HTML5 media (source, tracks, etc) + insertElements(type, attributes) { + if (utils.is.string(attributes)) { + utils.insertElement(type, this.media, { + src: attributes, + }); + } else if (utils.is.array(attributes)) { + this.warn(attributes); + + attributes.forEach(attribute => { + utils.insertElement(type, this.media, attribute); + }); + } + }, + + // Update source + // Sources are not checked for support so be careful + change(input) { + if (!utils.is.object(input) || !('sources' in input) || !input.sources.length) { + this.warn('Invalid source format'); + return; + } + + // Cancel current network requests + media.cancelRequests.call(this); + + // Destroy instance and re-setup + this.destroy.call( + this, + () => { + // TODO: Reset menus here + + // Remove elements + utils.removeElement(this.media); + this.media = null; + + // Reset class name + if (utils.is.htmlElement(this.elements.container)) { + this.elements.container.removeAttribute('class'); + } + + // Set the type + if ('type' in input) { + this.type = input.type; + + // Get child type for video (it might be an embed) + if (this.type === 'video') { + const firstSource = input.sources[0]; + + if ('type' in firstSource && types.embed.includes(firstSource.type)) { + this.type = firstSource.type; + } + } + } + + // Check for support + this.supported = support.check(this.type, this.config.inline); + + // Create new markup + switch (this.type) { + case 'video': + this.media = utils.createElement('video'); + break; + + case 'audio': + this.media = utils.createElement('audio'); + break; + + case 'youtube': + case 'vimeo': + this.media = utils.createElement('div'); + this.embedId = input.sources[0].src; + break; + + default: + break; + } + + // Inject the new element + this.elements.container.appendChild(this.media); + + // Autoplay the new source? + if (utils.is.boolean(input.autoplay)) { + this.config.autoplay = input.autoplay; + } + + // Set attributes for audio and video + if (this.isHTML5) { + if (this.config.crossorigin) { + this.media.setAttribute('crossorigin', ''); + } + if (this.config.autoplay) { + this.media.setAttribute('autoplay', ''); + } + if ('poster' in input) { + this.media.setAttribute('poster', input.poster); + } + if (this.config.loop.active) { + this.media.setAttribute('loop', ''); + } + if (this.config.muted) { + this.media.setAttribute('muted', ''); + } + if (this.config.inline) { + this.media.setAttribute('playsinline', ''); + } + } + + // Restore class hooks + utils.toggleClass( + this.elements.container, + this.config.classNames.captions.active, + this.supported.ui && this.captions.enabled + ); + + ui.addStyleHook.call(this); + + // Set new sources for html5 + if (this.isHTML5) { + source.insertElements.call(this, 'source', input.sources); + } + + // Set video title + this.config.title = input.title; + + // Set up from scratch + media.setup.call(this); + + // HTML5 stuff + if (this.isHTML5) { + // Setup captions + if ('tracks' in input) { + source.insertElements.call(this, 'track', input.tracks); + } + + // Load HTML5 sources + this.media.load(); + } + + // If HTML5 or embed but not fully supported, setupInterface and call ready now + if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) { + // Setup interface + ui.build.call(this); + } + }, + true + ); + }, +}; + +export default source; diff --git a/src/js/storage.js b/src/js/storage.js new file mode 100644 index 00000000..0d6031be --- /dev/null +++ b/src/js/storage.js @@ -0,0 +1,56 @@ +// ========================================================================== +// Plyr storage +// ========================================================================== + +import support from './support'; +import utils from './utils'; + +// Save a value back to local storage +function set(value) { + // Bail if we don't have localStorage support or it's disabled + if (!support.storage || !this.config.storage.enabled) { + return; + } + + // Update the working copy of the values + utils.extend(this.storage, value); + + // Update storage + window.localStorage.setItem(this.config.storage.key, JSON.stringify(this.storage)); +} + +// Setup localStorage +function setup() { + let value = null; + let storage = {}; + + // Bail if we don't have localStorage support or it's disabled + if (!support.storage || !this.config.storage.enabled) { + return storage; + } + + // Clean up old volume + // https://github.com/sampotts/plyr/issues/171 + window.localStorage.removeItem('plyr-volume'); + + // load value from the current key + value = window.localStorage.getItem(this.config.storage.key); + + if (!value) { + // Key wasn't set (or had been cleared), move along + } else if (/^\d+(\.\d+)?$/.test(value)) { + // If value is a number, it's probably volume from an older + // version of this. See: https://github.com/sampotts/plyr/pull/313 + // Update the key to be JSON + set({ + volume: parseFloat(value), + }); + } else { + // Assume it's JSON from this or a later version of plyr + storage = JSON.parse(value); + } + + return storage; +} + +export default { setup, set }; diff --git a/src/js/support.js b/src/js/support.js new file mode 100644 index 00000000..78650c9f --- /dev/null +++ b/src/js/support.js @@ -0,0 +1,174 @@ +// ========================================================================== +// Plyr support checks +// ========================================================================== + +import utils from './utils'; + +// Check for feature support +const support = { + // Basic support + audio: 'canPlayType' in document.createElement('audio'), + video: 'canPlayType' in document.createElement('video'), + + // Check for support + // Basic functionality vs full UI + check(type, inline) { + let api = false; + let ui = false; + const browser = utils.getBrowser(); + const playsInline = browser.isIPhone && inline && support.inline; + + switch (type) { + case 'video': + api = support.video; + ui = api && support.rangeInput && (!browser.isIPhone || playsInline); + break; + + case 'audio': + api = support.audio; + ui = api && support.rangeInput; + break; + + case 'youtube': + api = true; + ui = support.rangeInput && (!browser.isIPhone || playsInline); + break; + + case 'vimeo': + api = true; + ui = support.rangeInput && !browser.isIPhone; + break; + + default: + api = support.audio && support.video; + ui = api && support.rangeInput; + } + + return { + api, + ui, + }; + }, + + // Local storage + // We can't assume if local storage is present that we can use it + storage: (() => { + if (!('localStorage' in window)) { + return false; + } + + // Try to use it (it might be disabled, e.g. user is in private/porn mode) + // see: https://github.com/sampotts/plyr/issues/131 + const test = '___test'; + try { + window.localStorage.setItem(test, test); + window.localStorage.removeItem(test); + return true; + } catch (e) { + return false; + } + })(), + + // Picture-in-picture support + // Safari only currently + pip: (() => { + const browser = utils.getBrowser(); + return !browser.isIPhone && utils.is.function(utils.createElement('video').webkitSetPresentationMode); + })(), + + // Airplay support + // Safari only currently + airplay: utils.is.function(window.WebKitPlaybackTargetAvailabilityEvent), + + // Inline playback support + // https://webkit.org/blog/6784/new-video-policies-for-ios/ + inline: 'playsInline' in document.createElement('video'), + + // Check for mime type support against a player instance + // Credits: http://diveintohtml5.info/everything.html + // Related: http://www.leanbackplayer.com/test/h5mt.html + mime(player, type) { + const media = { player }; + + try { + // Bail if no checking function + if (!utils.is.function(media.canPlayType)) { + return false; + } + + // Type specific checks + if (player.type === 'video') { + switch (type) { + case 'video/webm': + return media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, ''); + case 'video/mp4': + return media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''); + case 'video/ogg': + return media.canPlayType('video/ogg; codecs="theora"').replace(/no/, ''); + default: + return false; + } + } else if (player.type === 'audio') { + switch (type) { + case 'audio/mpeg': + return media.canPlayType('audio/mpeg;').replace(/no/, ''); + case 'audio/ogg': + return media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''); + case 'audio/wav': + return media.canPlayType('audio/wav; codecs="1"').replace(/no/, ''); + default: + return false; + } + } + } catch (e) { + return false; + } + + // If we got this far, we're stuffed + return false; + }, + + // Check for textTracks support + textTracks: 'textTracks' in document.createElement('video'), + + // Check for passive event listener support + // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md + // https://www.youtube.com/watch?v=NPM6172J22g + passiveListeners: (() => { + // Test via a getter in the options object to see if the passive property is accessed + let supported = false; + try { + const options = Object.defineProperty({}, 'passive', { + get() { + supported = true; + return null; + }, + }); + window.addEventListener('test', null, options); + } catch (e) { + // Do nothing + } + + return supported; + })(), + + // <input type="range"> Sliders + rangeInput: (() => { + const range = document.createElement('input'); + range.type = 'range'; + return range.type === 'range'; + })(), + + // Touch + // Remember a device can be moust + touch enabled + touch: 'ontouchstart' in document.documentElement, + + // Detect transitions support + transitions: utils.transitionEnd !== false, + + // Reduced motion iOS & MacOS setting + // https://webkit.org/blog/7551/responsive-design-for-motion/ + reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches, +}; + +export default support; diff --git a/src/js/types.js b/src/js/types.js new file mode 100644 index 00000000..1f402a9b --- /dev/null +++ b/src/js/types.js @@ -0,0 +1,10 @@ +// ========================================================================== +// Plyr supported types +// ========================================================================== + +const types = { + embed: ['youtube', 'vimeo'], + html5: ['video', 'audio'], +}; + +export default types; diff --git a/src/js/ui.js b/src/js/ui.js new file mode 100644 index 00000000..2d612cdb --- /dev/null +++ b/src/js/ui.js @@ -0,0 +1,381 @@ +// ========================================================================== +// Plyr UI +// ========================================================================== + +import utils from './utils'; +import captions from './captions'; +import controls from './controls'; +import fullscreen from './fullscreen'; +import listeners from './listeners'; +import storage from './storage'; + +const ui = { + addStyleHook() { + utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true); + utils.toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui); + }, + + // Toggle native HTML5 media controls + toggleNativeControls(toggle) { + if (toggle && this.isHTML5) { + this.media.setAttribute('controls', ''); + } else { + this.media.removeAttribute('controls'); + } + }, + + // Setup the UI + build() { + // Re-attach media element listeners + // TODO: Use event bubbling + listeners.media.call(this); + + // Don't setup interface if no support + if (!this.supported.ui) { + this.warn(`Basic support only for ${this.type}`); + + // Remove controls + utils.removeElement.call(this, 'controls'); + + // Remove large play + utils.removeElement.call(this, 'buttons.play'); + + // Restore native controls + ui.toggleNativeControls.call(this, true); + + // Bail + return; + } + + // Inject custom controls if not present + if (!utils.is.htmlElement(this.elements.controls)) { + // Inject custom controls + controls.inject.call(this); + + // Re-attach control listeners + listeners.controls.call(this); + } + + // If there's no controls, bail + if (!utils.is.htmlElement(this.elements.controls)) { + return; + } + + // Remove native controls + ui.toggleNativeControls.call(this); + + // Setup fullscreen + fullscreen.setup.call(this); + + // Captions + captions.setup.call(this); + + // Set volume + this.volume = null; + ui.updateVolume.call(this); + + // Set playback speed + this.speed = null; + + // Set loop + // this.setLoop(); + + // Reset time display + ui.timeUpdate.call(this); + + // Update the UI + ui.checkPlaying.call(this); + + this.ready = true; + + // Ready event at end of execution stack + utils.dispatchEvent.call(this, this.media, 'ready'); + + // Autoplay + if (this.config.autoplay) { + this.play(); + } + }, + + // Show the duration on metadataloaded + displayDuration() { + if (!this.supported.ui) { + return; + } + + // If there's only one time display, display duration there + if (!this.elements.display.duration && this.config.displayDuration && this.media.paused) { + ui.updateTimeDisplay.call(this, this.duration, this.elements.display.currentTime); + } + + // If there's a duration element, update content + if (this.elements.display.duration) { + ui.updateTimeDisplay.call(this, this.duration, this.elements.display.duration); + } + + // Update the tooltip (if visible) + ui.updateSeekTooltip.call(this); + }, + + // Setup aria attribute for play and iframe title + setTitle() { + // Find the current text + let label = this.config.i18n.play; + + // If there's a media title set, use that for the label + if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) { + label += `, ${this.config.title}`; + + // Set container label + this.elements.container.setAttribute('aria-label', this.config.title); + } + + // If there's a play button, set label + if (this.supported.ui) { + if (utils.is.htmlElement(this.elements.buttons.play)) { + this.elements.buttons.play.setAttribute('aria-label', label); + } + if (utils.is.htmlElement(this.elements.buttons.playLarge)) { + this.elements.buttons.playLarge.setAttribute('aria-label', label); + } + } + + // Set iframe title + // https://github.com/sampotts/plyr/issues/124 + if (this.isEmbed) { + const iframe = utils.getElement.call(this, 'iframe'); + + if (!utils.is.htmlElement(iframe)) { + return; + } + + // Default to media type + const title = !utils.is.empty(this.config.title) ? this.config.title : 'video'; + + iframe.setAttribute('title', this.config.i18n.frameTitle.replace('{title}', title)); + } + }, + + // Check playing state + checkPlaying() { + utils.toggleClass(this.elements.container, this.config.classNames.playing, !this.media.paused); + + utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.media.paused); + + this.toggleControls(this.media.paused); + }, + + // Update volume UI and storage + updateVolume() { + // Update the <input type="range"> if present + if (this.supported.ui) { + const value = this.media.muted ? 0 : this.media.volume; + + if (this.elements.inputs.volume) { + ui.setRange.call(this, this.elements.inputs.volume, value); + } + } + + // Update the volume in storage + storage.set.call(this, { + volume: this.media.volume, + }); + + // Toggle class if muted + utils.toggleClass(this.elements.container, this.config.classNames.muted, this.media.muted); + + // Update checkbox for mute state + if (this.supported.ui && this.elements.buttons.mute) { + utils.toggleState(this.elements.buttons.mute, this.media.muted); + } + }, + + // Check if media is loading + checkLoading(event) { + this.loading = event.type === 'waiting'; + + // Clear timer + clearTimeout(this.timers.loading); + + // Timer to prevent flicker when seeking + this.timers.loading = setTimeout(() => { + // Toggle container class hook + utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading); + + // Show controls if loading, hide if done + this.toggleControls(this.loading); + }, this.loading ? 250 : 0); + }, + + // Update seek value and lower fill + setRange(target, value) { + if (!utils.is.htmlElement(target)) { + return; + } + + target.value = value; + + // Webkit range fill + controls.updateRangeFill.call(this, target); + }, + + // Set <progress> value + setProgress(target, input) { + // Default to 0 + const value = !utils.is.undefined(input) ? input : 0; + const progress = !utils.is.undefined(target) ? target : this.elements.display.buffer; + + // Update value and label + if (utils.is.htmlElement(progress)) { + progress.value = value; + + // Update text label inside + const label = progress.getElementsByTagName('span')[0]; + if (utils.is.htmlElement(label)) { + label.childNodes[0].nodeValue = value; + } + } + }, + + // Update <progress> elements + updateProgress(event) { + if (!this.supported.ui) { + return; + } + + let value = 0; + + if (event) { + switch (event.type) { + // Video playing + case 'timeupdate': + case 'seeking': + value = utils.getPercentage(this.currentTime, this.duration); + + // Set seek range value only if it's a 'natural' time event + if (event.type === 'timeupdate') { + ui.setRange.call(this, this.elements.inputs.seek, value); + } + + break; + + // Check buffer status + case 'playing': + case 'progress': + value = (() => { + const { buffered } = this.media; + + if (buffered && buffered.length) { + // HTML5 + return utils.getPercentage(buffered.end(0), this.duration); + } else if (utils.is.number(buffered)) { + // YouTube returns between 0 and 1 + return buffered * 100; + } + + return 0; + })(); + + ui.setProgress.call(this, this.elements.display.buffer, value); + + break; + + default: + break; + } + } + }, + + // Update the displayed time + updateTimeDisplay(value, element) { + // Bail if there's no duration display + if (!utils.is.htmlElement(element)) { + return null; + } + + // Fallback to 0 + const time = !Number.isNaN(value) ? value : 0; + + let secs = parseInt(time % 60, 10); + let mins = parseInt((time / 60) % 60, 10); + const hours = parseInt((time / 60 / 60) % 60, 10); + + // Do we need to display hours? + const displayHours = parseInt((this.duration / 60 / 60) % 60, 10) > 0; + + // Ensure it's two digits. For example, 03 rather than 3. + secs = `0${secs}`.slice(-2); + mins = `0${mins}`.slice(-2); + + // Generate display + const display = `${(displayHours ? `${hours}:` : '') + mins}:${secs}`; + + // Render + element.textContent = display; + + // Return for looping + return display; + }, + + // Handle time change event + timeUpdate(event) { + // Duration + ui.updateTimeDisplay.call(this, this.currentTime, this.elements.display.currentTime); + + // Ignore updates while seeking + if (event && event.type === 'timeupdate' && this.media.seeking) { + return; + } + + // Playing progress + ui.updateProgress.call(this, event); + }, + + // Update hover tooltip for seeking + updateSeekTooltip(event) { + // Bail if setting not true + if ( + !this.config.tooltips.seek || + !utils.is.htmlElement(this.elements.inputs.seek) || + !utils.is.htmlElement(this.elements.display.seekTooltip) || + this.duration === 0 + ) { + return; + } + + // Calculate percentage + const clientRect = this.elements.inputs.seek.getBoundingClientRect(); + let percent = 0; + const visible = `${this.config.classNames.tooltip}--visible`; + + // Determine percentage, if already visible + if (utils.is.event(event)) { + percent = 100 / clientRect.width * (event.pageX - clientRect.left); + } else if (utils.hasClass(this.elements.display.seekTooltip, visible)) { + percent = this.elements.display.seekTooltip.style.left.replace('%', ''); + } else { + return; + } + + // Set bounds + if (percent < 0) { + percent = 0; + } else if (percent > 100) { + percent = 100; + } + + // Display the time a click would seek to + ui.updateTimeDisplay.call(this, this.duration / 100 * percent, this.elements.display.seekTooltip); + + // Set position + this.elements.display.seekTooltip.style.left = `${percent}%`; + + // Show/hide the tooltip + // If the event is a moues in/out and percentage is inside bounds + if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) { + utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter'); + } + }, +}; + +export default ui; diff --git a/src/js/utils.js b/src/js/utils.js new file mode 100644 index 00000000..e81954f4 --- /dev/null +++ b/src/js/utils.js @@ -0,0 +1,667 @@ +// ========================================================================== +// Plyr utils +// ========================================================================== + +import support from './support'; + +const utils = { + // Check variable types + is: { + object(input) { + return this.getConstructor(input) === Object; + }, + number(input) { + return this.getConstructor(input) === Number && !Number.isNaN(input); + }, + string(input) { + return this.getConstructor(input) === String; + }, + boolean(input) { + return this.getConstructor(input) === Boolean; + }, + function(input) { + return this.getConstructor(input) === Function; + }, + array(input) { + return !this.undefined(input) && Array.isArray(input); + }, + nodeList(input) { + return !this.undefined(input) && input instanceof NodeList; + }, + htmlElement(input) { + return !this.undefined(input) && input instanceof HTMLElement; + }, + event(input) { + return !this.undefined(input) && input instanceof Event; + }, + cue(input) { + return this.instanceOf(input, window.TextTrackCue) || this.instanceOf(input, window.VTTCue); + }, + track(input) { + return ( + !this.undefined(input) && (this.instanceOf(input, window.TextTrack) || typeof input.kind === 'string') + ); + }, + undefined(input) { + return input !== null && typeof input === 'undefined'; + }, + empty(input) { + return ( + input === null || + typeof input === 'undefined' || + ((this.string(input) || this.array(input) || this.nodeList(input)) && input.length === 0) || + (this.object(input) && Object.keys(input).length === 0) + ); + }, + getConstructor(input) { + if (input === null || typeof input === 'undefined') { + return null; + } + + return input.constructor; + }, + instanceOf(input, constructor) { + return Boolean(input && constructor && input instanceof constructor); + }, + }, + + // Unfortunately, due to mixed support, UA sniffing is required + getBrowser() { + return { + isIE: /* @cc_on!@ */ false || !!document.documentMode, + isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent), + isIPhone: /(iPhone|iPod)/gi.test(navigator.platform), + isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform), + }; + }, + + // Load an external script + loadScript(url) { + // Check script is not already referenced + if (document.querySelectorAll(`script[src="${url}"]`).length) { + return; + } + + const tag = document.createElement('script'); + tag.src = url; + + const firstScriptTag = document.getElementsByTagName('script')[0]; + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); + }, + + // Generate a random ID + generateId(prefix) { + return `${prefix}-${Math.floor(Math.random() * 10000)}`; + }, + + // Determine if we're in an iframe + inFrame() { + try { + return window.self !== window.top; + } catch (e) { + return true; + } + }, + + // Wrap an element + wrap(elements, wrapper) { + // Convert `elements` to an array, if necessary. + const targets = elements.length ? elements : [elements]; + + // Loops backwards to prevent having to clone the wrapper on the + // first element (see `child` below). + Array.from(targets) + .reverse() + .forEach((element, index) => { + const child = index > 0 ? wrapper.cloneNode(true) : wrapper; + + // Cache the current parent and sibling. + const parent = element.parentNode; + const sibling = element.nextSibling; + + // Wrap the element (is automatically removed from its current + // parent). + child.appendChild(element); + + // If the element had a sibling, insert the wrapper before + // the sibling to maintain the HTML structure; otherwise, just + // append it to the parent. + if (sibling) { + parent.insertBefore(child, sibling); + } else { + parent.appendChild(child); + } + }); + }, + + // Remove an element + removeElement(element) { + if (!utils.is.htmlElement(element) || !utils.is.htmlElement(element.parentNode)) { + return null; + } + + element.parentNode.removeChild(element); + + return element; + }, + + // Inaert an element after another + insertAfter(element, target) { + target.parentNode.insertBefore(element, target.nextSibling); + }, + + // Create a DocumentFragment + createElement(type, attributes, text) { + // Create a new <element> + const element = document.createElement(type); + + // Set all passed attributes + if (utils.is.object(attributes)) { + utils.setAttributes(element, attributes); + } + + // Add text node + if (utils.is.string(text)) { + element.textContent = text; + } + + // Return built element + return element; + }, + + // Insert a DocumentFragment + insertElement(type, parent, attributes, text) { + // Inject the new <element> + parent.appendChild(utils.createElement(type, attributes, text)); + }, + + // Remove all child elements + emptyElement(element) { + let { length } = element.childNodes; + + while (length > 0) { + element.removeChild(element.lastChild); + length -= 1; + } + }, + + // Set attributes + setAttributes(element, attributes) { + Object.keys(attributes).forEach(key => { + element.setAttribute(key, attributes[key]); + }); + }, + + // Get an attribute object from a string selector + getAttributesFromSelector(sel, existingAttributes) { + // For example: + // '.test' to { class: 'test' } + // '#test' to { id: 'test' } + // '[data-test="test"]' to { 'data-test': 'test' } + + if (!utils.is.string(sel) || utils.is.empty(sel)) { + return {}; + } + + const attributes = {}; + const existing = existingAttributes; + + sel.split(',').forEach(s => { + // Remove whitespace + const selector = s.trim(); + const className = selector.replace('.', ''); + const stripped = selector.replace(/[[\]]/g, ''); + + // Get the parts and value + const parts = stripped.split('='); + const key = parts[0]; + const value = parts.length > 1 ? parts[1].replace(/["']/g, '') : ''; + + // Get the first character + const start = selector.charAt(0); + + switch (start) { + case '.': + // Add to existing classname + if (utils.is.object(existing) && utils.is.string(existing.class)) { + existing.class += ` ${className}`; + } + + attributes.class = className; + break; + + case '#': + // ID selector + attributes.id = selector.replace('#', ''); + break; + + case '[': + // Attribute selector + attributes[key] = value; + + break; + + default: + break; + } + }); + + return attributes; + }, + + // Toggle class on an element + toggleClass(element, className, toggle) { + if (utils.is.htmlElement(element)) { + const contains = element.classList.contains(className); + + element.classList[toggle ? 'add' : 'remove'](className); + + return (toggle && !contains) || (!toggle && contains); + } + + return null; + }, + + // Has class name + hasClass(element, className) { + return utils.is.htmlElement(element) && element.classList.contains(className); + }, + + // Element matches selector + matches(element, selector) { + const prototype = { Element }; + + function match() { + return Array.from(document.querySelectorAll(selector)).includes(this); + } + + const matches = + prototype.matches || + prototype.webkitMatchesSelector || + prototype.mozMatchesSelector || + prototype.msMatchesSelector || + match; + + return matches.call(element, selector); + }, + + // Find all elements + getElements(selector) { + return this.elements.container.querySelectorAll(selector); + }, + + // Find a single element + getElement(selector) { + return this.elements.container.querySelector(selector); + }, + + // Find the UI controls and store references in custom controls + // TODO: Allow settings menus with custom controls + findElements() { + try { + this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper); + + // Buttons + this.elements.buttons = { + play: utils.getElements.call(this, this.config.selectors.buttons.play), + pause: utils.getElement.call(this, this.config.selectors.buttons.pause), + restart: utils.getElement.call(this, this.config.selectors.buttons.restart), + rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind), + forward: utils.getElement.call(this, this.config.selectors.buttons.forward), + mute: utils.getElement.call(this, this.config.selectors.buttons.mute), + pip: utils.getElement.call(this, this.config.selectors.buttons.pip), + airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay), + settings: utils.getElement.call(this, this.config.selectors.buttons.settings), + captions: utils.getElement.call(this, this.config.selectors.buttons.captions), + fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen), + }; + + // Progress + this.elements.progress = utils.getElement.call(this, this.config.selectors.progress); + + // Inputs + this.elements.inputs = { + seek: utils.getElement.call(this, this.config.selectors.inputs.seek), + volume: utils.getElement.call(this, this.config.selectors.inputs.volume), + }; + + // Display + this.elements.display = { + buffer: utils.getElement.call(this, this.config.selectors.display.buffer), + duration: utils.getElement.call(this, this.config.selectors.display.duration), + currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime), + }; + + // Seek tooltip + if (utils.is.htmlElement(this.elements.progress)) { + this.elements.display.seekTooltip = this.elements.progress.querySelector( + `.${this.config.classNames.tooltip}` + ); + } + + return true; + } catch (error) { + // Log it + this.warn('It looks like there is a problem with your custom controls HTML', error); + + // Restore native video controls + this.toggleNativeControls(true); + + return false; + } + }, + + // Get the focused element + getFocusElement() { + let focused = document.activeElement; + + if (!focused || focused === document.body) { + focused = null; + } else { + focused = document.querySelector(':focus'); + } + + return focused; + }, + + // Trap focus inside container + trapFocus() { + const tabbables = utils.getElements.call(this, 'input:not([disabled]), button:not([disabled])'); + const first = tabbables[0]; + const last = tabbables[tabbables.length - 1]; + + utils.on( + this.elements.container, + 'keydown', + event => { + // If it is tab + if (event.which === 9 && this.fullscreen.active) { + if (event.target === last && !event.shiftKey) { + // Move focus to first element that can be tabbed if Shift isn't used + event.preventDefault(); + first.focus(); + } else if (event.target === first && event.shiftKey) { + // Move focus to last element that can be tabbed if Shift is used + event.preventDefault(); + last.focus(); + } + } + }, + false + ); + }, + + // Bind along with custom handler + proxy(element, eventName, customListener, defaultListener, passive, capture) { + utils.on( + element, + eventName, + event => { + if (customListener) { + customListener.apply(element, [event]); + } + defaultListener.apply(element, [event]); + }, + passive, + capture + ); + }, + + // Toggle event listener + toggleListener(elements, event, callback, toggle, passive, capture) { + // Bail if no elements + if (elements === null || utils.is.undefined(elements)) { + return; + } + + // If a nodelist is passed, call itself on each node + if (elements instanceof NodeList) { + // Create listener for each node + Array.from(elements).forEach(element => { + if (element instanceof Node) { + utils.toggleListener.call(null, element, event, callback, toggle, passive, capture); + } + }); + + return; + } + + // Allow multiple events + const events = event.split(' '); + + // Build options + // Default to just capture boolean + let options = utils.is.boolean(capture) ? capture : false; + + // If passive events listeners are supported + if (support.passiveListeners) { + options = { + // Whether the listener can be passive (i.e. default never prevented) + passive: utils.is.boolean(passive) ? passive : true, + // Whether the listener is a capturing listener or not + capture: utils.is.boolean(capture) ? capture : false, + }; + } + + // If a single node is passed, bind the event listener + events.forEach(type => { + elements[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options); + }); + }, + + // Bind event handler + on(element, events, callback, passive, capture) { + utils.toggleListener(element, events, callback, true, passive, capture); + }, + + // Unbind event handler + off(element, events, callback, passive, capture) { + utils.toggleListener(element, events, callback, false, passive, capture); + }, + + // Trigger event + dispatchEvent(element, type, bubbles, properties) { + // Bail if no element + if (!element || !type) { + return; + } + + // Create and dispatch the event + const event = new CustomEvent(type, { + bubbles: utils.is.boolean(bubbles) ? bubbles : false, + detail: Object.assign({}, properties, { + plyr: this instanceof Plyr ? this : null, + }), + }); + + // Dispatch the event + element.dispatchEvent(event); + }, + + // Toggle aria-pressed state on a toggle button + // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles + toggleState(target, state) { + // Bail if no target + if (!target) { + return null; + } + + // Get state + const newState = utils.is.boolean(state) ? state : !target.getAttribute('aria-pressed'); + + // Set the attribute on target + target.setAttribute('aria-pressed', newState); + + return newState; + }, + + // Get percentage + getPercentage(current, max) { + if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) { + return 0; + } + return (current / max * 100).toFixed(2); + }, + + // Deep extend/merge destination object with N more objects + // http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/ + // Removed call to arguments.callee (used explicit function name instead) + extend(...objects) { + const { length } = objects; + + // Bail if nothing to merge + if (!length) { + return null; + } + + // Return first if specified but nothing to merge + if (length === 1) { + return objects[0]; + } + + // First object is the destination + let destination = Array.prototype.shift.call(objects); + if (!utils.is.object(destination)) { + destination = {}; + } + + // Loop through all objects to merge + objects.forEach(source => { + if (!utils.is.object(source)) { + return; + } + + Object.keys(source).forEach(property => { + if (source[property] && source[property].constructor && source[property].constructor === Object) { + destination[property] = destination[property] || {}; + utils.extend(destination[property], source[property]); + } else { + destination[property] = source[property]; + } + }); + }); + + return destination; + }, + + // Parse YouTube ID from URL + parseYouTubeId(url) { + const regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; + return url.match(regex) ? RegExp.$2 : url; + }, + + // Parse Vimeo ID from URL + parseVimeoId(url) { + if (utils.is.number(Number(url))) { + return url; + } + + const regex = /^.*(vimeo.com\/|video\/)(\d+).*/; + return url.match(regex) ? RegExp.$2 : url; + }, + + // Convert object to URL parameters + buildUrlParameters(input) { + if (!utils.is.object(input)) { + return ''; + } + + return Object.keys(input) + .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(input[key])}`) + .join('&'); + }, + + // Remove HTML from a string + stripHTML(source) { + const fragment = document.createDocumentFragment(); + const element = document.createElement('div'); + fragment.appendChild(element); + element.innerHTML = source; + return fragment.firstChild.innerText; + }, + + // Load an SVG sprite + loadSprite(url, id) { + if (typeof url !== 'string') { + return; + } + + const prefix = 'cache-'; + const hasId = typeof id === 'string'; + let isCached = false; + + function updateSprite(data) { + // Inject content + this.innerHTML = data; + + // Inject the SVG to the body + document.body.insertBefore(this, document.body.childNodes[0]); + } + + // Only load once + if (!hasId || !document.querySelectorAll(`#${id}`).length) { + // Create container + const container = document.createElement('div'); + container.setAttribute('hidden', ''); + + if (hasId) { + container.setAttribute('id', id); + } + + // Check in cache + if (support.storage) { + const cached = window.localStorage.getItem(prefix + id); + isCached = cached !== null; + + if (isCached) { + const data = JSON.parse(cached); + updateSprite.call(container, data.content); + } + } + + // ReSharper disable once InconsistentNaming + const xhr = new XMLHttpRequest(); + + // XHR for Chrome/Firefox/Opera/Safari + if ('withCredentials' in xhr) { + xhr.open('GET', url, true); + } else { + return; + } + + // Once loaded, inject to container and body + xhr.onload = () => { + if (support.storage) { + window.localStorage.setItem( + prefix + id, + JSON.stringify({ + content: xhr.responseText, + }) + ); + } + + updateSprite.call(container, xhr.responseText); + }; + + xhr.send(); + } + }, + + // Get the transition end event + transitionEnd: (() => { + const element = document.createElement('span'); + + const events = { + WebkitTransition: 'webkitTransitionEnd', + MozTransition: 'transitionend', + OTransition: 'oTransitionEnd otransitionend', + transition: 'transitionend', + }; + + const type = Object.keys(events).find(event => element.style[event] !== undefined); + + return typeof type === 'string' ? type : false; + })(), +}; + +export default utils; diff --git a/src/less/base.less b/src/less/base.less index e41874a0..c6272e11 100644 --- a/src/less/base.less +++ b/src/less/base.less @@ -7,7 +7,6 @@ position: relative; max-width: 100%; min-width: 200px; - overflow: hidden; font-family: @plyr-font-family; font-weight: @plyr-font-weight-normal; direction: ltr; diff --git a/src/less/components/controls.less b/src/less/components/controls.less index 2750de32..dc4ea8b3 100644 --- a/src/less/components/controls.less +++ b/src/less/components/controls.less @@ -58,7 +58,7 @@ border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; color: @plyr-video-control-color; - transition: all 0.4s ease-in-out; + transition: opacity 0.4s ease-in-out, transform 0.4s ease-in-out; .plyr__control { svg { diff --git a/src/less/components/embed.less b/src/less/components/embed.less index 02b33425..f6b5b307 100644 --- a/src/less/components/embed.less +++ b/src/less/components/embed.less @@ -16,6 +16,13 @@ border: 0; user-select: none; } + + // Vimeo hack + > div { + position: relative; + padding-bottom: 200%; + transform: translateY(-35.95%); + } } // To allow mouse events to be captured if full support .plyr--full-ui .plyr__video-embed iframe { diff --git a/src/less/components/sliders.less b/src/less/components/sliders.less index e2a5ffcf..b3b328e3 100644 --- a/src/less/components/sliders.less +++ b/src/less/components/sliders.less @@ -46,10 +46,8 @@ // Microsoft &::-ms-track { - height: @plyr-range-track-height; - background: transparent; - border: 0; color: transparent; + .plyr-range-track(); } &::-ms-fill-upper { diff --git a/src/less/components/video.less b/src/less/components/video.less index b68bac96..f5ff01c8 100644 --- a/src/less/components/video.less +++ b/src/less/components/video.less @@ -2,6 +2,10 @@ // Video styles // -------------------------------------------------------------- +.plyr--video { + overflow: hidden; +} + .plyr__video-wrapper { position: relative; background: #000; |