diff --git a/form/.editorconfig b/form/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..e89330a618c137cdaccde46f87923736cc04dfb4 --- /dev/null +++ b/form/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/form/.gitignore b/form/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6b772c3b1a96c53eb307155fefcf698aef757188 --- /dev/null +++ b/form/.gitignore @@ -0,0 +1,47 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc +# Only exists if Bazel was run +/bazel-out + +# dependencies +/node_modules +/publish + +# profiling files +chrome-profiler-events*.json +speed-measure-plugin*.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db diff --git a/form/README.md b/form/README.md new file mode 100644 index 0000000000000000000000000000000000000000..265f0022e807a1ed9d7be9bdc03cdb0d051190df --- /dev/null +++ b/form/README.md @@ -0,0 +1,356 @@ +# ng-template-generator + +angularjs技术框架下的H5äº’åŠ¨æ¨¡æ¿æ¡†æž¶è„šæ‰‹æž¶ï¼ŒåŸºäºŽNG-ZORRO实现快速开å‘基于绘玩云的H5互动课件。 + +# 使用简介 + +## 剿œŸå‡†å¤‡ + +* git下载 https://git-scm.com/downloads +* nodejs下载 https://nodejs.org/zh-cn/download/ +* è°·æŒæµè§ˆå™¨ä¸‹è½½ https://www.google.cn/chrome/ + +都下载最新版就行,然åŽé»˜è®¤å®‰è£…å°±å¯ä»¥ + + +## 生æˆé¡¹ç›® + +* 登录绘玩云课件开å‘å¹³å°ï¼šhttp://staging-teach.ireadabc.com/ +* 点击“登录账å·ï¼ŒæŸ¥çœ‹æˆ‘的课件†+* 输入测试的用户å/密ç :developers/12345678 +* 在å³ä¸Šè§’“个人ä¸å¿ƒâ€çš„下拉èœå•里,点击“我的模æ¿â€ èœå•,然åŽç‚¹å‡»â€œæ–°å»ºæ¨¡æ¿â€, 填写必è¦çš„ä¿¡æ¯ï¼Œåœ¨â€œæŠ€æœ¯é€‰åž‹â€ä¸€é¡¹ä¸Šé€‰æ‹©â€œAngular†+* 点击“确定â€åŽï¼Œåˆ—表页就会出现一个新生æˆçš„æ¨¡æ¿é¡¹ç›® +* 在项目的å¡ç‰‡ä¸‹æ‰¾åˆ°â€œå¼€å‘â€æŒ‰é’®ï¼Œåˆ™ä¼šå¼¹å‡ºç›¸å¯¹åº”çš„gitåœ°å€ + +## 获å–å¹¶å¯åŠ¨é¡¹ç›® + +``` +// xxx 是上é¢é¡¹ç›®å¯¹åº”çš„Gitåœ°å€ +git clone xxx +cd 项目åç§°/ +npm install -g yarn +yarn install +npm start + +//å¯åЍæˆåŠŸåŽæ‰“å¼€æµè§ˆå™¨ï¼Œè¾“入:http://localhost:4200 则å¯ä»¥çœ‹åˆ°è¿™ä¸ªé¡¹ç›®çš„åˆå§‹åŒ–效果了 + +``` + +## 项目结构 + +|-- bin + +|-- dist + +|-- e2e + +|-- node_modules + +|-- publish + +|-- src + +| |-- app + +| | |-- common + +| | |-- form + +| | |-- pipes + +| | |-- play + +| | |-- services + +| | |-- style + +| | |-- app.component.html + +| | |-- app.component.scss + +| | |-- app.component.ts + +| | |-- app.module.ts + +| |-- assets + +| |-- environments + +| |-- services + +| |-- index.html + +| |-- main.ts + +| |--....... + + + +* å…¶ä¸ play 文件夹是H5模æ¿å±•示页é¢ï¼Œform文件夹是模æ¿çš„é…ç½®é¡µé¢ +* common文件夹是以往åšè¿‡çš„æ¨¡æ¿ç§¯ç´¯çš„一些比较常用的 AngularJs 的组件 +* assetsæ–‡ä»¶å¤¹å˜æ”¾æ¨¡æ¿æ ·å¼çš„陿€èµ„æºï¼Œä¾‹å¦‚å°å›¾æ ‡ã€èƒŒæ™¯å›¾ç‰‡ã€å—ä½“ã€æ ·å¼ç‰ç‰ +* 其他文件夹开å‘者å¯ä»¥ä¸åšä»»ä½•更改 + +## å¼€å§‹å¼€å‘ + +本脚手架的页é¢ç±»UI框架是基于 [NG-ZORRO](https://ng.ant.design/docs/introduce/zh "With a Title") 框架实现的,在é…置页é¢ï¼ˆform文件夹),一些表å•è¾“å…¥ï¼Œä¸Šä¼ å›¾ç‰‡ç‰ç»„件也å¯ä»¥ä½¿ç”¨ NG-ZORRO 现æˆçš„组件 + +### å¼€å‘é…置页é¢ï¼ˆform/) + +é…置页é¢ä¸»è¦ä½œç”¨æ˜¯ä¸ºäº†å‘ˆçŽ°å¤šæ ·åŒ–æ¨¡æ¿ï¼Œæé«˜H5模æ¿çš„高å¤ç”¨æ€§ã€çµæ´»æ€§æä¾›çš„一个é…ç½®å·¥å…·ï¼Œæ ¹æ®H5模æ¿çš„设计规划或特性,会规定æŸäº›å…ƒç´ 是å¯ä»¥é…置的,比如背景图片ã€éŸ³é¢‘ã€é€‰é¡¹ã€æ ‡é¢˜ç‰ç‰ç‰ç‰ã€‚(课件制作者) 通过é…置页é¢ï¼Œå°±å¯ä»¥çµæ´»çš„æ›´æ¢è¿™äº›ï¼Œä»Žè€Œå½¢æˆå¤šç§å¤šæ ·çš„课件。 + + +é…置页é¢çš„å¼€å‘è¦æ±‚很简å•,我们ä¸å…³å¿ƒå¸ƒå±€ã€æ ·å¼ã€äº¤äº’ç‰æ‰€æœ‰å®žçŽ°ç»†èŠ‚ä¸Žæ•ˆæžœï¼Œåªéœ€è°ƒç”¨ä¸¤ä¸ªå†…置的全局接å£å³å¯ï¼š + +* setData 接å£ï¼Œç”¨äºŽå°†é…置的数æ®å˜å‚¨åˆ°äº‘端。 + + æ¤æ–¹æ³•是一个异æ¥çš„æ–¹æ³•,接收三个必è¦å‚æ•° + + obj: 一个json对象 + + callback: 回调函数 + + t_name: 模æ¿åç§° + + 一般使用例å如下: + + ``` + // tsè¯æ³•,ä¸èƒ½ç›´æŽ¥ä½¿ç”¨jsçš„window对象自定义方法 + (<any> window).courseware.setData(obj, callback, t_name); + ``` + +* getData 接å£ï¼Œç”¨äºŽå½“点击修改的时候将é…置的数æ®ä»Žäº‘端获å–下æ¥ã€‚ + + æ¤æ–¹æ³•是一个异æ¥çš„æ–¹æ³•,接收两个必è¦å‚æ•° + + > callback: 回调函数, 回调函数里会得到云端ä¿å˜çš„æ•°æ® + + > t_name: 模æ¿åç§° + + 一般使用例å如下: + + ``` + // tsè¯æ³•,ä¸èƒ½ç›´æŽ¥ä½¿ç”¨jsçš„window对象自定义方法 + const getData = (<any> window).courseware.getData; + getData((data) => { + //data 就是云端获å–的数æ®ï¼Œä¹Ÿå°±æ˜¯setData方法å˜åˆ°äº‘端的那个obj + //模æ¿å¼€å‘è€…éœ€è¦æ ¹æ®æ•°æ®ï¼Œä¾æ¬¡å¡«å†™åˆ°è¡¨å•的相应ä½ç½®ï¼Œæ–¹ä¾¿ç”¨æˆ·äºŒæ¬¡ä¿®æ”¹ç¼–辑 + }); + ``` + +### å¼€å‘展示页é¢ï¼ˆplay/) + +展示页é¢ä¸»è¦æ˜¯å‘ˆçŽ°æ¨¡æ¿ï¼Œé€šè¿‡H5æŠ€æœ¯ï¼Œå®žçŽ°å¤šæ ·åŒ–çš„äº¤äº’ä¸Žå±•ç¤ºæ–¹å¼ã€‚ + + +å±•ç¤ºé¡µé¢æ›´ç®€å•,开å‘者å¯ä»¥è¿ç”¨å„ç§æŠ€æœ¯ï¼Œå®žçŽ°Web端å¯ä»¥å®žçŽ°çš„ä»»ä½•æ•ˆæžœï¼ŒåŒ…æ‹¬2Dã€3Dã€åŠ¨ç”»ã€æ¸¸æˆç‰å„ç§åœºæ™¯ï¼ŒæŠŠè¡¨å•é…置的数æ®èŽ·å–到,用于渲染相对应的页é¢å³å¯ï¼š + +* getData 接å£ï¼Œç”¨äºŽå½“点击修改的时候将é…置的数æ®ä»Žäº‘端获å–下æ¥ã€‚ + + æ¤æ–¹æ³•是一个异æ¥çš„æ–¹æ³•,接收两个必è¦å‚æ•° + + > callback: 回调函数, 回调函数里会得到云端ä¿å˜çš„æ•°æ® + + > t_name: 模æ¿åç§° + + 一般使用例å如下: + + ``` + // tsè¯æ³•,ä¸èƒ½ç›´æŽ¥ä½¿ç”¨jsçš„window对象自定义方法 + const getData = (<any> window).courseware.getData; + getData((data) => { + //data 就是云端获å–的数æ®ï¼Œä¹Ÿå°±æ˜¯setData方法å˜åˆ°äº‘端的那个obj + //模æ¿å¼€å‘è€…éœ€è¦æ ¹æ®æ•°æ®æ¥æ¸²æŸ“或控制展示页é¢çš„呈现,达到模æ¿çš„互动目的 + }); + ``` + + ### 互动课件 + + 通过H5的交互方å¼ï¼Œæˆ‘们å¯ä»¥å¾ˆè½»æ¾çš„制作在线的互动课件,使è€å¸ˆç«¯ä¸Žå¦ç”Ÿç«¯å®žçްè”åŠ¨ï¼Œä½¿åœ¨çº¿è¯¾å ‚æ›´å…·æœ‰äº¤äº’æ€§ã€‚ + + * onEvent å®šä¹‰äº‹ä»¶ï¼šç”¨äºŽè‡ªå®šä¹‰åŒæ¥äº‹ä»¶ï¼Œé…åˆå¤šç«¯äº’动使用,与sendEvent方法é…åˆä½¿ç”¨ï¼Œç”¨äºŽç›‘å¬å¤šç«¯å‘é€çš„åŒæ¥äº‹ä»¶ + + 傿•° + + > evtName : 自定义事件的åç§° + + > callback : å›žè°ƒå‡½æ•°ï¼Œå›žè°ƒå‡½æ•°é‡Œä¼šå¾—åˆ°ä¼ è¿‡æ¥çš„æ•°æ® + + 使用例å: + + ``` + const cw = (<any> window).courseware; + //订阅一个事件 + cw.onEvent('testEvent', (data,next) => { + console.log(data); + //处ç†äº‹ä»¶çš„åŒæ¥é€»è¾‘ + + //在逻辑处ç†å®Œä¹‹åŽä¸€å®šè¦æ‰§è¡Œnext方法,用于解é”事件队列 + next(); + }); + ``` + + * sendEvent å‘é€äº‹ä»¶ï¼šç”¨äºŽè‡ªå®šä¹‰åŒæ¥äº‹ä»¶ï¼Œé…åˆå¤šç«¯äº’动使用,与onEvent方法é…åˆä½¿ç”¨ï¼Œç”¨äºŽå¯¹ç«¯å‘é€åŒæ¥äº‹ä»¶ + + 傿•° + + > evtName : 自定义事件的åç§° + + > data : ä¼ é€’çš„å‚æ•° + + 使用例å: + + ``` + const cw = (<any> window).courseware; + //å‘é€äº‹ä»¶ + //è¿™æ ·ï¼Œæ‰€æœ‰ç«¯ï¼ˆæ•™å¸ˆã€å¦ç”Ÿï¼‰ éƒ½ä¼šè§¦å‘ testEvent 方法 + cw.sendEvent('testEvent', 'Hello world'); + + ``` + + * storeAspect å˜å‚¨åˆ‡é¢æ•°æ®ï¼š 课件的切é¢çŠ¶æ€æ•°æ®ï¼›äº’åŠ¨è¯¾ä»¶éœ€è¦æ¯ä¸€ä¸ªå¼€å‘者设计切é¢çжæ€ï¼Œç”¨äºŽå¦ç”Ÿè¿›å…¥å·²ç»è¿›è¡Œçš„课件,æ¢å¤è¯¾ä»¶åŒæ¥ã€‚例如è€å¸ˆè®²å›¾ç‰‡è½®æ’到第四页,这个时候å¦ç”Ÿè¿›å…¥æ•™å¸ˆï¼Œè¦æ¢å¤åˆ°ç¬¬å››é¡µï¼Œæ‰èƒ½è·Ÿè€å¸ˆåŒæ¥ä¸Šè¯¾ã€‚ + + 傿•° + + > data : ä¿å˜çš„æ•°æ®ï¼Œä¸€ä¸ªJSON对象 + + 使用例å: + + ``` + const cw = (<any> window).courseware; + //å˜å‚¨åˆ‡é¢æ•°æ®ï¼Œç”¨äºŽå¦ç”Ÿè¿›å…¥æ•™å®¤ï¼ŒåŒæ¥è¯¾å ‚ä¿¡æ¯ç‰ + cw.storeAspect({page: 5}); + ``` + + * getAspect 获å–åˆ‡é¢æ•°æ®ï¼š 课件的切é¢çŠ¶æ€æ•°æ®ï¼›äº’åŠ¨è¯¾ä»¶éœ€è¦æ¯ä¸€ä¸ªå¼€å‘者设计切é¢çжæ€ï¼Œç”¨äºŽå¦ç”Ÿè¿›å…¥å·²ç»è¿›è¡Œçš„课件,æ¢å¤è¯¾ä»¶åŒæ¥ã€‚例如è€å¸ˆè®²å›¾ç‰‡è½®æ’到第四页,这个时候å¦ç”Ÿè¿›å…¥æ•™å¸ˆï¼Œè¦æ¢å¤åˆ°ç¬¬å››é¡µï¼Œæ‰èƒ½è·Ÿè€å¸ˆåŒæ¥ä¸Šè¯¾ã€‚ + + 傿•° + + > callback : 获å–åˆ‡é¢æ•°æ®çš„回调函数 + + 使用例å: + + ``` + const cw = (<any> window).courseware; + //å˜å‚¨åˆ‡é¢æ•°æ®ï¼Œç”¨äºŽå¦ç”Ÿè¿›å…¥æ•™å®¤ï¼ŒåŒæ¥è¯¾å ‚ä¿¡æ¯ç‰ + cw.getAspect(function(aspect){ + //æ¢å¤åˆ‡é¢çжæ€çš„逻辑 + }); + ``` + + * 补充项 + + 1) æœ‰æ—¶å€™æˆ‘ä»¬åœ¨å®žçŽ°æ¨¡æ¿æ•ˆæžœçš„æ—¶å€™ï¼Œéœ€è¦ä¸€äº›åŸºæœ¬çš„ä¿¡æ¯ï¼Œæ¯”如教室信æ¯ã€å½“å‰ç”¨æˆ·ä¿¡æ¯ç‰ç‰ï¼Œä¾‹å¦‚,è€å¸ˆä¼šæ˜¾ç¤ºæŸä¸ªæŒ‰é’®ï¼Œè€Œå¦ç”Ÿä¸æ˜¾ç¤ºï¼Œæˆ‘们å¯ä»¥ç”¨å¦‚下方å¼èŽ·å–æ•™å®¤ä¿¡æ¯ï¼›åŽç»å¤§éƒ¨åˆ†é™æ€ä¿¡æ¯éƒ½ä¼šå®Œå–„到这个对象里 + + ``` + //èŽ·å–æ•™å®¤ä¿¡æ¯ï¼Œå€¼å¾—注æ„的是获å–这个信æ¯ä¸€å®šè¦å† getData方法之åŽï¼Œæˆ–者确ä¿é¡µé¢å®Œæˆä¹‹åŽ + getData((data, aspect) => { + let airClassInfo = window["air"].airClassInfo; + console.log(airClassInfo); + }); + ``` + + 2) 互动课件的 getData 方法的回调函数里多返回了一个切é¢å‚数,类似如下: + + ``` + const getData = (<any> window).courseware.getData; + getData((data, aspect) => { + //data 就是云端获å–的数æ®ï¼Œä¹Ÿå°±æ˜¯setData方法å˜åˆ°äº‘端的那个obj + //aspect 切é¢å‚数,用于æ¢å¤é¡µé¢çš„çŠ¶æ€ + //模æ¿å¼€å‘è€…éœ€è¦æ ¹æ®æ•°æ®æ¥æ¸²æŸ“或控制展示页é¢çš„呈现,达到模æ¿çš„互动目的 + }); + ``` + + 3) 一些必è¦çš„内置事件,通过监å¬è¿™äº›äº‹ä»¶ï¼Œæˆ‘们å¯ä»¥å®žçŽ°ä¸€äº›ç›¸å…³çš„åŠŸèƒ½ + + * userchange 事件,用æ¥ç›‘嬿•™å®¤å†…部的人员å˜åŠ¨æƒ…å†µï¼Œä¾‹å¦‚æŸäººè¿›å…¥ï¼ŒæŸäººé€€å‡ºéƒ½ä¼šè§¦å‘æ¤äº‹ä»¶ + + 示例: + + ``` + const cw = (<any> window).courseware; + //订阅一个事件 + cw.onEvent('userchange', (data,next) => { + //data的结构如下 + /*{ + * id: 'å˜åŠ¨ç”¨æˆ·çš„ID', + * connected: true/false, true: 连接的,false:dæ–开的 + * status: 'connect/reconnect', connect:新建连接,reconnect:釿–°è¿žæŽ¥ï¼›è¿™ä¸ªå—段在æ–开连接的事件里是缺失的 + * all_user: [] 这个是现有的用户列表 + *} + */ + console.log(data); + //处ç†äº‹ä»¶çš„åŒæ¥é€»è¾‘ + + //在逻辑处ç†å®Œä¹‹åŽä¸€å®šè¦æ‰§è¡Œnext方法,用于解é”事件队列 + next(); + }); + + ``` + + 4) 测试互动课件 + + 我们在本地开å‘ä¸ï¼Œæ— 法模拟线上è€å¸ˆå’Œå¦ç”Ÿäº’动的交互场景,所以æä¾›äº†ä¸€å¥—å¼€å‘者测试的账å·ï¼Œå¦‚下: + + 测试地å€ï¼šhttp://staging-ac.ireadabc.com/ + + è€å¸ˆç”¨æˆ·å/密ç :devtea / 1 + + å¦ç”Ÿç”¨æˆ·å/密ç : å¦ç”Ÿ1(13877777711 / 1) å¦ç”Ÿ2(13877777712 / 1) + + + 测试方法: + + 1ã€é¦–先开å‘者å‘布完模æ¿ä¹‹åŽï¼Œåœ¨åˆ¶ä½œè¯¾ä»¶çš„èœå•下用这个模æ¿åˆ¶ä½œä¸€ä¸ªè¯¾ä»¶ + + 2ã€åœ¨æœ¬åœ°æ‰“开两个æµè§ˆå™¨çª—å£ ä¸€ä¸ªç™»é™†è€å¸ˆç”¨æˆ·ï¼Œå¦ä¸€ä¸ªç™»é™†å¦ç”Ÿç”¨æˆ· + + 3ã€è€å¸ˆç”¨æˆ·è¿›å޻之åŽï¼Œå°±ä¼šæœ‰å¾ˆå¤šè¯¾ä»¶ï¼Œè¿™ä¸ªæ—¶å€™åŒå‡»è‡ªå·±åˆ¶ä½œçš„课件,å¦ç”Ÿçš„窗å£å°±ä¼šåŒæ¥çš„æ‰“开课件了 + + 4ã€æµ‹è¯•自己的交互事件,看看è€å¸ˆç«¯å’Œå¦ç”Ÿç«¯æ˜¯å¦æ˜¯è‡ªå·±æƒ³è¦çš„展示效果 + + + + ### 补充方法 + + 在模æ¿çš„编辑或展示过程ä¸ï¼Œè¿˜ä¼šç»å¸¸é‡åˆ°å¦‚下两个场景,特æä¾›é’ˆå¯¹æ€§çš„解决办法 + + 1) 表å•录入往往需è¦ä¸Šä¼ 图片ã€éŸ³è§†é¢‘ç‰å¤šåª’体文件,所以脚手架内置如下方法,用于获å–ä¸€ä¸ªä¸Šä¼ åˆ°äº‘ç«¯çš„æŽ¥å£æ–¹æ³• + + ``` + const uploadUrl = (<any> window).courseware.uploadUrl; + const uploadData = (<any> window).courseware.uploadData; + + //例如用于NG-ZORROçš„ä¸Šä¼ ç»„ä»¶åˆ™å¦‚ä¸‹å†™æ³•ï¼š + <nz-upload class="p-image-uploader" [nzDisabled]="disableUpload" + [nzShowUploadList]="false" + nzAccept = "image/*" + [nzAction]="uploadUrl" <!-- 注æ„这里 --> + [nzData]="uploadData" <!-- 注æ„这里 --> + (nzChange)="handleChange($event)"> + </nz-upload> + + ``` + + 2) 在展示页é¢åŠ è½½å®Œæˆçš„æ—¶å€™ï¼Œéœ€è¦è°ƒç”¨ä¸€ä¸‹ä¸‹é¢çš„æ–¹æ³•,用于释放切æ¢è¯¾ä»¶çš„é®ç½©å±‚ + + ``` + //æ¤æ–¹æ³•为固定写法, + //å…¶ä¸t_name为模æ¿å称,obj是云端å˜å‚¨çš„é…ç½®æ•°æ® + window["air"].hideAirClassLoading(t_name,obj); + ``` + + + ## 打包å‘布 + + 模æ¿å¼€å‘完æˆä¹‹åŽï¼Œè¦æŽ¨é€åˆ°äº‘å¹³å°ä¸Šä½¿ç”¨åˆ™éœ€è¦è¿›è¡Œæ‰“包å‘布æ“作 + + ``` + npm run publish + ``` + åœ¨é¡¹ç›®æ ¹ç›®å½•ä¸‹æ‰§è¡Œä¸Šè¿°å‘½ä»¤ï¼Œåˆ™åœ¨ ./publish 目录下生产一个 .zipçš„åŽ‹ç¼©åŒ…ï¼Œæ¤æ—¶æ‰“å¼€äº‘å¹³å° + http://staging-teach.ireadabc.com/ + 点击“模æ¿ç®¡ç†â€ èœå•,找到对应的模æ¿å¡ç‰‡ï¼Œç‚¹å‡»â€œå‘å¸ƒâ€æŒ‰é’®ï¼Œåœ¨å¼¹å‡ºçš„å¯¹è¯æ¡†ä¸é€‰ä¸åŽ‹ç¼©åŒ…ï¼Œç„¶åŽç‚¹å‡»â€œç¡®å®šâ€ï¼Œä¸Šä¼ 完æˆåŽï¼Œåˆ™å‘布就æˆåŠŸäº† + + + \ No newline at end of file diff --git a/form/angular.json b/form/angular.json new file mode 100644 index 0000000000000000000000000000000000000000..5952480a9ced5a16dc48a17e46fb1669d4e89426 --- /dev/null +++ b/form/angular.json @@ -0,0 +1,132 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "ng-template-generator": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/ng-template-generator", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "aot": true, + "assets": [ + "src/favicon.ico", + "src/assets", + { + "glob": "**/*", + "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", + "output": "/assets/" + } + ], + "styles": [ + "./node_modules/ng-zorro-antd/ng-zorro-antd.min.css", + "src/styles.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb", + "maximumError": "10kb" + } + ] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "ng-template-generator:build" + }, + "configurations": { + "production": { + "browserTarget": "ng-template-generator:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "ng-template-generator:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "./node_modules/ng-zorro-antd/ng-zorro-antd.min.css", + "src/styles.css" + ], + "scripts": [] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "tsconfig.app.json", + "tsconfig.spec.json", + "e2e/tsconfig.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + }, + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "ng-template-generator:serve" + }, + "configurations": { + "production": { + "devServerTarget": "ng-template-generator:serve:production" + } + } + } + } + } + }, + "defaultProject": "ng-template-generator" +} diff --git a/form/bin/publish.js b/form/bin/publish.js new file mode 100644 index 0000000000000000000000000000000000000000..6a7490ec42146a10a2ca12acffe1952cce456914 --- /dev/null +++ b/form/bin/publish.js @@ -0,0 +1,114 @@ +/**** + * 批é‡ç¼–译打包模æ¿å·¥å…· + * è¿è¡Œ npm run publish T_01 å‘½ä»¤æ¥æ‰“包T_01æ¨¡æ¿ + * è¿è¡Œ npm run publish T_01,T_02,T_03,T_04 命令æ¥åˆ†åˆ«æ‰“包 T_01,T_02,T_03,T_04 这四个模æ¿ï¼Œæ³¨æ„逗å·è¦ç”¨è‹±æ–‡çš„ + * è¿è¡Œ npm run publish all å‘½ä»¤æ¥æ‰“åŒ…æ‰€æœ‰æ¨¡æ¿ + */ + +const spawn = require('child_process').spawn; +const path = require("path"); +const fs = require("fs"); +const os = require('os'); +const compressing = require("compressing"); + +//Linux系统上'Linux' +//macOS 系统上'Darwin' +//Windows系统上'Windows_NT' +let sysType = os.type(); + +Date.prototype.Format = function(fmt) { + var o = { + "M+" : this.getMonth() + 1, + "d+" : this.getDate(), + "h+" : this.getHours(), + "m+" : this.getMinutes(), + "s+" : this.getSeconds(), + "q+" : Math.floor((this.getMonth() + 3) / 3), + "S" : this.getMilliseconds() + }; + if (/(y+)/.test(fmt)) + fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); + for (var k in o) + if (new RegExp("(" + k + ")").test(fmt)) + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); + return fmt; +} + +function clean(zipPath){ + if(fs.existsSync(zipPath)){ + fs.unlinkSync(zipPath); + } +} + +const runSpawn = async function (){ + + await new Promise(function(resolve,reject){ + + let pkg = require("../package.json"); + + let ls; + if(sysType==="Windows_NT"){ + //ng build --prod --build--optimizer --base-href /ng-one/ + ls = spawn("cmd.exe", ['/c', 'ng', 'build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/'] ); + }else{ + ls = spawn("ng", ['build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/'] ); + } + + ls.stdout.on('data', (data) => { + console.log(` ${data}`); + }); + + ls.stderr.on('data', (data) => { + console.log(`stderr: ${data}`); + reject(); + }); + + ls.on('close', (code) => { + console.log(`child process exited with code ${code}`); + //è¦åŽ‹ç¼©çš„ç›®å½• + let zippath = path.resolve(__dirname,"../dist", pkg.name); + //åŽ‹ç¼©åŒ…çš„å˜æ”¾ç›®å½• + let date = new Date(); + let zipname = pkg.name+"_"+date.Format("yyyyMMdd hh-mm-ss"); + let zipdir = path.resolve(__dirname,"../publish/"+zipname+".zip"); + clean(zipdir); //åˆ é™¤åŽŸæœ‰çš„åŒ… + + const tarStream = new compressing.zip.Stream(); + fs.readdir(zippath,function(err,files){ + if(err){ + console.log("======文件打开异常======"); + console.log(err); + reject(); + } + for(let i=0;i<files.length;i++){ + tarStream.addEntry(zippath+"/"+files[i]); + } + let writeStream = fs.createWriteStream(zipdir); + tarStream.pipe(writeStream); + writeStream.on('close', () => { + console.log(`æ¨¡æ¿ ${pkg.name} 打包已完æˆï¼`); + resolve(); + }) + }); + + }); + + }); +} + +// let projects = ""; +// if(process.argv.length<3){ +// console.log("ç¼ºå°‘å‚æ•°"); +// return; +// } +// projects = process.argv[2]; + +let exec = async function(){ + //åŽ‹ç¼©æ¨¡æ¿ + await runSpawn(); +} + +exec(); + + + diff --git a/form/browserslist b/form/browserslist new file mode 100644 index 0000000000000000000000000000000000000000..80848532e47d58cc7a4b618f600b438960f9f045 --- /dev/null +++ b/form/browserslist @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/form/e2e/protractor.conf.js b/form/e2e/protractor.conf.js new file mode 100644 index 0000000000000000000000000000000000000000..73e4e6806cd6b451dc89181ce574c386c6c837da --- /dev/null +++ b/form/e2e/protractor.conf.js @@ -0,0 +1,32 @@ +// @ts-check +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +/** + * @type { import("protractor").Config } + */ +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; \ No newline at end of file diff --git a/form/e2e/src/app.e2e-spec.ts b/form/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..88795455ca1701631269349ec710f974f5246262 --- /dev/null +++ b/form/e2e/src/app.e2e-spec.ts @@ -0,0 +1,23 @@ +import { AppPage } from './app.po'; +import { browser, logging } from 'protractor'; + +describe('workspace-project App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getTitleText()).toEqual('Welcome to ng-one!'); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain(jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry)); + }); +}); diff --git a/form/e2e/src/app.po.ts b/form/e2e/src/app.po.ts new file mode 100644 index 0000000000000000000000000000000000000000..5776aa9eb80d8e5ad05ed75ec9a04e7ee5060ba9 --- /dev/null +++ b/form/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get(browser.baseUrl) as Promise<any>; + } + + getTitleText() { + return element(by.css('app-root h1')).getText() as Promise<string>; + } +} diff --git a/form/e2e/tsconfig.json b/form/e2e/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..39b800f789619f0fb8063aba2e05bd5a57850e57 --- /dev/null +++ b/form/e2e/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} diff --git a/form/karma.conf.js b/form/karma.conf.js new file mode 100644 index 0000000000000000000000000000000000000000..4a9333c426e179201c431f16b2f2ea26cee7fc77 --- /dev/null +++ b/form/karma.conf.js @@ -0,0 +1,32 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, './coverage/ng-one'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/form/package-lock.json b/form/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..b03c7c395da22a8bfc5e118dd25816b146931901 --- /dev/null +++ b/form/package-lock.json @@ -0,0 +1,12897 @@ +{ + "name": "ng-template-generator", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.900.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.900.7.tgz", + "integrity": "sha512-hfiTVYc72kzbXrzK4tea6jnTDnSKpE1D+vEptBXN2tdXEVNEAQI5Qm5L1zVDtt16UdqoUTUypIgUc9jcNH1mUQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.7", + "rxjs": "6.5.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/build-angular": { + "version": "0.900.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.900.7.tgz", + "integrity": "sha512-Yv2y3OEaYEd0fE0pKvtqBpmkQYs9xJws7thHnJYCwIfYO55RfolYsXkJgAXke/4NPLrD3EsIDqoPxF7l+uw2/Q==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.900.7", + "@angular-devkit/build-optimizer": "0.900.7", + "@angular-devkit/build-webpack": "0.900.7", + "@angular-devkit/core": "9.0.7", + "@babel/core": "7.7.7", + "@babel/generator": "7.7.7", + "@babel/preset-env": "7.7.7", + "@ngtools/webpack": "9.0.7", + "ajv": "6.10.2", + "autoprefixer": "9.7.1", + "babel-loader": "8.0.6", + "browserslist": "^4.9.1", + "cacache": "13.0.1", + "caniuse-lite": "^1.0.30001032", + "circular-dependency-plugin": "5.2.0", + "copy-webpack-plugin": "5.1.1", + "core-js": "3.6.4", + "coverage-istanbul-loader": "2.0.3", + "cssnano": "4.1.10", + "file-loader": "4.2.0", + "find-cache-dir": "3.0.0", + "glob": "7.1.5", + "jest-worker": "24.9.0", + "karma-source-map-support": "1.4.0", + "less": "3.10.3", + "less-loader": "5.0.0", + "license-webpack-plugin": "2.1.3", + "loader-utils": "1.2.3", + "magic-string": "0.25.4", + "mini-css-extract-plugin": "0.8.0", + "minimatch": "3.0.4", + "open": "7.0.0", + "parse5": "4.0.0", + "postcss": "7.0.21", + "postcss-import": "12.0.1", + "postcss-loader": "3.0.0", + "raw-loader": "3.1.0", + "regenerator-runtime": "0.13.3", + "rimraf": "3.0.0", + "rollup": "1.25.2", + "rxjs": "6.5.3", + "sass": "1.23.3", + "sass-loader": "8.0.0", + "semver": "6.3.0", + "source-map": "0.7.3", + "source-map-loader": "0.2.4", + "source-map-support": "0.5.16", + "speed-measure-webpack-plugin": "1.3.1", + "style-loader": "1.0.0", + "stylus": "0.54.7", + "stylus-loader": "3.0.2", + "terser": "4.5.1", + "terser-webpack-plugin": "2.3.3", + "tree-kill": "1.2.2", + "webpack": "4.41.2", + "webpack-dev-middleware": "3.7.2", + "webpack-dev-server": "3.9.0", + "webpack-merge": "4.2.2", + "webpack-sources": "1.4.3", + "webpack-subresource-integrity": "1.3.4", + "worker-plugin": "3.2.0" + }, + "dependencies": { + "glob": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", + "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "@angular-devkit/build-optimizer": { + "version": "0.900.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.900.7.tgz", + "integrity": "sha512-gxin2oPNMN+PYo82At2JP1Q+uxnvwyDFWA1Wl+Ufuc5zHGhjKqxdQjkdMF7OT0ihtmkllN+t/NTB7rcx/Sx9Wg==", + "dev": true, + "requires": { + "loader-utils": "1.2.3", + "source-map": "0.7.3", + "tslib": "1.10.0", + "typescript": "3.6.4", + "webpack-sources": "1.4.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "typescript": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", + "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", + "dev": true + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.900.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.900.7.tgz", + "integrity": "sha512-Nwwqjo1ZpHFLavN+nXOmuBgGjhoMBZGelDCvHtiQlQ9N6i7k9cKnP7eU5pY7jbalBguS+gWg5wJIGnbqk1K9Rg==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.900.7", + "@angular-devkit/core": "9.0.7", + "rxjs": "6.5.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/core": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.0.7.tgz", + "integrity": "sha512-tMrz36sM1xrwvFf9Qm59GwALscVlMP7rQBjtd0fIR/QbsiOAIX4AQbV+vN6Vtwnzo5NIRZY1IXJUhesWms+h5w==", + "dev": true, + "requires": { + "ajv": "6.10.2", + "fast-json-stable-stringify": "2.0.0", + "magic-string": "0.25.4", + "rxjs": "6.5.3", + "source-map": "0.7.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "@angular-devkit/schematics": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-9.0.7.tgz", + "integrity": "sha512-ryPC+l24f3gX5DFMTLkDM/q2Kp6LPzBn6400k7j4qVdb1cIrZx+JUQd7F4iAksTTkX15EQPanptQXeztUrl9Ng==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.7", + "ora": "4.0.2", + "rxjs": "6.5.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular/animations": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.0.7.tgz", + "integrity": "sha512-74gY7onajmmnksy5E0/32bFv3B9NuWxV64kqD15YjGrh8AWe1BHt5enQI+rJ2tO8m2DKnwZsctis6k0Kcy+YKQ==" + }, + "@angular/cdk": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.2.3.tgz", + "integrity": "sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==", + "requires": { + "parse5": "^5.0.0", + "tslib": "^1.7.1" + } + }, + "@angular/cli": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-9.0.7.tgz", + "integrity": "sha512-/9CUNSSVyTtTNUADZ/VXJDEdhineMN/rfd35w6VsHiob49tKkeOTggaoiSne3RY4VCTqlo7GGf4KhhVXEMGnDQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.900.7", + "@angular-devkit/core": "9.0.7", + "@angular-devkit/schematics": "9.0.7", + "@schematics/angular": "9.0.7", + "@schematics/update": "0.900.7", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.1", + "debug": "^4.1.1", + "ini": "1.3.5", + "inquirer": "7.0.0", + "npm-package-arg": "6.1.1", + "npm-pick-manifest": "3.0.2", + "open": "7.0.0", + "pacote": "9.5.8", + "read-package-tree": "5.3.1", + "rimraf": "3.0.0", + "semver": "6.3.0", + "symbol-observable": "1.2.0", + "universal-analytics": "^0.4.20", + "uuid": "^3.3.2" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@angular/common": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.0.7.tgz", + "integrity": "sha512-B58YgxZva1DBaeayOBsaUOOkoyR+GRibuNC3gfOMm2vXeW9eCNX+jvDtw767GnKm2yGzIq8wB3x6GHojN00dPw==" + }, + "@angular/compiler": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.7.tgz", + "integrity": "sha512-hFpkuGpzxpK5h59LHHAjTFWsY6DCXZwgJFqvCuTPxWi/srvLGZRXrpC6Z1SlgHI9xxXaPfoa4uWw2VfA3BnqEg==" + }, + "@angular/compiler-cli": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.0.7.tgz", + "integrity": "sha512-+RXghex63v0Vi8vpQtDpWiqpAAnrTaN3bHT5fntRenq5+Ok5vL1MJ1mzbTmBXs2tuwTqNlwMm2AlZB7G/xcDMQ==", + "dev": true, + "requires": { + "canonical-path": "1.0.0", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.7.2", + "fs-extra": "4.0.2", + "magic-string": "^0.25.0", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "semver": "^6.3.0", + "source-map": "^0.6.1", + "sourcemap-codec": "^1.4.8", + "yargs": "13.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "yargs": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.1.0.tgz", + "integrity": "sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "@angular/core": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.7.tgz", + "integrity": "sha512-E9XZH5Dl+9MWG3MDC6wrKllhA8Rljpz66HOIeqKv2fHPed8kzuJZU3WJWLtbhDAXFwtGTyTZ4c82ZLSmqwTorg==" + }, + "@angular/forms": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.0.7.tgz", + "integrity": "sha512-PaHAmjMJDtg/3aGCPuq5BCRC1eZ/DBCpva9f7NrA1kqk0LcLdebm0v2uHwTOBtiz/VEgPvxiS4tXC4rjvUtfEg==" + }, + "@angular/language-service": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-9.0.7.tgz", + "integrity": "sha512-IZG1kvw48JyFRy7bfMHqBixWrEHZmXmkP5DWsi5Tw6KusaczkMghI20BevCkodPcajXWHAUHNKyp1tlE3OnH0w==", + "dev": true + }, + "@angular/platform-browser": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.0.7.tgz", + "integrity": "sha512-Por8omrEiSV2U/K2mm/Kuv+2R2rJkbAZ3ctEM6CWj9Y4Gz2akjOCxmEgWhhBeqdigcC3T1v707f52osf9jWBkg==" + }, + "@angular/platform-browser-dynamic": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.0.7.tgz", + "integrity": "sha512-jwpyd93ofcRtchbayKD5v4GN4Lc7vbPe6dMUiwfnVnVAql0bOD/3YRI7w5qJ0Xx0sgQT+9Xo6jTXYnyUsZpEww==" + }, + "@angular/router": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.0.7.tgz", + "integrity": "sha512-uKru9F/Zju//gg6INl54abnlpLdEUUO/GpCfMk4zqu8LCZGNFta6OY7VT+9DK9Vdrh/XUD70oE9WoelcRwwTYA==" + }, + "@ant-design/colors": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-3.2.2.tgz", + "integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==", + "requires": { + "tinycolor2": "^1.4.1" + } + }, + "@ant-design/icons-angular": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-angular/-/icons-angular-8.1.1.tgz", + "integrity": "sha512-JMfavPHwahJcGWT13bTCt4IHzrsNgbJzzB+VWYtzjwWszMCVkkOOn+aJbslupHOl72KWDvklN/LjCQPBgu7xLQ==", + "requires": { + "@ant-design/colors": "^3.1.0", + "tslib": "^1.9.0" + } + }, + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/core": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.7.tgz", + "integrity": "sha512-jlSjuj/7z138NLZALxVgrx13AOtqip42ATZP7+kYl53GvDV6+4dCek1mVUo8z8c8Xnw/mx2q3d9HWh3griuesQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.7", + "@babel/helpers": "^7.7.4", + "@babel/parser": "^7.7.7", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "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/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.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 + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", + "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^7.10.4", + "regexpu-core": "^4.7.0" + } + }, + "@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz", + "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==", + "dev": true, + "requires": { + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", + "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz", + "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz", + "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", + "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.0.tgz", + "integrity": "sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", + "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", + "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", + "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", + "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", + "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", + "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", + "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", + "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", + "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", + "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz", + "integrity": "sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", + "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", + "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", + "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", + "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", + "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", + "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", + "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", + "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", + "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", + "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", + "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", + "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", + "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", + "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", + "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", + "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", + "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", + "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", + "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", + "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", + "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", + "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz", + "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", + "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^7.10.4" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", + "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", + "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", + "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/preset-env": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.7.tgz", + "integrity": "sha512-pCu0hrSSDVI7kCVUOdcMNQEbOPJ52E+LrQ14sN8uL2ALfSqePZQlKrOy+tM4uhEdYlCHi4imr8Zz2cZe9oSdIg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.7.4", + "@babel/plugin-proposal-dynamic-import": "^7.7.4", + "@babel/plugin-proposal-json-strings": "^7.7.4", + "@babel/plugin-proposal-object-rest-spread": "^7.7.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.7.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.7.7", + "@babel/plugin-syntax-async-generators": "^7.7.4", + "@babel/plugin-syntax-dynamic-import": "^7.7.4", + "@babel/plugin-syntax-json-strings": "^7.7.4", + "@babel/plugin-syntax-object-rest-spread": "^7.7.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.7.4", + "@babel/plugin-syntax-top-level-await": "^7.7.4", + "@babel/plugin-transform-arrow-functions": "^7.7.4", + "@babel/plugin-transform-async-to-generator": "^7.7.4", + "@babel/plugin-transform-block-scoped-functions": "^7.7.4", + "@babel/plugin-transform-block-scoping": "^7.7.4", + "@babel/plugin-transform-classes": "^7.7.4", + "@babel/plugin-transform-computed-properties": "^7.7.4", + "@babel/plugin-transform-destructuring": "^7.7.4", + "@babel/plugin-transform-dotall-regex": "^7.7.7", + "@babel/plugin-transform-duplicate-keys": "^7.7.4", + "@babel/plugin-transform-exponentiation-operator": "^7.7.4", + "@babel/plugin-transform-for-of": "^7.7.4", + "@babel/plugin-transform-function-name": "^7.7.4", + "@babel/plugin-transform-literals": "^7.7.4", + "@babel/plugin-transform-member-expression-literals": "^7.7.4", + "@babel/plugin-transform-modules-amd": "^7.7.5", + "@babel/plugin-transform-modules-commonjs": "^7.7.5", + "@babel/plugin-transform-modules-systemjs": "^7.7.4", + "@babel/plugin-transform-modules-umd": "^7.7.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.7.4", + "@babel/plugin-transform-new-target": "^7.7.4", + "@babel/plugin-transform-object-super": "^7.7.4", + "@babel/plugin-transform-parameters": "^7.7.7", + "@babel/plugin-transform-property-literals": "^7.7.4", + "@babel/plugin-transform-regenerator": "^7.7.5", + "@babel/plugin-transform-reserved-words": "^7.7.4", + "@babel/plugin-transform-shorthand-properties": "^7.7.4", + "@babel/plugin-transform-spread": "^7.7.4", + "@babel/plugin-transform-sticky-regex": "^7.7.4", + "@babel/plugin-transform-template-literals": "^7.7.4", + "@babel/plugin-transform-typeof-symbol": "^7.7.4", + "@babel/plugin-transform-unicode-regex": "^7.7.4", + "@babel/types": "^7.7.4", + "browserslist": "^4.6.0", + "core-js-compat": "^3.6.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + } + }, + "@babel/runtime": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.0.tgz", + "integrity": "sha512-qArkXsjJq7H+T86WrIFV0Fnu/tNOkZ4cgXmjkzAu3b/58D5mFIO8JH/y77t7C9q0OdDRdh9s7Ue5GasYssxtXw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + } + } + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", + "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.0", + "@babel/types": "^7.11.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "@babel/generator": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", + "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@fortawesome/angular-fontawesome": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.6.1.tgz", + "integrity": "sha512-ARQjtRuT+ZskzJDJKPwuiGO3+7nS0iyNLU/uHVJHfG4LwGJxwVIGldwg1SU957sra0Z0OtWEajHMhiS4vB9LwQ==" + }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.30", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.30.tgz", + "integrity": "sha512-TsRwpTuKwFNiPhk1UfKgw7zNPeV5RhNp2Uw3pws+9gDAkPGKrtjR1y2lI3SYn7+YzyfuNknflpBA1LRKjt7hMg==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.30", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.30.tgz", + "integrity": "sha512-E3sAXATKCSVnT17HYmZjjbcmwihrNOCkoU7dVMlasrcwiJAHxSKeZ+4WN5O+ElgO/FaYgJmASl8p9N7/B/RttA==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.30" + } + }, + "@fortawesome/free-regular-svg-icons": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.14.0.tgz", + "integrity": "sha512-6LCFvjGSMPoUQbn3NVlgiG4CY5iIY8fOm+to/D6QS/GvdqhDt+xZklQeERdCvVRbnFa1ITc1rJHPRXqkX5wztQ==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.30" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.14.0.tgz", + "integrity": "sha512-M933RDM8cecaKMWDSk3FRYdnzWGW7kBBlGNGfvqLVwcwhUPNj9gcw+xZMrqBdRqxnSXdl3zWzTCNNGEtFUq67Q==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.30" + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, + "@ngtools/webpack": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.0.7.tgz", + "integrity": "sha512-MvoMaErkjESefoIrbt8F2RpKDr9KavwvH4v3hwSAKooVNFdFKNsjJ7m3gCQehumEfsYFq2mrEK2sTW4/CpFlMQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.7", + "enhanced-resolve": "4.1.1", + "rxjs": "6.5.3", + "webpack-sources": "1.4.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@schematics/angular": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-9.0.7.tgz", + "integrity": "sha512-3UCeexYx/YVo3kboyPZ8KgqBTduMA18AAm3s2yrC0qj41fBFVVZAZLa74uouTf4RYVgy9kR7J3uv6VLxrJPOnQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.7", + "@angular-devkit/schematics": "9.0.7" + } + }, + "@schematics/update": { + "version": "0.900.7", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.900.7.tgz", + "integrity": "sha512-e9tX2DGNYfj/k9mVICpQt2bWIYyD92dlsip7LzPeZGt+R9zCp5w19uBLa8Z00OgEGzFR1krhRvkQE5OxkkAnVw==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.7", + "@angular-devkit/schematics": "9.0.7", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "npm-package-arg": "^7.0.0", + "pacote": "9.5.8", + "rxjs": "6.5.3", + "semver": "6.3.0", + "semver-intersect": "1.4.0" + }, + "dependencies": { + "npm-package-arg": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz", + "integrity": "sha512-xXxr8y5U0kl8dVkz2oK7yZjPBvqM2fwaO5l3Yg13p03v8+E3qQcD0JNhHzjL1vyGgxcKkD0cco+NLR72iuPk3g==", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.2", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@tweenjs/tween.js": { + "version": "18.5.0", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.5.0.tgz", + "integrity": "sha512-/qyhdvbc6vWsFuiK7Wq74ZMu1F/9sFRlBv2qnjeu70XI0HRC8zOfUqbXT2irVLCSVuCI/fI7HphGdbsbyQ/Q5w==" + }, + "@types/estree": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", + "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/jasmine": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.12.tgz", + "integrity": "sha512-vJaQ58oceFao+NzpKNqLOWwHPsqA7YEhKv+mOXvYU4/qh+BfVWIxaBtL0Ck5iCS67yOkNwGkDCrzepnzIWF+7g==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.8.tgz", + "integrity": "sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg==", + "dev": true, + "requires": { + "@types/jasmine": "*" + } + }, + "@types/json-schema": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "12.12.53", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.53.tgz", + "integrity": "sha512-51MYTDTyCziHb70wtGNFRwB4l+5JNvdqzFSkbDvpbftEgVUBEE+T5f7pROhWMp/fxp07oNIEQZd5bbfAH22ohQ==", + "dev": true + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz", + "integrity": "sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw==", + "dev": true + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/webpack-sources": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.8.tgz", + "integrity": "sha512-JHB2/xZlXOjzjBB6fMOpH1eQAfsrpqVVIbneE0Rok16WXwFaznaI5vfg75U5WgGJm7V9W1c4xeRQDjX/zwvghA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.6.1" + } + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "dev": true + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "ali-oss": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ali-oss/-/ali-oss-6.10.0.tgz", + "integrity": "sha512-kWguelLe4QZCvqisN3i9i+kyaG2JCj+4AqXbc+HKJ3b4WYwkn2hS9INJHtrUSlo95yn9FKSNXwTAfLMrXyQlnA==", + "requires": { + "address": "^1.0.0", + "agentkeepalive": "^3.4.1", + "any-promise": "^1.3.0", + "bowser": "^1.6.0", + "co-defer": "^1.0.0", + "copy-to": "^2.0.1", + "dateformat": "^2.0.0", + "debug": "^2.2.0", + "destroy": "^1.0.4", + "end-or-error": "^1.0.1", + "get-ready": "^1.0.0", + "humanize-ms": "^1.2.0", + "is-type-of": "^1.0.0", + "js-base64": "^2.5.2", + "jstoxml": "^0.2.3", + "merge-descriptors": "^1.0.1", + "mime": "^2.4.5", + "mz-modules": "^2.1.0", + "platform": "^1.3.1", + "pump": "^3.0.0", + "sdk-base": "^2.0.1", + "stream-http": "2.8.2", + "stream-wormhole": "^1.0.4", + "urllib": "^2.33.1", + "utility": "^1.8.0", + "xml2js": "^0.4.16" + } + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "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": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "app-root-path": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz", + "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==", + "dev": true + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "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 + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "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 + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "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.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.3.tgz", + "integrity": "sha512-XTZ7xGML849LkQP86sWdQzfhwbt3YwIO6MqbX9mUNYY98VKaaVZP7YNNm70IpwecbkkxmfC5IYAzOQ/2p29zRA==" + }, + "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.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "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": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.1.tgz", + "integrity": "sha512-w3b5y1PXWlhYulevrTJ0lizkQ5CyqfeU6BIRDbuhsMupstHQOeb1Ur80tcB1zxSu7AwyY/qCQ7Vvqklh31ZBFw==", + "dev": true, + "requires": { + "browserslist": "^4.7.2", + "caniuse-lite": "^1.0.30001006", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.21", + "postcss-value-parser": "^4.0.2" + } + }, + "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.10.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", + "dev": true + }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, + "babel-loader": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", + "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "pify": "^4.0.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "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 + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "bowser": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz", + "integrity": "sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "browserify-sign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", + "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.13.0.tgz", + "integrity": "sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001093", + "electron-to-chromium": "^1.3.488", + "escalade": "^3.0.1", + "node-releases": "^1.1.58" + } + }, + "browserstack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.0.tgz", + "integrity": "sha512-HJDJ0TSlmkwnt9RZ+v5gFpa1XZTBYTj0ywvLwJ3241J7vMw2jAsGNVhKHtmCOyg+VxeLZyaibO9UL71AsUeDIw==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + } + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "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 + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "dev": true, + "requires": { + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^7.0.0", + "unique-filename": "^1.1.1" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001109", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001109.tgz", + "integrity": "sha512-4JIXRodHzdS3HdK8nSgIqXYLExOvG+D2/EenSvcub2Kp3QEADjo2v2oUn5g0n0D+UNwG9BtwKOyGcSq2qvQXvQ==", + "dev": true + }, + "canonical-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz", + "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.1.tgz", + "integrity": "sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-dependency-plugin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz", + "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.4.0.tgz", + "integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==", + "dev": true + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "co-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/co-defer/-/co-defer-1.0.0.tgz", + "integrity": "sha1-Pkp4eo7tawoh7ih8CU9+jeDTyBg=" + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "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 + }, + "codelyzer": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.2.2.tgz", + "integrity": "sha512-jB4FZ1Sx7kZhvZVdf+N2BaKTdrrNZOL0Bj10RRfrhHrb3zEvXjJvvq298JPMJAiyiCS/v4zs1QlGU0ip7xGqeA==", + "dev": true, + "requires": { + "app-root-path": "^2.2.1", + "aria-query": "^3.0.0", + "axobject-query": "2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2" + }, + "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 + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "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 + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "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.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compressing": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/compressing/-/compressing-1.5.1.tgz", + "integrity": "sha512-1AGBR4Vh0/rpPKSXHoV9cerLo0CUlAhZ/xsJqU3a9+2cbSaFjWT3fk2MIGkCnbpk//DGWrcWw03rhKFQrA9RQw==", + "requires": { + "flushwritable": "^1.0.0", + "get-ready": "^1.0.0", + "iconv-lite": "^0.5.0", + "mkdirp": "^0.5.1", + "pump": "^3.0.0", + "streamifier": "^0.1.1", + "tar-stream": "^1.5.2", + "yauzl": "^2.7.0", + "yazl": "^2.4.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", + "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "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=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=" + }, + "copy-webpack-plugin": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz", + "integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==", + "dev": true, + "requires": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + } + } + }, + "core-js": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", + "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==", + "dev": true + }, + "core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "requires": { + "browserslist": "^4.8.5", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "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=" + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "coverage-istanbul-loader": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/coverage-istanbul-loader/-/coverage-istanbul-loader-2.0.3.tgz", + "integrity": "sha512-LiGRvyIuzVYs3M1ZYK1tF0HekjH0DJ8zFdUwAZq378EJzqOgToyb1690dp3TAUlP6Y+82uu42LRjuROVeJ54CA==", + "dev": true, + "requires": { + "convert-source-map": "^1.7.0", + "istanbul-lib-instrument": "^4.0.0", + "loader-utils": "^1.2.3", + "merge-source-map": "^1.1.0", + "schema-utils": "^2.6.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", + "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", + "dev": true, + "requires": { + "css": "^2.0.0" + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "css-selector-tokenizer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", + "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.3.0.tgz", + "integrity": "sha512-pv9JPyatiPaQ6pf4OvD/dbfm0o5LviWmwxNWzblYf/1u9QZd0ihV+PMwy5jdQWQ3349kZmKEx9WXuSka2dM4cg==", + "dev": true + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true + }, + "csso": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.3.tgz", + "integrity": "sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ==", + "dev": true, + "requires": { + "css-tree": "1.0.0-alpha.39" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0-alpha.39", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.39.tgz", + "integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==", + "dev": true, + "requires": { + "mdn-data": "2.0.6", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz", + "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==", + "dev": true + } + } + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "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" + } + }, + "data-uri-to-buffer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", + "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==" + }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + }, + "date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "dev": true + }, + "dateformat": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "default-user-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-user-agent/-/default-user-agent-1.0.0.tgz", + "integrity": "sha1-FsRu/cq6PtxF8k8r1IaLAbfCrcY=", + "requires": { + "os-name": "~1.0.3" + } + }, + "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" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + } + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "requires": { + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "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 + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "dependency-graph": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", + "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "dev": true + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "digest-header": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/digest-header/-/digest-header-0.0.1.tgz", + "integrity": "sha1-Ecz23uxXZqw3l0TZAcEsuklRS+Y=", + "requires": { + "utility": "0.1.11" + }, + "dependencies": { + "utility": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/utility/-/utility-0.1.11.tgz", + "integrity": "sha1-/eYM+bTkdRlHoM9dEEzik2ciZxU=", + "requires": { + "address": ">=0.0.1" + } + } + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "electron-to-chromium": { + "version": "1.3.516", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.516.tgz", + "integrity": "sha512-WDM5AAQdOrvLqSX8g3Zd5AujBXfMxf96oeZkff0U2HF5op3tjShE+on2yay3r1UD4M9I3p0iHpAS4+yV8U8A9A==", + "dev": true + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "end-or-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/end-or-error/-/end-or-error-1.0.1.tgz", + "integrity": "sha1-3HpiEP5403L+4kqLSJnb0VVBTcs=" + }, + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "enhanced-resolve": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escalade": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", + "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "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 + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-loader": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.2.0.tgz", + "integrity": "sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.0.0.tgz", + "integrity": "sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.0", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "flushwritable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flushwritable/-/flushwritable-1.0.0.tgz", + "integrity": "sha1-PjKNj95BKtR+c44751C00pAENJg=" + }, + "follow-redirects": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.12.1.tgz", + "integrity": "sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg==", + "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 + }, + "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.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formstream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/formstream/-/formstream-1.1.0.tgz", + "integrity": "sha1-UfOXDyYTbrCtRDBN5M67UCB7RHk=", + "requires": { + "destroy": "^1.0.4", + "mime": "^1.3.4", + "pause-stream": "~0.0.11" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + } + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-extra": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-ready": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-ready/-/get-ready-1.0.0.tgz", + "integrity": "sha1-+RgX8emt7P6hOlYq38jeiDqzR4I=" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-uri": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.4.tgz", + "integrity": "sha512-v7LT/s8kVjs+Tx0ykk1I+H/rbpzkHvuIq87LmeXptcf5sNWm9uQiwjNAt94SJPA1zOlCntmnOlJvVWKmzsxG8Q==", + "requires": { + "data-uri-to-buffer": "1", + "debug": "2", + "extend": "~3.0.2", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "2" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "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.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "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.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "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", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "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.0.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.5" + } + } + } + }, + "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.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.5.tgz", + "integrity": "sha512-i4dpK6xj9BIpVOTboXIlKG9+8HMKggcrMX7WA24xZtKwX0TPelq/rbaS5rCKeNX8sJXZJGdSxpnEGtta+wismQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "html-entities": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", + "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-parser-js": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz", + "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "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.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "https-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", + "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "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 + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", + "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.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.5" + } + } + } + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "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-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.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-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-class-hotfix": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz", + "integrity": "sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==" + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.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.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-docker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.0.tgz", + "integrity": "sha512-mB2WygGsSeoXtLKpSYzP6sa0Z9DyU9ZyKlnvuZWxCociaI0qsF8u12sR72DFTX236g1u6oWSWYFuUk09nGQEjg==", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "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-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-type-of": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-type-of/-/is-type-of-1.2.1.tgz", + "integrity": "sha512-uK0kyX9LZYhSDS7H2sVJQJop1UnWPWmo5RvR3q2kFH6AUHYs7sOrVg0b4nyBHw29kRRNFofYN/JbHZDlHiItTA==", + "requires": { + "core-util-is": "^1.0.2", + "is-class-hotfix": "~0.0.6", + "isstream": "~0.1.2" + } + }, + "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-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "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": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "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=" + }, + "istanbul-api": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.7.tgz", + "integrity": "sha512-LYTOa2UrYFyJ/aSczZi/6lBykVMjCCvUmT64gOe+jPZFy4w6FYfPGqFT2IiQ2BxVHHDOvCD7qrIXb0EOh4uGWw==", + "dev": true, + "requires": { + "async": "^2.6.2", + "compare-versions": "^3.4.0", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.5", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0" + } + }, + "jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "requires": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "dependencies": { + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", + "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", + "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "dev": true, + "requires": { + "colors": "1.1.2" + } + }, + "jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "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": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "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 + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "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" + } + }, + "jstoxml": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jstoxml/-/jstoxml-0.2.4.tgz", + "integrity": "sha1-/z+2eFaIOgMpU8fOjOdIYhD0hEc=" + }, + "jszip": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz", + "integrity": "sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "karma": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-4.3.0.tgz", + "integrity": "sha512-NSPViHOt+RW38oJklvYxQC4BSQsv737oQlr/r06pCM+slDOr4myuI1ivkRmp+3dVpJDfZt2DmaPJ2wkx+ZZuMQ==", + "dev": true, + "requires": { + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "braces": "^3.0.2", + "chokidar": "^3.0.0", + "colors": "^1.1.0", + "connect": "^3.6.0", + "core-js": "^3.1.3", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "flatted": "^2.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.14", + "log4js": "^4.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "2.3.0" + } + }, + "karma-chrome-launcher": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", + "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "dev": true, + "requires": { + "which": "^1.2.1" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.1.1.tgz", + "integrity": "sha512-CH8lTi8+kKXGvrhy94+EkEMldLCiUA0xMOiL31vvli9qK0T+qcXJAwWBRVJWnVWxYkTmyWar8lPz63dxX6/z1A==", + "dev": true, + "requires": { + "istanbul-api": "^2.1.6", + "minimatch": "^3.0.4" + } + }, + "karma-jasmine": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", + "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", + "dev": true, + "requires": { + "jasmine-core": "^3.3" + } + }, + "karma-jasmine-html-reporter": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.4.tgz", + "integrity": "sha512-PtilRLno5O6wH3lDihRnz0Ba8oSn0YUJqKjjux1peoYGwo0AQqrWRbdWk/RLzcGlb+onTyXAnHl6M+Hu3UxG/Q==", + "dev": true + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "ko-sleep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ko-sleep/-/ko-sleep-1.0.3.tgz", + "integrity": "sha1-KKKgoUhei39BX/SI3uF9JHiKsII=", + "requires": { + "ms": "^2.0.0" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "less": { + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/less/-/less-3.10.3.tgz", + "integrity": "sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow==", + "dev": true, + "requires": { + "clone": "^2.1.2", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.4.1", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "^2.83.0", + "source-map": "~0.6.0" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true + } + } + }, + "less-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-5.0.0.tgz", + "integrity": "sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^4.0.1" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "license-webpack-plugin": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.1.3.tgz", + "integrity": "sha512-vTSY5r9HOq4sxR2BIxdIXWKI+9n3b+DoQkhKHedB3TdSxTfXUDRxKXdAj5iejR+qNXprXsxvEu9W+zOhgGIkAw==", + "dev": true, + "requires": { + "@types/webpack-sources": "^0.1.5", + "webpack-sources": "^1.2.0" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "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.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "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 + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "log4js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", + "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", + "dev": true, + "requires": { + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", + "rfdc": "^1.1.4", + "streamroller": "^1.0.6" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "loglevel": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz", + "integrity": "sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz", + "integrity": "sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "make-fetch-happen": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", + "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + }, + "dependencies": { + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + } + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "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-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "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.0.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.5" + } + } + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz", + "integrity": "sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "mz-modules": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mz-modules/-/mz-modules-2.1.0.tgz", + "integrity": "sha512-sjk8lcRW3vrVYnZ+W+67L/2rL+jbO5K/N6PFGIcLWTiYytNr22Ah9FDXFs+AQntTM1boZcoHi5qS+CV1seuPog==", + "requires": { + "glob": "^7.1.2", + "ko-sleep": "^1.0.3", + "mkdirp": "^0.5.1", + "pump": "^3.0.0", + "rimraf": "^2.6.1" + } + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=" + }, + "ng-zorro-antd": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/ng-zorro-antd/-/ng-zorro-antd-8.5.2.tgz", + "integrity": "sha512-x+QJULyU1IXiAbf/lFPxYC/JUJvBGzU9UXnXSyLnMPZpdtEXodaF/L1N1CpSUr5SimLiHRe/jsVHDWkg0HqfYg==", + "requires": { + "@angular/cdk": "^8.0.0", + "@ant-design/icons-angular": "^8.0.2", + "date-fns": "^1.30.1", + "tslib": "^1.9.0" + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-fetch-npm": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz", + "integrity": "sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg==", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-forge": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.60", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", + "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "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 + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true + }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-package-arg": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "dev": true, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + } + } + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", + "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-registry-fetch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.5.tgz", + "integrity": "sha512-yQ0/U4fYpCCqmueB2g8sc+89ckQ3eXpmU4+Yi2j5o/r0WkKvE2+Y0tK3DEILAtn2UaQTkjTHxIXe2/CSdit+/Q==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "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.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "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=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.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.5" + } + } + } + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-is": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.1.tgz", + "integrity": "sha512-ZpZpjcJeugQfWsfyQlshVoowIIQ1qBGSVll4rfDq6JJVO//fesjoX808hXWfBjY+ROZgpKDI5TRSRBSoJiZ8eg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-7.0.0.tgz", + "integrity": "sha512-K6EKzYqnwQzk+/dzJAQSBORub3xlBTxMz+ntpZpH/LyCa1o6KjXhuN+2npAaI9jaSmU3R1Q8NWf4KUWcyytGsQ==", + "dev": true, + "requires": { + "is-wsl": "^2.1.0" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + } + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "ora": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ora/-/ora-4.0.2.tgz", + "integrity": "sha512-YUOZbamht5mfLxPmk4M35CD/5DuOkAacxlEUbStVXpBAt4fyhBf+vZHI/HRkI++QUp3sNoeA2Gw4C+hi4eGSig==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.2.0", + "is-interactive": "^1.0.0", + "log-symbols": "^3.0.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "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": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "os-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-1.0.3.tgz", + "integrity": "sha1-GzefZINa98Wn9JizV8uVIVwVnt8=", + "requires": { + "osx-release": "^1.0.0", + "win-release": "^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.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "osx-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz", + "integrity": "sha1-8heRGigTaUmvG/kwiyQeJzfTzWw=", + "requires": { + "minimist": "^1.1.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pac-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.1.tgz", + "integrity": "sha512-44DUg21G/liUZ48dJpUSjZnFfZro/0K5JTyFYLBcmh9+T6Ooi4/i4efwUiEy0+4oQusCBqWdhv16XohIj1GqnQ==", + "requires": { + "agent-base": "^4.2.0", + "debug": "^4.1.1", + "get-uri": "^2.0.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^3.0.0", + "pac-resolver": "^3.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "pac-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", + "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", + "requires": { + "co": "^4.6.0", + "degenerator": "^1.0.4", + "ip": "^1.1.5", + "netmask": "^1.0.6", + "thunkify": "^2.1.2" + } + }, + "pacote": { + "version": "9.5.8", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.8.tgz", + "integrity": "sha512-0Tl8Oi/K0Lo4MZmH0/6IsT3gpGf9eEAznLXEQPKgPq7FscnbUOyopnVpwXlnQdIbCUaojWy1Wd7VMyqfVsRrIw==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^3.0.0", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.10", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + } + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "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 + }, + "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=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "requires": { + "through": "~2.3" + } + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "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.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "7.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz", + "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-calc": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.2.tgz", + "integrity": "sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ==", + "dev": true, + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-import": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz", + "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-load-config": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "requires": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "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.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true + } + } + }, + "protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "protractor": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.4.tgz", + "integrity": "sha512-BaL4vePgu3Vfa/whvTUAlgaCAId4uNSGxIFSCXMgj7LMYENPWLp85h5RBi9pdpX/bWQ8SF6flP7afmi2TC4eHw==", + "dev": true, + "requires": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.0.6", + "yargs": "^12.0.5" + }, + "dependencies": { + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "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", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "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 + }, + "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.6" + } + }, + "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 + }, + "webdriver-manager": { + "version": "12.1.7", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.7.tgz", + "integrity": "sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA==", + "dev": true, + "requires": { + "adm-zip": "^0.4.9", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + } + } + } + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "proxy-agent": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.1.1.tgz", + "integrity": "sha512-WudaR0eTsDx33O3EJE16PjBRZWcX8GqCEeERw1W3hZJgH/F2a46g7jty6UGty6NeJ4CKQy8ds2CJPMiyeqaTvw==", + "requires": { + "agent-base": "^4.2.0", + "debug": "4", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^3.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^3.0.1", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "raw-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-3.1.0.tgz", + "integrity": "sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^2.0.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-package-json": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", + "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "dev": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", + "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "regexpu-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "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", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "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 + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + } + } + }, + "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 + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "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": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rollup": { + "version": "1.25.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.25.2.tgz", + "integrity": "sha512-+7z6Wab/L45QCPcfpuTZKwKiB0tynj05s/+s2U3F2Bi7rOLPr9UcjUwO7/xpjlPNXA/hwnth6jBExFRGyf3tMg==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/node": "*", + "acorn": "^7.1.0" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.23.3.tgz", + "integrity": "sha512-1DKRZxJMOh4Bme16AbWTyYeJAjTlrvw2+fWshHHaepeJfGq2soFZTnt0YhWit+bohtDu4LdyPoEj6VFD4APHog==", + "dev": true, + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, + "sass-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.0.tgz", + "integrity": "sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "sdk-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/sdk-base/-/sdk-base-2.0.1.tgz", + "integrity": "sha1-ukAonovfJy7RHdnql+r5jgNtJMY=", + "requires": { + "get-ready": "~1.0.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "selfsigned": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "dev": true, + "requires": { + "node-forge": "0.9.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "semver-intersect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", + "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", + "dev": true, + "requires": { + "semver": "^5.0.0" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "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 + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.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 + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "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.5" + } + } + } + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sockjs-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "socks": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "requires": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "^5.0.0" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "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==" + }, + "source-map-loader": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz", + "integrity": "sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ==", + "dev": true, + "requires": { + "async": "^2.5.0", + "loader-utils": "^1.1.0" + } + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "spark-md5": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.1.tgz", + "integrity": "sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "speed-measure-webpack-plugin": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.1.tgz", + "integrity": "sha512-qVIkJvbtS9j/UeZumbdfz0vg+QfG/zxonAjzefZrqzkr7xOncLVXkeGbTpzd1gjCBM4PmVNkWlkeTVhgskAGSQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.2.tgz", + "integrity": "sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "stream-wormhole": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stream-wormhole/-/stream-wormhole-1.1.0.tgz", + "integrity": "sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==" + }, + "streamifier": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz", + "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=" + }, + "streamroller": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", + "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.14" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.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.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 + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "style-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.0.0.tgz", + "integrity": "sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "stylus": { + "version": "0.54.7", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.7.tgz", + "integrity": "sha512-Yw3WMTzVwevT6ZTrLCYNHAFmanMxdylelL3hkWNgPMeTCpMwpV3nXjpOHuBXtFv7aiO2xRuQS6OoAdgkNcSNug==", + "dev": true, + "requires": { + "css-parse": "~2.0.0", + "debug": "~3.1.0", + "glob": "^7.1.3", + "mkdirp": "~0.5.x", + "safer-buffer": "^2.1.2", + "sax": "~1.2.4", + "semver": "^6.0.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", + "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + } + }, + "terser": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.5.1.tgz", + "integrity": "sha512-lH9zLIbX8PRBEFCTvfHGCy0s9HEKnNso1Dx9swSopF3VUnFLB8DpQ61tHxoofovNC/sG0spajJM3EIIRSTByiQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + }, + "terser-webpack-plugin": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.3.tgz", + "integrity": "sha512-gWHkaGzGYjmDoYxksFZynWTzvXOAjQ5dd7xuTMYlv4zpWlLSb6v0QLSZjELzP5dMs1ox30O1BIPs9dgqlMHuLQ==", + "dev": true, + "requires": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.2.0", + "jest-worker": "^25.1.0", + "p-limit": "^2.2.2", + "schema-utils": "^2.6.4", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.4.3", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", + "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=" + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "tinycolor2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", + "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, + "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 + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.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.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "ts-node": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", + "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + }, + "tslint": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", + "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "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.0.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 + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", + "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", + "dev": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "unescape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz", + "integrity": "sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==", + "requires": { + "extend-shallow": "^2.0.1" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universal-analytics": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.23.tgz", + "integrity": "sha512-lgMIH7XBI6OgYn1woDEmxhGdj8yDefMKg7GkWdeATAlQZFrMrNyxSkpDzY57iY0/6fdlzTbBV03OawvvzG+q7A==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "request": "^2.88.2", + "uuid": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "urllib": { + "version": "2.36.1", + "resolved": "https://registry.npmjs.org/urllib/-/urllib-2.36.1.tgz", + "integrity": "sha512-g0Gh7bH5AwfPUzFetxPtJwumGHE6D7KQn0K68MwcJXPgO2K0AliwEIxLAwGMF+TpY75DYAsvz1h9ekagYoq33w==", + "requires": { + "any-promise": "^1.3.0", + "content-type": "^1.0.2", + "debug": "^2.6.9", + "default-user-agent": "^1.0.0", + "digest-header": "^0.0.1", + "ee-first": "~1.1.1", + "formstream": "^1.1.0", + "humanize-ms": "^1.2.0", + "iconv-lite": "^0.4.15", + "ip": "^1.1.5", + "proxy-agent": "^3.1.0", + "pump": "^3.0.0", + "qs": "^6.4.0", + "statuses": "^1.3.1", + "utility": "^1.16.1" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "dev": true, + "requires": { + "lru-cache": "4.1.x", + "tmp": "0.0.x" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "utility": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/utility/-/utility-1.16.3.tgz", + "integrity": "sha512-kYghm8fknkPkUd9ncODj/b2Zojc23gnRC29QmpmL3BBsSX6W++RNRTQ1tB7l0UA7d4SisIjUyvRfVET3lBwurw==", + "requires": { + "copy-to": "^2.0.1", + "escape-html": "^1.0.3", + "mkdirp": "^0.5.1", + "mz": "^2.7.0", + "unescape": "^1.0.1" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true + }, + "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.2.0" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "watchpack": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz", + "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==", + "dev": true, + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.0" + } + }, + "watchpack-chokidar2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz", + "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "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, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "requires": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + } + }, + "webpack": { + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "serialize-javascript": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", + "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "terser-webpack-plugin": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz", + "integrity": "sha512-U4mACBHIegmfoEe5fdongHESNJWqsGU+W0S/9+BmYGVQDw1+c2Ow05TpMhxjPK1sRb7cuYq1BPl1e5YHJMTCqA==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^3.1.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "webpack-dev-server": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz", + "integrity": "sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.2.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.4", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.25", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.4.0", + "spdy": "^4.0.1", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "12.0.5" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "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.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "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.0.2" + } + }, + "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.5" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "webpack-subresource-integrity": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.3.4.tgz", + "integrity": "sha512-6XbGYzjh30cGQT/NsC+9IAkJP8IL7/t47sbwR5DLSsamiD56Rwv4/+hsgEHsviPvrEFZ0JRAQtCRN3UsR2Pw9g==", + "dev": true, + "requires": { + "webpack-sources": "^1.3.0" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "win-release": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", + "integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=", + "requires": { + "semver": "^5.0.1" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "worker-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/worker-plugin/-/worker-plugin-3.2.0.tgz", + "integrity": "sha512-W5nRkw7+HlbsEt3qRP6MczwDDISjiRj2GYt9+bpe8A2La00TmJdwzG5bpdMXhRt1qcWmwAvl1TiKaHRa+XDS9Q==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "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.1", + "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.0" + } + }, + "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.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "requires": { + "buffer-crc32": "~0.2.3" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==" + } + } +} diff --git a/form/package.json b/form/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c9142eda9628c3fc9cf5db44b62bc836760bdad5 --- /dev/null +++ b/form/package.json @@ -0,0 +1,57 @@ +{ + "name": "ng-template-generator", + "version": "0.0.1", + "scripts": { + "start": "ng serve", + "build": "ng build --build--optimizer --aot --base-href /JGT/v3/", + "publish": "node ./bin/publish.js", + "ng": "ng", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "~9.0.2", + "@angular/common": "~9.0.2", + "@angular/compiler": "~9.0.2", + "@angular/core": "~9.0.2", + "@angular/forms": "~9.0.2", + "@angular/platform-browser": "~9.0.2", + "@angular/platform-browser-dynamic": "~9.0.2", + "@angular/router": "~9.0.2", + "@fortawesome/angular-fontawesome": "^0.6.0", + "@fortawesome/fontawesome-svg-core": "^1.2.27", + "@fortawesome/free-regular-svg-icons": "^5.12.1", + "@fortawesome/free-solid-svg-icons": "^5.12.1", + "@tweenjs/tween.js": "~18.5.0", + "ali-oss": "^6.5.1", + "compressing": "^1.5.0", + "ng-zorro-antd": "^8.5.2", + "rxjs": "~6.5.4", + "spark-md5": "^3.0.0", + "tslib": "^1.10.0", + "zone.js": "~0.10.2" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.900.3", + "@angular/cli": "~9.0.3", + "@angular/compiler-cli": "~9.0.2", + "@angular/language-service": "~9.0.2", + "@types/jasmine": "~3.5.0", + "@types/jasminewd2": "~2.0.3", + "@types/node": "^12.11.1", + "codelyzer": "^5.1.2", + "jasmine-core": "~3.5.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~4.3.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage-istanbul-reporter": "~2.1.0", + "karma-jasmine": "~2.0.1", + "karma-jasmine-html-reporter": "^1.4.2", + "protractor": "~5.4.3", + "ts-node": "~8.3.0", + "tslint": "~5.18.0", + "typescript": "~3.7.5" + } +} diff --git a/form/src/app/MyError.ts b/form/src/app/MyError.ts new file mode 100644 index 0000000000000000000000000000000000000000..e1264c74bd3eb232216890bc6eae9cbd1ef90948 --- /dev/null +++ b/form/src/app/MyError.ts @@ -0,0 +1,9 @@ + +import { ErrorHandler } from '@angular/core'; + +export class MyErrorHandler implements ErrorHandler { + handleError(error) { + console.log(error.stack); + (<any> window).courseware.sendErrorLog(error); + } +} \ No newline at end of file diff --git a/form/src/app/app.component.html b/form/src/app/app.component.html new file mode 100644 index 0000000000000000000000000000000000000000..44b4b71485c2ca9ca3fa1b37ea62d72a301864ba --- /dev/null +++ b/form/src/app/app.component.html @@ -0,0 +1,3 @@ +<app-form *ngIf="type==='form'"></app-form> + +<app-play *ngIf="type==='play'"></app-play> \ No newline at end of file diff --git a/form/src/app/app.component.scss b/form/src/app/app.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/form/src/app/app.component.ts b/form/src/app/app.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..43e76cf1f63519fac5fd34a9ac14b582542b9197 --- /dev/null +++ b/form/src/app/app.component.ts @@ -0,0 +1,29 @@ +import { Component , OnInit} from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent implements OnInit { + type = 'play'; + + constructor() { + const tp = this.getQueryString('type'); + if (tp) { + this.type = tp; + } + } + + ngOnInit() { + + } + getQueryString(name) { + const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); + const r = window.location.search.substr(1).match(reg); + if (r != null) { + return unescape(r[2]); + } + return null; + } +} diff --git a/form/src/app/app.module.ts b/form/src/app/app.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0995a75739d55061953bdc16761ee2f6524aed1 --- /dev/null +++ b/form/src/app/app.module.ts @@ -0,0 +1,65 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule, ErrorHandler } from '@angular/core'; + +import {MyErrorHandler} from './MyError'; + +import { AppComponent } from './app.component'; +import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd'; +import { FormsModule } from '@angular/forms'; +import { HttpClientModule } from '@angular/common/http'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { registerLocaleData } from '@angular/common'; +import zh from '@angular/common/locales/zh'; +import {FormComponent} from './form/form.component'; +import {PlayComponent} from './play/play.component'; +import {LessonTitleConfigComponent} from './common/lesson-title-config/lesson-title-config.component'; +import {BackgroundImagePipe} from './pipes/background-image.pipe'; +import {UploadImageWithPreviewComponent} from './common/upload-image-with-preview/upload-image-with-preview.component'; +import {PlayerContentWrapperComponent} from './common/player-content-wrapper/player-content-wrapper.component'; +import {CustomHotZoneComponent} from './common/custom-hot-zone/custom-hot-zone.component'; +import {UploadVideoComponent} from './common/upload-video/upload-video.component'; +import {TimePipe} from './pipes/time.pipe'; +import {ResourcePipe} from './pipes/resource.pipe'; +import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.component'; +import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; +import { fas } from '@fortawesome/free-solid-svg-icons'; +import { far } from '@fortawesome/free-regular-svg-icons'; + +registerLocaleData(zh); + +@NgModule({ + declarations: [ + AppComponent, + FormComponent, + PlayComponent, + LessonTitleConfigComponent, + AudioRecorderComponent, + UploadImageWithPreviewComponent, + BackgroundImagePipe, + ResourcePipe, + TimePipe, + UploadVideoComponent, + CustomHotZoneComponent, + + PlayerContentWrapperComponent + + ], + imports: [ + BrowserModule, + NgZorroAntdModule, + FormsModule, + HttpClientModule, + BrowserAnimationsModule, + FontAwesomeModule + ], + providers: [ + {provide: ErrorHandler, useClass: MyErrorHandler}, + { provide: NZ_I18N, useValue: zh_CN } + ], + bootstrap: [AppComponent] +}) +export class AppModule { + constructor(library: FaIconLibrary) { + library.addIconPacks(fas, far); + } +} diff --git a/form/src/app/common/audio-recorder/audio-recorder.component.html b/form/src/app/common/audio-recorder/audio-recorder.component.html new file mode 100644 index 0000000000000000000000000000000000000000..e174c34da6591aeefc1a0d1f9fb3576e6499d645 --- /dev/null +++ b/form/src/app/common/audio-recorder/audio-recorder.component.html @@ -0,0 +1,61 @@ +<div class="d-flex"> + <div class="p-btn-record d-flex"> + <div class="btn-clear" style="cursor: pointer" (click)="onBtnClearAudio()" *ngIf="withRmBtn && (audioUrl || audioBlob)"> + <fa-icon icon="times"></fa-icon> + </div> + <div class="btn-record" *ngIf="type===Type.RECORD && !isUploading" + [class.p-recording]="isRecording" + (click)="onBtnRecord()"> + <fa-icon icon="microphone"></fa-icon> + Record Audio + </div> + <nz-upload + [nzAccept] = "'.mp3'" + [nzShowUploadList]="false" + [nzAction]="uploadUrl" + [nzData]="uploadData" + (nzChange)="handleChange($event)"> + + <div class="btn-upload" [ngClass]="{'has-clear': withRmBtn && (audioUrl || audioBlob)}" *ngIf="type===Type.UPLOAD && !isUploading"> + <fa-icon icon="upload"></fa-icon> + Upload Audio + </div> + </nz-upload> + <div class="p-upload-progress-bg" *ngIf="isUploading"> + <div class="i-bg" [style.width]="progress+'%'"></div> + <div class="i-text"> + <fa-icon icon="cloud-upload-alt"></fa-icon> + Uploading... + </div> + </div> + + + <div *ngIf="audioUrl && needRemove; then truthyTemplate else falsyTemplate"></div> + + <ng-template #truthyTemplate > + + <div class="btn-delete" (click)="onBtnDeleteAudio()"> + <fa-icon icon="close"></fa-icon> + </div> + + </ng-template> + + <ng-template #falsyTemplate> + <div class="btn-switch" (click)="onBtnSwitchType()"> + <fa-icon icon="cog"></fa-icon> + </div> + </ng-template> + + + + + </div> + + <div class="p-progress ml-2" (click)="onBtnPlay()" *ngIf="audioUrl || audioBlob"> + <nz-progress [nzPercent]="percent" [nzWidth]="30" [nzFormat]="progressText" + nzType="circle"></nz-progress> + <div class="p-btn-play" [style.left]="isPlaying?'8px':''"> + <fa-icon [icon]="playIcon"></fa-icon> + </div> + </div> +</div> diff --git a/form/src/app/common/audio-recorder/audio-recorder.component.scss b/form/src/app/common/audio-recorder/audio-recorder.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..8267c9d059853b3be3cbf4cb51ee9dd66214379a --- /dev/null +++ b/form/src/app/common/audio-recorder/audio-recorder.component.scss @@ -0,0 +1,107 @@ +.d-flex{ + display: flex; +} +.p-btn-record { + font-size: 0.9rem; + color: #555; + font-family: "Monospaced Number", "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif; + + .btn-record, .btn-upload { + cursor: pointer; + text-align: center; + width: 130px; + height: 33px; + line-height: 33px; + border-radius: 0.5rem 0 0 0.5rem; + border: 1px solid #ddd; + border-right: 0.5px; + &:hover { + color: rgb(64, 169, 255); + } + } + .btn-record.has-clear, .btn-upload.has-clear{ + border-radius:0; + border-left: 0; + } + .btn-clear{ + text-align: center; + color: #aaa; + padding: 0 0.5rem; + border: 1px solid #ddd; + border-radius: 0.5rem 0 0 0.5rem; + height: 33px; + line-height: 33px; + } + .btn-switch { + text-align: center; + color: #aaa; + padding: 0 0.5rem; + border: 1px solid #ddd; + border-radius: 0 0.5rem 0.5rem 0; + height: 33px; + line-height: 33px; + &:hover { + color: rgb(64, 169, 255); + } + } + .btn-delete { + text-align: center; + color: #aaa; + padding: 0 0.5rem; + border: 1px solid #ddd; + border-radius: 0 0.5rem 0.5rem 0; + height: 33px; + line-height: 33px; + &:hover { + color: #ec5b56; + } + } +} + +.p-recording { + background: orangered; + color: white !important; +} + +.p-upload-progress-bg { + position: relative; + width: 130px; + height: 33px; + line-height: 33px; + & .i-text { + position: absolute; + width: 100%; + height: 100%; + text-align: center; + border-radius: 0.5rem 0 0 0.5rem; + border: 1px solid #ddd; + border-right: 0.5px; + color: white; + text-shadow: 0 0 2px rgba(0, 0, 0, .85); + } + & .i-bg { + position: absolute; + left: 0; + top: 0; + height: 100%; + background-color: #27b43f; + border-radius: 0.5rem 0 0 0.5rem; + } +} + +.p-progress { + margin-top: 2px; + position: relative; + line-height: 26px; + .p-btn-play { + position: absolute; + left: 10px; + top: 3px; + color: #555; + } +} + +:host ::ng-deep nz-upload { + line-height: 33px; +} + diff --git a/form/src/app/common/audio-recorder/audio-recorder.component.ts b/form/src/app/common/audio-recorder/audio-recorder.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..605db0ab773819d944f4b9932a82f5cfb6111f94 --- /dev/null +++ b/form/src/app/common/audio-recorder/audio-recorder.component.ts @@ -0,0 +1,234 @@ +import {Component, EventEmitter, Input, OnDestroy, OnInit, Output, NgZone, OnChanges} from '@angular/core'; +import {NzMessageService, NzNotificationService, UploadFile} from 'ng-zorro-antd'; +import {HttpClient, HttpEvent, HttpEventType, HttpRequest} from '@angular/common/http'; +import {environment} from '../../../environments/environment'; + +declare var Recorder; + +@Component({ + selector: 'app-audio-recorder', + templateUrl: './audio-recorder.component.html', + styleUrls: ['./audio-recorder.component.scss'] +}) +export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { + _audioUrl: string; + audio = new Audio(); + playIcon = 'play'; + isPlaying = false; + isRecording = false; + isUploading = false; + type = Type.UPLOAD; // record | upload + Type = Type; + @Input() + withRmBtn = false; + + uploadUrl; + uploadData; + + @Input() + needRemove = false; + + @Input() + audioItem: any = null; + + @Input() + set audioUrl(url) { + this._audioUrl = url; + if (url) { + this.audio.src = this._audioUrl; + this.audio.load(); + } + this.init(); + } + + get audioUrl() { + return this._audioUrl; + } + + @Output() audioUploaded = new EventEmitter(); + @Output() audioUploadFailure = new EventEmitter(); + @Output() audioRemoved = new EventEmitter(); + percent = 0; + progress = 0; + recorder: any; + audioBlob: any; + + + constructor( private nzMessageService: NzMessageService ) { + this.uploadUrl = (<any> window).courseware.uploadUrl(); + this.uploadData = (<any> window).courseware.uploadData(); + + window['air'].getUploadCallback = (url, data) => { + this.uploadUrl = url; + this.uploadData = data; + }; + } + + init() { + this.playIcon = 'play'; + this.isPlaying = false; + this.isRecording = false; + this.isUploading = false; + this.percent = 0; + this.progress = 0; + this.audioBlob = null; + } + ngOnChanges() { + // if (!this.audioItem || !this.audioItem.type) { + // return; + // } + // this.beforeUpload(this.audioItem); + } + ngOnInit() { + + this.audio.onplay = () => { + this.onPlay(); + }; + this.audio.onpause = () => { + this.onPause(); + }; + this.audio.ontimeupdate = (event) => { + this.onTimeUpdate(event); + }; + this.audio.onended = (event) => { + this.onEnded(); + }; + } + + ngOnDestroy() { + this.audio.pause(); + this.isPlaying = false; + this.audio.remove(); + // if (this.recorder.worker) { + // this.recorder.worker.terminate(); + // } + } + + progressText(percent) { + return ``; + } + + onPlay() { + console.log('play'); + this.playIcon = 'pause'; + this.isPlaying = true; + } + + onPause() { + console.log('pause'); + this.playIcon = 'play'; + this.isPlaying = false; + } + + onEnded() { + console.log('on end'); + this.playIcon = 'play'; + this.percent = 0; + this.isPlaying = false; + } + + onTimeUpdate(event) { + this.percent = Math.floor((this.audio.currentTime / this.audio.duration) * 100); + } + + onBtnPlay() { + if (this.isRecording) { + this.nzMessageService.warning('In Recording'); + return; + } + if (this.isPlaying) { + this.audio.pause(); + } else { + this.audio.play(); + } + } + + // 开始录音 + onBtnRecord = () => { + } + + // åˆ‡æ¢æ¨¡å¼ + onBtnSwitchType() { + } + onBtnClearAudio() { + this.audioUrl = null; + this.audioRemoved.emit(); + } + + onBtnDeleteAudio() { + this.audioUrl = null; + this.audioRemoved.emit(); + } + + handleChange(info: { type: string, file: UploadFile, event: any }): void { + switch (info.type) { + case 'start': + this.isUploading = true; + this.progress = 0; + break; + case 'success': + this.isUploading = false; + this.uploadSuccess(info.file.response); + this.audioUploaded.emit(info.file.response); + break; + case 'progress': + this.progress = parseInt(info.event.percent, 10); + break; + } + } + checkSelectFile(file: any) { + if (!file) { + return; + } + const isAudio = ['audio/mp3', 'audio/wav', 'audio/ogg'].includes(file.type); + if (!isAudio) { + this.nzMessageService.error('You can only upload Audio file ( mp3 | wav |ogg)'); + return; + } + const delta = 25; + const isOverSize = (file.size / 1024 / 1024) < delta; + if (!isOverSize) { + this.nzMessageService.error(`audio file must smaller than ${delta}MB!`); + return false; + } + return true; + } + beforeUpload = (file: File) => { + + this.audioUrl = null; + if (!this.checkSelectFile(file)) { + return false; + } + this.isUploading = true; + this.progress = 0; + } + uploadSuccess = (url) => { + this.nzMessageService.info('Upload Success'); + this.isUploading = false; + this.audioUrl = url; + } + uploadFailure = (err, file) => { + this.isUploading = false; + if (err.name && err.name === 'cancel') { + return; + } + console.log(err); + this.nzMessageService.error('Upload Error ' + err.message); + this.audioUploadFailure.emit(file); + } + doProgress = (p) => { + if (p > 1) { + p = 1; + } + if (p < 0) { + p = 0; + } + // console.log(Math.floor(p * 100)); + this.progress = Math.floor(p * 100); + } + +} + +enum Type { + RECORD = 1, UPLOAD +} diff --git a/form/src/app/common/custom-hot-zone/Unit.ts b/form/src/app/common/custom-hot-zone/Unit.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b99189ae1e79f71bf621d6c98beff55cb7df827 --- /dev/null +++ b/form/src/app/common/custom-hot-zone/Unit.ts @@ -0,0 +1,3108 @@ + +import TWEEN from '@tweenjs/tween.js'; + +interface AirWindow extends Window { + air: any; + curCtx: any; +} +declare let window: AirWindow; + +class Sprite { + x = 0; + y = 0; + color = ''; + radius = 0; + alive = false; + margin = 0; + angle = 0; + ctx; + + constructor(ctx = null) { + if (!ctx) { + this.ctx = window.curCtx; + } else { + this.ctx = ctx; + } + } + update($event) { + this.draw(); + } + draw() { + + } + +} + + + + + +export class MySprite extends Sprite { + + _width = 0; + _height = 0; + _anchorX = 0; + _anchorY = 0; + _offX = 0; + _offY = 0; + scaleX = 1; + scaleY = 1; + _alpha = 1; + rotation = 0; + visible = true; + skewX = 0; + skewY = 0; + + _shadowFlag = false; + _shadowColor; + _shadowOffsetX = 0; + _shadowOffsetY = 0; + _shadowBlur = 5; + + _radius = 0; + + children = [this]; + + childDepandVisible = true; + childDepandAlpha = false; + + img; + _z = 0; + + _showRect; + + + _bitmapFlag = false; + _offCanvas; + _offCtx; + + + init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) { + + if (imgObj) { + + this.img = imgObj; + + this.width = this.img.width; + this.height = this.img.height; + + + } + + this.anchorX = anchorX; + this.anchorY = anchorY; + } + + + setShowRect(rect) { + this._showRect = rect; + } + + setShadow(offX, offY, blur, color = 'rgba(0, 0, 0, 0.3)') { + + + this._shadowFlag = true; + this._shadowColor = color; + this._shadowOffsetX = offX; + this._shadowOffsetY = offY; + this._shadowBlur = blur; + + } + + setRadius(r) { + this._radius = r; + } + + + + + update($event = null) { + if (!this.visible && this.childDepandVisible) { + return; + } + + this.draw(); + + } + draw() { + + this.ctx.save(); + + this.drawInit(); + + this.updateChildren(); + + this.ctx.restore(); + + + } + + drawInit() { + + this.ctx.translate(this.x, this.y); + + this.ctx.rotate(this.rotation * Math.PI / 180); + + this.ctx.scale(this.scaleX, this.scaleY); + + this.ctx.globalAlpha = this.alpha; + + this.ctx.transform(1, this.skewX, this.skewY, 1, 0, 0); + + + + + // + // if (this._radius) { + // + // const r = this._radius; + // const w = this.width; + // const h = this.height; + // + // this.ctx.lineTo(-w / 2, h / 2); // 创建水平线 + // this.ctx.arcTo(-w / 2, -h / 2, -w / 2 + r, -h / 2, r); + // this.ctx.arcTo(w / 2, -h / 2, w / 2, -h / 2 + r, r); + // this.ctx.arcTo(w / 2, h / 2, w / 2 - r, h / 2, r); + // this.ctx.arcTo(-w / 2, h / 2, -w / 2, h / 2 - r, r); + // + // this.ctx.clip(); + // } + + } + + drawSelf() { + + + + if (this._shadowFlag) { + + this.ctx.shadowOffsetX = this._shadowOffsetX; + this.ctx.shadowOffsetY = this._shadowOffsetY; + this.ctx.shadowBlur = this._shadowBlur; + this.ctx.shadowColor = this._shadowColor; + } else { + this.ctx.shadowOffsetX = 0; + this.ctx.shadowOffsetY = 0; + this.ctx.shadowBlur = null; + this.ctx.shadowColor = null; + } + + + if (this.img) { + + if (this._showRect) { + const rect = this._showRect; + this.ctx.drawImage(this.img, rect.x, rect.y, rect.width, rect.height, this._offX, this._offY + rect.y, this.width, rect.height); + } else { + this.ctx.drawImage(this.img, this._offX, this._offY); + } + } + + + + + } + + updateChildren() { + + if (this.children.length <= 0) { return; } + + for (const child of this.children) { + if (child === this) { + if (this.visible) { + this.drawSelf(); + } + } else { + child.update(); + } + } + } + + + load(url, anchorX = 0.5, anchorY = 0.5) { + + return new Promise((resolve, reject) => { + const img = new Image(); + img.onload = () => resolve(img); + img.onerror = reject; + img.src = url; + }).then(img => { + + this.init(img, anchorX, anchorY); + return img; + }); + } + + addChild(child, z = 1) { + if (this.children.indexOf(child) === -1) { + this.children.push(child); + child._z = z; + child.parent = this; + } + + this.children.sort((a, b) => { + return a._z - b._z; + }); + + + if (this.childDepandAlpha) { + child.alpha = this.alpha; + } + + } + removeChild(child) { + const index = this.children.indexOf(child); + if (index !== -1) { + this.children.splice(index, 1); + } + } + + removeChildren() { + for (let i = 0; i < this.children.length; i++) { + if (this.children[i]) { + if (this.children[i] !== this) { + this.children.splice(i, 1); + i --; + } + } + } + } + + _changeChildAlpha(alpha) { + for (const child of this.children) { + if (child !== this) { + child.alpha = alpha; + } + } + } + + + set btimapFlag(v) { + this._bitmapFlag = v; + } + get btimapFlag() { + return this._bitmapFlag; + } + set alpha(v) { + this._alpha = v; + if (this.childDepandAlpha) { + this._changeChildAlpha(v); + } + } + get alpha() { + return this._alpha; + } + set width(v) { + this._width = v; + this.refreshAnchorOff(); + } + get width() { + return this._width; + } + set height(v) { + this._height = v; + this.refreshAnchorOff(); + } + get height() { + return this._height; + } + set anchorX(value) { + this._anchorX = value; + this.refreshAnchorOff(); + } + get anchorX() { + return this._anchorX; + } + set anchorY(value) { + this._anchorY = value; + this.refreshAnchorOff(); + } + get anchorY() { + return this._anchorY; + } + refreshAnchorOff() { + this._offX = -this._width * this.anchorX; + this._offY = -this._height * this.anchorY; + } + + setScaleXY(value) { + this.scaleX = this.scaleY = value; + } + + getBoundingBox() { + + const getParentData = (item) => { + + let px = item.x; + let py = item.y; + + let sx = item.scaleX; + let sy = item.scaleY; + const parent = item.parent; + if (parent) { + + const obj = getParentData(parent); + + const _x = obj.px; + const _y = obj.py; + const _sx = obj.sx; + const _sy = obj.sy; + + px = _x + item.x * _sx; + py = _y + item.y * _sy; + + sx *= _sx; + sy *= _sy; + + } + + return {px, py, sx, sy}; + }; + + + const data = getParentData(this); + + + const x = data.px + this._offX * Math.abs(data.sx); + const y = data.py + this._offY * Math.abs(data.sy); + const width = this.width * Math.abs(data.sx); + const height = this.height * Math.abs(data.sy); + + return {x, y, width, height}; + } + +} + + +export class RoundSprite extends MySprite { + + _newCtx; + + init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) { + + if (imgObj) { + + this.img = imgObj; + + this.width = this.img.width; + this.height = this.img.height; + + + } + + this.anchorX = anchorX; + this.anchorY = anchorY; + + const canvas = window['curCanvas']; + const w = canvas.nativeElement.width; + const h = canvas.nativeElement.height; + + + this._offCanvas = document.createElement('canvas'); + this._offCanvas.width = w; + this._offCanvas.height = h; + + this._offCtx = this._offCanvas.getContext('2d'); + + // this._newCtx = this.ctx; + // this.ctx = this._offCtx; + + } + + + + drawSelf() { + // + // if (this._shadowFlag) { + // + // this.ctx.shadowOffsetX = this._shadowOffsetX; + // this.ctx.shadowOffsetY = this._shadowOffsetY; + // this.ctx.shadowBlur = this._shadowBlur; + // this.ctx.shadowColor = this._shadowColor; + // } else { + // this.ctx.shadowOffsetX = 0; + // this.ctx.shadowOffsetY = 0; + // this.ctx.shadowBlur = null; + // this.ctx.shadowColor = null; + // } + + + if (this._radius) { + + const r = this._radius; + const w = this.width; + const h = this.height; + const x = -this._offX; + const y = -this._offY; + + this._offCtx.lineTo(x - w / 2, y + h / 2); // 创建水平线 + this._offCtx.arcTo(x - w / 2, y - h / 2, x - w / 2 + r, y - h / 2, r); + this._offCtx.arcTo(x + w / 2, y - h / 2, x + w / 2, y - h / 2 + r, r); + this._offCtx.arcTo(x + w / 2, y + h / 2, x + w / 2 - r, y + h / 2, r); + this._offCtx.arcTo(x - w / 2, y + h / 2, x - w / 2, y + h / 2 - r, r); + + this._offCtx.clip(); + } + + + if (this.img) { + + this._offCtx.drawImage(this.img, 0, 0); + this.ctx.drawImage(this._offCanvas,this._offX, this._offX); + } + + } +} + + + + + +export class ColorSpr extends MySprite { + + r = 0; + g = 0; + b = 0; + + createGSCanvas() { + + if (!this.img) { + return; + } + + + + const rect = this.getBoundingBox(); + if (rect.width <= 1 || rect.height <= 1) { + return; + } + + + const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height); + for ( let i = 0; i < c.height; i++) { + for ( let j = 0; j < c.width; j++) { + + const x = (i * 4) * c.width + ( j * 4 ); + const r = c.data[x]; + const g = c.data[x + 1]; + const b = c.data[x + 2]; + + c.data[x] = this.r; + c.data[x + 1] = this.g; + c.data[x + 2] = this.b; + + + + // c.data[x] = c.data[x + 1] = c.data[x + 2] = (r + g + b) / 3 ; + // // c.data[x + 3] = 255; + } + } + + this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height); + } + + + drawSelf() { + super.drawSelf(); + this.createGSCanvas(); + } + +} + + +export class GrayscaleSpr extends MySprite { + + grayScale = 120; + + createGSCanvas() { + + if (!this.img) { + return; + } + + + + const rect = this.getBoundingBox(); + + const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height); + for ( let i = 0; i < c.height; i++) { + for ( let j = 0; j < c.width; j++) { + + const x = (i * 4) * c.width + ( j * 4 ); + const r = c.data[x]; + const g = c.data[x + 1]; + const b = c.data[x + 2]; + // const a = c.data[x + 3]; + + c.data[x] = c.data[x + 1] = c.data[x + 2] = this.grayScale; // (r + g + b) / 3; + // c.data[x + 3] = 255; + } + } + + this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height); + } + + + drawSelf() { + super.drawSelf(); + this.createGSCanvas(); + } + +} + + + + + + +export class BitMapLabel extends MySprite { + + + labelArr; + baseUrl; + + setText(data, text) { + + this.labelArr = []; + + const labelArr = []; + const tmpArr = text.split(''); + let totalW = 0; + let h = 0; + for (const tmp of tmpArr) { + + const label = new MySprite(this.ctx); + label.init(data[tmp], 0); + this.addChild(label); + labelArr.push(label); + + totalW += label.width; + h = label.height; + } + + + this.width = totalW; + this.height = h; + + let offX = -totalW / 2; + for (const label of labelArr) { + label.x = offX; + offX += label.width; + } + + this.labelArr = labelArr; + } + +} + + + + +export class Label extends MySprite { + private _text: string; + + // fontSize:String = '40px'; + fontName = 'Verdana'; + textAlign = 'left'; + fontSize = 40; + fontColor = '#000000'; + fontWeight = 900; + _maxWidth; + outline = 0; + outlineColor = '#ffffff'; + // _shadowFlag = false; + // _shadowColor; + // _shadowOffsetX; + // _shadowOffsetY; + // _shadowBlur; + + _outlineFlag = false; + + _outLineWidth; + _outLineColor; + constructor(ctx = null) { + super(ctx); + this.init(); + } + + + get text(): string { + return this._text; + } + + set text(value: string) { + this._text = value; + this.refreshSize(); + } + + refreshSize() { + + this.ctx.save(); + + this.ctx.font = `${this.fontSize * this.scaleX}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = this.fontWeight; + + this._width = this.ctx.measureText(this.text).width; + this._height = this.fontSize; + this.refreshAnchorOff(); + + this.ctx.restore(); + + } + + setMaxSize(w) { + + this._maxWidth = w; + this.refreshSize(); + if (this.width >= w) { + this.scaleX *= w / this.width; + this.scaleY *= w / this.width; + } + } + + show(callBack = null) { + + this.visible = true; + + if (this.alpha >= 1) { + return; + } + + const tween = new TWEEN.Tween(this) + .to({ alpha: 1 }, 800) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }) + .start(); // Start the tween immediately. + } + + setOutline(width = 5, color = '#ffffff') { + + this._outlineFlag = true; + this._outLineWidth = width; + this._outLineColor = color; + + } + + drawText() { + + + if (!this.text) { return; } + + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = this.fontWeight; + + if (this._outlineFlag) { + this.ctx.lineWidth = this._outLineWidth; + this.ctx.strokeStyle = this._outLineColor; + this.ctx.strokeText(this.text, 0, 0); + } + + this.ctx.fillStyle = this.fontColor; + + + + if (this.outline > 0) { + this.ctx.lineWidth = this.outline; + this.ctx.strokeStyle = this.outlineColor; + this.ctx.strokeText(this.text, 0, 0); + + } + + this.ctx.fillText(this.text, 0, 0); + + + } + + + drawSelf() { + super.drawSelf(); + this.drawText(); + } + +} + +export class RichTextOld extends Label { + + textArr = []; + fontSize = 40; + + setText(text: string, words) { + + let newText = text; + for (const word of words) { + + const re = new RegExp(word, 'g'); + newText = newText.replace( re, `#${word}#`); + // newText = newText.replace(word, `#${word}#`); + } + + this.textArr = newText.split('#'); + this.text = newText; + + // this.setSize(); + } + + refreshSize() { + + this.ctx.save(); + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = this.fontWeight; + + let curX = 0; + for (const text of this.textArr) { + const w = this.ctx.measureText(text).width; + curX += w; + } + + this.width = curX; + this.height = this.fontSize; + this.refreshAnchorOff(); + + this.ctx.restore(); + + } + + + show(callBack = null) { + + // console.log(' in show '); + this.visible = true; + // this.alpha = 0; + + const tween = new TWEEN.Tween(this) + .to({ alpha: 1 }, 800) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }) + .start(); // Start the tween immediately. + + } + + + + drawText() { + + // console.log('in drawText', this.text); + + if (!this.text) { return; } + + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = 900; + + this.ctx.lineWidth = 5; + this.ctx.strokeStyle = '#ffffff'; + // this.ctx.strokeText(this.text, 0, 0); + + this.ctx.fillStyle = '#000000'; + // this.ctx.fillText(this.text, 0, 0); + + + let curX = 0; + for (let i = 0; i < this.textArr.length; i++) { + + const w = this.ctx.measureText(this.textArr[i]).width; + + if ((i + 1) % 2 === 0) { + this.ctx.fillStyle = '#c8171e'; + } else { + this.ctx.fillStyle = '#000000'; + } + + this.ctx.fillText(this.textArr[i], curX, 0); + curX += w; + + } + + + } + +} + + + + + +export class RichText extends Label { + + + disH = 30; + + constructor(ctx?: any) { + super(ctx); + + // this.dataArr = dataArr; + } + + + + drawText() { + + if (!this.text) { + return; + } + + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = this.fontWeight; + this.ctx.fillStyle = this.fontColor; + + + const selfW = this.width * this.scaleX; + + + const chr = this.text.split(' '); + let temp = ''; + const row = []; + const w = selfW - 80; + const disH = (this.fontSize + this.disH) * this.scaleY; + + + + + for (const c of chr) { + if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) { + temp += ' ' + c; + } else { + row.push(temp); + temp = ' ' + c; + } + } + row.push(temp); + + const x = 0; + const y = -row.length * disH / 2; + // for (let b = 0 ; b < row.length; b++) { + // this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + // } + + + if (this._outlineFlag) { + this.ctx.lineWidth = this._outLineWidth; + this.ctx.strokeStyle = this._outLineColor; + for (let b = 0 ; b < row.length; b++) { + this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + } + // this.ctx.strokeText(this.text, 0, 0); + } + + + // this.ctx.fillStyle = '#ff7600'; + for (let b = 0 ; b < row.length; b++) { + this.ctx.fillText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + } + + } + + + drawSelf() { + super.drawSelf(); + this.drawText(); + } + +} + + + + +export class LineRect extends MySprite { + + lineColor = '#ffffff'; + lineWidth = 10; + + setSize(w, h) { + this.width = w; + this.height = h; + } + + drawLine() { + + this.ctx.beginPath(); + this.ctx.moveTo(this._offX, this._offY); + this.ctx.lineTo(this._offX + this.width, this._offY); + this.ctx.lineTo(this._offX + this.width, this._offY + this.height); + this.ctx.lineTo(this._offX, this._offY + this.height); + this.ctx.closePath(); + + this.ctx.lineWidth = this.lineWidth; + // this.ctx.fillStyle = "rgb(2,33,42)"; //指定填充颜色 + // this.ctx.fill(); //对多边形进行填充 + + this.ctx.strokeStyle = this.lineColor; // "#ffffff"; + this.ctx.stroke(); + + } + + + drawSelf() { + super.drawSelf(); + this.drawLine(); + } +} + + +export class ShapeRect extends MySprite { + + fillColor = '#FF0000'; + + setSize(w, h) { + this.width = w; + this.height = h; + + // console.log('w:', w); + // console.log('h:', h); + } + + drawShape() { + + this.ctx.fillStyle = this.fillColor; + this.ctx.fillRect(this._offX, this._offY, this.width, this.height); + + } + + + drawSelf() { + super.drawSelf(); + this.drawShape(); + } +} + + + +export class Line extends MySprite { + + + lineWidth = 5; + lineColor = '#000000'; + _pointArr = []; + + roundFlag = true; + + _pointS = 1; + + + imgObj; + bitMap; + _offCtx; + _offCanvas; + + lastPointIndex = 0; + + init() { + + const canvas = window['curCanvas']; + const w = canvas.nativeElement.width; + const h = canvas.nativeElement.height; + + console.log('w: ', w); + console.log('h: ', h); + + + this._offCanvas = document.createElement('canvas'); + this._offCanvas.width = w; + this._offCanvas.height = h; + // this._offCanvas = _offCanvas; + // this._offCtx = this._offCanvas.getContext('2d'); + + + // this._offCanvas = new OffscreenCanvas(w, h); + this._offCtx = this._offCanvas.getContext('2d'); + } + + addPoint(x, y) { + + this._pointArr.push([x, y]); + + if (this._pointArr.length < 2) { + return; + } + // + // const lastP = this._pointArr[this._pointArr.length - 1]; + // + // + // const context = this._offCtx; + // context.moveTo (lastP[0], lastP[1]); // è®¾ç½®èµ·ç‚¹çŠ¶æ€ + // context.lineTo (x, y); // è®¾ç½®æœ«ç«¯çŠ¶æ€ + // + // context.lineWidth = this.lineWidth; //è®¾ç½®çº¿å®½çŠ¶æ€ + // context.strokeStyle = this.lineColor; + // context.stroke(); + // + // + // this.bitMap = this._offCanvas.transferToImageBitmap(); + + + + // const tmpLine = new MySprite(this._offCtx); + // tmpLine.init(this.imgObj); + // tmpLine.anchorY = 1; + // tmpLine.anchorX = 0.5; + // tmpLine.x = lastP[0]; + // tmpLine.y = lastP[1]; + // + // const disH = getPosDistance(lastP[0], lastP[1], x, y); + // tmpLine.scaleX = this.lineWidth / tmpLine.width; + // tmpLine.scaleY = disH / tmpLine.height * 1.1; + // + // const angle = getAngleByPos(lastP[0], lastP[1], x, y); + // tmpLine.rotation = angle; + // + // this.addChild(tmpLine); + + } + + setPointArr(arr, imgObj) { + + this.removeChildren(); + + if (arr.length < 2) { + return; + } + + let p1 = arr[0]; + let p2; + for (let i = 1; i < arr.length; i++) { + + p2 = arr[i]; + + const tmpLine = new MySprite(); + tmpLine.init(imgObj); + tmpLine.anchorY = 1; + tmpLine.anchorX = 0.5; + tmpLine.x = p1[0]; + tmpLine.y = p1[1]; + + const disH = getPosDistance(p1[0], p1[1], p2[0], p2[1]); + tmpLine.scaleX = this.lineWidth / tmpLine.width; + tmpLine.scaleY = disH / tmpLine.height * 1.1; + + const angle = getAngleByPos(p1[0], p1[1], p2[0], p2[1]); + tmpLine.rotation = angle; + + this.addChild(tmpLine); + + p1 = p2; + } + } + + + + + drawLine() { + + if (this._pointArr.length < 2) { + return; + } + + + const curMaxPointIndex = this._pointArr.length - 1; + if (curMaxPointIndex > this.lastPointIndex) { + + const arr = this._pointArr; + + const context = this._offCtx; + context.moveTo (arr[this.lastPointIndex][0] * this._pointS, arr[this.lastPointIndex][1] * this._pointS); // è®¾ç½®èµ·ç‚¹çŠ¶æ€ + for (let i = this.lastPointIndex + 1; i < arr.length; i++) { + context.lineTo (arr[i][0] * this._pointS, arr[i][1] * this._pointS); // è®¾ç½®æœ«ç«¯çŠ¶æ€ + } + + if (this.roundFlag) { + context.lineCap = "round"; + } + context.lineWidth = this.lineWidth; //è®¾ç½®çº¿å®½çŠ¶æ€ + context.strokeStyle = this.lineColor; + context.stroke(); + + + this.lastPointIndex = curMaxPointIndex; + + // this.bitMap = this._offCanvas.transferToImageBitmap(); + + } + + + // this.ctx.drawImage(this.bitMap, this._offX, this._offY); + this.ctx.drawImage(this._offCanvas, this._offX, this._offY); + + } + + drawSelf() { + super.drawSelf(); + this.drawLine(); + + + // if (this.img) { + // this.ctx.drawImage(this._offCanvas, 0, 0, this.width, this.height); + // } + + // if (this.bitMap) { + // this.bitMap = this._offCanvas.transferToImageBitmap(); + // this.ctx.drawImage(this.bitMap, 0, 0, this.width, this.height); + // } + + } +} + + +export class ShapeCircle extends MySprite { + + fillColor = '#FF0000'; + radius = 0; + + + setRadius(r) { + this.anchorX = this.anchorY = 0.5; + + this.radius = r; + this.width = r * 2; + this.height = r * 2; + } + + drawShape() { + + this.ctx.beginPath(); + this.ctx.fillStyle = this.fillColor; + this.ctx.arc(0, 0, this.radius, 0, angleToRadian(360)); + this.ctx.fill(); + } + + drawSelf() { + super.drawSelf(); + this.drawShape(); + } +} + + + + +export class ShapeRectNew extends MySprite { + + + radius = 0; + fillColor = '#ffffff'; + strokeColor = '#000000'; + fill = true; + stroke = false; + lineWidth = 1; + + setSize(w, h, r) { + this.width = w; + this.height = h; + this.radius = r; + } + + setOutLine(color, lineWidth) { + this.stroke = true; + this.strokeColor = color; + this.lineWidth = lineWidth; + } + + + drawShape() { + + const ctx = this.ctx; + const width = this.width; + const height = this.height; + const radius = this.radius; + + ctx.save(); + ctx.beginPath(0); + // 从å³ä¸‹è§’顺时针绘制,弧度从0到1/2PI + ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2); + + // 矩形下边线 + ctx.lineTo(radius, height); + + // 左下角圆弧,弧度从1/2PI到PI + ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI); + + // 矩形左边线 + ctx.lineTo(0, radius); + + // 左上角圆弧,弧度从PI到3/2PI + ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2); + + // 上边线 + ctx.lineTo(width - radius, 0); + + // å³ä¸Šè§’圆弧 + ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2); + + // å³è¾¹çº¿ + ctx.lineTo(width, height - radius); + ctx.closePath(); + + if (this.fill) { + ctx.fillStyle = this.fillColor; + ctx.fill(); + } + if (this.stroke) { + ctx.lineWidth = this.lineWidth; + ctx.strokeStyle = this.strokeColor; + ctx.stroke(); + } + ctx.restore(); + + } + + + drawSelf() { + super.drawSelf(); + this.drawShape(); + } + +} +export class MyAnimation extends MySprite { + + + frameArr = []; + frameIndex = 0; + playFlag = false; + lastDateTime; + curDelay = 0; + + + loop = false; + playEndFunc; + delayPerUnit = 1; + + restartFlag = false; + reverseFlag = false; + + addFrameByImg(img) { + + const spr = new MySprite(this.ctx); + spr.init(img); + this._refreshSize(img); + + spr.visible = false; + + this.addChild(spr); + this.frameArr.push(spr); + + this.frameArr[this.frameIndex].visible = true; + } + + addFrameByUrl(url) { + + const spr = new MySprite(this.ctx); + spr.load(url).then(img => { + + this._refreshSize(img); + }); + spr.visible = false; + + this.addChild(spr); + this.frameArr.push(spr); + + this.frameArr[this.frameIndex].visible = true; + } + + _refreshSize(img: any) { + + if (this.width < img.width) { + this.width = img.width; + } + if (this.height < img.height) { + this.height = img.height; + } + } + + + + play() { + this.playFlag = true; + this.lastDateTime = new Date().getTime(); + } + + stop() { + this.playFlag = false; + } + + + replay() { + this.restartFlag = true; + this.play(); + } + + + reverse() { + this.reverseFlag = !this.reverseFlag; + this.frameArr.reverse(); + this.frameIndex = 0; + } + + showAllFrame() { + for (const frame of this.frameArr ) { + frame.alpha = 1; + } + } + + hideAllFrame() { + for (const frame of this.frameArr) { + frame.alpha = 0; + } + } + + + playEnd() { + + this.playFlag = false; + this.curDelay = 0; + + this.frameArr[this.frameIndex].visible = true; + + if (this.playEndFunc) { + this.playEndFunc(); + this.playEndFunc = null; + } + } + + updateFrame() { + if (this.frameArr[this.frameIndex]) { + this.frameArr[this.frameIndex].visible = false; + } + + this.frameIndex ++; + if (this.frameIndex >= this.frameArr.length) { + if (this.loop) { + this.frameIndex = 0; + } else if (this.restartFlag) { + this.restartFlag = false; + this.frameIndex = 0; + } else { + this.frameIndex -- ; + this.playEnd(); + return; + } + } + + this.frameArr[this.frameIndex].visible = true; + + } + + + + + _updateDelay(delay) { + + this.curDelay += delay; + if (this.curDelay < this.delayPerUnit) { + return; + } + this.curDelay -= this.delayPerUnit; + this.updateFrame(); + } + + _updateLastDate() { + if (!this.playFlag) { return; } + + let delay = 0; + if (this.lastDateTime) { + delay = (new Date().getTime() - this.lastDateTime) / 1000; + } + this.lastDateTime = new Date().getTime(); + this._updateDelay(delay); + } + + update($event: any = null) { + super.update($event); + this._updateLastDate(); + } + + +} + + + + +// --------=========== util func =============------------- + + +export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) { + + const tween = new TWEEN.Tween(item).to(obj, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + if (update) { + tween.onUpdate( (a, b) => { + update(a, b); + }); + } + + tween.start(); + return tween; +} + + + + +export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null) { + + const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + + +export function scaleItem(item, scale, time = 0.8, callBack = null, easing = null) { + + const tween = new TWEEN.Tween(item).to({ scaleX: scale, scaleY: scale}, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + + tween.start(); + return tween; +} + + +export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null) { + + const tween = new TWEEN.Tween(item).to({ x, y}, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + + tween.start(); + + return tween; +} + + + + + + + +export function endShow(item, s = 1) { + + item.scaleX = item.scaleY = 0; + item.alpha = 0; + + const tween = new TWEEN.Tween(item) + .to({ alpha: 1, scaleX: s, scaleY: s }, 800) + .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + + }) + .start(); +} + +export function hideItem(item, time = 0.8, callBack = null, easing = null) { + + if (item.alpha === 0) { + return; + } + + const tween = new TWEEN.Tween(item) + .to({alpha: 0}, time * 1000) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }); + + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + +export function showItem(item, time = 0.8, callBack = null, easing = null) { + + if (item.alpha === 1) { + if (callBack) { + callBack(); + } + return; + } + + item.visible = true; + const tween = new TWEEN.Tween(item) + .to({alpha: 1}, time * 1000) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }); + + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + +export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = null) { + + + const tween = new TWEEN.Tween(item) + .to({alpha}, time * 1000) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }); + + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + +export function showStar(item, time = 0.8, callBack = null, easing = null) { + + + const tween = new TWEEN.Tween(item) + .to({alpha: 1, scale: 1}, time * 1000) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }); + + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + +export function randomSortByArr(arr) { + if (!arr) { + return; + } + const newArr = []; + const tmpArr = arr.concat(); + while (tmpArr.length > 0) { + const randomIndex = Math.floor( tmpArr.length * Math.random() ); + newArr.push(tmpArr[randomIndex]); + tmpArr.splice(randomIndex, 1); + } + return newArr; +} + + +export function radianToAngle(radian) { + return radian * 180 / Math.PI; + // 角度 = 弧度 * 180 / Math.PI; +} + +export function angleToRadian(angle) { + return angle * Math.PI / 180; + // 弧度= 角度 * Math.PI / 180; +} + +export function getPosByAngle(angle, len) { + + const radian = angle * Math.PI / 180; + const x = Math.sin(radian) * len; + const y = Math.cos(radian) * len; + + return {x, y}; + +} + +export function getAngleByPos(px, py, mx, my) { + + const x = Math.abs(px - mx); + const y = Math.abs(py - my); + + const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + const cos = y / z; + const radina = Math.acos(cos); // 用å三角函数求弧度 + let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // å°†å¼§åº¦è½¬æ¢æˆè§’度 + + if (mx > px && my > py) {// é¼ æ ‡åœ¨ç¬¬å››è±¡é™ + angle = 180 - angle; + } + if (mx === px && my > py) {// é¼ æ ‡åœ¨yè½´è´Ÿæ–¹å‘上 + angle = 180; + } + if (mx > px && my === py) {// é¼ æ ‡åœ¨xè½´æ£æ–¹å‘上 + angle = 90; + } + if (mx < px && my > py) {// é¼ æ ‡åœ¨ç¬¬ä¸‰è±¡é™ + angle = 180 + angle; + } + if (mx < px && my === py) {// é¼ æ ‡åœ¨xè½´è´Ÿæ–¹å‘ + angle = 270; + } + if (mx < px && my < py) {// é¼ æ ‡åœ¨ç¬¬äºŒè±¡é™ + angle = 360 - angle; + } + + // console.log('angle: ', angle); + return angle; + +} + + +export function removeItemFromArr(arr, item) { + const index = arr.indexOf(item); + if (index !== -1) { + arr.splice(index, 1); + } +} + + + + + + +export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null) { + + const r = getPosDistance(item.x, item.y, x0, y0); + let a = getAngleByPos(item.x, item.y, x0, y0); + a += 90; + const obj = {r, a}; + + item._circleAngle = a; + const targetA = a + addR; + + const tween = new TWEEN.Tween(item).to({_circleAngle: targetA}, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + + tween.onUpdate( (item, progress) => { + + // console.log(item._circleAngle); + const r = obj.r; + const a = item._circleAngle; + + const x = x0 + r * xPer * Math.cos(a * Math.PI / 180); + const y = y0 + r * yPer * Math.sin(a * Math.PI / 180); + + item.x = x; + item.y = y; + + // obj.a ++; + }); + + tween.start(); +} + + +export function getPosDistance(sx, sy, ex, ey) { + + const _x = ex - sx; + const _y = ey - sy; + const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) ); + return len; +} + +export function delayCall(callback, second) { + const tween = new TWEEN.Tween(this) + .delay(second * 1000) + .onComplete(() => { + if (callback) { + callback(); + } + }) + .start(); +} + + +export function formatTime(fmt, date) { + + // "yyyy-MM-dd HH:mm:ss"; + + const o = { + 'M+': date.getMonth() + 1, // 月份 + 'd+': date.getDate(), // æ—¥ + 'h+': date.getHours(), // å°æ—¶ + 'm+': date.getMinutes(), // 分 + 's+': date.getSeconds(), // ç§’ + 'q+': Math.floor((date.getMonth() + 3) / 3), // å£åº¦ + S: date.getMilliseconds() // 毫秒 + }; + if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); } + for (const k in o) { + if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) + ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))); + } + } + return fmt; +} + +export function getMinScale(item, maxLen) { + const sx = maxLen / item.width; + const sy = maxLen / item.height; + const minS = Math.min(sx, sy); + return minS; +} + + + +export function jelly(item, time = 0.7) { + + + if (item.jellyTween) { + TWEEN.remove(item.jellyTween); + } + + const t = time / 9; + const baseSX = item.scaleX; + const baseSY = item.scaleY; + let index = 0; + + const run = () => { + if (index >= arr.length) { + item.jellyTween = null; + return; + } + const data = arr[index]; + const t = tweenChange(item, {scaleX: data[0], scaleY: data[1]}, data[2], () => { + index ++; + run(); + }, TWEEN.Easing.Sinusoidal.InOut); + item.jellyTween = t; + }; + + const arr = [ + [baseSX * 1.1, baseSY * 0.9, t], + [baseSX * 0.98, baseSY * 1.02, t * 2], + [baseSX * 1.02, baseSY * 0.98, t * 2], + [baseSX * 0.99, baseSY * 1.01, t * 2], + [baseSX * 1.0, baseSY * 1.0, t * 2], + ]; + + + run(); +} + + + +export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) { + + + for (let i = 0; i < num; i ++) { + + const particle = new MySprite(); + particle.init(img); + particle.x = pos.x; + particle.y = pos.y; + parent.addChild(particle); + + const randomR = 360 * Math.random(); + particle.rotation = randomR; + + const randomS = 0.3 + Math.random() * 0.7; + particle.setScaleXY(randomS * 0.3); + + const randomX = Math.random() * 20 - 10; + particle.x += randomX; + + const randomY = Math.random() * 20 - 10; + particle.y += randomY; + + const randomL = minLen + Math.random() * (maxLen - minLen); + const randomA = 360 * Math.random(); + const randomT = getPosByAngle(randomA, randomL); + moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, showTime, () => { + + + + }, TWEEN.Easing.Exponential.Out); + + // scaleItem(particle, 0, 0.6, () => { + // + // }); + + scaleItem(particle, randomS, 0.6, () => { + + }, TWEEN.Easing.Exponential.Out); + + setTimeout(() => { + + hideItem(particle, 0.4, () => { + + }, TWEEN.Easing.Cubic.In); + + }, showTime * 0.5 * 1000); + + + } +} + + + +export function shake(item, time = 0.5, callback = null, rate = 1) { + + if (item.shakeTween) { + return; + } + + item.shakeTween = true; + const offX = 15 * item.scaleX * rate; + const offY = 15 * item.scaleX * rate; + const baseX = item.x; + const baseY = item.y; + const easing = TWEEN.Easing.Sinusoidal.InOut; + + + const move4 = () => { + moveItem(item, baseX, baseY, time / 4, () => { + item.shakeTween = false; + if (callback) { + callback(); + } + }, easing); + }; + + const move3 = () => { + moveItem(item, baseX + offX / 4, baseY + offY / 4, time / 4, () => { + move4(); + }, easing); + }; + + const move2 = () => { + moveItem(item, baseX - offX / 4 * 3, baseY - offY / 4 * 3, time / 4, () => { + move3(); + }, easing); + }; + + const move1 = () => { + moveItem(item, baseX + offX, baseY + offY, time / 7.5, () => { + move2(); + }, easing); + }; + + move1(); + +} + +// --------------- custom class -------------------- + + + +export class HotZoneItem extends MySprite { + + + lineDashFlag = false; + arrow: MySprite; + label: Label; + title; + + arrowTop; + arrowRight; + + audio_url; + pic_url; + text; + private _itemType; + private shapeRect: ShapeRect; + + get itemType() { + return this._itemType; + } + set itemType(value) { + this._itemType = value; + } + + setSize(w, h) { + this.width = w; + this.height = h; + + + const rect = new ShapeRect(this.ctx); + rect.x = -w / 2; + rect.y = -h / 2; + rect.setSize(w, h); + rect.fillColor = '#ffffff'; + rect.alpha = 0.2; + this.addChild(rect); + } + + showLabel(text = null) { + + + if (!this.label) { + this.label = new Label(this.ctx); + this.label.anchorY = 0; + this.label.fontSize = 40; + this.label.textAlign = 'center'; + this.addChild(this.label); + // this.label.scaleX = 1 / this.scaleX; + // this.label.scaleY = 1 / this.scaleY; + + this.refreshLabelScale(); + + } + + if (text) { + this.label.text = text; + } else if (this.title) { + this.label.text = this.title; + } + this.label.visible = true; + + } + + hideLabel() { + if (!this.label) { return; } + + this.label.visible = false; + } + + refreshLabelScale() { + if (this.scaleX == this.scaleY) { + this.label.setScaleXY(1); + } + + if (this.scaleX > this.scaleY) { + this.label.scaleX = this.scaleY / this.scaleX; + } else { + this.label.scaleY = this.scaleX / this.scaleY; + } + } + + showLineDash() { + this.lineDashFlag = true; + + if (this.arrow) { + this.arrow.visible = true; + } else { + this.arrow = new MySprite(this.ctx); + this.arrow.load('assets/common/arrow.png', 1, 0); + this.arrow.setScaleXY(0.06); + + this.arrowTop = new MySprite(this.ctx); + this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0); + this.arrowTop.setScaleXY(0.06); + + this.arrowRight = new MySprite(this.ctx); + this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5); + this.arrowRight.setScaleXY(0.06); + } + + this.showLabel(); + } + + hideLineDash() { + + this.lineDashFlag = false; + + if (this.arrow) { + this.arrow.visible = false; + } + + this.hideLabel(); + } + + + + drawArrow() { + if (!this.arrow) { return; } + + const rect = this.getBoundingBox(); + this.arrow.x = rect.x + rect.width; + this.arrow.y = rect.y; + + this.arrow.update(); + + + this.arrowTop.x = rect.x + rect.width / 2; + this.arrowTop.y = rect.y; + this.arrowTop.update(); + + this.arrowRight.x = rect.x + rect.width; + this.arrowRight.y = rect.y + rect.height / 2; + this.arrowRight.update(); + } + + drawFrame() { + + + this.ctx.save(); + + + const rect = this.getBoundingBox(); + + const w = rect.width; + const h = rect.height; + const x = rect.x + w / 2; + const y = rect.y + h / 2; + + this.ctx.setLineDash([5, 5]); + this.ctx.lineWidth = 2; + this.ctx.strokeStyle = '#1bfff7'; + // this.ctx.fillStyle = '#ffffff'; + + this.ctx.beginPath(); + + this.ctx.moveTo( x - w / 2, y - h / 2); + + this.ctx.lineTo(x + w / 2, y - h / 2); + + this.ctx.lineTo(x + w / 2, y + h / 2); + + this.ctx.lineTo(x - w / 2, y + h / 2); + + this.ctx.lineTo(x - w / 2, y - h / 2); + + // this.ctx.fill(); + this.ctx.stroke(); + + + + + this.ctx.restore(); + + } + + draw() { + super.draw(); + + if (this.lineDashFlag) { + this.drawFrame(); + this.drawArrow(); + } + } +} + +export class HotZoneImg extends MySprite { + + drawFrame() { + + this.ctx.save(); + + const rect = this.getBoundingBox(); + const w = rect.width; + const h = rect.height; + const x = rect.x + w / 2; + const y = rect.y + h / 2; + + this.ctx.setLineDash([5, 5]); + this.ctx.lineWidth = 2; + this.ctx.strokeStyle = '#1bfff7'; + + this.ctx.beginPath(); + this.ctx.moveTo( x - w / 2, y - h / 2); + this.ctx.lineTo(x + w / 2, y - h / 2); + this.ctx.lineTo(x + w / 2, y + h / 2); + this.ctx.lineTo(x - w / 2, y + h / 2); + this.ctx.lineTo(x - w / 2, y - h / 2); + + // this.ctx.fill(); + this.ctx.stroke(); + + this.ctx.restore(); + } + + draw() { + super.draw(); + + this.drawFrame(); + } +} + +export class HotZoneLabel extends Label { + + drawFrame() { + + this.ctx.save(); + + const rect = this.getBoundingBox(); + const w = rect.width / this.scaleX; + const h = this.height * this.scaleY; + const x = this.x; + const y = this.y; + + this.ctx.setLineDash([5, 5]); + this.ctx.lineWidth = 2; + this.ctx.strokeStyle = '#1bfff7'; + + this.ctx.beginPath(); + this.ctx.moveTo( x - w / 2, y - h / 2); + this.ctx.lineTo(x + w / 2, y - h / 2); + this.ctx.lineTo(x + w / 2, y + h / 2); + this.ctx.lineTo(x - w / 2, y + h / 2); + this.ctx.lineTo(x - w / 2, y - h / 2); + + // this.ctx.fill(); + this.ctx.stroke(); + + this.ctx.restore(); + } + + draw() { + super.draw(); + + this.drawFrame(); + } +} + + + + +export class EditorItem extends MySprite { + + lineDashFlag = false; + arrow: MySprite; + label: Label; + text; + + showLabel(text = null) { + + + if (!this.label) { + this.label = new Label(this.ctx); + this.label.anchorY = 0; + this.label.fontSize = 50; + this.label.textAlign = 'center'; + this.addChild(this.label); + this.label.setScaleXY(1 / this.scaleX); + } + + if (text) { + this.label.text = text; + } else if (this.text) { + this.label.text = this.text; + } + this.label.visible = true; + + } + + hideLabel() { + if (!this.label) { return; } + + this.label.visible = false; + } + + showLineDash() { + this.lineDashFlag = true; + + if (this.arrow) { + this.arrow.visible = true; + } else { + this.arrow = new MySprite(this.ctx); + this.arrow.load('assets/common/arrow.png', 1, 0); + this.arrow.setScaleXY(0.06); + + } + + this.showLabel(); + } + + hideLineDash() { + + this.lineDashFlag = false; + + if (this.arrow) { + this.arrow.visible = false; + } + + this.hideLabel(); + } + + + + drawArrow() { + if (!this.arrow) { return; } + + const rect = this.getBoundingBox(); + this.arrow.x = rect.x + rect.width; + this.arrow.y = rect.y; + + this.arrow.update(); + } + + drawFrame() { + + + this.ctx.save(); + + + const rect = this.getBoundingBox(); + + const w = rect.width; + const h = rect.height; + const x = rect.x + w / 2; + const y = rect.y + h / 2; + + this.ctx.setLineDash([5, 5]); + this.ctx.lineWidth = 2; + this.ctx.strokeStyle = '#1bfff7'; + // this.ctx.fillStyle = '#ffffff'; + + this.ctx.beginPath(); + + this.ctx.moveTo( x - w / 2, y - h / 2); + + this.ctx.lineTo(x + w / 2, y - h / 2); + + this.ctx.lineTo(x + w / 2, y + h / 2); + + this.ctx.lineTo(x - w / 2, y + h / 2); + + this.ctx.lineTo(x - w / 2, y - h / 2); + + // this.ctx.fill(); + this.ctx.stroke(); + + + + + this.ctx.restore(); + + } + + draw() { + super.draw(); + + if (this.lineDashFlag) { + this.drawFrame(); + this.drawArrow(); + } + } +} + + + +// +// +// import TWEEN from '@tweenjs/tween.js'; +// +// +// class Sprite { +// x = 0; +// y = 0; +// color = ''; +// radius = 0; +// alive = false; +// margin = 0; +// angle = 0; +// ctx; +// +// constructor(ctx) { +// this.ctx = ctx; +// } +// update($event) { +// this.draw(); +// } +// draw() { +// +// } +// +// } +// +// +// +// +// +// export class MySprite extends Sprite { +// +// width = 0; +// height = 0; +// _anchorX = 0; +// _anchorY = 0; +// _offX = 0; +// _offY = 0; +// scaleX = 1; +// scaleY = 1; +// alpha = 1; +// rotation = 0; +// visible = true; +// +// children = [this]; +// +// img; +// _z = 0; +// +// +// init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) { +// +// if (imgObj) { +// +// this.img = imgObj; +// +// this.width = this.img.width; +// this.height = this.img.height; +// } +// +// this.anchorX = anchorX; +// this.anchorY = anchorY; +// } +// +// +// +// update($event = null) { +// if (this.visible) { +// this.draw(); +// } +// } +// draw() { +// +// this.ctx.save(); +// +// this.drawInit(); +// +// this.updateChildren(); +// +// this.ctx.restore(); +// } +// +// drawInit() { +// +// this.ctx.translate(this.x, this.y); +// +// this.ctx.rotate(this.rotation * Math.PI / 180); +// +// this.ctx.scale(this.scaleX, this.scaleY); +// +// this.ctx.globalAlpha = this.alpha; +// +// } +// +// drawSelf() { +// if (this.img) { +// this.ctx.drawImage(this.img, this._offX, this._offY); +// } +// } +// +// updateChildren() { +// +// if (this.children.length <= 0) { return; } +// +// for (let i = 0; i < this.children.length; i++) { +// +// if (this.children[i] === this) { +// +// this.drawSelf(); +// } else { +// +// this.children[i].update(); +// } +// } +// } +// +// +// load(url, anchorX = 0.5, anchorY = 0.5) { +// +// return new Promise((resolve, reject) => { +// const img = new Image(); +// img.onload = () => resolve(img); +// img.onerror = reject; +// img.src = url; +// }).then(img => { +// +// this.init(img, anchorX, anchorY); +// return img; +// }); +// } +// +// addChild(child, z = 1) { +// if (this.children.indexOf(child) === -1) { +// this.children.push(child); +// child._z = z; +// child.parent = this; +// } +// +// this.children.sort((a, b) => { +// return a._z - b._z; +// }); +// +// } +// removeChild(child) { +// const index = this.children.indexOf(child); +// if (index !== -1) { +// this.children.splice(index, 1); +// } +// } +// +// set anchorX(value) { +// this._anchorX = value; +// this.refreshAnchorOff(); +// } +// get anchorX() { +// return this._anchorX; +// } +// set anchorY(value) { +// this._anchorY = value; +// this.refreshAnchorOff(); +// } +// get anchorY() { +// return this._anchorY; +// } +// refreshAnchorOff() { +// this._offX = -this.width * this.anchorX; +// this._offY = -this.height * this.anchorY; +// } +// +// setScaleXY(value) { +// this.scaleX = this.scaleY = value; +// } +// +// getBoundingBox() { +// +// const x = this.x + this._offX * this.scaleX; +// const y = this.y + this._offY * this.scaleY; +// const width = this.width * this.scaleX; +// const height = this.height * this.scaleY; +// +// return {x, y, width, height}; +// } +// +// } +// +// +// +// +// +// export class Item extends MySprite { +// +// baseX; +// +// move(targetY, callBack) { +// +// const self = this; +// +// const tween = new TWEEN.Tween(this) +// .to({ y: targetY }, 2500) +// .easing(TWEEN.Easing.Quintic.Out) +// .onComplete(function() { +// +// self.hide(callBack); +// // if (callBack) { +// // callBack(); +// // } +// }) +// .start(); +// +// } +// +// show(callBack = null) { +// +// const tween = new TWEEN.Tween(this) +// .to({ alpha: 1 }, 800) +// // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. +// .onComplete(function() { +// if (callBack) { +// callBack(); +// } +// }) +// .start(); // Start the tween immediately. +// +// } +// +// hide(callBack = null) { +// +// const tween = new TWEEN.Tween(this) +// .to({ alpha: 0 }, 800) +// // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. +// .onComplete(function() { +// if (callBack) { +// callBack(); +// } +// }) +// .start(); // Start the tween immediately. +// } +// +// +// shake(id) { +// +// +// if (!this.baseX) { +// this.baseX = this.x; +// } +// +// const baseX = this.baseX; +// const baseTime = 50; +// const sequence = [ +// {target: {x: baseX + 40 * id}, time: baseTime - 25}, +// {target: {x: baseX - 20 * id}, time: baseTime}, +// {target: {x: baseX + 10 * id}, time: baseTime}, +// {target: {x: baseX - 5 * id}, time: baseTime}, +// {target: {x: baseX + 2 * id}, time: baseTime}, +// {target: {x: baseX - 1 * id}, time: baseTime}, +// {target: {x: baseX}, time: baseTime}, +// +// ]; +// +// +// const self = this; +// +// function runSequence() { +// +// if (self['shakeTween']) { +// self['shakeTween'].stop(); +// } +// +// const tween = new TWEEN.Tween(self); +// +// if (sequence.length > 0) { +// // console.log('sequence.length: ', sequence.length); +// const action = sequence.shift(); +// tween.to(action['target'], action['time']); +// tween.onComplete( () => { +// runSequence(); +// }); +// tween.start(); +// +// self['shakeTween'] = tween; +// } +// } +// +// runSequence(); +// +// } +// +// +// +// drop(targetY, callBack = null) { +// +// const self = this; +// +// const time = Math.abs(targetY - this.y) * 2.4; +// +// this.alpha = 1; +// +// const tween = new TWEEN.Tween(this) +// .to({ y: targetY }, time) +// .easing(TWEEN.Easing.Cubic.In) +// .onComplete(function() { +// +// // self.hideItem(callBack); +// if (callBack) { +// callBack(); +// } +// }) +// .start(); +// +// +// } +// +// +// } +// +// +// export class EndSpr extends MySprite { +// +// show(s) { +// +// this.scaleX = this.scaleY = 0; +// this.alpha = 0; +// +// const tween = new TWEEN.Tween(this) +// .to({ alpha: 1, scaleX: s, scaleY: s }, 800) +// .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth. +// .onComplete(function() { +// +// }) +// .start(); // Start the tween immediately. +// +// } +// } +// +// +// +// export class ShapeRect extends MySprite { +// +// fillColor = '#FF0000'; +// +// setSize(w, h) { +// this.width = w; +// this.height = h; +// +// console.log('w:', w); +// console.log('h:', h); +// } +// +// drawShape() { +// +// this.ctx.fillStyle = this.fillColor; +// this.ctx.fillRect(this._offX, this._offY, this.width, this.height); +// +// } +// +// +// drawSelf() { +// super.drawSelf(); +// this.drawShape(); +// } +// } +// +// +// export class HotZoneItem extends MySprite { +// +// +// lineDashFlag = false; +// arrow: MySprite; +// label: Label; +// title; +// +// arrowTop; +// arrowRight; +// +// audio_url; +// pic_url; +// text; +// private _itemType; +// private shapeRect: ShapeRect; +// +// get itemType() { +// return this._itemType; +// } +// set itemType(value) { +// this._itemType = value; +// } +// +// setSize(w, h) { +// this.width = w; +// this.height = h; +// +// +// const rect = new ShapeRect(this.ctx); +// rect.x = -w / 2; +// rect.y = -h / 2; +// rect.setSize(w, h); +// rect.fillColor = '#ffffff'; +// rect.alpha = 0.2; +// this.addChild(rect); +// } +// +// showLabel(text = null) { +// +// +// if (!this.label) { +// this.label = new Label(this.ctx); +// this.label.anchorY = 0; +// this.label.fontSize = '40px'; +// this.label.textAlign = 'center'; +// this.addChild(this.label); +// // this.label.scaleX = 1 / this.scaleX; +// // this.label.scaleY = 1 / this.scaleY; +// +// this.refreshLabelScale(); +// +// } +// +// if (text) { +// this.label.text = text; +// } else if (this.title) { +// this.label.text = this.title; +// } +// this.label.visible = true; +// +// } +// +// hideLabel() { +// if (!this.label) { return; } +// +// this.label.visible = false; +// } +// +// refreshLabelScale() { +// if (this.scaleX == this.scaleY) { +// this.label.setScaleXY(1); +// } +// +// if (this.scaleX > this.scaleY) { +// this.label.scaleX = this.scaleY / this.scaleX; +// } else { +// this.label.scaleY = this.scaleX / this.scaleY; +// } +// } +// +// showLineDash() { +// this.lineDashFlag = true; +// +// if (this.arrow) { +// this.arrow.visible = true; +// } else { +// this.arrow = new MySprite(this.ctx); +// this.arrow.load('assets/common/arrow.png', 1, 0); +// this.arrow.setScaleXY(0.06); +// +// this.arrowTop = new MySprite(this.ctx); +// this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0); +// this.arrowTop.setScaleXY(0.06); +// +// this.arrowRight = new MySprite(this.ctx); +// this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5); +// this.arrowRight.setScaleXY(0.06); +// } +// +// this.showLabel(); +// } +// +// hideLineDash() { +// +// this.lineDashFlag = false; +// +// if (this.arrow) { +// this.arrow.visible = false; +// } +// +// this.hideLabel(); +// } +// +// +// +// drawArrow() { +// if (!this.arrow) { return; } +// +// const rect = this.getBoundingBox(); +// this.arrow.x = rect.x + rect.width; +// this.arrow.y = rect.y; +// +// this.arrow.update(); +// +// +// this.arrowTop.x = rect.x + rect.width / 2; +// this.arrowTop.y = rect.y; +// this.arrowTop.update(); +// +// this.arrowRight.x = rect.x + rect.width; +// this.arrowRight.y = rect.y + rect.height / 2; +// this.arrowRight.update(); +// } +// +// drawFrame() { +// +// +// this.ctx.save(); +// +// +// const rect = this.getBoundingBox(); +// +// const w = rect.width; +// const h = rect.height; +// const x = rect.x + w / 2; +// const y = rect.y + h / 2; +// +// this.ctx.setLineDash([5, 5]); +// this.ctx.lineWidth = 2; +// this.ctx.strokeStyle = '#1bfff7'; +// // this.ctx.fillStyle = '#ffffff'; +// +// this.ctx.beginPath(); +// +// this.ctx.moveTo( x - w / 2, y - h / 2); +// +// this.ctx.lineTo(x + w / 2, y - h / 2); +// +// this.ctx.lineTo(x + w / 2, y + h / 2); +// +// this.ctx.lineTo(x - w / 2, y + h / 2); +// +// this.ctx.lineTo(x - w / 2, y - h / 2); +// +// // this.ctx.fill(); +// this.ctx.stroke(); +// +// +// +// +// this.ctx.restore(); +// +// } +// +// draw() { +// super.draw(); +// +// if (this.lineDashFlag) { +// this.drawFrame(); +// this.drawArrow(); +// } +// } +// } +// +// +// export class EditorItem extends MySprite { +// +// lineDashFlag = false; +// arrow: MySprite; +// label:Label; +// text; +// +// showLabel(text = null) { +// +// +// if (!this.label) { +// this.label = new Label(this.ctx); +// this.label.anchorY = 0; +// this.label.fontSize = '50px'; +// this.label.textAlign = 'center'; +// this.addChild(this.label); +// this.label.setScaleXY(1 / this.scaleX); +// } +// +// if (text) { +// this.label.text = text; +// } else if (this.text) { +// this.label.text = this.text; +// } +// this.label.visible = true; +// +// } +// +// hideLabel() { +// if (!this.label) { return; } +// +// this.label.visible = false; +// } +// +// showLineDash() { +// this.lineDashFlag = true; +// +// if (this.arrow) { +// this.arrow.visible = true; +// } else { +// this.arrow = new MySprite(this.ctx); +// this.arrow.load('assets/common/arrow.png', 1, 0); +// this.arrow.setScaleXY(0.06); +// +// } +// +// this.showLabel(); +// } +// +// hideLineDash() { +// +// this.lineDashFlag = false; +// +// if (this.arrow) { +// this.arrow.visible = false; +// } +// +// this.hideLabel(); +// } +// +// +// +// drawArrow() { +// if (!this.arrow) { return; } +// +// const rect = this.getBoundingBox(); +// this.arrow.x = rect.x + rect.width; +// this.arrow.y = rect.y; +// +// this.arrow.update(); +// } +// +// drawFrame() { +// +// +// this.ctx.save(); +// +// +// const rect = this.getBoundingBox(); +// +// const w = rect.width; +// const h = rect.height; +// const x = rect.x + w / 2; +// const y = rect.y + h / 2; +// +// this.ctx.setLineDash([5, 5]); +// this.ctx.lineWidth = 2; +// this.ctx.strokeStyle = '#1bfff7'; +// // this.ctx.fillStyle = '#ffffff'; +// +// this.ctx.beginPath(); +// +// this.ctx.moveTo( x - w / 2, y - h / 2); +// +// this.ctx.lineTo(x + w / 2, y - h / 2); +// +// this.ctx.lineTo(x + w / 2, y + h / 2); +// +// this.ctx.lineTo(x - w / 2, y + h / 2); +// +// this.ctx.lineTo(x - w / 2, y - h / 2); +// +// // this.ctx.fill(); +// this.ctx.stroke(); +// +// +// +// +// this.ctx.restore(); +// +// } +// +// draw() { +// super.draw(); +// +// if (this.lineDashFlag) { +// this.drawFrame(); +// this.drawArrow(); +// } +// } +// } +// +// +// +// export class Label extends MySprite { +// +// text:String; +// fontSize:String = '40px'; +// fontName:String = 'Verdana'; +// textAlign:String = 'left'; +// +// +// constructor(ctx) { +// super(ctx); +// this.init(); +// } +// +// drawText() { +// +// // console.log('in drawText', this.text); +// +// if (!this.text) { return; } +// +// this.ctx.font = `${this.fontSize} ${this.fontName}`; +// this.ctx.textAlign = this.textAlign; +// this.ctx.textBaseline = 'middle'; +// this.ctx.fontWeight = 900; +// +// this.ctx.lineWidth = 5; +// this.ctx.strokeStyle = '#ffffff'; +// this.ctx.strokeText(this.text, 0, 0); +// +// this.ctx.fillStyle = '#000000'; +// this.ctx.fillText(this.text, 0, 0); +// +// +// } +// +// +// drawSelf() { +// super.drawSelf(); +// this.drawText(); +// } +// +// } +// +// +// +// export function getPosByAngle(angle, len) { +// +// const radian = angle * Math.PI / 180; +// const x = Math.sin(radian) * len; +// const y = Math.cos(radian) * len; +// +// return {x, y}; +// +// } +// +// export function getAngleByPos(px, py, mx, my) { +// +// // const _x = p2x - p1x; +// // const _y = p2y - p1y; +// // const tan = _y / _x; +// // +// // const radina = Math.atan(tan); // 用å三角函数求弧度 +// // const angle = Math.floor(180 / (Math.PI / radina)); // +// // +// // console.log('r: ' , angle); +// // return angle; +// // +// +// +// +// const x = Math.abs(px - mx); +// const y = Math.abs(py - my); +// // const x = Math.abs(mx - px); +// // const y = Math.abs(my - py); +// const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); +// const cos = y / z; +// const radina = Math.acos(cos); // 用å三角函数求弧度 +// let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // å°†å¼§åº¦è½¬æ¢æˆè§’度 +// +// if(mx > px && my > py) {// é¼ æ ‡åœ¨ç¬¬å››è±¡é™ +// angle = 180 - angle; +// } +// +// if(mx === px && my > py) {// é¼ æ ‡åœ¨yè½´è´Ÿæ–¹å‘上 +// angle = 180; +// } +// +// if(mx > px && my === py) {// é¼ æ ‡åœ¨xè½´æ£æ–¹å‘上 +// angle = 90; +// } +// +// if(mx < px && my > py) {// é¼ æ ‡åœ¨ç¬¬ä¸‰è±¡é™ +// angle = 180 + angle; +// } +// +// if(mx < px && my === py) {// é¼ æ ‡åœ¨xè½´è´Ÿæ–¹å‘ +// angle = 270; +// } +// +// if(mx < px && my < py) {// é¼ æ ‡åœ¨ç¬¬äºŒè±¡é™ +// angle = 360 - angle; +// } +// +// // console.log('angle: ', angle); +// return angle; +// +// } diff --git a/form/src/app/common/custom-hot-zone/custom-hot-zone.component.html b/form/src/app/common/custom-hot-zone/custom-hot-zone.component.html new file mode 100644 index 0000000000000000000000000000000000000000..9028527061890eefb1557c53f49394c7ea827b11 --- /dev/null +++ b/form/src/app/common/custom-hot-zone/custom-hot-zone.component.html @@ -0,0 +1,100 @@ +<div class="p-image-children-editor"> + + <h5 style="margin-left: 2.5%;"> preview: </h5> + + <div class="preview-box" #wrap> + <canvas id="canvas" #canvas></canvas> + </div> + + <div nz-row nzType="flex" nzAlign="middle"> + <div nz-col nzSpan="5" nzOffset="1"> + + <h5> add background: </h5> + + <div class="bg-box"> + <app-upload-image-with-preview + [picUrl]="bgItem?.url" + (imageUploaded)="onBackgroundUploadSuccess($event)"> + </app-upload-image-with-preview> + </div> + </div> + + <div nz-col nzSpan="5" nzOffset="1" class="img-box" + *ngFor="let it of hotZoneArr; let i = index"> + + <div + style="margin: auto; padding: 5px; margin-top: 30px; width:90%; border: 2px dashed #ddd; border-radius: 10px"> + <span style="margin-left: 40%;"> item-{{i + 1}} + </span> + <button style="float: right;" nz-button nzType="danger" nzSize="small" (click)="deleteBtnClick(i)"> + X + </button> + + <nz-divider style="margin-top: 10px;"></nz-divider> + + + <div style="margin-top: -20px; margin-bottom: 5px"> + <nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)"> + <label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label> + <label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label> + <label *ngIf="isHasText" nz-radio nzValue="text">文本</label> + </nz-radio-group> + </div> + + <div *ngIf="it.itemType == 'pic'"> + <app-upload-image-with-preview + [picUrl]="it?.pic_url" + (imageUploaded)="onItemImgUploadSuccess($event, it)"> + </app-upload-image-with-preview> + </div> + + <div *ngIf="it.itemType == 'text'"> + <input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)"> + </div> + + <div style="width: 100%; margin-top: 5px;"> + <app-audio-recorder + [audioUrl]="it.audio_url" + (audioUploaded)="onItemAudioUploadSuccess($event, it)" + ></app-audio-recorder> + </div> + + </div> + + </div> + + + <div nz-col nzSpan="5" nzOffset="1"> + + <div class="bg-box"> + <button nz-button nzType="dashed" (click)="addBtnClick()" + class="add-btn"> + <i nz-icon nzType="plus-circle" nzTheme="outline"></i> + <!--Add Image--> + Add hot zone + </button> + </div> + + </div> + </div> + + + <nz-divider></nz-divider> + + <div class="save-box"> + + <button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round" + (click)="saveClick()" > + <i nz-icon nzType="save"></i> + Save + </button> + + </div> + + +</div> + + +<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label> + + diff --git a/form/src/app/common/custom-hot-zone/custom-hot-zone.component.scss b/form/src/app/common/custom-hot-zone/custom-hot-zone.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..9e2c2bf053571db2d78708132b23fe87e0acc9b2 --- /dev/null +++ b/form/src/app/common/custom-hot-zone/custom-hot-zone.component.scss @@ -0,0 +1,210 @@ + +.p-image-children-editor { + + width: 100%; + height: 100%; + border-radius: 0.5rem; + + border: 2px solid #ddd; + + + + .preview-box { + + margin: auto; + width: 95%; + height: 35vw; + + border: 2px dashed #ddd; + border-radius: 0.5rem; + background-color: #fafafa; + text-align: center; + color: #aaa; + + + .preview-img { + height: 100%; + width: auto; + } + + } + + + + .bg-box{ + //width: 100%; + margin-bottom: 1rem; + + } + + .img-box { + margin-bottom: 1rem; + + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + .img-box-upload{ + width: 80%; + } + + .add-btn { + margin-top: 1rem; + width: 200px; + height: 90px; + + display: flex; + align-items: center; + justify-content: center; + } +} + + +.save-box { + width: 100%; + + display: flex; + align-items: center; + justify-content: center; + + .save-btn { + width: 160px; + height: 40px; + + //margin-top: 20px; + margin-bottom: 20px; + + display: flex; + align-items: center; + justify-content: center; + } +} + +h5 { + margin-top: 1rem; +} + + + +@font-face +{ + font-family: 'BRLNSR_1'; + src: url("/assets/font/BRLNSR_1.TTF") ; +} + + + + + + + + + + + + + + + +//@import '../../../style/common_mixin'; +// +//.p-image-uploader { +// position: relative; +// display: block; +// width: 100%; +// height: 0; +// padding-bottom: 56.25%; +// .p-box { +// position: absolute; +// left: 0; +// top: 0; +// right: 0; +// bottom: 0; +// border: 2px dashed #ddd; +// border-radius: 0.5rem; +// background-color: #fafafa; +// text-align: center; +// color: #aaa; +// .p-upload-icon { +// text-align: center; +// margin: auto; +// .anticon-upload { +// color: #888; +// font-size: 5rem; +// } +// .p-progress-bar { +// position: relative; +// width: 20rem; +// height: 1.5rem; +// border: 1px solid #ccc; +// border-radius: 1rem; +// .p-progress-bg { +// background-color: #1890ff; +// border-radius: 1rem; +// height: 100%; +// } +// .p-progress-value { +// position: absolute; +// top: 0; +// left: 0; +// width: 100%; +// height: 100%; +// text-shadow: 0 0 4px #000; +// color: white; +// text-align: center; +// font-size: 0.9rem; +// line-height: 1.5rem; +// } +// } +// } +// .p-preview { +// width: 100%; +// height: 100%; +// //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); +// @include k-img-bg(); +// } +// } +//} +// +//.p-btn-delete { +// position: absolute; +// right: -0.5rem; +// top: -0.5rem; +// width: 2rem; +// height: 2rem; +// border: 0.2rem solid white; +// border-radius: 50%; +// font-size: 1.2rem; +// background-color: #fb781a; +// color: white; +// text-align: center; +//} +// +//.p-upload-progress-bg { +// position: absolute; +// width: 100%; +// height: 100%; +// display: flex; +// align-items: center; +// justify-content: center; +// & .i-text { +// position: absolute; +// text-align: center; +// color: white; +// text-shadow: 0 0 2px rgba(0, 0, 0, .85); +// } +// & .i-bg { +// position: absolute; +// left: 0; +// top: 0; +// height: 100%; +// background-color: #27b43f; +// border-radius: 0.5rem; +// } +//} +// +// +//:host ::ng-deep .ant-upload { +// display: block; +//} diff --git a/form/src/app/common/custom-hot-zone/custom-hot-zone.component.ts b/form/src/app/common/custom-hot-zone/custom-hot-zone.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc2a4cf04d4592cc6a399cf5708c713dbb3439fd --- /dev/null +++ b/form/src/app/common/custom-hot-zone/custom-hot-zone.component.ts @@ -0,0 +1,986 @@ +import { + Component, + ElementRef, + EventEmitter, + HostListener, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import {Subject} from 'rxjs'; +import {debounceTime} from 'rxjs/operators'; +import {EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr} from './Unit'; +import TWEEN from '@tweenjs/tween.js'; +import {getMinScale} from "../../play/Unit"; +import {tar} from "compressing"; + + +@Component({ + selector: 'app-custom-hot-zone', + templateUrl: './custom-hot-zone.component.html', + styleUrls: ['./custom-hot-zone.component.scss'] +}) +export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { + + + @Input() + imgItemArr = null; + @Input() + hotZoneItemArr = null; + @Input() + hotZoneArr = null; + @Output() + save = new EventEmitter(); + @ViewChild('canvas', {static: true}) canvas: ElementRef; + @ViewChild('wrap', {static: true}) wrap: ElementRef; + + @Input() + isHasRect = true; + @Input() + isHasPic = true; + @Input() + isHasText = true; + @Input() + hotZoneFontObj = { + size: 50, + name: 'BRLNSR_1', + color: '#8f3758' + } + @Input() + defaultItemType = 'text'; + + @Input() + hotZoneImgSize = 190; + + saveDisabled = true; + + canvasWidth = 1280; + canvasHeight = 720; + canvasBaseW = 1280; + // @HostListener('window:resize', ['$event']) + canvasBaseH = 720; + mapScale = 1; + ctx; + mx; + my; // ç‚¹å‡»åæ ‡ + // 声音 + bgAudio = new Audio(); + images = new Map(); + animationId: any; + + + // èµ„æº + // rawImages = new Map(res); + winResizeEventStream = new Subject(); + canvasLeft; + canvasTop; + renderArr; + imgArr = []; + oldPos; + radioValue; + curItem; + bg: MySprite; + changeSizeFlag = false; + changeTopSizeFlag = false; + changeRightSizeFlag = false; + + constructor() { + } + + _bgItem = null; + + get bgItem() { + return this._bgItem; + } + + @Input() + set bgItem(v) { + this._bgItem = v; + + this.init(); + } + + onResize(event) { + this.winResizeEventStream.next(); + } + + + ngOnInit() { + + this.initListener(); + + // this.init(); + this.update(); + + } + + ngOnDestroy() { + window.cancelAnimationFrame(this.animationId); + } + + + ngOnChanges() { + + } + + + onBackgroundUploadSuccess(e) { + console.log('e: ', e); + this.bgItem.url = e.url; + this.refreshBackground(); + } + + onItemImgUploadSuccess(e, item) { + item.pic_url = e.url; + this.loadHotZonePic(item.pic, e.url); + } + + onItemAudioUploadSuccess(e, item) { + item.audio_url = e.url; + } + + + refreshBackground(callBack = null) { + + if (!this.bg) { + this.bg = new MySprite(this.ctx); + this.renderArr.push(this.bg); + } + + const bg = this.bg; + if (this.bgItem.url) { + + bg.load(this.bgItem.url).then(() => { + const rate1 = this.canvasWidth / bg.width; + const rate2 = this.canvasHeight / bg.height; + + const rate = Math.min(rate1, rate2); + bg.setScaleXY(rate); + + + bg.x = this.canvasWidth / 2; + bg.y = this.canvasHeight / 2; + + if (callBack) { + callBack(); + } + }); + } + + } + + + addBtnClick() { + // this.imgArr.push({}); + // this.hotZoneArr.push({}); + + const item = this.getHotZoneItem(); + this.hotZoneArr.push(item); + + this.refreshItem(item); + + this.refreshHotZoneId(); + + } + + deleteBtnClick(index) { + + const item = this.hotZoneArr.splice(index, 1)[0]; + removeItemFromArr(this.renderArr, item.pic); + removeItemFromArr(this.renderArr, item.textLabel); + + this.refreshHotZoneId(); + + } + + onImgUploadSuccessByImg(e, img) { + img.pic_url = e.url; + this.refreshImage(img); + } + + refreshImage(img) { + + this.hideAllLineDash(); + + img.picItem = this.getPicItem(img); + + this.refreshImageId(); + + } + + + refreshHotZoneId() { + for (let i = 0; i < this.hotZoneArr.length; i++) { + this.hotZoneArr[i].index = i; + + if (this.hotZoneArr[i]) { + this.hotZoneArr[i].title = 'item-' + (i + 1); + + } + } + } + + + refreshImageId() { + for (let i = 0; i < this.imgArr.length; i++) { + this.imgArr[i].id = i; + + if (this.imgArr[i].picItem) { + this.imgArr[i].picItem.text = 'Image-' + (i + 1); + } + } + + } + + getHotZoneItem(saveData = null) { + + + const itemW = 200; + const itemH = 200; + const item = new HotZoneItem(this.ctx); + item.setSize(itemW, itemH); + item.anchorX = 0.5; + item.anchorY = 0.5; + + item.x = this.canvasWidth / 2; + item.y = this.canvasHeight / 2; + + item.itemType = this.defaultItemType; + + if (saveData) { + + const saveRect = saveData.rect; + item.scaleX = saveRect.width / item.width; + item.scaleY = saveRect.height / item.height; + item.x = saveRect.x + saveRect.width / 2; + item.y = saveRect.y + saveRect.height / 2; + + } + + item.showLineDash(); + + const pic = new HotZoneImg(this.ctx); + pic.visible = false; + item['pic'] = pic; + if (saveData && saveData.pic_url) { + this.loadHotZonePic(pic, saveData.pic_url); + } + pic.x = item.x; + pic.y = item.y; + this.renderArr.push(pic); + + const textLabel = new HotZoneLabel(this.ctx); + textLabel.fontSize = this.hotZoneFontObj.size; + textLabel.fontName = this.hotZoneFontObj.name; + textLabel.fontColor = this.hotZoneFontObj.color; + textLabel.textAlign = 'center'; + // textLabel.setOutline(); + // console.log('saveData:', saveData); + item['textLabel'] = textLabel; + textLabel.setScaleXY(this.mapScale); + if (saveData && saveData.text) { + textLabel.text = saveData.text; + textLabel.refreshSize(); + } + textLabel.x = item.x; + textLabel.y = item.y; + this.renderArr.push(textLabel); + + return item; + } + + + getPicItem(img, saveData = null) { + + + const item = new EditorItem(this.ctx); + item.load(img.pic_url).then(img => { + + let maxW, maxH; + if (this.bg) { + maxW = this.bg.width * this.bg.scaleX; + maxH = this.bg.height * this.bg.scaleY; + } else { + maxW = this.canvasWidth; + maxH = this.canvasHeight; + } + + let scaleX = maxW / 3 / item.width; + let scaleY = maxH / 3 / item.height; + + if (item.height * scaleX < this.canvasHeight) { + item.setScaleXY(scaleX); + } else { + item.setScaleXY(scaleY); + } + item.x = this.canvasWidth / 2; + item.y = this.canvasHeight / 2; + + if (saveData) { + + const saveRect = saveData.rect; + item.setScaleXY(saveRect.width / item.width); + item.x = saveRect.x + saveRect.width / 2; + item.y = saveRect.y + saveRect.height / 2; + + } else { + item.showLineDash(); + } + + }); + return item; + } + + + onAudioUploadSuccessByImg(e, img) { + img.audio_url = e.url; + } + + deleteItem(e, i) { + // this.imgArr.splice(i , 1); + // this.refreshImageId(); + + this.hotZoneArr.splice(i, 1); + this.refreshHotZoneId(); + } + + + radioChange(e, item) { + item.itemType = e; + + this.refreshItem(item); + + // console.log(' in radioChange e: ', e); + } + + refreshItem(item) { + switch (item.itemType) { + case 'rect': + this.setRectState(item); + break; + case 'pic': + this.setPicState(item); + break; + case 'text': + this.setTextState(item); + break; + default: + + } + } + + + init() { + + this.initData(); + this.initCtx(); + + this.initItem(); + } + + initItem() { + if (!this.bgItem) { + this.bgItem = {}; + } else { + this.refreshBackground(() => { + + // if (!this.imgItemArr) { + // this.imgItemArr = []; + // } else { + // this.initImgArr(); + // } + + // console.log('aaaaa'); + + if (!this.hotZoneItemArr) { + this.hotZoneItemArr = []; + } else { + this.initHotZoneArr(); + } + + }); + } + + } + + initHotZoneArr() { + + // console.log('this.hotZoneArr: ', this.hotZoneArr); + let curBgRect; + if (this.bg) { + curBgRect = this.bg.getBoundingBox(); + } else { + curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight}; + } + + let oldBgRect = this.bgItem.rect; + if (!oldBgRect) { + oldBgRect = curBgRect; + } + + const rate = curBgRect.width / oldBgRect.width; + + console.log('rate: ', rate); + + this.hotZoneArr = []; + const arr = this.hotZoneItemArr.concat(); + for (let i = 0; i < arr.length; i++) { + + const data = JSON.parse(JSON.stringify(arr[i])); + // const img = {pic_url: data.pic_url}; + + data.rect.x *= rate; + data.rect.y *= rate; + data.rect.width *= rate; + data.rect.height *= rate; + + data.rect.x += curBgRect.x; + data.rect.y += curBgRect.y; + + // img['picItem'] = this.getPicItem(img, data); + // img['audio_url'] = arr[i].audio_url; + // this.imgArr.push(img); + + const item = this.getHotZoneItem(data); + item.audio_url = data.audio_url; + item.pic_url = data.pic_url; + item.text = data.text; + item.itemType = data.itemType; + this.refreshItem(item); + + console.log('item: ', item); + this.hotZoneArr.push(item); + + } + + this.refreshHotZoneId(); + + // this.refreshImageId(); + + } + + + initImgArr() { + + console.log('this.imgItemArr: ', this.imgItemArr); + let curBgRect; + if (this.bg) { + curBgRect = this.bg.getBoundingBox(); + } else { + curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight}; + } + + let oldBgRect = this.bgItem.rect; + if (!oldBgRect) { + oldBgRect = curBgRect; + } + + const rate = curBgRect.width / oldBgRect.width; + + console.log('rate: ', rate); + + this.imgArr = []; + const arr = this.imgItemArr.concat(); + for (let i = 0; i < arr.length; i++) { + + const data = JSON.parse(JSON.stringify(arr[i])); + const img = {pic_url: data.pic_url}; + + data.rect.x *= rate; + data.rect.y *= rate; + data.rect.width *= rate; + data.rect.height *= rate; + + data.rect.x += curBgRect.x; + data.rect.y += curBgRect.y; + + img['picItem'] = this.getPicItem(img, data); + img['audio_url'] = arr[i].audio_url; + this.imgArr.push(img); + } + this.refreshImageId(); + } + + + initData() { + + this.canvasWidth = this.wrap.nativeElement.clientWidth; + this.canvasHeight = this.wrap.nativeElement.clientHeight; + this.mapScale = this.canvasWidth / this.canvasBaseW; + this.renderArr = []; + this.bg = null; + + this.imgArr = []; + this.hotZoneArr = []; + } + + initCtx() { + this.ctx = this.canvas.nativeElement.getContext('2d'); + this.canvas.nativeElement.width = this.canvasWidth; + this.canvas.nativeElement.height = this.canvasHeight; + } + + + mapDown(event) { + + this.oldPos = {x: this.mx, y: this.my}; + + for (let i = 0; i < this.hotZoneArr.length; i++) { + + const item = this.hotZoneArr[i]; + let callback; + let target; + switch (item.itemType) { + case 'rect': + target = item; + callback = this.clickedHotZoneRect.bind(this); + break; + case 'pic': + target = item.pic; + callback = this.clickedHotZonePic.bind(this); + break; + case 'text': + target = item.textLabel; + callback = this.clickedHotZoneText.bind(this); + break; + } + + if (this.checkClickTarget(target)) { + callback(target); + return; + } + } + + + } + + + mapMove(event) { + if (!this.curItem) { + return; + } + + if (this.changeSizeFlag) { + this.changeSize(); + + } else if (this.changeTopSizeFlag) { + this.changeTopSize(); + + } else if (this.changeRightSizeFlag) { + this.changeRightSize(); + + } else { + + const addX = this.mx - this.oldPos.x; + const addY = this.my - this.oldPos.y; + this.curItem.x += addX; + this.curItem.y += addY; + } + + this.oldPos = {x: this.mx, y: this.my}; + + this.saveDisabled = true; + + } + + mapUp(event) { + this.curItem = null; + this.changeSizeFlag = false; + this.changeTopSizeFlag = false; + this.changeRightSizeFlag = false; + } + + + changeSize() { + const rect = this.curItem.getBoundingBox(); + + let lenW = (this.mx - (rect.x + rect.width / 2)) * 2; + let lenH = ((rect.y + rect.height / 2) - this.my) * 2; + + + let minLen = 20; + let s; + if (lenW < lenH) { + if (lenW < minLen) { + lenW = minLen; + } + s = lenW / this.curItem.width; + + } else { + if (lenH < minLen) { + lenH = minLen; + } + s = lenH / this.curItem.height; + } + + + // console.log('s: ', s); + this.curItem.setScaleXY(s); + this.curItem.refreshLabelScale(); + } + + + changeTopSize() { + const rect = this.curItem.getBoundingBox(); + + // let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2; + let lenH = ((rect.y + rect.height / 2) - this.my) * 2; + + + let minLen = 20; + let s; + // if (lenW < lenH) { + // if (lenW < minLen) { + // lenW = minLen; + // } + // s = lenW / this.curItem.width; + // + // } else { + if (lenH < minLen) { + lenH = minLen; + } + s = lenH / this.curItem.height; + // } + + + // console.log('s: ', s); + this.curItem.scaleY = s; + this.curItem.refreshLabelScale(); + } + + changeRightSize() { + const rect = this.curItem.getBoundingBox(); + + let lenW = (this.mx - (rect.x + rect.width / 2)) * 2; + // let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2; + + let minLen = 20; + let s; + if (lenW < minLen) { + lenW = minLen; + } + s = lenW / this.curItem.width; + + this.curItem.scaleX = s; + this.curItem.refreshLabelScale(); + } + + changeItemSize(item) { + this.curItem = item; + this.changeSizeFlag = true; + } + + changeItemTopSize(item) { + this.curItem = item; + this.changeTopSizeFlag = true; + } + + changeItemRightSize(item) { + this.curItem = item; + this.changeRightSizeFlag = true; + } + + changeCurItem(item) { + + this.hideAllLineDash(); + + this.curItem = item; + this.curItem.showLineDash(); + } + + hideAllLineDash() { + + for (let i = 0; i < this.imgArr.length; i++) { + if (this.imgArr[i].picItem) { + this.imgArr[i].picItem.hideLineDash(); + } + } + } + + + update() { + if (!this.ctx) { + return; + } + + + this.animationId = window.requestAnimationFrame(this.update.bind(this)); + // 清除画布内容 + this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + + for (let i = 0; i < this.renderArr.length; i++) { + this.renderArr[i].update(this); + } + + // for (let i = 0; i < this.imgArr.length; i++) { + // const picItem = this.imgArr[i].picItem; + // if (picItem) { + // picItem.update(this); + // } + // } + + this.updateArr(this.hotZoneArr); + this.updatePos() + + + TWEEN.update(); + } + + updateArr(arr) { + if (arr) { + for (let i = 0; i < arr.length; i++) { + arr[i].update(); + } + } + } + + + renderAfterResize() { + this.canvasWidth = this.wrap.nativeElement.clientWidth; + this.canvasHeight = this.wrap.nativeElement.clientHeight; + this.init(); + } + + initListener() { + + this.winResizeEventStream + .pipe(debounceTime(500)) + .subscribe(data => { + this.renderAfterResize(); + }); + + if (this.IsPC()) { + + this.canvas.nativeElement.addEventListener('mousedown', (event) => { + setMxMyByMouse(event); + this.mapDown(event); + }); + + this.canvas.nativeElement.addEventListener('mousemove', (event) => { + setMxMyByMouse(event); + this.mapMove(event); + }); + + this.canvas.nativeElement.addEventListener('mouseup', (event) => { + setMxMyByMouse(event); + this.mapUp(event); + }); + + const setMxMyByMouse = (event) => { + this.mx = event.offsetX; + this.my = event.offsetY; + }; + + } else { + + this.canvas.nativeElement.addEventListener('touchstart', (event) => { + setMxMyByTouch(event); + this.mapDown(event); + }); + + this.canvas.nativeElement.addEventListener('touchmove', (event) => { + setMxMyByTouch(event); + this.mapMove(event); + }); + + this.canvas.nativeElement.addEventListener('touchend', (event) => { + setMxMyByTouch(event); + this.mapUp(event); + }); + + this.canvas.nativeElement.addEventListener('touchcancel', (event) => { + setMxMyByTouch(event); + this.mapUp(event); + }); + + + const setMxMyByTouch = (event) => { + if (event.touches.length <= 0) { + return; + } + + if (this.canvasLeft == null) { + setParentOffset(); + } + + this.mx = event.touches[0].pageX - this.canvasLeft; + this.my = event.touches[0].pageY - this.canvasTop; + }; + + + const setParentOffset = () => { + + const rect = this.canvas.nativeElement.getBoundingClientRect(); + this.canvasLeft = rect.left; + this.canvasTop = rect.top; + }; + } + } + + IsPC() { + if (window['ELECTRON']) { + return false; // å°è£…å®¢æˆ·ç«¯æ ‡è®° + } + if (document.body.ontouchstart !== undefined) { + return false; + } else { + return true; + } + } + + + checkClickTarget(target) { + + const rect = target.getBoundingBox(); + if (this.checkPointInRect(this.mx, this.my, rect)) { + return true; + } + return false; + } + + checkPointInRect(x, y, rect) { + if (x >= rect.x && x <= rect.x + rect.width) { + if (y >= rect.y && y <= rect.y + rect.height) { + return true; + } + } + return false; + } + + + saveClick() { + const bgItem = this.bgItem; + if (this.bg) { + bgItem['rect'] = this.bg.getBoundingBox(); + } else { + bgItem['rect'] = { + x: 0, + y: 0, + width: Math.round(this.canvasWidth * 100) / 100, + height: Math.round(this.canvasHeight * 100) / 100 + }; + } + + + const hotZoneItemArr = []; + const hotZoneArr = this.hotZoneArr; + for (let i = 0; i < hotZoneArr.length; i++) { + + const hotZoneItem = { + index: hotZoneArr[i].index, + pic_url: hotZoneArr[i].pic_url, + text: hotZoneArr[i].text, + audio_url: hotZoneArr[i].audio_url, + itemType: hotZoneArr[i].itemType, + fontSize: this.hotZoneFontObj.size, + fontName: this.hotZoneFontObj.name, + fontColor: this.hotZoneFontObj.color, + fontScale: hotZoneArr[i].textLabel ? hotZoneArr[i].textLabel.scaleX : 1, + imgScale: hotZoneArr[i].pic ? hotZoneArr[i].pic.scaleX : 1, + mapScale: this.mapScale + }; + hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox(); + hotZoneItem['rect'].x = Math.round((hotZoneItem['rect'].x - bgItem['rect'].x) * 100) / 100; + hotZoneItem['rect'].y = Math.round((hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100; + hotZoneItem['rect'].width = Math.round((hotZoneItem['rect'].width) * 100) / 100; + hotZoneItem['rect'].height = Math.round((hotZoneItem['rect'].height) * 100) / 100; + + + hotZoneItemArr.push(hotZoneItem); + } + + console.log('hotZoneItemArr: ', hotZoneItemArr); + + this.save.emit({bgItem, hotZoneItemArr}); + } + + private updatePos() { + this.hotZoneArr.forEach((item) => { + let x, y; + switch (item.itemType) { + case 'rect': + x = item.x; + y = item.y; + break; + + case 'pic': + x = item.pic.x; + y = item.pic.y; + break; + + case 'text': + x = item.textLabel.x; + y = item.textLabel.y; + break; + } + + item.x = x; + item.y = y; + item.pic.x = x; + item.pic.y = y; + item.textLabel.x = x; + item.textLabel.y = y; + }); + } + + private setPicState(item: any) { + item.visible = false; + item.textLabel.visible = false; + item.pic.visible = true; + } + + private setRectState(item: any) { + item.visible = true; + item.textLabel.visible = false; + item.pic.visible = false; + } + + private setTextState(item: any) { + item.visible = false; + item.pic.visible = false; + item.textLabel.visible = true; + } + + private clickedHotZoneRect(item: any) { + if (this.checkClickTarget(item)) { + + if (item.lineDashFlag && this.checkClickTarget(item.arrow)) { + this.changeItemSize(item); + } else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) { + this.changeItemTopSize(item); + } else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) { + this.changeItemRightSize(item); + } else { + this.changeCurItem(item); + } + return; + } + } + + private clickedHotZonePic(item: any) { + if (this.checkClickTarget(item)) { + this.curItem = item; + } + } + + private clickedHotZoneText(item: any) { + if (this.checkClickTarget(item)) { + this.curItem = item; + } + } + + saveText(item) { + item.textLabel.text = item.text; + } + + private loadHotZonePic(pic: HotZoneImg, url) { + const baseLen = this.hotZoneImgSize * this.mapScale; + pic.load(url).then(() => { + const s = getMinScale(pic, baseLen); + pic.setScaleXY(s); + }); + } +} diff --git a/form/src/app/common/lesson-title-config/lesson-title-config.component.html b/form/src/app/common/lesson-title-config/lesson-title-config.component.html new file mode 100644 index 0000000000000000000000000000000000000000..996dc651e4b301c3f940ae9cb200d14bc224a086 --- /dev/null +++ b/form/src/app/common/lesson-title-config/lesson-title-config.component.html @@ -0,0 +1,93 @@ + +<div class="title-config"> + + <div class="title-wrap"> + <div class="row" style="margin: 5px;"> + <div class="p-content" style="width:100%"> + <div class="p-tool-box d-flex" style="background: #fff;"> + <nz-select class="ml-1" style="width: 120px;" [(ngModel)]="__fontFamily" + (ngModelChange)="onChangeFontFamily($event)" + nzPlaceHolder="Font Family" + [nzDropdownMatchSelectWidth]="false"> + <nz-option [nzValue]="font" nzCustomContent [nzLabel]="font" *ngFor="let font of fontFamilyList"> + <span [ngStyle]="{'font-family': font}" >{{font}}</span> + </nz-option> + </nz-select> + <nz-select class="ml-1" style="width: 110px;" [(ngModel)]="__fontSize" + (ngModelChange)="onChangeFontSize()" + nzPlaceHolder="Font Size"> + <nz-option [nzValue]="i" [nzLabel]="'Size - ' + i" *ngFor="let i of fontSizeRange"></nz-option> + </nz-select> + <div class="p-divider"></div> + <div class="i-tool-font-btn d-flex mr-2"> + <div class="position-relative fa-icon" (click)="onChangeBold()"> +<!-- <div class="fa fa-bold"></div>--> + <fa-icon icon="bold"></fa-icon> + </div> + </div> + <div class="i-tool-font-btn d-flex mr-2"> + <div class="position-relative fa-icon" (click)="onChangeItalic()"> +<!-- <div class="fa fa-italic"></div>--> + <fa-icon icon="italic"></fa-icon> + </div> + </div> + <div class="i-tool-font-btn d-flex mr-2"> + <div class="position-relative fa-icon" (click)="onChangeUnderline()"> +<!-- <div class="fa fa-underline"></div>--> + <fa-icon icon="underline"></fa-icon> + </div> + </div> + <div class="i-tool-font-btn d-flex"> + <div class="position-relative fa-icon" (click)="onChangeStrikethrough()"> +<!-- <div class="fa fa-strikethrough"></div>--> + <fa-icon icon="strikethrough"></fa-icon> + </div> + </div> + <div class="p-divider"></div> + <div class="i-tool-font-color d-flex"> + <div class="position-relative i-left flex-fill" (click)="onChangeFontColor($event)"> +<!-- <div class="fa fa-font"></div>--> + <fa-icon icon="palette"></fa-icon> + <div class="i-color" [style.background-color]="__fontColor"></div> + </div> + <div class="i-dropdown-menu" nzPlacement="bottom" + nz-popover [(nzVisible)]="isShowFontColorPane" nzTrigger="click" + [nzContent]="colorPane"> + <i nz-icon type="down" theme="outline"></i> + </div> + </div> + <div class="p-divider"></div> + <div style="background: #fff;display: block;"> + <div class="position-relative"> + <app-audio-recorder [audioUrl]="titleObj && titleObj.audio_url" (audioUploaded)="titleAudioUploaded($event)"></app-audio-recorder> + </div> + </div> + </div> + + <div class="width-100 d-flex"> + <iframe #titleEl id="titleContentEgret" frameborder="0" style="overflow: hidden;width: 100%; height:48px; margin: 0; padding: 0;"></iframe> + </div> + </div> + + <ng-template #colorPane> + <div class="p-color-pane" nz-row nzGutter="16" nzType="flex"> + <div nz-col class="p-color-item" *ngFor="let color of colorList" + [style.background-color]="color" + (click)="onSelectColor(color)" + > + </div> + </div> + </ng-template> + + </div> + + + + + + + </div> + + + +</div> diff --git a/form/src/app/common/lesson-title-config/lesson-title-config.component.scss b/form/src/app/common/lesson-title-config/lesson-title-config.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..d8dca5324cc4a7d988176d83f887b9feaa3dffdf --- /dev/null +++ b/form/src/app/common/lesson-title-config/lesson-title-config.component.scss @@ -0,0 +1,365 @@ +@import '../../style/common_mixin.css'; + +.title-config { + .letter-wrap{ + width: 3rem; + flex: 0 0 3rem; + } + .str-wrap{ + margin-left: 1rem;flex: 1 1; + } + .type-row{ + margin: 0;padding-top: 1rem; + } + +} +@font-face +{ + font-family: 'BRLNSDB'; + src: url("../../../assets/font/BRLNSDB.TTF") ; +} + +@font-face +{ + font-family: 'BRLNSB'; + src: url("../../../assets/font/BRLNSB.TTF") ; +} + +@font-face +{ + font-family: 'BRLNSR'; + src: url("../../../assets/font/BRLNSR.TTF") ; +} + +@font-face +{ + font-family: 'GOTHIC'; + src: url("../../../assets/font/GOTHIC.TTF") ; +} + +@font-face +{ + font-family: 'GOTHICB'; + src: url("../../../assets/font/GOTHICB.TTF") ; +} + +@font-face +{ + font-family: 'GOTHICBI'; + src: url("../../../assets/font/GOTHICBI.TTF") ; +} + +@font-face +{ + font-family: 'GOTHICI'; + src: url("../../../assets/font/GOTHICI.TTF") ; +} + +@font-face +{ + font-family: 'MMTextBook'; + src: url("../../../assets/font/MMTextBook.otf") ; +} + +@font-face +{ + font-family: 'MMTextBook-Bold'; + src: url("../../../assets/font/MMTextBook-Bold.otf") ; +} + +@font-face +{ + font-family: 'MMTextBook-BoldItalic'; + src: url("../../../assets/font/MMTextBook-BoldItalic.otf") ; +} + +@font-face +{ + font-family: 'MMTextBook-Italic'; + src: url("../../../assets/font/MMTextBook-Italic.otf") ; +} +@mixin tool-btn { + border: 1px solid #ddd; + display: flex; + justify-content: center; + align-items: center; + height: 100%; + outline: none; + border-radius: 6px; + color: #555; +} +.d-flex{ + display: flex; +} + +.position-relative { + position: relative; +} + .flex-fill { + -webkit-box-flex: 1; + flex: 1 1 auto; + justify-content: center; + display: flex; + } + +.i-dropdown-menu{ + width: 15px; + font-size: 10px; + border-left: 1px solid #ddd; + display: -webkit-box; + display: flex; + -webkit-box-align: center; + align-items: center; + flex: 0 +} +.p-title-box .p-title { + font-size: 20px; + } +.p-title-box input { + width: 300px; + margin-left: 10px; + } + +.p-content { + border: 1px solid #ddd; + box-shadow: 0 0 8px #eee; + margin-top: 10px; +} + +.p-divider { + border-left: 1px solid #ccc; + margin: 5px 8px; + height: 85%; +} + +.p-tool-box { + background-color: #efefef; + padding: 2px; + height: 37px; + display: flex; + align-items: center; + border-bottom: 1px solid #ddd; + + + +} +// save +.i-tool-save { + //@include tool-btn(); + color: white; +} +.i-tool-save:disabled { + color: #555; +} + +// font-size +.i-tool-font-size { + //@include tool-btn(); + width: 37px; + +} +.i-tool-font-size:hover { + color: black; + border-color: #bbb; +} + +// font-color +.i-tool-font-color, .i-tool-font-btn { + border: 1px solid #ddd; + //padding: 3px 7px; + border-radius: 6px; + width: 45px; + height: 31px; + background-color: white; + color: #555; + ::ng-deep > span { + display: flex; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + padding: 3px 7px; + } + .i-left { + .fa-font,.fa-bold,.fa-italic,.fa-strikethrough, .fa-underline { + font-size: 10px; + position: absolute; + color: #555; + left: 8px; + top: 7px; + } + .i-color { + width: 68%; + height: 5px; + background-color: black; + position: absolute; + top: 21px; + left: 5px; + } + } + .i-dropdown-menu { + width: 15px; + font-size: 10px; + border-left: 1px solid #ddd; + display: flex; + align-items: center; + .anticon-down { + transform: scale(0.6); + } + } +} +.i-tool-font-btn{ + width: 31px; +} +.fa-icon{ + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; +} +// bg-color +.i-tool-bg-color { + @include tool-btn(); + padding: 0 9px; + ::ng-deep > span { + display: flex; + align-items: center; + } + + .i-color { + display: block; + width: 16px; + height: 16px; + background-color: white; + margin-left: 10px; + } +} + + +// horizontal-center +.i-tool-horizontal-center { + @include tool-btn(); + width: 37px; +} +.p-box { + width: 1280px; + height: 720px; + left: 0; + top: 0; + transform-origin: top left; + overflow: hidden; +} + + + +.p-animation-index-box { + .i-animation-index { + position: absolute; + font-size: 34px; + font-family: Arial; + border: 1px solid #ddd; + border-radius: 4px; + min-width: 50px; + min-height: 50px; + display: flex; + align-items: center; + justify-content: center; + background-color: darkorange; + color: white; + } +} + +.p-edit { + background-color: white; + border: 1px solid black; + padding: 2px 15px; +} + +.p-selected { + border: 1px solid darkorange; + box-shadow: 0 0 8px #ddd; +} + +.p-tool-item-disable { + color: rgba(0, 0, 0, .25) !important; + background-color: transparent !important; + pointer-events: none; +} + +// ----------- +.p-color-pane { + width: 80px; + .p-color-item { + width: 17px; + height: 17px; + cursor: pointer; + margin: 4px; + border: 1px solid #bbb; + } + .p-color-item-active { + border: 1px solid white; + transform: scale(1.1); + } +} + +.p-user-guide { + font-size: 40px; + display: flex; + justify-content: center; + align-items: center; +} + +.p-animation-box { + width: 400px; + background-color: #efefef; + border-left: 1px solid #ddd; + padding: 10px; + text-align: center; + + .p-animation-label { + z-index: 1; + position: relative; + } + + ::ng-deep .ant-radio-button-wrapper { + padding: 0 10px; + } + + .i-toolbox { + & > div { + font-size: 20px; + cursor: pointer; + color: #555; + padding: 0 3px; + margin: 0 5px; + } + & > div:hover { + color: #1585ff; + transform: scale(1.1); + } + } + + .p-animation-list { + background-color: white; + border-radius: 10px; + height: calc(100% - 86px); + overflow-y: auto; + .p-animation-item { + padding: 0 20px; + background-color: aliceblue; + margin-top: 6px; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + cursor: pointer; + text-align: left; + display: flex; + } + .i-active { + background-color: antiquewhite; + } + } +} + diff --git a/form/src/app/common/lesson-title-config/lesson-title-config.component.ts b/form/src/app/common/lesson-title-config/lesson-title-config.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b7601fbea4baa9a2ea8f4a4cd5baed833259249 --- /dev/null +++ b/form/src/app/common/lesson-title-config/lesson-title-config.component.ts @@ -0,0 +1,339 @@ + +import { + Component, + ElementRef, + EventEmitter, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + ViewChild +} from '@angular/core'; + +const editorTpl = `<html lang="en"><head><meta charset="utf-8"> + <meta name="viewport" + content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/> + <style> +@font-face{ + font-family: 'BRLNSDB'; + src: url("../../../assets/font/BRLNSDB.TTF") ; +} + +@font-face{ + font-family: 'BRLNSB'; + src: url("../../../assets/font/BRLNSB.TTF") ; +} + +@font-face{ + font-family: 'BRLNSR'; + src: url("../../../assets/font/BRLNSR.TTF") ; +} + +@font-face{ + font-family: 'GOTHIC'; + src: url("../../../assets/font/GOTHIC.TTF") ; +} + +@font-face{ + font-family: 'GOTHICB'; + src: url("../../../assets/font/GOTHICB.TTF") ; +} + +@font-face{ + font-family: 'GOTHICBI'; + src: url("../../../assets/font/GOTHICBI.TTF") ; +} + +@font-face{ + font-family: 'GOTHICI'; + src: url("../../../assets/font/GOTHICI.TTF") ; +} + +@font-face{ + font-family: 'MMTextBook'; + src: url("../../../assets/font/MMTextBook.otf") ; +} + +@font-face{ + font-family: 'MMTextBook-Bold'; + src: url("../../../assets/font/MMTextBook-Bold.otf") ; +} + +@font-face{ + font-family: 'MMTextBook-BoldItalic'; + src: url("../../../assets/font/MMTextBook-BoldItalic.otf") ; +} + +@font-face{ + font-family: 'MMTextBook-Italic'; + src: url("../../../assets/font/MMTextBook-Italic.otf") ; +} +html, body{ +/*font-size: 30px;*/ +} +body{ + height:48px; + + overflow: hidden; + margin: 0; + padding: 0 .5rem; + font-family: 'BRLNSB, BRLNSDB, BRLNSR, GOTHIC, GOTHICB, MMTextBook'; + background: #FFF; + line-height: 48px; +} +</style> + </head> + <body>{{content}}</body> +</html>`; + +@Component({ + selector: 'app-lesson-title-config', + templateUrl: './lesson-title-config.component.html', + styleUrls: ['./lesson-title-config.component.scss'] +}) +export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, OnChanges { + + fontFamilyList = [ + 'Arial', + 'BRLNSB', + 'BRLNSDB', + 'BRLNSR', + 'GOTHIC', + 'GOTHICB', + // "GOTHICBI", + // "GOTHICI", + 'MMTextBook', + // "MMTextBook-Bold", + // "MMTextBook-Italic", + // "MMTextBook-BoldItalic", + ]; + + + + colorList = [ + '#000000', + '#ffffff', + '#595959', + '#0075c2', + '#c61c1e', + '#9cbc3a', + '#008000', + '#FF0000', + '#D2691E', + ]; + MIN_FONT_SIZE = 1; + MAX_FONT_SIZE = 7; + isShowFontColorPane = false; + isShowBGColorPane = false; + fontSizeRange = [ + // {name: '1å·', value: 9}, + // {name: '2å·', value: 13}, + // {name: '3å·', value: 16}, + // {name: '4å·', value: 18}, + // {name: '5å·', value: 24}, + // {name: '6å·', value: 32}, + + ]; + + editorContent = ''; + + + __fontFamily = 'Arial'; + __fontColor = ''; + __fontSize = 3; + + loopCnt = 0; + maxLoops = 20; + + @ViewChild('titleEl', {static: true}) titleEl: ElementRef; + titleEW = null; + + + @Input() + titleObj = { + content: '', + audio_url: '' + }; + + + @Output() + titleUpdated = new EventEmitter(); + + constructor() { + this.fontSizeRange = []; + for (let i = this.MIN_FONT_SIZE; i <= this.MAX_FONT_SIZE; ++i) { + this.fontSizeRange.push(i); + } + this.__fontSize = 3; + this.__fontColor = this.colorList[0]; + + } + ngOnChanges(vars) { + if (!vars.titleObj.previousValue) {// åˆå§‹åŒ–,内容是空 + return; + } + let defObj = this.titleObj; + if (!vars.titleObj.currentValue) { + defObj = { + content: '', + audio_url: '' + }; + } else { + defObj = vars.titleObj.currentValue; + } + this.titleObj.content = defObj.content || ''; + this.titleObj.audio_url = defObj.audio_url || ''; + this.titleEW.document.body.innerHTML = this.titleObj.content; + } + + ngOnInit() { + if (!this.titleObj) { + this.titleObj = { + content: '', + audio_url: '' + }; + } + this.titleObj.content = this.titleObj.content || ''; + this.titleObj.audio_url = this.titleObj.audio_url || ''; + + this.editorContent = editorTpl.replace('{{content}}', this.titleObj.content) ; + this.titleEW = this.titleEl.nativeElement.contentWindow; + console.log('this.titleEW', this.titleEW); + const tdoc = this.titleEW.document; + tdoc.designMode = 'on'; + tdoc.open('text/html', 'replace'); + tdoc.write(this.editorContent); + tdoc.close(); + tdoc.addEventListener('keypress', this.keyPress, true); + tdoc.addEventListener('blur', () => { + if (this.titleObj.content === this.titleEW.document.body.innerHTML.trim()) { + return; + } + this.shouldSave(); + }, true); + } + htmlEncode(text) { + if (!text) { + return ''; + } + return text.replace(/\&/ig, '&') + .replace(/\</ig, '<') + .replace(/\>/ig, '>') + .replace(/\"/ig, '"'); + } + + htmlDecode(text) { + if (!text) { + return ''; + } + return text.replace(/\&\;/ig, '&') + .replace(/\<\;/ig, '<') + .replace(/\>\;/ig, '>') + .replace(/\"\;/ig, '"'); + } + + + ngOnDestroy(): void { + + } + + keyPress(evt) { + try { + + if (evt.charCode === 13) { + evt.preventDefault(); + evt.stopPropagation(); + return; + } + if (evt.ctrlKey) { + const key = String.fromCharCode(evt.charCode).toLowerCase(); + let cmd = ''; + switch (key) { + case 'b': cmd = 'bold'; break; + case 'i': cmd = 'italic'; break; + case 'u': cmd = 'underline'; break; + } + + + if (cmd) { + this.execEditorCommand(cmd); + + // stop the event bubble + evt.preventDefault(); + evt.stopPropagation(); + } + } + } catch (e) { + console.log(1, e); + alert(e); + } + } + + execEditorCommand(command, option?: any) { + console.log('sssss'); + try { + this.titleEW.focus(); + const result = this.titleEW.document.execCommand(command, false, option); + console.log(result); + this.loopCnt = 0; + + return false; + } catch (e) { + alert(e); + if (this.loopCnt < this.maxLoops) { + setTimeout(() => { + this.execEditorCommand(command, option); + }, 100); + this.loopCnt += 1; + } else { + alert('Error executing command.'); + } + } + } + + onSelectColor(color) { + this.execEditorCommand('forecolor', color); + this.__fontColor = color; + } + onChangeFontColor(val) { + this.execEditorCommand('forecolor', this.__fontColor); + } + onChangeFontFamily(font) { + this.execEditorCommand('fontName', font); + } + onChangeFontSize(size?: any) { + + if (size) { + size += this.__fontSize; + } else { + size = this.__fontSize; + } + size = Math.max(this.MIN_FONT_SIZE, size); + size = Math.min(this.MAX_FONT_SIZE, size); + this.execEditorCommand('fontsize', size); + } + onChangeBold() { + this.execEditorCommand('bold'); + } + onChangeItalic() { + this.execEditorCommand('italic'); + } + onChangeUnderline() { + this.execEditorCommand('underline'); + } + onChangeStrikethrough() { + this.execEditorCommand('strikethrough'); + } + titleAudioUploaded(res) { + this.titleObj.audio_url = res.url; + this.titleUpdated.emit(this.titleObj); + } + shouldSave = () => { + console.log('title shouldSave', this.titleObj); + this.titleObj.content = this.titleEW.document.body.innerHTML.trim(); + this.titleUpdated.emit(this.titleObj); + } +} + + diff --git a/form/src/app/common/player-content-wrapper/player-content-wrapper.component.html b/form/src/app/common/player-content-wrapper/player-content-wrapper.component.html new file mode 100644 index 0000000000000000000000000000000000000000..864df8e812e3a5f90261869b915ee1e0767ba648 --- /dev/null +++ b/form/src/app/common/player-content-wrapper/player-content-wrapper.component.html @@ -0,0 +1,8 @@ +<div class="cmp-player-content-wrapper" #wrapperEl> + <div class="cmp-cnt-box"> + <img [src]="'assets/'+ratio+'.png'" alt=""> + <div class="cmp-cnt-main"> + <ng-content></ng-content> + </div> + </div> +</div> \ No newline at end of file diff --git a/form/src/app/common/player-content-wrapper/player-content-wrapper.component.scss b/form/src/app/common/player-content-wrapper/player-content-wrapper.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..6aec336fb2e4155b1375abdd53191d4f23dc900e --- /dev/null +++ b/form/src/app/common/player-content-wrapper/player-content-wrapper.component.scss @@ -0,0 +1,54 @@ +@import '../../style/common_mixin.css'; + +.cmp-player-content-wrapper{ + max-height: 100%; + display: block; + position: relative; + height: 100%; + .cmp-cnt-box{ + display: inline-block; + max-width: 100%; + max-height: 100%; + width: auto; + height: 100%; + position: relative; + img{ + height: 100%; + width: auto; + } + + } + .cmp-cnt-main{ + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + flex-direction: column; + } +} + + +[style*="--aspect-ratio"] > :first-child { + width: 100%; +} +[style*="--aspect-ratio"] > img { + height: auto; +} +@supports (--custom:property) { + [style*="--aspect-ratio"] { + position: relative; + } + [style*="--aspect-ratio"]::before { + content: ""; + display: block; + padding-bottom: calc(100% / (var(--aspect-ratio))); + } + [style*="--aspect-ratio"] > :first-child { + position: absolute; + top: 0; + left: 0; + height: 100%; + } +} diff --git a/form/src/app/common/player-content-wrapper/player-content-wrapper.component.ts b/form/src/app/common/player-content-wrapper/player-content-wrapper.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0780a42be855a6e3fff637a01a0f4d0002e20e4a --- /dev/null +++ b/form/src/app/common/player-content-wrapper/player-content-wrapper.component.ts @@ -0,0 +1,55 @@ +import { + AfterViewInit, + Component, + ElementRef, + Input, + OnChanges, + OnDestroy, + OnInit, + ViewChild +} from '@angular/core'; + + +@Component({ + selector: 'app-player-content-wrapper', + templateUrl: './player-content-wrapper.component.html', + styleUrls: ['./player-content-wrapper.component.scss'] +}) +export class PlayerContentWrapperComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit { + + + @ViewChild('wrapperEl', {static: true }) wrapperEl: ElementRef; + + // // aspect ratio? + @Input() ratio; + _w: string; + _h: string; + + constructor() { + if (window.innerHeight < window.innerWidth) { + this._h = '100%'; + this._w = 'auto'; + } else { + this._w = '100%'; + this._h = 'auto'; + } + } + ngOnInit() { + if (!this.ratio) { + this.ratio = '20-9'; + } + + + } + ngOnChanges() { + + } + ngOnDestroy(): void { + + } + + ngAfterViewInit() { + + } +} + diff --git a/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.html b/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.html new file mode 100644 index 0000000000000000000000000000000000000000..b5c26bb34504cb78bc873f9e811802831b5f348e --- /dev/null +++ b/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.html @@ -0,0 +1,37 @@ +<div class="position-relative"> + <nz-upload class="p-image-uploader" [nzDisabled]="disableUpload" + [nzShowUploadList]="false" + nzAccept = "image/*" + [nzAction]="uploadUrl" + [nzData]="uploadData" + (nzChange)="handleChange($event)"> + <!--[nzBeforeUpload]="customUpload">--> + <div class="p-box d-flex align-items-center"> + <div class="p-upload-icon" *ngIf="!picUrl && !uploading"> + <i nz-icon nzType="cloud-upload" nzTheme="outline" [style.font-size]="iconSize + 'em'"></i> + <div class="m-3"></div> + <span>{{TIP}}</span> + <!--<div class="mt-5 p-progress-bar" *ngIf="uploading">--> + <!--<div class="p-progress-bg" [style.width]="progress*0.2+'rem'"></div>--> + <!--<div class="p-progress-value">{{progress}}%</div>--> + <!--</div>--> + </div> + <div class="p-upload-progress-bg" *ngIf="uploading"> + <div class="i-bg" [style.width]="progress+'%'"></div> + <div class="i-text"> + <fa-icon icon="cloud-upload-alt"></fa-icon> + Uploading... + </div> + </div> + <div class="p-preview" *ngIf="!uploading && picUrl " + [style.background-image]="picUrl | backgroundImage "> + </div> + </div> + </nz-upload> + <div class="p-btn-delete" *ngIf="canDelete" + nz-popconfirm nzTitle="Are you sure ?" + (nzOnConfirm)="onDelete()" + > + <i nz-icon nzType="close" nzTheme="outline"></i> + </div> +</div> diff --git a/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.scss b/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..98dad112e7375a490e4481a61439e04462c3f85d --- /dev/null +++ b/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.scss @@ -0,0 +1,106 @@ +@import '../../style/common_mixin.css'; + +.p-image-uploader { + position: relative; + display: block; + width: 100%; + height: 0; + padding-bottom: 56.25%; + .p-box { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + border: 2px dashed #ddd; + border-radius: 0.5rem; + background-color: #fafafa; + text-align: center; + color: #aaa; + .p-upload-icon { + text-align: center; + margin: auto; + .anticon-upload { + color: #888; + font-size: 5rem; + } + .p-progress-bar { + position: relative; + width: 20rem; + height: 1.5rem; + border: 1px solid #ccc; + border-radius: 1rem; + .p-progress-bg { + background-color: #1890ff; + border-radius: 1rem; + height: 100%; + } + .p-progress-value { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-shadow: 0 0 4px #000; + color: white; + text-align: center; + font-size: 0.9rem; + line-height: 1.5rem; + } + } + } + .p-preview { + width: 100%; + height: 100%; + background-size: contain; + background-repeat: no-repeat; + background-position: 50% 50%; + //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); + } + } + .d-flex{ + display: flex; + } +} + +.p-btn-delete { + position: absolute; + right: -0.5rem; + top: -0.5rem; + width: 2rem; + height: 2rem; + border: 0.2rem solid white; + border-radius: 50%; + font-size: 1.2rem; + background-color: #fb781a; + color: white; + text-align: center; +} + +.p-upload-progress-bg { + position: absolute; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + & .i-text { + position: absolute; + text-align: center; + color: white; + text-shadow: 0 0 2px rgba(0, 0, 0, .85); + } + & .i-bg { + position: absolute; + left: 0; + top: 0; + height: 100%; + background-color: #27b43f; + border-radius: 0.5rem; + } +} + + +:host ::ng-deep .ant-upload { + display: block; +} diff --git a/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.ts b/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4694a1f1ae4b582b3c121e601c6322437888820 --- /dev/null +++ b/form/src/app/common/upload-image-with-preview/upload-image-with-preview.component.ts @@ -0,0 +1,158 @@ +import {Component, EventEmitter, Input, OnChanges, OnDestroy, Output} from '@angular/core'; +import { NzMessageService, UploadXHRArgs, UploadFile } from 'ng-zorro-antd'; + + +@Component({ + selector: 'app-upload-image-with-preview', + templateUrl: './upload-image-with-preview.component.html', + styleUrls: ['./upload-image-with-preview.component.scss'] +}) +export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges { + uploading = false; + progress = 0; + @Input() + picUrl; + @Input() + canDelete = false; + @Output() + imageUploaded = new EventEmitter(); + @Output() + imageUploadFailure = new EventEmitter(); + @Output() + delete = new EventEmitter(); + @Input() + picItem = null; + @Input() + iconSize = 2; + @Input() + TIP = 'Click here to upload image'; + @Input() + disableUpload = false; + + uploadUrl; + uploadData; + + constructor(private nzMessageService: NzMessageService) { + + this.uploadUrl = (<any> window).courseware.uploadUrl(); + this.uploadData = (<any> window).courseware.uploadData(); + + window['air'].getUploadCallback = (url, data) => { + this.uploadUrl = url; + this.uploadData = data; + }; + + } + ngOnChanges() { + if (!this.picItem) { + return; + } + } + + + + + + handleChange(info: { type: string, file: UploadFile, event: any }): void { + + console.log('info:' , info); + + switch (info.type) { + case 'start': + // this.isUploading = true; + // this.progress = 0; + + this.picUrl = null; + // this.beforeUpload(item.file as any); + if (!this.checkSelectFile(info.file)) { + return; + } + this.uploading = true; + this.progress = 0; + + break; + + case 'success': + // this.isUploading = false; + // this.uploadSuccess(info.file.response); + // this.audioUploaded.emit(info.file.response); + + this.uploadSuccess(info.file); + + break; + case 'progress': + this.progress = parseInt(info.event.percent, 10); + this.doProgress(this.progress); + break; + } + } + + onDelete() { + this.delete.emit(); + } + checkSelectFile(file) { + const isImg = ['image/jpeg', 'image/png', 'image/jpeg', 'image/gif', 'image/bmp'].includes(file.type); + if (!isImg) { + this.nzMessageService.error('You can only upload Image file (jpg|gif|png|bmp)'); + return false; + } + const isGif = !['image/jpeg', 'image/png', 'image/jpeg', 'image/bmp'].includes(file.type); + const delta = isGif ? 20 : 5; + const isOverSize = file.size / 1024 / 1024 < delta; + if (!isOverSize) { + this.nzMessageService.error(`${isGif ? 'Gif' : 'Image'} must smaller than ${delta}MB!`); + return false; + } + return true; + } + + uploadSuccess = (file) => { + this.nzMessageService.info('Upload Success'); + this.uploading = false; + this.picUrl = file.response.url ; + // this.uploadFinished(url); + // if (!inOSS) { + const img = new Image(); + img.addEventListener('load', () => { + + const height = img.naturalHeight; + const width = img.naturalWidth; + file['height'] = height; + file['width'] = width; + img.remove(); + this.imageUploaded.emit(file.response); + // this.resService.updateImage(id, {width, height}).then( () => { + // this.imageUploaded.emit({res_id: id, id, name, hash, url}); + // }); + + }); + img.src = file.response.url; + // } else { + // this.imageUploaded.emit({res_id: id, id, name, hash, url}); + // } + } + + uploadFailure = (err, file) => { + this.uploading = false; + if (err.name && err.name === 'cancel') { + return; + } + console.log(err); + this.nzMessageService.error('Upload Error ' + err.message); + this.imageUploadFailure.emit(file); + } + + doProgress = function(p) { + if (p > 1) { + p = 1; + } + if (p < 0) { + p = 0; + } + // console.log(Math.floor(p * 100)); + this.progress = Math.floor(p * 100); + } + ngOnDestroy() { + } + +} diff --git a/form/src/app/common/upload-video/upload-video.component.html b/form/src/app/common/upload-video/upload-video.component.html new file mode 100644 index 0000000000000000000000000000000000000000..8f1533993f2bdcf3d5f3e0cd4337f3fa96a1ebd7 --- /dev/null +++ b/form/src/app/common/upload-video/upload-video.component.html @@ -0,0 +1,94 @@ +<div class="p-video-box"> +<div class="up-video" style="display: flex;"> + <!--<nz-upload class="" [nzDisabled]="!showUploadBtn"--> + <!--[nzShowUploadList]="false"--> + <!--[nzBeforeUpload]="beforeUpload"--> + <!--nzAccept = ".mp4"--> + <!--style="margin-right: 1rem">--> + + <nz-upload class="p-image-uploader" [nzDisabled]="uploading" + [nzShowUploadList]="false" + nzAccept = ".mp4" + [nzAction]="uploadUrl" + [nzData]="uploadData" + (nzChange)="handleChange($event)" + style="margin-right: 1rem"> + + <button type="button" nz-button nzType="default" *ngIf="showUploadBtn" [disabled]="uploading" + [nzLoading]="uploading" > + <i nz-icon nzType="plus" nzTheme="outline"></i> + <span>{{ uploading ? 'Uploading' : 'Select Video' }}</span> + <!--<span>Select Video</span>--> + </button> + + + + + </nz-upload> + <!--<button nz-button nzType="primary" *ngIf="showUploadBtn"--> + <!--style="margin-right: 1rem"--> + <!--type="button"--> + <!--[nzLoading]="uploading"--> + <!--(click)="handleUpload()"--> + <!--[disabled]="!videoFile || uploading">--> + <!--<i nz-icon type="upload" theme="outline"></i>--> + <!--<span>{{ uploading ? 'Uploading' : 'Start Upload' }}</span>--> + <!--</button>--> + + <!-- + <button type="button" + (click)="extraCover()" + nz-button nzType="default" + [disabled]=" !(videoUrl && videoUrl.constructor.name === 'String')">设置å°é¢</button> + --> + <!-- + <nz-divider></nz-divider> + + <div [style.display]="!uploading?'none':''" style="position:relative"> + <div style="width: calc( 100% - 20px);"> + <nz-progress [nzPercent]="progress"> + </nz-progress> + </div> + <i (click)="cancelUpload()" class="anticon anticon-close-circle" style="position: absolute;top: 50%;right: 0;transform: translateY(-50%);cursor: pointer"></i> + </div> + --> + + +</div> +<div class="p-box d-flex align-items-center p-video-uploader"> + <div class="p-upload-icon" *ngIf="!showUploadBtn && !videoUrl && !uploading"> + <i nz-icon nzType="upload" nzTheme="outline"></i> + <div class="m-3"></div> + <span>Click here to upload video</span> + <div class="mt-5 p-progress-bar" *ngIf="uploading"> + <div class="p-progress-bg" [style.width]="progress*0.2+'rem'"></div> + <div class="p-progress-value">{{progress}}%</div> + </div> + </div> + <div class="p-upload-progress-bg dddd " *ngIf="uploading" + [ngClass]="{'smart-bar': showUploadBtn}" > + <div class="i-bg" [style.width]="progress+'%'"></div> + <div class="i-text"> + <fa-icon icon="cloud-upload-alt"></fa-icon> + Uploading... + </div> + </div> + <div class="p-upload-check-bg" *ngIf="checking"> + <div class="i-bg" [style.width]="progress+'%'"></div> + <div class="i-text"> + <fa-icon icon="cloud-upload-alt"></fa-icon> + <i nz-icon nzType="loading" nzTheme="outline"></i>Checking... + </div> + </div> + <div class="p-preview" *ngIf="!uploading && videoUrl " > + <!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>--> + <video [src]="safeVideoUrl(videoUrl)" controls #videoNode></video> + </div> +</div> +<div [style.display]="!checkVideoExists?'none':''"> + <span><i nz-icon nzType="loading" nzTheme="outline"></i> checking file to upload</span> +</div> +</div> + + + diff --git a/form/src/app/common/upload-video/upload-video.component.scss b/form/src/app/common/upload-video/upload-video.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..3e0fc1ce96f94d17a3d5da5af6a1e88824c08f09 --- /dev/null +++ b/form/src/app/common/upload-video/upload-video.component.scss @@ -0,0 +1,152 @@ +@import '../../style/common_mixin.css'; +/*.p-video-box{ + bottom: 0; + border: 2px dashed #ddd; + border-radius: 0.5rem; + background-color: #fafafa; + text-align: center; + color: #aaa; + padding-top: 56.25%; + //font-size: 4rem; + position: relative; + .p-upload-icon{ + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50% ,-50%); + } +}*/ +.p-video-uploader { + position: relative; + display: block; + width: 100%; + height: 0; + padding-bottom: 56.25%; + .p-box { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + border: 2px dashed #ddd; + //border-radius: 0.5rem; + background-color: #fafafa; + text-align: center; + color: #aaa; + + + } +} +.p-upload-icon { + text-align: center; + margin: auto; + +} +.p-upload-icon .anticon-upload { + color: #888; + font-size: 5rem; +} +p-progress-bar { + position: relative; + width: 20rem; + height: 1.5rem; + border: 1px solid #ccc; + border-radius: 1rem; + +} +.p-progress-bar .p-progress-bg { + background-color: #1890ff; + border-radius: 1rem; + height: 100%; +} +.p-progress-bar .p-progress-value { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-shadow: 0 0 4px #000; + color: white; + text-align: center; + font-size: 0.9rem; + line-height: 1.5rem; +} +.p-preview { + width: 100%; + height: 100%; + //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); + +} +.p-preview video{ + max-height: 100%; + max-width: 100%; + position: absolute; + display: flex; + } +.p-btn-delete { + position: absolute; + right: -0.5rem; + top: -0.5rem; + width: 2rem; + height: 2rem; + border: 0.2rem solid white; + border-radius: 50%; + font-size: 1.2rem; + background-color: #fb781a; + color: white; + text-align: center; +} + +.p-upload-progress-bg, .p-upload-check-bg { + position: absolute; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + & .i-text { + position: absolute; + text-align: center; + color: white; + text-shadow: 0 0 2px rgba(0, 0, 0, .85); + } + & .i-bg { + position: absolute; + left: 0; + top: 0; + height: 100%; + background-color: #1890ff; + //border-radius: 0.5rem 0 0 0.5rem; + } +} +.p-upload-progress-bg.smart-bar{ + height: 50px!important; + margin-top: 20px!important; +} +.p-upload-check-bg { + position: absolute; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + & .i-text { + position: absolute; + text-align: center; + color: white; + text-shadow: 0 0 2px rgba(0, 0, 0, .85); + } + & .i-bg { + position: absolute; + left: 0; + top: 0; + height: 100%; + background-color: #17a2b8; + //border-radius: 0.5rem 0 0 0.5rem; + } +} + + +//:host ::ng-deep .ant-upload { +// display: block; +//} diff --git a/form/src/app/common/upload-video/upload-video.component.ts b/form/src/app/common/upload-video/upload-video.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..013f8ad224a9a0bc09a015e2254b1cbaa4136bce --- /dev/null +++ b/form/src/app/common/upload-video/upload-video.component.ts @@ -0,0 +1,211 @@ +import {Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, SecurityContext, ViewChild} from '@angular/core'; +import {NzMessageService, UploadChangeParam, UploadFile, UploadFileStatus} from 'ng-zorro-antd'; +import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; + + +@Component({ + selector: 'app-upload-video', + templateUrl: './upload-video.component.html', + styleUrls: ['./upload-video.component.scss'] +}) +export class UploadVideoComponent implements OnChanges, OnDestroy { + uploading = false; + checking = false; + checkVideoExists = false; + uploadClicked = false; + + @Input() + videoFile = null; + uploaderInst = null; + + progress = 0; + // @Input() + // setCovering = false; + + @Input() + videoUrl = ''; + @ViewChild('videoNode', {static: true }) + videoNode: ElementRef; + + + + + // @Input() + // extractCoverFunc = null; + + @Output() + videoUploaded = new EventEmitter(); + @Output() + videoUploadFailure = new EventEmitter(); + @Output() + extractVideoCover = new EventEmitter(); + + + @Input() + showUploadBtn = true; + @Input() + item: any; + // videoItem = null; + + uploadUrl; + uploadData; + + constructor(private nzMessageService: NzMessageService, + private sanitization: DomSanitizer + // private cwService: _coursewareService, + // private resService: ResourceService + ) { + this.uploading = false; + this.videoFile = null; + + + this.uploadUrl = (<any> window).courseware.uploadUrl(); + this.uploadData = (<any> window).courseware.uploadData(); + + window['air'].getUploadCallback = (url, data) => { + + this.uploadUrl = url; + this.uploadData = data; + }; + + } + ngOnChanges() { + // if (!this.videoFile || this.showUploadBtn) { + // return; + // } + // this.beforeUpload(this.videoFile); + // this.handleUpload(); + } + ngOnDestroy(): void { + URL.revokeObjectURL(this.videoUrl); + } + + safeVideoUrl(url) { + console.log(url); + return this.sanitization.bypassSecurityTrustResourceUrl(url); // `${url}`; + } + videoLoadedMetaData() { + + } + + + handleChange(info: UploadChangeParam/* { type: string, file: UploadFile, event: any }*/): void { + + console.log('info:' , info); + + switch (info.type) { + case 'start': + + // this.beforeUpload(info.file); + + + if (!this.checkSelectFile(info.file)) { + return; + } + + + this.uploading = true; + this.progress = 0; + + break; + + case 'success': + + + this.uploadSuccess(info.file); + + // this.beforeUpload(info.file); + // this.uploadSuccess(info.file); + + break; + case 'progress': + this.progress = info.event.percent; + this.doProgress(this.progress); + break; + } + } + + + checkSelectFile(file) { + if (!file.lastModified) { + return false; + } + const delta = 500; + const isOverSize = (file.size / 1024 / 1024) < delta; + if (!isOverSize) { + this.nzMessageService.error(`video must smaller than ${delta}MB!`); + return false; + } + return true; + } + checkHashFinish = (hash) => { + this.checking = false; + this.uploading = true; + } + + uploadSuccess = (file) => { + + this.nzMessageService.info('Upload Success'); + // this.updateStatus(false); + this.uploading = false; + this.videoFile = null; + // this.updateSource(url); + this.videoUrl = file.response.url; + // console.log(this.picUrl) + // this.uploadFinished(url); + // if (!inOSS) { + const vid = document.createElement('video'); + vid.addEventListener('loadedmetadata', () => { + const height = vid.videoHeight; + const width = vid.videoWidth; + let duration = vid.duration; + if (duration) { + duration = duration * 1000; + } + file.height = height; + file.width = width; + file.duration = duration; + vid.preload = 'none'; + vid.src = ''; + vid.remove(); + + this.videoUploaded.emit(file.response); + + // this.resService.updateVideo(id, {width, height, duration}).then( () => { + // this.videoUploaded.emit({res_id: id, id, name, hash, url}); + // }); + + }); + vid.src = file.response.url; + // } else { + // this.videoUploaded.emit(file.response); + // } + + + + } + + + + uploadFailure = (err, file) => { + this.uploading = false; + if (err.name && err.name === 'cancel') { + return; + } + console.log(err); + this.nzMessageService.error('Upload Error ' + err.message); + this.videoUploadFailure.emit(file); + } + + doProgress = (p) => { + if (p > 1) { + p = 1; + } + if (p < 0) { + p = 0; + } + // console.log(Math.floor(p * 100)); + this.progress = Math.floor(p * 100); + } +} + diff --git a/form/src/app/form/form.component.css b/form/src/app/form/form.component.css new file mode 100644 index 0000000000000000000000000000000000000000..5d78cd06c5f047021baddbe66edf8dae0954fb5d --- /dev/null +++ b/form/src/app/form/form.component.css @@ -0,0 +1,35 @@ +@import '../style/common_mixin.css'; + + +.model-content { + width: 100%; + height: 100%; + +} + +.radioPaire { + float: left; + margin: 3px; + border-style: dashed; + border-color: #000; + border-width: 1px; +} + +.border { + border-radius: 20px; + border-style: dashed; + padding: 20px; + margin: 20px; + /*width: 500px; */ + /*//border-radius: 20px;*/ + /*//border-width: 2px;*/ + /*//border-color: #000000;*/ +} + + +.border-lite { + border: 2px dashed #ddd; + border-radius: 0.5rem; + padding: 10px; + margin: 10px; +} diff --git a/form/src/app/form/form.component.html b/form/src/app/form/form.component.html new file mode 100644 index 0000000000000000000000000000000000000000..3836ff944244c9fac11d53e1301227e43db81b31 --- /dev/null +++ b/form/src/app/form/form.component.html @@ -0,0 +1,36 @@ +<div class="model-content"> + <!-- <div class="border" style=" width: 520px; height: 120px;"> + <span style="height: 30px; font-size: 18px;">å•è¯éŸ³é¢‘:</span> + <br> + <app-audio-recorder [audioUrl]=" item.audio" (audioUploaded)="onAudioUploadSuccess($event)"> + </app-audio-recorder> + </div> + <div class="border" style="width: 520px;"> + <span style="height: 30px; font-size: 18px;">æ£ç¡®å—æ¯ï¼š</span> + <div> + <div *ngFor="let rightWord of item.rightWordList; let i = index"> + <div style="padding: 2px;"> + <input style="width: 150px;float: left;" type="text" nz-input [(ngModel)]="rightWord.word" (blur)="save()"> + <app-audio-recorder style="float: left;" [audioUrl]="rightWord.audio" + (audioUploaded)="onRightAudioUploadSuccess($event, i)"> + </app-audio-recorder> + <button style="float: right; margin-left: 10px; height: 32px; color: red;" nz-button nzType="dashed" + class="add-btn" (click)="removeRightWord(i)"> + <i nz-icon nzType="minus-circle" nzTheme="outline"></i> + åˆ é™¤å—æ¯ + </button> + </div> + <br> <br> + </div> + </div> + <div *ngIf="(item.rightWordList.length +item.wrongWordList.length < 5)"> + <button style="margin-left: 2px; margin-top: 2px; height: 32px;" nz-button nzType="dashed" class="add-btn" + (click)="addRightWord()"> + <i nz-icon nzType="plus-circle" nzTheme="outline"></i> + æ·»åŠ <span style="color: #44bb44;">æ£ç¡®</span>çš„å—æ¯ + </button> + </div> + </div> + --> + +</div> diff --git a/form/src/app/form/form.component.ts b/form/src/app/form/form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..082e3ececafbaecfd34e33722fae3e1549440a28 --- /dev/null +++ b/form/src/app/form/form.component.ts @@ -0,0 +1,115 @@ +import { Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef } from '@angular/core'; +import { JsonPipe } from '@angular/common'; + + +@Component({ + selector: 'app-form', + templateUrl: './form.component.html', + styleUrls: ['./form.component.css'] +}) +export class FormComponent implements OnInit, OnChanges, OnDestroy { + + // å‚¨å˜æ•°æ®ç”¨ + saveKey = "test_001"; + // 储å˜å¯¹è±¡ + item; + + constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) { + + } + + createShell() { + this.item.wordList.push({ + word: '', + audio: '', + backWord: '', + backWordAudio: '', + }); + this.save(); + } + + removeShell(idx) { + this.item.wordList.splice(idx, 1); + this.save(); + } + + ngOnInit() { + + this.item = { + wordList: [] + }; + + // 获å–å˜å‚¨çš„æ•°æ® + (<any>window).courseware.getData((data) => { + + if (data) { + this.item = data; + } + + this.init(); + this.changeDetectorRef.markForCheck(); + this.changeDetectorRef.detectChanges(); + this.refresh(); + + }, this.saveKey); + } + + ngOnChanges() { + } + + ngOnDestroy() { + } + + init() { + + } + + + /** + * 储å˜å›¾ç‰‡æ•°æ® + * @param e + */ + onImageUploadSuccess(e, key) { + + this.item[key] = e.url; + this.save(); + } + + /** + * 储å˜éŸ³é¢‘æ•°æ® + * @param e + */ + onAudioUploadSuccess(e) { + this.item.audio = e.url; + this.save(); + } + + onWordAudioUploadSuccess(e, idx) { + this.item.wordList[idx].audio = e.url; + this.save(); + } + + onBackWordAudioUploadSuccess(e, idx) { + this.item.wordList[idx].backWordAudio = e.url; + this.save(); + } + + /** + * å‚¨å˜æ•°æ® + */ + save() { + (<any>window).courseware.setData(this.item, null, this.saveKey); + this.refresh(); + console.log('this.item = ' + JSON.stringify(this.item)); + } + + /** + * 刷新 æ¸²æŸ“é¡µé¢ + */ + refresh() { + setTimeout(() => { + this.appRef.tick(); + }, 1); + } + +} \ No newline at end of file diff --git a/form/src/app/pipes/background-image.pipe.ts b/form/src/app/pipes/background-image.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc15f66b9a285399cf75b9719b345f0de67c2902 --- /dev/null +++ b/form/src/app/pipes/background-image.pipe.ts @@ -0,0 +1,23 @@ +import {Pipe, PipeTransform} from '@angular/core'; +// import {ElectronUtil} from '../util/ElectronUtil'; + +declare const APP_PATH; +// const isInElectron = localStorage.getItem('electron'); + +@Pipe({ + name: 'backgroundImage' +}) +export class BackgroundImagePipe implements PipeTransform { + + transform(value: any, coursewareSid?: string) { + // const ret = value ? `url(${value})` : ''; + const ret = value ? `url(${value})` : ''; + return ret; + // let ret = value > 0 ? `url(/api/media-resource/${value}/file)` : ''; + // if (isInElectron && ElectronUtil.hasCached(coursewareSid, value)) { + // ret = `url(file://${APP_PATH}/courseware_cache/${coursewareSid}/${value})`; + // } + // return ret; + } + +} diff --git a/form/src/app/pipes/resource.pipe.ts b/form/src/app/pipes/resource.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7f5f8df579c3d7981a2556ef149990a9d6ba50b --- /dev/null +++ b/form/src/app/pipes/resource.pipe.ts @@ -0,0 +1,28 @@ +import {Pipe, PipeTransform} from '@angular/core'; +// import {ElectronUtil} from '../util/ElectronUtil'; + +declare const APP_PATH; +// const isInElectron = localStorage.getItem('electron'); + +@Pipe({ + name: 'resource' +}) +export class ResourcePipe implements PipeTransform { + + transform(pic_url: any, coursewareSid?: string): string { + // return pic_url; + if (pic_url && typeof pic_url === 'object') { + return pic_url; + } + // console.log('resource', pic_url) + return `${pic_url}?t=${Math.random()}`; + + // let ret = value ? `/api/resource/${value}/file` : ''; + // let ret = res_id ? `/resource/audio/${res_id}` : ''; + // if (isInElectron && ElectronUtil.hasCached(coursewareSid, res_id)) { + // ret = `file://${APP_PATH}/courseware_cache/${coursewareSid}/${res_id}`; + // } + // return ret; + } + +} diff --git a/form/src/app/pipes/time.pipe.ts b/form/src/app/pipes/time.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..af84a0c697319c7f0c1f41115a113a6f4540d423 --- /dev/null +++ b/form/src/app/pipes/time.pipe.ts @@ -0,0 +1,19 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import * as _ from 'lodash'; + +@Pipe({ + name: 'time' +}) +export class TimePipe implements PipeTransform { + + transform(value: any, args?: any): any { + let ret = '00:00'; + if (_.isNumber(value) && value > 0) { + const minutes = Math.floor(value / 60); + const seconds = Math.floor(value % 60); + ret = _.padStart(minutes, 2, '0') + ':' + _.padStart(seconds, 2, '0'); + } + return ret; + } + +} diff --git a/form/src/app/play/Unit.ts b/form/src/app/play/Unit.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a84782db4c8f7a50a9e45a2bd7e50d7f32d2f0c --- /dev/null +++ b/form/src/app/play/Unit.ts @@ -0,0 +1,1676 @@ + +import TWEEN from '@tweenjs/tween.js'; + +interface AirWindow extends Window { + air: any; + curCtx: any; +} +declare let window: AirWindow; + +class Sprite { + x = 0; + y = 0; + color = ''; + radius = 0; + alive = false; + margin = 0; + angle = 0; + ctx; + + constructor(ctx = null) { + if (!ctx) { + this.ctx = window.curCtx; + } else { + this.ctx = ctx; + } + } + update($event) { + this.draw(); + } + draw() { + + } + +} + + + + + +export class MySprite extends Sprite { + + _width = 0; + _height = 0; + _anchorX = 0; + _anchorY = 0; + _offX = 0; + _offY = 0; + scaleX = 1; + scaleY = 1; + _alpha = 1; + rotation = 0; + visible = true; + skewX = 0; + skewY = 0; + + _shadowFlag = false; + _shadowColor; + _shadowOffsetX = 0; + _shadowOffsetY = 0; + _shadowBlur = 5; + + _radius = 0; + + children = [this]; + + childDepandVisible = true; + childDepandAlpha = false; + + img; + _z = 0; + + + init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) { + + if (imgObj) { + + this.img = imgObj; + + this.width = this.img.width; + this.height = this.img.height; + + + } + + this.anchorX = anchorX; + this.anchorY = anchorY; + } + + + setShadow(offX, offY, blur, color = 'rgba(0, 0, 0, 0.3)') { + + + this._shadowFlag = true; + this._shadowColor = color; + this._shadowOffsetX = offX; + this._shadowOffsetY = offY; + this._shadowBlur = blur; + + } + + setRadius(r) { + this._radius = r; + } + + + update($event = null) { + if (!this.visible && this.childDepandVisible) { + return; + } + + this.draw(); + + } + draw() { + + this.ctx.save(); + + this.drawInit(); + + this.updateChildren(); + + this.ctx.restore(); + + + } + + drawInit() { + + this.ctx.translate(this.x, this.y); + + this.ctx.rotate(this.rotation * Math.PI / 180); + + this.ctx.scale(this.scaleX, this.scaleY); + + this.ctx.globalAlpha = this.alpha; + + this.ctx.transform(1, this.skewX, this.skewY, 1, 0, 0); + + + + + + if (this._radius) { + + const r = this._radius; + const w = this.width; + const h = this.height; + + this.ctx.lineTo(-w / 2, h / 2); // 创建水平线 + this.ctx.arcTo(-w / 2, -h / 2, -w / 2 + r, -h / 2, r); + this.ctx.arcTo(w / 2, -h / 2, w / 2, -h / 2 + r, r); + this.ctx.arcTo(w / 2, h / 2, w / 2 - r, h / 2, r); + this.ctx.arcTo(-w / 2, h / 2, -w / 2, h / 2 - r, r); + + this.ctx.clip(); + } + + } + + drawSelf() { + + + + if (this._shadowFlag) { + + this.ctx.shadowOffsetX = this._shadowOffsetX; + this.ctx.shadowOffsetY = this._shadowOffsetY; + this.ctx.shadowBlur = this._shadowBlur; + this.ctx.shadowColor = this._shadowColor; + } else { + this.ctx.shadowOffsetX = 0; + this.ctx.shadowOffsetY = 0; + this.ctx.shadowBlur = null; + this.ctx.shadowColor = null; + } + + + if (this.img) { + this.ctx.drawImage(this.img, this._offX, this._offY); + } + + + + + } + + updateChildren() { + + if (this.children.length <= 0) { return; } + + for (const child of this.children) { + if (child === this) { + if (this.visible) { + this.drawSelf(); + } + } else { + child.update(); + } + } + } + + + load(url, anchorX = 0.5, anchorY = 0.5) { + + return new Promise((resolve, reject) => { + const img = new Image(); + img.onload = () => resolve(img); + img.onerror = reject; + img.src = url; + }).then(img => { + + this.init(img, anchorX, anchorY); + return img; + }); + } + + addChild(child, z = 1) { + if (this.children.indexOf(child) === -1) { + this.children.push(child); + child._z = z; + child.parent = this; + } + + this.children.sort((a, b) => { + return a._z - b._z; + }); + + + if (this.childDepandAlpha) { + child.alpha = this.alpha; + } + + } + removeChild(child) { + const index = this.children.indexOf(child); + if (index !== -1) { + this.children.splice(index, 1); + } + } + + removeChildren() { + for (let i = 0; i < this.children.length; i++) { + if (this.children[i]) { + if (this.children[i] !== this) { + this.children.splice(i, 1); + i --; + } + } + } + } + + _changeChildAlpha(alpha) { + for (const child of this.children) { + if (child !== this) { + child.alpha = alpha; + } + } + } + + set alpha(v) { + this._alpha = v; + if (this.childDepandAlpha) { + this._changeChildAlpha(v); + } + } + get alpha() { + return this._alpha; + } + set width(v) { + this._width = v; + this.refreshAnchorOff(); + } + get width() { + return this._width; + } + set height(v) { + this._height = v; + this.refreshAnchorOff(); + } + get height() { + return this._height; + } + set anchorX(value) { + this._anchorX = value; + this.refreshAnchorOff(); + } + get anchorX() { + return this._anchorX; + } + set anchorY(value) { + this._anchorY = value; + this.refreshAnchorOff(); + } + get anchorY() { + return this._anchorY; + } + refreshAnchorOff() { + this._offX = -this._width * this.anchorX; + this._offY = -this._height * this.anchorY; + } + + setScaleXY(value) { + this.scaleX = this.scaleY = value; + } + + getBoundingBox() { + + + const getParentData = (item) => { + + let px = item.x; + let py = item.y; + + let sx = item.scaleX; + let sy = item.scaleY; + const parent = item.parent; + if (parent) { + + const obj = getParentData(parent); + + const _x = obj.px; + const _y = obj.py; + const _sx = obj.sx; + const _sy = obj.sy; + + px = _x + item.x * _sx; + py = _y + item.y * _sy; + + sx *= _sx; + sy *= _sy; + + } + + return {px, py, sx, sy}; + }; + + + const data = getParentData(this); + + + const x = data.px + this._offX * Math.abs(data.sx); + const y = data.py + this._offY * Math.abs(data.sy); + const width = this.width * Math.abs(data.sx); + const height = this.height * Math.abs(data.sy); + + // const x = this.x + this._offX * Math.abs(this.scaleX); + // const y = this.y + this._offY * Math.abs(this.scaleY); + // const width = this.width * Math.abs(this.scaleX); + // const height = this.height * Math.abs(this.scaleY); + + return {x, y, width, height}; + } + +} + + + + + +export class ColorSpr extends MySprite { + + r = 0; + g = 0; + b = 0; + + createGSCanvas() { + + if (!this.img) { + return; + } + + + + const rect = this.getBoundingBox(); + if (rect.width <= 1 || rect.height <= 1) { + return; + } + + + const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height); + for ( let i = 0; i < c.height; i++) { + for ( let j = 0; j < c.width; j++) { + + const x = (i * 4) * c.width + ( j * 4 ); + const r = c.data[x]; + const g = c.data[x + 1]; + const b = c.data[x + 2]; + + c.data[x] = this.r; + c.data[x + 1] = this.g; + c.data[x + 2] = this.b; + + + + // c.data[x] = c.data[x + 1] = c.data[x + 2] = (r + g + b) / 3 ; + // // c.data[x + 3] = 255; + } + } + + this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height); + } + + + drawSelf() { + super.drawSelf(); + this.createGSCanvas(); + } + +} + + +export class GrayscaleSpr extends MySprite { + + grayScale = 120; + + createGSCanvas() { + + if (!this.img) { + return; + } + + + + const rect = this.getBoundingBox(); + + const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height); + for ( let i = 0; i < c.height; i++) { + for ( let j = 0; j < c.width; j++) { + + const x = (i * 4) * c.width + ( j * 4 ); + const r = c.data[x]; + const g = c.data[x + 1]; + const b = c.data[x + 2]; + // const a = c.data[x + 3]; + + c.data[x] = c.data[x + 1] = c.data[x + 2] = this.grayScale; // (r + g + b) / 3; + // c.data[x + 3] = 255; + } + } + + this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height); + } + + + drawSelf() { + super.drawSelf(); + this.createGSCanvas(); + } + +} + + + + + + +export class BitMapLabel extends MySprite { + + + labelArr; + baseUrl; + + setText(data, text) { + + this.labelArr = []; + + const labelArr = []; + const tmpArr = text.split(''); + let totalW = 0; + let h = 0; + for (const tmp of tmpArr) { + + const label = new MySprite(this.ctx); + label.init(data[tmp], 0); + this.addChild(label); + labelArr.push(label); + + totalW += label.width; + h = label.height; + } + + + this.width = totalW; + this.height = h; + + let offX = -totalW / 2; + for (const label of labelArr) { + label.x = offX; + offX += label.width; + } + + this.labelArr = labelArr; + } + +} + + + + +export class Label extends MySprite { + + text: string; + // fontSize:String = '40px'; + fontName = 'Verdana'; + textAlign = 'left'; + fontSize = 40; + fontColor = '#000000'; + fontWeight = 900; + _maxWidth; + outline = 0; + outlineColor = '#ffffff'; + + // _shadowFlag = false; + // _shadowColor; + // _shadowOffsetX; + // _shadowOffsetY; + // _shadowBlur; + + _outlineFlag = false; + _outLineWidth; + _outLineColor; + + + constructor(ctx = null) { + super(ctx); + this.init(); + } + + refreshSize() { + + this.ctx.save(); + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = this.fontWeight; + + this._width = this.ctx.measureText(this.text).width; + this._height = this.fontSize; + this.refreshAnchorOff(); + + this.ctx.restore(); + + } + + setMaxSize(w) { + + this._maxWidth = w; + this.refreshSize(); + if (this.width >= w) { + this.scaleX *= w / this.width; + this.scaleY *= w / this.width; + } + } + + show(callBack = null) { + + this.visible = true; + + if (this.alpha >= 1) { + return; + } + + const tween = new TWEEN.Tween(this) + .to({ alpha: 1 }, 800) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }) + .start(); // Start the tween immediately. + } + + // setShadow(offX = 0, offY = 2, blur = 2, color = 'rgba(0, 0, 0, 0.2)') { + // + // this._shadowFlag = true; + // this._shadowColor = color; + // // 将阴影å‘å³ç§»åЍ15px,å‘上移动10px + // this._shadowOffsetX = 5; + // this._shadowOffsetY = 5; + // // 轻微模糊阴影 + // this._shadowBlur = 5; + // } + + setOutline(width = 5, color = '#ffffff') { + + this._outlineFlag = true; + this._outLineWidth = width; + this._outLineColor = color; + + } + + drawText() { + + // console.log('in drawText', this.text); + + if (!this.text) { return; } + + + // if (this._shadowFlag) { + // + // this.ctx.shadowColor = this._shadowColor; + // // 将阴影å‘å³ç§»åЍ15px,å‘上移动10px + // this.ctx.shadowOffsetX = this._shadowOffsetX; + // this.ctx.shadowOffsetY = this._shadowOffsetY; + // // 轻微模糊阴影 + // this.ctx.shadowBlur = this._shadowBlur; + // } + + + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = this.fontWeight; + + if (this._outlineFlag) { + this.ctx.lineWidth = this._outLineWidth; + this.ctx.strokeStyle = this._outLineColor; + this.ctx.strokeText(this.text, 0, 0); + } + + this.ctx.fillStyle = this.fontColor; + + + + if (this.outline > 0) { + this.ctx.lineWidth = this.outline; + this.ctx.strokeStyle = this.outlineColor; + this.ctx.strokeText(this.text, 0, 0); + + } + + this.ctx.fillText(this.text, 0, 0); + + + } + + + drawSelf() { + super.drawSelf(); + this.drawText(); + } + +} + +export class RichTextOld extends Label { + + textArr = []; + fontSize = 40; + + setText(text: string, words) { + + let newText = text; + for (const word of words) { + + const re = new RegExp(word, 'g'); + newText = newText.replace( re, `#${word}#`); + // newText = newText.replace(word, `#${word}#`); + } + + this.textArr = newText.split('#'); + this.text = newText; + + // this.setSize(); + } + + refreshSize() { + + this.ctx.save(); + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = this.fontWeight; + + let curX = 0; + for (const text of this.textArr) { + const w = this.ctx.measureText(text).width; + curX += w; + } + + this.width = curX; + this.height = this.fontSize; + this.refreshAnchorOff(); + + this.ctx.restore(); + + } + + + show(callBack = null) { + + // console.log(' in show '); + this.visible = true; + // this.alpha = 0; + + const tween = new TWEEN.Tween(this) + .to({ alpha: 1 }, 800) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }) + .start(); // Start the tween immediately. + + } + + + + drawText() { + + // console.log('in drawText', this.text); + + if (!this.text) { return; } + + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = 900; + + this.ctx.lineWidth = 5; + this.ctx.strokeStyle = '#ffffff'; + // this.ctx.strokeText(this.text, 0, 0); + + this.ctx.fillStyle = '#000000'; + // this.ctx.fillText(this.text, 0, 0); + + + let curX = 0; + for (let i = 0; i < this.textArr.length; i++) { + + const w = this.ctx.measureText(this.textArr[i]).width; + + if ((i + 1) % 2 === 0) { + this.ctx.fillStyle = '#c8171e'; + } else { + this.ctx.fillStyle = '#000000'; + } + + this.ctx.fillText(this.textArr[i], curX, 0); + curX += w; + + } + + + } + +} + + + + + +export class RichText extends Label { + + + disH = 30; + + constructor(ctx?: any) { + super(ctx); + + // this.dataArr = dataArr; + } + + + + drawText() { + + if (!this.text) { + return; + } + + + this.ctx.font = `${this.fontSize}px ${this.fontName}`; + this.ctx.textAlign = this.textAlign; + this.ctx.textBaseline = 'middle'; + this.ctx.fontWeight = this.fontWeight; + this.ctx.fillStyle = this.fontColor; + + + const selfW = this.width * this.scaleX; + + + const chr = this.text.split(' '); + let temp = ''; + const row = []; + const w = selfW - 80; + const disH = (this.fontSize + this.disH) * this.scaleY; + + + + + for (const c of chr) { + if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) { + temp += ' ' + c; + } else { + row.push(temp); + temp = ' ' + c; + } + } + row.push(temp); + + const x = 0; + const y = -row.length * disH / 2; + // for (let b = 0 ; b < row.length; b++) { + // this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + // } + + + if (this._outlineFlag) { + this.ctx.lineWidth = this._outLineWidth; + this.ctx.strokeStyle = this._outLineColor; + for (let b = 0 ; b < row.length; b++) { + this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + } + // this.ctx.strokeText(this.text, 0, 0); + } + + + // this.ctx.fillStyle = '#ff7600'; + for (let b = 0 ; b < row.length; b++) { + this.ctx.fillText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + } + + } + + + drawSelf() { + super.drawSelf(); + this.drawText(); + } + +} + + + + +export class LineRect extends MySprite { + + lineColor = '#ffffff'; + lineWidth = 10; + + setSize(w, h) { + this.width = w; + this.height = h; + } + + drawLine() { + + this.ctx.beginPath(); + this.ctx.moveTo(this._offX, this._offY); + this.ctx.lineTo(this._offX + this.width, this._offY); + this.ctx.lineTo(this._offX + this.width, this._offY + this.height); + this.ctx.lineTo(this._offX, this._offY + this.height); + this.ctx.closePath(); + + this.ctx.lineWidth = this.lineWidth; + // this.ctx.fillStyle = "rgb(2,33,42)"; //指定填充颜色 + // this.ctx.fill(); //对多边形进行填充 + + this.ctx.strokeStyle = this.lineColor; // "#ffffff"; + this.ctx.stroke(); + + } + + + drawSelf() { + super.drawSelf(); + this.drawLine(); + } +} + + +export class ShapeRect extends MySprite { + + fillColor = '#FF0000'; + + setSize(w, h) { + this.width = w; + this.height = h; + + // console.log('w:', w); + // console.log('h:', h); + } + + drawShape() { + + this.ctx.fillStyle = this.fillColor; + this.ctx.fillRect(this._offX, this._offY, this.width, this.height); + + } + + + drawSelf() { + super.drawSelf(); + this.drawShape(); + } +} + + + +export class ShapeCircle extends MySprite { + + fillColor = '#FF0000'; + radius = 0; + + + setRadius(r) { + this.anchorX = this.anchorY = 0.5; + + this.radius = r; + this.width = r * 2; + this.height = r * 2; + } + + drawShape() { + + this.ctx.beginPath(); + this.ctx.fillStyle = this.fillColor; + this.ctx.arc(0, 0, this.radius, 0, angleToRadian(360)); + this.ctx.fill(); + } + + drawSelf() { + super.drawSelf(); + this.drawShape(); + } +} + +export class ShapeRectNew extends MySprite { + + + radius = 0; + fillColor = '#ffffff'; + strokeColor = '#000000'; + fill = true; + stroke = false; + lineWidth = 1; + + setSize(w, h, r) { + this.width = w; + this.height = h; + this.radius = r; + } + + setOutLine(color, lineWidth) { + this.stroke = true; + this.strokeColor = color; + this.lineWidth = lineWidth; + } + + + drawShape() { + + const ctx = this.ctx; + const width = this.width; + const height = this.height; + const radius = this.radius; + + ctx.save(); + ctx.beginPath(0); + // 从å³ä¸‹è§’顺时针绘制,弧度从0到1/2PI + ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2); + + // 矩形下边线 + ctx.lineTo(radius, height); + + // 左下角圆弧,弧度从1/2PI到PI + ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI); + + // 矩形左边线 + ctx.lineTo(0, radius); + + // 左上角圆弧,弧度从PI到3/2PI + ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2); + + // 上边线 + ctx.lineTo(width - radius, 0); + + // å³ä¸Šè§’圆弧 + ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2); + + // å³è¾¹çº¿ + ctx.lineTo(width, height - radius); + ctx.closePath(); + + if (this.fill) { + ctx.fillStyle = this.fillColor; + ctx.fill(); + } + if (this.stroke) { + ctx.lineWidth = this.lineWidth; + ctx.strokeStyle = this.strokeColor; + ctx.stroke(); + } + ctx.restore(); + + } + + + drawSelf() { + super.drawSelf(); + this.drawShape(); + } + +} +export class MyAnimation extends MySprite { + + + frameArr = []; + frameIndex = 0; + playFlag = false; + lastDateTime; + curDelay = 0; + + + loop = false; + playEndFunc; + delayPerUnit = 1; + + restartFlag = false; + reverseFlag = false; + + addFrameByImg(img) { + + const spr = new MySprite(this.ctx); + spr.init(img); + this._refreshSize(img); + + spr.visible = false; + + this.addChild(spr); + this.frameArr.push(spr); + + this.frameArr[this.frameIndex].visible = true; + } + + addFrameByUrl(url) { + + const spr = new MySprite(this.ctx); + spr.load(url).then(img => { + + this._refreshSize(img); + }); + spr.visible = false; + + this.addChild(spr); + this.frameArr.push(spr); + + this.frameArr[this.frameIndex].visible = true; + } + + _refreshSize(img: any) { + + if (this.width < img.width) { + this.width = img.width; + } + if (this.height < img.height) { + this.height = img.height; + } + } + + + + play() { + this.playFlag = true; + this.lastDateTime = new Date().getTime(); + } + + stop() { + this.playFlag = false; + } + + + replay() { + this.restartFlag = true; + this.play(); + } + + + reverse() { + this.reverseFlag = !this.reverseFlag; + this.frameArr.reverse(); + this.frameIndex = 0; + } + + showAllFrame() { + for (const frame of this.frameArr ) { + frame.alpha = 1; + } + } + + hideAllFrame() { + for (const frame of this.frameArr) { + frame.alpha = 0; + } + } + + + playEnd() { + + this.playFlag = false; + this.curDelay = 0; + + this.frameArr[this.frameIndex].visible = true; + + if (this.playEndFunc) { + this.playEndFunc(); + this.playEndFunc = null; + } + } + + updateFrame() { + if (this.frameArr[this.frameIndex]) { + this.frameArr[this.frameIndex].visible = false; + } + + this.frameIndex ++; + if (this.frameIndex >= this.frameArr.length) { + if (this.loop) { + this.frameIndex = 0; + } else if (this.restartFlag) { + this.restartFlag = false; + this.frameIndex = 0; + } else { + this.frameIndex -- ; + this.playEnd(); + return; + } + } + + this.frameArr[this.frameIndex].visible = true; + + } + + + + + _updateDelay(delay) { + + this.curDelay += delay; + if (this.curDelay < this.delayPerUnit) { + return; + } + this.curDelay -= this.delayPerUnit; + this.updateFrame(); + } + + _updateLastDate() { + if (!this.playFlag) { return; } + + let delay = 0; + if (this.lastDateTime) { + delay = (new Date().getTime() - this.lastDateTime) / 1000; + } + this.lastDateTime = new Date().getTime(); + this._updateDelay(delay); + } + + update($event: any = null) { + super.update($event); + this._updateLastDate(); + } + + +} + + + + +// --------=========== util func =============------------- + + +export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) { + + const tween = new TWEEN.Tween(item).to(obj, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + if (update) { + tween.onUpdate( (a, b) => { + update(a, b); + }); + } + + tween.start(); + return tween; +} + + + + +export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null) { + + const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + + +export function scaleItem(item, scale, time = 0.8, callBack = null, easing = null) { + + const tween = new TWEEN.Tween(item).to({ scaleX: scale, scaleY: scale}, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + + tween.start(); + return tween; +} + + +export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null) { + + const tween = new TWEEN.Tween(item).to({ x, y}, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + + tween.start(); + + return tween; +} + + + + + + + +export function endShow(item, s = 1) { + + item.scaleX = item.scaleY = 0; + item.alpha = 0; + + const tween = new TWEEN.Tween(item) + .to({ alpha: 1, scaleX: s, scaleY: s }, 800) + .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + + }) + .start(); +} + +export function hideItem(item, time = 0.8, callBack = null, easing = null) { + + if (item.alpha === 0) { + return; + } + + const tween = new TWEEN.Tween(item) + .to({alpha: 0}, time * 1000) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }); + + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + +export function showItem(item, time = 0.8, callBack = null, easing = null) { + + if (item.alpha === 1) { + if (callBack) { + callBack(); + } + return; + } + + item.visible = true; + const tween = new TWEEN.Tween(item) + .to({alpha: 1}, time * 1000) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }); + + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + +export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = null) { + + + const tween = new TWEEN.Tween(item) + .to({alpha}, time * 1000) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }); + + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + +export function showStar(item, time = 0.8, callBack = null, easing = null) { + + + const tween = new TWEEN.Tween(item) + .to({alpha: 1, scale: 1}, time * 1000) + // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. + .onComplete(() => { + if (callBack) { + callBack(); + } + }); + + if (easing) { + tween.easing(easing); + } + + tween.start(); +} + + +export function randomSortByArr(arr) { + const newArr = []; + const tmpArr = arr.concat(); + while (tmpArr.length > 0) { + const randomIndex = Math.floor( tmpArr.length * Math.random() ); + newArr.push(tmpArr[randomIndex]); + tmpArr.splice(randomIndex, 1); + } + return newArr; +} + + +export function radianToAngle(radian) { + return radian * 180 / Math.PI; + // 角度 = 弧度 * 180 / Math.PI; +} + +export function angleToRadian(angle) { + return angle * Math.PI / 180; + // 弧度= 角度 * Math.PI / 180; +} + +export function getPosByAngle(angle, len) { + + const radian = angle * Math.PI / 180; + const x = Math.sin(radian) * len; + const y = Math.cos(radian) * len; + + return {x, y}; + +} + +export function getAngleByPos(px, py, mx, my) { + + const x = Math.abs(px - mx); + const y = Math.abs(py - my); + + const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + const cos = y / z; + const radina = Math.acos(cos); // 用å三角函数求弧度 + let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // å°†å¼§åº¦è½¬æ¢æˆè§’度 + + if (mx > px && my > py) {// é¼ æ ‡åœ¨ç¬¬å››è±¡é™ + angle = 180 - angle; + } + if (mx === px && my > py) {// é¼ æ ‡åœ¨yè½´è´Ÿæ–¹å‘上 + angle = 180; + } + if (mx > px && my === py) {// é¼ æ ‡åœ¨xè½´æ£æ–¹å‘上 + angle = 90; + } + if (mx < px && my > py) {// é¼ æ ‡åœ¨ç¬¬ä¸‰è±¡é™ + angle = 180 + angle; + } + if (mx < px && my === py) {// é¼ æ ‡åœ¨xè½´è´Ÿæ–¹å‘ + angle = 270; + } + if (mx < px && my < py) {// é¼ æ ‡åœ¨ç¬¬äºŒè±¡é™ + angle = 360 - angle; + } + + // console.log('angle: ', angle); + return angle; + +} + + +export function removeItemFromArr(arr, item) { + const index = arr.indexOf(item); + if (index !== -1) { + arr.splice(index, 1); + } +} + + + + + + +export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null) { + + const r = getPosDistance(item.x, item.y, x0, y0); + let a = getAngleByPos(item.x, item.y, x0, y0); + a += 90; + const obj = {r, a}; + + item._circleAngle = a; + const targetA = a + addR; + + const tween = new TWEEN.Tween(item).to({_circleAngle: targetA}, time * 1000); + + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); + } + + tween.onUpdate( (item, progress) => { + + // console.log(item._circleAngle); + const r = obj.r; + const a = item._circleAngle; + + const x = x0 + r * xPer * Math.cos(a * Math.PI / 180); + const y = y0 + r * yPer * Math.sin(a * Math.PI / 180); + + item.x = x; + item.y = y; + + // obj.a ++; + }); + + tween.start(); +} + + +export function getPosDistance(sx, sy, ex, ey) { + + const _x = ex - sx; + const _y = ey - sy; + const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) ); + return len; +} + +export function delayCall(callback, second) { + const tween = new TWEEN.Tween(this) + .delay(second * 1000) + .onComplete(() => { + if (callback) { + callback(); + } + }) + .start(); +} + + +export function formatTime(fmt, date) { + + // "yyyy-MM-dd HH:mm:ss"; + + const o = { + 'M+': date.getMonth() + 1, // 月份 + 'd+': date.getDate(), // æ—¥ + 'h+': date.getHours(), // å°æ—¶ + 'm+': date.getMinutes(), // 分 + 's+': date.getSeconds(), // ç§’ + 'q+': Math.floor((date.getMonth() + 3) / 3), // å£åº¦ + S: date.getMilliseconds() // 毫秒 + }; + if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); } + for (const k in o) { + if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) + ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))); + } + } + return fmt; +} + +export function getMinScale(item, maxLen) { + const sx = maxLen / item.width; + const sy = maxLen / item.height; + const minS = Math.min(sx, sy); + return minS; +} + + + +export function jelly(item, time = 0.7) { + + + if (item.jellyTween) { + TWEEN.remove(item.jellyTween); + } + + const t = time / 9; + const baseSX = item.scaleX; + const baseSY = item.scaleY; + let index = 0; + + const run = () => { + if (index >= arr.length) { + item.jellyTween = null; + return; + } + const data = arr[index]; + const t = tweenChange(item, {scaleX: data[0], scaleY: data[1]}, data[2], () => { + index ++; + run(); + }, TWEEN.Easing.Sinusoidal.InOut); + item.jellyTween = t; + }; + + const arr = [ + [baseSX * 1.1, baseSY * 0.9, t], + [baseSX * 0.98, baseSY * 1.02, t * 2], + [baseSX * 1.02, baseSY * 0.98, t * 2], + [baseSX * 0.99, baseSY * 1.01, t * 2], + [baseSX * 1.0, baseSY * 1.0, t * 2], + ]; + + + run(); +} + + + +export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) { + + + for (let i = 0; i < num; i ++) { + + const particle = new MySprite(); + particle.init(img); + particle.x = pos.x; + particle.y = pos.y; + parent.addChild(particle); + + const randomR = 360 * Math.random(); + particle.rotation = randomR; + + const randomS = 0.3 + Math.random() * 0.7; + particle.setScaleXY(randomS * 0.3); + + const randomX = Math.random() * 20 - 10; + particle.x += randomX; + + const randomY = Math.random() * 20 - 10; + particle.y += randomY; + + const randomL = minLen + Math.random() * (maxLen - minLen); + const randomA = 360 * Math.random(); + const randomT = getPosByAngle(randomA, randomL); + moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, showTime, () => { + + + + }, TWEEN.Easing.Exponential.Out); + + // scaleItem(particle, 0, 0.6, () => { + // + // }); + + scaleItem(particle, randomS, 0.6, () => { + + }, TWEEN.Easing.Exponential.Out); + + setTimeout(() => { + + hideItem(particle, 0.4, () => { + + }, TWEEN.Easing.Cubic.In); + + }, showTime * 0.5 * 1000); + + + } +} + + + +export function shake(item, time = 0.5, callback = null, rate = 1) { + + if (item.shakeTween) { + return; + } + + item.shakeTween = true; + const offX = 15 * item.scaleX * rate; + const offY = 15 * item.scaleX * rate; + const baseX = item.x; + const baseY = item.y; + const easing = TWEEN.Easing.Sinusoidal.InOut; + + + const move4 = () => { + moveItem(item, baseX, baseY, time / 4, () => { + item.shakeTween = false; + if (callback) { + callback(); + } + }, easing); + }; + + const move3 = () => { + moveItem(item, baseX + offX / 4, baseY + offY / 4, time / 4, () => { + move4(); + }, easing); + }; + + const move2 = () => { + moveItem(item, baseX - offX / 4 * 3, baseY - offY / 4 * 3, time / 4, () => { + move3(); + }, easing); + }; + + const move1 = () => { + moveItem(item, baseX + offX, baseY + offY, time / 7.5, () => { + move2(); + }, easing); + }; + + move1(); + +} + +// --------------- custom class -------------------- + diff --git a/form/src/app/play/play.component.css b/form/src/app/play/play.component.css new file mode 100644 index 0000000000000000000000000000000000000000..bbda49566c0a6aa2c621e2f863caf1849e492572 --- /dev/null +++ b/form/src/app/play/play.component.css @@ -0,0 +1,19 @@ +.game-container { + width: 100%; + height: 100%; + background: #ffffff; + background-size: cover; +} + +#canvas { + +} + + + +@font-face +{ + font-family: 'BRLNSDB'; + src: url("../../assets/font/BRLNSDB.TTF") ; +} + diff --git a/form/src/app/play/play.component.html b/form/src/app/play/play.component.html new file mode 100644 index 0000000000000000000000000000000000000000..960fb495a359c3c7803c4370d8c7d8457517d70e --- /dev/null +++ b/form/src/app/play/play.component.html @@ -0,0 +1,3 @@ +<div class="game-container" #wrap> + <canvas id="canvas" #canvas></canvas> +</div> diff --git a/form/src/app/play/play.component.ts b/form/src/app/play/play.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4b8a863d45aa9f51852483802422d4dfacce939 --- /dev/null +++ b/form/src/app/play/play.component.ts @@ -0,0 +1,679 @@ +import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core'; + +import { + Label, + MySprite, tweenChange, + +} from './Unit'; +import {res, resAudio} from './resources'; + +import {Subject} from 'rxjs'; +import {debounceTime} from 'rxjs/operators'; + +import TWEEN from '@tweenjs/tween.js'; + + + + +@Component({ + selector: 'app-play', + templateUrl: './play.component.html', + styleUrls: ['./play.component.css'] +}) +export class PlayComponent implements OnInit, OnDestroy { + + @ViewChild('canvas', {static: true }) canvas: ElementRef; + @ViewChild('wrap', {static: true }) wrap: ElementRef; + + // æ•°æ® + data; + + ctx; + + canvasWidth = 1280; // canvas实际宽度 + canvasHeight = 720; // canvas实际高度 + + canvasBaseW = 1280; // canvas 资æºé¢„设宽度 + canvasBaseH = 720; // canvas 资æºé¢„设高度 + + mx; // 点击xåæ ‡ + my; // 点击yåæ ‡ + + + // èµ„æº + rawImages = new Map(res); + rawAudios = new Map(resAudio); + + images = new Map(); + + animationId: any; + winResizeEventStream = new Subject(); + + audioObj = {}; + + renderArr; + mapScale = 1; + + canvasLeft; + canvasTop; + + saveKey = 'test_0011'; + + + btnLeft; + btnRight; + pic1; + pic2; + + canTouch = true; + + curPic; + + @HostListener('window:resize', ['$event']) + onResize(event) { + this.winResizeEventStream.next(); + } + + + ngOnInit() { + + this.data = {}; + + // èŽ·å–æ•°æ® + const getData = (<any> window).courseware.getData; + getData((data) => { + + if (data && typeof data == 'object') { + this.data = data; + } + // console.log('data:' , data); + + // åˆå§‹åŒ– å„äº‹ä»¶ç›‘å¬ + this.initListener(); + + // è‹¥æ— æ•°æ® åˆ™ä¸ºé¢„è§ˆæ¨¡å¼ éœ€è¦å¡«å……一些默认数æ®ç”¨æ¥æ˜¾ç¤º + this.initDefaultData(); + + // åˆå§‹åŒ– éŸ³é¢‘èµ„æº + this.initAudio(); + // åˆå§‹åŒ– å›¾ç‰‡èµ„æº + this.initImg(); + // å¼€å§‹é¢„åŠ è½½èµ„æº + this.load(); + + }, this.saveKey); + + } + + ngOnDestroy() { + window['curCtx'] = null; + window.cancelAnimationFrame(this.animationId); + } + + + load() { + + // é¢„åŠ è½½èµ„æº + this.loadResources().then(() => { + window["air"].hideAirClassLoading(this.saveKey, this.data); + this.init(); + this.update(); + }); + } + + + init() { + + this.initCtx(); + this.initData(); + this.initView(); + } + + initCtx() { + this.canvasWidth = this.wrap.nativeElement.clientWidth; + this.canvasHeight = this.wrap.nativeElement.clientHeight; + this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth; + this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight; + + + this.ctx = this.canvas.nativeElement.getContext('2d'); + this.canvas.nativeElement.width = this.canvasWidth; + this.canvas.nativeElement.height = this.canvasHeight; + + window['curCtx'] = this.ctx; + } + + + + + + + updateItem(item) { + if (item) { + item.update(); + } + } + + updateArr(arr) { + if (!arr) { + return; + } + for (let i = 0; i < arr.length; i++) { + arr[i].update(this); + } + } + + + + + + + + initListener() { + + this.winResizeEventStream + .pipe(debounceTime(500)) + .subscribe(data => { + this.renderAfterResize(); + }); + + + // --------------------------------------------- + const setParentOffset = () => { + const rect = this.canvas.nativeElement.getBoundingClientRect(); + this.canvasLeft = rect.left; + this.canvasTop = rect.top; + }; + const setMxMyByTouch = (event) => { + if (event.touches.length <= 0) { + return; + } + if (this.canvasLeft == null) { + setParentOffset(); + } + this.mx = event.touches[0].pageX - this.canvasLeft; + this.my = event.touches[0].pageY - this.canvasTop; + }; + + const setMxMyByMouse = (event) => { + this.mx = event.offsetX; + this.my = event.offsetY; + }; + // --------------------------------------------- + + + let firstTouch = true; + + const touchDownFunc = (e) => { + if (firstTouch) { + firstTouch = false; + removeMouseListener(); + } + setMxMyByTouch(e); + this.mapDown(e); + }; + const touchMoveFunc = (e) => { + setMxMyByTouch(e); + this.mapMove(e); + }; + const touchUpFunc = (e) => { + setMxMyByTouch(e); + this.mapUp(e); + }; + + const mouseDownFunc = (e) => { + if (firstTouch) { + firstTouch = false; + removeTouchListener(); + } + setMxMyByMouse(e); + this.mapDown(e); + }; + const mouseMoveFunc = (e) => { + setMxMyByMouse(e); + this.mapMove(e); + }; + const mouseUpFunc = (e) => { + setMxMyByMouse(e); + this.mapUp(e); + }; + + + const element = this.canvas.nativeElement; + + const addTouchListener = () => { + element.addEventListener('touchstart', touchDownFunc); + element.addEventListener('touchmove', touchMoveFunc); + element.addEventListener('touchend', touchUpFunc); + element.addEventListener('touchcancel', touchUpFunc); + }; + const removeTouchListener = () => { + element.removeEventListener('touchstart', touchDownFunc); + element.removeEventListener('touchmove', touchMoveFunc); + element.removeEventListener('touchend', touchUpFunc); + element.removeEventListener('touchcancel', touchUpFunc); + }; + + const addMouseListener = () => { + element.addEventListener('mousedown', mouseDownFunc); + element.addEventListener('mousemove', mouseMoveFunc); + element.addEventListener('mouseup', mouseUpFunc); + }; + const removeMouseListener = () => { + element.removeEventListener('mousedown', mouseDownFunc); + element.removeEventListener('mousemove', mouseMoveFunc); + element.removeEventListener('mouseup', mouseUpFunc); + }; + + addMouseListener(); + addTouchListener(); + } + + + playAudio(key, now = false, callback = null) { + + const audio = this.audioObj[key]; + if (audio) { + if (now) { + audio.pause(); + audio.currentTime = 0; + } + + if (callback) { + audio.onended = () => { + callback(); + }; + } + audio.play(); + } + } + + + + loadResources() { + const pr = []; + this.rawImages.forEach((value, key) => {// é¢„åŠ è½½å›¾ç‰‡ + + const p = this.preload(value) + .then(img => { + this.images.set(key, img); + }) + .catch(err => console.log(err)); + + pr.push(p); + }); + + this.rawAudios.forEach((value, key) => {// é¢„åŠ è½½éŸ³é¢‘ + + const a = this.preloadAudio(value) + .then(() => { + // this.images.set(key, img); + }) + .catch(err => console.log(err)); + + pr.push(a); + }); + return Promise.all(pr); + } + + preload(url) { + return new Promise((resolve, reject) => { + const img = new Image(); + // img.crossOrigin = "anonymous"; + img.onload = () => resolve(img); + img.onerror = reject; + img.src = url; + }); + } + + preloadAudio(url) { + return new Promise((resolve, reject) => { + const audio = new Audio(); + audio.oncanplay = (a) => { + resolve(); + }; + audio.onerror = () => { + reject(); + }; + audio.src = url; + audio.load(); + }); + } + + + renderAfterResize() { + this.canvasWidth = this.wrap.nativeElement.clientWidth; + this.canvasHeight = this.wrap.nativeElement.clientHeight; + this.init(); + } + + + + + + checkClickTarget(target) { + + const rect = target.getBoundingBox(); + + if (this.checkPointInRect(this.mx, this.my, rect)) { + return true; + } + return false; + } + + getWorlRect(target) { + + let rect = target.getBoundingBox(); + + if (target.parent) { + + const pRect = this.getWorlRect(target.parent); + rect.x += pRect.x; + rect.y += pRect.y; + } + return rect; + } + + checkPointInRect(x, y, rect) { + if (x >= rect.x && x <= rect.x + rect.width) { + if (y >= rect.y && y <= rect.y + rect.height) { + return true; + } + } + return false; + } + + + + + + addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) { + + const audioObj = this.audioObj; + + if (url == null) { + url = key; + } + + this.rawAudios.set(key, url); + + const audio = new Audio(); + audio.src = url; + audio.load(); + audio.loop = loop; + audio.volume = vlomue; + + audioObj[key] = audio; + + if (callback) { + audio.onended = () => { + callback(); + }; + } + } + + addUrlToImages(url) { + this.rawImages.set(url, url); + } + + + + + + + // ======================================================编写区域========================================================================== + + + + + + /** + * æ·»åŠ é»˜è®¤æ•°æ® ä¾¿äºŽæ— æ•°æ®æ—¶çš„展示 + */ + initDefaultData() { + + if (!this.data.pic_url) { + this.data.pic_url = 'assets/play/default/pic.jpg'; + this.data.pic_url_2 = 'assets/play/default/pic.jpg'; + } + } + + + /** + * æ·»åŠ é¢„åŠ è½½å›¾ç‰‡ + */ + initImg() { + + this.addUrlToImages(this.data.pic_url); + this.addUrlToImages(this.data.pic_url_2); + + } + + /** + * æ·»åŠ é¢„åŠ è½½éŸ³é¢‘ + */ + initAudio() { + + // éŸ³é¢‘èµ„æº + this.addUrlToAudioObj(this.data.audio_url); + this.addUrlToAudioObj(this.data.audio_url_2); + + // 音效 + this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3); + + } + + + + /** + * åˆå§‹åŒ–æ•°æ® + */ + initData() { + + const sx = this.canvasWidth / this.canvasBaseW; + const sy = this.canvasHeight / this.canvasBaseH; + const s = Math.min(sx, sy); + this.mapScale = s; + + // this.mapScale = sx; + // this.mapScale = sy; + + + this.renderArr = []; + + + + } + + + + /** + * åˆå§‹åŒ–试图 + */ + initView() { + + + this.initPic(); + + this.initBottomPart(); + + } + + initBottomPart() { + + const btnLeft = new MySprite(); + btnLeft.init(this.images.get('btn_left')); + btnLeft.x = this.canvasWidth - 150 * this.mapScale; + btnLeft.y = this.canvasHeight - 100 * this.mapScale; + + btnLeft.setScaleXY(this.mapScale); + + this.renderArr.push(btnLeft); + + this.btnLeft = btnLeft; + + + + const btnRight = new MySprite(); + btnRight.init(this.images.get('btn_right')); + btnRight.x = this.canvasWidth - 50 * this.mapScale; + btnRight.y = this.canvasHeight - 100 * this.mapScale; + btnRight.setScaleXY(this.mapScale); + + this.renderArr.push(btnRight); + + this.btnRight = btnRight; + } + + initPic() { + + const maxW = this.canvasWidth * 0.7; + + const pic1 = new MySprite(); + pic1.init(this.images.get(this.data.pic_url)); + pic1.x = this.canvasWidth / 2; + pic1.y = this.canvasHeight / 2; + pic1.setScaleXY(maxW / pic1.width); + + this.renderArr.push(pic1); + this.pic1 = pic1; + + + const label1 = new Label(); + label1.text = this.data.text; + label1.textAlign = 'center'; + label1.fontSize = 50; + label1.fontName = 'BRLNSDB'; + label1.fontColor = '#ffffff'; + + pic1.addChild(label1); + + + + + + const pic2 = new MySprite(); + pic2.init(this.images.get(this.data.pic_url_2)); + pic2.x = this.canvasWidth / 2 + this.canvasWidth; + pic2.y = this.canvasHeight / 2; + pic2.setScaleXY(maxW / pic2.width); + + this.renderArr.push(pic2); + this.pic2 = pic2; + + this.curPic = pic1; + } + + + btnLeftClicked() { + + this.lastPage(); + } + + btnRightClicked() { + + this.nextPage(); + } + + lastPage() { + + if (this.curPic == this.pic1) { + return; + } + + this.canTouch = false; + + const moveLen = this.canvasWidth; + tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1); + tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => { + this.canTouch = true; + this.curPic = this.pic1; + }); + } + + nextPage() { + + if (this.curPic == this.pic2) { + return; + } + + this.canTouch = false; + + const moveLen = this.canvasWidth; + tweenChange(this.pic1, {x: this.pic1.x - moveLen}, 1); + tweenChange(this.pic2, {x: this.pic2.x - moveLen}, 1, () => { + this.canTouch = true; + this.curPic = this.pic2; + }); + } + + pic1Clicked() { + this.playAudio(this.data.audio_url); + } + + pic2Clicked() { + this.playAudio(this.data.audio_url_2); + } + + + + + + mapDown(event) { + + if (!this.canTouch) { + return; + } + + if ( this.checkClickTarget(this.btnLeft) ) { + this.btnLeftClicked(); + return; + } + + if ( this.checkClickTarget(this.btnRight) ) { + this.btnRightClicked(); + return; + } + + if ( this.checkClickTarget(this.pic1) ) { + this.pic1Clicked(); + return; + } + + if ( this.checkClickTarget(this.pic2) ) { + this.pic2Clicked(); + return; + } + + } + + mapMove(event) { + + } + + mapUp(event) { + + } + + + + update() { + + // ---------------------------------------------------------- + this.animationId = window.requestAnimationFrame(this.update.bind(this)); + // 清除画布内容 + this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + // tween 更新动画 + TWEEN.update(); + // ---------------------------------------------------------- + + + + this.updateArr(this.renderArr); + + + } + + + +} diff --git a/form/src/app/play/resources.js b/form/src/app/play/resources.js new file mode 100644 index 0000000000000000000000000000000000000000..d9b584c92bc24d0c04374cb1568478fdbefba9c7 --- /dev/null +++ b/form/src/app/play/resources.js @@ -0,0 +1,18 @@ +const res = [ + + // ['bg', "assets/play/bg.jpg"], + ['btn_left', "assets/play/btn_left.png"], + ['btn_right', "assets/play/btn_right.png"], + // ['text_bg', "assets/play/text_bg.png"], + +]; + + + +const resAudio = [ + + ['click', "assets/play/music/click.mp3"], + +]; + +export {res, resAudio}; diff --git a/form/src/app/style/colors.scss b/form/src/app/style/colors.scss new file mode 100644 index 0000000000000000000000000000000000000000..13a0b006f187cb8e40157579e8f7a66014aec551 --- /dev/null +++ b/form/src/app/style/colors.scss @@ -0,0 +1,16 @@ +$color_black: #111111; +$color_gray: #aaaaaa; +$color_silver: #dddddd; +$color_navy: #001f3f; +$color_blue: #0074d9; +$color_aqua: #7fdbff; +$color_teal: #39cccc; +$color_olive: #3d9970; +$color_green: #2ecc40; +$color_lime: #01ff70; +$color_yellow: #ffdc00; +$color_orange: #ff851b; +$color_red: #ff4136; +$color_maroon: #85144b; +$color_fuchsia: #f012be; +$color_purple: #b10dc9; diff --git a/form/src/app/style/common_mixin.css b/form/src/app/style/common_mixin.css new file mode 100644 index 0000000000000000000000000000000000000000..3e7ed8cfc0608eda7287079af94a1e9fd11d6f68 --- /dev/null +++ b/form/src/app/style/common_mixin.css @@ -0,0 +1,6 @@ +/* +global css to mixin +*/ + + + diff --git a/form/src/assets/.gitkeep b/form/src/assets/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/form/src/assets/common/arrow.png b/form/src/assets/common/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..d69b353b4da29da2a821723bee68d51e9aaeee05 Binary files /dev/null and b/form/src/assets/common/arrow.png differ diff --git a/form/src/assets/common/arrow_right.png b/form/src/assets/common/arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..65859da4bfbcf54c25e481b232ce21f9184c7425 Binary files /dev/null and b/form/src/assets/common/arrow_right.png differ diff --git a/form/src/assets/common/arrow_top.png b/form/src/assets/common/arrow_top.png new file mode 100644 index 0000000000000000000000000000000000000000..d4bcadc92d0400e6d2bdbb4c47fb4b7c55ed77ea Binary files /dev/null and b/form/src/assets/common/arrow_top.png differ diff --git a/form/src/assets/default/video-not-upload.jpg b/form/src/assets/default/video-not-upload.jpg new file mode 100644 index 0000000000000000000000000000000000000000..31fbbcc7703958c0153d883aeded25e2a53e0542 Binary files /dev/null and b/form/src/assets/default/video-not-upload.jpg differ diff --git a/form/src/assets/font/BRLNSB.TTF b/form/src/assets/font/BRLNSB.TTF new file mode 100644 index 0000000000000000000000000000000000000000..509477ede1b11d912a8f5503001a917720522d08 Binary files /dev/null and b/form/src/assets/font/BRLNSB.TTF differ diff --git a/form/src/assets/font/BRLNSDB.TTF b/form/src/assets/font/BRLNSDB.TTF new file mode 100644 index 0000000000000000000000000000000000000000..e5f34b2f342ffcd820a8a0956af3ab36bb1f9e1f Binary files /dev/null and b/form/src/assets/font/BRLNSDB.TTF differ diff --git a/form/src/assets/font/BRLNSR.TTF b/form/src/assets/font/BRLNSR.TTF new file mode 100644 index 0000000000000000000000000000000000000000..efaf22ff70a2b17519804a3f616208e73ff5896a Binary files /dev/null and b/form/src/assets/font/BRLNSR.TTF differ diff --git a/form/src/assets/font/GOTHIC.TTF b/form/src/assets/font/GOTHIC.TTF new file mode 100644 index 0000000000000000000000000000000000000000..c60a324123eaaeab58c400c139bcabbc6d0d2a9f Binary files /dev/null and b/form/src/assets/font/GOTHIC.TTF differ diff --git a/form/src/assets/font/GOTHICB.TTF b/form/src/assets/font/GOTHICB.TTF new file mode 100644 index 0000000000000000000000000000000000000000..d3577b960846dd2a9d2cbaceab7b8715b3c5fd54 Binary files /dev/null and b/form/src/assets/font/GOTHICB.TTF differ diff --git a/form/src/assets/font/GOTHICBI.TTF b/form/src/assets/font/GOTHICBI.TTF new file mode 100644 index 0000000000000000000000000000000000000000..d01cefabe3f5aac0dca611b750d07215cfe00dbf Binary files /dev/null and b/form/src/assets/font/GOTHICBI.TTF differ diff --git a/form/src/assets/font/GOTHICI.TTF b/form/src/assets/font/GOTHICI.TTF new file mode 100644 index 0000000000000000000000000000000000000000..777a6d87f5de328998284ce7c4a0df169a6474a2 Binary files /dev/null and b/form/src/assets/font/GOTHICI.TTF differ diff --git a/form/src/assets/font/MMTextBook-Bold.otf b/form/src/assets/font/MMTextBook-Bold.otf new file mode 100644 index 0000000000000000000000000000000000000000..8e378d817bec7b1acd2a82cfeabcb53c90fd5960 Binary files /dev/null and b/form/src/assets/font/MMTextBook-Bold.otf differ diff --git a/form/src/assets/font/MMTextBook-BoldItalic.otf b/form/src/assets/font/MMTextBook-BoldItalic.otf new file mode 100644 index 0000000000000000000000000000000000000000..04d6fb6e1ca10bec6d4df267184f8179b9ba1468 Binary files /dev/null and b/form/src/assets/font/MMTextBook-BoldItalic.otf differ diff --git a/form/src/assets/font/MMTextBook-Italic.otf b/form/src/assets/font/MMTextBook-Italic.otf new file mode 100644 index 0000000000000000000000000000000000000000..05e5aaa409dc78ee5c98167653a7ed18eab92b49 Binary files /dev/null and b/form/src/assets/font/MMTextBook-Italic.otf differ diff --git a/form/src/assets/font/MMTextBook.otf b/form/src/assets/font/MMTextBook.otf new file mode 100644 index 0000000000000000000000000000000000000000..f8ca9b645c27bcd4bfe1f351f4ff30f4558e302f Binary files /dev/null and b/form/src/assets/font/MMTextBook.otf differ diff --git a/form/src/assets/libs/audio-recorder/lame.min.js b/form/src/assets/libs/audio-recorder/lame.min.js new file mode 100644 index 0000000000000000000000000000000000000000..32bfe8c66168578389d30380ca553d2b2150a47b --- /dev/null +++ b/form/src/assets/libs/audio-recorder/lame.min.js @@ -0,0 +1,308 @@ +function lamejs(){function Y(d){return new Int32Array(d)}function H(d){return new Float32Array(d)}function ra(d){if(1==d.length)return H(d[0]);var k=d[0];d=d.slice(1);for(var q=[],C=0;C<k;C++)q.push(ra(d));return q}function db(d){if(1==d.length)return Y(d[0]);var k=d[0];d=d.slice(1);for(var q=[],C=0;C<k;C++)q.push(db(d));return q}function vc(d){if(1==d.length)return new Int16Array(d[0]);var k=d[0];d=d.slice(1);for(var q=[],C=0;C<k;C++)q.push(vc(d));return q}function Zb(d){if(1==d.length)return Array(d[0]); +var k=d[0];d=d.slice(1);for(var q=[],C=0;C<k;C++)q.push(Zb(d));return q}function sa(d){this.ordinal=d}function M(d){this.ordinal=d}function ka(d){this.ordinal=function(){return d}}function Fc(){this.getLameVersion=function(){return"3.98.4"};this.getLameShortVersion=function(){return"3.98.4"};this.getLameVeryShortVersion=function(){return"LAME3.98r"};this.getPsyVersion=function(){return"0.93"};this.getLameUrl=function(){return"http://www.mp3dev.org/"};this.getLameOsBitness=function(){return"32bits"}} +function Gc(){function d(b,g,a,h,k,e,n,c,f,E,z,w,A,v,p){this.vbr_q=b;this.quant_comp=g;this.quant_comp_s=a;this.expY=h;this.st_lrm=k;this.st_s=e;this.masking_adj=n;this.masking_adj_short=c;this.ath_lower=f;this.ath_curve=E;this.ath_sensitivity=z;this.interch=w;this.safejoint=A;this.sfb21mod=v;this.msfix=p}function k(b,g,a,d,k,e,n,c,f,E,z,w,A,v){this.quant_comp=g;this.quant_comp_s=a;this.safejoint=d;this.nsmsfix=k;this.st_lrm=e;this.st_s=n;this.nsbass=c;this.scale=f;this.masking_adj=E;this.ath_lower= +z;this.ath_curve=w;this.interch=A;this.sfscale=v}function q(b,g,a){var d=b.VBR==M.vbr_rh?t:r,k=b.VBR_q_frac,e=d[g],d=d[g+1];e.st_lrm+=k*(d.st_lrm-e.st_lrm);e.st_s+=k*(d.st_s-e.st_s);e.masking_adj+=k*(d.masking_adj-e.masking_adj);e.masking_adj_short+=k*(d.masking_adj_short-e.masking_adj_short);e.ath_lower+=k*(d.ath_lower-e.ath_lower);e.ath_curve+=k*(d.ath_curve-e.ath_curve);e.ath_sensitivity+=k*(d.ath_sensitivity-e.ath_sensitivity);e.interch+=k*(d.interch-e.interch);e.msfix+=k*(d.msfix-e.msfix);d= +e.vbr_q;0>d&&(d=0);9<d&&(d=9);b.VBR_q=d;b.VBR_q_frac=0;0!=a?b.quant_comp=e.quant_comp:0<Math.abs(b.quant_comp- -1)||(b.quant_comp=e.quant_comp);0!=a?b.quant_comp_short=e.quant_comp_s:0<Math.abs(b.quant_comp_short- -1)||(b.quant_comp_short=e.quant_comp_s);0!=e.expY&&(b.experimentalY=0!=e.expY);0!=a?b.internal_flags.nsPsy.attackthre=e.st_lrm:0<Math.abs(b.internal_flags.nsPsy.attackthre- -1)||(b.internal_flags.nsPsy.attackthre=e.st_lrm);0!=a?b.internal_flags.nsPsy.attackthre_s=e.st_s:0<Math.abs(b.internal_flags.nsPsy.attackthre_s- +-1)||(b.internal_flags.nsPsy.attackthre_s=e.st_s);0!=a?b.maskingadjust=e.masking_adj:0<Math.abs(b.maskingadjust-0)||(b.maskingadjust=e.masking_adj);0!=a?b.maskingadjust_short=e.masking_adj_short:0<Math.abs(b.maskingadjust_short-0)||(b.maskingadjust_short=e.masking_adj_short);0!=a?b.ATHlower=-e.ath_lower/10:0<Math.abs(10*-b.ATHlower-0)||(b.ATHlower=-e.ath_lower/10);0!=a?b.ATHcurve=e.ath_curve:0<Math.abs(b.ATHcurve- -1)||(b.ATHcurve=e.ath_curve);0!=a?b.athaa_sensitivity=e.ath_sensitivity:0<Math.abs(b.athaa_sensitivity- +-1)||(b.athaa_sensitivity=e.ath_sensitivity);0<e.interch&&(0!=a?b.interChRatio=e.interch:0<Math.abs(b.interChRatio- -1)||(b.interChRatio=e.interch));0<e.safejoint&&(b.exp_nspsytune|=e.safejoint);0<e.sfb21mod&&(b.exp_nspsytune|=e.sfb21mod<<20);0!=a?b.msfix=e.msfix:0<Math.abs(b.msfix- -1)||(b.msfix=e.msfix);0==a&&(b.VBR_q=g,b.VBR_q_frac=k)}function C(b,d,a){var h=B.nearestBitrateFullIndex(d);b.VBR=M.vbr_abr;b.VBR_mean_bitrate_kbps=d;b.VBR_mean_bitrate_kbps=Math.min(b.VBR_mean_bitrate_kbps,320);b.VBR_mean_bitrate_kbps= +Math.max(b.VBR_mean_bitrate_kbps,8);b.brate=b.VBR_mean_bitrate_kbps;320<b.VBR_mean_bitrate_kbps&&(b.disable_reservoir=!0);0<g[h].safejoint&&(b.exp_nspsytune|=2);0<g[h].sfscale&&(b.internal_flags.noise_shaping=2);if(0<Math.abs(g[h].nsbass)){var k=int(4*g[h].nsbass);0>k&&(k+=64);b.exp_nspsytune|=k<<2}0!=a?b.quant_comp=g[h].quant_comp:0<Math.abs(b.quant_comp- -1)||(b.quant_comp=g[h].quant_comp);0!=a?b.quant_comp_short=g[h].quant_comp_s:0<Math.abs(b.quant_comp_short- -1)||(b.quant_comp_short=g[h].quant_comp_s); +0!=a?b.msfix=g[h].nsmsfix:0<Math.abs(b.msfix- -1)||(b.msfix=g[h].nsmsfix);0!=a?b.internal_flags.nsPsy.attackthre=g[h].st_lrm:0<Math.abs(b.internal_flags.nsPsy.attackthre- -1)||(b.internal_flags.nsPsy.attackthre=g[h].st_lrm);0!=a?b.internal_flags.nsPsy.attackthre_s=g[h].st_s:0<Math.abs(b.internal_flags.nsPsy.attackthre_s- -1)||(b.internal_flags.nsPsy.attackthre_s=g[h].st_s);0!=a?b.scale=g[h].scale:0<Math.abs(b.scale- -1)||(b.scale=g[h].scale);0!=a?b.maskingadjust=g[h].masking_adj:0<Math.abs(b.maskingadjust- +0)||(b.maskingadjust=g[h].masking_adj);0<g[h].masking_adj?0!=a?b.maskingadjust_short=.9*g[h].masking_adj:0<Math.abs(b.maskingadjust_short-0)||(b.maskingadjust_short=.9*g[h].masking_adj):0!=a?b.maskingadjust_short=1.1*g[h].masking_adj:0<Math.abs(b.maskingadjust_short-0)||(b.maskingadjust_short=1.1*g[h].masking_adj);0!=a?b.ATHlower=-g[h].ath_lower/10:0<Math.abs(10*-b.ATHlower-0)||(b.ATHlower=-g[h].ath_lower/10);0!=a?b.ATHcurve=g[h].ath_curve:0<Math.abs(b.ATHcurve- -1)||(b.ATHcurve=g[h].ath_curve);0!= +a?b.interChRatio=g[h].interch:0<Math.abs(b.interChRatio- -1)||(b.interChRatio=g[h].interch);return d}var B;this.setModules=function(b){B=b};var t=[new d(0,9,9,0,5.2,125,-4.2,-6.3,4.8,1,0,0,2,21,.97),new d(1,9,9,0,5.3,125,-3.6,-5.6,4.5,1.5,0,0,2,21,1.35),new d(2,9,9,0,5.6,125,-2.2,-3.5,2.8,2,0,0,2,21,1.49),new d(3,9,9,1,5.8,130,-1.8,-2.8,2.6,3,-4,0,2,20,1.64),new d(4,9,9,1,6,135,-.7,-1.1,1.1,3.5,-8,0,2,0,1.79),new d(5,9,9,1,6.4,140,.5,.4,-7.5,4,-12,2E-4,0,0,1.95),new d(6,9,9,1,6.6,145,.67,.65,-14.7, +6.5,-19,4E-4,0,0,2.3),new d(7,9,9,1,6.6,145,.8,.75,-19.7,8,-22,6E-4,0,0,2.7),new d(8,9,9,1,6.6,145,1.2,1.15,-27.5,10,-23,7E-4,0,0,0),new d(9,9,9,1,6.6,145,1.6,1.6,-36,11,-25,8E-4,0,0,0),new d(10,9,9,1,6.6,145,2,2,-36,12,-25,8E-4,0,0,0)],r=[new d(0,9,9,0,4.2,25,-7,-4,7.5,1,0,0,2,26,.97),new d(1,9,9,0,4.2,25,-5.6,-3.6,4.5,1.5,0,0,2,21,1.35),new d(2,9,9,0,4.2,25,-4.4,-1.8,2,2,0,0,2,18,1.49),new d(3,9,9,1,4.2,25,-3.4,-1.25,1.1,3,-4,0,2,15,1.64),new d(4,9,9,1,4.2,25,-2.2,.1,0,3.5,-8,0,2,0,1.79),new d(5, +9,9,1,4.2,25,-1,1.65,-7.7,4,-12,2E-4,0,0,1.95),new d(6,9,9,1,4.2,25,-0,2.47,-7.7,6.5,-19,4E-4,0,0,2),new d(7,9,9,1,4.2,25,.5,2,-14.5,8,-22,6E-4,0,0,2),new d(8,9,9,1,4.2,25,1,2.4,-22,10,-23,7E-4,0,0,2),new d(9,9,9,1,4.2,25,1.5,2.95,-30,11,-25,8E-4,0,0,2),new d(10,9,9,1,4.2,25,2,2.95,-36,12,-30,8E-4,0,0,2)],g=[new k(8,9,9,0,0,6.6,145,0,.95,0,-30,11,.0012,1),new k(16,9,9,0,0,6.6,145,0,.95,0,-25,11,.001,1),new k(24,9,9,0,0,6.6,145,0,.95,0,-20,11,.001,1),new k(32,9,9,0,0,6.6,145,0,.95,0,-15,11,.001,1), +new k(40,9,9,0,0,6.6,145,0,.95,0,-10,11,9E-4,1),new k(48,9,9,0,0,6.6,145,0,.95,0,-10,11,9E-4,1),new k(56,9,9,0,0,6.6,145,0,.95,0,-6,11,8E-4,1),new k(64,9,9,0,0,6.6,145,0,.95,0,-2,11,8E-4,1),new k(80,9,9,0,0,6.6,145,0,.95,0,0,8,7E-4,1),new k(96,9,9,0,2.5,6.6,145,0,.95,0,1,5.5,6E-4,1),new k(112,9,9,0,2.25,6.6,145,0,.95,0,2,4.5,5E-4,1),new k(128,9,9,0,1.95,6.4,140,0,.95,0,3,4,2E-4,1),new k(160,9,9,1,1.79,6,135,0,.95,-2,5,3.5,0,1),new k(192,9,9,1,1.49,5.6,125,0,.97,-4,7,3,0,0),new k(224,9,9,1,1.25,5.2, +125,0,.98,-6,9,2,0,0),new k(256,9,9,1,.97,5.2,125,0,1,-8,10,1,0,0),new k(320,9,9,1,.9,5.2,125,0,1,-10,12,0,0,0)];this.apply_preset=function(b,d,a){switch(d){case V.R3MIX:d=V.V3;b.VBR=M.vbr_mtrh;break;case V.MEDIUM:d=V.V4;b.VBR=M.vbr_rh;break;case V.MEDIUM_FAST:d=V.V4;b.VBR=M.vbr_mtrh;break;case V.STANDARD:d=V.V2;b.VBR=M.vbr_rh;break;case V.STANDARD_FAST:d=V.V2;b.VBR=M.vbr_mtrh;break;case V.EXTREME:d=V.V0;b.VBR=M.vbr_rh;break;case V.EXTREME_FAST:d=V.V0;b.VBR=M.vbr_mtrh;break;case V.INSANE:return d= +320,b.preset=d,C(b,d,a),b.VBR=M.vbr_off,d}b.preset=d;switch(d){case V.V9:return q(b,9,a),d;case V.V8:return q(b,8,a),d;case V.V7:return q(b,7,a),d;case V.V6:return q(b,6,a),d;case V.V5:return q(b,5,a),d;case V.V4:return q(b,4,a),d;case V.V3:return q(b,3,a),d;case V.V2:return q(b,2,a),d;case V.V1:return q(b,1,a),d;case V.V0:return q(b,0,a),d}if(8<=d&&320>=d)return C(b,d,a);b.preset=0;return d}}function O(){function d(g,b,l,a,h,k){for(;0!=h--;)l[a]=1E-10+g[b+0]*k[0]-l[a-1]*k[1]+g[b-1]*k[2]-l[a-2]*k[3]+ +g[b-2]*k[4]-l[a-3]*k[5]+g[b-3]*k[6]-l[a-4]*k[7]+g[b-4]*k[8]-l[a-5]*k[9]+g[b-5]*k[10]-l[a-6]*k[11]+g[b-6]*k[12]-l[a-7]*k[13]+g[b-7]*k[14]-l[a-8]*k[15]+g[b-8]*k[16]-l[a-9]*k[17]+g[b-9]*k[18]-l[a-10]*k[19]+g[b-10]*k[20],++a,++b}function k(d,b,l,a,h,k){for(;0!=h--;)l[a]=d[b+0]*k[0]-l[a-1]*k[1]+d[b-1]*k[2]-l[a-2]*k[3]+d[b-2]*k[4],++a,++b}function q(d){return d*d}var C=O.RMS_WINDOW_TIME_NUMERATOR,B=O.RMS_WINDOW_TIME_DENOMINATOR,t=[[.038575994352,-3.84664617118067,-.02160367184185,7.81501653005538,-.00123395316851, +-11.34170355132042,-9.291677959E-5,13.05504219327545,-.01655260341619,-12.28759895145294,.02161526843274,9.4829380631979,-.02074045215285,-5.87257861775999,.00594298065125,2.75465861874613,.00306428023191,-.86984376593551,1.2025322027E-4,.13919314567432,.00288463683916],[.0541865640643,-3.47845948550071,-.02911007808948,6.36317777566148,-.00848709379851,-8.54751527471874,-.00851165645469,9.4769360780128,-.00834990904936,-8.81498681370155,.02245293253339,6.85401540936998,-.02596338512915,-4.39470996079559, +.01624864962975,2.19611684890774,-.00240879051584,-.75104302451432,.00674613682247,.13149317958808,-.00187763777362],[.15457299681924,-2.37898834973084,-.09331049056315,2.84868151156327,-.06247880153653,-2.64577170229825,.02163541888798,2.23697657451713,-.05588393329856,-1.67148153367602,.04781476674921,1.00595954808547,.00222312597743,-.45953458054983,.03174092540049,.16378164858596,-.01390589421898,-.05032077717131,.00651420667831,.0234789740702,-.00881362733839],[.30296907319327,-1.61273165137247, +-.22613988682123,1.0797749225997,-.08587323730772,-.2565625775407,.03282930172664,-.1627671912044,-.00915702933434,-.22638893773906,-.02364141202522,.39120800788284,-.00584456039913,-.22138138954925,.06276101321749,.04500235387352,-8.28086748E-6,.02005851806501,.00205861885564,.00302439095741,-.02950134983287],[.33642304856132,-1.49858979367799,-.2557224142557,.87350271418188,-.11828570177555,.12205022308084,.11921148675203,-.80774944671438,-.07834489609479,.47854794562326,-.0046997791438,-.12453458140019, +-.0058950022444,-.04067510197014,.05724228140351,.08333755284107,.00832043980773,-.04237348025746,-.0163538138454,.02977207319925,-.0176017656815],[.4491525660845,-.62820619233671,-.14351757464547,.29661783706366,-.22784394429749,-.372563729424,-.01419140100551,.00213767857124,.04078262797139,-.42029820170918,-.12398163381748,.22199650564824,.04097565135648,.00613424350682,.10478503600251,.06747620744683,-.01863887810927,.05784820375801,-.03193428438915,.03222754072173,.00541907748707],[.56619470757641, +-1.04800335126349,-.75464456939302,.29156311971249,.1624213774223,-.26806001042947,.16744243493672,.00819999645858,-.18901604199609,.45054734505008,.3093178284183,-.33032403314006,-.27562961986224,.0673936833311,.00647310677246,-.04784254229033,.08647503780351,.01639907836189,-.0378898455484,.01807364323573,-.00588215443421],[.58100494960553,-.51035327095184,-.53174909058578,-.31863563325245,-.14289799034253,-.20256413484477,.17520704835522,.1472815413433,.02377945217615,.38952639978999,.15558449135573, +-.23313271880868,-.25344790059353,-.05246019024463,.01628462406333,-.02505961724053,.06920467763959,.02442357316099,-.03721611395801,.01818801111503,-.00749618797172],[.53648789255105,-.2504987195602,-.42163034350696,-.43193942311114,-.00275953611929,-.03424681017675,.04267842219415,-.04678328784242,-.10214864179676,.26408300200955,.14590772289388,.15113130533216,-.02459864859345,-.17556493366449,-.11202315195388,-.18823009262115,-.04060034127,.05477720428674,.0478866554818,.0470440968812,-.02217936801134]], +r=[[.98621192462708,-1.97223372919527,-1.97242384925416,.97261396931306,.98621192462708],[.98500175787242,-1.96977855582618,-1.97000351574484,.9702284756635,.98500175787242],[.97938932735214,-1.95835380975398,-1.95877865470428,.95920349965459,.97938932735214],[.97531843204928,-1.95002759149878,-1.95063686409857,.95124613669835,.97531843204928],[.97316523498161,-1.94561023566527,-1.94633046996323,.94705070426118,.97316523498161],[.96454515552826,-1.92783286977036,-1.92909031105652,.93034775234268, +.96454515552826],[.96009142950541,-1.91858953033784,-1.92018285901082,.92177618768381,.96009142950541],[.95856916599601,-1.9154210807478,-1.91713833199203,.91885558323625,.95856916599601],[.94597685600279,-1.88903307939452,-1.89195371200558,.89487434461664,.94597685600279]];this.InitGainAnalysis=function(d,b){var l;a:{for(l=0;l<MAX_ORDER;l++)d.linprebuf[l]=d.lstepbuf[l]=d.loutbuf[l]=d.rinprebuf[l]=d.rstepbuf[l]=d.routbuf[l]=0;switch(0|b){case 48E3:d.reqindex=0;break;case 44100:d.reqindex=1;break; +case 32E3:d.reqindex=2;break;case 24E3:d.reqindex=3;break;case 22050:d.reqindex=4;break;case 16E3:d.reqindex=5;break;case 12E3:d.reqindex=6;break;case 11025:d.reqindex=7;break;case 8E3:d.reqindex=8;break;default:l=INIT_GAIN_ANALYSIS_ERROR;break a}d.sampleWindow=0|(b*C+B-1)/B;d.lsum=0;d.rsum=0;d.totsamp=0;Ia.ill(d.A,0);l=INIT_GAIN_ANALYSIS_OK}if(l!=INIT_GAIN_ANALYSIS_OK)return INIT_GAIN_ANALYSIS_ERROR;d.linpre=MAX_ORDER;d.rinpre=MAX_ORDER;d.lstep=MAX_ORDER;d.rstep=MAX_ORDER;d.lout=MAX_ORDER;d.rout= +MAX_ORDER;Ia.fill(d.B,0);return INIT_GAIN_ANALYSIS_OK};this.AnalyzeSamples=function(g,b,l,a,h,D,e){var n,c,f,E,z,w;if(0==D)return GAIN_ANALYSIS_OK;w=0;E=D;switch(e){case 1:a=b;h=l;break;case 2:break;default:return GAIN_ANALYSIS_ERROR}D<MAX_ORDER?(K.arraycopy(b,l,g.linprebuf,MAX_ORDER,D),K.arraycopy(a,h,g.rinprebuf,MAX_ORDER,D)):(K.arraycopy(b,l,g.linprebuf,MAX_ORDER,MAX_ORDER),K.arraycopy(a,h,g.rinprebuf,MAX_ORDER,MAX_ORDER));for(;0<E;){z=E>g.sampleWindow-g.totsamp?g.sampleWindow-g.totsamp:E;w<MAX_ORDER? +(e=g.linpre+w,n=g.linprebuf,c=g.rinpre+w,f=g.rinprebuf,z>MAX_ORDER-w&&(z=MAX_ORDER-w)):(e=l+w,n=b,c=h+w,f=a);d(n,e,g.lstepbuf,g.lstep+g.totsamp,z,t[g.reqindex]);d(f,c,g.rstepbuf,g.rstep+g.totsamp,z,t[g.reqindex]);k(g.lstepbuf,g.lstep+g.totsamp,g.loutbuf,g.lout+g.totsamp,z,r[g.reqindex]);k(g.rstepbuf,g.rstep+g.totsamp,g.routbuf,g.rout+g.totsamp,z,r[g.reqindex]);e=g.lout+g.totsamp;n=g.loutbuf;c=g.rout+g.totsamp;f=g.routbuf;for(var A=z%8;0!=A--;)g.lsum+=q(n[e++]),g.rsum+=q(f[c++]);for(A=z/8;0!=A--;)g.lsum+= +q(n[e+0])+q(n[e+1])+q(n[e+2])+q(n[e+3])+q(n[e+4])+q(n[e+5])+q(n[e+6])+q(n[e+7]),e+=8,g.rsum+=q(f[c+0])+q(f[c+1])+q(f[c+2])+q(f[c+3])+q(f[c+4])+q(f[c+5])+q(f[c+6])+q(f[c+7]),c+=8;E-=z;w+=z;g.totsamp+=z;g.totsamp==g.sampleWindow&&(e=10*O.STEPS_per_dB*Math.log10((g.lsum+g.rsum)/g.totsamp*.5+1E-37),e=0>=e?0:0|e,e>=g.A.length&&(e=g.A.length-1),g.A[e]++,g.lsum=g.rsum=0,K.arraycopy(g.loutbuf,g.totsamp,g.loutbuf,0,MAX_ORDER),K.arraycopy(g.routbuf,g.totsamp,g.routbuf,0,MAX_ORDER),K.arraycopy(g.lstepbuf,g.totsamp, +g.lstepbuf,0,MAX_ORDER),K.arraycopy(g.rstepbuf,g.totsamp,g.rstepbuf,0,MAX_ORDER),g.totsamp=0);if(g.totsamp>g.sampleWindow)return GAIN_ANALYSIS_ERROR}D<MAX_ORDER?(K.arraycopy(g.linprebuf,D,g.linprebuf,0,MAX_ORDER-D),K.arraycopy(g.rinprebuf,D,g.rinprebuf,0,MAX_ORDER-D),K.arraycopy(b,l,g.linprebuf,MAX_ORDER-D,D),K.arraycopy(a,h,g.rinprebuf,MAX_ORDER-D,D)):(K.arraycopy(b,l+D-MAX_ORDER,g.linprebuf,0,MAX_ORDER),K.arraycopy(a,h+D-MAX_ORDER,g.rinprebuf,0,MAX_ORDER));return GAIN_ANALYSIS_OK};this.GetTitleGain= +function(d){var b;b=d.A;var l=d.A.length,a,h=0;for(a=0;a<l;a++)h+=b[a];if(0==h)b=GAIN_NOT_ENOUGH_SAMPLES;else{h=0|Math.ceil(h*(1-.95));for(a=l;0<a--&&!(0>=(h-=b[a])););b=64.82-a/O.STEPS_per_dB}for(l=0;l<d.A.length;l++)d.B[l]+=d.A[l],d.A[l]=0;for(l=0;l<MAX_ORDER;l++)d.linprebuf[l]=d.lstepbuf[l]=d.loutbuf[l]=d.rinprebuf[l]=d.rstepbuf[l]=d.routbuf[l]=0;d.totsamp=0;d.lsum=d.rsum=0;return b}}function tb(){function J(a){this.bits=0|a}function k(a,c,b,d,e,p){c=.5946/c;for(a>>=1;0!=a--;)e[p++]=c>b[d++]?0: +1,e[p++]=c>b[d++]?0:1}function q(a,c,b,d,e,p){a>>=1;var m=a%2;for(a>>=1;0!=a--;){var f,n,g,u,h,l,k;f=b[d++]*c;n=b[d++]*c;h=0|f;g=b[d++]*c;l=0|n;u=b[d++]*c;k=0|g;f+=t.adj43[h];h=0|u;n+=t.adj43[l];e[p++]=0|f;g+=t.adj43[k];e[p++]=0|n;u+=t.adj43[h];e[p++]=0|g;e[p++]=0|u}0!=m&&(f=b[d++]*c,n=b[d++]*c,f+=t.adj43[0|f],n+=t.adj43[0|n],e[p++]=0|f,e[p++]=0|n)}function C(a,c,b,d){var e,p=c,m=e=0;do{var f=a[p++],n=a[p++];e<f&&(e=f);m<n&&(m=n)}while(p<b);e<m&&(e=m);switch(e){case 0:return e;case 1:p=c;c=0;e=r.ht[1].hlen; +do m=2*a[p+0]+a[p+1],p+=2,c+=e[m];while(p<b);d.bits+=c;return 1;case 2:case 3:p=c;c=g[e-1];e=0;m=r.ht[c].xlen;f=2==c?r.table23:r.table56;do n=a[p+0]*m+a[p+1],p+=2,e+=f[n];while(p<b);a=e&65535;e>>=16;e>a&&(e=a,c++);d.bits+=e;return c;case 4:case 5:case 6:case 7:case 8:case 9:case 10:case 11:case 12:case 13:case 14:case 15:p=c;c=g[e-1];var f=m=e=0,n=r.ht[c].xlen,h=r.ht[c].hlen,u=r.ht[c+1].hlen,l=r.ht[c+2].hlen;do{var k=a[p+0]*n+a[p+1],p=p+2;e+=h[k];m+=u[k];f+=l[k]}while(p<b);a=c;e>m&&(e=m,a++);e>f&& +(e=f,a=c+2);d.bits+=e;return a;default:if(e>ma.IXMAX_VAL)return d.bits=ma.LARGE_BITS,-1;e-=15;for(p=24;32>p&&!(r.ht[p].linmax>=e);p++);for(m=p-8;24>m&&!(r.ht[m].linmax>=e);m++);e=m;f=65536*r.ht[e].xlen+r.ht[p].xlen;m=0;do n=a[c++],h=a[c++],0!=n&&(14<n&&(n=15,m+=f),n*=16),0!=h&&(14<h&&(h=15,m+=f),n+=h),m+=r.largetbl[n];while(c<b);a=m&65535;m>>=16;m>a&&(m=a,e=p);d.bits+=m;return e}}function B(a,c,e,b,f,p,m,n){for(var y=c.big_values,g=2;g<d.SBMAX_l+1;g++){var h=a.scalefac_band.l[g];if(h>=y)break;var l= +f[g-2]+c.count1bits;if(e.part2_3_length<=l)break;l=new J(l);h=C(b,h,y,l);l=l.bits;e.part2_3_length<=l||(e.assign(c),e.part2_3_length=l,e.region0_count=p[g-2],e.region1_count=g-2-p[g-2],e.table_select[0]=m[g-2],e.table_select[1]=n[g-2],e.table_select[2]=h)}}var t=null;this.qupvt=null;this.setModules=function(a){t=this.qupvt=a};var ta=[[0,0],[0,0],[0,0],[0,0],[0,0],[0,1],[1,1],[1,1],[1,2],[2,2],[2,3],[2,3],[3,4],[3,4],[3,4],[4,5],[4,5],[4,6],[5,6],[5,6],[5,7],[6,7],[6,7]],g=[1,2,5,7,7,10,10,13,13,13, +13,13,13,13,13];this.noquant_count_bits=function(a,c,e){var b=c.l3_enc,f=Math.min(576,c.max_nonzero_coeff+2>>1<<1);null!=e&&(e.sfb_count1=0);for(;1<f&&0==(b[f-1]|b[f-2]);f-=2);c.count1=f;for(var p=0,m=0;3<f;f-=4){var n;if(1<((b[f-1]|b[f-2]|b[f-3]|b[f-4])&2147483647))break;n=2*(2*(2*b[f-4]+b[f-3])+b[f-2])+b[f-1];p+=r.t32l[n];m+=r.t33l[n]}n=p;c.count1table_select=0;p>m&&(n=m,c.count1table_select=1);c.count1bits=n;c.big_values=f;if(0==f)return n;c.block_type==d.SHORT_TYPE?(p=3*a.scalefac_band.s[3],p> +c.big_values&&(p=c.big_values),m=c.big_values):c.block_type==d.NORM_TYPE?(p=c.region0_count=a.bv_scf[f-2],m=c.region1_count=a.bv_scf[f-1],m=a.scalefac_band.l[p+m+2],p=a.scalefac_band.l[p+1],m<f&&(n=new J(n),c.table_select[2]=C(b,m,f,n),n=n.bits)):(c.region0_count=7,c.region1_count=d.SBMAX_l-1-7-1,p=a.scalefac_band.l[8],m=f,p>m&&(p=m));p=Math.min(p,f);m=Math.min(m,f);0<p&&(n=new J(n),c.table_select[0]=C(b,0,p,n),n=n.bits);p<m&&(n=new J(n),c.table_select[1]=C(b,p,m,n),n=n.bits);2==a.use_best_huffman&& +(c.part2_3_length=n,best_huffman_divide(a,c),n=c.part2_3_length);if(null!=e&&c.block_type==d.NORM_TYPE){for(b=0;a.scalefac_band.l[b]<c.big_values;)b++;e.sfb_count1=b}return n};this.count_bits=function(a,c,e,b){var f=e.l3_enc,n=ma.IXMAX_VAL/t.IPOW20(e.global_gain);if(e.xrpow_max>n)return ma.LARGE_BITS;var n=t.IPOW20(e.global_gain),m,g,y=0,h,u=0,l=0,la=0,F=0,G=f,I=0,T=c,U=0;h=null!=b&&e.global_gain==b.global_gain;g=e.block_type==d.SHORT_TYPE?38:21;for(m=0;m<=g;m++){var D=-1;if(h||e.block_type==d.NORM_TYPE)D= +e.global_gain-(e.scalefac[m]+(0!=e.preflag?t.pretab[m]:0)<<e.scalefac_scale+1)-8*e.subblock_gain[e.window[m]];if(h&&b.step[m]==D)0!=u&&(q(u,n,T,U,G,I),u=0),0!=l&&(k(l,n,T,U,G,I),l=0);else{var ia=e.width[m];y+e.width[m]>e.max_nonzero_coeff&&(m=e.max_nonzero_coeff-y+1,Ia.fill(f,e.max_nonzero_coeff,576,0),ia=m,0>ia&&(ia=0),m=g+1);0==u&&0==l&&(G=f,I=F,T=c,U=la);null!=b&&0<b.sfb_count1&&m>=b.sfb_count1&&0<b.step[m]&&D>=b.step[m]?(0!=u&&(q(u,n,T,U,G,I),u=0,G=f,I=F,T=c,U=la),l+=ia):(0!=l&&(k(l,n,T,U,G,I), +l=0,G=f,I=F,T=c,U=la),u+=ia);if(0>=ia){0!=l&&(k(l,n,T,U,G,I),l=0);0!=u&&(q(u,n,T,U,G,I),u=0);break}}m<=g&&(F+=e.width[m],la+=e.width[m],y+=e.width[m])}0!=u&&q(u,n,T,U,G,I);0!=l&&k(l,n,T,U,G,I);if(0!=(a.substep_shaping&2))for(n=0,g=.634521682242439/t.IPOW20(e.global_gain+e.scalefac_scale),y=0;y<e.sfbmax;y++)if(h=e.width[y],0==a.pseudohalf[y])n+=h;else for(u=n,n+=h;u<n;++u)f[u]=c[u]>=g?f[u]:0;return this.noquant_count_bits(a,e,b)};this.best_huffman_divide=function(a,c){var e=new Ab,b=c.l3_enc,f=Y(23), +n=Y(23),m=Y(23),g=Y(23);if(c.block_type!=d.SHORT_TYPE||1!=a.mode_gr){e.assign(c);if(c.block_type==d.NORM_TYPE){for(var y=c.big_values,h=0;22>=h;h++)f[h]=ma.LARGE_BITS;for(h=0;16>h;h++){var l=a.scalefac_band.l[h+1];if(l>=y)break;for(var k=0,q=new J(k),F=C(b,0,l,q),k=q.bits,G=0;8>G;G++){var I=a.scalefac_band.l[h+G+2];if(I>=y)break;q=k;q=new J(q);I=C(b,l,I,q);q=q.bits;f[h+G]>q&&(f[h+G]=q,n[h+G]=h,m[h+G]=F,g[h+G]=I)}}B(a,e,c,b,f,n,m,g)}y=e.big_values;if(!(0==y||1<(b[y-2]|b[y-1])||(y=c.count1+2,576<y))){e.assign(c); +e.count1=y;for(l=h=0;y>e.big_values;y-=4)k=2*(2*(2*b[y-4]+b[y-3])+b[y-2])+b[y-1],h+=r.t32l[k],l+=r.t33l[k];e.big_values=y;e.count1table_select=0;h>l&&(h=l,e.count1table_select=1);e.count1bits=h;e.block_type==d.NORM_TYPE?B(a,e,c,b,f,n,m,g):(e.part2_3_length=h,h=a.scalefac_band.l[8],h>y&&(h=y),0<h&&(f=new J(e.part2_3_length),e.table_select[0]=C(b,0,h,f),e.part2_3_length=f.bits),y>h&&(f=new J(e.part2_3_length),e.table_select[1]=C(b,h,y,f),e.part2_3_length=f.bits),c.part2_3_length>e.part2_3_length&&c.assign(e))}}}; +var b=[1,1,1,1,8,2,2,2,4,4,4,8,8,8,16,16],l=[1,2,4,8,1,2,4,8,2,4,8,2,4,8,4,8],a=[0,0,0,0,3,1,1,1,2,2,2,3,3,3,4,4],h=[0,1,2,3,0,1,2,3,1,2,3,1,2,3,2,3];tb.slen1_tab=a;tb.slen2_tab=h;this.best_scalefac_store=function(c,e,f,n){var g=n.tt[e][f],p,m,x,y=0;for(p=m=0;p<g.sfbmax;p++){x=g.width[p];m+=x;for(x=-x;0>x&&0==g.l3_enc[x+m];x++);0==x&&(g.scalefac[p]=y=-2)}if(0==g.scalefac_scale&&0==g.preflag){for(p=m=0;p<g.sfbmax;p++)0<g.scalefac[p]&&(m|=g.scalefac[p]);if(0==(m&1)&&0!=m){for(p=0;p<g.sfbmax;p++)0<g.scalefac[p]&& +(g.scalefac[p]>>=1);g.scalefac_scale=y=1}}if(0==g.preflag&&g.block_type!=d.SHORT_TYPE&&2==c.mode_gr){for(p=11;p<d.SBPSY_l&&!(g.scalefac[p]<t.pretab[p]&&-2!=g.scalefac[p]);p++);if(p==d.SBPSY_l){for(p=11;p<d.SBPSY_l;p++)0<g.scalefac[p]&&(g.scalefac[p]-=t.pretab[p]);g.preflag=y=1}}for(p=0;4>p;p++)n.scfsi[f][p]=0;if(2==c.mode_gr&&1==e&&n.tt[0][f].block_type!=d.SHORT_TYPE&&n.tt[1][f].block_type!=d.SHORT_TYPE){e=n.tt[1][f];m=n.tt[0][f];for(y=0;y<r.scfsi_band.length-1;y++){for(p=r.scfsi_band[y];p<r.scfsi_band[y+ +1]&&!(m.scalefac[p]!=e.scalefac[p]&&0<=e.scalefac[p]);p++);if(p==r.scfsi_band[y+1]){for(p=r.scfsi_band[y];p<r.scfsi_band[y+1];p++)e.scalefac[p]=-1;n.scfsi[f][y]=1}}for(p=n=f=0;11>p;p++)-1!=e.scalefac[p]&&(n++,f<e.scalefac[p]&&(f=e.scalefac[p]));for(x=m=0;p<d.SBPSY_l;p++)-1!=e.scalefac[p]&&(x++,m<e.scalefac[p]&&(m=e.scalefac[p]));for(y=0;16>y;y++)f<b[y]&&m<l[y]&&(p=a[y]*n+h[y]*x,e.part2_length>p&&(e.part2_length=p,e.scalefac_compress=y));y=0}for(p=0;p<g.sfbmax;p++)-2==g.scalefac[p]&&(g.scalefac[p]= +0);0!=y&&(2==c.mode_gr?this.scale_bitcount(g):this.scale_bitcount_lsf(c,g))};var D=[0,18,36,54,54,36,54,72,54,72,90,72,90,108,108,126],e=[0,18,36,54,51,35,53,71,52,70,88,69,87,105,104,122],n=[0,10,20,30,33,21,31,41,32,42,52,43,53,63,64,74];this.scale_bitcount=function(a){var c,f=0,g=0,h,p=a.scalefac;if(a.block_type==d.SHORT_TYPE)h=D,0!=a.mixed_block_flag&&(h=e);else if(h=n,0==a.preflag){for(c=11;c<d.SBPSY_l&&!(p[c]<t.pretab[c]);c++);if(c==d.SBPSY_l)for(a.preflag=1,c=11;c<d.SBPSY_l;c++)p[c]-=t.pretab[c]}for(c= +0;c<a.sfbdivide;c++)f<p[c]&&(f=p[c]);for(;c<a.sfbmax;c++)g<p[c]&&(g=p[c]);a.part2_length=ma.LARGE_BITS;for(c=0;16>c;c++)f<b[c]&&g<l[c]&&a.part2_length>h[c]&&(a.part2_length=h[c],a.scalefac_compress=c);return a.part2_length==ma.LARGE_BITS};var c=[[15,15,7,7],[15,15,7,0],[7,3,0,0],[15,31,31,0],[7,7,7,0],[3,3,0,0]];this.scale_bitcount_lsf=function(a,e){var b,n,g,p,m,h,y,l=Y(4),u=e.scalefac;b=0!=e.preflag?2:0;for(h=0;4>h;h++)l[h]=0;if(e.block_type==d.SHORT_TYPE){n=1;var k=t.nr_of_sfb_block[b][n];for(g= +y=0;4>g;g++)for(p=k[g]/3,h=0;h<p;h++,y++)for(m=0;3>m;m++)u[3*y+m]>l[g]&&(l[g]=u[3*y+m])}else for(n=0,k=t.nr_of_sfb_block[b][n],g=y=0;4>g;g++)for(p=k[g],h=0;h<p;h++,y++)u[y]>l[g]&&(l[g]=u[y]);p=!1;for(g=0;4>g;g++)l[g]>c[b][g]&&(p=!0);if(!p){e.sfb_partition_table=t.nr_of_sfb_block[b][n];for(g=0;4>g;g++)e.slen[g]=f[l[g]];n=e.slen[0];g=e.slen[1];l=e.slen[2];m=e.slen[3];switch(b){case 0:e.scalefac_compress=(5*n+g<<4)+(l<<2)+m;break;case 1:e.scalefac_compress=400+(5*n+g<<2)+l;break;case 2:e.scalefac_compress= +500+3*n+g;break;default:K.err.printf("intensity stereo not implemented yet\n")}}if(!p)for(g=e.part2_length=0;4>g;g++)e.part2_length+=e.slen[g]*e.sfb_partition_table[g];return p};var f=[0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4];this.huffman_init=function(a){for(var c=2;576>=c;c+=2){for(var e=0,b;a.scalefac_band.l[++e]<c;);for(b=ta[e][0];a.scalefac_band.l[b+1]>c;)b--;0>b&&(b=ta[e][0]);a.bv_scf[c-2]=b;for(b=ta[e][1];a.scalefac_band.l[b+a.bv_scf[c-2]+2]>c;)b--;0>b&&(b=ta[e][1]);a.bv_scf[c-1]=b}}}function Hc(){var d; +this.setModules=function(k){d=k};this.ResvFrameBegin=function(k,q){var C=k.internal_flags,B,t=C.l3_side,r=d.getframebits(k);q.bits=(r-8*C.sideinfo_len)/C.mode_gr;var g=2048*C.mode_gr-8;320<k.brate?B=8*int(1E3*k.brate/(k.out_samplerate/1152)/8+.5):(B=11520,k.strict_ISO&&(B=8*int(32E4/(k.out_samplerate/1152)/8+.5)));C.ResvMax=B-r;C.ResvMax>g&&(C.ResvMax=g);if(0>C.ResvMax||k.disable_reservoir)C.ResvMax=0;r=q.bits*C.mode_gr+Math.min(C.ResvSize,C.ResvMax);r>B&&(r=B);t.resvDrain_pre=0;null!=C.pinfo&&(C.pinfo.mean_bits= +q.bits/2,C.pinfo.resvsize=C.ResvSize);return r};this.ResvMaxBits=function(d,q,J,B){var t=d.internal_flags,r=t.ResvSize,g=t.ResvMax;0!=B&&(r+=q);0!=(t.substep_shaping&1)&&(g*=.9);J.bits=q;10*r>9*g?(B=r-9*g/10,J.bits+=B,t.substep_shaping|=128):(B=0,t.substep_shaping&=127,d.disable_reservoir||0!=(t.substep_shaping&1)||(J.bits-=.1*q));d=r<6*t.ResvMax/10?r:6*t.ResvMax/10;d-=B;0>d&&(d=0);return d};this.ResvAdjust=function(d,q){d.ResvSize-=q.part2_3_length+q.part2_length};this.ResvFrameEnd=function(d,q){var J, +B=d.l3_side;d.ResvSize+=q*d.mode_gr;var t=0;B.resvDrain_post=0;B.resvDrain_pre=0;0!=(J=d.ResvSize%8)&&(t+=J);J=d.ResvSize-t-d.ResvMax;0<J&&(t+=J);J=Math.min(8*B.main_data_begin,t)/8;B.resvDrain_pre+=8*J;t-=8*J;d.ResvSize-=8*J;B.main_data_begin-=J;B.resvDrain_post+=t;d.ResvSize-=t}}function ua(){function J(a,e,b){for(;0<b;){var d;0==z&&(z=8,E++,a.header[a.w_ptr].write_timing==f&&(d=a,K.arraycopy(d.header[d.w_ptr].buf,0,c,E,d.sideinfo_len),E+=d.sideinfo_len,f+=8*d.sideinfo_len,d.w_ptr=d.w_ptr+1&da.MAX_HEADER_BUF- +1),c[E]=0);d=Math.min(b,z);b-=d;z-=d;c[E]|=e>>b<<z;f+=d}}function k(a,c){var b=a.internal_flags,d;8<=c&&(J(b,76,8),c-=8);8<=c&&(J(b,65,8),c-=8);8<=c&&(J(b,77,8),c-=8);8<=c&&(J(b,69,8),c-=8);if(32<=c){var m=e.getLameShortVersion();if(32<=c)for(d=0;d<m.length&&8<=c;++d)c-=8,J(b,m.charAt(d),8)}for(;1<=c;--c)J(b,b.ancillary_flag,1),b.ancillary_flag^=a.disable_reservoir?0:1}function q(a,c,e){for(var b=a.header[a.h_ptr].ptr;0<e;){var m=Math.min(e,8-(b&7));e-=m;a.header[a.h_ptr].buf[b>>3]|=c>>e<<8-(b&7)- +m;b+=m}a.header[a.h_ptr].ptr=b}function C(a,c){a<<=8;for(var e=0;8>e;e++)a<<=1,c<<=1,0!=((c^a)&65536)&&(c^=32773);return c}function B(a,c){var e=r.ht[c.count1table_select+32],b,m=0,d=c.big_values,f=c.big_values;for(b=(c.count1-c.big_values)/4;0<b;--b){var n=0,g=0,h;h=c.l3_enc[d+0];0!=h&&(g+=8,0>c.xr[f+0]&&n++);h=c.l3_enc[d+1];0!=h&&(g+=4,n*=2,0>c.xr[f+1]&&n++);h=c.l3_enc[d+2];0!=h&&(g+=2,n*=2,0>c.xr[f+2]&&n++);h=c.l3_enc[d+3];0!=h&&(g++,n*=2,0>c.xr[f+3]&&n++);d+=4;f+=4;J(a,n+e.table[g],e.hlen[g]); +m+=e.hlen[g]}return m}function t(c,a,e,b,m){var d=r.ht[a],f=0;if(0==a)return f;for(;e<b;e+=2){var n=0,g=0,h=d.xlen,l=d.xlen,k=0,G=m.l3_enc[e],I=m.l3_enc[e+1];0!=G&&(0>m.xr[e]&&k++,n--);15<a&&(14<G&&(k|=G-15<<1,g=h,G=15),14<I&&(l=I-15,k<<=h,k|=l,g+=h,I=15),l=16);0!=I&&(k<<=1,0>m.xr[e+1]&&k++,n--);G=G*l+I;g-=n;n+=d.hlen[G];J(c,d.table[G],n);J(c,k,g);f+=n+g}return f}function H(c,a){var e=3*c.scalefac_band.s[3];e>a.big_values&&(e=a.big_values);var b=t(c,a.table_select[0],0,e,a);return b+=t(c,a.table_select[1], +e,a.big_values,a)}function g(c,a){var e,b,m,d;e=a.big_values;b=a.region0_count+1;m=c.scalefac_band.l[b];b+=a.region1_count+1;d=c.scalefac_band.l[b];m>e&&(m=e);d>e&&(d=e);b=t(c,a.table_select[0],0,m,a);b+=t(c,a.table_select[1],m,d,a);return b+=t(c,a.table_select[2],d,e,a)}function b(){this.total=0}function l(c,e){var b=c.internal_flags,d,m,n,g;g=b.w_ptr;n=b.h_ptr-1;-1==n&&(n=da.MAX_HEADER_BUF-1);d=b.header[n].write_timing-f;e.total=d;0<=d&&(m=1+n-g,n<g&&(m=1+n-g+da.MAX_HEADER_BUF),d-=8*m*b.sideinfo_len); +b=a.getframebits(c);d+=b;e.total+=b;e.total=0!=e.total%8?1+e.total/8:e.total/8;e.total+=E+1;0>d&&K.err.println("strange error flushing buffer ... \n");return d}var a=this,h=null,D=null,e=null,n=null;this.setModules=function(a,c,b,d){h=a;D=c;e=b;n=d};var c=null,f=0,E=0,z=0;this.getframebits=function(a){var c=a.internal_flags;return 8*(0|72E3*(a.version+1)*(0!=c.bitrate_index?r.bitrate_table[a.version][c.bitrate_index]:a.brate)/a.out_samplerate+c.padding)};this.CRC_writeheader=function(a,c){var e;e= +C(c[2]&255,65535);e=C(c[3]&255,e);for(var b=6;b<a.sideinfo_len;b++)e=C(c[b]&255,e);c[4]=byte(e>>8);c[5]=byte(e&255)};this.flush_bitstream=function(c){var a=c.internal_flags,e,d;e=a.l3_side;0>(d=l(c,new b))||(k(c,d),a.ResvSize=0,e.main_data_begin=0,a.findReplayGain&&(e=h.GetTitleGain(a.rgdata),a.RadioGain=Math.floor(10*e+.5)|0),a.findPeakSample&&(a.noclipGainChange=Math.ceil(200*Math.log10(a.PeakSample/32767))|0,0<a.noclipGainChange?EQ(c.scale,1)||EQ(c.scale,0)?a.noclipScale=Math.floor(32767/a.PeakSample* +100)/100:a.noclipScale=-1:a.noclipScale=-1))};this.add_dummy_byte=function(a,e,b){a=a.internal_flags;for(var d;0<b--;){d=e;for(var m=8;0<m;){var n;0==z&&(z=8,E++,c[E]=0);n=Math.min(m,z);m-=n;z-=n;c[E]|=d>>m<<z;f+=n}for(d=0;d<da.MAX_HEADER_BUF;++d)a.header[d].write_timing+=8}};this.format_bitstream=function(a){var c=a.internal_flags,e;e=c.l3_side;var n=this.getframebits(a);k(a,e.resvDrain_pre);var m=a.internal_flags,h,y,E;h=m.l3_side;m.header[m.h_ptr].ptr=0;Ia.fill(m.header[m.h_ptr].buf,0,m.sideinfo_len, +0);16E3>a.out_samplerate?q(m,4094,12):q(m,4095,12);q(m,a.version,1);q(m,1,2);q(m,a.error_protection?0:1,1);q(m,m.bitrate_index,4);q(m,m.samplerate_index,2);q(m,m.padding,1);q(m,a.extension,1);q(m,a.mode.ordinal(),2);q(m,m.mode_ext,2);q(m,a.copyright,1);q(m,a.original,1);q(m,a.emphasis,2);a.error_protection&&q(m,0,16);if(1==a.version){q(m,h.main_data_begin,9);2==m.channels_out?q(m,h.private_bits,3):q(m,h.private_bits,5);for(E=0;E<m.channels_out;E++)for(y=0;4>y;y++)q(m,h.scfsi[E][y],1);for(y=0;2>y;y++)for(E= +0;E<m.channels_out;E++){var u=h.tt[y][E];q(m,u.part2_3_length+u.part2_length,12);q(m,u.big_values/2,9);q(m,u.global_gain,8);q(m,u.scalefac_compress,4);u.block_type!=d.NORM_TYPE?(q(m,1,1),q(m,u.block_type,2),q(m,u.mixed_block_flag,1),14==u.table_select[0]&&(u.table_select[0]=16),q(m,u.table_select[0],5),14==u.table_select[1]&&(u.table_select[1]=16),q(m,u.table_select[1],5),q(m,u.subblock_gain[0],3),q(m,u.subblock_gain[1],3),q(m,u.subblock_gain[2],3)):(q(m,0,1),14==u.table_select[0]&&(u.table_select[0]= +16),q(m,u.table_select[0],5),14==u.table_select[1]&&(u.table_select[1]=16),q(m,u.table_select[1],5),14==u.table_select[2]&&(u.table_select[2]=16),q(m,u.table_select[2],5),q(m,u.region0_count,4),q(m,u.region1_count,3));q(m,u.preflag,1);q(m,u.scalefac_scale,1);q(m,u.count1table_select,1)}}else for(q(m,h.main_data_begin,8),q(m,h.private_bits,m.channels_out),E=y=0;E<m.channels_out;E++)u=h.tt[y][E],q(m,u.part2_3_length+u.part2_length,12),q(m,u.big_values/2,9),q(m,u.global_gain,8),q(m,u.scalefac_compress, +9),u.block_type!=d.NORM_TYPE?(q(m,1,1),q(m,u.block_type,2),q(m,u.mixed_block_flag,1),14==u.table_select[0]&&(u.table_select[0]=16),q(m,u.table_select[0],5),14==u.table_select[1]&&(u.table_select[1]=16),q(m,u.table_select[1],5),q(m,u.subblock_gain[0],3),q(m,u.subblock_gain[1],3),q(m,u.subblock_gain[2],3)):(q(m,0,1),14==u.table_select[0]&&(u.table_select[0]=16),q(m,u.table_select[0],5),14==u.table_select[1]&&(u.table_select[1]=16),q(m,u.table_select[1],5),14==u.table_select[2]&&(u.table_select[2]=16), +q(m,u.table_select[2],5),q(m,u.region0_count,4),q(m,u.region1_count,3)),q(m,u.scalefac_scale,1),q(m,u.count1table_select,1);a.error_protection&&CRC_writeheader(m,m.header[m.h_ptr].buf);h=m.h_ptr;m.h_ptr=h+1&da.MAX_HEADER_BUF-1;m.header[m.h_ptr].write_timing=m.header[h].write_timing+n;m.h_ptr==m.w_ptr&&K.err.println("Error: MAX_HEADER_BUF too small in bitstream.c \n");var m=8*c.sideinfo_len,z=0,t=a.internal_flags,F=t.l3_side;if(1==a.version)for(h=0;2>h;h++)for(E=0;E<t.channels_out;E++){var G=F.tt[h][E], +I=tb.slen1_tab[G.scalefac_compress],T=tb.slen2_tab[G.scalefac_compress];for(y=u=0;y<G.sfbdivide;y++)-1!=G.scalefac[y]&&(J(t,G.scalefac[y],I),u+=I);for(;y<G.sfbmax;y++)-1!=G.scalefac[y]&&(J(t,G.scalefac[y],T),u+=T);u=G.block_type==d.SHORT_TYPE?u+H(t,G):u+g(t,G);u+=B(t,G);z+=u}else for(E=h=0;E<t.channels_out;E++){var G=F.tt[h][E],U=0,T=y=u=0;if(G.block_type==d.SHORT_TYPE){for(;4>T;T++)for(var D=G.sfb_partition_table[T]/3,ia=G.slen[T],I=0;I<D;I++,y++)J(t,Math.max(G.scalefac[3*y+0],0),ia),J(t,Math.max(G.scalefac[3* +y+1],0),ia),J(t,Math.max(G.scalefac[3*y+2],0),ia),U+=3*ia;u+=H(t,G)}else{for(;4>T;T++)for(D=G.sfb_partition_table[T],ia=G.slen[T],I=0;I<D;I++,y++)J(t,Math.max(G.scalefac[y],0),ia),U+=ia;u+=g(t,G)}u+=B(t,G);z+=U+u}m+=z;k(a,e.resvDrain_post);m+=e.resvDrain_post;e.main_data_begin+=(n-m)/8;l(a,new b)!=c.ResvSize&&K.err.println("Internal buffer inconsistency. flushbits <> ResvSize");8*e.main_data_begin!=c.ResvSize&&(K.err.printf("bit reservoir error: \nl3_side.main_data_begin: %d \nResvoir size: %d \nresv drain (post) %d \nresv drain (pre) %d \nheader and sideinfo: %d \ndata bits: %d \ntotal bits: %d (remainder: %d) \nbitsperframe: %d \n", +8*e.main_data_begin,c.ResvSize,e.resvDrain_post,e.resvDrain_pre,8*c.sideinfo_len,m-e.resvDrain_post-8*c.sideinfo_len,m,m%8,n),K.err.println("This is a fatal error. It has several possible causes:"),K.err.println("90%% LAME compiled with buggy version of gcc using advanced optimizations"),K.err.println(" 9%% Your system is overclocked"),K.err.println(" 1%% bug in LAME encoding library"),c.ResvSize=8*e.main_data_begin);if(1E9<f){for(a=0;a<da.MAX_HEADER_BUF;++a)c.header[a].write_timing-=f;f=0}return 0}; +this.copy_buffer=function(a,e,b,d,m){var f=E+1;if(0>=f)return 0;if(0!=d&&f>d)return-1;K.arraycopy(c,0,e,b,f);E=-1;z=0;if(0!=m&&(d=Y(1),d[0]=a.nMusicCRC,n.updateMusicCRC(d,e,b,f),a.nMusicCRC=d[0],0<f&&(a.VBR_seek_table.nBytesWritten+=f),a.decode_on_the_fly)){d=ra([2,1152]);m=f;for(var g=-1,l;0!=g;)if(g=D.hip_decode1_unclipped(a.hip,e,b,m,d[0],d[1]),m=0,-1==g&&(g=0),0<g){if(a.findPeakSample){for(l=0;l<g;l++)d[0][l]>a.PeakSample?a.PeakSample=d[0][l]:-d[0][l]>a.PeakSample&&(a.PeakSample=-d[0][l]);if(1< +a.channels_out)for(l=0;l<g;l++)d[1][l]>a.PeakSample?a.PeakSample=d[1][l]:-d[1][l]>a.PeakSample&&(a.PeakSample=-d[1][l])}if(a.findReplayGain&&h.AnalyzeSamples(a.rgdata,d[0],0,d[1],0,g,a.channels_out)==O.GAIN_ANALYSIS_ERROR)return-6}}return f};this.init_bit_stream_w=function(a){c=new Int8Array(V.LAME_MAXMP3BUFFER);a.h_ptr=a.w_ptr=0;a.header[a.h_ptr].write_timing=0;E=-1;f=z=0}}function ub(){function d(a,b){var c=a[b+0]&255,c=c<<8|a[b+1]&255,c=c<<8,c=c|a[b+2]&255,c=c<<8;return c|=a[b+3]&255}function k(a, +b,c){a[b+0]=c>>24&255;a[b+1]=c>>16&255;a[b+2]=c>>8&255;a[b+3]=c&255}function q(a,b,c){a[b+0]=c>>8&255;a[b+1]=c&255}function C(a,b,c){return 255&(a<<b|c&~(-1<<b))}function B(a,b){var c=a.internal_flags;b[0]=C(b[0],8,255);b[1]=C(b[1],3,7);b[1]=C(b[1],1,16E3>a.out_samplerate?0:1);b[1]=C(b[1],1,a.version);b[1]=C(b[1],2,1);b[1]=C(b[1],1,a.error_protection?0:1);b[2]=C(b[2],4,c.bitrate_index);b[2]=C(b[2],2,c.samplerate_index);b[2]=C(b[2],1,0);b[2]=C(b[2],1,a.extension);b[3]=C(b[3],2,a.mode.ordinal());b[3]= +C(b[3],2,c.mode_ext);b[3]=C(b[3],1,a.copyright);b[3]=C(b[3],1,a.original);b[3]=C(b[3],2,a.emphasis);b[0]=255;var c=b[1]&241,d;d=1==a.version?128:16E3>a.out_samplerate?32:64;a.VBR==M.vbr_off&&(d=a.brate);d=a.free_format?0:255&16*H.BitrateIndex(d,a.version,a.out_samplerate);b[1]=1==a.version?255&(c|10):255&(c|2);c=b[2]&13;b[2]=255&(d|c)}function t(a,b){return b=b>>8^D[(b^a)&255]}var H,g,b;this.setModules=function(a,d,c){H=a;g=d;b=c};var l=ub.NUMTOCENTRIES,a=ub.MAXFRAMESIZE,h=l+4+4+4+4+4+9+1+1+8+1+1+ +3+1+1+2+4+2+2,D=[0,49345,49537,320,49921,960,640,49729,50689,1728,1920,51009,1280,50625,50305,1088,52225,3264,3456,52545,3840,53185,52865,3648,2560,51905,52097,2880,51457,2496,2176,51265,55297,6336,6528,55617,6912,56257,55937,6720,7680,57025,57217,8E3,56577,7616,7296,56385,5120,54465,54657,5440,55041,6080,5760,54849,53761,4800,4992,54081,4352,53697,53377,4160,61441,12480,12672,61761,13056,62401,62081,12864,13824,63169,63361,14144,62721,13760,13440,62529,15360,64705,64897,15680,65281,16320,16E3,65089, +64001,15040,15232,64321,14592,63937,63617,14400,10240,59585,59777,10560,60161,11200,10880,59969,60929,11968,12160,61249,11520,60865,60545,11328,58369,9408,9600,58689,9984,59329,59009,9792,8704,58049,58241,9024,57601,8640,8320,57409,40961,24768,24960,41281,25344,41921,41601,25152,26112,42689,42881,26432,42241,26048,25728,42049,27648,44225,44417,27968,44801,28608,28288,44609,43521,27328,27520,43841,26880,43457,43137,26688,30720,47297,47489,31040,47873,31680,31360,47681,48641,32448,32640,48961,32E3, +48577,48257,31808,46081,29888,30080,46401,30464,47041,46721,30272,29184,45761,45953,29504,45313,29120,28800,45121,20480,37057,37249,20800,37633,21440,21120,37441,38401,22208,22400,38721,21760,38337,38017,21568,39937,23744,23936,40257,24320,40897,40577,24128,23040,39617,39809,23360,39169,22976,22656,38977,34817,18624,18816,35137,19200,35777,35457,19008,19968,36545,36737,20288,36097,19904,19584,35905,17408,33985,34177,17728,34561,18368,18048,34369,33281,17088,17280,33601,16640,33217,32897,16448];this.addVbrFrame= +function(a){var b=a.internal_flags;var c=b.VBR_seek_table;a=r.bitrate_table[a.version][b.bitrate_index];c.nVbrNumFrames++;c.sum+=a;c.seen++;if(!(c.seen<c.want)&&(c.pos<c.size&&(c.bag[c.pos]=c.sum,c.pos++,c.seen=0),c.pos==c.size)){for(a=1;a<c.size;a+=2)c.bag[a/2]=c.bag[a];c.want*=2;c.pos/=2}};this.getVbrTag=function(a){var b=new VBRTagData,c=0;b.flags=0;var f=a[c+1]>>3&1,g=a[c+2]>>2&3,h=a[c+3]>>6&3,k=a[c+2]>>4&15,k=r.bitrate_table[f][k];b.samprate=14==a[c+1]>>4?r.samplerate_table[2][g]:r.samplerate_table[f][g]; +g=c=0!=f?3!=h?c+36:c+21:3!=h?c+21:c+13;if(!(new String(a,g,4(),null)).equals("Xing")&&!(new String(a,g,4(),null)).equals("Info"))return null;c+=4;b.hId=f;g=b.flags=d(a,c);c+=4;0!=(g&1)&&(b.frames=d(a,c),c+=4);0!=(g&2)&&(b.bytes=d(a,c),c+=4);if(0!=(g&4)){if(null!=b.toc)for(h=0;h<l;h++)b.toc[h]=a[c+h];c+=l}b.vbrScale=-1;0!=(g&8)&&(b.vbrScale=d(a,c),c+=4);b.headersize=72E3*(f+1)*k/b.samprate;c+=21;f=a[c+0]<<4;f+=a[c+1]>>4;k=(a[c+1]&15)<<8;k+=a[c+2]&255;if(0>f||3E3<f)f=-1;if(0>k||3E3<k)k=-1;b.encDelay= +f;b.encPadding=k;return b};this.InitVbrTag=function(b){var d=b.internal_flags,c;c=1==b.version?128:16E3>b.out_samplerate?32:64;b.VBR==M.vbr_off&&(c=b.brate);c=72E3*(b.version+1)*c/b.out_samplerate;var f=d.sideinfo_len+h;d.VBR_seek_table.TotalFrameSize=c;if(c<f||c>a)b.bWriteVbrTag=!1;else for(d.VBR_seek_table.nVbrNumFrames=0,d.VBR_seek_table.nBytesWritten=0,d.VBR_seek_table.sum=0,d.VBR_seek_table.seen=0,d.VBR_seek_table.want=1,d.VBR_seek_table.pos=0,null==d.VBR_seek_table.bag&&(d.VBR_seek_table.bag= +new int[400],d.VBR_seek_table.size=400),c=new Int8Array(a),B(b,c),d=d.VBR_seek_table.TotalFrameSize,f=0;f<d;++f)g.add_dummy_byte(b,c[f]&255,1)};this.updateMusicCRC=function(a,b,c,d){for(var g=0;g<d;++g)a[0]=t(b[c+g],a[0])};this.getLameTagFrame=function(a,d){var c=a.internal_flags;if(!a.bWriteVbrTag||c.Class_ID!=V.LAME_ID||0>=c.VBR_seek_table.pos)return 0;if(d.length<c.VBR_seek_table.TotalFrameSize)return c.VBR_seek_table.TotalFrameSize;Ia.fill(d,0,c.VBR_seek_table.TotalFrameSize,0);B(a,d);var f=new Int8Array(l); +if(a.free_format)for(var h=1;h<l;++h)f[h]=255&255*h/100;else{var z=c.VBR_seek_table;if(!(0>=z.pos))for(h=1;h<l;++h){var w=0|Math.floor(h/l*z.pos);w>z.pos-1&&(w=z.pos-1);w=0|256*z.bag[w]/z.sum;255<w&&(w=255);f[h]=255&w}}w=c.sideinfo_len;a.error_protection&&(w-=2);d[w++]=0;d[w++]=0;d[w++]=0;d[w++]=0;k(d,w,15);w+=4;k(d,w,c.VBR_seek_table.nVbrNumFrames);w+=4;z=c.VBR_seek_table.nBytesWritten+c.VBR_seek_table.TotalFrameSize;k(d,w,0|z);w+=4;K.arraycopy(f,0,d,w,f.length);w+=f.length;a.error_protection&&g.CRC_writeheader(c, +d);for(var A=0,h=0;h<w;h++)A=t(d[h],A);var f=w,h=A,v=a.internal_flags,w=0,A=a.encoder_delay,p=a.encoder_padding,m=100-10*a.VBR_q-a.quality,x=b.getLameVeryShortVersion(),y;y=[1,5,3,2,4,0,3];var W=0|(255<a.lowpassfreq/100+.5?255:a.lowpassfreq/100+.5),u=0,D=0,J=a.internal_flags.noise_shaping,F=0,G=0,I=0,T=0,F=0,F=0!=(a.exp_nspsytune&1),I=0!=(a.exp_nspsytune&2),U=!1,qa=!1,ia=a.internal_flags.nogap_total,ya=a.internal_flags.nogap_current,T=a.ATHtype,r=0,C;switch(a.VBR){case vbr_abr:C=a.VBR_mean_bitrate_kbps; +break;case vbr_off:C=a.brate;break;default:C=a.VBR_min_bitrate_kbps}y=0+(a.VBR.ordinal()<y.length?y[a.VBR.ordinal()]:0);v.findReplayGain&&(510<v.RadioGain&&(v.RadioGain=510),-510>v.RadioGain&&(v.RadioGain=-510),D=11264,D=0<=v.RadioGain?D|v.RadioGain:D|512|-v.RadioGain);v.findPeakSample&&(u=Math.abs(0|v.PeakSample/32767*Math.pow(2,23)+.5));-1!=ia&&(0<ya&&(qa=!0),ya<ia-1&&(U=!0));r=T+((F?1:0)<<4)+((I?1:0)<<5)+((U?1:0)<<6)+((qa?1:0)<<7);0>m&&(m=0);switch(a.mode){case MONO:F=0;break;case STEREO:F=1;break; +case DUAL_CHANNEL:F=2;break;case JOINT_STEREO:F=a.force_ms?4:3;break;default:F=7}I=32E3>=a.in_samplerate?0:48E3==a.in_samplerate?2:48E3<a.in_samplerate?3:1;if(a.short_blocks==sa.short_block_forced||a.short_blocks==sa.short_block_dispensed||-1==a.lowpassfreq&&-1==a.highpassfreq||a.scale_left<a.scale_right||a.scale_left>a.scale_right||a.disable_reservoir&&320>a.brate||a.noATH||a.ATHonly||0==T||32E3>=a.in_samplerate)G=1;T=J+(F<<2)+(G<<5)+(I<<6);F=v.nMusicCRC;k(d,f+w,m);w+=4;for(v=0;9>v;v++)d[f+w+v]= +255&x.charAt(v);w+=9;d[f+w]=255&y;w++;d[f+w]=255&W;w++;k(d,f+w,u);w+=4;q(d,f+w,D);w+=2;q(d,f+w,0);w+=2;d[f+w]=255&r;w++;d[f+w]=255<=C?255:255&C;w++;d[f+w]=255&A>>4;d[f+w+1]=255&(A<<4)+(p>>8);d[f+w+2]=255&p;w+=3;d[f+w]=255&T;w++;d[f+w++]=0;q(d,f+w,a.preset);w+=2;k(d,f+w,z);w+=4;q(d,f+w,F);w+=2;for(z=0;z<w;z++)h=t(d[f+z],h);q(d,f+w,h);return c.VBR_seek_table.TotalFrameSize};this.putVbrTag=function(b,d){if(0>=b.internal_flags.VBR_seek_table.pos)return-1;d.seek(d.length());if(0==d.length())return-1;d.seek(0); +var c=new Int8Array(10);d.readFully(c);c=(new String(c,"ISO-8859-1")).startsWith("ID3")?0:((c[6]&127)<<21|(c[7]&127)<<14|(c[8]&127)<<7|c[9]&127)+c.length;d.seek(c);var c=new Int8Array(a),f=getLameTagFrame(b,c);if(f>c.length)return-1;if(1>f)return 0;d.write(c,0,f);return 0}}function Q(d,k,q,r){this.xlen=d;this.linmax=k;this.table=q;this.hlen=r}function eb(d){this.bits=d}function Ic(){this.setModules=function(d,k){}}function $b(){this.bits=this.over_SSD=this.over_count=this.max_noise=this.tot_noise= +this.over_noise=0}function Jc(){this.scale_right=this.scale_left=this.scale=this.out_samplerate=this.in_samplerate=this.num_channels=this.num_samples=this.class_id=0;this.decode_only=this.bWriteVbrTag=this.analysis=!1;this.quality=0;this.mode=ka.STEREO;this.write_id3tag_automatic=this.decode_on_the_fly=this.findReplayGain=this.free_format=this.force_ms=!1;this.error_protection=this.emphasis=this.extension=this.original=this.copyright=this.compression_ratio=this.brate=0;this.disable_reservoir=this.strict_ISO= +!1;this.quant_comp_short=this.quant_comp=0;this.experimentalY=!1;this.preset=this.exp_nspsytune=this.experimentalZ=0;this.VBR=null;this.maskingadjust_short=this.maskingadjust=this.highpasswidth=this.lowpasswidth=this.highpassfreq=this.lowpassfreq=this.VBR_hard_min=this.VBR_max_bitrate_kbps=this.VBR_min_bitrate_kbps=this.VBR_mean_bitrate_kbps=this.VBR_q=this.VBR_q_frac=0;this.noATH=this.ATHshort=this.ATHonly=!1;this.athaa_sensitivity=this.athaa_loudapprox=this.athaa_type=this.ATHlower=this.ATHcurve= +this.ATHtype=0;this.short_blocks=null;this.useTemporal=!1;this.msfix=this.interChRatio=0;this.tune=!1;this.lame_allocated_gfp=this.frameNum=this.framesize=this.encoder_padding=this.encoder_delay=this.version=this.tune_value_a=0;this.internal_flags=null}function Kc(){this.linprebuf=H(2*O.MAX_ORDER);this.linpre=0;this.lstepbuf=H(O.MAX_SAMPLES_PER_WINDOW+O.MAX_ORDER);this.lstep=0;this.loutbuf=H(O.MAX_SAMPLES_PER_WINDOW+O.MAX_ORDER);this.lout=0;this.rinprebuf=H(2*O.MAX_ORDER);this.rinpre=0;this.rstepbuf= +H(O.MAX_SAMPLES_PER_WINDOW+O.MAX_ORDER);this.rstep=0;this.routbuf=H(O.MAX_SAMPLES_PER_WINDOW+O.MAX_ORDER);this.first=this.freqindex=this.rsum=this.lsum=this.totsamp=this.sampleWindow=this.rout=0;this.A=Y(0|O.STEPS_per_dB*O.MAX_dB);this.B=Y(0|O.STEPS_per_dB*O.MAX_dB)}function Lc(){this.floor=this.decay=this.adjustLimit=this.adjust=this.aaSensitivityP=this.useAdjust=0;this.l=H(d.SBMAX_l);this.s=H(d.SBMAX_s);this.psfb21=H(d.PSFB21);this.psfb12=H(d.PSFB12);this.cb_l=H(d.CBANDS);this.cb_s=H(d.CBANDS); +this.eql_w=H(d.BLKSIZE/2)}function Mc(J){this.quantize=J;this.iteration_loop=function(k,q,J,B){var t=k.internal_flags,r=H(na.SFBMAX),g=H(576),b=Y(2),l,a,h=t.l3_side;l=new eb(0);this.quantize.rv.ResvFrameBegin(k,l);l=l.bits;for(var D=0;D<t.mode_gr;D++)for(a=this.quantize.qupvt.on_pe(k,q,b,l,D,D),t.mode_ext==d.MPG_MD_MS_LR&&(this.quantize.ms_convert(t.l3_side,D),this.quantize.qupvt.reduce_side(b,J[D],l,a)),a=0;a<t.channels_out;a++){var e,n=h.tt[D][a];n.block_type!=d.SHORT_TYPE?(e=0,e=t.PSY.mask_adjust- +e):(e=0,e=t.PSY.mask_adjust_short-e);t.masking_lower=Math.pow(10,.1*e);this.quantize.init_outer_loop(t,n);this.quantize.init_xrpow(t,n,g)&&(this.quantize.qupvt.calc_xmin(k,B[D][a],n,r),this.quantize.outer_loop(k,n,r,g,a,b[a]));this.quantize.iteration_finish_one(t,D,a)}this.quantize.rv.ResvFrameEnd(t,l)}}function ha(J,k,q,r){this.l=Y(1+d.SBMAX_l);this.s=Y(1+d.SBMAX_s);this.psfb21=Y(1+d.PSFB21);this.psfb12=Y(1+d.PSFB12);var B=this.l,t=this.s;4==arguments.length&&(this.arrL=arguments[0],this.arrS=arguments[1], +this.arr21=arguments[2],this.arr12=arguments[3],K.arraycopy(this.arrL,0,B,0,Math.min(this.arrL.length,this.l.length)),K.arraycopy(this.arrS,0,t,0,Math.min(this.arrS.length,this.s.length)),K.arraycopy(this.arr21,0,this.psfb21,0,Math.min(this.arr21.length,this.psfb21.length)),K.arraycopy(this.arr12,0,this.psfb12,0,Math.min(this.arr12.length,this.psfb12.length)))}function ma(){function J(a,b){var c=B.ATHformula(b,a);return c=Math.pow(10,(c-100)/10+a.ATHlower)}function k(a){this.s=a}var q=null,r=null, +B=null;this.setModules=function(a,b,c){q=a;r=b;B=c};this.IPOW20=function(b){return a[b]};var t=ma.IXMAX_VAL+2,ta=ma.Q_MAX,g=ma.Q_MAX2;this.nr_of_sfb_block=[[[6,5,5,5],[9,9,9,9],[6,9,9,9]],[[6,5,7,3],[9,9,12,6],[6,9,12,6]],[[11,10,0,0],[18,18,0,0],[15,18,0,0]],[[7,7,7,0],[12,12,12,0],[6,15,12,0]],[[6,6,6,3],[12,9,9,6],[6,12,9,6]],[[8,8,5,0],[15,12,9,0],[6,18,9,0]]];var b=[0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0];this.pretab=b;this.sfBandIndex=[new ha([0,6,12,18,24,30,36,44,54,66,80,96,116,140, +168,200,238,284,336,396,464,522,576],[0,4,8,12,18,24,32,42,56,74,100,132,174,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]),new ha([0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,332,394,464,540,576],[0,4,8,12,18,26,36,48,62,80,104,136,180,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]),new ha([0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576],[0,4,8,12,18,26,36,48,62,80,104,134,174,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]),new ha([0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162, +196,238,288,342,418,576],[0,4,8,12,16,22,30,40,52,66,84,106,136,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]),new ha([0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576],[0,4,8,12,16,22,28,38,50,64,80,100,126,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]),new ha([0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576],[0,4,8,12,16,22,30,42,58,78,104,138,180,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]),new ha([0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464, +522,576],[0,4,8,12,18,26,36,48,62,80,104,134,174,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]),new ha([0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576],[0,4,8,12,18,26,36,48,62,80,104,134,174,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]),new ha([0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576],[0,8,16,24,36,52,72,96,124,160,162,164,166,192],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0])];var l=H(ta+g+1),a=H(ta),h=H(t),D=H(t);this.adj43=D;this.iteration_init=function(b){var n= +b.internal_flags,c=n.l3_side;if(0==n.iteration_init_init){n.iteration_init_init=1;c.main_data_begin=0;for(var c=b.internal_flags.ATH.l,f=b.internal_flags.ATH.psfb21,k=b.internal_flags.ATH.s,z=b.internal_flags.ATH.psfb12,w=b.internal_flags,A=b.out_samplerate,v=0;v<d.SBMAX_l;v++){var p=w.scalefac_band.l[v],m=w.scalefac_band.l[v+1];for(c[v]=vb.MAX_VALUE;p<m;p++){var x=p*A/1152,x=J(b,x);c[v]=Math.min(c[v],x)}}for(v=0;v<d.PSFB21;v++)for(p=w.scalefac_band.psfb21[v],m=w.scalefac_band.psfb21[v+1],f[v]=vb.MAX_VALUE;p< +m;p++)x=p*A/1152,x=J(b,x),f[v]=Math.min(f[v],x);for(v=0;v<d.SBMAX_s;v++){p=w.scalefac_band.s[v];m=w.scalefac_band.s[v+1];for(k[v]=vb.MAX_VALUE;p<m;p++)x=p*A/384,x=J(b,x),k[v]=Math.min(k[v],x);k[v]*=w.scalefac_band.s[v+1]-w.scalefac_band.s[v]}for(v=0;v<d.PSFB12;v++){p=w.scalefac_band.psfb12[v];m=w.scalefac_band.psfb12[v+1];for(z[v]=vb.MAX_VALUE;p<m;p++)x=p*A/384,x=J(b,x),z[v]=Math.min(z[v],x);z[v]*=w.scalefac_band.s[13]-w.scalefac_band.s[12]}if(b.noATH){for(v=0;v<d.SBMAX_l;v++)c[v]=1E-20;for(v=0;v< +d.PSFB21;v++)f[v]=1E-20;for(v=0;v<d.SBMAX_s;v++)k[v]=1E-20;for(v=0;v<d.PSFB12;v++)z[v]=1E-20}w.ATH.floor=10*Math.log10(J(b,-1));h[0]=0;for(c=1;c<t;c++)h[c]=Math.pow(c,4/3);for(c=0;c<t-1;c++)D[c]=c+1-Math.pow(.5*(h[c]+h[c+1]),.75);D[c]=.5;for(c=0;c<ta;c++)a[c]=Math.pow(2,-.1875*(c-210));for(c=0;c<=ta+g;c++)l[c]=Math.pow(2,.25*(c-210-g));q.huffman_init(n);c=b.exp_nspsytune>>2&63;32<=c&&(c-=64);f=Math.pow(10,c/4/10);c=b.exp_nspsytune>>8&63;32<=c&&(c-=64);k=Math.pow(10,c/4/10);c=b.exp_nspsytune>>14&63; +32<=c&&(c-=64);z=Math.pow(10,c/4/10);c=b.exp_nspsytune>>20&63;32<=c&&(c-=64);b=z*Math.pow(10,c/4/10);for(c=0;c<d.SBMAX_l;c++)w=6>=c?f:13>=c?k:20>=c?z:b,n.nsPsy.longfact[c]=w;for(c=0;c<d.SBMAX_s;c++)w=5>=c?f:10>=c?k:11>=c?z:b,n.nsPsy.shortfact[c]=w}};this.on_pe=function(a,b,c,d,g,h){var l=a.internal_flags,k=0,v=Y(2),p,k=new eb(k);a=r.ResvMaxBits(a,d,k,h);var k=k.bits,m=k+a;m>da.MAX_BITS_PER_GRANULE&&(m=da.MAX_BITS_PER_GRANULE);for(p=h=0;p<l.channels_out;++p)c[p]=Math.min(da.MAX_BITS_PER_CHANNEL,k/ +l.channels_out),v[p]=0|c[p]*b[g][p]/700-c[p],v[p]>3*d/4&&(v[p]=3*d/4),0>v[p]&&(v[p]=0),v[p]+c[p]>da.MAX_BITS_PER_CHANNEL&&(v[p]=Math.max(0,da.MAX_BITS_PER_CHANNEL-c[p])),h+=v[p];if(h>a)for(p=0;p<l.channels_out;++p)v[p]=a*v[p]/h;for(p=0;p<l.channels_out;++p)c[p]+=v[p],a-=v[p];for(p=h=0;p<l.channels_out;++p)h+=c[p];if(h>da.MAX_BITS_PER_GRANULE)for(p=0;p<l.channels_out;++p)c[p]*=da.MAX_BITS_PER_GRANULE,c[p]/=h;return m};this.reduce_side=function(a,b,c,d){b=.33*(.5-b)/.5;0>b&&(b=0);.5<b&&(b=.5);b=0|.5* +b*(a[0]+a[1]);b>da.MAX_BITS_PER_CHANNEL-a[0]&&(b=da.MAX_BITS_PER_CHANNEL-a[0]);0>b&&(b=0);125<=a[1]&&(125<a[1]-b?(a[0]<c&&(a[0]+=b),a[1]-=b):(a[0]+=a[1]-125,a[1]=125));b=a[0]+a[1];b>d&&(a[0]=d*a[0]/b,a[1]=d*a[1]/b)};this.athAdjust=function(a,b,c){b=X.FAST_LOG10_X(b,10);a*=a;var d=0;b-=c;1E-20<a&&(d=1+X.FAST_LOG10_X(a,10/90.30873362));0>d&&(d=0);b=b*d+(c+90.30873362-94.82444863);return Math.pow(10,.1*b)};this.calc_xmin=function(a,b,c,f){var g=0,h=a.internal_flags,l,k=0,v=0,p=h.ATH,m=c.xr,x=a.VBR== +M.vbr_mtrh?1:0,y=h.masking_lower;if(a.VBR==M.vbr_mtrh||a.VBR==M.vbr_mt)y=1;for(l=0;l<c.psy_lmax;l++){var q,u,t,D,F,G;u=a.VBR==M.vbr_rh||a.VBR==M.vbr_mtrh?athAdjust(p.adjust,p.l[l],p.floor):p.adjust*p.l[l];F=c.width[l];t=u/F;D=2.220446049250313E-16;G=F>>1;q=0;do{var I;I=m[k]*m[k];q+=I;D+=I<t?I:t;k++;I=m[k]*m[k];q+=I;D+=I<t?I:t;k++}while(0<--G);q>u&&v++;l==d.SBPSY_l&&(t=u*h.nsPsy.longfact[l],D<t&&(D=t));0!=x&&(u=D);a.ATHonly||(D=b.en.l[l],0<D&&(t=q*b.thm.l[l]*y/D,0!=x&&(t*=h.nsPsy.longfact[l]),u<t&& +(u=t)));0!=x?f[g++]=u:f[g++]=u*h.nsPsy.longfact[l]}q=575;if(c.block_type!=d.SHORT_TYPE)for(u=576;0!=u--&&ua.EQ(m[u],0);)q=u;c.max_nonzero_coeff=q;for(var T=c.sfb_smin;l<c.psymax;T++,l+=3){var U,J;J=a.VBR==M.vbr_rh||a.VBR==M.vbr_mtrh?athAdjust(p.adjust,p.s[T],p.floor):p.adjust*p.s[T];F=c.width[l];for(U=0;3>U;U++){q=0;G=F>>1;t=J/F;D=2.220446049250313E-16;do I=m[k]*m[k],q+=I,D+=I<t?I:t,k++,I=m[k]*m[k],q+=I,D+=I<t?I:t,k++;while(0<--G);q>J&&v++;T==d.SBPSY_s&&(t=J*h.nsPsy.shortfact[T],D<t&&(D=t));u=0!= +x?D:J;a.ATHonly||a.ATHshort||(D=b.en.s[T][U],0<D&&(t=q*b.thm.s[T][U]*y/D,0!=x&&(t*=h.nsPsy.shortfact[T]),u<t&&(u=t)));0!=x?f[g++]=u:f[g++]=u*h.nsPsy.shortfact[T]}a.useTemporal&&(f[g-3]>f[g-3+1]&&(f[g-3+1]+=(f[g-3]-f[g-3+1])*h.decay),f[g-3+1]>f[g-3+2]&&(f[g-3+2]+=(f[g-3+1]-f[g-3+2])*h.decay))}return v};this.calc_noise_core=function(a,b,c,d){var g=0,l=b.s,k=a.l3_enc;if(l>a.count1)for(;0!=c--;){var q;q=a.xr[l];l++;g+=q*q;q=a.xr[l];l++;g+=q*q}else if(l>a.big_values){var v=H(2);v[0]=0;for(v[1]=d;0!=c--;)q= +Math.abs(a.xr[l])-v[k[l]],l++,g+=q*q,q=Math.abs(a.xr[l])-v[k[l]],l++,g+=q*q}else for(;0!=c--;)q=Math.abs(a.xr[l])-h[k[l]]*d,l++,g+=q*q,q=Math.abs(a.xr[l])-h[k[l]]*d,l++,g+=q*q;b.s=l;return g};this.calc_noise=function(a,d,c,f,g){var h=0,q=0,t,v,p=0,m=0,x=0,y=-20,D=0,u=a.scalefac,J=0;for(t=f.over_SSD=0;t<a.psymax;t++){var B=a.global_gain-(u[J++]+(0!=a.preflag?b[t]:0)<<a.scalefac_scale+1)-8*a.subblock_gain[a.window[t]],F=0;null!=g&&g.step[t]==B?(F=g.noise[t],D+=a.width[t],c[h++]=F/d[q++],F=g.noise_log[t]): +(F=l[B+ma.Q_MAX2],v=a.width[t]>>1,D+a.width[t]>a.max_nonzero_coeff&&(v=a.max_nonzero_coeff-D+1,v=0<v?v>>1:0),D=new k(D),F=this.calc_noise_core(a,D,v,F),D=D.s,null!=g&&(g.step[t]=B,g.noise[t]=F),F=c[h++]=F/d[q++],F=X.FAST_LOG10(Math.max(F,1E-20)),null!=g&&(g.noise_log[t]=F));null!=g&&(g.global_gain=a.global_gain);x+=F;0<F&&(B=Math.max(0|10*F+.5,1),f.over_SSD+=B*B,p++,m+=F);y=Math.max(y,F)}f.over_count=p;f.tot_noise=x;f.over_noise=m;f.max_noise=y;return p};this.set_pinfo=function(a,g,c,f,h){var l=a.internal_flags, +k,q,t,p,m=0==g.scalefac_scale?.5:1,x=g.scalefac,y=H(na.SFBMAX),D=H(na.SFBMAX),u=new $b;calc_xmin(a,c,g,y);calc_noise(g,y,D,u,null);var J=0;q=g.sfb_lmax;g.block_type!=d.SHORT_TYPE&&0==g.mixed_block_flag&&(q=22);for(k=0;k<q;k++){var B=l.scalefac_band.l[k],F=l.scalefac_band.l[k+1],G=F-B;for(p=0;J<F;J++)p+=g.xr[J]*g.xr[J];p/=G;t=1E15;l.pinfo.en[f][h][k]=t*p;l.pinfo.xfsf[f][h][k]=t*y[k]*D[k]/G;p=0<c.en.l[k]&&!a.ATHonly?p/c.en.l[k]:0;l.pinfo.thr[f][h][k]=t*Math.max(p*c.thm.l[k],l.ATH.l[k]);l.pinfo.LAMEsfb[f][h][k]= +0;0!=g.preflag&&11<=k&&(l.pinfo.LAMEsfb[f][h][k]=-m*b[k]);k<d.SBPSY_l&&(l.pinfo.LAMEsfb[f][h][k]-=m*x[k])}if(g.block_type==d.SHORT_TYPE)for(q=k,k=g.sfb_smin;k<d.SBMAX_s;k++)for(var B=l.scalefac_band.s[k],F=l.scalefac_band.s[k+1],G=F-B,I=0;3>I;I++){p=0;for(t=B;t<F;t++)p+=g.xr[J]*g.xr[J],J++;p=Math.max(p/G,1E-20);t=1E15;l.pinfo.en_s[f][h][3*k+I]=t*p;l.pinfo.xfsf_s[f][h][3*k+I]=t*y[q]*D[q]/G;p=0<c.en.s[k][I]?p/c.en.s[k][I]:0;if(a.ATHonly||a.ATHshort)p=0;l.pinfo.thr_s[f][h][3*k+I]=t*Math.max(p*c.thm.s[k][I], +l.ATH.s[k]);l.pinfo.LAMEsfb_s[f][h][3*k+I]=-2*g.subblock_gain[I];k<d.SBPSY_s&&(l.pinfo.LAMEsfb_s[f][h][3*k+I]-=m*x[q]);q++}l.pinfo.LAMEqss[f][h]=g.global_gain;l.pinfo.LAMEmainbits[f][h]=g.part2_3_length+g.part2_length;l.pinfo.LAMEsfbits[f][h]=g.part2_length;l.pinfo.over[f][h]=u.over_count;l.pinfo.max_noise[f][h]=10*u.max_noise;l.pinfo.over_noise[f][h]=10*u.over_noise;l.pinfo.tot_noise[f][h]=10*u.tot_noise;l.pinfo.over_SSD[f][h]=u.over_SSD}}function Nc(){this.sfb_count1=this.global_gain=0;this.step= +Y(39);this.noise=H(39);this.noise_log=H(39)}function Ab(){this.xr=H(576);this.l3_enc=Y(576);this.scalefac=Y(na.SFBMAX);this.mixed_block_flag=this.block_type=this.scalefac_compress=this.global_gain=this.count1=this.big_values=this.part2_3_length=this.xrpow_max=0;this.table_select=Y(3);this.subblock_gain=Y(4);this.sfbdivide=this.psymax=this.sfbmax=this.psy_lmax=this.sfb_smin=this.sfb_lmax=this.part2_length=this.count1table_select=this.scalefac_scale=this.preflag=this.region1_count=this.region0_count= +0;this.width=Y(na.SFBMAX);this.window=Y(na.SFBMAX);this.count1bits=0;this.sfb_partition_table=null;this.slen=Y(4);this.max_nonzero_coeff=0;var d=this;this.assign=function(k){d.xr=new Float32Array(k.xr);d.l3_enc=new Int32Array(k.l3_enc);d.scalefac=new Int32Array(k.scalefac);d.xrpow_max=k.xrpow_max;d.part2_3_length=k.part2_3_length;d.big_values=k.big_values;d.count1=k.count1;d.global_gain=k.global_gain;d.scalefac_compress=k.scalefac_compress;d.block_type=k.block_type;d.mixed_block_flag=k.mixed_block_flag; +d.table_select=new Int32Array(k.table_select);d.subblock_gain=new Int32Array(k.subblock_gain);d.region0_count=k.region0_count;d.region1_count=k.region1_count;d.preflag=k.preflag;d.scalefac_scale=k.scalefac_scale;d.count1table_select=k.count1table_select;d.part2_length=k.part2_length;d.sfb_lmax=k.sfb_lmax;d.sfb_smin=k.sfb_smin;d.psy_lmax=k.psy_lmax;d.sfbmax=k.sfbmax;d.psymax=k.psymax;d.sfbdivide=k.sfbdivide;d.width=new Int32Array(k.width);d.window=new Int32Array(k.window);d.count1bits=k.count1bits; +d.sfb_partition_table=k.sfb_partition_table.slice(0);d.slen=new Int32Array(k.slen);d.max_nonzero_coeff=k.max_nonzero_coeff}}function Oc(){function J(d){this.ordinal=d}function k(d){for(var b=0;b<d.sfbmax;b++)if(0==d.scalefac[b]+d.subblock_gain[d.window[b]])return!1;return!0}var q;this.rv=null;var r;this.qupvt=null;var B,t=new Ic,ta;this.setModules=function(d,b,l,a){q=d;this.rv=r=b;this.qupvt=B=l;ta=a;t.setModules(B,ta)};this.ms_convert=function(d,b){for(var l=0;576>l;++l){var a=d.tt[b][0].xr[l],h= +d.tt[b][1].xr[l];d.tt[b][0].xr[l]=.5*(a+h)*X.SQRT2;d.tt[b][1].xr[l]=.5*(a-h)*X.SQRT2}};this.init_xrpow=function(d,b,l){var a=0,h=0|b.max_nonzero_coeff;b.xrpow_max=0;Ia.fill(l,h,576,0);for(var k=a=0;k<=h;++k){var e=Math.abs(b.xr[k]),a=a+e;l[k]=Math.sqrt(e*Math.sqrt(e));l[k]>b.xrpow_max&&(b.xrpow_max=l[k])}if(1E-20<a){l=0;0!=(d.substep_shaping&2)&&(l=1);for(h=0;h<b.psymax;h++)d.pseudohalf[h]=l;return!0}Ia.fill(b.l3_enc,0,576,0);return!1};this.init_outer_loop=function(g,b){b.part2_3_length=0;b.big_values= +0;b.count1=0;b.global_gain=210;b.scalefac_compress=0;b.table_select[0]=0;b.table_select[1]=0;b.table_select[2]=0;b.subblock_gain[0]=0;b.subblock_gain[1]=0;b.subblock_gain[2]=0;b.subblock_gain[3]=0;b.region0_count=0;b.region1_count=0;b.preflag=0;b.scalefac_scale=0;b.count1table_select=0;b.part2_length=0;b.sfb_lmax=d.SBPSY_l;b.sfb_smin=d.SBPSY_s;b.psy_lmax=g.sfb21_extra?d.SBMAX_l:d.SBPSY_l;b.psymax=b.psy_lmax;b.sfbmax=b.sfb_lmax;b.sfbdivide=11;for(var l=0;l<d.SBMAX_l;l++)b.width[l]=g.scalefac_band.l[l+ +1]-g.scalefac_band.l[l],b.window[l]=3;if(b.block_type==d.SHORT_TYPE){var a=H(576);b.sfb_smin=0;b.sfb_lmax=0;0!=b.mixed_block_flag&&(b.sfb_smin=3,b.sfb_lmax=2*g.mode_gr+4);b.psymax=b.sfb_lmax+3*((g.sfb21_extra?d.SBMAX_s:d.SBPSY_s)-b.sfb_smin);b.sfbmax=b.sfb_lmax+3*(d.SBPSY_s-b.sfb_smin);b.sfbdivide=b.sfbmax-18;b.psy_lmax=b.sfb_lmax;var h=g.scalefac_band.l[b.sfb_lmax];K.arraycopy(b.xr,0,a,0,576);for(l=b.sfb_smin;l<d.SBMAX_s;l++)for(var k=g.scalefac_band.s[l],e=g.scalefac_band.s[l+1],n=0;3>n;n++)for(var c= +k;c<e;c++)b.xr[h++]=a[3*c+n];a=b.sfb_lmax;for(l=b.sfb_smin;l<d.SBMAX_s;l++)b.width[a]=b.width[a+1]=b.width[a+2]=g.scalefac_band.s[l+1]-g.scalefac_band.s[l],b.window[a]=0,b.window[a+1]=1,b.window[a+2]=2,a+=3}b.count1bits=0;b.sfb_partition_table=B.nr_of_sfb_block[0][0];b.slen[0]=0;b.slen[1]=0;b.slen[2]=0;b.slen[3]=0;b.max_nonzero_coeff=575;Ia.fill(b.scalefac,0);l=g.ATH;a=b.xr;if(b.block_type!=d.SHORT_TYPE)for(h=!1,k=d.PSFB21-1;0<=k&&!h;k--)for(e=g.scalefac_band.psfb21[k],n=g.scalefac_band.psfb21[k+ +1],c=B.athAdjust(l.adjust,l.psfb21[k],l.floor),1E-12<g.nsPsy.longfact[21]&&(c*=g.nsPsy.longfact[21]),--n;n>=e;n--)if(Math.abs(a[n])<c)a[n]=0;else{h=!0;break}else for(c=0;3>c;c++)for(h=!1,k=d.PSFB12-1;0<=k&&!h;k--){var e=3*g.scalefac_band.s[12]+(g.scalefac_band.s[13]-g.scalefac_band.s[12])*c+(g.scalefac_band.psfb12[k]-g.scalefac_band.psfb12[0]),n=e+(g.scalefac_band.psfb12[k+1]-g.scalefac_band.psfb12[k]),f=B.athAdjust(l.adjust,l.psfb12[k],l.floor);1E-12<g.nsPsy.shortfact[12]&&(f*=g.nsPsy.shortfact[12]); +for(--n;n>=e;n--)if(Math.abs(a[n])<f)a[n]=0;else{h=!0;break}}};J.BINSEARCH_NONE=new J(0);J.BINSEARCH_UP=new J(1);J.BINSEARCH_DOWN=new J(2);this.trancate_smallspectrums=function(g,b,l,a){var h=H(na.SFBMAX);if((0!=(g.substep_shaping&4)||b.block_type!=d.SHORT_TYPE)&&0==(g.substep_shaping&128)){B.calc_noise(b,l,h,new $b,null);for(var k=0;576>k;k++){var e=0;0!=b.l3_enc[k]&&(e=Math.abs(b.xr[k]));a[k]=e}k=0;e=8;b.block_type==d.SHORT_TYPE&&(e=6);do{var n,c,f,q,t=b.width[e],k=k+t;if(!(1<=h[e]||(Ia.sort(a, +k-t,t),ua.EQ(a[k-1],0)))){n=(1-h[e])*l[e];q=c=0;do{var w;for(f=1;q+f<t&&!ua.NEQ(a[q+k-t],a[q+k+f-t]);f++);w=a[q+k-t]*a[q+k-t]*f;if(n<w){0!=q&&(c=a[q+k-t-1]);break}n-=w;q+=f}while(q<t);if(!ua.EQ(c,0)){do Math.abs(b.xr[k-t])<=c&&(b.l3_enc[k-t]=0);while(0<--t)}}}while(++e<b.psymax);b.part2_3_length=ta.noquant_count_bits(g,b,null)}};this.outer_loop=function(g,b,l,a,h,q){var e=g.internal_flags,n=new Ab,c=H(576),f=H(na.SFBMAX),t=new $b,z,w=new Nc,A=9999999,v=!1,p=!1,m=0,x,y,W=e.CurrentStep[h],u=!1,r=e.OldValue[h]; +z=J.BINSEARCH_NONE;b.global_gain=r;for(x=q-b.part2_length;;){y=ta.count_bits(e,a,b,null);if(1==W||y==x)break;y>x?(z==J.BINSEARCH_DOWN&&(u=!0),u&&(W/=2),z=J.BINSEARCH_UP,y=W):(z==J.BINSEARCH_UP&&(u=!0),u&&(W/=2),z=J.BINSEARCH_DOWN,y=-W);b.global_gain+=y;0>b.global_gain&&(b.global_gain=0,u=!0);255<b.global_gain&&(b.global_gain=255,u=!0)}for(;y>x&&255>b.global_gain;)b.global_gain++,y=ta.count_bits(e,a,b,null);e.CurrentStep[h]=4<=r-b.global_gain?4:2;e.OldValue[h]=b.global_gain;b.part2_3_length=y;if(0== +e.noise_shaping)return 100;B.calc_noise(b,l,f,t,w);t.bits=b.part2_3_length;n.assign(b);h=0;for(K.arraycopy(a,0,c,0,576);!v;){do{x=new $b;u=255;W=0!=(e.substep_shaping&2)?20:3;if(e.sfb21_extra){if(1<f[n.sfbmax])break;if(n.block_type==d.SHORT_TYPE&&(1<f[n.sfbmax+1]||1<f[n.sfbmax+2]))break}r=n;y=a;z=g.internal_flags;for(var C=r,F=f,G=y,I=g.internal_flags,T=void 0,T=0==C.scalefac_scale?1.2968395546510096:1.6817928305074292,U=0,qa=0;qa<C.sfbmax;qa++)U<F[qa]&&(U=F[qa]);qa=I.noise_shaping_amp;3==qa&&(qa= +p?2:1);switch(qa){case 2:break;case 1:U=1<U?Math.pow(U,.5):.95*U;break;default:U=1<U?1:.95*U}for(var ia=0,qa=0;qa<C.sfbmax;qa++){var ya=C.width[qa],ia=ia+ya;if(!(F[qa]<U)){if(0!=(I.substep_shaping&2)&&(I.pseudohalf[qa]=0==I.pseudohalf[qa]?1:0,0==I.pseudohalf[qa]&&2==I.noise_shaping_amp))break;C.scalefac[qa]++;for(ya=-ya;0>ya;ya++)G[ia+ya]*=T,G[ia+ya]>C.xrpow_max&&(C.xrpow_max=G[ia+ya]);if(2==I.noise_shaping_amp)break}}if(C=k(r))r=!1;else if(C=2==z.mode_gr?ta.scale_bitcount(r):ta.scale_bitcount_lsf(z, +r)){if(1<z.noise_shaping)if(Ia.fill(z.pseudohalf,0),0==r.scalefac_scale){C=r;for(G=F=0;G<C.sfbmax;G++){T=C.width[G];I=C.scalefac[G];0!=C.preflag&&(I+=B.pretab[G]);F+=T;if(0!=(I&1))for(I++,T=-T;0>T;T++)y[F+T]*=1.2968395546510096,y[F+T]>C.xrpow_max&&(C.xrpow_max=y[F+T]);C.scalefac[G]=I>>1}C.preflag=0;C.scalefac_scale=1;C=!1}else if(r.block_type==d.SHORT_TYPE&&0<z.subblock_gain){b:{C=z;F=r;G=void 0;I=F.scalefac;for(G=0;G<F.sfb_lmax;G++)if(16<=I[G]){y=!0;break b}for(T=0;3>T;T++){qa=U=0;for(G=F.sfb_lmax+ +T;G<F.sfbdivide;G+=3)U<I[G]&&(U=I[G]);for(;G<F.sfbmax;G+=3)qa<I[G]&&(qa=I[G]);if(!(16>U&&8>qa)){if(7<=F.subblock_gain[T]){y=!0;break b}F.subblock_gain[T]++;U=C.scalefac_band.l[F.sfb_lmax];for(G=F.sfb_lmax+T;G<F.sfbmax;G+=3)if(qa=F.width[G],ia=I[G],ia-=4>>F.scalefac_scale,0<=ia)I[G]=ia,U+=3*qa;else{I[G]=0;ia=B.IPOW20(210+(ia<<F.scalefac_scale+1));U+=qa*(T+1);for(ya=-qa;0>ya;ya++)y[U+ya]*=ia,y[U+ya]>F.xrpow_max&&(F.xrpow_max=y[U+ya]);U+=qa*(3-T-1)}ia=B.IPOW20(202);U+=F.width[G]*(T+1);for(ya=-F.width[G];0> +ya;ya++)y[U+ya]*=ia,y[U+ya]>F.xrpow_max&&(F.xrpow_max=y[U+ya])}}y=!1}C=y||k(r)}C||(C=2==z.mode_gr?ta.scale_bitcount(r):ta.scale_bitcount_lsf(z,r));r=!C}else r=!0;if(!r)break;0!=n.scalefac_scale&&(u=254);r=q-n.part2_length;if(0>=r)break;for(;(n.part2_3_length=ta.count_bits(e,a,n,w))>r&&n.global_gain<=u;)n.global_gain++;if(n.global_gain>u)break;if(0==t.over_count){for(;(n.part2_3_length=ta.count_bits(e,a,n,w))>A&&n.global_gain<=u;)n.global_gain++;if(n.global_gain>u)break}B.calc_noise(n,l,f,x,w);x.bits= +n.part2_3_length;z=b.block_type!=d.SHORT_TYPE?g.quant_comp:g.quant_comp_short;u=t;r=x;C=n;y=f;F=void 0;switch(z){default:case 9:0<u.over_count?(F=r.over_SSD<=u.over_SSD,r.over_SSD==u.over_SSD&&(F=r.bits<u.bits)):F=0>r.max_noise&&10*r.max_noise+r.bits<=10*u.max_noise+u.bits;break;case 0:F=r.over_count<u.over_count||r.over_count==u.over_count&&r.over_noise<u.over_noise||r.over_count==u.over_count&&ua.EQ(r.over_noise,u.over_noise)&&r.tot_noise<u.tot_noise;break;case 8:z=r;G=1E-37;for(F=0;F<C.psymax;F++)I= +y[F],I=X.FAST_LOG10(.368+.632*I*I*I),G+=I;y=Math.max(1E-20,G);z.max_noise=y;case 1:F=r.max_noise<u.max_noise;break;case 2:F=r.tot_noise<u.tot_noise;break;case 3:F=r.tot_noise<u.tot_noise&&r.max_noise<u.max_noise;break;case 4:F=0>=r.max_noise&&.2<u.max_noise||0>=r.max_noise&&0>u.max_noise&&u.max_noise>r.max_noise-.2&&r.tot_noise<u.tot_noise||0>=r.max_noise&&0<u.max_noise&&u.max_noise>r.max_noise-.2&&r.tot_noise<u.tot_noise+u.over_noise||0<r.max_noise&&-.05<u.max_noise&&u.max_noise>r.max_noise-.1&& +r.tot_noise+r.over_noise<u.tot_noise+u.over_noise||0<r.max_noise&&-.1<u.max_noise&&u.max_noise>r.max_noise-.15&&r.tot_noise+r.over_noise+r.over_noise<u.tot_noise+u.over_noise+u.over_noise;break;case 5:F=r.over_noise<u.over_noise||ua.EQ(r.over_noise,u.over_noise)&&r.tot_noise<u.tot_noise;break;case 6:F=r.over_noise<u.over_noise||ua.EQ(r.over_noise,u.over_noise)&&(r.max_noise<u.max_noise||ua.EQ(r.max_noise,u.max_noise)&&r.tot_noise<=u.tot_noise);break;case 7:F=r.over_count<u.over_count||r.over_noise< +u.over_noise}0==u.over_count&&(F=F&&r.bits<u.bits);z=F?1:0;if(0!=z)A=b.part2_3_length,t=x,b.assign(n),h=0,K.arraycopy(a,0,c,0,576);else if(0==e.full_outer_loop){if(++h>W&&0==t.over_count)break;if(3==e.noise_shaping_amp&&p&&30<h)break;if(3==e.noise_shaping_amp&&p&&15<n.global_gain-m)break}}while(255>n.global_gain+n.scalefac_scale);3==e.noise_shaping_amp?p?v=!0:(n.assign(b),K.arraycopy(c,0,a,0,576),h=0,m=n.global_gain,p=!0):v=!0}g.VBR==M.vbr_rh||g.VBR==M.vbr_mtrh?K.arraycopy(c,0,a,0,576):0!=(e.substep_shaping& +1)&&trancate_smallspectrums(e,b,l,a);return t.over_count};this.iteration_finish_one=function(d,b,l){var a=d.l3_side,h=a.tt[b][l];ta.best_scalefac_store(d,b,l,a);1==d.use_best_huffman&&ta.best_huffman_divide(d,h);r.ResvAdjust(d,h)};this.VBR_encode_granule=function(d,b,l,a,h,k,e){var n=d.internal_flags,c=new Ab,f=H(576),q=e,t=e+1,t=(e+k)/2,r,A=0,v=n.sfb21_extra;Ia.fill(c.l3_enc,0);do n.sfb21_extra=t>q-42?!1:v,r=outer_loop(d,b,l,a,h,t),0>=r?(A=1,t=b.part2_3_length,c.assign(b),K.arraycopy(a,0,f,0,576), +e=t-32,r=e-k,t=(e+k)/2):(k=t+32,r=e-k,t=(e+k)/2,0!=A&&(A=2,b.assign(c),K.arraycopy(f,0,a,0,576)));while(12<r);n.sfb21_extra=v;2==A&&K.arraycopy(c.l3_enc,0,b.l3_enc,0,576)};this.get_framebits=function(d,b){var l=d.internal_flags;l.bitrate_index=l.VBR_min_bitrate;var a=q.getframebits(d);l.bitrate_index=1;for(var a=q.getframebits(d),h=1;h<=l.VBR_max_bitrate;h++)l.bitrate_index=h,a=new eb(a),b[h]=r.ResvFrameBegin(d,a),a=a.bits};this.VBR_old_prepare=function(g,b,l,a,h,k,e,n,c){var f=g.internal_flags,q; +q=0;var t=1,w=0;f.bitrate_index=f.VBR_max_bitrate;var A=r.ResvFrameBegin(g,new eb(0))/f.mode_gr;get_framebits(g,k);for(var v=0;v<f.mode_gr;v++){var p=B.on_pe(g,b,n[v],A,v,0);f.mode_ext==d.MPG_MD_MS_LR&&(ms_convert(f.l3_side,v),B.reduce_side(n[v],l[v],A,p));for(p=0;p<f.channels_out;++p){var m=f.l3_side.tt[v][p];m.block_type!=d.SHORT_TYPE?(q=1.28/(1+Math.exp(3.5-b[v][p]/300))-.05,q=f.PSY.mask_adjust-q):(q=2.56/(1+Math.exp(3.5-b[v][p]/300))-.14,q=f.PSY.mask_adjust_short-q);f.masking_lower=Math.pow(10, +.1*q);init_outer_loop(f,m);c[v][p]=B.calc_xmin(g,a[v][p],m,h[v][p]);0!=c[v][p]&&(t=0);e[v][p]=126;w+=n[v][p]}}for(v=0;v<f.mode_gr;v++)for(p=0;p<f.channels_out;p++)w>k[f.VBR_max_bitrate]&&(n[v][p]*=k[f.VBR_max_bitrate],n[v][p]/=w),e[v][p]>n[v][p]&&(e[v][p]=n[v][p]);return t};this.bitpressure_strategy=function(g,b,l,a){for(var h=0;h<g.mode_gr;h++)for(var k=0;k<g.channels_out;k++){for(var e=g.l3_side.tt[h][k],n=b[h][k],c=0,f=0;f<e.psy_lmax;f++)n[c++]*=1+.029*f*f/d.SBMAX_l/d.SBMAX_l;if(e.block_type== +d.SHORT_TYPE)for(f=e.sfb_smin;f<d.SBMAX_s;f++)n[c++]*=1+.029*f*f/d.SBMAX_s/d.SBMAX_s,n[c++]*=1+.029*f*f/d.SBMAX_s/d.SBMAX_s,n[c++]*=1+.029*f*f/d.SBMAX_s/d.SBMAX_s;a[h][k]=0|Math.max(l[h][k],.9*a[h][k])}};this.VBR_new_prepare=function(g,b,k,a,h,q){var e=g.internal_flags,n=1,c=0,f=0,t;g.free_format?(e.bitrate_index=0,c=new eb(c),t=r.ResvFrameBegin(g,c),c=c.bits,h[0]=t):(e.bitrate_index=e.VBR_max_bitrate,c=new eb(c),r.ResvFrameBegin(g,c),c=c.bits,get_framebits(g,h),t=h[e.VBR_max_bitrate]);for(h=0;h< +e.mode_gr;h++){B.on_pe(g,b,q[h],c,h,0);e.mode_ext==d.MPG_MD_MS_LR&&ms_convert(e.l3_side,h);for(var z=0;z<e.channels_out;++z){var w=e.l3_side.tt[h][z];e.masking_lower=Math.pow(10,.1*e.PSY.mask_adjust);init_outer_loop(e,w);0!=B.calc_xmin(g,k[h][z],w,a[h][z])&&(n=0);f+=q[h][z]}}for(h=0;h<e.mode_gr;h++)for(z=0;z<e.channels_out;z++)f>t&&(q[h][z]*=t,q[h][z]/=f);return n};this.calc_target_bits=function(g,b,k,a,h,t){var e=g.internal_flags,n=e.l3_side,c,f;e.bitrate_index=e.VBR_max_bitrate;f=new eb(0);t[0]= +r.ResvFrameBegin(g,f);e.bitrate_index=1;f=q.getframebits(g)-8*e.sideinfo_len;h[0]=f/(e.mode_gr*e.channels_out);f=g.VBR_mean_bitrate_kbps*g.framesize*1E3;0!=(e.substep_shaping&1)&&(f*=1.09);f/=g.out_samplerate;f-=8*e.sideinfo_len;f/=e.mode_gr*e.channels_out;c=.93+.07*(11-g.compression_ratio)/5.5;.9>c&&(c=.9);1<c&&(c=1);for(g=0;g<e.mode_gr;g++){var E=0;for(h=0;h<e.channels_out;h++){a[g][h]=int(c*f);if(700<b[g][h]){var z=int((b[g][h]-700)/1.4),w=n.tt[g][h];a[g][h]=int(c*f);w.block_type==d.SHORT_TYPE&& +z<f/2&&(z=f/2);z>3*f/2?z=3*f/2:0>z&&(z=0);a[g][h]+=z}a[g][h]>da.MAX_BITS_PER_CHANNEL&&(a[g][h]=da.MAX_BITS_PER_CHANNEL);E+=a[g][h]}if(E>da.MAX_BITS_PER_GRANULE)for(h=0;h<e.channels_out;++h)a[g][h]*=da.MAX_BITS_PER_GRANULE,a[g][h]/=E}if(e.mode_ext==d.MPG_MD_MS_LR)for(g=0;g<e.mode_gr;g++)B.reduce_side(a[g],k[g],f*e.channels_out,da.MAX_BITS_PER_GRANULE);for(g=b=0;g<e.mode_gr;g++)for(h=0;h<e.channels_out;h++)a[g][h]>da.MAX_BITS_PER_CHANNEL&&(a[g][h]=da.MAX_BITS_PER_CHANNEL),b+=a[g][h];if(b>t[0])for(g= +0;g<e.mode_gr;g++)for(h=0;h<e.channels_out;h++)a[g][h]*=t[0],a[g][h]/=b}}function Qa(){this.thm=new ic;this.en=new ic}function Pc(){function r(b,d,a){for(var g=10,q=d+238-14-286,e=-15;0>e;e++){var n,c,f;n=k[g+-10];c=b[q+-224]*n;f=b[d+224]*n;n=k[g+-9];c+=b[q+-160]*n;f+=b[d+160]*n;n=k[g+-8];c+=b[q+-96]*n;f+=b[d+96]*n;n=k[g+-7];c+=b[q+-32]*n;f+=b[d+32]*n;n=k[g+-6];c+=b[q+32]*n;f+=b[d+-32]*n;n=k[g+-5];c+=b[q+96]*n;f+=b[d+-96]*n;n=k[g+-4];c+=b[q+160]*n;f+=b[d+-160]*n;n=k[g+-3];c+=b[q+224]*n;f+=b[d+-224]* +n;n=k[g+-2];c+=b[d+-256]*n;f-=b[q+256]*n;n=k[g+-1];c+=b[d+-192]*n;f-=b[q+192]*n;n=k[g+0];c+=b[d+-128]*n;f-=b[q+128]*n;n=k[g+1];c+=b[d+-64]*n;f-=b[q+64]*n;n=k[g+2];c+=b[d+0]*n;f-=b[q+0]*n;n=k[g+3];c+=b[d+64]*n;f-=b[q+-64]*n;n=k[g+4];c+=b[d+128]*n;f-=b[q+-128]*n;n=k[g+5];c+=b[d+192]*n;f-=b[q+-192]*n;c*=k[g+6];n=f-c;a[30+2*e]=f+c;a[31+2*e]=k[g+7]*n;g+=18;d--;q++}f=b[d+-16]*k[g+-10];c=b[d+-32]*k[g+-2];f+=(b[d+-48]-b[d+16])*k[g+-9];c+=b[d+-96]*k[g+-1];f+=(b[d+-80]+b[d+48])*k[g+-8];c+=b[d+-160]*k[g+0]; +f+=(b[d+-112]-b[d+80])*k[g+-7];c+=b[d+-224]*k[g+1];f+=(b[d+-144]+b[d+112])*k[g+-6];c-=b[d+32]*k[g+2];f+=(b[d+-176]-b[d+144])*k[g+-5];c-=b[d+96]*k[g+3];f+=(b[d+-208]+b[d+176])*k[g+-4];c-=b[d+160]*k[g+4];f+=(b[d+-240]-b[d+208])*k[g+-3];c-=b[d+224];b=c-f;d=c+f;f=a[14];c=a[15]-f;a[31]=d+f;a[30]=b+c;a[15]=b-c;a[14]=d-f;c=a[28]-a[0];a[0]+=a[28];a[28]=c*k[g+-36+7];c=a[29]-a[1];a[1]+=a[29];a[29]=c*k[g+-36+7];c=a[26]-a[2];a[2]+=a[26];a[26]=c*k[g+-72+7];c=a[27]-a[3];a[3]+=a[27];a[27]=c*k[g+-72+7];c=a[24]-a[4]; +a[4]+=a[24];a[24]=c*k[g+-108+7];c=a[25]-a[5];a[5]+=a[25];a[25]=c*k[g+-108+7];c=a[22]-a[6];a[6]+=a[22];a[22]=c*X.SQRT2;c=a[23]-a[7];a[7]+=a[23];a[23]=c*X.SQRT2-a[7];a[7]-=a[6];a[22]-=a[7];a[23]-=a[22];c=a[6];a[6]=a[31]-c;a[31]+=c;c=a[7];a[7]=a[30]-c;a[30]+=c;c=a[22];a[22]=a[15]-c;a[15]+=c;c=a[23];a[23]=a[14]-c;a[14]+=c;c=a[20]-a[8];a[8]+=a[20];a[20]=c*k[g+-180+7];c=a[21]-a[9];a[9]+=a[21];a[21]=c*k[g+-180+7];c=a[18]-a[10];a[10]+=a[18];a[18]=c*k[g+-216+7];c=a[19]-a[11];a[11]+=a[19];a[19]=c*k[g+-216+ +7];c=a[16]-a[12];a[12]+=a[16];a[16]=c*k[g+-252+7];c=a[17]-a[13];a[13]+=a[17];a[17]=c*k[g+-252+7];c=-a[20]+a[24];a[20]+=a[24];a[24]=c*k[g+-216+7];c=-a[21]+a[25];a[21]+=a[25];a[25]=c*k[g+-216+7];c=a[4]-a[8];a[4]+=a[8];a[8]=c*k[g+-216+7];c=a[5]-a[9];a[5]+=a[9];a[9]=c*k[g+-216+7];c=a[0]-a[12];a[0]+=a[12];a[12]=c*k[g+-72+7];c=a[1]-a[13];a[1]+=a[13];a[13]=c*k[g+-72+7];c=a[16]-a[28];a[16]+=a[28];a[28]=c*k[g+-72+7];c=-a[17]+a[29];a[17]+=a[29];a[29]=c*k[g+-72+7];c=X.SQRT2*(a[2]-a[10]);a[2]+=a[10];a[10]=c; +c=X.SQRT2*(a[3]-a[11]);a[3]+=a[11];a[11]=c;c=X.SQRT2*(-a[18]+a[26]);a[18]+=a[26];a[26]=c-a[18];c=X.SQRT2*(-a[19]+a[27]);a[19]+=a[27];a[27]=c-a[19];c=a[2];a[19]-=a[3];a[3]-=c;a[2]=a[31]-c;a[31]+=c;c=a[3];a[11]-=a[19];a[18]-=c;a[3]=a[30]-c;a[30]+=c;c=a[18];a[27]-=a[11];a[19]-=c;a[18]=a[15]-c;a[15]+=c;c=a[19];a[10]-=c;a[19]=a[14]-c;a[14]+=c;c=a[10];a[11]-=c;a[10]=a[23]-c;a[23]+=c;c=a[11];a[26]-=c;a[11]=a[22]-c;a[22]+=c;c=a[26];a[27]-=c;a[26]=a[7]-c;a[7]+=c;c=a[27];a[27]=a[6]-c;a[6]+=c;c=X.SQRT2*(a[0]- +a[4]);a[0]+=a[4];a[4]=c;c=X.SQRT2*(a[1]-a[5]);a[1]+=a[5];a[5]=c;c=X.SQRT2*(a[16]-a[20]);a[16]+=a[20];a[20]=c;c=X.SQRT2*(a[17]-a[21]);a[17]+=a[21];a[21]=c;c=-X.SQRT2*(a[8]-a[12]);a[8]+=a[12];a[12]=c-a[8];c=-X.SQRT2*(a[9]-a[13]);a[9]+=a[13];a[13]=c-a[9];c=-X.SQRT2*(a[25]-a[29]);a[25]+=a[29];a[29]=c-a[25];c=-X.SQRT2*(a[24]+a[28]);a[24]-=a[28];a[28]=c-a[24];c=a[24]-a[16];a[24]=c;c=a[20]-c;a[20]=c;c=a[28]-c;a[28]=c;c=a[25]-a[17];a[25]=c;c=a[21]-c;a[21]=c;c=a[29]-c;a[29]=c;c=a[17]-a[1];a[17]=c;c=a[9]-c; +a[9]=c;c=a[25]-c;a[25]=c;c=a[5]-c;a[5]=c;c=a[21]-c;a[21]=c;c=a[13]-c;a[13]=c;c=a[29]-c;a[29]=c;c=a[1]-a[0];a[1]=c;c=a[16]-c;a[16]=c;c=a[17]-c;a[17]=c;c=a[8]-c;a[8]=c;c=a[9]-c;a[9]=c;c=a[24]-c;a[24]=c;c=a[25]-c;a[25]=c;c=a[4]-c;a[4]=c;c=a[5]-c;a[5]=c;c=a[20]-c;a[20]=c;c=a[21]-c;a[21]=c;c=a[12]-c;a[12]=c;c=a[13]-c;a[13]=c;c=a[28]-c;a[28]=c;c=a[29]-c;a[29]=c;c=a[0];a[0]+=a[31];a[31]-=c;c=a[1];a[1]+=a[30];a[30]-=c;c=a[16];a[16]+=a[15];a[15]-=c;c=a[17];a[17]+=a[14];a[14]-=c;c=a[8];a[8]+=a[23];a[23]-=c; +c=a[9];a[9]+=a[22];a[22]-=c;c=a[24];a[24]+=a[7];a[7]-=c;c=a[25];a[25]+=a[6];a[6]-=c;c=a[4];a[4]+=a[27];a[27]-=c;c=a[5];a[5]+=a[26];a[26]-=c;c=a[20];a[20]+=a[11];a[11]-=c;c=a[21];a[21]+=a[10];a[10]-=c;c=a[12];a[12]+=a[19];a[19]-=c;c=a[13];a[13]+=a[18];a[18]-=c;c=a[28];a[28]+=a[3];a[3]-=c;c=a[29];a[29]+=a[2];a[2]-=c}var k=[-.1482523854003001,32.308141959636465,296.40344946382766,883.1344870032432,11113.947376231741,1057.2713659324597,305.7402417275812,30.825928907280012,3.8533188138216365,59.42900443849514, +709.5899960123345,5281.91112291017,-5829.66483675846,-817.6293103748613,-76.91656988279972,-4.594269939176596,.9063471690191471,.1960342806591213,-.15466694054279598,34.324387823855965,301.8067566458425,817.599602898885,11573.795901679885,1181.2520595540152,321.59731579894424,31.232021761053772,3.7107095756221318,53.650946155329365,684.167428119626,5224.56624370173,-6366.391851890084,-908.9766368219582,-89.83068876699639,-5.411397422890401,.8206787908286602,.3901806440322567,-.16070888947830023,36.147034243915876, +304.11815768187864,732.7429163887613,11989.60988270091,1300.012278487897,335.28490093152146,31.48816102859945,3.373875931311736,47.232241542899175,652.7371796173471,5132.414255594984,-6909.087078780055,-1001.9990371107289,-103.62185754286375,-6.104916304710272,.7416505462720353,.5805693545089249,-.16636367662261495,37.751650073343995,303.01103387567713,627.9747488785183,12358.763425278165,1412.2779918482834,346.7496836825721,31.598286663170416,3.1598635433980946,40.57878626349686,616.1671130880391, +5007.833007176154,-7454.040671756168,-1095.7960341867115,-118.24411666465777,-6.818469345853504,.6681786379192989,.7653668647301797,-.1716176790982088,39.11551877123304,298.3413246578966,503.5259106886539,12679.589408408976,1516.5821921214542,355.9850766329023,31.395241710249053,2.9164211881972335,33.79716964664243,574.8943997801362,4853.234992253242,-7997.57021486075,-1189.7624067269965,-133.6444792601766,-7.7202770609839915,.5993769336819237,.9427934736519954,-.17645823955292173,40.21879108166477, +289.9982036694474,359.3226160751053,12950.259102786438,1612.1013903507662,362.85067106591504,31.045922092242872,2.822222032597987,26.988862316190684,529.8996541764288,4671.371946949588,-8535.899136645805,-1282.5898586244496,-149.58553632943463,-8.643494270763135,.5345111359507916,1.111140466039205,-.36174739330527045,41.04429910497807,277.5463268268618,195.6386023135583,13169.43812144731,1697.6433561479398,367.40983966190305,30.557037410382826,2.531473372857427,20.070154905927314,481.50208566532336, +4464.970341588308,-9065.36882077239,-1373.62841526722,-166.1660487028118,-9.58289321133207,.4729647758913199,1.268786568327291,-.36970682634889585,41.393213350082036,261.2935935556502,12.935476055240873,13336.131683328815,1772.508612059496,369.76534388639965,29.751323653701338,2.4023193045459172,13.304795348228817,430.5615775526625,4237.0568611071185,-9581.931701634761,-1461.6913552409758,-183.12733958476446,-10.718010163869403,.41421356237309503,1.414213562373095,-.37677560326535325,41.619486213528496, +241.05423794991074,-187.94665032361226,13450.063605744153,1836.153896465782,369.4908799925761,29.001847876923147,2.0714759319987186,6.779591200894186,377.7767837205709,3990.386575512536,-10081.709459700915,-1545.947424837898,-200.3762958015653,-11.864482073055006,.3578057213145241,1.546020906725474,-.3829366947518991,41.1516456456653,216.47684307105183,-406.1569483347166,13511.136535077321,1887.8076599260432,367.3025214564151,28.136213436723654,1.913880671464418,.3829366947518991,323.85365704338597, +3728.1472257487526,-10561.233882199509,-1625.2025997821418,-217.62525175416,-13.015432208941645,.3033466836073424,1.66293922460509,-.5822628872992417,40.35639251440489,188.20071124269245,-640.2706748618148,13519.21490106562,1927.6022433578062,362.8197642637487,26.968821921868447,1.7463817695935329,-5.62650678237171,269.3016715297017,3453.386536448852,-11016.145278780888,-1698.6569643425091,-234.7658734267683,-14.16351421663124,.2504869601913055,1.76384252869671,-.5887180101749253,39.23429103868072, +155.76096234403798,-889.2492977967378,13475.470561874661,1955.0535223723712,356.4450994756727,25.894952980042156,1.5695032905781554,-11.181939564328772,214.80884394039484,3169.1640829158237,-11443.321309975563,-1765.1588461316153,-251.68908574481912,-15.49755935939164,.198912367379658,1.847759065022573,-.7912582233652842,37.39369355329111,119.699486012458,-1151.0956593239027,13380.446257078214,1970.3952110853447,348.01959814116185,24.731487364283044,1.3850130831637748,-16.421408865300393,161.05030052864092, +2878.3322807850063,-11838.991423510031,-1823.985884688674,-268.2854986386903,-16.81724543849939,.1483359875383474,1.913880671464418,-.7960642926861912,35.2322109610459,80.01928065061526,-1424.0212633405113,13235.794061869668,1973.804052543835,337.9908651258184,23.289159354463873,1.3934255946442087,-21.099669467133474,108.48348407242611,2583.700758091299,-12199.726194855148,-1874.2780658979746,-284.2467154529415,-18.11369784385905,.09849140335716425,1.961570560806461,-.998795456205172,32.56307803611191, +36.958364584370486,-1706.075448829146,13043.287458812016,1965.3831106103316,326.43182772364605,22.175018750622293,1.198638339011324,-25.371248002043963,57.53505923036915,2288.41886619975,-12522.674544337233,-1914.8400385312243,-299.26241273417224,-19.37805630698734,.04912684976946725,1.990369453344394,.0178904535*X.SQRT2/2.384E-6,.008938074*X.SQRT2/2.384E-6,.0015673635*X.SQRT2/2.384E-6,.001228571*X.SQRT2/2.384E-6,4.856585E-4*X.SQRT2/2.384E-6,1.09434E-4*X.SQRT2/2.384E-6,5.0783E-5*X.SQRT2/2.384E-6, +6.914E-6*X.SQRT2/2.384E-6,12804.797818791945,1945.5515939597317,313.4244966442953,20.801593959731544,1995.1556208053692,9.000838926174497,-29.20218120805369],q=[[2.382191739347913E-13,6.423305872147834E-13,9.400849094049688E-13,1.122435026096556E-12,1.183840321267481E-12,1.122435026096556E-12,9.40084909404969E-13,6.423305872147839E-13,2.382191739347918E-13,5.456116108943412E-12,4.878985199565852E-12,4.240448995017367E-12,3.559909094758252E-12,2.858043359288075E-12,2.156177623817898E-12,1.475637723558783E-12, +8.371015190102974E-13,2.599706096327376E-13,-5.456116108943412E-12,-4.878985199565852E-12,-4.240448995017367E-12,-3.559909094758252E-12,-2.858043359288076E-12,-2.156177623817898E-12,-1.475637723558783E-12,-8.371015190102975E-13,-2.599706096327376E-13,-2.382191739347923E-13,-6.423305872147843E-13,-9.400849094049696E-13,-1.122435026096556E-12,-1.183840321267481E-12,-1.122435026096556E-12,-9.400849094049694E-13,-6.42330587214784E-13,-2.382191739347918E-13],[2.382191739347913E-13,6.423305872147834E-13, +9.400849094049688E-13,1.122435026096556E-12,1.183840321267481E-12,1.122435026096556E-12,9.400849094049688E-13,6.423305872147841E-13,2.382191739347918E-13,5.456116108943413E-12,4.878985199565852E-12,4.240448995017367E-12,3.559909094758253E-12,2.858043359288075E-12,2.156177623817898E-12,1.475637723558782E-12,8.371015190102975E-13,2.599706096327376E-13,-5.461314069809755E-12,-4.921085770524055E-12,-4.343405037091838E-12,-3.732668368707687E-12,-3.093523840190885E-12,-2.430835727329465E-12,-1.734679010007751E-12, +-9.74825365660928E-13,-2.797435120168326E-13,0,0,0,0,0,0,-2.283748241799531E-13,-4.037858874020686E-13,-2.146547464825323E-13],[.1316524975873958,.414213562373095,.7673269879789602,1.091308501069271,1.303225372841206,1.56968557711749,1.920982126971166,2.414213562373094,3.171594802363212,4.510708503662055,7.595754112725146,22.90376554843115,.984807753012208,.6427876096865394,.3420201433256688,.9396926207859084,-.1736481776669303,-.7660444431189779,.8660254037844387,.5,-.5144957554275265,-.4717319685649723, +-.3133774542039019,-.1819131996109812,-.09457419252642064,-.04096558288530405,-.01419856857247115,-.003699974673760037,.8574929257125442,.8817419973177052,.9496286491027329,.9833145924917901,.9955178160675857,.9991605581781475,.999899195244447,.9999931550702802],[0,0,0,0,0,0,2.283748241799531E-13,4.037858874020686E-13,2.146547464825323E-13,5.461314069809755E-12,4.921085770524055E-12,4.343405037091838E-12,3.732668368707687E-12,3.093523840190885E-12,2.430835727329466E-12,1.734679010007751E-12,9.74825365660928E-13, +2.797435120168326E-13,-5.456116108943413E-12,-4.878985199565852E-12,-4.240448995017367E-12,-3.559909094758253E-12,-2.858043359288075E-12,-2.156177623817898E-12,-1.475637723558782E-12,-8.371015190102975E-13,-2.599706096327376E-13,-2.382191739347913E-13,-6.423305872147834E-13,-9.400849094049688E-13,-1.122435026096556E-12,-1.183840321267481E-12,-1.122435026096556E-12,-9.400849094049688E-13,-6.423305872147841E-13,-2.382191739347918E-13]],C=q[d.SHORT_TYPE],B=q[d.SHORT_TYPE],t=q[d.SHORT_TYPE],M=q[d.SHORT_TYPE], +g=[0,1,16,17,8,9,24,25,4,5,20,21,12,13,28,29,2,3,18,19,10,11,26,27,6,7,22,23,14,15,30,31];this.mdct_sub48=function(b,k,a){for(var h=286,D=0;D<b.channels_out;D++){for(var e=0;e<b.mode_gr;e++){for(var n,c=b.l3_side.tt[e][D],f=c.xr,E=0,z=b.sb_sample[D][1-e],w=0,A=0;9>A;A++)for(r(k,h,z[w]),r(k,h+32,z[w+1]),w+=2,h+=64,n=1;32>n;n+=2)z[w-1][n]*=-1;for(n=0;32>n;n++,E+=18){var z=c.block_type,w=b.sb_sample[D][e],v=b.sb_sample[D][1-e];0!=c.mixed_block_flag&&2>n&&(z=0);if(1E-12>b.amp_filter[n])Ia.fill(f,E+0, +E+18,0);else{if(1>b.amp_filter[n])for(A=0;18>A;A++)v[A][g[n]]*=b.amp_filter[n];if(z==d.SHORT_TYPE){for(A=-3;0>A;A++){var p=q[d.SHORT_TYPE][A+3];f[E+3*A+9]=w[9+A][g[n]]*p-w[8-A][g[n]];f[E+3*A+18]=w[14-A][g[n]]*p+w[15+A][g[n]];f[E+3*A+10]=w[15+A][g[n]]*p-w[14-A][g[n]];f[E+3*A+19]=v[2-A][g[n]]*p+v[3+A][g[n]];f[E+3*A+11]=v[3+A][g[n]]*p-v[2-A][g[n]];f[E+3*A+20]=v[8-A][g[n]]*p+v[9+A][g[n]]}A=f;w=E;for(p=0;3>p;p++){var m,x,y,W,u;y=A[w+6]*q[d.SHORT_TYPE][0]-A[w+15];v=A[w+0]*q[d.SHORT_TYPE][2]-A[w+9];m=y+ +v;x=y-v;y=A[w+15]*q[d.SHORT_TYPE][0]+A[w+6];v=A[w+9]*q[d.SHORT_TYPE][2]+A[w+0];W=y+v;u=-y+v;v=2.069978111953089E-11*(A[w+3]*q[d.SHORT_TYPE][1]-A[w+12]);y=2.069978111953089E-11*(A[w+12]*q[d.SHORT_TYPE][1]+A[w+3]);A[w+0]=1.90752519173728E-11*m+v;A[w+15]=1.90752519173728E-11*-W+y;x*=1.6519652744032674E-11;W=9.537625958686404E-12*W+y;A[w+3]=x-W;A[w+6]=x+W;m=9.537625958686404E-12*m-v;u*=1.6519652744032674E-11;A[w+9]=m+u;A[w+12]=m-u;w++}}else{p=H(18);for(A=-9;0>A;A++)m=q[z][A+27]*v[A+9][g[n]]+q[z][A+36]* +v[8-A][g[n]],x=q[z][A+9]*w[A+9][g[n]]-q[z][A+18]*w[8-A][g[n]],p[A+9]=m-x*C[3+A+9],p[A+18]=m*C[3+A+9]+x;var A=f,w=E,pa=u=W=y=x=m=v=void 0,la=void 0,F=void 0,G=void 0;x=p[17]-p[9];W=p[15]-p[11];u=p[14]-p[12];pa=p[0]+p[8];la=p[1]+p[7];F=p[2]+p[6];G=p[3]+p[5];A[w+17]=pa+F-G-(la-p[4]);m=(pa+F-G)*B[19]+(la-p[4]);v=(x-W-u)*B[18];A[w+5]=v+m;A[w+6]=v-m;y=(p[16]-p[10])*B[18];la=la*B[19]+p[4];v=x*B[12]+y+W*B[13]+u*B[14];m=-pa*B[16]+la-F*B[17]+G*B[15];A[w+1]=v+m;A[w+2]=v-m;v=x*B[13]-y-W*B[14]+u*B[12];m=-pa*B[17]+ +la-F*B[15]+G*B[16];A[w+9]=v+m;A[w+10]=v-m;v=x*B[14]-y+W*B[12]-u*B[13];m=pa*B[15]-la+F*B[16]-G*B[17];A[w+13]=v+m;A[w+14]=v-m;G=F=la=pa=u=W=y=x=void 0;x=p[8]-p[0];W=p[6]-p[2];u=p[5]-p[3];pa=p[17]+p[9];la=p[16]+p[10];F=p[15]+p[11];G=p[14]+p[12];A[w+0]=pa+F+G+(la+p[13]);v=(pa+F+G)*B[19]-(la+p[13]);m=(x-W+u)*B[18];A[w+11]=v+m;A[w+12]=v-m;y=(p[7]-p[1])*B[18];la=p[13]-la*B[19];v=pa*B[15]-la+F*B[16]+G*B[17];m=x*B[14]+y+W*B[12]+u*B[13];A[w+3]=v+m;A[w+4]=v-m;v=-pa*B[17]+la-F*B[15]-G*B[16];m=x*B[13]+y-W*B[14]- +u*B[12];A[w+7]=v+m;A[w+8]=v-m;v=-pa*B[16]+la-F*B[17]-G*B[15];m=x*B[12]-y+W*B[13]-u*B[14];A[w+15]=v+m;A[w+16]=v-m}}if(z!=d.SHORT_TYPE&&0!=n)for(A=7;0<=A;--A)z=f[E+A]*t[20+A]+f[E+-1-A]*M[28+A],w=f[E+A]*M[28+A]-f[E+-1-A]*t[20+A],f[E+-1-A]=z,f[E+A]=w}}k=a;h=286;if(1==b.mode_gr)for(e=0;18>e;e++)K.arraycopy(b.sb_sample[D][1][e],0,b.sb_sample[D][0][e],0,32)}}}function d(){var r=d.FFTOFFSET,k=d.MPG_MD_MS_LR,q=null,C=this.psy=null,B=null,t=null;this.setModules=function(d,b,k,a){q=d;C=this.psy=b;B=a;t=k};var ta= +new Pc;this.lame_encode_mp3_frame=function(g,b,l,a,h,D){var e=Zb([2,2]);e[0][0]=new Qa;e[0][1]=new Qa;e[1][0]=new Qa;e[1][1]=new Qa;var n=Zb([2,2]);n[0][0]=new Qa;n[0][1]=new Qa;n[1][0]=new Qa;n[1][1]=new Qa;var c=[null,null],f=g.internal_flags,E=ra([2,4]),z=[.5,.5],w=[[0,0],[0,0]],A=[[0,0],[0,0]];c[0]=b;c[1]=l;if(0==f.lame_encode_frame_init){b=g.internal_flags;var v,p;if(0==b.lame_encode_frame_init){l=H(2014);var m=H(2014);b.lame_encode_frame_init=1;for(p=v=0;v<286+576*(1+b.mode_gr);++v)v<576*b.mode_gr? +(l[v]=0,2==b.channels_out&&(m[v]=0)):(l[v]=c[0][p],2==b.channels_out&&(m[v]=c[1][p]),++p);for(p=0;p<b.mode_gr;p++)for(v=0;v<b.channels_out;v++)b.l3_side.tt[p][v].block_type=d.SHORT_TYPE;ta.mdct_sub48(b,l,m)}}f.padding=0;0>(f.slot_lag-=f.frac_SpF)&&(f.slot_lag+=g.out_samplerate,f.padding=1);if(0!=f.psymodel)for(m=[null,null],v=0,p=Y(2),l=0;l<f.mode_gr;l++){for(b=0;b<f.channels_out;b++)m[b]=c[b],v=576+576*l-d.FFTOFFSET;b=g.VBR==M.vbr_mtrh||g.VBR==M.vbr_mt?C.L3psycho_anal_vbr(g,m,v,l,e,n,w[l],A[l],E[l], +p):C.L3psycho_anal_ns(g,m,v,l,e,n,w[l],A[l],E[l],p);if(0!=b)return-4;g.mode==ka.JOINT_STEREO&&(z[l]=E[l][2]+E[l][3],0<z[l]&&(z[l]=E[l][3]/z[l]));for(b=0;b<f.channels_out;b++){var x=f.l3_side.tt[l][b];x.block_type=p[b];x.mixed_block_flag=0}}else for(l=0;l<f.mode_gr;l++)for(b=0;b<f.channels_out;b++)f.l3_side.tt[l][b].block_type=d.NORM_TYPE,f.l3_side.tt[l][b].mixed_block_flag=0,A[l][b]=w[l][b]=700;0==f.ATH.useAdjust?f.ATH.adjust=1:(b=f.loudness_sq[0][0],E=f.loudness_sq[1][0],2==f.channels_out?(b+=f.loudness_sq[0][1], +E+=f.loudness_sq[1][1]):(b+=b,E+=E),2==f.mode_gr&&(b=Math.max(b,E)),b=.5*b*f.ATH.aaSensitivityP,.03125<b?(1<=f.ATH.adjust?f.ATH.adjust=1:f.ATH.adjust<f.ATH.adjustLimit&&(f.ATH.adjust=f.ATH.adjustLimit),f.ATH.adjustLimit=1):(E=31.98*b+6.25E-4,f.ATH.adjust>=E?(f.ATH.adjust*=.075*E+.925,f.ATH.adjust<E&&(f.ATH.adjust=E)):f.ATH.adjustLimit>=E?f.ATH.adjust=E:f.ATH.adjust<f.ATH.adjustLimit&&(f.ATH.adjust=f.ATH.adjustLimit),f.ATH.adjustLimit=E));ta.mdct_sub48(f,c[0],c[1]);f.mode_ext=d.MPG_MD_LR_LR;if(g.force_ms)f.mode_ext= +d.MPG_MD_MS_LR;else if(g.mode==ka.JOINT_STEREO){for(l=m=E=0;l<f.mode_gr;l++)for(b=0;b<f.channels_out;b++)E+=A[l][b],m+=w[l][b];E<=1*m&&(E=f.l3_side.tt[0],b=f.l3_side.tt[f.mode_gr-1],E[0].block_type==E[1].block_type&&b[0].block_type==b[1].block_type&&(f.mode_ext=d.MPG_MD_MS_LR))}f.mode_ext==k&&(e=n,w=A);if(g.analysis&&null!=f.pinfo)for(l=0;l<f.mode_gr;l++)for(b=0;b<f.channels_out;b++)f.pinfo.ms_ratio[l]=f.ms_ratio[l],f.pinfo.ms_ener_ratio[l]=z[l],f.pinfo.blocktype[l][b]=f.l3_side.tt[l][b].block_type, +f.pinfo.pe[l][b]=w[l][b],K.arraycopy(f.l3_side.tt[l][b].xr,0,f.pinfo.xr[l][b],0,576),f.mode_ext==k&&(f.pinfo.ers[l][b]=f.pinfo.ers[l][b+2],K.arraycopy(f.pinfo.energy[l][b+2],0,f.pinfo.energy[l][b],0,f.pinfo.energy[l][b].length));if(g.VBR==M.vbr_off||g.VBR==M.vbr_abr){for(n=0;18>n;n++)f.nsPsy.pefirbuf[n]=f.nsPsy.pefirbuf[n+1];for(l=A=0;l<f.mode_gr;l++)for(b=0;b<f.channels_out;b++)A+=w[l][b];f.nsPsy.pefirbuf[18]=A;A=f.nsPsy.pefirbuf[9];for(n=0;9>n;n++)A+=(f.nsPsy.pefirbuf[n]+f.nsPsy.pefirbuf[18-n])* +d.fircoef[n];A=3350*f.mode_gr*f.channels_out/A;for(l=0;l<f.mode_gr;l++)for(b=0;b<f.channels_out;b++)w[l][b]*=A}f.iteration_loop.iteration_loop(g,w,z,e);q.format_bitstream(g);a=q.copy_buffer(f,a,h,D,1);g.bWriteVbrTag&&B.addVbrFrame(g);if(g.analysis&&null!=f.pinfo){for(b=0;b<f.channels_out;b++){for(h=0;h<r;h++)f.pinfo.pcmdata[b][h]=f.pinfo.pcmdata[b][h+g.framesize];for(h=r;1600>h;h++)f.pinfo.pcmdata[b][h]=c[b][h-r]}t.set_frame_pinfo(g,e)}f.bitrate_stereoMode_Hist[f.bitrate_index][4]++;f.bitrate_stereoMode_Hist[15][4]++; +2==f.channels_out&&(f.bitrate_stereoMode_Hist[f.bitrate_index][f.mode_ext]++,f.bitrate_stereoMode_Hist[15][f.mode_ext]++);for(g=0;g<f.mode_gr;++g)for(c=0;c<f.channels_out;++c)h=f.l3_side.tt[g][c].block_type|0,0!=f.l3_side.tt[g][c].mixed_block_flag&&(h=4),f.bitrate_blockType_Hist[f.bitrate_index][h]++,f.bitrate_blockType_Hist[f.bitrate_index][5]++,f.bitrate_blockType_Hist[15][h]++,f.bitrate_blockType_Hist[15][5]++;return a}}function Qc(){this.size=this.pos=this.want=this.seen=this.sum=0;this.bag=null; +this.TotalFrameSize=this.nBytesWritten=this.nVbrNumFrames=0}function Rc(){this.tt=[[null,null],[null,null]];this.resvDrain_post=this.resvDrain_pre=this.private_bits=this.main_data_begin=0;this.scfsi=[Y(4),Y(4)];for(var d=0;2>d;d++)for(var k=0;2>k;k++)this.tt[d][k]=new Ab}function Sc(){this.last_en_subshort=ra([4,9]);this.lastAttacks=Y(4);this.pefirbuf=H(19);this.longfact=H(d.SBMAX_l);this.shortfact=H(d.SBMAX_s);this.attackthre_s=this.attackthre=0}function ic(){this.l=H(d.SBMAX_l);this.s=ra([d.SBMAX_s, +3]);var r=this;this.assign=function(k){K.arraycopy(k.l,0,r.l,0,d.SBMAX_l);for(var q=0;q<d.SBMAX_s;q++)for(var C=0;3>C;C++)r.s[q][C]=k.s[q][C]}}function da(){function r(){this.ptr=this.write_timing=0;this.buf=new Int8Array(40)}this.fill_buffer_resample_init=this.iteration_init_init=this.lame_encode_frame_init=this.Class_ID=0;this.mfbuf=ra([2,da.MFSIZE]);this.full_outer_loop=this.use_best_huffman=this.subblock_gain=this.noise_shaping_stop=this.psymodel=this.substep_shaping=this.noise_shaping_amp=this.noise_shaping= +this.highpass2=this.highpass1=this.lowpass2=this.lowpass1=this.mode_ext=this.samplerate_index=this.bitrate_index=this.VBR_max_bitrate=this.VBR_min_bitrate=this.mf_size=this.mf_samples_to_encode=this.resample_ratio=this.channels_out=this.channels_in=this.mode_gr=0;this.l3_side=new Rc;this.ms_ratio=H(2);this.slot_lag=this.frac_SpF=this.padding=0;this.tag_spec=null;this.nMusicCRC=0;this.OldValue=Y(2);this.CurrentStep=Y(2);this.masking_lower=0;this.bv_scf=Y(576);this.pseudohalf=Y(na.SFBMAX);this.sfb21_extra= +!1;this.inbuf_old=Array(2);this.blackfilt=Array(2*da.BPC+1);this.itime=new Float64Array(2);this.sideinfo_len=0;this.sb_sample=ra([2,2,18,d.SBLIMIT]);this.amp_filter=H(32);this.header=Array(da.MAX_HEADER_BUF);this.ResvMax=this.ResvSize=this.ancillary_flag=this.w_ptr=this.h_ptr=0;this.scalefac_band=new ha;this.minval_l=H(d.CBANDS);this.minval_s=H(d.CBANDS);this.nb_1=ra([4,d.CBANDS]);this.nb_2=ra([4,d.CBANDS]);this.nb_s1=ra([4,d.CBANDS]);this.nb_s2=ra([4,d.CBANDS]);this.s3_ll=this.s3_ss=null;this.decay= +0;this.thm=Array(4);this.en=Array(4);this.tot_ener=H(4);this.loudness_sq=ra([2,2]);this.loudness_sq_save=H(2);this.mld_l=H(d.SBMAX_l);this.mld_s=H(d.SBMAX_s);this.bm_l=Y(d.SBMAX_l);this.bo_l=Y(d.SBMAX_l);this.bm_s=Y(d.SBMAX_s);this.bo_s=Y(d.SBMAX_s);this.npart_s=this.npart_l=0;this.s3ind=db([d.CBANDS,2]);this.s3ind_s=db([d.CBANDS,2]);this.numlines_s=Y(d.CBANDS);this.numlines_l=Y(d.CBANDS);this.rnumlines_l=H(d.CBANDS);this.mld_cb_l=H(d.CBANDS);this.mld_cb_s=H(d.CBANDS);this.numlines_l_num1=this.numlines_s_num1= +0;this.pe=H(4);this.ms_ener_ratio_old=this.ms_ratio_l_old=this.ms_ratio_s_old=0;this.blocktype_old=Y(2);this.nsPsy=new Sc;this.VBR_seek_table=new Qc;this.PSY=this.ATH=null;this.nogap_current=this.nogap_total=0;this.findPeakSample=this.findReplayGain=this.decode_on_the_fly=!0;this.AudiophileGain=this.RadioGain=this.PeakSample=0;this.rgdata=null;this.noclipScale=this.noclipGainChange=0;this.bitrate_stereoMode_Hist=db([16,5]);this.bitrate_blockType_Hist=db([16,6]);this.hip=this.pinfo=null;this.in_buffer_nsamples= +0;this.iteration_loop=this.in_buffer_1=this.in_buffer_0=null;for(var k=0;k<this.en.length;k++)this.en[k]=new ic;for(k=0;k<this.thm.length;k++)this.thm[k]=new ic;for(k=0;k<this.header.length;k++)this.header[k]=new r}function Tc(){function r(d,k,g){var b=0,l,a,h;g<<=1;var q=k+g;l=4;do{var e,n,c,f,B,z,w;w=l>>1;f=l;B=l<<1;z=B+f;l=B<<1;a=k;h=a+w;do{var A,v,p,m;v=d[a+0]-d[a+f];A=d[a+0]+d[a+f];m=d[a+B]-d[a+z];p=d[a+B]+d[a+z];d[a+B]=A-p;d[a+0]=A+p;d[a+z]=v-m;d[a+f]=v+m;v=d[h+0]-d[h+f];A=d[h+0]+d[h+f];m=X.SQRT2* +d[h+z];p=X.SQRT2*d[h+B];d[h+B]=A-p;d[h+0]=A+p;d[h+z]=v-m;d[h+f]=v+m;h+=l;a+=l}while(a<q);n=C[b+0];e=C[b+1];for(c=1;c<w;c++){var x,y;x=1-2*e*e;y=2*e*n;a=k+c;h=k+f-c;do{var W,u,J,H,F;W=y*d[a+f]-x*d[h+f];p=x*d[a+f]+y*d[h+f];v=d[a+0]-p;A=d[a+0]+p;J=d[h+0]-W;u=d[h+0]+W;W=y*d[a+z]-x*d[h+z];p=x*d[a+z]+y*d[h+z];m=d[a+B]-p;p=d[a+B]+p;F=d[h+B]-W;H=d[h+B]+W;W=e*p-n*F;p=n*p+e*F;d[a+B]=A-p;d[a+0]=A+p;d[h+z]=J-W;d[h+f]=J+W;W=n*H-e*m;p=e*H+n*m;d[h+B]=u-p;d[h+0]=u+p;d[a+z]=v-W;d[a+f]=v+W;h+=l;a+=l}while(a<q);x=n; +n=x*C[b+0]-e*C[b+1];e=x*C[b+1]+e*C[b+0]}b+=2}while(l<g)}var k=H(d.BLKSIZE),q=H(d.BLKSIZE_s/2),C=[.9238795325112867,.3826834323650898,.9951847266721969,.0980171403295606,.9996988186962042,.02454122852291229,.9999811752826011,.006135884649154475],B=[0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226, +18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254];this.fft_short=function(k,C,g,b,l){for(k=0;3>k;k++){var a=d.BLKSIZE_s/2,h=65535&192*(k+1),D=d.BLKSIZE_s/8-1;do{var e,n,c,f,E,z=B[D<<2]&255;e=q[z]*b[g][l+z+h];E=q[127-z]*b[g][l+z+h+128];n=e-E;e+=E;c=q[z+64]*b[g][l+z+h+64];E=q[63-z]*b[g][l+z+h+192];f=c-E;c+=E;a-=4;C[k][a+0]=e+c;C[k][a+2]=e-c;C[k][a+ +1]=n+f;C[k][a+3]=n-f;e=q[z+1]*b[g][l+z+h+1];E=q[126-z]*b[g][l+z+h+129];n=e-E;e+=E;c=q[z+65]*b[g][l+z+h+65];E=q[62-z]*b[g][l+z+h+193];f=c-E;c+=E;C[k][a+d.BLKSIZE_s/2+0]=e+c;C[k][a+d.BLKSIZE_s/2+2]=e-c;C[k][a+d.BLKSIZE_s/2+1]=n+f;C[k][a+d.BLKSIZE_s/2+3]=n-f}while(0<=--D);r(C[k],a,d.BLKSIZE_s/2)}};this.fft_long=function(q,C,g,b,l){q=d.BLKSIZE/8-1;var a=d.BLKSIZE/2;do{var h,D,e,n,c,f=B[q]&255;h=k[f]*b[g][l+f];c=k[f+512]*b[g][l+f+512];D=h-c;h+=c;e=k[f+256]*b[g][l+f+256];c=k[f+768]*b[g][l+f+768];n=e-c; +e+=c;a-=4;C[a+0]=h+e;C[a+2]=h-e;C[a+1]=D+n;C[a+3]=D-n;h=k[f+1]*b[g][l+f+1];c=k[f+513]*b[g][l+f+513];D=h-c;h+=c;e=k[f+257]*b[g][l+f+257];c=k[f+769]*b[g][l+f+769];n=e-c;e+=c;C[a+d.BLKSIZE/2+0]=h+e;C[a+d.BLKSIZE/2+2]=h-e;C[a+d.BLKSIZE/2+1]=D+n;C[a+d.BLKSIZE/2+3]=D-n}while(0<=--q);r(C,a,d.BLKSIZE/2)};this.init_fft=function(r){for(r=0;r<d.BLKSIZE;r++)k[r]=.42-.5*Math.cos(2*Math.PI*(r+.5)/d.BLKSIZE)+.08*Math.cos(4*Math.PI*(r+.5)/d.BLKSIZE);for(r=0;r<d.BLKSIZE_s/2;r++)q[r]=.5*(1-Math.cos(2*Math.PI*(r+.5)/ +d.BLKSIZE_s))}}function jc(){function r(a,c){for(var b=0,m=0;m<d.BLKSIZE/2;++m)b+=a[m]*c.ATH.eql_w[m];return b*=z}function k(a,d,c,b,g,f){var e;if(d>a)if(d<a*A)e=d/a;else return a+d;else{if(a>=d*A)return a+d;e=a/d}a+=d;if(6>=b+3){if(e>=w)return a;b=0|X.FAST_LOG10_X(e,16);return a*x[b]}b=0|X.FAST_LOG10_X(e,16);d=0!=f?g.ATH.cb_s[c]*g.ATH.adjust:g.ATH.cb_l[c]*g.ATH.adjust;return a<v*d?a>d?(c=1,13>=b&&(c=y[b]),d=X.FAST_LOG10_X(a/d,10/15),a*((m[b]-c)*d+c)):13<b?a:a*y[b]:a*m[b]}function q(a,d,c){var b; +0>a&&(a=0);0>d&&(d=0);if(0>=a)return d;if(0>=d)return a;b=d>a?d/a:a/d;if(-2<=c&&2>=c){if(b>=w)return a+d;c=0|X.FAST_LOG10_X(b,16);return(a+d)*W[c]}if(b<A)return a+d;a<d&&(a=d);return a}function C(a,c,b,m,g){var f,e,k=0,h=0;for(f=e=0;f<d.SBMAX_s;++e,++f){for(var l=a.bo_s[f],n=a.npart_s,l=l<n?l:n;e<l;)k+=c[e],h+=b[e],e++;a.en[m].s[f][g]=k;a.thm[m].s[f][g]=h;if(e>=n){++f;break}h=a.PSY.bo_s_weight[f];n=1-h;k=h*c[e];h*=b[e];a.en[m].s[f][g]+=k;a.thm[m].s[f][g]+=h;k=n*c[e];h=n*b[e]}for(;f<d.SBMAX_s;++f)a.en[m].s[f][g]= +0,a.thm[m].s[f][g]=0}function B(a,c,b,m){var g,f,e=0,k=0;for(g=f=0;g<d.SBMAX_l;++f,++g){for(var h=a.bo_l[g],l=a.npart_l,h=h<l?h:l;f<h;)e+=c[f],k+=b[f],f++;a.en[m].l[g]=e;a.thm[m].l[g]=k;if(f>=l){++g;break}k=a.PSY.bo_l_weight[g];l=1-k;e=k*c[f];k*=b[f];a.en[m].l[g]+=e;a.thm[m].l[g]+=k;e=l*c[f];k=l*b[f]}for(;g<d.SBMAX_l;++g)a.en[m].l[g]=0,a.thm[m].l[g]=0}function t(a,d,c){return 1<=c?a:0>=c?d:0<d?Math.pow(a/d,c)*d:0}function V(a,c){for(var b=309.07,m=0;m<d.SBMAX_s-1;m++)for(var g=0;3>g;g++){var f=a.thm.s[m][g]; +if(0<f){var f=f*c,e=a.en.s[m][g];e>f&&(b=e>1E10*f?b+23.02585092994046*u[m]:b+u[m]*X.FAST_LOG10(e/f))}}return b}function g(a,c){for(var b=281.0575,m=0;m<d.SBMAX_l-1;m++){var g=a.thm.l[m];if(0<g){var g=g*c,f=a.en.l[m];f>g&&(b=f>1E10*g?b+23.02585092994046*pa[m]:b+pa[m]*X.FAST_LOG10(f/g))}}return b}function b(a,d,c,b,m){var g,f;for(g=f=0;g<a.npart_l;++g){var e=0,k=0,h;for(h=0;h<a.numlines_l[g];++h,++f){var l=d[f],e=e+l;k<l&&(k=l)}c[g]=e;b[g]=k;m[g]=e*a.rnumlines_l[g]}}function l(a,d,c,b){var m=p.length- +1,g=0,f=c[g]+c[g+1];if(0<f){var e=d[g];e<d[g+1]&&(e=d[g+1]);f=20*(2*e-f)/(f*(a.numlines_l[g]+a.numlines_l[g+1]-1));f|=0;f>m&&(f=m);b[g]=f}else b[g]=0;for(g=1;g<a.npart_l-1;g++)f=c[g-1]+c[g]+c[g+1],0<f?(e=d[g-1],e<d[g]&&(e=d[g]),e<d[g+1]&&(e=d[g+1]),f=20*(3*e-f)/(f*(a.numlines_l[g-1]+a.numlines_l[g]+a.numlines_l[g+1]-1)),f|=0,f>m&&(f=m),b[g]=f):b[g]=0;f=c[g-1]+c[g];0<f?(e=d[g-1],e<d[g]&&(e=d[g]),f=20*(2*e-f)/(f*(a.numlines_l[g-1]+a.numlines_l[g]-1)),f|=0,f>m&&(f=m),b[g]=f):b[g]=0}function a(a,d,c, +b,m,g,f){var e=2*g;m=0<g?Math.pow(10,m):1;for(var k,h,l=0;l<f;++l){var n=a[2][l],p=a[3][l],y=d[0][l],q=d[1][l],u=d[2][l],x=d[3][l];y<=1.58*q&&q<=1.58*y?(k=c[l]*n,h=Math.max(u,Math.min(x,c[l]*p)),k=Math.max(x,Math.min(u,k))):(h=u,k=x);0<g&&(x=b[l]*m,y=Math.min(Math.max(y,x),Math.max(q,x)),u=Math.max(h,x),x=Math.max(k,x),q=u+x,0<q&&y*e<q&&(y=y*e/q,u*=y,x*=y),h=Math.min(u,h),k=Math.min(x,k));h>n&&(h=n);k>p&&(k=p);d[2][l]=h;d[3][l]=k}}function h(a,d){var c;c=0<=a?27*-a:a*d;return-72>=c?0:Math.exp(.2302585093* +c)}function D(a){0>a&&(a=0);a*=.001;return 13*Math.atan(.76*a)+3.5*Math.atan(a*a/56.25)}function e(a,c,b,m,g,f,e,k,h,l,n,p){var y=H(d.CBANDS+1),q=k/(15<p?1152:384),u=Y(d.HBLKSIZE),x;k/=h;var r=0,v=0;for(x=0;x<d.CBANDS;x++){var t,w;t=D(k*r);y[x]=k*r;for(w=r;.34>D(k*w)-t&&w<=h/2;w++);a[x]=w-r;for(v=x+1;r<w;)u[r++]=x;if(r>h/2){r=h/2;++x;break}}y[x]=k*r;for(r=0;r<p;r++)x=l[r],t=l[r+1],x=0|Math.floor(.5+n*(x-.5)),0>x&&(x=0),w=0|Math.floor(.5+n*(t-.5)),w>h/2&&(w=h/2),b[r]=(u[x]+u[w])/2,c[r]=u[w],e[r]=(q* +t-y[c[r]])/(y[c[r]+1]-y[c[r]]),0>e[r]?e[r]=0:1<e[r]&&(e[r]=1),t=D(k*l[r]*n),t=Math.min(t,15.5)/15.5,f[r]=Math.pow(10,1.25*(1-Math.cos(Math.PI*t))-2.5);for(c=r=0;c<v;c++)b=a[c],t=D(k*r),f=D(k*(r+b-1)),m[c]=.5*(t+f),t=D(k*(r-.5)),f=D(k*(r+b-.5)),g[c]=f-t,r+=b;return v}function n(a,c,b,m,g,f){var e=ra([d.CBANDS,d.CBANDS]),k=0;if(f)for(var l=0;l<c;l++)for(f=0;f<c;f++){var n;var y=n=void 0,y=n=void 0;n=b[l]-b[f];n=0<=n?3*n:1.5*n;.5<=n&&2.5>=n?(y=n-.5,y=8*(y*y-2*y)):y=0;n+=.474;n=15.811389+7.5*n-17.5*Math.sqrt(1+ +n*n);-60>=n?n=0:(n=Math.exp(.2302585093*(y+n)),n/=.6609193);y=n*m[f];e[l][f]=y*g[l]}else for(f=0;f<c;f++){n=15+Math.min(21/b[f],12);var p;var l=n,q=y=0;p=0;var u=q=void 0;for(p=0;1E-20<h(p,l);--p);q=p;for(u=0;1E-12<Math.abs(u-q);)p=(u+q)/2,0<h(p,l)?u=p:q=p;y=q;for(p=0;1E-20<h(p,l);p+=1);q=0;for(u=p;1E-12<Math.abs(u-q);)p=(u+q)/2,0<h(p,l)?q=p:u=p;for(var q=u,u=0,x=void 0,x=0;1E3>=x;++x)p=y+x*(q-y)/1E3,p=h(p,l),u+=p;p=1001/(u*(q-y));for(l=0;l<c;l++)y=p*h(b[l]-b[f],n)*m[f],e[l][f]=y*g[l]}for(l=0;l<c;l++){for(f= +0;f<c&&!(0<e[l][f]);f++);a[l][0]=f;for(f=c-1;0<f&&!(0<e[l][f]);f--);a[l][1]=f;k+=a[l][1]-a[l][0]+1}b=H(k);for(l=m=0;l<c;l++)for(f=a[l][0];f<=a[l][1];f++)b[m++]=e[l][f];return b}function c(a){a=D(a);a=Math.min(a,15.5)/15.5;return Math.pow(10,1.25*(1-Math.cos(Math.PI*a))-2.5)}function f(a,c){-.3>a&&(a=3410);a=Math.max(.1,a/1E3);return 3.64*Math.pow(a,-.8)-6.8*Math.exp(-.6*Math.pow(a-3.4,2))+6*Math.exp(-.15*Math.pow(a-8.7,2))+.001*(.6+.04*c)*Math.pow(a,4)}var E=new Tc,z=1/217621504/(d.BLKSIZE/2),w,A, +v,p=[1,.79433,.63096,.63096,.63096,.63096,.63096,.25119,.11749],m=[3.3246*3.3246,3.23837*3.23837,9.9500500969,9.0247369744,8.1854926609,7.0440875649,2.46209*2.46209,2.284*2.284,4.4892710641,1.96552*1.96552,1.82335*1.82335,1.69146*1.69146,2.4621061921,2.1508568964,1.37074*1.37074,1.31036*1.31036,1.5691069696,1.4555939904,1.16203*1.16203,1.2715945225,1.09428*1.09428,1.0659*1.0659,1.0779838276,1.0382591025,1],x=[1.7782755904,1.35879*1.35879,1.38454*1.38454,1.39497*1.39497,1.40548*1.40548,1.3537*1.3537, +1.6999465924,1.22321*1.22321,1.3169398564,1],y=[5.5396212496,2.29259*2.29259,4.9868695969,2.12675*2.12675,2.02545*2.02545,1.87894*1.87894,1.74303*1.74303,1.61695*1.61695,2.2499700001,1.39148*1.39148,1.29083*1.29083,1.19746*1.19746,1.2339655056,1.0779838276],W=[1.7782755904,1.35879*1.35879,1.38454*1.38454,1.39497*1.39497,1.40548*1.40548,1.3537*1.3537,1.6999465924,1.22321*1.22321,1.3169398564,1],u=[11.8,13.6,17.2,32,46.5,51.3,57.5,67.1,71.5,84.6,97.6,130],pa=[6.8,5.8,5.8,6.4,6.5,9.9,12.1,14.4,15,18.9, +21.6,26.9,34.2,40.2,46.8,56.5,60.7,73.9,85.7,93.4,126.1],la=[-1.730326E-17,-.01703172,-1.349528E-17,.0418072,-6.73278E-17,-.0876324,-3.0835E-17,.1863476,-1.104424E-16,-.627638];this.L3psycho_anal_ns=function(a,c,m,f,e,h,n,y,q,u){var x=a.internal_flags,v=ra([2,d.BLKSIZE]),w=ra([2,3,d.BLKSIZE_s]),F=H(d.CBANDS+1),z=H(d.CBANDS+1),A=H(d.CBANDS+2),W=Y(2),D=Y(2),pa,R,Fa,L,K,Z,Da,O,Q=ra([2,576]),P,da=Y(d.CBANDS+2),N=Y(d.CBANDS+2);Ia.fill(N,0);pa=x.channels_out;a.mode==ka.JOINT_STEREO&&(pa=4);P=a.VBR==M.vbr_off? +0==x.ResvMax?0:x.ResvSize/x.ResvMax*.5:a.VBR==M.vbr_rh||a.VBR==M.vbr_mtrh||a.VBR==M.vbr_mt?.6:1;for(R=0;R<x.channels_out;R++){var ua=c[R],ma=m+576-350-21+192;for(L=0;576>L;L++){var Ga,Sa;Ga=ua[ma+L+10];for(K=Sa=0;9>K;K+=2)Ga+=la[K]*(ua[ma+L+K]+ua[ma+L+21-K]),Sa+=la[K+1]*(ua[ma+L+K+1]+ua[ma+L+21-K-1]);Q[R][L]=Ga+Sa}e[f][R].en.assign(x.en[R]);e[f][R].thm.assign(x.thm[R]);2<pa&&(h[f][R].en.assign(x.en[R+2]),h[f][R].thm.assign(x.thm[R+2]))}for(R=0;R<pa;R++){var ea=H(12),Oa=[0,0,0,0],kc=H(12),na=1,Ca, +ha=H(d.CBANDS),Qa=H(d.CBANDS),va=[0,0,0,0],db=H(d.HBLKSIZE),fb=ra([3,d.HBLKSIZE_s]);for(L=0;3>L;L++)ea[L]=x.nsPsy.last_en_subshort[R][L+6],kc[L]=ea[L]/x.nsPsy.last_en_subshort[R][L+4],Oa[0]+=ea[L];if(2==R)for(L=0;576>L;L++){var eb,Gb;eb=Q[0][L];Gb=Q[1][L];Q[0][L]=eb+Gb;Q[1][L]=eb-Gb}var vb=Q[R&1],Hb=0;for(L=0;9>L;L++){for(var tb=Hb+64,Ta=1;Hb<tb;Hb++)Ta<Math.abs(vb[Hb])&&(Ta=Math.abs(vb[Hb]));x.nsPsy.last_en_subshort[R][L]=ea[L+3]=Ta;Oa[1+L/3]+=Ta;Ta=Ta>ea[L+3-2]?Ta/ea[L+3-2]:ea[L+3-2]>10*Ta?ea[L+ +3-2]/(10*Ta):0;kc[L+3]=Ta}if(a.analysis){var Pb=kc[0];for(L=1;12>L;L++)Pb<kc[L]&&(Pb=kc[L]);x.pinfo.ers[f][R]=x.pinfo.ers_save[R];x.pinfo.ers_save[R]=Pb}Ca=3==R?x.nsPsy.attackthre_s:x.nsPsy.attackthre;for(L=0;12>L;L++)0==va[L/3]&&kc[L]>Ca&&(va[L/3]=L%3+1);for(L=1;4>L;L++)1.7>(Oa[L-1]>Oa[L]?Oa[L-1]/Oa[L]:Oa[L]/Oa[L-1])&&(va[L]=0,1==L&&(va[0]=0));0!=va[0]&&0!=x.nsPsy.lastAttacks[R]&&(va[0]=0);if(3==x.nsPsy.lastAttacks[R]||0!=va[0]+va[1]+va[2]+va[3])na=0,0!=va[1]&&0!=va[0]&&(va[1]=0),0!=va[2]&&0!=va[1]&& +(va[2]=0),0!=va[3]&&0!=va[2]&&(va[3]=0);2>R?D[R]=na:0==na&&(D[0]=D[1]=0);q[R]=x.tot_ener[R];var S=a,Pa=db,Qb=fb,Ua=v,wb=R&1,Ya=w,Va=R&1,mb=f,Ja=R,za=c,ub=m,$a=S.internal_flags;if(2>Ja)E.fft_long($a,Ua[wb],Ja,za,ub),E.fft_short($a,Ya[Va],Ja,za,ub);else if(2==Ja){for(var fa=d.BLKSIZE-1;0<=fa;--fa){var Rb=Ua[wb+0][fa],Ib=Ua[wb+1][fa];Ua[wb+0][fa]=(Rb+Ib)*X.SQRT2*.5;Ua[wb+1][fa]=(Rb-Ib)*X.SQRT2*.5}for(var Ka=2;0<=Ka;--Ka)for(fa=d.BLKSIZE_s-1;0<=fa;--fa)Rb=Ya[Va+0][Ka][fa],Ib=Ya[Va+1][Ka][fa],Ya[Va+0][Ka][fa]= +(Rb+Ib)*X.SQRT2*.5,Ya[Va+1][Ka][fa]=(Rb-Ib)*X.SQRT2*.5}Pa[0]=Ua[wb+0][0];Pa[0]*=Pa[0];for(fa=d.BLKSIZE/2-1;0<=fa;--fa){var ac=Ua[wb+0][d.BLKSIZE/2-fa],Bb=Ua[wb+0][d.BLKSIZE/2+fa];Pa[d.BLKSIZE/2-fa]=.5*(ac*ac+Bb*Bb)}for(Ka=2;0<=Ka;--Ka)for(Qb[Ka][0]=Ya[Va+0][Ka][0],Qb[Ka][0]*=Qb[Ka][0],fa=d.BLKSIZE_s/2-1;0<=fa;--fa)ac=Ya[Va+0][Ka][d.BLKSIZE_s/2-fa],Bb=Ya[Va+0][Ka][d.BLKSIZE_s/2+fa],Qb[Ka][d.BLKSIZE_s/2-fa]=.5*(ac*ac+Bb*Bb);for(var Ea=0,fa=11;fa<d.HBLKSIZE;fa++)Ea+=Pa[fa];$a.tot_ener[Ja]=Ea;if(S.analysis){for(fa= +0;fa<d.HBLKSIZE;fa++)$a.pinfo.energy[mb][Ja][fa]=$a.pinfo.energy_save[Ja][fa],$a.pinfo.energy_save[Ja][fa]=Pa[fa];$a.pinfo.pe[mb][Ja]=$a.pe[Ja]}2==S.athaa_loudapprox&&2>Ja&&($a.loudness_sq[mb][Ja]=$a.loudness_sq_save[Ja],$a.loudness_sq_save[Ja]=r(Pa,$a));b(x,db,F,ha,Qa);l(x,ha,Qa,da);for(O=0;3>O;O++){for(var qc,Ba,gb=fb,hb=z,Sb=A,Jb=R,bc=O,aa=a.internal_flags,nb=void 0,oa=void 0,oa=nb=0;oa<aa.npart_s;++oa){for(var ab=0,lc=0,Ab=aa.numlines_s[oa],ib=0;ib<Ab;++ib,++nb){var rc=gb[bc][nb],ab=ab+rc;lc< +rc&&(lc=rc)}hb[oa]=ab}for(nb=oa=0;oa<aa.npart_s;oa++){var ob=aa.s3ind_s[oa][0],Cb=aa.s3_ss[nb++]*hb[ob];for(++ob;ob<=aa.s3ind_s[oa][1];)Cb+=aa.s3_ss[nb]*hb[ob],++nb,++ob;var Tb=2*aa.nb_s1[Jb][oa];Sb[oa]=Math.min(Cb,Tb);aa.blocktype_old[Jb&1]==d.SHORT_TYPE&&(Tb=16*aa.nb_s2[Jb][oa],Sb[oa]=Math.min(Tb,Sb[oa]));aa.nb_s2[Jb][oa]=aa.nb_s1[Jb][oa];aa.nb_s1[Jb][oa]=Cb}for(;oa<=d.CBANDS;++oa)hb[oa]=0,Sb[oa]=0;C(x,z,A,R,O);for(Da=0;Da<d.SBMAX_s;Da++){Ba=x.thm[R].s[Da][O];Ba*=.8;if(2<=va[O]||1==va[O+1]){var Kb= +0!=O?O-1:2,Ta=t(x.thm[R].s[Da][Kb],Ba,.6*P);Ba=Math.min(Ba,Ta)}if(1==va[O])Kb=0!=O?O-1:2,Ta=t(x.thm[R].s[Da][Kb],Ba,.3*P),Ba=Math.min(Ba,Ta);else if(0!=O&&3==va[O-1]||0==O&&3==x.nsPsy.lastAttacks[R])Kb=2!=O?O+1:0,Ta=t(x.thm[R].s[Da][Kb],Ba,.3*P),Ba=Math.min(Ba,Ta);qc=ea[3*O+3]+ea[3*O+4]+ea[3*O+5];6*ea[3*O+5]<qc&&(Ba*=.5,6*ea[3*O+4]<qc&&(Ba*=.5));x.thm[R].s[Da][O]=Ba}}x.nsPsy.lastAttacks[R]=va[2];for(Fa=Z=0;Fa<x.npart_l;Fa++){for(var pb=x.s3ind[Fa][0],Ub=F[pb]*p[da[pb]],qb=x.s3_ll[Z++]*Ub;++pb<=x.s3ind[Fa][1];)Ub= +F[pb]*p[da[pb]],qb=k(qb,x.s3_ll[Z++]*Ub,pb,pb-Fa,x,0);qb*=.158489319246111;A[Fa]=x.blocktype_old[R&1]==d.SHORT_TYPE?qb:t(Math.min(qb,Math.min(2*x.nb_1[R][Fa],16*x.nb_2[R][Fa])),qb,P);x.nb_2[R][Fa]=x.nb_1[R][Fa];x.nb_1[R][Fa]=qb}for(;Fa<=d.CBANDS;++Fa)F[Fa]=0,A[Fa]=0;B(x,F,A,R)}if((a.mode==ka.STEREO||a.mode==ka.JOINT_STEREO)&&0<a.interChRatio){var Db=a.interChRatio,ba=a.internal_flags;if(1<ba.channels_out){for(var La=0;La<d.SBMAX_l;La++){var cc=ba.thm[0].l[La],Lb=ba.thm[1].l[La];ba.thm[0].l[La]+=Lb* +Db;ba.thm[1].l[La]+=cc*Db}for(La=0;La<d.SBMAX_s;La++)for(var rb=0;3>rb;rb++)cc=ba.thm[0].s[La][rb],Lb=ba.thm[1].s[La][rb],ba.thm[0].s[La][rb]+=Lb*Db,ba.thm[1].s[La][rb]+=cc*Db}}if(a.mode==ka.JOINT_STEREO){for(var Wa,ga=0;ga<d.SBMAX_l;ga++)if(!(x.thm[0].l[ga]>1.58*x.thm[1].l[ga]||x.thm[1].l[ga]>1.58*x.thm[0].l[ga])){var Za=x.mld_l[ga]*x.en[3].l[ga],sb=Math.max(x.thm[2].l[ga],Math.min(x.thm[3].l[ga],Za)),Za=x.mld_l[ga]*x.en[2].l[ga],sc=Math.max(x.thm[3].l[ga],Math.min(x.thm[2].l[ga],Za));x.thm[2].l[ga]= +sb;x.thm[3].l[ga]=sc}for(ga=0;ga<d.SBMAX_s;ga++)for(var wa=0;3>wa;wa++)x.thm[0].s[ga][wa]>1.58*x.thm[1].s[ga][wa]||x.thm[1].s[ga][wa]>1.58*x.thm[0].s[ga][wa]||(Za=x.mld_s[ga]*x.en[3].s[ga][wa],sb=Math.max(x.thm[2].s[ga][wa],Math.min(x.thm[3].s[ga][wa],Za)),Za=x.mld_s[ga]*x.en[2].s[ga][wa],sc=Math.max(x.thm[3].s[ga][wa],Math.min(x.thm[2].s[ga][wa],Za)),x.thm[2].s[ga][wa]=sb,x.thm[3].s[ga][wa]=sc);Wa=a.msfix;if(0<Math.abs(Wa)){for(var Mb=Wa,mc=Mb,dc=Math.pow(10,a.ATHlower*x.ATH.adjust),Mb=2*Mb,mc=2* +mc,Aa=0;Aa<d.SBMAX_l;Aa++){var Vb,Ra,Ha,bb;bb=x.ATH.cb_l[x.bm_l[Aa]]*dc;Vb=Math.min(Math.max(x.thm[0].l[Aa],bb),Math.max(x.thm[1].l[Aa],bb));Ra=Math.max(x.thm[2].l[Aa],bb);Ha=Math.max(x.thm[3].l[Aa],bb);if(Vb*Mb<Ra+Ha){var ec=Vb*mc/(Ra+Ha);Ra*=ec;Ha*=ec}x.thm[2].l[Aa]=Math.min(Ra,x.thm[2].l[Aa]);x.thm[3].l[Aa]=Math.min(Ha,x.thm[3].l[Aa])}dc*=d.BLKSIZE_s/d.BLKSIZE;for(Aa=0;Aa<d.SBMAX_s;Aa++)for(var xa=0;3>xa;xa++)bb=x.ATH.cb_s[x.bm_s[Aa]]*dc,Vb=Math.min(Math.max(x.thm[0].s[Aa][xa],bb),Math.max(x.thm[1].s[Aa][xa], +bb)),Ra=Math.max(x.thm[2].s[Aa][xa],bb),Ha=Math.max(x.thm[3].s[Aa][xa],bb),Vb*Mb<Ra+Ha&&(ec=Vb*Mb/(Ra+Ha),Ra*=ec,Ha*=ec),x.thm[2].s[Aa][xa]=Math.min(x.thm[2].s[Aa][xa],Ra),x.thm[3].s[Aa][xa]=Math.min(x.thm[3].s[Aa][xa],Ha)}}var jb=a.internal_flags;a.short_blocks!=sa.short_block_coupled||0!=D[0]&&0!=D[1]||(D[0]=D[1]=0);for(var Na=0;Na<jb.channels_out;Na++)W[Na]=d.NORM_TYPE,a.short_blocks==sa.short_block_dispensed&&(D[Na]=1),a.short_blocks==sa.short_block_forced&&(D[Na]=0),0!=D[Na]?jb.blocktype_old[Na]== +d.SHORT_TYPE&&(W[Na]=d.STOP_TYPE):(W[Na]=d.SHORT_TYPE,jb.blocktype_old[Na]==d.NORM_TYPE&&(jb.blocktype_old[Na]=d.START_TYPE),jb.blocktype_old[Na]==d.STOP_TYPE&&(jb.blocktype_old[Na]=d.SHORT_TYPE)),u[Na]=jb.blocktype_old[Na],jb.blocktype_old[Na]=W[Na];for(R=0;R<pa;R++){var Wb,kb=0,ca,Eb;if(1<R){Wb=y;kb=-2;ca=d.NORM_TYPE;if(u[0]==d.SHORT_TYPE||u[1]==d.SHORT_TYPE)ca=d.SHORT_TYPE;Eb=h[f][R-2]}else Wb=n,kb=0,ca=u[R],Eb=e[f][R];Wb[kb+R]=ca==d.SHORT_TYPE?V(Eb,x.masking_lower):g(Eb,x.masking_lower);a.analysis&& +(x.pinfo.pe[f][R]=Wb[kb+R])}return 0};var F=[-1.730326E-17,-.01703172,-1.349528E-17,.0418072,-6.73278E-17,-.0876324,-3.0835E-17,.1863476,-1.104424E-16,-.627638];this.L3psycho_anal_vbr=function(c,m,f,e,k,h,n,x,y,u){for(var v=c.internal_flags,w,z,A=H(d.HBLKSIZE),W=ra([3,d.HBLKSIZE_s]),D=ra([2,d.BLKSIZE]),M=ra([2,3,d.BLKSIZE_s]),la=ra([4,d.CBANDS]),O=ra([4,d.CBANDS]),R=ra([4,3]),K=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],L=Y(2),pa=c.mode==ka.JOINT_STEREO?4:v.channels_out,Z=ra([2,576]),Q=c.internal_flags, +da=Q.channels_out,ua=c.mode==ka.JOINT_STEREO?4:da,P=0;P<da;P++){firbuf=m[P];for(var ma=f+576-350-21+192,N=0;576>N;N++){var na,Ca;na=firbuf[ma+N+10];for(var Ga=Ca=0;9>Ga;Ga+=2)na+=F[Ga]*(firbuf[ma+N+Ga]+firbuf[ma+N+21-Ga]),Ca+=F[Ga+1]*(firbuf[ma+N+Ga+1]+firbuf[ma+N+21-Ga-1]);Z[P][N]=na+Ca}k[e][P].en.assign(Q.en[P]);k[e][P].thm.assign(Q.thm[P]);2<ua&&(h[e][P].en.assign(Q.en[P+2]),h[e][P].thm.assign(Q.thm[P+2]))}for(P=0;P<ua;P++){var Sa=H(12),ea=H(12),Oa=[0,0,0,0],Ia=Z[P&1],ha=0,eb=3==P?Q.nsPsy.attackthre_s: +Q.nsPsy.attackthre,Qa=1;if(2==P)for(N=0,Ga=576;0<Ga;++N,--Ga){var db=Z[0][N],va=Z[1][N];Z[0][N]=db+va;Z[1][N]=db-va}for(N=0;3>N;N++)ea[N]=Q.nsPsy.last_en_subshort[P][N+6],Sa[N]=ea[N]/Q.nsPsy.last_en_subshort[P][N+4],Oa[0]+=ea[N];for(N=0;9>N;N++){for(var vb=ha+64,fb=1;ha<vb;ha++)fb<Math.abs(Ia[ha])&&(fb=Math.abs(Ia[ha]));Q.nsPsy.last_en_subshort[P][N]=ea[N+3]=fb;Oa[1+N/3]+=fb;fb=fb>ea[N+3-2]?fb/ea[N+3-2]:ea[N+3-2]>10*fb?ea[N+3-2]/(10*fb):0;Sa[N+3]=fb}for(N=0;3>N;++N){var ub=ea[3*N+3]+ea[3*N+4]+ea[3* +N+5],Gb=1;6*ea[3*N+5]<ub&&(Gb*=.5,6*ea[3*N+4]<ub&&(Gb*=.5));R[P][N]=Gb}if(c.analysis){for(var tb=Sa[0],N=1;12>N;N++)tb<Sa[N]&&(tb=Sa[N]);Q.pinfo.ers[e][P]=Q.pinfo.ers_save[P];Q.pinfo.ers_save[P]=tb}for(N=0;12>N;N++)0==K[P][N/3]&&Sa[N]>eb&&(K[P][N/3]=N%3+1);for(N=1;4>N;N++){var Hb=Oa[N-1],Ab=Oa[N];4E4>Math.max(Hb,Ab)&&Hb<1.7*Ab&&Ab<1.7*Hb&&(1==N&&K[P][0]<=K[P][N]&&(K[P][0]=0),K[P][N]=0)}K[P][0]<=Q.nsPsy.lastAttacks[P]&&(K[P][0]=0);if(3==Q.nsPsy.lastAttacks[P]||0!=K[P][0]+K[P][1]+K[P][2]+K[P][3])Qa= +0,0!=K[P][1]&&0!=K[P][0]&&(K[P][1]=0),0!=K[P][2]&&0!=K[P][1]&&(K[P][2]=0),0!=K[P][3]&&0!=K[P][2]&&(K[P][3]=0);2>P?L[P]=Qa:0==Qa&&(L[0]=L[1]=0);y[P]=Q.tot_ener[P]}var Ta=c.internal_flags;c.short_blocks!=sa.short_block_coupled||0!=L[0]&&0!=L[1]||(L[0]=L[1]=0);for(var Pb=0;Pb<Ta.channels_out;Pb++)c.short_blocks==sa.short_block_dispensed&&(L[Pb]=1),c.short_blocks==sa.short_block_forced&&(L[Pb]=0);for(var S=0;S<pa;S++){var Pa=S&1;w=D;var Qb=c,Ua=S,wb=e,Ya=A,Va=w,mb=Pa,Ja=Qb.internal_flags;if(2>Ua)E.fft_long(Ja, +Va[mb],Ua,m,f);else if(2==Ua)for(var za=d.BLKSIZE-1;0<=za;--za){var $b=Va[mb+0][za],$a=Va[mb+1][za];Va[mb+0][za]=($b+$a)*X.SQRT2*.5;Va[mb+1][za]=($b-$a)*X.SQRT2*.5}Ya[0]=Va[mb+0][0];Ya[0]*=Ya[0];for(za=d.BLKSIZE/2-1;0<=za;--za){var fa=Va[mb+0][d.BLKSIZE/2-za],Rb=Va[mb+0][d.BLKSIZE/2+za];Ya[d.BLKSIZE/2-za]=.5*(fa*fa+Rb*Rb)}for(var Ib=0,za=11;za<d.HBLKSIZE;za++)Ib+=Ya[za];Ja.tot_ener[Ua]=Ib;if(Qb.analysis){for(za=0;za<d.HBLKSIZE;za++)Ja.pinfo.energy[wb][Ua][za]=Ja.pinfo.energy_save[Ua][za],Ja.pinfo.energy_save[Ua][za]= +Ya[za];Ja.pinfo.pe[wb][Ua]=Ja.pe[Ua]}var Ka=S,ac=A,Bb=c.internal_flags;2==c.athaa_loudapprox&&2>Ka&&(Bb.loudness_sq[e][Ka]=Bb.loudness_sq_save[Ka],Bb.loudness_sq_save[Ka]=r(ac,Bb));if(0!=L[Pa]){var Ea=v,qc=A,Ba=la[S],gb=O[S],hb=S,Sb=H(d.CBANDS),Jb=H(d.CBANDS),bc=Y(d.CBANDS+2),aa=void 0;b(Ea,qc,Ba,Sb,Jb);l(Ea,Sb,Jb,bc);for(var nb=0,aa=0;aa<Ea.npart_l;aa++){var oa,ab,lc,ic,ib=Ea.s3ind[aa][0],rc=Ea.s3ind[aa][1],ob=0,Cb=0,ob=bc[ib],Cb=Cb+1;ab=Ea.s3_ll[nb]*Ba[ib]*p[bc[ib]];++nb;for(++ib;ib<=rc;)ob+=bc[ib], +Cb+=1,oa=Ea.s3_ll[nb]*Ba[ib]*p[bc[ib]],ab=ic=q(ab,oa,ib-aa),++nb,++ib;ob=(1+2*ob)/(2*Cb);lc=.5*p[ob];ab*=lc;if(Ea.blocktype_old[hb&1]==d.SHORT_TYPE){var Tb=2*Ea.nb_1[hb][aa];gb[aa]=0<Tb?Math.min(ab,Tb):Math.min(ab,.3*Ba[aa])}else{var Kb=16*Ea.nb_2[hb][aa],pb=2*Ea.nb_1[hb][aa];0>=Kb&&(Kb=ab);0>=pb&&(pb=ab);Tb=Ea.blocktype_old[hb&1]==d.NORM_TYPE?Math.min(pb,Kb):pb;gb[aa]=Math.min(ab,Tb)}Ea.nb_2[hb][aa]=Ea.nb_1[hb][aa];Ea.nb_1[hb][aa]=ab;oa=Sb[aa];oa*=Ea.minval_l[aa];oa*=lc;gb[aa]>oa&&(gb[aa]=oa);1< +Ea.masking_lower&&(gb[aa]*=Ea.masking_lower);gb[aa]>Ba[aa]&&(gb[aa]=Ba[aa]);1>Ea.masking_lower&&(gb[aa]*=Ea.masking_lower)}for(;aa<d.CBANDS;++aa)Ba[aa]=0,gb[aa]=0}else for(var Ub=v,qb=S,Db=0;Db<Ub.npart_l;Db++)Ub.nb_2[qb][Db]=Ub.nb_1[qb][Db],Ub.nb_1[qb][Db]=0}2==L[0]+L[1]&&c.mode==ka.JOINT_STEREO&&a(la,O,v.mld_cb_l,v.ATH.cb_l,c.ATHlower*v.ATH.adjust,c.msfix,v.npart_l);for(S=0;S<pa;S++)Pa=S&1,0!=L[Pa]&&B(v,la[S],O[S],S);for(var ba=0;3>ba;ba++){for(S=0;S<pa;++S)if(Pa=S&1,0!=L[Pa]){var La=v,cc=S;if(0== +ba)for(var Lb=0;Lb<La.npart_s;Lb++)La.nb_s2[cc][Lb]=La.nb_s1[cc][Lb],La.nb_s1[cc][Lb]=0}else{z=M;var rb=S,Wa=ba,ga=W,Za=z,sb=Pa,sc=c.internal_flags;0==Wa&&2>rb&&E.fft_short(sc,Za[sb],rb,m,f);if(2==rb)for(var wa=d.BLKSIZE_s-1;0<=wa;--wa){var Mb=Za[sb+0][Wa][wa],mc=Za[sb+1][Wa][wa];Za[sb+0][Wa][wa]=(Mb+mc)*X.SQRT2*.5;Za[sb+1][Wa][wa]=(Mb-mc)*X.SQRT2*.5}ga[Wa][0]=Za[sb+0][Wa][0];ga[Wa][0]*=ga[Wa][0];for(wa=d.BLKSIZE_s/2-1;0<=wa;--wa){var dc=Za[sb+0][Wa][d.BLKSIZE_s/2-wa],Aa=Za[sb+0][Wa][d.BLKSIZE_s/ +2+wa];ga[Wa][d.BLKSIZE_s/2-wa]=.5*(dc*dc+Aa*Aa)}for(var Vb=W,Ra=la[S],Ha=O[S],bb=S,ec=ba,xa=c.internal_flags,jb=new float[d.CBANDS],Na=H(d.CBANDS),Wb=void 0,kb=void 0,ca=void 0,Eb=new int[d.CBANDS],ca=kb=0;ca<xa.npart_s;++ca){for(var Ob=0,Zb=0,jc=xa.numlines_s[ca],Wb=0;Wb<jc;++Wb,++kb){var Bc=Vb[ec][kb],Ob=Ob+Bc;Zb<Bc&&(Zb=Bc)}Ra[ca]=Ob;jb[ca]=Zb;Na[ca]=Ob/jc}for(;ca<d.CBANDS;++ca)jb[ca]=0,Na[ca]=0;var Xb=xa,xb=jb,fc=Na,nc=Eb,oc=p.length-1,ja=0,Xa=fc[ja]+fc[ja+1];if(0<Xa){var lb=xb[ja];lb<xb[ja+1]&& +(lb=xb[ja+1]);var Xa=20*(2*lb-Xa)/(Xa*(Xb.numlines_s[ja]+Xb.numlines_s[ja+1]-1)),yb=0|Xa;yb>oc&&(yb=oc);nc[ja]=yb}else nc[ja]=0;for(ja=1;ja<Xb.npart_s-1;ja++)Xa=fc[ja-1]+fc[ja]+fc[ja+1],0<Xa?(lb=xb[ja-1],lb<xb[ja]&&(lb=xb[ja]),lb<xb[ja+1]&&(lb=xb[ja+1]),Xa=20*(3*lb-Xa)/(Xa*(Xb.numlines_s[ja-1]+Xb.numlines_s[ja]+Xb.numlines_s[ja+1]-1)),yb=0|Xa,yb>oc&&(yb=oc),nc[ja]=yb):nc[ja]=0;Xa=fc[ja-1]+fc[ja];0<Xa?(lb=xb[ja-1],lb<xb[ja]&&(lb=xb[ja]),Xa=20*(2*lb-Xa)/(Xa*(Xb.numlines_s[ja-1]+Xb.numlines_s[ja]-1)), +yb=0|Xa,yb>oc&&(yb=oc),nc[ja]=yb):nc[ja]=0;for(kb=ca=0;ca<xa.npart_s;ca++){var Fb=xa.s3ind_s[ca][0],vc=xa.s3ind_s[ca][1],pc,wc,Nb,gc,Cc;pc=Eb[Fb];wc=1;gc=xa.s3_ss[kb]*Ra[Fb]*p[Eb[Fb]];++kb;for(++Fb;Fb<=vc;)pc+=Eb[Fb],wc+=1,Nb=xa.s3_ss[kb]*Ra[Fb]*p[Eb[Fb]],gc=q(gc,Nb,Fb-ca),++kb,++Fb;pc=(1+2*pc)/(2*wc);Cc=.5*p[pc];gc*=Cc;Ha[ca]=gc;xa.nb_s2[bb][ca]=xa.nb_s1[bb][ca];xa.nb_s1[bb][ca]=gc;Nb=jb[ca];Nb*=xa.minval_s[ca];Nb*=Cc;Ha[ca]>Nb&&(Ha[ca]=Nb);1<xa.masking_lower&&(Ha[ca]*=xa.masking_lower);Ha[ca]>Ra[ca]&& +(Ha[ca]=Ra[ca]);1>xa.masking_lower&&(Ha[ca]*=xa.masking_lower)}for(;ca<d.CBANDS;++ca)Ra[ca]=0,Ha[ca]=0}0==L[0]+L[1]&&c.mode==ka.JOINT_STEREO&&a(la,O,v.mld_cb_s,v.ATH.cb_s,c.ATHlower*v.ATH.adjust,c.msfix,v.npart_s);for(S=0;S<pa;++S)Pa=S&1,0==L[Pa]&&C(v,la[S],O[S],S,ba)}for(S=0;S<pa;S++)if(Pa=S&1,0==L[Pa])for(var hc=0;hc<d.SBMAX_s;hc++){for(var Ec=H(3),ba=0;3>ba;ba++){var cb=v.thm[S].s[hc][ba],cb=.8*cb;if(2<=K[S][ba]||1==K[S][ba+1])var tc=0!=ba?ba-1:2,uc=t(v.thm[S].s[hc][tc],cb,.36),cb=Math.min(cb, +uc);else if(1==K[S][ba])tc=0!=ba?ba-1:2,uc=t(v.thm[S].s[hc][tc],cb,.18),cb=Math.min(cb,uc);else if(0!=ba&&3==K[S][ba-1]||0==ba&&3==v.nsPsy.lastAttacks[S])tc=2!=ba?ba+1:0,uc=t(v.thm[S].s[hc][tc],cb,.18),cb=Math.min(cb,uc);cb*=R[S][ba];Ec[ba]=cb}for(ba=0;3>ba;ba++)v.thm[S].s[hc][ba]=Ec[ba]}for(S=0;S<pa;S++)v.nsPsy.lastAttacks[S]=K[S][2];for(var Yb=c.internal_flags,zb=0;zb<Yb.channels_out;zb++){var Dc=d.NORM_TYPE;0!=L[zb]?Yb.blocktype_old[zb]==d.SHORT_TYPE&&(Dc=d.STOP_TYPE):(Dc=d.SHORT_TYPE,Yb.blocktype_old[zb]== +d.NORM_TYPE&&(Yb.blocktype_old[zb]=d.START_TYPE),Yb.blocktype_old[zb]==d.STOP_TYPE&&(Yb.blocktype_old[zb]=d.SHORT_TYPE));u[zb]=Yb.blocktype_old[zb];Yb.blocktype_old[zb]=Dc}for(S=0;S<pa;S++){var xc,yc,zc,Ac;if(1<S){xc=x;yc=-2;zc=d.NORM_TYPE;if(u[0]==d.SHORT_TYPE||u[1]==d.SHORT_TYPE)zc=d.SHORT_TYPE;Ac=h[e][S-2]}else xc=n,yc=0,zc=u[S],Ac=k[e][S];xc[yc+S]=zc==d.SHORT_TYPE?V(Ac,v.masking_lower):g(Ac,v.masking_lower);c.analysis&&(v.pinfo.pe[e][S]=xc[yc+S])}return 0};this.psymodel_init=function(a){var b= +a.internal_flags,m,f=!0,g=13,k=0,h=0,l=-8.25,p=-4.5,x=H(d.CBANDS),y=H(d.CBANDS),q=H(d.CBANDS),u=a.out_samplerate;switch(a.experimentalZ){default:case 0:f=!0;break;case 1:f=a.VBR==M.vbr_mtrh||a.VBR==M.vbr_mt?!1:!0;break;case 2:f=!1;break;case 3:g=8,k=-1.75,h=-.0125,l=-8.25,p=-2.25}b.ms_ener_ratio_old=.25;b.blocktype_old[0]=b.blocktype_old[1]=d.NORM_TYPE;for(m=0;4>m;++m){for(var r=0;r<d.CBANDS;++r)b.nb_1[m][r]=1E20,b.nb_2[m][r]=1E20,b.nb_s1[m][r]=b.nb_s2[m][r]=1;for(var t=0;t<d.SBMAX_l;t++)b.en[m].l[t]= +1E20,b.thm[m].l[t]=1E20;for(r=0;3>r;++r){for(t=0;t<d.SBMAX_s;t++)b.en[m].s[t][r]=1E20,b.thm[m].s[t][r]=1E20;b.nsPsy.lastAttacks[m]=0}for(r=0;9>r;r++)b.nsPsy.last_en_subshort[m][r]=10}b.loudness_sq_save[0]=b.loudness_sq_save[1]=0;b.npart_l=e(b.numlines_l,b.bo_l,b.bm_l,x,y,b.mld_l,b.PSY.bo_l_weight,u,d.BLKSIZE,b.scalefac_band.l,d.BLKSIZE/1152,d.SBMAX_l);for(m=0;m<b.npart_l;m++)t=k,x[m]>=g&&(t=h*(x[m]-g)/(24-g)+k*(24-x[m])/(24-g)),q[m]=Math.pow(10,t/10),b.rnumlines_l[m]=0<b.numlines_l[m]?1/b.numlines_l[m]: +0;b.s3_ll=n(b.s3ind,b.npart_l,x,y,q,f);for(m=r=0;m<b.npart_l;m++){h=vb.MAX_VALUE;for(t=0;t<b.numlines_l[m];t++,r++)k=u*r/(1E3*d.BLKSIZE),k=this.ATHformula(1E3*k,a)-20,k=Math.pow(10,.1*k),k*=b.numlines_l[m],h>k&&(h=k);b.ATH.cb_l[m]=h;h=-20+20*x[m]/10;6<h&&(h=100);-15>h&&(h=-15);h-=8;b.minval_l[m]=Math.pow(10,h/10)*b.numlines_l[m]}b.npart_s=e(b.numlines_s,b.bo_s,b.bm_s,x,y,b.mld_s,b.PSY.bo_s_weight,u,d.BLKSIZE_s,b.scalefac_band.s,d.BLKSIZE_s/384,d.SBMAX_s);for(m=r=0;m<b.npart_s;m++){t=l;x[m]>=g&&(t= +p*(x[m]-g)/(24-g)+l*(24-x[m])/(24-g));q[m]=Math.pow(10,t/10);h=vb.MAX_VALUE;for(t=0;t<b.numlines_s[m];t++,r++)k=u*r/(1E3*d.BLKSIZE_s),k=this.ATHformula(1E3*k,a)-20,k=Math.pow(10,.1*k),k*=b.numlines_s[m],h>k&&(h=k);b.ATH.cb_s[m]=h;h=-7+7*x[m]/12;12<x[m]&&(h*=1+3.1*Math.log(1+h));12>x[m]&&(h*=1+2.3*Math.log(1-h));-15>h&&(h=-15);h-=8;b.minval_s[m]=Math.pow(10,h/10)*b.numlines_s[m]}b.s3_ss=n(b.s3ind_s,b.npart_s,x,y,q,f);w=Math.pow(10,.5625);A=Math.pow(10,1.5);v=Math.pow(10,1.5);E.init_fft(b);b.decay= +Math.exp(-2.302585092994046/(.01*u/192));m=3.5;0!=(a.exp_nspsytune&2)&&(m=1);0<Math.abs(a.msfix)&&(m=a.msfix);a.msfix=m;for(f=0;f<b.npart_l;f++)b.s3ind[f][1]>b.npart_l-1&&(b.s3ind[f][1]=b.npart_l-1);b.ATH.decay=Math.pow(10,576*b.mode_gr/u*-1.2);b.ATH.adjust=.01;b.ATH.adjustLimit=1;if(-1!=a.ATHtype){r=a.out_samplerate/d.BLKSIZE;for(m=k=f=0;m<d.BLKSIZE/2;++m)k+=r,b.ATH.eql_w[m]=1/Math.pow(10,this.ATHformula(k,a)/10),f+=b.ATH.eql_w[m];f=1/f;for(m=d.BLKSIZE/2;0<=--m;)b.ATH.eql_w[m]*=f}for(f=r=0;f<b.npart_s;++f)for(m= +0;m<b.numlines_s[f];++m)++r;for(f=r=0;f<b.npart_l;++f)for(m=0;m<b.numlines_l[f];++m)++r;for(m=r=0;m<b.npart_l;m++)k=u*(r+b.numlines_l[m]/2)/(1*d.BLKSIZE),b.mld_cb_l[m]=c(k),r+=b.numlines_l[m];for(;m<d.CBANDS;++m)b.mld_cb_l[m]=1;for(m=r=0;m<b.npart_s;m++)k=u*(r+b.numlines_s[m]/2)/(1*d.BLKSIZE_s),b.mld_cb_s[m]=c(k),r+=b.numlines_s[m];for(;m<d.CBANDS;++m)b.mld_cb_s[m]=1;return 0};this.ATHformula=function(a,c){var b;switch(c.ATHtype){case 0:b=f(a,9);break;case 1:b=f(a,-1);break;case 2:b=f(a,0);break; +case 3:b=f(a,1)+6;break;case 4:b=f(a,c.ATHcurve);break;default:b=f(a,0)}return b}}function V(){function J(){this.mask_adjust_short=this.mask_adjust=0;this.bo_l_weight=H(d.SBMAX_l);this.bo_s_weight=H(d.SBMAX_s)}function k(){this.lowerlimit=0}function q(a,c){this.lowpass=c}function C(a){return 1<a?0:0>=a?1:Math.cos(Math.PI/2*a)}function B(a,c){switch(a){case 44100:return c.version=1,0;case 48E3:return c.version=1;case 32E3:return c.version=1,2;case 22050:return c.version=0;case 24E3:return c.version= +0,1;case 16E3:return c.version=0,2;case 11025:return c.version=0;case 12E3:return c.version=0,1;case 8E3:return c.version=0,2;default:return c.version=0,-1}}function t(a,c,b){16E3>b&&(c=2);b=r.bitrate_table[c][1];for(var d=2;14>=d;d++)0<r.bitrate_table[c][d]&&Math.abs(r.bitrate_table[c][d]-a)<Math.abs(b-a)&&(b=r.bitrate_table[c][d]);return b}function Q(a,c,b){16E3>b&&(c=2);for(b=0;14>=b;b++)if(0<r.bitrate_table[c][b]&&r.bitrate_table[c][b]==a)return b;return-1}function g(a,c){var b=[new q(8,2E3), +new q(16,3700),new q(24,3900),new q(32,5500),new q(40,7E3),new q(48,7500),new q(56,1E4),new q(64,11E3),new q(80,13500),new q(96,15100),new q(112,15600),new q(128,17E3),new q(160,17500),new q(192,18600),new q(224,19400),new q(256,19700),new q(320,20500)],d=e.nearestBitrateFullIndex(c);a.lowerlimit=b[d].lowpass}function b(a){var c=d.BLKSIZE+a.framesize-d.FFTOFFSET;return c=Math.max(c,512+a.framesize-32)}function l(m,f,g,k,l,p,q){var r=m.internal_flags,v=0,t,w,A=[null,null],z=[null,null];if(4294479419!= +r.Class_ID)return-3;if(0==k)return 0;t=c.copy_buffer(r,l,p,q,0);if(0>t)return t;p+=t;v+=t;z[0]=f;z[1]=g;if(ua.NEQ(m.scale,0)&&ua.NEQ(m.scale,1))for(t=0;t<k;++t)z[0][t]*=m.scale,2==r.channels_out&&(z[1][t]*=m.scale);if(ua.NEQ(m.scale_left,0)&&ua.NEQ(m.scale_left,1))for(t=0;t<k;++t)z[0][t]*=m.scale_left;if(ua.NEQ(m.scale_right,0)&&ua.NEQ(m.scale_right,1))for(t=0;t<k;++t)z[1][t]*=m.scale_right;if(2==m.num_channels&&1==r.channels_out)for(t=0;t<k;++t)z[0][t]=.5*(z[0][t]+z[1][t]),z[1][t]=0;f=b(m);A[0]= +r.mfbuf[0];A[1]=r.mfbuf[1];for(g=0;0<k;){var B=[null,null];t=w=0;B[0]=z[0];B[1]=z[1];t=new a;var C=m;w=A;var E=g,J=k,K=t,M=C.internal_flags;if(.9999>M.resample_ratio||1.0001<M.resample_ratio)for(var Q=0;Q<M.channels_out;Q++){var V=new h,Y=K,X=w[Q],ta=M.mf_size,ka=C.framesize,ma=B[Q],ra=E,R=J,Fa=V,L=Q,Ma=C.internal_flags,Z=void 0,Da=0,na=void 0,sa=C.out_samplerate/D(C.out_samplerate,C.in_samplerate);sa>da.BPC&&(sa=da.BPC);var P=1E-4>Math.abs(Ma.resample_ratio-Math.floor(.5+Ma.resample_ratio))?1:0, +na=1/Ma.resample_ratio;1<na&&(na=1);var ha=31;0==ha%2&&--ha;ha+=P;P=ha+1;if(0==Ma.fill_buffer_resample_init){Ma.inbuf_old[0]=H(P);Ma.inbuf_old[1]=H(P);for(Z=0;Z<=2*sa;++Z)Ma.blackfilt[Z]=H(P);Ma.itime[0]=0;for(Da=Ma.itime[1]=0;Da<=2*sa;Da++){for(var N=0,Ca=(Da-sa)/(2*sa),Z=0;Z<=ha;Z++){var Ia=Ma.blackfilt[Da],Ga=Z,Sa,ea=Z-Ca;Sa=ha;var Oa=Math.PI*na,ea=ea/Sa;0>ea&&(ea=0);1<ea&&(ea=1);var Qa=ea-.5,ea=.42-.5*Math.cos(2*ea*Math.PI)+.08*Math.cos(4*ea*Math.PI);Sa=1E-9>Math.abs(Qa)?Oa/Math.PI:ea*Math.sin(Sa* +Oa*Qa)/(Math.PI*Sa*Qa);N+=Ia[Ga]=Sa}for(Z=0;Z<=ha;Z++)Ma.blackfilt[Da][Z]/=N}Ma.fill_buffer_resample_init=1}N=Ma.inbuf_old[L];for(na=0;na<ka;na++){Z=na*Ma.resample_ratio;Da=0|Math.floor(Z-Ma.itime[L]);if(ha+Da-ha/2>=R)break;Ca=Z-Ma.itime[L]-(Da+ha%2*.5);Ca=0|Math.floor(2*Ca*sa+sa+.5);for(Z=Ia=0;Z<=ha;++Z)Ga=Z+Da-ha/2,Ia+=(0>Ga?N[P+Ga]:ma[ra+Ga])*Ma.blackfilt[Ca][Z];X[ta+na]=Ia}Fa.num_used=Math.min(R,ha+Da-ha/2);Ma.itime[L]+=Fa.num_used-na*Ma.resample_ratio;if(Fa.num_used>=P)for(Z=0;Z<P;Z++)N[Z]=ma[ra+ +Fa.num_used+Z-P];else{X=P-Fa.num_used;for(Z=0;Z<X;++Z)N[Z]=N[Z+Fa.num_used];for(Da=0;Z<P;++Z,++Da)N[Z]=ma[ra+Da]}Y.n_out=na;K.n_in=V.num_used}else for(K.n_out=Math.min(C.framesize,J),K.n_in=K.n_out,C=0;C<K.n_out;++C)w[0][M.mf_size+C]=B[0][E+C],2==M.channels_out&&(w[1][M.mf_size+C]=B[1][E+C]);w=t.n_in;t=t.n_out;if(r.findReplayGain&&!r.decode_on_the_fly&&n.AnalyzeSamples(r.rgdata,A[0],r.mf_size,A[1],r.mf_size,t,r.channels_out)==O.GAIN_ANALYSIS_ERROR)return-6;k-=w;g+=w;r.mf_size+=t;1>r.mf_samples_to_encode&& +(r.mf_samples_to_encode=d.ENCDELAY+d.POSTDELAY);r.mf_samples_to_encode+=t;if(r.mf_size>=f){w=q-v;0==q&&(w=0);t=m;w=e.enc.lame_encode_mp3_frame(t,A[0],A[1],l,p,w);t.frameNum++;t=w;if(0>t)return t;p+=t;v+=t;r.mf_size-=m.framesize;r.mf_samples_to_encode-=m.framesize;for(w=0;w<r.channels_out;w++)for(t=0;t<r.mf_size;t++)A[w][t]=A[w][t+m.framesize]}}return v}function a(){this.n_out=this.n_in=0}function h(){this.num_used=0}function D(a,c){return 0!=c?D(c,a%c):a}var e=this;V.V9=410;V.V8=420;V.V7=430;V.V6= +440;V.V5=450;V.V4=460;V.V3=470;V.V2=480;V.V1=490;V.V0=500;V.R3MIX=1E3;V.STANDARD=1001;V.EXTREME=1002;V.INSANE=1003;V.STANDARD_FAST=1004;V.EXTREME_FAST=1005;V.MEDIUM=1006;V.MEDIUM_FAST=1007;V.LAME_MAXMP3BUFFER=147456;var n,c,f,E,z,w=new jc,A,v,p;this.enc=new d;this.setModules=function(a,b,d,g,e,k,h,l,q){n=a;c=b;f=d;E=g;z=e;A=k;v=l;p=q;this.enc.setModules(c,w,E,A)};this.lame_init=function(){var a=new Jc,c;a.class_id=4294479419;c=a.internal_flags=new da;a.mode=ka.NOT_SET;a.original=1;a.in_samplerate= +44100;a.num_channels=2;a.num_samples=-1;a.bWriteVbrTag=!0;a.quality=-1;a.short_blocks=null;c.subblock_gain=-1;a.lowpassfreq=0;a.highpassfreq=0;a.lowpasswidth=-1;a.highpasswidth=-1;a.VBR=M.vbr_off;a.VBR_q=4;a.ATHcurve=-1;a.VBR_mean_bitrate_kbps=128;a.VBR_min_bitrate_kbps=0;a.VBR_max_bitrate_kbps=0;a.VBR_hard_min=0;c.VBR_min_bitrate=1;c.VBR_max_bitrate=13;a.quant_comp=-1;a.quant_comp_short=-1;a.msfix=-1;c.resample_ratio=1;c.OldValue[0]=180;c.OldValue[1]=180;c.CurrentStep[0]=4;c.CurrentStep[1]=4;c.masking_lower= +1;c.nsPsy.attackthre=-1;c.nsPsy.attackthre_s=-1;a.scale=-1;a.athaa_type=-1;a.ATHtype=-1;a.athaa_loudapprox=-1;a.athaa_sensitivity=0;a.useTemporal=null;a.interChRatio=-1;c.mf_samples_to_encode=d.ENCDELAY+d.POSTDELAY;a.encoder_padding=0;c.mf_size=d.ENCDELAY-d.MDCTDELAY;a.findReplayGain=!1;a.decode_on_the_fly=!1;c.decode_on_the_fly=!1;c.findReplayGain=!1;c.findPeakSample=!1;c.RadioGain=0;c.AudiophileGain=0;c.noclipGainChange=0;c.noclipScale=-1;a.preset=0;a.write_id3tag_automatic=!0;a.lame_allocated_gfp= +1;return a};this.nearestBitrateFullIndex=function(a){for(var c=[8,16,24,32,40,48,56,64,80,96,112,128,160,192,224,256,320],b=0,d=0,f=0,g=0,g=c[16],f=16,d=c[16],b=16,e=0;16>e;e++)if(Math.max(a,c[e+1])!=a){g=c[e+1];f=e+1;d=c[e];b=e;break}return g-a>a-d?b:f};this.lame_init_params=function(a){var b=a.internal_flags;b.Class_ID=0;null==b.ATH&&(b.ATH=new Lc);null==b.PSY&&(b.PSY=new J);null==b.rgdata&&(b.rgdata=new Kc);b.channels_in=a.num_channels;1==b.channels_in&&(a.mode=ka.MONO);b.channels_out=a.mode== +ka.MONO?1:2;b.mode_ext=d.MPG_MD_MS_LR;a.mode==ka.MONO&&(a.force_ms=!1);a.VBR==M.vbr_off&&128!=a.VBR_mean_bitrate_kbps&&0==a.brate&&(a.brate=a.VBR_mean_bitrate_kbps);a.VBR!=M.vbr_off&&a.VBR!=M.vbr_mtrh&&a.VBR!=M.vbr_mt&&(a.free_format=!1);a.VBR==M.vbr_off&&0==a.brate&&ua.EQ(a.compression_ratio,0)&&(a.compression_ratio=11.025);a.VBR==M.vbr_off&&0<a.compression_ratio&&(0==a.out_samplerate&&(a.out_samplerate=map2MP3Frequency(int(.97*a.in_samplerate))),a.brate=0|16*a.out_samplerate*b.channels_out/(1E3* +a.compression_ratio),b.samplerate_index=B(a.out_samplerate,a),a.free_format||(a.brate=t(a.brate,a.version,a.out_samplerate)));0!=a.out_samplerate&&(16E3>a.out_samplerate?(a.VBR_mean_bitrate_kbps=Math.max(a.VBR_mean_bitrate_kbps,8),a.VBR_mean_bitrate_kbps=Math.min(a.VBR_mean_bitrate_kbps,64)):32E3>a.out_samplerate?(a.VBR_mean_bitrate_kbps=Math.max(a.VBR_mean_bitrate_kbps,8),a.VBR_mean_bitrate_kbps=Math.min(a.VBR_mean_bitrate_kbps,160)):(a.VBR_mean_bitrate_kbps=Math.max(a.VBR_mean_bitrate_kbps,32), +a.VBR_mean_bitrate_kbps=Math.min(a.VBR_mean_bitrate_kbps,320)));if(0==a.lowpassfreq){var e=16E3;switch(a.VBR){case M.vbr_off:e=new k;g(e,a.brate);e=e.lowerlimit;break;case M.vbr_abr:e=new k;g(e,a.VBR_mean_bitrate_kbps);e=e.lowerlimit;break;case M.vbr_rh:var h=[19500,19E3,18600,18E3,17500,16E3,15600,14900,12500,1E4,3950];if(0<=a.VBR_q&&9>=a.VBR_q)var e=h[a.VBR_q],h=h[a.VBR_q+1],l=a.VBR_q_frac,e=linear_int(e,h,l);else e=19500;break;default:h=[19500,19E3,18500,18E3,17500,16500,15500,14500,12500,9500, +3950],0<=a.VBR_q&&9>=a.VBR_q?(e=h[a.VBR_q],h=h[a.VBR_q+1],l=a.VBR_q_frac,e=linear_int(e,h,l)):e=19500}a.mode!=ka.MONO||a.VBR!=M.vbr_off&&a.VBR!=M.vbr_abr||(e*=1.5);a.lowpassfreq=e|0}0==a.out_samplerate&&(2*a.lowpassfreq>a.in_samplerate&&(a.lowpassfreq=a.in_samplerate/2),e=a.lowpassfreq|0,h=a.in_samplerate,l=44100,48E3<=h?l=48E3:44100<=h?l=44100:32E3<=h?l=32E3:24E3<=h?l=24E3:22050<=h?l=22050:16E3<=h?l=16E3:12E3<=h?l=12E3:11025<=h?l=11025:8E3<=h&&(l=8E3),-1==e?e=l:(15960>=e&&(l=44100),15250>=e&&(l= +32E3),11220>=e&&(l=24E3),9970>=e&&(l=22050),7230>=e&&(l=16E3),5420>=e&&(l=12E3),4510>=e&&(l=11025),3970>=e&&(l=8E3),e=h<l?44100<h?48E3:32E3<h?44100:24E3<h?32E3:22050<h?24E3:16E3<h?22050:12E3<h?16E3:11025<h?12E3:8E3<h?11025:8E3:l),a.out_samplerate=e);a.lowpassfreq=Math.min(20500,a.lowpassfreq);a.lowpassfreq=Math.min(a.out_samplerate/2,a.lowpassfreq);a.VBR==M.vbr_off&&(a.compression_ratio=16*a.out_samplerate*b.channels_out/(1E3*a.brate));a.VBR==M.vbr_abr&&(a.compression_ratio=16*a.out_samplerate*b.channels_out/ +(1E3*a.VBR_mean_bitrate_kbps));a.bWriteVbrTag||(a.findReplayGain=!1,a.decode_on_the_fly=!1,b.findPeakSample=!1);b.findReplayGain=a.findReplayGain;b.decode_on_the_fly=a.decode_on_the_fly;b.decode_on_the_fly&&(b.findPeakSample=!0);if(b.findReplayGain&&n.InitGainAnalysis(b.rgdata,a.out_samplerate)==O.INIT_GAIN_ANALYSIS_ERROR)return a.internal_flags=null,-6;b.decode_on_the_fly&&!a.decode_only&&(null!=b.hip&&p.hip_decode_exit(b.hip),b.hip=p.hip_decode_init());b.mode_gr=24E3>=a.out_samplerate?1:2;a.framesize= +576*b.mode_gr;a.encoder_delay=d.ENCDELAY;b.resample_ratio=a.in_samplerate/a.out_samplerate;switch(a.VBR){case M.vbr_mt:case M.vbr_rh:case M.vbr_mtrh:a.compression_ratio=[5.7,6.5,7.3,8.2,10,11.9,13,14,15,16.5][a.VBR_q];break;case M.vbr_abr:a.compression_ratio=16*a.out_samplerate*b.channels_out/(1E3*a.VBR_mean_bitrate_kbps);break;default:a.compression_ratio=16*a.out_samplerate*b.channels_out/(1E3*a.brate)}a.mode==ka.NOT_SET&&(a.mode=ka.JOINT_STEREO);0<a.highpassfreq?(b.highpass1=2*a.highpassfreq,b.highpass2= +0<=a.highpasswidth?2*(a.highpassfreq+a.highpasswidth):2*a.highpassfreq,b.highpass1/=a.out_samplerate,b.highpass2/=a.out_samplerate):(b.highpass1=0,b.highpass2=0);0<a.lowpassfreq?(b.lowpass2=2*a.lowpassfreq,0<=a.lowpasswidth?(b.lowpass1=2*(a.lowpassfreq-a.lowpasswidth),0>b.lowpass1&&(b.lowpass1=0)):b.lowpass1=2*a.lowpassfreq,b.lowpass1/=a.out_samplerate,b.lowpass2/=a.out_samplerate):(b.lowpass1=0,b.lowpass2=0);var e=a.internal_flags,q=32,D=-1;if(0<e.lowpass1){for(var F=999,h=0;31>=h;h++)l=h/31,l>= +e.lowpass2&&(q=Math.min(q,h)),e.lowpass1<l&&l<e.lowpass2&&(F=Math.min(F,h));e.lowpass1=999==F?(q-.75)/31:(F-.75)/31;e.lowpass2=q/31}0<e.highpass2&&e.highpass2<.75/31*.9&&(e.highpass1=0,e.highpass2=0,K.err.println("Warning: highpass filter disabled. highpass frequency too small\n"));if(0<e.highpass2){q=-1;for(h=0;31>=h;h++)l=h/31,l<=e.highpass1&&(D=Math.max(D,h)),e.highpass1<l&&l<e.highpass2&&(q=Math.max(q,h));e.highpass1=D/31;e.highpass2=-1==q?(D+.75)/31:(q+.75)/31}for(h=0;32>h;h++)l=h/31,D=e.highpass2> +e.highpass1?C((e.highpass2-l)/(e.highpass2-e.highpass1+1E-20)):1,l=e.lowpass2>e.lowpass1?C((l-e.lowpass1)/(e.lowpass2-e.lowpass1+1E-20)):1,e.amp_filter[h]=D*l;b.samplerate_index=B(a.out_samplerate,a);if(0>b.samplerate_index)return a.internal_flags=null,-1;if(a.VBR==M.vbr_off)if(a.free_format)b.bitrate_index=0;else{if(a.brate=t(a.brate,a.version,a.out_samplerate),b.bitrate_index=Q(a.brate,a.version,a.out_samplerate),0>=b.bitrate_index)return a.internal_flags=null,-1}else b.bitrate_index=1;a.analysis&& +(a.bWriteVbrTag=!1);null!=b.pinfo&&(a.bWriteVbrTag=!1);c.init_bit_stream_w(b);e=b.samplerate_index+3*a.version+6*(16E3>a.out_samplerate?1:0);for(h=0;h<d.SBMAX_l+1;h++)b.scalefac_band.l[h]=E.sfBandIndex[e].l[h];for(h=0;h<d.PSFB21+1;h++)l=(b.scalefac_band.l[22]-b.scalefac_band.l[21])/d.PSFB21,l=b.scalefac_band.l[21]+h*l,b.scalefac_band.psfb21[h]=l;b.scalefac_band.psfb21[d.PSFB21]=576;for(h=0;h<d.SBMAX_s+1;h++)b.scalefac_band.s[h]=E.sfBandIndex[e].s[h];for(h=0;h<d.PSFB12+1;h++)l=(b.scalefac_band.s[13]- +b.scalefac_band.s[12])/d.PSFB12,l=b.scalefac_band.s[12]+h*l,b.scalefac_band.psfb12[h]=l;b.scalefac_band.psfb12[d.PSFB12]=192;b.sideinfo_len=1==a.version?1==b.channels_out?21:36:1==b.channels_out?13:21;a.error_protection&&(b.sideinfo_len+=2);e=a.internal_flags;a.frameNum=0;a.write_id3tag_automatic&&v.id3tag_write_v2(a);e.bitrate_stereoMode_Hist=db([16,5]);e.bitrate_blockType_Hist=db([16,6]);e.PeakSample=0;a.bWriteVbrTag&&A.InitVbrTag(a);b.Class_ID=4294479419;for(e=0;19>e;e++)b.nsPsy.pefirbuf[e]=700* +b.mode_gr*b.channels_out;-1==a.ATHtype&&(a.ATHtype=4);switch(a.VBR){case M.vbr_mt:a.VBR=M.vbr_mtrh;case M.vbr_mtrh:null==a.useTemporal&&(a.useTemporal=!1);f.apply_preset(a,500-10*a.VBR_q,0);0>a.quality&&(a.quality=LAME_DEFAULT_QUALITY);5>a.quality&&(a.quality=0);5<a.quality&&(a.quality=5);b.PSY.mask_adjust=a.maskingadjust;b.PSY.mask_adjust_short=a.maskingadjust_short;b.sfb21_extra=a.experimentalY?!1:44E3<a.out_samplerate;b.iteration_loop=new VBRNewIterationLoop(z);break;case M.vbr_rh:f.apply_preset(a, +500-10*a.VBR_q,0);b.PSY.mask_adjust=a.maskingadjust;b.PSY.mask_adjust_short=a.maskingadjust_short;b.sfb21_extra=a.experimentalY?!1:44E3<a.out_samplerate;6<a.quality&&(a.quality=6);0>a.quality&&(a.quality=LAME_DEFAULT_QUALITY);b.iteration_loop=new VBROldIterationLoop(z);break;default:b.sfb21_extra=!1,0>a.quality&&(a.quality=LAME_DEFAULT_QUALITY),e=a.VBR,e==M.vbr_off&&(a.VBR_mean_bitrate_kbps=a.brate),f.apply_preset(a,a.VBR_mean_bitrate_kbps,0),a.VBR=e,b.PSY.mask_adjust=a.maskingadjust,b.PSY.mask_adjust_short= +a.maskingadjust_short,b.iteration_loop=e==M.vbr_off?new Mc(z):new ABRIterationLoop(z)}if(a.VBR!=M.vbr_off){b.VBR_min_bitrate=1;b.VBR_max_bitrate=14;16E3>a.out_samplerate&&(b.VBR_max_bitrate=8);if(0!=a.VBR_min_bitrate_kbps&&(a.VBR_min_bitrate_kbps=t(a.VBR_min_bitrate_kbps,a.version,a.out_samplerate),b.VBR_min_bitrate=Q(a.VBR_min_bitrate_kbps,a.version,a.out_samplerate),0>b.VBR_min_bitrate)||0!=a.VBR_max_bitrate_kbps&&(a.VBR_max_bitrate_kbps=t(a.VBR_max_bitrate_kbps,a.version,a.out_samplerate),b.VBR_max_bitrate= +Q(a.VBR_max_bitrate_kbps,a.version,a.out_samplerate),0>b.VBR_max_bitrate))return-1;a.VBR_min_bitrate_kbps=r.bitrate_table[a.version][b.VBR_min_bitrate];a.VBR_max_bitrate_kbps=r.bitrate_table[a.version][b.VBR_max_bitrate];a.VBR_mean_bitrate_kbps=Math.min(r.bitrate_table[a.version][b.VBR_max_bitrate],a.VBR_mean_bitrate_kbps);a.VBR_mean_bitrate_kbps=Math.max(r.bitrate_table[a.version][b.VBR_min_bitrate],a.VBR_mean_bitrate_kbps)}a.tune&&(b.PSY.mask_adjust+=a.tune_value_a,b.PSY.mask_adjust_short+=a.tune_value_a); +e=a.internal_flags;switch(a.quality){default:case 9:e.psymodel=0;e.noise_shaping=0;e.noise_shaping_amp=0;e.noise_shaping_stop=0;e.use_best_huffman=0;e.full_outer_loop=0;break;case 8:a.quality=7;case 7:e.psymodel=1;e.noise_shaping=0;e.noise_shaping_amp=0;e.noise_shaping_stop=0;e.use_best_huffman=0;e.full_outer_loop=0;break;case 6:e.psymodel=1;0==e.noise_shaping&&(e.noise_shaping=1);e.noise_shaping_amp=0;e.noise_shaping_stop=0;-1==e.subblock_gain&&(e.subblock_gain=1);e.use_best_huffman=0;e.full_outer_loop= +0;break;case 5:e.psymodel=1;0==e.noise_shaping&&(e.noise_shaping=1);e.noise_shaping_amp=0;e.noise_shaping_stop=0;-1==e.subblock_gain&&(e.subblock_gain=1);e.use_best_huffman=0;e.full_outer_loop=0;break;case 4:e.psymodel=1;0==e.noise_shaping&&(e.noise_shaping=1);e.noise_shaping_amp=0;e.noise_shaping_stop=0;-1==e.subblock_gain&&(e.subblock_gain=1);e.use_best_huffman=1;e.full_outer_loop=0;break;case 3:e.psymodel=1;0==e.noise_shaping&&(e.noise_shaping=1);e.noise_shaping_amp=1;e.noise_shaping_stop=1;-1== +e.subblock_gain&&(e.subblock_gain=1);e.use_best_huffman=1;e.full_outer_loop=0;break;case 2:e.psymodel=1;0==e.noise_shaping&&(e.noise_shaping=1);0==e.substep_shaping&&(e.substep_shaping=2);e.noise_shaping_amp=1;e.noise_shaping_stop=1;-1==e.subblock_gain&&(e.subblock_gain=1);e.use_best_huffman=1;e.full_outer_loop=0;break;case 1:e.psymodel=1;0==e.noise_shaping&&(e.noise_shaping=1);0==e.substep_shaping&&(e.substep_shaping=2);e.noise_shaping_amp=2;e.noise_shaping_stop=1;-1==e.subblock_gain&&(e.subblock_gain= +1);e.use_best_huffman=1;e.full_outer_loop=0;break;case 0:e.psymodel=1,0==e.noise_shaping&&(e.noise_shaping=1),0==e.substep_shaping&&(e.substep_shaping=2),e.noise_shaping_amp=2,e.noise_shaping_stop=1,-1==e.subblock_gain&&(e.subblock_gain=1),e.use_best_huffman=1,e.full_outer_loop=0}b.ATH.useAdjust=0>a.athaa_type?3:a.athaa_type;b.ATH.aaSensitivityP=Math.pow(10,a.athaa_sensitivity/-10);null==a.short_blocks&&(a.short_blocks=sa.short_block_allowed);a.short_blocks!=sa.short_block_allowed||a.mode!=ka.JOINT_STEREO&& +a.mode!=ka.STEREO||(a.short_blocks=sa.short_block_coupled);0>a.quant_comp&&(a.quant_comp=1);0>a.quant_comp_short&&(a.quant_comp_short=0);0>a.msfix&&(a.msfix=0);a.exp_nspsytune|=1;0>a.internal_flags.nsPsy.attackthre&&(a.internal_flags.nsPsy.attackthre=jc.NSATTACKTHRE);0>a.internal_flags.nsPsy.attackthre_s&&(a.internal_flags.nsPsy.attackthre_s=jc.NSATTACKTHRE_S);0>a.scale&&(a.scale=1);0>a.ATHtype&&(a.ATHtype=4);0>a.ATHcurve&&(a.ATHcurve=4);0>a.athaa_loudapprox&&(a.athaa_loudapprox=2);0>a.interChRatio&& +(a.interChRatio=0);null==a.useTemporal&&(a.useTemporal=!0);b.slot_lag=b.frac_SpF=0;a.VBR==M.vbr_off&&(b.slot_lag=b.frac_SpF=72E3*(a.version+1)*a.brate%a.out_samplerate|0);E.iteration_init(a);w.psymodel_init(a);return 0};this.lame_encode_flush=function(a,e,f,g){var h=a.internal_flags,k=vc([2,1152]),l=0,n,p,q=h.mf_samples_to_encode-d.POSTDELAY,r=b(a);if(1>h.mf_samples_to_encode)return 0;n=0;a.in_samplerate!=a.out_samplerate&&(q+=16*a.out_samplerate/a.in_samplerate);p=a.framesize-q%a.framesize;576>p&& +(p+=a.framesize);a.encoder_padding=p;for(p=(q+p)/a.framesize;0<p&&0<=l;){var t=r-h.mf_size,q=a.frameNum,t=t*a.in_samplerate,t=t/a.out_samplerate;1152<t&&(t=1152);1>t&&(t=1);l=g-n;0==g&&(l=0);l=this.lame_encode_buffer(a,k[0],k[1],t,e,f,l);f+=l;n+=l;p-=q!=a.frameNum?1:0}h.mf_samples_to_encode=0;if(0>l)return l;l=g-n;0==g&&(l=0);c.flush_bitstream(a);l=c.copy_buffer(h,e,f,l,1);if(0>l)return l;f+=l;n+=l;l=g-n;0==g&&(l=0);if(a.write_id3tag_automatic){v.id3tag_write_v1(a);l=c.copy_buffer(h,e,f,l,0);if(0> +l)return l;n+=l}return n};this.lame_encode_buffer=function(a,b,c,d,e,f,g){var h=a.internal_flags,k=[null,null];if(4294479419!=h.Class_ID)return-3;if(0==d)return 0;if(null==h.in_buffer_0||h.in_buffer_nsamples<d)h.in_buffer_0=H(d),h.in_buffer_1=H(d),h.in_buffer_nsamples=d;k[0]=h.in_buffer_0;k[1]=h.in_buffer_1;for(var n=0;n<d;n++)k[0][n]=b[n],1<h.channels_in&&(k[1][n]=c[n]);return l(a,k[0],k[1],d,e,f,g)}}function Uc(){this.setModules=function(d,k){}}function Vc(){this.setModules=function(d,k,q){}}function Wc(){} +function Xc(){this.setModules=function(d,k){}}function Ca(){this.sampleRate=this.channels=this.dataLen=this.dataOffset=0}function Ob(d){return d.charCodeAt(0)<<24|d.charCodeAt(1)<<16|d.charCodeAt(2)<<8|d.charCodeAt(3)}var Ia={fill:function(d,k,q,r){if(2==arguments.length)for(var B=0;B<d.length;B++)d[B]=arguments[1];else for(B=k;B<q;B++)d[B]=r}},K={arraycopy:function(d,k,q,r,B){for(B=k+B;k<B;)q[r++]=d[k++]}},X={SQRT2:1.4142135623730951,FAST_LOG10:function(d){return Math.log10(d)},FAST_LOG10_X:function(d, +k){return Math.log10(d)*k}};sa.short_block_allowed=new sa(0);sa.short_block_coupled=new sa(1);sa.short_block_dispensed=new sa(2);sa.short_block_forced=new sa(3);var vb={MAX_VALUE:3.4028235E38};M.vbr_off=new M(0);M.vbr_mt=new M(1);M.vbr_rh=new M(2);M.vbr_abr=new M(3);M.vbr_mtrh=new M(4);M.vbr_default=M.vbr_mtrh;ka.STEREO=new ka(0);ka.JOINT_STEREO=new ka(1);ka.DUAL_CHANNEL=new ka(2);ka.MONO=new ka(3);ka.NOT_SET=new ka(4);O.STEPS_per_dB=100;O.MAX_dB=120;O.GAIN_NOT_ENOUGH_SAMPLES=-24601;O.GAIN_ANALYSIS_ERROR= +0;O.GAIN_ANALYSIS_OK=1;O.INIT_GAIN_ANALYSIS_ERROR=0;O.INIT_GAIN_ANALYSIS_OK=1;O.YULE_ORDER=10;O.MAX_ORDER=O.YULE_ORDER;O.MAX_SAMP_FREQ=48E3;O.RMS_WINDOW_TIME_NUMERATOR=1;O.RMS_WINDOW_TIME_DENOMINATOR=20;O.MAX_SAMPLES_PER_WINDOW=O.MAX_SAMP_FREQ*O.RMS_WINDOW_TIME_NUMERATOR/O.RMS_WINDOW_TIME_DENOMINATOR+1;ua.EQ=function(d,k){return Math.abs(d)>Math.abs(k)?Math.abs(d-k)<=1E-6*Math.abs(d):Math.abs(d-k)<=1E-6*Math.abs(k)};ua.NEQ=function(d,k){return!ua.EQ(d,k)};ub.NUMTOCENTRIES=100;ub.MAXFRAMESIZE=2880; +var r={t1HB:[1,1,1,0],t2HB:[1,2,1,3,1,1,3,2,0],t3HB:[3,2,1,1,1,1,3,2,0],t5HB:[1,2,6,5,3,1,4,4,7,5,7,1,6,1,1,0],t6HB:[7,3,5,1,6,2,3,2,5,4,4,1,3,3,2,0],t7HB:[1,2,10,19,16,10,3,3,7,10,5,3,11,4,13,17,8,4,12,11,18,15,11,2,7,6,9,14,3,1,6,4,5,3,2,0],t8HB:[3,4,6,18,12,5,5,1,2,16,9,3,7,3,5,14,7,3,19,17,15,13,10,4,13,5,8,11,5,1,12,4,4,1,1,0],t9HB:[7,5,9,14,15,7,6,4,5,5,6,7,7,6,8,8,8,5,15,6,9,10,5,1,11,7,9,6,4,1,14,4,6,2,6,0],t10HB:[1,2,10,23,35,30,12,17,3,3,8,12,18,21,12,7,11,9,15,21,32,40,19,6,14,13,22,34, +46,23,18,7,20,19,33,47,27,22,9,3,31,22,41,26,21,20,5,3,14,13,10,11,16,6,5,1,9,8,7,8,4,4,2,0],t11HB:[3,4,10,24,34,33,21,15,5,3,4,10,32,17,11,10,11,7,13,18,30,31,20,5,25,11,19,59,27,18,12,5,35,33,31,58,30,16,7,5,28,26,32,19,17,15,8,14,14,12,9,13,14,9,4,1,11,4,6,6,6,3,2,0],t12HB:[9,6,16,33,41,39,38,26,7,5,6,9,23,16,26,11,17,7,11,14,21,30,10,7,17,10,15,12,18,28,14,5,32,13,22,19,18,16,9,5,40,17,31,29,17,13,4,2,27,12,11,15,10,7,4,1,27,12,8,12,6,3,1,0],t13HB:[1,5,14,21,34,51,46,71,42,52,68,52,67,44,43,19, +3,4,12,19,31,26,44,33,31,24,32,24,31,35,22,14,15,13,23,36,59,49,77,65,29,40,30,40,27,33,42,16,22,20,37,61,56,79,73,64,43,76,56,37,26,31,25,14,35,16,60,57,97,75,114,91,54,73,55,41,48,53,23,24,58,27,50,96,76,70,93,84,77,58,79,29,74,49,41,17,47,45,78,74,115,94,90,79,69,83,71,50,59,38,36,15,72,34,56,95,92,85,91,90,86,73,77,65,51,44,43,42,43,20,30,44,55,78,72,87,78,61,46,54,37,30,20,16,53,25,41,37,44,59,54,81,66,76,57,54,37,18,39,11,35,33,31,57,42,82,72,80,47,58,55,21,22,26,38,22,53,25,23,38,70,60,51, +36,55,26,34,23,27,14,9,7,34,32,28,39,49,75,30,52,48,40,52,28,18,17,9,5,45,21,34,64,56,50,49,45,31,19,12,15,10,7,6,3,48,23,20,39,36,35,53,21,16,23,13,10,6,1,4,2,16,15,17,27,25,20,29,11,17,12,16,8,1,1,0,1],t15HB:[7,12,18,53,47,76,124,108,89,123,108,119,107,81,122,63,13,5,16,27,46,36,61,51,42,70,52,83,65,41,59,36,19,17,15,24,41,34,59,48,40,64,50,78,62,80,56,33,29,28,25,43,39,63,55,93,76,59,93,72,54,75,50,29,52,22,42,40,67,57,95,79,72,57,89,69,49,66,46,27,77,37,35,66,58,52,91,74,62,48,79,63,90,62,40, +38,125,32,60,56,50,92,78,65,55,87,71,51,73,51,70,30,109,53,49,94,88,75,66,122,91,73,56,42,64,44,21,25,90,43,41,77,73,63,56,92,77,66,47,67,48,53,36,20,71,34,67,60,58,49,88,76,67,106,71,54,38,39,23,15,109,53,51,47,90,82,58,57,48,72,57,41,23,27,62,9,86,42,40,37,70,64,52,43,70,55,42,25,29,18,11,11,118,68,30,55,50,46,74,65,49,39,24,16,22,13,14,7,91,44,39,38,34,63,52,45,31,52,28,19,14,8,9,3,123,60,58,53,47,43,32,22,37,24,17,12,15,10,2,1,71,37,34,30,28,20,17,26,21,16,10,6,8,6,2,0],t16HB:[1,5,14,44,74,63, +110,93,172,149,138,242,225,195,376,17,3,4,12,20,35,62,53,47,83,75,68,119,201,107,207,9,15,13,23,38,67,58,103,90,161,72,127,117,110,209,206,16,45,21,39,69,64,114,99,87,158,140,252,212,199,387,365,26,75,36,68,65,115,101,179,164,155,264,246,226,395,382,362,9,66,30,59,56,102,185,173,265,142,253,232,400,388,378,445,16,111,54,52,100,184,178,160,133,257,244,228,217,385,366,715,10,98,48,91,88,165,157,148,261,248,407,397,372,380,889,884,8,85,84,81,159,156,143,260,249,427,401,392,383,727,713,708,7,154,76,73, +141,131,256,245,426,406,394,384,735,359,710,352,11,139,129,67,125,247,233,229,219,393,743,737,720,885,882,439,4,243,120,118,115,227,223,396,746,742,736,721,712,706,223,436,6,202,224,222,218,216,389,386,381,364,888,443,707,440,437,1728,4,747,211,210,208,370,379,734,723,714,1735,883,877,876,3459,865,2,377,369,102,187,726,722,358,711,709,866,1734,871,3458,870,434,0,12,10,7,11,10,17,11,9,13,12,10,7,5,3,1,3],t24HB:[15,13,46,80,146,262,248,434,426,669,653,649,621,517,1032,88,14,12,21,38,71,130,122,216, +209,198,327,345,319,297,279,42,47,22,41,74,68,128,120,221,207,194,182,340,315,295,541,18,81,39,75,70,134,125,116,220,204,190,178,325,311,293,271,16,147,72,69,135,127,118,112,210,200,188,352,323,306,285,540,14,263,66,129,126,119,114,214,202,192,180,341,317,301,281,262,12,249,123,121,117,113,215,206,195,185,347,330,308,291,272,520,10,435,115,111,109,211,203,196,187,353,332,313,298,283,531,381,17,427,212,208,205,201,193,186,177,169,320,303,286,268,514,377,16,335,199,197,191,189,181,174,333,321,305,289, +275,521,379,371,11,668,184,183,179,175,344,331,314,304,290,277,530,383,373,366,10,652,346,171,168,164,318,309,299,287,276,263,513,375,368,362,6,648,322,316,312,307,302,292,284,269,261,512,376,370,364,359,4,620,300,296,294,288,282,273,266,515,380,374,369,365,361,357,2,1033,280,278,274,267,264,259,382,378,372,367,363,360,358,356,0,43,20,19,17,15,13,11,9,7,6,4,7,5,3,1,3],t32HB:[1,10,8,20,12,20,16,32,14,12,24,0,28,16,24,16],t33HB:[15,28,26,48,22,40,36,64,14,24,20,32,12,16,8,0],t1l:[1,4,3,5],t2l:[1,4, +7,4,5,7,6,7,8],t3l:[2,3,7,4,4,7,6,7,8],t5l:[1,4,7,8,4,5,8,9,7,8,9,10,8,8,9,10],t6l:[3,4,6,8,4,4,6,7,5,6,7,8,7,7,8,9],t7l:[1,4,7,9,9,10,4,6,8,9,9,10,7,7,9,10,10,11,8,9,10,11,11,11,8,9,10,11,11,12,9,10,11,12,12,12],t8l:[2,4,7,9,9,10,4,4,6,10,10,10,7,6,8,10,10,11,9,10,10,11,11,12,9,9,10,11,12,12,10,10,11,11,13,13],t9l:[3,4,6,7,9,10,4,5,6,7,8,10,5,6,7,8,9,10,7,7,8,9,9,10,8,8,9,9,10,11,9,9,10,10,11,11],t10l:[1,4,7,9,10,10,10,11,4,6,8,9,10,11,10,10,7,8,9,10,11,12,11,11,8,9,10,11,12,12,11,12,9,10,11,12, +12,12,12,12,10,11,12,12,13,13,12,13,9,10,11,12,12,12,13,13,10,10,11,12,12,13,13,13],t11l:[2,4,6,8,9,10,9,10,4,5,6,8,10,10,9,10,6,7,8,9,10,11,10,10,8,8,9,11,10,12,10,11,9,10,10,11,11,12,11,12,9,10,11,12,12,13,12,13,9,9,9,10,11,12,12,12,9,9,10,11,12,12,12,12],t12l:[4,4,6,8,9,10,10,10,4,5,6,7,9,9,10,10,6,6,7,8,9,10,9,10,7,7,8,8,9,10,10,10,8,8,9,9,10,10,10,11,9,9,10,10,10,11,10,11,9,9,9,10,10,11,11,12,10,10,10,11,11,11,11,12],t13l:[1,5,7,8,9,10,10,11,10,11,12,12,13,13,14,14,4,6,8,9,10,10,11,11,11,11, +12,12,13,14,14,14,7,8,9,10,11,11,12,12,11,12,12,13,13,14,15,15,8,9,10,11,11,12,12,12,12,13,13,13,13,14,15,15,9,9,11,11,12,12,13,13,12,13,13,14,14,15,15,16,10,10,11,12,12,12,13,13,13,13,14,13,15,15,16,16,10,11,12,12,13,13,13,13,13,14,14,14,15,15,16,16,11,11,12,13,13,13,14,14,14,14,15,15,15,16,18,18,10,10,11,12,12,13,13,14,14,14,14,15,15,16,17,17,11,11,12,12,13,13,13,15,14,15,15,16,16,16,18,17,11,12,12,13,13,14,14,15,14,15,16,15,16,17,18,19,12,12,12,13,14,14,14,14,15,15,15,16,17,17,17,18,12,13,13,14, +14,15,14,15,16,16,17,17,17,18,18,18,13,13,14,15,15,15,16,16,16,16,16,17,18,17,18,18,14,14,14,15,15,15,17,16,16,19,17,17,17,19,18,18,13,14,15,16,16,16,17,16,17,17,18,18,21,20,21,18],t15l:[3,5,6,8,8,9,10,10,10,11,11,12,12,12,13,14,5,5,7,8,9,9,10,10,10,11,11,12,12,12,13,13,6,7,7,8,9,9,10,10,10,11,11,12,12,13,13,13,7,8,8,9,9,10,10,11,11,11,12,12,12,13,13,13,8,8,9,9,10,10,11,11,11,11,12,12,12,13,13,13,9,9,9,10,10,10,11,11,11,11,12,12,13,13,13,14,10,9,10,10,10,11,11,11,11,12,12,12,13,13,14,14,10,10,10, +11,11,11,11,12,12,12,12,12,13,13,13,14,10,10,10,11,11,11,11,12,12,12,12,13,13,14,14,14,10,10,11,11,11,11,12,12,12,13,13,13,13,14,14,14,11,11,11,11,12,12,12,12,12,13,13,13,13,14,15,14,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,15,12,12,11,12,12,12,13,13,13,13,13,13,14,14,15,15,12,12,12,12,12,13,13,13,13,14,14,14,14,14,15,15,13,13,13,13,13,13,13,13,14,14,14,14,15,15,14,15,13,13,13,13,13,13,13,14,14,14,14,14,15,15,15,15],t16_5l:[1,5,7,9,10,10,11,11,12,12,12,13,13,13,14,11,4,6,8,9,10,11,11,11,12,12, +12,13,14,13,14,11,7,8,9,10,11,11,12,12,13,12,13,13,13,14,14,12,9,9,10,11,11,12,12,12,13,13,14,14,14,15,15,13,10,10,11,11,12,12,13,13,13,14,14,14,15,15,15,12,10,10,11,11,12,13,13,14,13,14,14,15,15,15,16,13,11,11,11,12,13,13,13,13,14,14,14,14,15,15,16,13,11,11,12,12,13,13,13,14,14,15,15,15,15,17,17,13,11,12,12,13,13,13,14,14,15,15,15,15,16,16,16,13,12,12,12,13,13,14,14,15,15,15,15,16,15,16,15,14,12,13,12,13,14,14,14,14,15,16,16,16,17,17,16,13,13,13,13,13,14,14,15,16,16,16,16,16,16,15,16,14,13,14,14, +14,14,15,15,15,15,17,16,16,16,16,18,14,15,14,14,14,15,15,16,16,16,18,17,17,17,19,17,14,14,15,13,14,16,16,15,16,16,17,18,17,19,17,16,14,11,11,11,12,12,13,13,13,14,14,14,14,14,14,14,12],t16l:[1,5,7,9,10,10,11,11,12,12,12,13,13,13,14,10,4,6,8,9,10,11,11,11,12,12,12,13,14,13,14,10,7,8,9,10,11,11,12,12,13,12,13,13,13,14,14,11,9,9,10,11,11,12,12,12,13,13,14,14,14,15,15,12,10,10,11,11,12,12,13,13,13,14,14,14,15,15,15,11,10,10,11,11,12,13,13,14,13,14,14,15,15,15,16,12,11,11,11,12,13,13,13,13,14,14,14,14, +15,15,16,12,11,11,12,12,13,13,13,14,14,15,15,15,15,17,17,12,11,12,12,13,13,13,14,14,15,15,15,15,16,16,16,12,12,12,12,13,13,14,14,15,15,15,15,16,15,16,15,13,12,13,12,13,14,14,14,14,15,16,16,16,17,17,16,12,13,13,13,13,14,14,15,16,16,16,16,16,16,15,16,13,13,14,14,14,14,15,15,15,15,17,16,16,16,16,18,13,15,14,14,14,15,15,16,16,16,18,17,17,17,19,17,13,14,15,13,14,16,16,15,16,16,17,18,17,19,17,16,13,10,10,10,11,11,12,12,12,13,13,13,13,13,13,13,10],t24l:[4,5,7,8,9,10,10,11,11,12,12,12,12,12,13,10,5,6,7,8, +9,10,10,11,11,11,12,12,12,12,12,10,7,7,8,9,9,10,10,11,11,11,11,12,12,12,13,9,8,8,9,9,10,10,10,11,11,11,11,12,12,12,12,9,9,9,9,10,10,10,10,11,11,11,12,12,12,12,13,9,10,9,10,10,10,10,11,11,11,11,12,12,12,12,12,9,10,10,10,10,10,11,11,11,11,12,12,12,12,12,13,9,11,10,10,10,11,11,11,11,12,12,12,12,12,13,13,10,11,11,11,11,11,11,11,11,11,12,12,12,12,13,13,10,11,11,11,11,11,11,11,12,12,12,12,12,13,13,13,10,12,11,11,11,11,12,12,12,12,12,12,13,13,13,13,10,12,12,11,11,11,12,12,12,12,12,12,13,13,13,13,10,12,12, +12,12,12,12,12,12,12,12,13,13,13,13,13,10,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,10,13,12,12,12,12,12,12,13,13,13,13,13,13,13,13,10,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,6],t32l:[1,5,5,7,5,8,7,9,5,7,7,9,7,9,9,10],t33l:[4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8]};r.ht=[new Q(0,0,null,null),new Q(2,0,r.t1HB,r.t1l),new Q(3,0,r.t2HB,r.t2l),new Q(3,0,r.t3HB,r.t3l),new Q(0,0,null,null),new Q(4,0,r.t5HB,r.t5l),new Q(4,0,r.t6HB,r.t6l),new Q(6,0,r.t7HB,r.t7l),new Q(6,0,r.t8HB,r.t8l),new Q(6,0,r.t9HB,r.t9l),new Q(8, +0,r.t10HB,r.t10l),new Q(8,0,r.t11HB,r.t11l),new Q(8,0,r.t12HB,r.t12l),new Q(16,0,r.t13HB,r.t13l),new Q(0,0,null,r.t16_5l),new Q(16,0,r.t15HB,r.t15l),new Q(1,1,r.t16HB,r.t16l),new Q(2,3,r.t16HB,r.t16l),new Q(3,7,r.t16HB,r.t16l),new Q(4,15,r.t16HB,r.t16l),new Q(6,63,r.t16HB,r.t16l),new Q(8,255,r.t16HB,r.t16l),new Q(10,1023,r.t16HB,r.t16l),new Q(13,8191,r.t16HB,r.t16l),new Q(4,15,r.t24HB,r.t24l),new Q(5,31,r.t24HB,r.t24l),new Q(6,63,r.t24HB,r.t24l),new Q(7,127,r.t24HB,r.t24l),new Q(8,255,r.t24HB,r.t24l), +new Q(9,511,r.t24HB,r.t24l),new Q(11,2047,r.t24HB,r.t24l),new Q(13,8191,r.t24HB,r.t24l),new Q(0,0,r.t32HB,r.t32l),new Q(0,0,r.t33HB,r.t33l)];r.largetbl=[65540,327685,458759,589832,655369,655370,720906,720907,786443,786444,786444,851980,851980,851980,917517,655370,262149,393222,524295,589832,655369,720906,720906,720907,786443,786443,786444,851980,917516,851980,917516,655370,458759,524295,589832,655369,720905,720906,786442,786443,851979,786443,851979,851980,851980,917516,917517,720905,589832,589832, +655369,720905,720906,786442,786442,786443,851979,851979,917515,917516,917516,983052,983052,786441,655369,655369,720905,720906,786442,786442,851978,851979,851979,917515,917516,917516,983052,983052,983053,720905,655370,655369,720906,720906,786442,851978,851979,917515,851979,917515,917516,983052,983052,983052,1048588,786441,720906,720906,720906,786442,851978,851979,851979,851979,917515,917516,917516,917516,983052,983052,1048589,786441,720907,720906,786442,786442,851979,851979,851979,917515,917516,983052, +983052,983052,983052,1114125,1114125,786442,720907,786443,786443,851979,851979,851979,917515,917515,983051,983052,983052,983052,1048588,1048589,1048589,786442,786443,786443,786443,851979,851979,917515,917515,983052,983052,983052,983052,1048588,983053,1048589,983053,851978,786444,851979,786443,851979,917515,917516,917516,917516,983052,1048588,1048588,1048589,1114125,1114125,1048589,786442,851980,851980,851979,851979,917515,917516,983052,1048588,1048588,1048588,1048588,1048589,1048589,983053,1048589, +851978,851980,917516,917516,917516,917516,983052,983052,983052,983052,1114124,1048589,1048589,1048589,1048589,1179661,851978,983052,917516,917516,917516,983052,983052,1048588,1048588,1048589,1179661,1114125,1114125,1114125,1245197,1114125,851978,917517,983052,851980,917516,1048588,1048588,983052,1048589,1048589,1114125,1179661,1114125,1245197,1114125,1048589,851978,655369,655369,655369,720905,720905,786441,786441,786441,851977,851977,851977,851978,851978,851978,851978,655366];r.table23=[65538,262147, +458759,262148,327684,458759,393222,458759,524296];r.table56=[65539,262148,458758,524296,262148,327684,524294,589831,458757,524294,589831,655368,524295,524295,589832,655369];r.bitrate_table=[[0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1],[0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1],[0,8,16,24,32,40,48,56,64,-1,-1,-1,-1,-1,-1,-1]];r.samplerate_table=[[22050,24E3,16E3,-1],[44100,48E3,32E3,-1],[11025,12E3,8E3,-1]];r.scfsi_band=[0,6,11,16,21];ma.Q_MAX=257;ma.Q_MAX2=116;ma.LARGE_BITS=1E5; +ma.IXMAX_VAL=8206;var na={};na.SFBMAX=3*d.SBMAX_s;d.ENCDELAY=576;d.POSTDELAY=1152;d.MDCTDELAY=48;d.FFTOFFSET=224+d.MDCTDELAY;d.DECDELAY=528;d.SBLIMIT=32;d.CBANDS=64;d.SBPSY_l=21;d.SBPSY_s=12;d.SBMAX_l=22;d.SBMAX_s=13;d.PSFB21=6;d.PSFB12=6;d.BLKSIZE=1024;d.HBLKSIZE=d.BLKSIZE/2+1;d.BLKSIZE_s=256;d.HBLKSIZE_s=d.BLKSIZE_s/2+1;d.NORM_TYPE=0;d.START_TYPE=1;d.SHORT_TYPE=2;d.STOP_TYPE=3;d.MPG_MD_LR_LR=0;d.MPG_MD_LR_I=1;d.MPG_MD_MS_LR=2;d.MPG_MD_MS_I=3;d.fircoef=[-.1039435,-.1892065,-.0432472*5,-.155915,3.898045E-17, +.0467745*5,.50455,.756825,.187098*5];da.MFSIZE=3456+d.ENCDELAY-d.MDCTDELAY;da.MAX_HEADER_BUF=256;da.MAX_BITS_PER_CHANNEL=4095;da.MAX_BITS_PER_GRANULE=7680;da.BPC=320;Ca.RIFF=Ob("RIFF");Ca.WAVE=Ob("WAVE");Ca.fmt_=Ob("fmt ");Ca.data=Ob("data");Ca.readHeader=function(d){var k=new Ca,q=d.getUint32(0,!1);if(Ca.RIFF==q&&(d.getUint32(4,!0),Ca.WAVE==d.getUint32(8,!1)&&Ca.fmt_==d.getUint32(12,!1))){var r=d.getUint32(16,!0),B=20;switch(r){case 16:case 18:k.channels=d.getUint16(B+2,!0);k.sampleRate=d.getUint32(B+ +4,!0);break;default:throw"extended fmt chunk not implemented";}for(var B=B+r,r=Ca.data,t=0;r!=q;){q=d.getUint32(B,!1);t=d.getUint32(B+4,!0);if(r==q)break;B+=t+8}k.dataLen=t;k.dataOffset=B+8;return k}};na.SFBMAX=3*d.SBMAX_s;this.Mp3Encoder=function(d,k,q){3!=arguments.length&&(console.error("WARN: Mp3Encoder(channels, samplerate, kbps) not specified"),d=1,k=44100,q=128);var r=new V,B=new Uc,t=new O,H=new ua,g=new Gc,b=new ma,l=new Oc,a=new ub,h=new Fc,D=new Xc,e=new Hc,n=new tb,c=new Vc,f=new Wc;r.setModules(t, +H,g,b,l,a,h,D,f);H.setModules(t,f,h,a);D.setModules(H,h);g.setModules(r);l.setModules(H,e,b,n);b.setModules(n,e,r.enc.psy);e.setModules(H);n.setModules(b);a.setModules(r,H,h);B.setModules(c,f);c.setModules(h,D,g);var E=r.lame_init();E.num_channels=d;E.in_samplerate=k;E.brate=q;E.mode=ka.STEREO;E.quality=3;E.bWriteVbrTag=!1;E.disable_reservoir=!0;E.write_id3tag_automatic=!1;r.lame_init_params(E);var z=1152,w=0|1.25*z+7200,A=new Int8Array(w);this.encodeBuffer=function(a,b){1==d&&(b=a);a.length>z&&(z= +a.length,w=0|1.25*z+7200,A=new Int8Array(w));var c=r.lame_encode_buffer(E,a,b,a.length,A,0,w);return new Int8Array(A.subarray(0,c))};this.flush=function(){var a=r.lame_encode_flush(E,A,0,w);return new Int8Array(A.subarray(0,a))}};this.WavHeader=Ca}; diff --git a/form/src/assets/libs/audio-recorder/recorder.js b/form/src/assets/libs/audio-recorder/recorder.js new file mode 100644 index 0000000000000000000000000000000000000000..fba724169978e87c9c776d977d90c2fe4fe11431 --- /dev/null +++ b/form/src/assets/libs/audio-recorder/recorder.js @@ -0,0 +1,141 @@ +(function (exports) { + //公共方法 + var Util = { + //åˆå§‹åŒ– + init: function () { + navigator.getUserMedia = navigator.getUserMedia || + navigator.webkitGetUserMedia || + navigator.mozGetUserMedia || + navigator.msGetUserMedia; + + window.AudioContext = window.AudioContext || + window.webkitAudioContext; + }, + //日志 + log: function () { + console.log.apply(console, arguments); + } + }; + //æž„é€ å‡½æ•° + var Recorder = function (config) { + + var _this = this; + config = config || {}; //åˆå§‹åŒ–é…置对象 + config.sampleRate = config.sampleRate || 44100; //é‡‡æ ·é¢‘çŽ‡ï¼Œé»˜è®¤ä¸º44100Hz(æ ‡å‡†MP3é‡‡æ ·çŽ‡) + config.bitRate = config.bitRate || 128; //比特率,默认为128kbps(æ ‡å‡†MP3è´¨é‡) + + Util.init(); + + if (navigator.getUserMedia) { + navigator.getUserMedia({ + audio: true //é…置对象 + }, + function (stream) { //æˆåŠŸå›žè°ƒ + var context = new AudioContext(), + microphone = context.createMediaStreamSource(stream), //媒体æµéŸ³é¢‘æº + processor = context.createScriptProcessor(16384, 1, 1), //js音频处ç†å™¨ + successCallback, errorCallback; + + config.sampleRate = context.sampleRate; + + processor.onaudioprocess = function (event) { + //监å¬éŸ³é¢‘录制过程 + var array = event.inputBuffer.getChannelData(0); + realTimeWorker.postMessage({cmd: 'encode', buf: array}); + }; + + var realTimeWorker = new Worker('assets/libs/audio-recorder/worker.js'); //å¼€å¯åŽå°çº¿ç¨‹ + _this.worker = realTimeWorker; + realTimeWorker.onmessage = function (e) { //主线程监å¬åŽå°çº¿ç¨‹ï¼Œå®žæ—¶é€šä¿¡ + switch (e.data.cmd) { + case 'init': + Util.log('åˆå§‹åŒ–æˆåŠŸ'); + if (config.success) { + config.success(); + } + break; + case 'end': + if (successCallback) { + var blob = new Blob(e.data.buf, {type: 'audio/mp3'}); + successCallback(blob); + Util.log('MP3大å°ï¼š' + blob.size + '%cB', 'color:#0000EE'); + } + break; + case 'error': + Util.log('错误信æ¯ï¼š' + e.data.error); + if (errorCallback) { + errorCallback(e.data.error); + } + break; + default: + Util.log('未知信æ¯ï¼š' + e.data); + } + }; + //接å£åˆ—表 + //开始录音 + _this.start = function () { + if (processor && microphone) { + microphone.connect(processor); + processor.connect(context.destination); + Util.log('开始录音'); + } + }; + //结æŸå½•音 + _this.stop = function () { + if (processor && microphone) { + microphone.disconnect(); + processor.disconnect(); + Util.log('录音结æŸ'); + } + }; + //获å–blobæ ¼å¼å½•音文件 + _this.getBlob = function (onSuccess, onError) { + successCallback = onSuccess; + errorCallback = onError; + realTimeWorker.postMessage({cmd: 'finish'}); + }; + + realTimeWorker.postMessage({ + cmd: 'init', + config: { + sampleRate: config.sampleRate, + bitRate: config.bitRate + } + }); + }, + function (error) { //失败回调 + var msg; + switch (error.code || error.name) { + case 'PermissionDeniedError': + case 'PERMISSION_DENIED': + case 'NotAllowedError': + msg = '用户拒ç»è®¿é—®éº¦å…‹é£Ž'; + break; + case 'NOT_SUPPORTED_ERROR': + case 'NotSupportedError': + msg = 'æµè§ˆå™¨ä¸æ”¯æŒéº¦å…‹é£Ž'; + break; + case 'MANDATORY_UNSATISFIED_ERROR': + case 'MandatoryUnsatisfiedError': + msg = '找ä¸åˆ°éº¦å…‹é£Žè®¾å¤‡'; + break; + default: + msg = 'æ— æ³•æ‰“å¼€éº¦å…‹é£Žï¼Œå¼‚å¸¸ä¿¡æ¯:' + (error.code || error.name); + break; + } + Util.log(msg); + if (config.error) { + config.error(msg); + } + }); + } else { + Util.log('当剿µè§ˆå™¨ä¸æ”¯æŒå½•音功能'); + if (config.fix) { + config.fix('当剿µè§ˆå™¨ä¸æ”¯æŒå½•音功能'); + } + } + + }; + //æ¨¡å—æŽ¥å£ + exports.Recorder = Recorder; +})(window); diff --git a/form/src/assets/libs/audio-recorder/worker.js b/form/src/assets/libs/audio-recorder/worker.js new file mode 100644 index 0000000000000000000000000000000000000000..41e7c93988ef1bbbf49a3115fc61e9849149c44e --- /dev/null +++ b/form/src/assets/libs/audio-recorder/worker.js @@ -0,0 +1,108 @@ +(function () { + 'use strict'; + if (!importScripts) { + var importScripts = (function (globalEval) { + var xhr = new XMLHttpRequest; + return function importScripts() { + var + args = Array.prototype.slice.call(arguments) + , len = args.length + , i = 0 + , meta + , data + , content + ; + for (; i < len; i++) { + if (args[i].substr(0, 5).toLowerCase() === "data:") { + data = args[i]; + content = data.indexOf(","); + meta = data.substr(5, content).toLowerCase(); + data = decodeURIComponent(data.substr(content + 1)); + if (/;\s*base64\s*[;,]/.test(meta)) { + data = atob(data); + } + if (/;\s*charset=[uU][tT][fF]-?8\s*[;,]/.test(meta)) { + data = decodeURIComponent(escape(data)); + } + } else { + xhr.open("GET", args[i], false); + xhr.send(null); + data = xhr.responseText; + } + globalEval(data); + } + }; + }(eval)); + } + + + importScripts('assets/libs/audio-recorder/lame.min.js'); + + var mp3Encoder, maxSamples = 1152, samplesMono, lame, config, dataBuffer; + + var clearBuffer = function () { + dataBuffer = []; + }; + + var appendToBuffer = function (mp3Buf) { + dataBuffer.push(new Int8Array(mp3Buf)); + }; + + var init = function (prefConfig) { + config = prefConfig || {}; + lame = new lamejs(); + mp3Encoder = new lame.Mp3Encoder(1, config.sampleRate || 44100, config.bitRate || 128); + clearBuffer(); + self.postMessage({ + cmd: 'init' + }); + }; + + var floatTo16BitPCM = function (input, output) { + for (var i = 0; i < input.length; i++) { + var s = Math.max(-1, Math.min(1, input[i])); + output[i] = (s < 0 ? s * 0x8000 : s * 0x7FFF); + } + }; + + var convertBuffer = function (arrayBuffer) { + var data = new Float32Array(arrayBuffer); + var out = new Int16Array(arrayBuffer.length); + floatTo16BitPCM(data, out); + return out; + }; + + var encode = function (arrayBuffer) { + samplesMono = convertBuffer(arrayBuffer); + var remaining = samplesMono.length; + for (var i = 0; remaining >= 0; i += maxSamples) { + var left = samplesMono.subarray(i, i + maxSamples); + var mp3buf = mp3Encoder.encodeBuffer(left); + appendToBuffer(mp3buf); + remaining -= maxSamples; + } + }; + + var finish = function () { + appendToBuffer(mp3Encoder.flush()); + self.postMessage({ + cmd: 'end', + buf: dataBuffer + }); + clearBuffer(); + }; + + self.onmessage = function (e) { + switch (e.data.cmd) { + case 'init': + init(e.data.config); + break; + case 'encode': + encode(e.data.buf); + break; + case 'finish': + finish(); + break; + } + }; +})(); diff --git a/form/src/assets/libs/service-worker/cache-service.js b/form/src/assets/libs/service-worker/cache-service.js new file mode 100644 index 0000000000000000000000000000000000000000..d9111ae6c9fe6486339ab52c4df819a9e0b42e0d --- /dev/null +++ b/form/src/assets/libs/service-worker/cache-service.js @@ -0,0 +1,535 @@ +/* + Copyright 2014 Google Inc. All Rights Reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +// While overkill for this specific sample in which there is only one cache, +// this is one best practice that can be followed in general to keep track of +// multiple caches used by a given service worker, and keep them all versioned. +// It maps a shorthand identifier for a cache to a specific, versioned cache name. + +// Note that since global state is discarded in between service worker restarts, these +// variables will be reinitialized each time the service worker handles an event, and you +// should not attempt to change their values inside an event handler. (Treat them as constants.) + +// If at any point you want to force pages that use this service worker to start using a fresh +// cache, then increment the CACHE_VERSION value. It will kick off the service worker update +// flow and the old cache(s) will be purged as part of the activate event handler when the +// updated service worker is activated. +var CACHE_SID = 0; +var CACHE_VER = ''; +var isPlayerPage = false; +// var CURRENT_CACHES = {}; +// var CURRENT_CACHES = null; + +async function progressDownloader(urlOrRequest, port, sid) { + let url = urlOrRequest; + let response = await fetch(url); + if (urlOrRequest instanceof Request) { + url = urlOrRequest.url; + } + let isBin = false; + if (url.endsWith('.mp4') + || url.endsWith('.mp3') + || url.endsWith('.jpg') + || url.endsWith('.png')){ + isBin = true; + } + + const reader = response.body.getReader(); + const contentLength = +response.headers.get('Content-Length'); + port.postMessage({ + len: contentLength, + status: 'init', + sid + }); + let receivedLength = 0; + let mb = 0; + let timeS = new Date().getTime(); + let timeD = 0; + let speed = 0; + let chunks = []; // array of received binary chunks (comprises the body) + while(true) { + const {done, value} = await reader.read(); + if (done) { + break; + } + chunks.push(value); + receivedLength += value.length; + /*mb += value.length; + if(mb > 1000 * 1000) { + timeD = new Date().getTime() - timeS; + // timeD = timeD /1000; + speed = mb / timeD; + mb = 0; + timeS = new Date().getTime(); + }*/ + // console.log(`Received ${receivedLength} of ${contentLength}`) + // cb && cb(receivedLength , contentLength) + port.postMessage({ + loaded: value.length, + status: 'downloading', + sid + }); + } + + if (isBin) { + return new Blob(chunks); + } else { + let chunksAll = new Uint8Array(receivedLength); + let position = 0; + for(let chunk of chunks) { + chunksAll.set(chunk, position); + position += chunk.length; + } + return chunksAll; //new TextDecoder("utf-8").decode(chunksAll); + } + +} +self.addEventListener('install', function(event) { + event.waitUntil(self.skipWaiting()); // Activate worker immediately +}); + +self.addEventListener('activate', function(event) { + event.waitUntil(self.clients.claim({ + includeUncontrolled: true + }).then(function() { + // After the activation and claiming is complete, send a message to each of the controlled + // pages letting it know that it's active. + // This will trigger navigator.serviceWorker.onmessage in each client. + return self.clients.matchAll().then(function(clients) { + return Promise.all(clients.map(function(client) { + // return client.postMessage('The service worker has activated and ' + + // 'taken control.'); + return client.postMessage({ + name: 'initOk', + }); + + })); + }); + })); // Become available to all pages +}); +/* +self.addEventListener('activate', function(event) { + // Delete all caches that aren't named in CURRENT_CACHES. + // While there is only one cache in this example, the same logic will handle the case where + // there are multiple versioned caches. + // var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) { + // return CURRENT_CACHES[key]; + // }); + + event.waitUntil( + caches.keys().then(function(cacheNames) { + // return Promise.all( + // cacheNames.map(function(cacheName) { + // if (expectedCacheNames.indexOf(cacheName) === -1) { + // // If this cache name isn't present in the array of "expected" cache names, then delete it. + // console.log('Deleting out of date cache:', cacheName); + // return caches.delete(cacheName); + // } + // }) + // ); + }).then(function() { + return clients.claim(); + }).then(function() { + // After the activation and claiming is complete, send a message to each of the controlled + // pages letting it know that it's active. + // This will trigger navigator.serviceWorker.onmessage in each client. + return self.clients.matchAll().then(function(clients) { + return Promise.all(clients.map(function(client) { + return client.postMessage('The service worker has activated and ' + + 'taken control.'); + })); + }); + }) + ); +});*/ + +self.addEventListener('message', function(event) { + // console.log('Handling message event:', event); + if (event.data.command === 'remove') { + if (!event.data.key) { + return; + } + caches.delete(event.data.key) + /*caches.keys().then(function(cacheNames) { + console.log('clear', cacheNames); + // return caches.delete(event.data.ver); + // CACHE_VER = event.data.newVer; + // CACHE_SID = event.data.sid; + if (!event.data.key) { + return; + } + return caches.delete(event.data.key); + return Promise.all( + cacheNames.map(function(cacheName) { + if ( cache_ver === cacheName) { + // If this cache name isn't present in the array of "expected" cache names, then delete it. + console.log('Deleting out of date cache:', cacheName); + // localStorage.removeItem('item-cache-'+event.data.sid); + // self.clients.matchAll().then(function(clients) { + // clients.forEach(function(client) { + // client.postMessage({ + // + // }); + // }); + // }); + console.log('delete', cacheName) + return caches.delete(cacheName); + } + }) + ); + })*/ + /*.then(function() { + return clients.claim(); + })*/ + /*.then(function() { + // After the activation and claiming is complete, send a message to each of the controlled + // pages letting it know that it's active. + // This will trigger navigator.serviceWorker.onmessage in each client. + return self.clients.matchAll().then(function(clients) { + return Promise.all(clients.map(function(client) { + return client.postMessage('The service worker has activated and ' + + 'taken control.'); + })); + }); + })*/ + .then(function() { + console.log('delete finished') + event.ports[0].postMessage({ + error: null + }); + }); + return; + } + if (event.data.command === 'clearAll') { + event.waitUntil( + caches.keys().then(function(cacheNames) { + return Promise.all( + cacheNames.map(function(cacheName) { + return caches.delete(cacheName); + }) + ); + }).then(function() { + event.ports[0].postMessage({ + error: null + }); + }).catch(err => { + event.ports[0].postMessage({ + error: err, + }); + }) + ); + return; + } + if (event.data.command === 'listCachedCoursewares') { + var cacheData = {} + // caches.open('item-cache-c965d3a0630911e994fa058136a96bb1-1556518161000').then(r=>{console.log(r.keys().then(items=>console.log(items[0])))}) + caches.keys().then((cacheNames) => { + cacheNames.map((cacheName) => { + if (cacheName.indexOf('item-cache') > -1) { + var size = 0; + caches.open(cacheName).then((cache) => { + console.log(cacheName) + cache.keys().then((requests) => { + console.log(requests[0]) + for(var req of requests) { + console.log(req) + cache.match(req.url).then(resp => { + console.log(resp.headers.entries()) + }) + // cache.match(req.url).then((resp) => { + // console.log(req.url, resp.length) + // size += parseInt(resp.headers['Content-Length']) + // }).catch(err => { + // console.log(err) + // }); + } + }).then(() => { + cacheData.cacheName = size; + }) + }); + + } + }); + }).then(function(result) { + // event.ports[0].postMessage({ + // error: null, + // urls: urls + // }); + }); + return; + } + + // var key = 'item-cache-' + event.data.sid + '-'+ event.data.ver; + var key = event.data.key; + var p = caches.open(key).then(function(cache) { + // throw {name: 'QuotaExceededError'} + switch (event.data.command) { + // This command returns a list of the URLs corresponding to the Request objects + // that serve as keys for the current cache. + case 'keys': + return cache.keys().then(function(requests) { + var urls = requests.map(function(request) { + return request.url; + }); + + return urls.sort(); + }).then(function(urls) { + // event.ports[0] corresponds to the MessagePort that was transferred as part of the controlled page's + // call to controller.postMessage(). Therefore, event.ports[0].postMessage() will trigger the onmessage + // handler from the controlled page. + // It's up to you how to structure the messages that you send back; this is just one example. + event.ports[0].postMessage({ + error: null, + urls: urls + }); + }); + + // This command adds a new request/response pair to the cache. + case 'add': + // If event.data.url isn't a valid URL, new Request() will throw a TypeError which will be handled + // by the outer .catch(). + // Hardcode {mode: 'no-cors} since the default for new Requests constructed from strings is to require + // CORS, and we don't have any way of knowing whether an arbitrary URL that a user entered supports CORS. + var request = new Request(event.data.url, {mode: 'cors', cache: 'reload'}); // {mode: 'no-cors'} + // console.log('start', event.data.url); + // return fetch(request) + // .then(function(res){ + // return res.arrayBuffer(); + // }) + const startTime = new Date().getTime(); + let len = 0; + return progressDownloader(request, event.ports[0], event.data.sid).then((ab) => { + var cl = ab.size ? ab.size : ab.byteLength; + len = cl; + return cache.put(event.data.url, new Response(ab, { + // url: event.data.url, + // type: 'cors', + status: 200, + statusText: 'OK', + headers: [ + ['Content-Length', cl+''], + ] + })); + }).then(function(r) { + event.ports[0].postMessage({ + error: null, + status: 'finished', + len: len, + time: new Date().getTime() - startTime + }); + }); + + // This command removes a request/response pair from the cache (assuming it exists). + case 'delete': + return cache.delete(event.data.url).then(function(success) { + event.ports[0].postMessage({ + error: success ? null : 'Item was not found in the cache.' + }); + }); + + default: + // This will be handled by the outer .catch(). + throw Error('Unknown command: ' + event.data.command); + } + }).catch(function(error) { + // If the promise rejects, handle it by returning a standardized error message to the controlled page. + console.log('Message handling failed:', event.data.url, error); + // if (error.name == 'QuotaExceededError') { + event.ports[0].postMessage({ + //error: {name: 'QuotaExceededError'} + error: {name: error.name, message: error.message}, + status: 'error' + }); + // } + }); + + // Beginning in Chrome 51, event is an ExtendableMessageEvent, which supports + // the waitUntil() method for extending the lifetime of the event handler + // until the promise is resolved. + if ('waitUntil' in event) { + event.waitUntil(p); + } + + // Without support for waitUntil(), there's a chance that if the promise chain + // takes "too long" to execute, the service worker might be automatically + // stopped before it's complete. +}); + + +self.addEventListener('fetch', function(event) { + + // console.log('Handling fetch event for', event.request.method, event.request.url); + // if (event.request.method !== 'GET' || !CACHE_SID || !CACHE_VER) { + // event.respondWith(function(){ + // return fetch(request).then(networkResponse => { + // return networkResponse; + // }).catch(_ => { + // console.error('direct Fetching failed:', error); + // + // throw error; + // }) + // }); + // + // return; + // } + + /*if (!CACHE_SID || !CACHE_VER) { + event.request.mode = 'no-cors'; + return fetch(event.request).then(function(response) { + // console.log('Response from network is:', response); + console.log(999) + return response; + }).catch(function(error) { + // This catch() will handle exceptions thrown from the fetch() operation. + // Note that a HTTP error response (e.g. 404) will NOT trigger an exception. + // It will return a normal response object that has the appropriate error code set. + console.error('Fetching failed 9:', error); + + throw error; + }); + }*/ + // var isNormReq = !CACHE_SID || !CACHE_VER; + // var key = 'item-cache-' + CACHE_SID + '-'+ CACHE_VER; + if (event.request.method == 'GET' ) { + if (event.request.headers.get('range')) { + var pos = + Number(/^bytes\=(\d+)\-$/g.exec(event.request.headers.get('range'))[1]); + // console.log('Range request for', event.request.url, + // ', starting position:', pos); + event.respondWith( + caches.match(event.request.url, { + ignoreSearch: true, + ignoreVary: true + }).then(function(response) { + if (response) { + console.log('Found response in cache:', event.request.url); + return response.arrayBuffer().then(ab => { + return new Response( + ab.slice(pos), + { + status: 206, + statusText: 'Partial Content', + headers: [ + ['Content-Length', ab.byteLength+''], + ['Content-Range', 'bytes ' + pos + '-' + + (ab.byteLength - 1) + '/' + ab.byteLength]] + }); + }); + + // return response; + } + // event.request.mode = 'cors'; + // event.request.cache = 'reload'; + var request = new Request(event.request.url, + { + method: event.request.method, + mode: 'cors', + cache: 'reload', + headers: event.request.headers + }); + return fetch(request).then(function(response) { + console.log('Response from network is:', event.request.url); + return response; + })/*.then(res => { + return res.arrayBuffer(); + }).then(ab => { + return new Response( + ab.slice(pos), + { + status: 206, + statusText: 'Partial Content', + headers: [ + ['Content-Length', ab.byteLength+''], + ['Content-Range', 'bytes ' + pos + '-' + + (ab.byteLength - 1) + '/' + (pos + ab.byteLength)]] + }); + })*/ + }) + /*caches.open(key) + .then(function(cache) { + return cache.match(event.request.url); + }).then(function(res) { + if (!res) { + return fetch(event.request) + .then(res => { + return res.arrayBuffer(); + }); + } + return res.arrayBuffer(); + }).then(function(ab) { + return new Response( + ab.slice(pos), + { + status: 206, + statusText: 'Partial Content', + headers: [ + ['Content-Length', ab.byteLength+''], + ['Content-Range', 'bytes ' + pos + '-' + + (ab.byteLength - 1) + '/' + ab.byteLength]] + }); + })*/ + ); + } else { + // console.log('Non-range request for', event.request.url); + event.respondWith( + // caches.match() will look for a cache entry in all of the caches available to the service worker. + // It's an alternative to first opening a specific named cache and then matching on that. + caches.match(event.request, { + ignoreSearch: true, + ignoreVary: true + }).then(function(response) { + if (response) { + // console.log('%c Response in cache:', 'color:DodgerBlue;', response); + return response; + } + + // event.request will always have the proper mode set ('cors, 'no-cors', etc.) so we don't + // have to hardcode 'no-cors' like we do when fetch()ing in the install handler. + // event.request.mode = 'cors'; + // cache: 'reload' + if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { + return; + } + // console.log('No response found in cache.', event.request.url); + return fetch(event.request).then(function(response) { + // console.log('%c Response from network is:', 'color:#bada55', response); + + return response; + }).catch(function(error) { + // This catch() will handle exceptions thrown from the fetch() operation. + // Note that a HTTP error response (e.g. 404) will NOT trigger an exception. + // It will return a normal response object that has the appropriate error code set. + console.error('Fetching failed:', error); + + // throw error; + }); + }) + ); + } + } else { + event.respondWith( + fetch(event.request).then(function(response) { + // console.log('not get from network:', response); + // console.log(888) + return response; + }).catch(function(error) { + // This catch() will handle exceptions thrown from the fetch() operation. + // Note that a HTTP error response (e.g. 404) will NOT trigger an exception. + // It will return a normal response object that has the appropriate error code set. + console.error('Fetching failed 8:', error); + throw error; + }) + ); + } +}); + diff --git a/form/src/assets/libs/video-js-7.0.0/video-js.css b/form/src/assets/libs/video-js-7.0.0/video-js.css new file mode 100644 index 0000000000000000000000000000000000000000..aff41ca123d0a129efcdd11456356eee91347973 --- /dev/null +++ b/form/src/assets/libs/video-js-7.0.0/video-js.css @@ -0,0 +1,1699 @@ +.video-js .vjs-big-play-button .vjs-icon-placeholder:before, .vjs-button > .vjs-icon-placeholder:before, .video-js .vjs-modal-dialog, .vjs-modal-dialog .vjs-modal-dialog-content { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.video-js .vjs-big-play-button .vjs-icon-placeholder:before, .vjs-button > .vjs-icon-placeholder:before { + text-align: center; +} + +@font-face { + font-family: VideoJS; + src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAABBIAAsAAAAAGoQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADsAAABUIIslek9TLzIAAAFEAAAAPgAAAFZRiV3RY21hcAAAAYQAAADQAAADIjn098ZnbHlmAAACVAAACv4AABEIAwnSw2hlYWQAAA1UAAAAKgAAADYUHzoRaGhlYQAADYAAAAAbAAAAJA4DByFobXR4AAANnAAAAA8AAACE4AAAAGxvY2EAAA2sAAAARAAAAEQ9NEHGbWF4cAAADfAAAAAfAAAAIAEyAIFuYW1lAAAOEAAAASUAAAIK1cf1oHBvc3QAAA84AAABDwAAAZ5AAl/0eJxjYGRgYOBiMGCwY2BycfMJYeDLSSzJY5BiYGGAAJA8MpsxJzM9kYEDxgPKsYBpDiBmg4gCACY7BUgAeJxjYGQ7xTiBgZWBgaWQ5RkDA8MvCM0cwxDOeI6BgYmBlZkBKwhIc01hcPjI+FGBHcRdyA4RZgQRAC4HCwEAAHic7dFprsIgAEXhg8U61XmeWcBb1FuQP4w7ZQXK5boMm3yclFDSANAHmuKviBBeBPQ8ymyo8w3jOh/5r2ui5nN6v8sYNJb3WMdeWRvLji0DhozKdxM6psyYs2DJijUbtuzYc+DIiTMXrty4k8oGLb+n0xCe37ekM7Z66j1DbUy3l6PpHnLfdLO5NdSBoQ4NdWSoY9ON54mhdqa/y1NDnRnq3FAXhro01JWhrg11Y6hbQ90Z6t5QD4Z6NNSToZ4N9WKoV0O9GerdUJORPqkhTd54nJ1YDXBU1RV+576/JBs2bPYPkrDZt5vsJrv53V/I5mclhGDCTwgGBQQSTEji4hCkYIAGd4TGIWFAhV0RQTpWmQp1xv6hA4OTOlNr2zFANbHUYbq2OtNCpViRqsk+e+7bTQAhzti8vPfuPffcc88959zznbcMMPjHD/KDDGEY0ABpYX384NhlomIYlo4JISGEY9mMh2FSidYiqkEUphtNYDSY/dXg9023l4DdxlqUl0chuZRhncJKrsCQHIwcGuwfnhMIzBnuH4Sym+1D2zaGjheXlhYfD238z80mKYMmvJ5XeOTzd8z9eujbMxJNhu4C9xPE/bCMiDuSNIWgkTQwBE55hLSAE7ZwhrHLnAHZOGV/kmBGTiNjZxzI77Hb7Hqjz68TjT6vh+5JT/cCIkqS0D6CqPf5jX4Qjdx5j6vlDfZM4aZFdbVXIxtOlJaP/WottMnH6CJQ3bTiue3PrY23HjnChtuamxwvvzFjxkPrNj3z0tG9T561HDYf6OgmRWvlY3JQHoQb8ltV2Yet7YfWctEjR1AtxS/cSX6U4alf6NJEBQ7YKg9wrXQKd0IeZCb2ux75Uhh1Un+Nz+9LTOE7PK777nN5xqdTneTBhCbx446mZrhnUkrCz2YhA9dSMxaG0SYmT8hi9ZPu1E94PJYQSH6LRmhxec7Q7ZeXntgQuVpbh+a4qWNsckVyTdn0P7o7DpgPW84+uRcq0BITflBikGdUjAZ9wYBVI3mtrNvr9kpg1UsaK6t3690aoorC1lg0GpMH2HAMtkZjsSi5Ig9ESVosOh7GQfLjKNLvKpMKkLSKNFAka710GdgSi8oDMSoNhqjkKBXTgn3swtaxyzGkUzIzae9RtLdWkSlZ1KDX6EzgllzV4NV4SoDFSOGD4+HCeQUF8wrZ5Hs8zIb5EaVxy8DYFTbMCJPnLIWZxugZE2NlivC0gc1qEQUR8jEKgZcAXeH18BiCgl5nlHh0CrjB4Hb5fX4gb0J7c9PuHVsfgkx2n/vTY/JV8kn8PGxf7faOZ8qX8JVByuIf4whk9sqXli2hvPJV9hrp0hY7l8r2x37ydaVsb4xvXv/47v2NjfCl8m5oRDJclFMoE1yk0Uh1Te4/m8lFXe9qBZD0EkheicebXvzI2PLCuoKCukLuhPIeKwaHPEouxw3kMqaIUXDQ1p0mip+MyCORSCQaoUsnY1VZ38nUTrG21WvVo4f1OsEJFhvSfAFwGfT8VHRMeAVUpwLOoLzjT/REIj3O3FhuURE+nERF+0pTId5Fyxv5sfwGyg4O+my4vZv0sZm7oeQlFZORiB+tG0MweVNraeitl7yxiPIHTk4/diVxs94o5lEYishB2iAtkchEnsActoEpx44Fo8XnsQMaA22BlqC20RmhBKzYojZyYaxg+JggMc4HHY2m+L9EkWSYljirOisrO7d3VorxzyZ6Vc4lJqITAu1b2wOBdrLElAP+bFc2eGaZFVbkmJktv5uT6Jlz5D/MnBFor6ig/JPnRViBsV3LNKGGqB1ChJ0tgQywlVLFJIuQgTFttwkiKxhyQdAZMdMYtSaoAewqfvXVYPAbDT6/1mez85YS8FSDywQ6NfAnef6FNEGMilnppyvn5rB6tTyq1pOceRWnp2WJEZFXHeX5oyoem1nTTgdqc4heDY7bOeKz63vnz+/dRx+s31Ht2JGanQ5seirfWJL9tjozU/12TnEjn5oux9OzU3ckGbBzBwNOyk69JykKH0n/0LM9A72tuwM3zQpIRu4AxiToseEpgPOmbROyFe9/X2yeUvoUsCyEvjcgs7fpWP3/aKlFN0+6HFUe6D9HFz/XPwBlN9tTqNyZjFJ8UO2RUT5/h4CptCctEyeisnOyXjALEp7dXKaQKf6O7IMnGjNNACRMLxqdYJX8eMLvmmd68D+ayBLyKKYZwYxDt/GNhzETDJ05Qxlyi3pi3/Z93ndYVSumgj0V/KkIFlO6+1K3fF2+3g0q+YtuSIf0bvmLqV09nnobI6hwcjIP8aPCKayjsF5JBY3LaKAeRLSyYB1h81oTwe9SlPMkXB7G0mfL9q71gaqqwPqu67QRKS1+ObTx+sbQy9QV2OQHEScGkdFBeT7v7qisqqrs6N52i78/R+6S0qQONVj26agOVoswCyQWIV5D86vH53bxNUeXV0K+XZaHv/nm/KsHhOvylwsWnJX/HE8l/4WCv5x+l5n08z6UU8bUMa3MBpSmM7F63AxntdC9eBCKEZW9Hr+ABNqtxgAQrSbMtmrW7lKQuoSgBhSrTazWVU2QAKWY8wiiuhqFmQgWJBgoXiuWIm42N7hqZbBsgXz52O5P5uSvaNgFGnOuvsRw8I8Laha91wMvDuxqWFheN7/8GVtTltdS83DQsXRmqc5ZtcJXEVrlV2doTWk5+Yunm71dG5f55m/qY0MjI93vv9/NfpxXV9sUXrxy2fbNy1or65cOlDRnOoKFeeXcbw42H/bNDT5Qs3flgs31gWC1lD1nfUV/X7NdCnSUdHY2e8afzfKsqZ5ZljfDqjLOmk3UebNXB+aHArPYDRs+/HDDxeT5DiP+sFg7OpRaVQMGBV89PpeBdj22hCE0Uub0UqwLrNWsG0cuyadgLXTeR5rbO4+3c/vl15cur2nRq+TXCQDcS3SO+s6ak+e5/eMS+1dw3btu3YG2tvFL8XdIZvdjdW6TO/4B7IdrZWVPmctm5/59AgsPItTSbCiIBr2OqIGzmu20SMKAS7yqwGBUfGfgjDYlLLDeF0SfcLB2LSx8flT+08/kzz6yOj96rft4rpTjdPQcmLd47uKibbDq7ZSz/XtbH2nN717Nd62rU+c8Icevvv7I09wA6WvjVcafb+FsbNG+ZQ80Rn6ZZsvrP7teP2dzTdoETvNhjCmsr8FID2sJ69VYvdUcxk4AzYRlKcaE38eXNRlfW9H1as9i6acLHp1XpuNB5K7DIvkX08y1ZYvh3KfWaiCzH+ztrSDmD7LuX73x/mJelB8Yj39t8nhNQJJ2CAthpoFGLsGgtSOCJooCGoaJAMTjSWHVZ08YAa1Fg9lPI5U6DOsGVjDasJeZZ+YyhfCwfOzCxlBA69M9XLXtza7H/rav+9Tjq5xNi0wpKQIRNO4Lrzz7yp5QVYM6Jd/oc1Uvn/mQhhuWh6ENXoS2YTZ8QT42bF5d/559zp5r0Uff2VnR2tdf2/WCOd2cO0Mw6qpWPnvxpV0nrt5fZd2yItc199GWe8vlNfNDq+CH/7yAAnB9hn7T4QO4c1g9ScxsZgmzntnE/IDGndtHMw69lFwoCnYsMGx+rBp8JSBqdLzBr9QRPq/PbhWMWFtQZp1xguy/haw3TEHm3TWAnxFWQQWgt7M5OV0lCz1VRYucpWliy7z6Zd4urwPIyeZQqli2Lgg7szJV09PysATbOQtYIrB2YzbkJYkGgJ0m4AjPUap1pvYu1K9qr97z0Yl3p332b2LYB78ncYIlRkau/8GObSsOlZancACE5d5ily+c2+7h5Yj4lqhVmXXB+iXLfvdqSgqfKtQvfHDV0OnvQR1qhw42XS/vkvsh/hXcrDFP0a+SJNIomEfD1nsrYGO+1bgTOJhM8Hv6ek+7vVglxuSRwoKn17S937bm6YJCeSSG0Op1n+7tE37tcZ/p7dsTv4EUrGpDbWueKigsLHhqTVsoEj+JU0kaSjnj9tz8/gryQWwJ9BcJXBC/7smO+I/IFURJetFPrdt5WcoL6DbEJaygI8CTHfQTjf40ofD+DwalTqIAAHicY2BkYGAA4uByr8R4fpuvDNzsDCBw7f/3LmSanREszsHABKIAKi0J7gAAeJxjYGRgYGcAARD5/z87IwMjAypQBAAtgwI4AHicY2BgYGAfYAwAOkQA4QAAAAAAAA4AaAB+AMwA4AECAUIBbAGYAcICGAJYArQC4AMwA7AD3gQwBJYE3AUkBWYFigYgBmYGtAbqB1gIEghYCG4IhHicY2BkYGBQZChlYGcAASYg5gJCBob/YD4DABfTAbQAeJxdkE1qg0AYhl8Tk9AIoVDaVSmzahcF87PMARLIMoFAl0ZHY1BHdBJIT9AT9AQ9RQ9Qeqy+yteNMzDzfM+88w0K4BY/cNAMB6N2bUaPPBLukybCLvleeAAPj8JD+hfhMV7hC3u4wxs7OO4NzQSZcI/8Ltwnfwi75E/hAR7wJTyk/xYeY49fYQ/PztM+jbTZ7LY6OWdBJdX/pqs6NYWa+zMxa13oKrA6Uoerqi/JwtpYxZXJ1coUVmeZUWVlTjq0/tHacjmdxuL90OR8O0UEDYMNdtiSEpz5XQGqzlm30kzUdAYFFOb8R7NOZk0q2lwAyz1i7oAr1xoXvrOgtYhZx8wY5KRV269JZ5yGpmzPTjQhvY9je6vEElPOuJP3mWKnP5M3V+YAAAB4nG2PyXLCMBBE3YCNDWEL2ffk7o8S8oCnkCVHC5C/jzBQlUP6IHVPzYyekl5y0iL5X5/ooY8BUmQYIkeBEca4wgRTzDDHAtdY4ga3uMM9HvCIJzzjBa94wzs+8ImvZNAq8TM+HqVkKxWlrQiOxjujQkNlEzyNzl6Z/cU2XF06at7U83VQyklLpEvSnuzsb+HAPnPfQVgaupa1Jlu4sPLsFblcitaz0dHU0ZF1qatjZ1+aTXYCmp6u0gSvWNPyHLtFZ+ZeXWVSaEkqs3T8S74WklbGbNNNq4LL4+CWKtZDv2cfX8l8aFbKFhEnJnJ+IULFpqwoQnNHlHaVQtPBl+ypmbSWdmyC61KS/AKZC3Y+AA==) format("woff"); + font-weight: normal; + font-style: normal; +} + +.vjs-icon-play, .video-js .vjs-big-play-button .vjs-icon-placeholder:before, .video-js .vjs-play-control .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-play:before, .video-js .vjs-big-play-button .vjs-icon-placeholder:before, .video-js .vjs-play-control .vjs-icon-placeholder:before { + content: "\f101"; +} + +.vjs-icon-play-circle { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-play-circle:before { + content: "\f102"; +} + +.vjs-icon-pause, .video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-pause:before, .video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder:before { + content: "\f103"; +} + +.vjs-icon-volume-mute, .video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-volume-mute:before, .video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder:before { + content: "\f104"; +} + +.vjs-icon-volume-low, .video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-volume-low:before, .video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder:before { + content: "\f105"; +} + +.vjs-icon-volume-mid, .video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-volume-mid:before, .video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder:before { + content: "\f106"; +} + +.vjs-icon-volume-high, .video-js .vjs-mute-control .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-volume-high:before, .video-js .vjs-mute-control .vjs-icon-placeholder:before { + content: "\f107"; +} + +.vjs-icon-fullscreen-enter, .video-js .vjs-fullscreen-control .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-fullscreen-enter:before, .video-js .vjs-fullscreen-control .vjs-icon-placeholder:before { + content: "\f108"; +} + +.vjs-icon-fullscreen-exit, .video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-fullscreen-exit:before, .video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder:before { + content: "\f109"; +} + +.vjs-icon-square { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-square:before { + content: "\f10a"; +} + +.vjs-icon-spinner { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-spinner:before { + content: "\f10b"; +} + +.vjs-icon-subtitles, .video-js .vjs-subtitles-button .vjs-icon-placeholder, .video-js .vjs-subs-caps-button .vjs-icon-placeholder, +.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder, +.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder, +.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder, +.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-subtitles:before, .video-js .vjs-subtitles-button .vjs-icon-placeholder:before, .video-js .vjs-subs-caps-button .vjs-icon-placeholder:before, +.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder:before, +.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder:before, +.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder:before, +.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder:before { + content: "\f10c"; +} + +.vjs-icon-captions, .video-js .vjs-captions-button .vjs-icon-placeholder, .video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder, +.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-captions:before, .video-js .vjs-captions-button .vjs-icon-placeholder:before, .video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder:before, +.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder:before { + content: "\f10d"; +} + +.vjs-icon-chapters, .video-js .vjs-chapters-button .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-chapters:before, .video-js .vjs-chapters-button .vjs-icon-placeholder:before { + content: "\f10e"; +} + +.vjs-icon-share { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-share:before { + content: "\f10f"; +} + +.vjs-icon-cog { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-cog:before { + content: "\f110"; +} + +.vjs-icon-circle, .video-js .vjs-play-progress, .video-js .vjs-volume-level { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-circle:before, .video-js .vjs-play-progress:before, .video-js .vjs-volume-level:before { + content: "\f111"; +} + +.vjs-icon-circle-outline { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-circle-outline:before { + content: "\f112"; +} + +.vjs-icon-circle-inner-circle { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-circle-inner-circle:before { + content: "\f113"; +} + +.vjs-icon-hd { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-hd:before { + content: "\f114"; +} + +.vjs-icon-cancel, .video-js .vjs-control.vjs-close-button .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-cancel:before, .video-js .vjs-control.vjs-close-button .vjs-icon-placeholder:before { + content: "\f115"; +} + +.vjs-icon-replay, .video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-replay:before, .video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder:before { + content: "\f116"; +} + +.vjs-icon-facebook { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-facebook:before { + content: "\f117"; +} + +.vjs-icon-gplus { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-gplus:before { + content: "\f118"; +} + +.vjs-icon-linkedin { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-linkedin:before { + content: "\f119"; +} + +.vjs-icon-twitter { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-twitter:before { + content: "\f11a"; +} + +.vjs-icon-tumblr { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-tumblr:before { + content: "\f11b"; +} + +.vjs-icon-pinterest { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-pinterest:before { + content: "\f11c"; +} + +.vjs-icon-audio-description, .video-js .vjs-descriptions-button .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-audio-description:before, .video-js .vjs-descriptions-button .vjs-icon-placeholder:before { + content: "\f11d"; +} + +.vjs-icon-audio, .video-js .vjs-audio-button .vjs-icon-placeholder { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-audio:before, .video-js .vjs-audio-button .vjs-icon-placeholder:before { + content: "\f11e"; +} + +.vjs-icon-next-item { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-next-item:before { + content: "\f11f"; +} + +.vjs-icon-previous-item { + font-family: VideoJS; + font-weight: normal; + font-style: normal; +} + +.vjs-icon-previous-item:before { + content: "\f120"; +} + +.video-js { + display: block; + vertical-align: top; + box-sizing: border-box; + color: #fff; + background-color: #000; + position: relative; + padding: 0; + font-size: 10px; + line-height: 1; + font-weight: normal; + font-style: normal; + font-family: Arial, Helvetica, sans-serif; + word-break: initial; +} + +.video-js:-moz-full-screen { + position: absolute; +} + +.video-js:-webkit-full-screen { + width: 100% !important; + height: 100% !important; +} + +.video-js[tabindex="-1"] { + outline: none; +} + +.video-js *, +.video-js *:before, +.video-js *:after { + box-sizing: inherit; +} + +.video-js ul { + font-family: inherit; + font-size: inherit; + line-height: inherit; + list-style-position: outside; + margin-left: 0; + margin-right: 0; + margin-top: 0; + margin-bottom: 0; +} + +.video-js.vjs-fluid, +.video-js.vjs-16-9, +.video-js.vjs-4-3 { + width: 100%; + max-width: 100%; + height: 0; +} + +.video-js.vjs-16-9 { + padding-top: 56.25%; +} + +.video-js.vjs-4-3 { + padding-top: 75%; +} + +.video-js.vjs-fill { + width: 100%; + height: 100%; +} + +.video-js .vjs-tech { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +body.vjs-full-window { + padding: 0; + margin: 0; + height: 100%; +} + +.vjs-full-window .video-js.vjs-fullscreen { + position: fixed; + overflow: hidden; + z-index: 1000; + left: 0; + top: 0; + bottom: 0; + right: 0; +} + +.video-js.vjs-fullscreen { + width: 100% !important; + height: 100% !important; + padding-top: 0 !important; +} + +.video-js.vjs-fullscreen.vjs-user-inactive { + cursor: none; +} + +.vjs-hidden { + display: none !important; +} + +.vjs-disabled { + opacity: 0.5; + cursor: default; +} + +.video-js .vjs-offscreen { + height: 1px; + left: -9999px; + position: absolute; + top: 0; + width: 1px; +} + +.vjs-lock-showing { + display: block !important; + opacity: 1; + visibility: visible; +} + +.vjs-no-js { + padding: 20px; + color: #fff; + background-color: #000; + font-size: 18px; + font-family: Arial, Helvetica, sans-serif; + text-align: center; + width: 300px; + height: 150px; + margin: 0px auto; +} + +.vjs-no-js a, +.vjs-no-js a:visited { + color: #66A8CC; +} + +.video-js .vjs-big-play-button { + font-size: 3em; + line-height: 1.5em; + height: 1.5em; + width: 3em; + display: block; + position: absolute; + top: 10px; + left: 10px; + padding: 0; + cursor: pointer; + opacity: 1; + border: 0.06666em solid #fff; + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.7); + -webkit-border-radius: 0.3em; + -moz-border-radius: 0.3em; + border-radius: 0.3em; + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -ms-transition: all 0.4s; + -o-transition: all 0.4s; + transition: all 0.4s; +} + +.vjs-big-play-centered .vjs-big-play-button { + top: 50%; + left: 50%; + margin-top: -0.75em; + margin-left: -1.5em; +} + +.video-js:hover .vjs-big-play-button, +.video-js .vjs-big-play-button:focus { + border-color: #fff; + background-color: #73859f; + background-color: rgba(115, 133, 159, 0.5); + -webkit-transition: all 0s; + -moz-transition: all 0s; + -ms-transition: all 0s; + -o-transition: all 0s; + transition: all 0s; +} + +.vjs-controls-disabled .vjs-big-play-button, +.vjs-has-started .vjs-big-play-button, +.vjs-using-native-controls .vjs-big-play-button, +.vjs-error .vjs-big-play-button { + display: none; +} + +.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause .vjs-big-play-button { + display: block; +} + +.video-js button { + background: none; + border: none; + color: inherit; + display: inline-block; + font-size: inherit; + line-height: inherit; + text-transform: none; + text-decoration: none; + transition: none; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.vjs-control .vjs-button { + width: 100%; + height: 100%; +} + +.video-js .vjs-control.vjs-close-button { + cursor: pointer; + height: 3em; + position: absolute; + right: 0; + top: 0.5em; + z-index: 2; +} + +.video-js .vjs-modal-dialog { + background: rgba(0, 0, 0, 0.8); + background: -webkit-linear-gradient(-90deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0)); + background: linear-gradient(180deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0)); + overflow: auto; +} + +.video-js .vjs-modal-dialog > * { + box-sizing: border-box; +} + +.vjs-modal-dialog .vjs-modal-dialog-content { + font-size: 1.2em; + line-height: 1.5; + padding: 20px 24px; + z-index: 1; +} + +.vjs-menu-button { + cursor: pointer; +} + +.vjs-menu-button.vjs-disabled { + cursor: default; +} + +.vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu { + display: none; +} + +.vjs-menu .vjs-menu-content { + display: block; + padding: 0; + margin: 0; + font-family: Arial, Helvetica, sans-serif; + overflow: auto; +} + +.vjs-menu .vjs-menu-content > * { + box-sizing: border-box; +} + +.vjs-scrubbing .vjs-control.vjs-menu-button:hover .vjs-menu { + display: none; +} + +.vjs-menu li { + list-style: none; + margin: 0; + padding: 0.2em 0; + line-height: 1.4em; + font-size: 1.2em; + text-align: center; + text-transform: lowercase; +} + +.vjs-menu li.vjs-menu-item:focus, +.vjs-menu li.vjs-menu-item:hover { + background-color: #73859f; + background-color: rgba(115, 133, 159, 0.5); +} + +.vjs-menu li.vjs-selected, +.vjs-menu li.vjs-selected:focus, +.vjs-menu li.vjs-selected:hover { + background-color: #fff; + color: #2B333F; +} + +.vjs-menu li.vjs-menu-title { + text-align: center; + text-transform: uppercase; + font-size: 1em; + line-height: 2em; + padding: 0; + margin: 0 0 0.3em 0; + font-weight: bold; + cursor: default; +} + +.vjs-menu-button-popup .vjs-menu { + display: none; + position: absolute; + bottom: 0; + width: 10em; + left: -3em; + height: 0em; + margin-bottom: 1.5em; + border-top-color: rgba(43, 51, 63, 0.7); +} + +.vjs-menu-button-popup .vjs-menu .vjs-menu-content { + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.7); + position: absolute; + width: 100%; + bottom: 1.5em; + max-height: 15em; +} + +.vjs-workinghover .vjs-menu-button-popup:hover .vjs-menu, +.vjs-menu-button-popup .vjs-menu.vjs-lock-showing { + display: block; +} + +.video-js .vjs-menu-button-inline { + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -ms-transition: all 0.4s; + -o-transition: all 0.4s; + transition: all 0.4s; + overflow: hidden; +} + +.video-js .vjs-menu-button-inline:before { + width: 2.222222222em; +} + +.video-js .vjs-menu-button-inline:hover, +.video-js .vjs-menu-button-inline:focus, +.video-js .vjs-menu-button-inline.vjs-slider-active, +.video-js.vjs-no-flex .vjs-menu-button-inline { + width: 12em; +} + +.vjs-menu-button-inline .vjs-menu { + opacity: 0; + height: 100%; + width: auto; + position: absolute; + left: 4em; + top: 0; + padding: 0; + margin: 0; + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -ms-transition: all 0.4s; + -o-transition: all 0.4s; + transition: all 0.4s; +} + +.vjs-menu-button-inline:hover .vjs-menu, +.vjs-menu-button-inline:focus .vjs-menu, +.vjs-menu-button-inline.vjs-slider-active .vjs-menu { + display: block; + opacity: 1; +} + +.vjs-no-flex .vjs-menu-button-inline .vjs-menu { + display: block; + opacity: 1; + position: relative; + width: auto; +} + +.vjs-no-flex .vjs-menu-button-inline:hover .vjs-menu, +.vjs-no-flex .vjs-menu-button-inline:focus .vjs-menu, +.vjs-no-flex .vjs-menu-button-inline.vjs-slider-active .vjs-menu { + width: auto; +} + +.vjs-menu-button-inline .vjs-menu-content { + width: auto; + height: 100%; + margin: 0; + overflow: hidden; +} + +.video-js .vjs-control-bar { + display: none; + width: 100%; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 3.0em; + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.7); +} + +.vjs-has-started .vjs-control-bar { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + visibility: visible; + opacity: 1; + -webkit-transition: visibility 0.1s, opacity 0.1s; + -moz-transition: visibility 0.1s, opacity 0.1s; + -ms-transition: visibility 0.1s, opacity 0.1s; + -o-transition: visibility 0.1s, opacity 0.1s; + transition: visibility 0.1s, opacity 0.1s; +} + +.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { + visibility: visible; + opacity: 0; + -webkit-transition: visibility 1s, opacity 1s; + -moz-transition: visibility 1s, opacity 1s; + -ms-transition: visibility 1s, opacity 1s; + -o-transition: visibility 1s, opacity 1s; + transition: visibility 1s, opacity 1s; +} + +.vjs-controls-disabled .vjs-control-bar, +.vjs-using-native-controls .vjs-control-bar, +.vjs-error .vjs-control-bar { + display: none !important; +} + +.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { + opacity: 1; + visibility: visible; +} + +.vjs-has-started.vjs-no-flex .vjs-control-bar { + display: table; +} + +.video-js .vjs-control { + position: relative; + text-align: center; + margin: 0; + padding: 0; + height: 100%; + width: 4em; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; +} + +.vjs-button > .vjs-icon-placeholder:before { + font-size: 1.8em; + line-height: 1.67; +} + +.video-js .vjs-control:focus:before, +.video-js .vjs-control:hover:before, +.video-js .vjs-control:focus { + text-shadow: 0em 0em 1em white; +} + +.video-js .vjs-control-text { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.vjs-no-flex .vjs-control { + display: table-cell; + vertical-align: middle; +} + +.video-js .vjs-custom-control-spacer { + display: none; +} + +.video-js .vjs-progress-control { + cursor: pointer; + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + min-width: 4em; +} + +.video-js .vjs-progress-control.disabled { + cursor: default; +} + +.vjs-live .vjs-progress-control { + display: none; +} + +.vjs-no-flex .vjs-progress-control { + width: auto; +} + +.video-js .vjs-progress-holder { + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -ms-transition: all 0.2s; + -o-transition: all 0.2s; + transition: all 0.2s; + height: 0.3em; +} + +.video-js .vjs-progress-control .vjs-progress-holder { + margin: 0 10px; +} + +.video-js .vjs-progress-control:hover .vjs-progress-holder { + font-size: 1.666666666666666666em; +} + +.video-js .vjs-progress-control:hover .vjs-progress-holder.disabled { + font-size: 1em; +} + +.video-js .vjs-progress-holder .vjs-play-progress, +.video-js .vjs-progress-holder .vjs-load-progress, +.video-js .vjs-progress-holder .vjs-load-progress div { + position: absolute; + display: block; + height: 100%; + margin: 0; + padding: 0; + width: 0; +} + +.video-js .vjs-play-progress { + background-color: #fff; +} + +.video-js .vjs-play-progress:before { + font-size: 0.9em; + position: absolute; + right: -0.5em; + top: -0.333333333333333em; + z-index: 1; +} + +.video-js .vjs-load-progress { + background: rgba(115, 133, 159, 0.5); +} + +.video-js .vjs-load-progress div { + background: rgba(115, 133, 159, 0.75); +} + +.video-js .vjs-time-tooltip { + background-color: #fff; + background-color: rgba(255, 255, 255, 0.8); + -webkit-border-radius: 0.3em; + -moz-border-radius: 0.3em; + border-radius: 0.3em; + color: #000; + float: right; + font-family: Arial, Helvetica, sans-serif; + font-size: 1em; + padding: 6px 8px 8px 8px; + pointer-events: none; + position: relative; + top: -3.4em; + visibility: hidden; + z-index: 1; +} + +.video-js .vjs-progress-holder:focus .vjs-time-tooltip { + display: none; +} + +.video-js .vjs-progress-control:hover .vjs-time-tooltip, +.video-js .vjs-progress-control:hover .vjs-progress-holder:focus .vjs-time-tooltip { + display: block; + font-size: 0.6em; + visibility: visible; +} + +.video-js .vjs-progress-control.disabled:hover .vjs-time-tooltip { + font-size: 1em; +} + +.video-js .vjs-progress-control .vjs-mouse-display { + display: none; + position: absolute; + width: 1px; + height: 100%; + background-color: #000; + z-index: 1; +} + +.vjs-no-flex .vjs-progress-control .vjs-mouse-display { + z-index: 0; +} + +.video-js .vjs-progress-control:hover .vjs-mouse-display { + display: block; +} + +.video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display { + visibility: hidden; + opacity: 0; + -webkit-transition: visibility 1s, opacity 1s; + -moz-transition: visibility 1s, opacity 1s; + -ms-transition: visibility 1s, opacity 1s; + -o-transition: visibility 1s, opacity 1s; + transition: visibility 1s, opacity 1s; +} + +.video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display { + display: none; +} + +.vjs-mouse-display .vjs-time-tooltip { + color: #fff; + background-color: #000; + background-color: rgba(0, 0, 0, 0.8); +} + +.video-js .vjs-slider { + position: relative; + cursor: pointer; + padding: 0; + margin: 0 0.45em 0 0.45em; + /* iOS Safari */ + -webkit-touch-callout: none; + /* Safari */ + -webkit-user-select: none; + /* Konqueror HTML */ + -khtml-user-select: none; + /* Firefox */ + -moz-user-select: none; + /* Internet Explorer/Edge */ + -ms-user-select: none; + /* Non-prefixed version, currently supported by Chrome and Opera */ + user-select: none; + background-color: #73859f; + background-color: rgba(115, 133, 159, 0.5); +} + +.video-js .vjs-slider.disabled { + cursor: default; +} + +.video-js .vjs-slider:focus { + text-shadow: 0em 0em 1em white; + -webkit-box-shadow: 0 0 1em #fff; + -moz-box-shadow: 0 0 1em #fff; + box-shadow: 0 0 1em #fff; +} + +.video-js .vjs-mute-control { + cursor: pointer; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; +} + +.video-js .vjs-volume-control { + cursor: pointer; + margin-right: 1em; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.video-js .vjs-volume-control.vjs-volume-horizontal { + width: 5em; +} + +.video-js .vjs-volume-panel .vjs-volume-control { + visibility: visible; + opacity: 0; + width: 1px; + height: 1px; + margin-left: -1px; +} + +.video-js .vjs-volume-panel { + -webkit-transition: width 1s; + -moz-transition: width 1s; + -ms-transition: width 1s; + -o-transition: width 1s; + transition: width 1s; +} + +.video-js .vjs-volume-panel:hover .vjs-volume-control, +.video-js .vjs-volume-panel:active .vjs-volume-control, +.video-js .vjs-volume-panel:focus .vjs-volume-control, +.video-js .vjs-volume-panel .vjs-volume-control:hover, +.video-js .vjs-volume-panel .vjs-volume-control:active, +.video-js .vjs-volume-panel .vjs-mute-control:hover ~ .vjs-volume-control, +.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active { + visibility: visible; + opacity: 1; + position: relative; + -webkit-transition: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s; + -moz-transition: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s; + -ms-transition: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s; + -o-transition: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s; + transition: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s; +} + +.video-js .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal, +.video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal, +.video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal, +.video-js .vjs-volume-panel .vjs-volume-control:hover.vjs-volume-horizontal, +.video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-horizontal, +.video-js .vjs-volume-panel .vjs-mute-control:hover ~ .vjs-volume-control.vjs-volume-horizontal, +.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-horizontal { + width: 5em; + height: 3em; +} + +.video-js .vjs-volume-panel.vjs-volume-panel-horizontal:hover, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active { + width: 9em; + -webkit-transition: width 0.1s; + -moz-transition: width 0.1s; + -ms-transition: width 0.1s; + -o-transition: width 0.1s; + transition: width 0.1s; +} + +.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical { + height: 8em; + width: 3em; + left: -3.5em; + -webkit-transition: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s; + -moz-transition: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s; + -ms-transition: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s; + -o-transition: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s; + transition: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s; +} + +.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal { + -webkit-transition: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s; + -moz-transition: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s; + -ms-transition: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s; + -o-transition: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s; + transition: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s; +} + +.video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal { + width: 5em; + height: 3em; + visibility: visible; + opacity: 1; + position: relative; + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} + +.video-js.vjs-no-flex .vjs-volume-control.vjs-volume-vertical, +.video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical { + position: absolute; + bottom: 3em; + left: 0.5em; +} + +.video-js .vjs-volume-panel { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.video-js .vjs-volume-bar { + margin: 1.35em 0.45em; +} + +.vjs-volume-bar.vjs-slider-horizontal { + width: 5em; + height: 0.3em; +} + +.vjs-volume-bar.vjs-slider-vertical { + width: 0.3em; + height: 5em; + margin: 1.35em auto; +} + +.video-js .vjs-volume-level { + position: absolute; + bottom: 0; + left: 0; + background-color: #fff; +} + +.video-js .vjs-volume-level:before { + position: absolute; + font-size: 0.9em; +} + +.vjs-slider-vertical .vjs-volume-level { + width: 0.3em; +} + +.vjs-slider-vertical .vjs-volume-level:before { + top: -0.5em; + left: -0.3em; +} + +.vjs-slider-horizontal .vjs-volume-level { + height: 0.3em; +} + +.vjs-slider-horizontal .vjs-volume-level:before { + top: -0.3em; + right: -0.5em; +} + +.video-js .vjs-volume-panel.vjs-volume-panel-vertical { + width: 4em; +} + +.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level { + height: 100%; +} + +.vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level { + width: 100%; +} + +.video-js .vjs-volume-vertical { + width: 3em; + height: 8em; + bottom: 8em; + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.7); +} + +.video-js .vjs-volume-horizontal .vjs-menu { + left: -2em; +} + +.vjs-poster { + display: inline-block; + vertical-align: middle; + background-repeat: no-repeat; + background-position: 50% 50%; + background-size: contain; + background-color: #000000; + cursor: pointer; + margin: 0; + padding: 0; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + height: 100%; +} + +.vjs-has-started .vjs-poster { + display: none; +} + +.vjs-audio.vjs-has-started .vjs-poster { + display: block; +} + +.vjs-using-native-controls .vjs-poster { + display: none; +} + +.video-js .vjs-live-control { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: flex-start; + -webkit-align-items: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; + font-size: 1em; + line-height: 3em; +} + +.vjs-no-flex .vjs-live-control { + display: table-cell; + width: auto; + text-align: left; +} + +.video-js .vjs-time-control { + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; + font-size: 1em; + line-height: 3em; + min-width: 2em; + width: auto; + padding-left: 1em; + padding-right: 1em; +} + +.vjs-live .vjs-time-control { + display: none; +} + +.video-js .vjs-current-time, +.vjs-no-flex .vjs-current-time { + display: none; +} + +.video-js .vjs-duration, +.vjs-no-flex .vjs-duration { + display: none; +} + +.vjs-time-divider { + display: none; + line-height: 3em; +} + +.vjs-live .vjs-time-divider { + display: none; +} + +.video-js .vjs-play-control .vjs-icon-placeholder { + cursor: pointer; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; +} + +.vjs-text-track-display { + position: absolute; + bottom: 3em; + left: 0; + right: 0; + top: 0; + pointer-events: none; +} + +.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display { + bottom: 1em; +} + +.video-js .vjs-text-track { + font-size: 1.4em; + text-align: center; + margin-bottom: 0.1em; +} + +.vjs-subtitles { + color: #fff; +} + +.vjs-captions { + color: #fc6; +} + +.vjs-tt-cue { + display: block; +} + +video::-webkit-media-text-track-display { + -moz-transform: translateY(-3em); + -ms-transform: translateY(-3em); + -o-transform: translateY(-3em); + -webkit-transform: translateY(-3em); + transform: translateY(-3em); +} + +.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display { + -moz-transform: translateY(-1.5em); + -ms-transform: translateY(-1.5em); + -o-transform: translateY(-1.5em); + -webkit-transform: translateY(-1.5em); + transform: translateY(-1.5em); +} + +.video-js .vjs-fullscreen-control { + cursor: pointer; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; +} + +.vjs-playback-rate > .vjs-menu-button, +.vjs-playback-rate .vjs-playback-rate-value { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.vjs-playback-rate .vjs-playback-rate-value { + pointer-events: none; + font-size: 1.5em; + line-height: 2; + text-align: center; +} + +.vjs-playback-rate .vjs-menu { + width: 4em; + left: 0em; +} + +.vjs-error .vjs-error-display .vjs-modal-dialog-content { + font-size: 1.4em; + text-align: center; +} + +.vjs-error .vjs-error-display:before { + color: #fff; + content: 'X'; + font-family: Arial, Helvetica, sans-serif; + font-size: 4em; + left: 0; + line-height: 1; + margin-top: -0.5em; + position: absolute; + text-shadow: 0.05em 0.05em 0.1em #000; + text-align: center; + top: 50%; + vertical-align: middle; + width: 100%; +} + +.vjs-loading-spinner { + display: none; + position: absolute; + top: 50%; + left: 50%; + margin: -25px 0 0 -25px; + opacity: 0.85; + text-align: left; + border: 6px solid rgba(43, 51, 63, 0.7); + box-sizing: border-box; + background-clip: padding-box; + width: 50px; + height: 50px; + border-radius: 25px; + visibility: hidden; +} + +.vjs-seeking .vjs-loading-spinner, +.vjs-waiting .vjs-loading-spinner { + display: block; + animation: 0s linear 0.3s forwards vjs-spinner-show; +} + +.vjs-loading-spinner:before, +.vjs-loading-spinner:after { + content: ""; + position: absolute; + margin: -6px; + box-sizing: inherit; + width: inherit; + height: inherit; + border-radius: inherit; + opacity: 1; + border: inherit; + border-color: transparent; + border-top-color: white; +} + +.vjs-seeking .vjs-loading-spinner:before, +.vjs-seeking .vjs-loading-spinner:after, +.vjs-waiting .vjs-loading-spinner:before, +.vjs-waiting .vjs-loading-spinner:after { + -webkit-animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; + animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; +} + +.vjs-seeking .vjs-loading-spinner:before, +.vjs-waiting .vjs-loading-spinner:before { + border-top-color: white; +} + +.vjs-seeking .vjs-loading-spinner:after, +.vjs-waiting .vjs-loading-spinner:after { + border-top-color: white; + -webkit-animation-delay: 0.44s; + animation-delay: 0.44s; +} + +@keyframes vjs-spinner-show { + to { + visibility: visible; + } +} + +@-webkit-keyframes vjs-spinner-show { + to { + visibility: visible; + } +} + +@keyframes vjs-spinner-spin { + 100% { + transform: rotate(360deg); + } +} + +@-webkit-keyframes vjs-spinner-spin { + 100% { + -webkit-transform: rotate(360deg); + } +} + +@keyframes vjs-spinner-fade { + 0% { + border-top-color: #73859f; + } + 20% { + border-top-color: #73859f; + } + 35% { + border-top-color: white; + } + 60% { + border-top-color: #73859f; + } + 100% { + border-top-color: #73859f; + } +} + +@-webkit-keyframes vjs-spinner-fade { + 0% { + border-top-color: #73859f; + } + 20% { + border-top-color: #73859f; + } + 35% { + border-top-color: white; + } + 60% { + border-top-color: #73859f; + } + 100% { + border-top-color: #73859f; + } +} + +.vjs-chapters-button .vjs-menu ul { + width: 24em; +} + +.video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder { + position: absolute; +} + +.video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before { + font-family: VideoJS; + content: "\f10d"; + font-size: 1.5em; + line-height: inherit; +} + +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-custom-control-spacer { + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; +} + +.video-js.vjs-layout-tiny:not(.vjs-fullscreen).vjs-no-flex .vjs-custom-control-spacer { + width: auto; +} + +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-remaining-time, +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-playback-rate, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-progress-control, +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-volume-control, +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-descriptions-button, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-captions-button, +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-subtitles-button, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-audio-button { + display: none; +} + +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-remaining-time, +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-playback-rate, +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-volume-control, +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-descriptions-button, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-captions-button, +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-subtitles-button, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-audio-button { + display: none; +} + +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-remaining-time, +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-playback-rate, +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-volume-control, +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-descriptions-button, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-captions-button, +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-subtitles-button .vjs-audio-button { + display: none; +} + +.vjs-modal-dialog.vjs-text-track-settings { + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.75); + color: #fff; + height: 70%; +} + +.vjs-text-track-settings .vjs-modal-dialog-content { + display: table; +} + +.vjs-text-track-settings .vjs-track-settings-colors, +.vjs-text-track-settings .vjs-track-settings-font, +.vjs-text-track-settings .vjs-track-settings-controls { + display: table-cell; +} + +.vjs-text-track-settings .vjs-track-settings-controls { + text-align: right; + vertical-align: bottom; +} + +@supports (display: grid) { + .vjs-text-track-settings .vjs-modal-dialog-content { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr auto; + } + + .vjs-text-track-settings .vjs-track-settings-colors { + display: block; + grid-column: 1; + grid-row: 1; + } + + .vjs-text-track-settings .vjs-track-settings-font { + grid-column: 2; + grid-row: 1; + } + + .vjs-text-track-settings .vjs-track-settings-controls { + grid-column: 2; + grid-row: 2; + } +} + +.vjs-track-setting > select { + margin-right: 5px; +} + +.vjs-text-track-settings fieldset { + margin: 5px; + padding: 3px; + border: none; +} + +.vjs-text-track-settings fieldset span { + display: inline-block; +} + +.vjs-text-track-settings legend { + color: #fff; + margin: 0 0 5px 0; +} + +.vjs-text-track-settings .vjs-label { + position: absolute; + clip: rect(1px 1px 1px 1px); + clip: rect(1px, 1px, 1px, 1px); + display: block; + margin: 0 0 5px 0; + padding: 0; + border: 0; + height: 1px; + width: 1px; + overflow: hidden; +} + +.vjs-track-settings-controls button:focus, +.vjs-track-settings-controls button:active { + outline-style: solid; + outline-width: medium; + background-image: linear-gradient(0deg, #fff 88%, #73859f 100%); +} + +.vjs-track-settings-controls button:hover { + color: rgba(43, 51, 63, 0.75); +} + +.vjs-track-settings-controls button { + background-color: #fff; + background-image: linear-gradient(-180deg, #fff 88%, #73859f 100%); + color: #2B333F; + cursor: pointer; + border-radius: 2px; +} + +.vjs-track-settings-controls .vjs-default-button { + margin-right: 1em; +} + +@media print { + .video-js > *:not(.vjs-tech):not(.vjs-poster) { + visibility: hidden; + } +} + +.vjs-resize-manager { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: none; + visibility: hidden; +} diff --git a/form/src/assets/libs/video-js-7.0.0/video-js.min.css b/form/src/assets/libs/video-js-7.0.0/video-js.min.css new file mode 100644 index 0000000000000000000000000000000000000000..10c2521f9f101f826a611c3eaedf8d489a3f04d4 --- /dev/null +++ b/form/src/assets/libs/video-js-7.0.0/video-js.min.css @@ -0,0 +1 @@ +.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-modal-dialog,.vjs-button>.vjs-icon-placeholder:before,.vjs-modal-dialog .vjs-modal-dialog-content{position:absolute;top:0;left:0;width:100%;height:100%}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.vjs-button>.vjs-icon-placeholder:before{text-align:center}@font-face{font-family:VideoJS;src:url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAABBIAAsAAAAAGoQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADsAAABUIIslek9TLzIAAAFEAAAAPgAAAFZRiV3RY21hcAAAAYQAAADQAAADIjn098ZnbHlmAAACVAAACv4AABEIAwnSw2hlYWQAAA1UAAAAKgAAADYUHzoRaGhlYQAADYAAAAAbAAAAJA4DByFobXR4AAANnAAAAA8AAACE4AAAAGxvY2EAAA2sAAAARAAAAEQ9NEHGbWF4cAAADfAAAAAfAAAAIAEyAIFuYW1lAAAOEAAAASUAAAIK1cf1oHBvc3QAAA84AAABDwAAAZ5AAl/0eJxjYGRgYOBiMGCwY2BycfMJYeDLSSzJY5BiYGGAAJA8MpsxJzM9kYEDxgPKsYBpDiBmg4gCACY7BUgAeJxjYGQ7xTiBgZWBgaWQ5RkDA8MvCM0cwxDOeI6BgYmBlZkBKwhIc01hcPjI+FGBHcRdyA4RZgQRAC4HCwEAAHic7dFprsIgAEXhg8U61XmeWcBb1FuQP4w7ZQXK5boMm3yclFDSANAHmuKviBBeBPQ8ymyo8w3jOh/5r2ui5nN6v8sYNJb3WMdeWRvLji0DhozKdxM6psyYs2DJijUbtuzYc+DIiTMXrty4k8oGLb+n0xCe37ekM7Z66j1DbUy3l6PpHnLfdLO5NdSBoQ4NdWSoY9ON54mhdqa/y1NDnRnq3FAXhro01JWhrg11Y6hbQ90Z6t5QD4Z6NNSToZ4N9WKoV0O9GerdUJORPqkhTd54nJ1YDXBU1RV+576/JBs2bPYPkrDZt5vsJrv53V/I5mclhGDCTwgGBQQSTEji4hCkYIAGd4TGIWFAhV0RQTpWmQp1xv6hA4OTOlNr2zFANbHUYbq2OtNCpViRqsk+e+7bTQAhzti8vPfuPffcc88959zznbcMMPjHD/KDDGEY0ABpYX384NhlomIYlo4JISGEY9mMh2FSidYiqkEUphtNYDSY/dXg9023l4DdxlqUl0chuZRhncJKrsCQHIwcGuwfnhMIzBnuH4Sym+1D2zaGjheXlhYfD238z80mKYMmvJ5XeOTzd8z9eujbMxJNhu4C9xPE/bCMiDuSNIWgkTQwBE55hLSAE7ZwhrHLnAHZOGV/kmBGTiNjZxzI77Hb7Hqjz68TjT6vh+5JT/cCIkqS0D6CqPf5jX4Qjdx5j6vlDfZM4aZFdbVXIxtOlJaP/WottMnH6CJQ3bTiue3PrY23HjnChtuamxwvvzFjxkPrNj3z0tG9T561HDYf6OgmRWvlY3JQHoQb8ltV2Yet7YfWctEjR1AtxS/cSX6U4alf6NJEBQ7YKg9wrXQKd0IeZCb2ux75Uhh1Un+Nz+9LTOE7PK777nN5xqdTneTBhCbx446mZrhnUkrCz2YhA9dSMxaG0SYmT8hi9ZPu1E94PJYQSH6LRmhxec7Q7ZeXntgQuVpbh+a4qWNsckVyTdn0P7o7DpgPW84+uRcq0BITflBikGdUjAZ9wYBVI3mtrNvr9kpg1UsaK6t3690aoorC1lg0GpMH2HAMtkZjsSi5Ig9ESVosOh7GQfLjKNLvKpMKkLSKNFAka710GdgSi8oDMSoNhqjkKBXTgn3swtaxyzGkUzIzae9RtLdWkSlZ1KDX6EzgllzV4NV4SoDFSOGD4+HCeQUF8wrZ5Hs8zIb5EaVxy8DYFTbMCJPnLIWZxugZE2NlivC0gc1qEQUR8jEKgZcAXeH18BiCgl5nlHh0CrjB4Hb5fX4gb0J7c9PuHVsfgkx2n/vTY/JV8kn8PGxf7faOZ8qX8JVByuIf4whk9sqXli2hvPJV9hrp0hY7l8r2x37ydaVsb4xvXv/47v2NjfCl8m5oRDJclFMoE1yk0Uh1Te4/m8lFXe9qBZD0EkheicebXvzI2PLCuoKCukLuhPIeKwaHPEouxw3kMqaIUXDQ1p0mip+MyCORSCQaoUsnY1VZ38nUTrG21WvVo4f1OsEJFhvSfAFwGfT8VHRMeAVUpwLOoLzjT/REIj3O3FhuURE+nERF+0pTId5Fyxv5sfwGyg4O+my4vZv0sZm7oeQlFZORiB+tG0MweVNraeitl7yxiPIHTk4/diVxs94o5lEYishB2iAtkchEnsActoEpx44Fo8XnsQMaA22BlqC20RmhBKzYojZyYaxg+JggMc4HHY2m+L9EkWSYljirOisrO7d3VorxzyZ6Vc4lJqITAu1b2wOBdrLElAP+bFc2eGaZFVbkmJktv5uT6Jlz5D/MnBFor6ig/JPnRViBsV3LNKGGqB1ChJ0tgQywlVLFJIuQgTFttwkiKxhyQdAZMdMYtSaoAewqfvXVYPAbDT6/1mez85YS8FSDywQ6NfAnef6FNEGMilnppyvn5rB6tTyq1pOceRWnp2WJEZFXHeX5oyoem1nTTgdqc4heDY7bOeKz63vnz+/dRx+s31Ht2JGanQ5seirfWJL9tjozU/12TnEjn5oux9OzU3ckGbBzBwNOyk69JykKH0n/0LM9A72tuwM3zQpIRu4AxiToseEpgPOmbROyFe9/X2yeUvoUsCyEvjcgs7fpWP3/aKlFN0+6HFUe6D9HFz/XPwBlN9tTqNyZjFJ8UO2RUT5/h4CptCctEyeisnOyXjALEp7dXKaQKf6O7IMnGjNNACRMLxqdYJX8eMLvmmd68D+ayBLyKKYZwYxDt/GNhzETDJ05Qxlyi3pi3/Z93ndYVSumgj0V/KkIFlO6+1K3fF2+3g0q+YtuSIf0bvmLqV09nnobI6hwcjIP8aPCKayjsF5JBY3LaKAeRLSyYB1h81oTwe9SlPMkXB7G0mfL9q71gaqqwPqu67QRKS1+ObTx+sbQy9QV2OQHEScGkdFBeT7v7qisqqrs6N52i78/R+6S0qQONVj26agOVoswCyQWIV5D86vH53bxNUeXV0K+XZaHv/nm/KsHhOvylwsWnJX/HE8l/4WCv5x+l5n08z6UU8bUMa3MBpSmM7F63AxntdC9eBCKEZW9Hr+ABNqtxgAQrSbMtmrW7lKQuoSgBhSrTazWVU2QAKWY8wiiuhqFmQgWJBgoXiuWIm42N7hqZbBsgXz52O5P5uSvaNgFGnOuvsRw8I8Laha91wMvDuxqWFheN7/8GVtTltdS83DQsXRmqc5ZtcJXEVrlV2doTWk5+Yunm71dG5f55m/qY0MjI93vv9/NfpxXV9sUXrxy2fbNy1or65cOlDRnOoKFeeXcbw42H/bNDT5Qs3flgs31gWC1lD1nfUV/X7NdCnSUdHY2e8afzfKsqZ5ZljfDqjLOmk3UebNXB+aHArPYDRs+/HDDxeT5DiP+sFg7OpRaVQMGBV89PpeBdj22hCE0Uub0UqwLrNWsG0cuyadgLXTeR5rbO4+3c/vl15cur2nRq+TXCQDcS3SO+s6ak+e5/eMS+1dw3btu3YG2tvFL8XdIZvdjdW6TO/4B7IdrZWVPmctm5/59AgsPItTSbCiIBr2OqIGzmu20SMKAS7yqwGBUfGfgjDYlLLDeF0SfcLB2LSx8flT+08/kzz6yOj96rft4rpTjdPQcmLd47uKibbDq7ZSz/XtbH2nN717Nd62rU+c8Icevvv7I09wA6WvjVcafb+FsbNG+ZQ80Rn6ZZsvrP7teP2dzTdoETvNhjCmsr8FID2sJ69VYvdUcxk4AzYRlKcaE38eXNRlfW9H1as9i6acLHp1XpuNB5K7DIvkX08y1ZYvh3KfWaiCzH+ztrSDmD7LuX73x/mJelB8Yj39t8nhNQJJ2CAthpoFGLsGgtSOCJooCGoaJAMTjSWHVZ08YAa1Fg9lPI5U6DOsGVjDasJeZZ+YyhfCwfOzCxlBA69M9XLXtza7H/rav+9Tjq5xNi0wpKQIRNO4Lrzz7yp5QVYM6Jd/oc1Uvn/mQhhuWh6ENXoS2YTZ8QT42bF5d/559zp5r0Uff2VnR2tdf2/WCOd2cO0Mw6qpWPnvxpV0nrt5fZd2yItc199GWe8vlNfNDq+CH/7yAAnB9hn7T4QO4c1g9ScxsZgmzntnE/IDGndtHMw69lFwoCnYsMGx+rBp8JSBqdLzBr9QRPq/PbhWMWFtQZp1xguy/haw3TEHm3TWAnxFWQQWgt7M5OV0lCz1VRYucpWliy7z6Zd4urwPIyeZQqli2Lgg7szJV09PysATbOQtYIrB2YzbkJYkGgJ0m4AjPUap1pvYu1K9qr97z0Yl3p332b2LYB78ncYIlRkau/8GObSsOlZancACE5d5ily+c2+7h5Yj4lqhVmXXB+iXLfvdqSgqfKtQvfHDV0OnvQR1qhw42XS/vkvsh/hXcrDFP0a+SJNIomEfD1nsrYGO+1bgTOJhM8Hv6ek+7vVglxuSRwoKn17S937bm6YJCeSSG0Op1n+7tE37tcZ/p7dsTv4EUrGpDbWueKigsLHhqTVsoEj+JU0kaSjnj9tz8/gryQWwJ9BcJXBC/7smO+I/IFURJetFPrdt5WcoL6DbEJaygI8CTHfQTjf40ofD+DwalTqIAAHicY2BkYGAA4uByr8R4fpuvDNzsDCBw7f/3LmSanREszsHABKIAKi0J7gAAeJxjYGRgYGcAARD5/z87IwMjAypQBAAtgwI4AHicY2BgYGAfYAwAOkQA4QAAAAAAAA4AaAB+AMwA4AECAUIBbAGYAcICGAJYArQC4AMwA7AD3gQwBJYE3AUkBWYFigYgBmYGtAbqB1gIEghYCG4IhHicY2BkYGBQZChlYGcAASYg5gJCBob/YD4DABfTAbQAeJxdkE1qg0AYhl8Tk9AIoVDaVSmzahcF87PMARLIMoFAl0ZHY1BHdBJIT9AT9AQ9RQ9Qeqy+yteNMzDzfM+88w0K4BY/cNAMB6N2bUaPPBLukybCLvleeAAPj8JD+hfhMV7hC3u4wxs7OO4NzQSZcI/8Ltwnfwi75E/hAR7wJTyk/xYeY49fYQ/PztM+jbTZ7LY6OWdBJdX/pqs6NYWa+zMxa13oKrA6Uoerqi/JwtpYxZXJ1coUVmeZUWVlTjq0/tHacjmdxuL90OR8O0UEDYMNdtiSEpz5XQGqzlm30kzUdAYFFOb8R7NOZk0q2lwAyz1i7oAr1xoXvrOgtYhZx8wY5KRV269JZ5yGpmzPTjQhvY9je6vEElPOuJP3mWKnP5M3V+YAAAB4nG2PyXLCMBBE3YCNDWEL2ffk7o8S8oCnkCVHC5C/jzBQlUP6IHVPzYyekl5y0iL5X5/ooY8BUmQYIkeBEca4wgRTzDDHAtdY4ga3uMM9HvCIJzzjBa94wzs+8ImvZNAq8TM+HqVkKxWlrQiOxjujQkNlEzyNzl6Z/cU2XF06at7U83VQyklLpEvSnuzsb+HAPnPfQVgaupa1Jlu4sPLsFblcitaz0dHU0ZF1qatjZ1+aTXYCmp6u0gSvWNPyHLtFZ+ZeXWVSaEkqs3T8S74WklbGbNNNq4LL4+CWKtZDv2cfX8l8aFbKFhEnJnJ+IULFpqwoQnNHlHaVQtPBl+ypmbSWdmyC61KS/AKZC3Y+AA==) format("woff");font-weight:400;font-style:normal}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-play-control .vjs-icon-placeholder,.vjs-icon-play{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-big-play-button .vjs-icon-placeholder:before,.video-js .vjs-play-control .vjs-icon-placeholder:before,.vjs-icon-play:before{content:"\f101"}.vjs-icon-play-circle{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-play-circle:before{content:"\f102"}.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder,.vjs-icon-pause{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder:before,.vjs-icon-pause:before{content:"\f103"}.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder,.vjs-icon-volume-mute{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder:before,.vjs-icon-volume-mute:before{content:"\f104"}.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder,.vjs-icon-volume-low{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder:before,.vjs-icon-volume-low:before{content:"\f105"}.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder,.vjs-icon-volume-mid{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder:before,.vjs-icon-volume-mid:before{content:"\f106"}.video-js .vjs-mute-control .vjs-icon-placeholder,.vjs-icon-volume-high{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-mute-control .vjs-icon-placeholder:before,.vjs-icon-volume-high:before{content:"\f107"}.video-js .vjs-fullscreen-control .vjs-icon-placeholder,.vjs-icon-fullscreen-enter{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-fullscreen-control .vjs-icon-placeholder:before,.vjs-icon-fullscreen-enter:before{content:"\f108"}.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder,.vjs-icon-fullscreen-exit{font-family:VideoJS;font-weight:400;font-style:normal}.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder:before,.vjs-icon-fullscreen-exit:before{content:"\f109"}.vjs-icon-square{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-square:before{content:"\f10a"}.vjs-icon-spinner{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-spinner:before{content:"\f10b"}.video-js .vjs-subs-caps-button .vjs-icon-placeholder,.video-js .vjs-subtitles-button .vjs-icon-placeholder,.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder,.vjs-icon-subtitles{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js .vjs-subtitles-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder:before,.vjs-icon-subtitles:before{content:"\f10c"}.video-js .vjs-captions-button .vjs-icon-placeholder,.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder,.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder,.vjs-icon-captions{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-captions-button .vjs-icon-placeholder:before,.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder:before,.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder:before,.vjs-icon-captions:before{content:"\f10d"}.video-js .vjs-chapters-button .vjs-icon-placeholder,.vjs-icon-chapters{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-chapters-button .vjs-icon-placeholder:before,.vjs-icon-chapters:before{content:"\f10e"}.vjs-icon-share{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-share:before{content:"\f10f"}.vjs-icon-cog{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-cog:before{content:"\f110"}.video-js .vjs-play-progress,.video-js .vjs-volume-level,.vjs-icon-circle{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-progress:before,.video-js .vjs-volume-level:before,.vjs-icon-circle:before{content:"\f111"}.vjs-icon-circle-outline{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-circle-outline:before{content:"\f112"}.vjs-icon-circle-inner-circle{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-circle-inner-circle:before{content:"\f113"}.vjs-icon-hd{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-hd:before{content:"\f114"}.video-js .vjs-control.vjs-close-button .vjs-icon-placeholder,.vjs-icon-cancel{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-control.vjs-close-button .vjs-icon-placeholder:before,.vjs-icon-cancel:before{content:"\f115"}.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder,.vjs-icon-replay{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder:before,.vjs-icon-replay:before{content:"\f116"}.vjs-icon-facebook{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-facebook:before{content:"\f117"}.vjs-icon-gplus{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-gplus:before{content:"\f118"}.vjs-icon-linkedin{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-linkedin:before{content:"\f119"}.vjs-icon-twitter{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-twitter:before{content:"\f11a"}.vjs-icon-tumblr{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-tumblr:before{content:"\f11b"}.vjs-icon-pinterest{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-pinterest:before{content:"\f11c"}.video-js .vjs-descriptions-button .vjs-icon-placeholder,.vjs-icon-audio-description{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-descriptions-button .vjs-icon-placeholder:before,.vjs-icon-audio-description:before{content:"\f11d"}.video-js .vjs-audio-button .vjs-icon-placeholder,.vjs-icon-audio{font-family:VideoJS;font-weight:400;font-style:normal}.video-js .vjs-audio-button .vjs-icon-placeholder:before,.vjs-icon-audio:before{content:"\f11e"}.vjs-icon-next-item{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-next-item:before{content:"\f11f"}.vjs-icon-previous-item{font-family:VideoJS;font-weight:400;font-style:normal}.vjs-icon-previous-item:before{content:"\f120"}.video-js{display:block;vertical-align:top;box-sizing:border-box;color:#fff;background-color:#000;position:relative;padding:0;font-size:10px;line-height:1;font-weight:400;font-style:normal;font-family:Arial,Helvetica,sans-serif;word-break:initial}.video-js:-moz-full-screen{position:absolute}.video-js:-webkit-full-screen{width:100%!important;height:100%!important}.video-js[tabindex="-1"]{outline:0}.video-js *,.video-js :after,.video-js :before{box-sizing:inherit}.video-js ul{font-family:inherit;font-size:inherit;line-height:inherit;list-style-position:outside;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.video-js.vjs-16-9,.video-js.vjs-4-3,.video-js.vjs-fluid{width:100%;max-width:100%;height:0}.video-js.vjs-16-9{padding-top:56.25%}.video-js.vjs-4-3{padding-top:75%}.video-js.vjs-fill{width:100%;height:100%}.video-js .vjs-tech{position:absolute;top:0;left:0;width:100%;height:100%}body.vjs-full-window{padding:0;margin:0;height:100%}.vjs-full-window .video-js.vjs-fullscreen{position:fixed;overflow:hidden;z-index:1000;left:0;top:0;bottom:0;right:0}.video-js.vjs-fullscreen{width:100%!important;height:100%!important;padding-top:0!important}.video-js.vjs-fullscreen.vjs-user-inactive{cursor:none}.vjs-hidden{display:none!important}.vjs-disabled{opacity:.5;cursor:default}.video-js .vjs-offscreen{height:1px;left:-9999px;position:absolute;top:0;width:1px}.vjs-lock-showing{display:block!important;opacity:1;visibility:visible}.vjs-no-js{padding:20px;color:#fff;background-color:#000;font-size:18px;font-family:Arial,Helvetica,sans-serif;text-align:center;width:300px;height:150px;margin:0 auto}.vjs-no-js a,.vjs-no-js a:visited{color:#66a8cc}.video-js .vjs-big-play-button{font-size:3em;line-height:1.5em;height:1.5em;width:3em;display:block;position:absolute;top:10px;left:10px;padding:0;cursor:pointer;opacity:1;border:.06666em solid #fff;background-color:#2b333f;background-color:rgba(43,51,63,.7);-webkit-border-radius:.3em;-moz-border-radius:.3em;border-radius:.3em;-webkit-transition:all .4s;-moz-transition:all .4s;-ms-transition:all .4s;-o-transition:all .4s;transition:all .4s}.vjs-big-play-centered .vjs-big-play-button{top:50%;left:50%;margin-top:-.75em;margin-left:-1.5em}.video-js .vjs-big-play-button:focus,.video-js:hover .vjs-big-play-button{border-color:#fff;background-color:#73859f;background-color:rgba(115,133,159,.5);-webkit-transition:all 0s;-moz-transition:all 0s;-ms-transition:all 0s;-o-transition:all 0s;transition:all 0s}.vjs-controls-disabled .vjs-big-play-button,.vjs-error .vjs-big-play-button,.vjs-has-started .vjs-big-play-button,.vjs-using-native-controls .vjs-big-play-button{display:none}.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause .vjs-big-play-button{display:block}.video-js button{background:0 0;border:none;color:inherit;display:inline-block;font-size:inherit;line-height:inherit;text-transform:none;text-decoration:none;transition:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.vjs-control .vjs-button{width:100%;height:100%}.video-js .vjs-control.vjs-close-button{cursor:pointer;height:3em;position:absolute;right:0;top:.5em;z-index:2}.video-js .vjs-modal-dialog{background:rgba(0,0,0,.8);background:-webkit-linear-gradient(-90deg,rgba(0,0,0,.8),rgba(255,255,255,0));background:linear-gradient(180deg,rgba(0,0,0,.8),rgba(255,255,255,0));overflow:auto}.video-js .vjs-modal-dialog>*{box-sizing:border-box}.vjs-modal-dialog .vjs-modal-dialog-content{font-size:1.2em;line-height:1.5;padding:20px 24px;z-index:1}.vjs-menu-button{cursor:pointer}.vjs-menu-button.vjs-disabled{cursor:default}.vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu{display:none}.vjs-menu .vjs-menu-content{display:block;padding:0;margin:0;font-family:Arial,Helvetica,sans-serif;overflow:auto}.vjs-menu .vjs-menu-content>*{box-sizing:border-box}.vjs-scrubbing .vjs-control.vjs-menu-button:hover .vjs-menu{display:none}.vjs-menu li{list-style:none;margin:0;padding:.2em 0;line-height:1.4em;font-size:1.2em;text-align:center;text-transform:lowercase}.vjs-menu li.vjs-menu-item:focus,.vjs-menu li.vjs-menu-item:hover{background-color:#73859f;background-color:rgba(115,133,159,.5)}.vjs-menu li.vjs-selected,.vjs-menu li.vjs-selected:focus,.vjs-menu li.vjs-selected:hover{background-color:#fff;color:#2b333f}.vjs-menu li.vjs-menu-title{text-align:center;text-transform:uppercase;font-size:1em;line-height:2em;padding:0;margin:0 0 .3em 0;font-weight:700;cursor:default}.vjs-menu-button-popup .vjs-menu{display:none;position:absolute;bottom:0;width:10em;left:-3em;height:0;margin-bottom:1.5em;border-top-color:rgba(43,51,63,.7)}.vjs-menu-button-popup .vjs-menu .vjs-menu-content{background-color:#2b333f;background-color:rgba(43,51,63,.7);position:absolute;width:100%;bottom:1.5em;max-height:15em}.vjs-menu-button-popup .vjs-menu.vjs-lock-showing,.vjs-workinghover .vjs-menu-button-popup:hover .vjs-menu{display:block}.video-js .vjs-menu-button-inline{-webkit-transition:all .4s;-moz-transition:all .4s;-ms-transition:all .4s;-o-transition:all .4s;transition:all .4s;overflow:hidden}.video-js .vjs-menu-button-inline:before{width:2.222222222em}.video-js .vjs-menu-button-inline.vjs-slider-active,.video-js .vjs-menu-button-inline:focus,.video-js .vjs-menu-button-inline:hover,.video-js.vjs-no-flex .vjs-menu-button-inline{width:12em}.vjs-menu-button-inline .vjs-menu{opacity:0;height:100%;width:auto;position:absolute;left:4em;top:0;padding:0;margin:0;-webkit-transition:all .4s;-moz-transition:all .4s;-ms-transition:all .4s;-o-transition:all .4s;transition:all .4s}.vjs-menu-button-inline.vjs-slider-active .vjs-menu,.vjs-menu-button-inline:focus .vjs-menu,.vjs-menu-button-inline:hover .vjs-menu{display:block;opacity:1}.vjs-no-flex .vjs-menu-button-inline .vjs-menu{display:block;opacity:1;position:relative;width:auto}.vjs-no-flex .vjs-menu-button-inline.vjs-slider-active .vjs-menu,.vjs-no-flex .vjs-menu-button-inline:focus .vjs-menu,.vjs-no-flex .vjs-menu-button-inline:hover .vjs-menu{width:auto}.vjs-menu-button-inline .vjs-menu-content{width:auto;height:100%;margin:0;overflow:hidden}.video-js .vjs-control-bar{display:none;width:100%;position:absolute;bottom:0;left:0;right:0;height:3em;background-color:#2b333f;background-color:rgba(43,51,63,.7)}.vjs-has-started .vjs-control-bar{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;visibility:visible;opacity:1;-webkit-transition:visibility .1s,opacity .1s;-moz-transition:visibility .1s,opacity .1s;-ms-transition:visibility .1s,opacity .1s;-o-transition:visibility .1s,opacity .1s;transition:visibility .1s,opacity .1s}.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{visibility:visible;opacity:0;-webkit-transition:visibility 1s,opacity 1s;-moz-transition:visibility 1s,opacity 1s;-ms-transition:visibility 1s,opacity 1s;-o-transition:visibility 1s,opacity 1s;transition:visibility 1s,opacity 1s}.vjs-controls-disabled .vjs-control-bar,.vjs-error .vjs-control-bar,.vjs-using-native-controls .vjs-control-bar{display:none!important}.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{opacity:1;visibility:visible}.vjs-has-started.vjs-no-flex .vjs-control-bar{display:table}.video-js .vjs-control{position:relative;text-align:center;margin:0;padding:0;height:100%;width:4em;-webkit-box-flex:none;-moz-box-flex:none;-webkit-flex:none;-ms-flex:none;flex:none}.vjs-button>.vjs-icon-placeholder:before{font-size:1.8em;line-height:1.67}.video-js .vjs-control:focus,.video-js .vjs-control:focus:before,.video-js .vjs-control:hover:before{text-shadow:0 0 1em #fff}.video-js .vjs-control-text{border:0;clip:rect(0 0 0 0);height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.vjs-no-flex .vjs-control{display:table-cell;vertical-align:middle}.video-js .vjs-custom-control-spacer{display:none}.video-js .vjs-progress-control{cursor:pointer;-webkit-box-flex:auto;-moz-box-flex:auto;-webkit-flex:auto;-ms-flex:auto;flex:auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;min-width:4em}.video-js .vjs-progress-control.disabled{cursor:default}.vjs-live .vjs-progress-control{display:none}.vjs-no-flex .vjs-progress-control{width:auto}.video-js .vjs-progress-holder{-webkit-box-flex:auto;-moz-box-flex:auto;-webkit-flex:auto;-ms-flex:auto;flex:auto;-webkit-transition:all .2s;-moz-transition:all .2s;-ms-transition:all .2s;-o-transition:all .2s;transition:all .2s;height:.3em}.video-js .vjs-progress-control .vjs-progress-holder{margin:0 10px}.video-js .vjs-progress-control:hover .vjs-progress-holder{font-size:1.666666666666666666em}.video-js .vjs-progress-control:hover .vjs-progress-holder.disabled{font-size:1em}.video-js .vjs-progress-holder .vjs-load-progress,.video-js .vjs-progress-holder .vjs-load-progress div,.video-js .vjs-progress-holder .vjs-play-progress{position:absolute;display:block;height:100%;margin:0;padding:0;width:0}.video-js .vjs-play-progress{background-color:#fff}.video-js .vjs-play-progress:before{font-size:.9em;position:absolute;right:-.5em;top:-.333333333333333em;z-index:1}.video-js .vjs-load-progress{background:rgba(115,133,159,.5)}.video-js .vjs-load-progress div{background:rgba(115,133,159,.75)}.video-js .vjs-time-tooltip{background-color:#fff;background-color:rgba(255,255,255,.8);-webkit-border-radius:.3em;-moz-border-radius:.3em;border-radius:.3em;color:#000;float:right;font-family:Arial,Helvetica,sans-serif;font-size:1em;padding:6px 8px 8px 8px;pointer-events:none;position:relative;top:-3.4em;visibility:hidden;z-index:1}.video-js .vjs-progress-holder:focus .vjs-time-tooltip{display:none}.video-js .vjs-progress-control:hover .vjs-progress-holder:focus .vjs-time-tooltip,.video-js .vjs-progress-control:hover .vjs-time-tooltip{display:block;font-size:.6em;visibility:visible}.video-js .vjs-progress-control.disabled:hover .vjs-time-tooltip{font-size:1em}.video-js .vjs-progress-control .vjs-mouse-display{display:none;position:absolute;width:1px;height:100%;background-color:#000;z-index:1}.vjs-no-flex .vjs-progress-control .vjs-mouse-display{z-index:0}.video-js .vjs-progress-control:hover .vjs-mouse-display{display:block}.video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display{visibility:hidden;opacity:0;-webkit-transition:visibility 1s,opacity 1s;-moz-transition:visibility 1s,opacity 1s;-ms-transition:visibility 1s,opacity 1s;-o-transition:visibility 1s,opacity 1s;transition:visibility 1s,opacity 1s}.video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display{display:none}.vjs-mouse-display .vjs-time-tooltip{color:#fff;background-color:#000;background-color:rgba(0,0,0,.8)}.video-js .vjs-slider{position:relative;cursor:pointer;padding:0;margin:0 .45em 0 .45em;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#73859f;background-color:rgba(115,133,159,.5)}.video-js .vjs-slider.disabled{cursor:default}.video-js .vjs-slider:focus{text-shadow:0 0 1em #fff;-webkit-box-shadow:0 0 1em #fff;-moz-box-shadow:0 0 1em #fff;box-shadow:0 0 1em #fff}.video-js .vjs-mute-control{cursor:pointer;-webkit-box-flex:none;-moz-box-flex:none;-webkit-flex:none;-ms-flex:none;flex:none}.video-js .vjs-volume-control{cursor:pointer;margin-right:1em;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.video-js .vjs-volume-control.vjs-volume-horizontal{width:5em}.video-js .vjs-volume-panel .vjs-volume-control{visibility:visible;opacity:0;width:1px;height:1px;margin-left:-1px}.video-js .vjs-volume-panel{-webkit-transition:width 1s;-moz-transition:width 1s;-ms-transition:width 1s;-o-transition:width 1s;transition:width 1s}.video-js .vjs-volume-panel .vjs-mute-control:hover~.vjs-volume-control,.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active,.video-js .vjs-volume-panel .vjs-volume-control:active,.video-js .vjs-volume-panel .vjs-volume-control:hover,.video-js .vjs-volume-panel:active .vjs-volume-control,.video-js .vjs-volume-panel:focus .vjs-volume-control,.video-js .vjs-volume-panel:hover .vjs-volume-control{visibility:visible;opacity:1;position:relative;-webkit-transition:visibility .1s,opacity .1s,height .1s,width .1s,left 0s,top 0s;-moz-transition:visibility .1s,opacity .1s,height .1s,width .1s,left 0s,top 0s;-ms-transition:visibility .1s,opacity .1s,height .1s,width .1s,left 0s,top 0s;-o-transition:visibility .1s,opacity .1s,height .1s,width .1s,left 0s,top 0s;transition:visibility .1s,opacity .1s,height .1s,width .1s,left 0s,top 0s}.video-js .vjs-volume-panel .vjs-mute-control:hover~.vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-horizontal,.video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-horizontal,.video-js .vjs-volume-panel .vjs-volume-control:hover.vjs-volume-horizontal,.video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal,.video-js .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal{width:5em;height:3em}.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active,.video-js .vjs-volume-panel.vjs-volume-panel-horizontal:hover{width:9em;-webkit-transition:width .1s;-moz-transition:width .1s;-ms-transition:width .1s;-o-transition:width .1s;transition:width .1s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical{height:8em;width:3em;left:-3.5em;-webkit-transition:visibility 1s,opacity 1s,height 1s 1s,width 1s 1s,left 1s 1s,top 1s 1s;-moz-transition:visibility 1s,opacity 1s,height 1s 1s,width 1s 1s,left 1s 1s,top 1s 1s;-ms-transition:visibility 1s,opacity 1s,height 1s 1s,width 1s 1s,left 1s 1s,top 1s 1s;-o-transition:visibility 1s,opacity 1s,height 1s 1s,width 1s 1s,left 1s 1s,top 1s 1s;transition:visibility 1s,opacity 1s,height 1s 1s,width 1s 1s,left 1s 1s,top 1s 1s}.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal{-webkit-transition:visibility 1s,opacity 1s,height 1s 1s,width 1s,left 1s 1s,top 1s 1s;-moz-transition:visibility 1s,opacity 1s,height 1s 1s,width 1s,left 1s 1s,top 1s 1s;-ms-transition:visibility 1s,opacity 1s,height 1s 1s,width 1s,left 1s 1s,top 1s 1s;-o-transition:visibility 1s,opacity 1s,height 1s 1s,width 1s,left 1s 1s,top 1s 1s;transition:visibility 1s,opacity 1s,height 1s 1s,width 1s,left 1s 1s,top 1s 1s}.video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal{width:5em;height:3em;visibility:visible;opacity:1;position:relative;-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}.video-js.vjs-no-flex .vjs-volume-control.vjs-volume-vertical,.video-js.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical{position:absolute;bottom:3em;left:.5em}.video-js .vjs-volume-panel{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.video-js .vjs-volume-bar{margin:1.35em .45em}.vjs-volume-bar.vjs-slider-horizontal{width:5em;height:.3em}.vjs-volume-bar.vjs-slider-vertical{width:.3em;height:5em;margin:1.35em auto}.video-js .vjs-volume-level{position:absolute;bottom:0;left:0;background-color:#fff}.video-js .vjs-volume-level:before{position:absolute;font-size:.9em}.vjs-slider-vertical .vjs-volume-level{width:.3em}.vjs-slider-vertical .vjs-volume-level:before{top:-.5em;left:-.3em}.vjs-slider-horizontal .vjs-volume-level{height:.3em}.vjs-slider-horizontal .vjs-volume-level:before{top:-.3em;right:-.5em}.video-js .vjs-volume-panel.vjs-volume-panel-vertical{width:4em}.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level{height:100%}.vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level{width:100%}.video-js .vjs-volume-vertical{width:3em;height:8em;bottom:8em;background-color:#2b333f;background-color:rgba(43,51,63,.7)}.video-js .vjs-volume-horizontal .vjs-menu{left:-2em}.vjs-poster{display:inline-block;vertical-align:middle;background-repeat:no-repeat;background-position:50% 50%;background-size:contain;background-color:#000;cursor:pointer;margin:0;padding:0;position:absolute;top:0;right:0;bottom:0;left:0;height:100%}.vjs-has-started .vjs-poster{display:none}.vjs-audio.vjs-has-started .vjs-poster{display:block}.vjs-using-native-controls .vjs-poster{display:none}.video-js .vjs-live-control{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-flex:auto;-moz-box-flex:auto;-webkit-flex:auto;-ms-flex:auto;flex:auto;font-size:1em;line-height:3em}.vjs-no-flex .vjs-live-control{display:table-cell;width:auto;text-align:left}.video-js .vjs-time-control{-webkit-box-flex:none;-moz-box-flex:none;-webkit-flex:none;-ms-flex:none;flex:none;font-size:1em;line-height:3em;min-width:2em;width:auto;padding-left:1em;padding-right:1em}.vjs-live .vjs-time-control{display:none}.video-js .vjs-current-time,.vjs-no-flex .vjs-current-time{display:none}.video-js .vjs-duration,.vjs-no-flex .vjs-duration{display:none}.vjs-time-divider{display:none;line-height:3em}.vjs-live .vjs-time-divider{display:none}.video-js .vjs-play-control .vjs-icon-placeholder{cursor:pointer;-webkit-box-flex:none;-moz-box-flex:none;-webkit-flex:none;-ms-flex:none;flex:none}.vjs-text-track-display{position:absolute;bottom:3em;left:0;right:0;top:0;pointer-events:none}.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display{bottom:1em}.video-js .vjs-text-track{font-size:1.4em;text-align:center;margin-bottom:.1em}.vjs-subtitles{color:#fff}.vjs-captions{color:#fc6}.vjs-tt-cue{display:block}video::-webkit-media-text-track-display{-moz-transform:translateY(-3em);-ms-transform:translateY(-3em);-o-transform:translateY(-3em);-webkit-transform:translateY(-3em);transform:translateY(-3em)}.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display{-moz-transform:translateY(-1.5em);-ms-transform:translateY(-1.5em);-o-transform:translateY(-1.5em);-webkit-transform:translateY(-1.5em);transform:translateY(-1.5em)}.video-js .vjs-fullscreen-control{cursor:pointer;-webkit-box-flex:none;-moz-box-flex:none;-webkit-flex:none;-ms-flex:none;flex:none}.vjs-playback-rate .vjs-playback-rate-value,.vjs-playback-rate>.vjs-menu-button{position:absolute;top:0;left:0;width:100%;height:100%}.vjs-playback-rate .vjs-playback-rate-value{pointer-events:none;font-size:1.5em;line-height:2;text-align:center}.vjs-playback-rate .vjs-menu{width:4em;left:0}.vjs-error .vjs-error-display .vjs-modal-dialog-content{font-size:1.4em;text-align:center}.vjs-error .vjs-error-display:before{color:#fff;content:'X';font-family:Arial,Helvetica,sans-serif;font-size:4em;left:0;line-height:1;margin-top:-.5em;position:absolute;text-shadow:.05em .05em .1em #000;text-align:center;top:50%;vertical-align:middle;width:100%}.vjs-loading-spinner{display:none;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;opacity:.85;text-align:left;border:6px solid rgba(43,51,63,.7);box-sizing:border-box;background-clip:padding-box;width:50px;height:50px;border-radius:25px;visibility:hidden}.vjs-seeking .vjs-loading-spinner,.vjs-waiting .vjs-loading-spinner{display:block;animation:0s linear .3s forwards vjs-spinner-show}.vjs-loading-spinner:after,.vjs-loading-spinner:before{content:"";position:absolute;margin:-6px;box-sizing:inherit;width:inherit;height:inherit;border-radius:inherit;opacity:1;border:inherit;border-color:transparent;border-top-color:#fff}.vjs-seeking .vjs-loading-spinner:after,.vjs-seeking .vjs-loading-spinner:before,.vjs-waiting .vjs-loading-spinner:after,.vjs-waiting .vjs-loading-spinner:before{-webkit-animation:vjs-spinner-spin 1.1s cubic-bezier(.6,.2,0,.8) infinite,vjs-spinner-fade 1.1s linear infinite;animation:vjs-spinner-spin 1.1s cubic-bezier(.6,.2,0,.8) infinite,vjs-spinner-fade 1.1s linear infinite}.vjs-seeking .vjs-loading-spinner:before,.vjs-waiting .vjs-loading-spinner:before{border-top-color:#fff}.vjs-seeking .vjs-loading-spinner:after,.vjs-waiting .vjs-loading-spinner:after{border-top-color:#fff;-webkit-animation-delay:.44s;animation-delay:.44s}@keyframes vjs-spinner-show{to{visibility:visible}}@-webkit-keyframes vjs-spinner-show{to{visibility:visible}}@keyframes vjs-spinner-spin{100%{transform:rotate(360deg)}}@-webkit-keyframes vjs-spinner-spin{100%{-webkit-transform:rotate(360deg)}}@keyframes vjs-spinner-fade{0%{border-top-color:#73859f}20%{border-top-color:#73859f}35%{border-top-color:#fff}60%{border-top-color:#73859f}100%{border-top-color:#73859f}}@-webkit-keyframes vjs-spinner-fade{0%{border-top-color:#73859f}20%{border-top-color:#73859f}35%{border-top-color:#fff}60%{border-top-color:#73859f}100%{border-top-color:#73859f}}.vjs-chapters-button .vjs-menu ul{width:24em}.video-js .vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder{position:absolute}.video-js .vjs-subs-caps-button+.vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before{font-family:VideoJS;content:"\f10d";font-size:1.5em;line-height:inherit}.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-custom-control-spacer{-webkit-box-flex:auto;-moz-box-flex:auto;-webkit-flex:auto;-ms-flex:auto;flex:auto}.video-js.vjs-layout-tiny:not(.vjs-fullscreen).vjs-no-flex .vjs-custom-control-spacer{width:auto}.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-audio-button,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-captions-button,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-chapters-button,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-current-time,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-descriptions-button,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-duration,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-mute-control,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-playback-rate,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-progress-control,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-remaining-time,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-subtitles-button,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-time-divider,.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-volume-control{display:none}.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-audio-button,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-captions-button,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-chapters-button,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-current-time,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-descriptions-button,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-duration,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-mute-control,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-playback-rate,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-remaining-time,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-subtitles-button,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-time-divider,.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-volume-control{display:none}.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-captions-button,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-chapters-button,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-current-time,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-descriptions-button,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-duration,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-mute-control,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-playback-rate,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-remaining-time,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-subtitles-button .vjs-audio-button,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-time-divider,.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-volume-control{display:none}.vjs-modal-dialog.vjs-text-track-settings{background-color:#2b333f;background-color:rgba(43,51,63,.75);color:#fff;height:70%}.vjs-text-track-settings .vjs-modal-dialog-content{display:table}.vjs-text-track-settings .vjs-track-settings-colors,.vjs-text-track-settings .vjs-track-settings-controls,.vjs-text-track-settings .vjs-track-settings-font{display:table-cell}.vjs-text-track-settings .vjs-track-settings-controls{text-align:right;vertical-align:bottom}@supports (display:grid){.vjs-text-track-settings .vjs-modal-dialog-content{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr auto}.vjs-text-track-settings .vjs-track-settings-colors{display:block;grid-column:1;grid-row:1}.vjs-text-track-settings .vjs-track-settings-font{grid-column:2;grid-row:1}.vjs-text-track-settings .vjs-track-settings-controls{grid-column:2;grid-row:2}}.vjs-track-setting>select{margin-right:5px}.vjs-text-track-settings fieldset{margin:5px;padding:3px;border:none}.vjs-text-track-settings fieldset span{display:inline-block}.vjs-text-track-settings legend{color:#fff;margin:0 0 5px 0}.vjs-text-track-settings .vjs-label{position:absolute;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);display:block;margin:0 0 5px 0;padding:0;border:0;height:1px;width:1px;overflow:hidden}.vjs-track-settings-controls button:active,.vjs-track-settings-controls button:focus{outline-style:solid;outline-width:medium;background-image:linear-gradient(0deg,#fff 88%,#73859f 100%)}.vjs-track-settings-controls button:hover{color:rgba(43,51,63,.75)}.vjs-track-settings-controls button{background-color:#fff;background-image:linear-gradient(-180deg,#fff 88%,#73859f 100%);color:#2b333f;cursor:pointer;border-radius:2px}.vjs-track-settings-controls .vjs-default-button{margin-right:1em}@media print{.video-js>:not(.vjs-tech):not(.vjs-poster){visibility:hidden}}.vjs-resize-manager{position:absolute;top:0;left:0;width:100%;height:100%;border:none;visibility:hidden} diff --git a/form/src/assets/libs/video-js-7.0.0/video.js b/form/src/assets/libs/video-js-7.0.0/video.js new file mode 100644 index 0000000000000000000000000000000000000000..7fbbd14e6924cad421d0cce2f555276b99bde878 --- /dev/null +++ b/form/src/assets/libs/video-js-7.0.0/video.js @@ -0,0 +1,47623 @@ +/** + * @license + * Video.js 7.0.0 <http://videojs.com/> + * Copyright Brightcove, Inc. <https://www.brightcove.com/> + * Available under Apache License Version 2.0 + * <https://github.com/videojs/video.js/blob/master/LICENSE> + * + * Includes vtt.js <https://github.com/mozilla/vtt.js> + * Available under Apache License Version 2.0 + * <https://github.com/mozilla/vtt.js/blob/master/LICENSE> + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.videojs = factory()); +}(this, (function () { + + var version = "7.0.0"; + + var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + function createCommonjsModule(fn, module) { + return module = {exports: {}}, fn(module, module.exports), module.exports; + } + + var win; + + if (typeof window !== "undefined") { + win = window; + } else if (typeof commonjsGlobal !== "undefined") { + win = commonjsGlobal; + } else if (typeof self !== "undefined") { + win = self; + } else { + win = {}; + } + + var window_1 = win; + + var empty = {}; + + var empty$1 = /*#__PURE__*/Object.freeze({ + default: empty + }); + + var minDoc = (empty$1 && empty) || empty$1; + + var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof window !== 'undefined' ? window : {}; + + var doccy; + + if (typeof document !== 'undefined') { + doccy = document; + } else { + doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; + + if (!doccy) { + doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; + } + } + + var document_1 = doccy; + + /** + * @file log.js + * @module log + */ + + var log = void 0; + + // This is the private tracking variable for logging level. + var level = 'info'; + + // This is the private tracking variable for the logging history. + var history = []; + + /** + * Log messages to the console and history based on the type of message + * + * @private + * @param {string} type + * The name of the console method to use. + * + * @param {Array} args + * The arguments to be passed to the matching console method. + */ + var logByType = function logByType(type, args) { + var lvl = log.levels[level]; + var lvlRegExp = new RegExp('^(' + lvl + ')$'); + + if (type !== 'log') { + + // Add the type to the front of the message when it's not "log". + args.unshift(type.toUpperCase() + ':'); + } + + // Add a clone of the args at this point to history. + if (history) { + history.push([].concat(args)); + } + + // Add console prefix after adding to history. + args.unshift('VIDEOJS:'); + + // If there's no console then don't try to output messages, but they will + // still be stored in history. + if (!window_1.console) { + return; + } + + // Was setting these once outside of this function, but containing them + // in the function makes it easier to test cases where console doesn't exist + // when the module is executed. + var fn = window_1.console[type]; + + if (!fn && type === 'debug') { + // Certain browsers don't have support for console.debug. For those, we + // should default to the closest comparable log. + fn = window_1.console.info || window_1.console.log; + } + + // Bail out if there's no console or if this type is not allowed by the + // current logging level. + if (!fn || !lvl || !lvlRegExp.test(type)) { + return; + } + + fn[Array.isArray(args) ? 'apply' : 'call'](window_1.console, args); + }; + + /** + * Logs plain debug messages. Similar to `console.log`. + * + * @class + * @param {Mixed[]} args + * One or more messages or objects that should be logged. + */ + log = function log() { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + logByType('log', args); + }; + + /** + * Enumeration of available logging levels, where the keys are the level names + * and the values are `|`-separated strings containing logging methods allowed + * in that logging level. These strings are used to create a regular expression + * matching the function name being called. + * + * Levels provided by video.js are: + * + * - `off`: Matches no calls. Any value that can be cast to `false` will have + * this effect. The most restrictive. + * - `all`: Matches only Video.js-provided functions (`debug`, `log`, + * `log.warn`, and `log.error`). + * - `debug`: Matches `log.debug`, `log`, `log.warn`, and `log.error` calls. + * - `info` (default): Matches `log`, `log.warn`, and `log.error` calls. + * - `warn`: Matches `log.warn` and `log.error` calls. + * - `error`: Matches only `log.error` calls. + * + * @type {Object} + */ + log.levels = { + all: 'debug|log|warn|error', + off: '', + debug: 'debug|log|warn|error', + info: 'log|warn|error', + warn: 'warn|error', + error: 'error', + DEFAULT: level + }; + + /** + * Get or set the current logging level. If a string matching a key from + * {@link log.levels} is provided, acts as a setter. Regardless of argument, + * returns the current logging level. + * + * @param {string} [lvl] + * Pass to set a new logging level. + * + * @return {string} + * The current logging level. + */ + log.level = function (lvl) { + if (typeof lvl === 'string') { + if (!log.levels.hasOwnProperty(lvl)) { + throw new Error('"' + lvl + '" in not a valid log level'); + } + level = lvl; + } + return level; + }; + + /** + * Returns an array containing everything that has been logged to the history. + * + * This array is a shallow clone of the internal history record. However, its + * contents are _not_ cloned; so, mutating objects inside this array will + * mutate them in history. + * + * @return {Array} + */ + log.history = function () { + return history ? [].concat(history) : []; + }; + + /** + * Clears the internal history tracking, but does not prevent further history + * tracking. + */ + log.history.clear = function () { + if (history) { + history.length = 0; + } + }; + + /** + * Disable history tracking if it is currently enabled. + */ + log.history.disable = function () { + if (history !== null) { + history.length = 0; + history = null; + } + }; + + /** + * Enable history tracking if it is currently disabled. + */ + log.history.enable = function () { + if (history === null) { + history = []; + } + }; + + /** + * Logs error messages. Similar to `console.error`. + * + * @param {Mixed[]} args + * One or more messages or objects that should be logged as an error + */ + log.error = function () { + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + return logByType('error', args); + }; + + /** + * Logs warning messages. Similar to `console.warn`. + * + * @param {Mixed[]} args + * One or more messages or objects that should be logged as a warning. + */ + log.warn = function () { + for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } + + return logByType('warn', args); + }; + + /** + * Logs debug messages. Similar to `console.debug`, but may also act as a comparable + * log if `console.debug` is not available + * + * @param {Mixed[]} args + * One or more messages or objects that should be logged as debug. + */ + log.debug = function () { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + return logByType('debug', args); + }; + + var log$1 = log; + + function clean(s) { + return s.replace(/\n\r?\s*/g, ''); + } + + var tsml = function tsml(sa) { + var s = '', + i = 0; + + for (; i < arguments.length; i++) { + s += clean(sa[i]) + (arguments[i + 1] || ''); + } + return s; + }; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + var inherits = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + }; + + var possibleConstructorReturn = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && (typeof call === "object" || typeof call === "function") ? call : self; + }; + + var taggedTemplateLiteralLoose = function (strings, raw) { + strings.raw = raw; + return strings; + }; + + /** + * @file obj.js + * @module obj + */ + + /** + * @callback obj:EachCallback + * + * @param {Mixed} value + * The current key for the object that is being iterated over. + * + * @param {string} key + * The current key-value for object that is being iterated over + */ + + /** + * @callback obj:ReduceCallback + * + * @param {Mixed} accum + * The value that is accumulating over the reduce loop. + * + * @param {Mixed} value + * The current key for the object that is being iterated over. + * + * @param {string} key + * The current key-value for object that is being iterated over + * + * @return {Mixed} + * The new accumulated value. + */ + var toString = Object.prototype.toString; + + /** + * Get the keys of an Object + * + * @param {Object} + * The Object to get the keys from + * + * @return {string[]} + * An array of the keys from the object. Returns an empty array if the + * object passed in was invalid or had no keys. + * + * @private + */ + var keys = function keys(object) { + return isObject(object) ? Object.keys(object) : []; + }; + + /** + * Array-like iteration for objects. + * + * @param {Object} object + * The object to iterate over + * + * @param {obj:EachCallback} fn + * The callback function which is called for each key in the object. + */ + function each(object, fn) { + keys(object).forEach(function (key) { + return fn(object[key], key); + }); + } + + /** + * Array-like reduce for objects. + * + * @param {Object} object + * The Object that you want to reduce. + * + * @param {Function} fn + * A callback function which is called for each key in the object. It + * receives the accumulated value and the per-iteration value and key + * as arguments. + * + * @param {Mixed} [initial = 0] + * Starting value + * + * @return {Mixed} + * The final accumulated value. + */ + function reduce(object, fn) { + var initial = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + + return keys(object).reduce(function (accum, key) { + return fn(accum, object[key], key); + }, initial); + } + + /** + * Object.assign-style object shallow merge/extend. + * + * @param {Object} target + * @param {Object} ...sources + * @return {Object} + */ + function assign(target) { + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + if (Object.assign) { + return Object.assign.apply(Object, [target].concat(sources)); + } + + sources.forEach(function (source) { + if (!source) { + return; + } + + each(source, function (value, key) { + target[key] = value; + }); + }); + + return target; + } + + /** + * Returns whether a value is an object of any kind - including DOM nodes, + * arrays, regular expressions, etc. Not functions, though. + * + * This avoids the gotcha where using `typeof` on a `null` value + * results in `'object'`. + * + * @param {Object} value + * @return {Boolean} + */ + function isObject(value) { + return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object'; + } + + /** + * Returns whether an object appears to be a "plain" object - that is, a + * direct instance of `Object`. + * + * @param {Object} value + * @return {Boolean} + */ + function isPlain(value) { + return isObject(value) && toString.call(value) === '[object Object]' && value.constructor === Object; + } + + /** + * @file computed-style.js + * @module computed-style + */ + + /** + * A safe getComputedStyle. + * + * This is needed because in Firefox, if the player is loaded in an iframe with + * `display:none`, then `getComputedStyle` returns `null`, so, we do a null-check to + * make sure that the player doesn't break in these cases. + * + * @param {Element} el + * The element you want the computed style of + * + * @param {string} prop + * The property name you want + * + * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397 + * + * @static + * @const + */ + function computedStyle(el, prop) { + if (!el || !prop) { + return ''; + } + + if (typeof window_1.getComputedStyle === 'function') { + var cs = window_1.getComputedStyle(el); + + return cs ? cs[prop] : ''; + } + + return ''; + } + + var _templateObject = taggedTemplateLiteralLoose(['Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set ', ' to ', '.'], ['Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set ', ' to ', '.']); + + /** + * Detect if a value is a string with any non-whitespace characters. + * + * @param {string} str + * The string to check + * + * @return {boolean} + * - True if the string is non-blank + * - False otherwise + * + */ + function isNonBlankString(str) { + return typeof str === 'string' && /\S/.test(str); + } + + /** + * Throws an error if the passed string has whitespace. This is used by + * class methods to be relatively consistent with the classList API. + * + * @param {string} str + * The string to check for whitespace. + * + * @throws {Error} + * Throws an error if there is whitespace in the string. + * + */ + function throwIfWhitespace(str) { + if (/\s/.test(str)) { + throw new Error('class has illegal whitespace characters'); + } + } + + /** + * Produce a regular expression for matching a className within an elements className. + * + * @param {string} className + * The className to generate the RegExp for. + * + * @return {RegExp} + * The RegExp that will check for a specific `className` in an elements + * className. + */ + function classRegExp(className) { + return new RegExp('(^|\\s)' + className + '($|\\s)'); + } + + /** + * Whether the current DOM interface appears to be real. + * + * @return {Boolean} + */ + function isReal() { + // Both document and window will never be undefined thanks to `global`. + return document_1 === window_1.document; + } + + /** + * Determines, via duck typing, whether or not a value is a DOM element. + * + * @param {Mixed} value + * The thing to check + * + * @return {boolean} + * - True if it is a DOM element + * - False otherwise + */ + function isEl(value) { + return isObject(value) && value.nodeType === 1; + } + + /** + * Determines if the current DOM is embedded in an iframe. + * + * @return {boolean} + * + */ + function isInFrame() { + + // We need a try/catch here because Safari will throw errors when attempting + // to get either `parent` or `self` + try { + return window_1.parent !== window_1.self; + } catch (x) { + return true; + } + } + + /** + * Creates functions to query the DOM using a given method. + * + * @param {string} method + * The method to create the query with. + * + * @return {Function} + * The query method + */ + function createQuerier(method) { + return function (selector, context) { + if (!isNonBlankString(selector)) { + return document_1[method](null); + } + if (isNonBlankString(context)) { + context = document_1.querySelector(context); + } + + var ctx = isEl(context) ? context : document_1; + + return ctx[method] && ctx[method](selector); + }; + } + + /** + * Creates an element and applies properties. + * + * @param {string} [tagName='div'] + * Name of tag to be created. + * + * @param {Object} [properties={}] + * Element properties to be applied. + * + * @param {Object} [attributes={}] + * Element attributes to be applied. + * + * @param {String|Element|TextNode|Array|Function} [content] + * Contents for the element (see: {@link dom:normalizeContent}) + * + * @return {Element} + * The element that was created. + */ + function createEl() { + var tagName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div'; + var properties = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + var content = arguments[3]; + + var el = document_1.createElement(tagName); + + Object.getOwnPropertyNames(properties).forEach(function (propName) { + var val = properties[propName]; + + // See #2176 + // We originally were accepting both properties and attributes in the + // same object, but that doesn't work so well. + if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') { + log$1.warn(tsml(_templateObject, propName, val)); + el.setAttribute(propName, val); + + // Handle textContent since it's not supported everywhere and we have a + // method for it. + } else if (propName === 'textContent') { + textContent(el, val); + } else { + el[propName] = val; + } + }); + + Object.getOwnPropertyNames(attributes).forEach(function (attrName) { + el.setAttribute(attrName, attributes[attrName]); + }); + + if (content) { + appendContent(el, content); + } + + return el; + } + + /** + * Injects text into an element, replacing any existing contents entirely. + * + * @param {Element} el + * The element to add text content into + * + * @param {string} text + * The text content to add. + * + * @return {Element} + * The element with added text content. + */ + function textContent(el, text) { + if (typeof el.textContent === 'undefined') { + el.innerText = text; + } else { + el.textContent = text; + } + return el; + } + + /** + * Insert an element as the first child node of another + * + * @param {Element} child + * Element to insert + * + * @param {Element} parent + * Element to insert child into + */ + function prependTo(child, parent) { + if (parent.firstChild) { + parent.insertBefore(child, parent.firstChild); + } else { + parent.appendChild(child); + } + } + + /** + * Check if an element has a CSS class + * + * @param {Element} element + * Element to check + * + * @param {string} classToCheck + * Class name to check for + * + * @return {boolean} + * - True if the element had the class + * - False otherwise. + * + * @throws {Error} + * Throws an error if `classToCheck` has white space. + */ + function hasClass(element, classToCheck) { + throwIfWhitespace(classToCheck); + if (element.classList) { + return element.classList.contains(classToCheck); + } + return classRegExp(classToCheck).test(element.className); + } + + /** + * Add a CSS class name to an element + * + * @param {Element} element + * Element to add class name to. + * + * @param {string} classToAdd + * Class name to add. + * + * @return {Element} + * The dom element with the added class name. + */ + function addClass(element, classToAdd) { + if (element.classList) { + element.classList.add(classToAdd); + + // Don't need to `throwIfWhitespace` here because `hasElClass` will do it + // in the case of classList not being supported. + } else if (!hasClass(element, classToAdd)) { + element.className = (element.className + ' ' + classToAdd).trim(); + } + + return element; + } + + /** + * Remove a CSS class name from an element + * + * @param {Element} element + * Element to remove a class name from. + * + * @param {string} classToRemove + * Class name to remove + * + * @return {Element} + * The dom element with class name removed. + */ + function removeClass(element, classToRemove) { + if (element.classList) { + element.classList.remove(classToRemove); + } else { + throwIfWhitespace(classToRemove); + element.className = element.className.split(/\s+/).filter(function (c) { + return c !== classToRemove; + }).join(' '); + } + + return element; + } + + /** + * The callback definition for toggleElClass. + * + * @callback Dom~PredicateCallback + * @param {Element} element + * The DOM element of the Component. + * + * @param {string} classToToggle + * The `className` that wants to be toggled + * + * @return {boolean|undefined} + * - If true the `classToToggle` will get added to `element`. + * - If false the `classToToggle` will get removed from `element`. + * - If undefined this callback will be ignored + */ + + /** + * Adds or removes a CSS class name on an element depending on an optional + * condition or the presence/absence of the class name. + * + * @param {Element} element + * The element to toggle a class name on. + * + * @param {string} classToToggle + * The class that should be toggled + * + * @param {boolean|PredicateCallback} [predicate] + * See the return value for {@link Dom~PredicateCallback} + * + * @return {Element} + * The element with a class that has been toggled. + */ + function toggleClass(element, classToToggle, predicate) { + + // This CANNOT use `classList` internally because IE11 does not support the + // second parameter to the `classList.toggle()` method! Which is fine because + // `classList` will be used by the add/remove functions. + var has = hasClass(element, classToToggle); + + if (typeof predicate === 'function') { + predicate = predicate(element, classToToggle); + } + + if (typeof predicate !== 'boolean') { + predicate = !has; + } + + // If the necessary class operation matches the current state of the + // element, no action is required. + if (predicate === has) { + return; + } + + if (predicate) { + addClass(element, classToToggle); + } else { + removeClass(element, classToToggle); + } + + return element; + } + + /** + * Apply attributes to an HTML element. + * + * @param {Element} el + * Element to add attributes to. + * + * @param {Object} [attributes] + * Attributes to be applied. + */ + function setAttributes(el, attributes) { + Object.getOwnPropertyNames(attributes).forEach(function (attrName) { + var attrValue = attributes[attrName]; + + if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) { + el.removeAttribute(attrName); + } else { + el.setAttribute(attrName, attrValue === true ? '' : attrValue); + } + }); + } + + /** + * Get an element's attribute values, as defined on the HTML tag + * Attributes are not the same as properties. They're defined on the tag + * or with setAttribute (which shouldn't be used with HTML) + * This will return true or false for boolean attributes. + * + * @param {Element} tag + * Element from which to get tag attributes. + * + * @return {Object} + * All attributes of the element. + */ + function getAttributes(tag) { + var obj = {}; + + // known boolean attributes + // we can check for matching boolean properties, but not all browsers + // and not all tags know about these attributes, so, we still want to check them manually + var knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ','; + + if (tag && tag.attributes && tag.attributes.length > 0) { + var attrs = tag.attributes; + + for (var i = attrs.length - 1; i >= 0; i--) { + var attrName = attrs[i].name; + var attrVal = attrs[i].value; + + // check for known booleans + // the matching element property will return a value for typeof + if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) { + // the value of an included boolean attribute is typically an empty + // string ('') which would equal false if we just check for a false value. + // we also don't want support bad code like autoplay='false' + attrVal = attrVal !== null ? true : false; + } + + obj[attrName] = attrVal; + } + } + + return obj; + } + + /** + * Get the value of an element's attribute + * + * @param {Element} el + * A DOM element + * + * @param {string} attribute + * Attribute to get the value of + * + * @return {string} + * value of the attribute + */ + function getAttribute(el, attribute) { + return el.getAttribute(attribute); + } + + /** + * Set the value of an element's attribute + * + * @param {Element} el + * A DOM element + * + * @param {string} attribute + * Attribute to set + * + * @param {string} value + * Value to set the attribute to + */ + function setAttribute(el, attribute, value) { + el.setAttribute(attribute, value); + } + + /** + * Remove an element's attribute + * + * @param {Element} el + * A DOM element + * + * @param {string} attribute + * Attribute to remove + */ + function removeAttribute(el, attribute) { + el.removeAttribute(attribute); + } + + /** + * Attempt to block the ability to select text while dragging controls + */ + function blockTextSelection() { + document_1.body.focus(); + document_1.onselectstart = function () { + return false; + }; + } + + /** + * Turn off text selection blocking + */ + function unblockTextSelection() { + document_1.onselectstart = function () { + return true; + }; + } + + /** + * Identical to the native `getBoundingClientRect` function, but ensures that + * the method is supported at all (it is in all browsers we claim to support) + * and that the element is in the DOM before continuing. + * + * This wrapper function also shims properties which are not provided by some + * older browsers (namely, IE8). + * + * Additionally, some browsers do not support adding properties to a + * `ClientRect`/`DOMRect` object; so, we shallow-copy it with the standard + * properties (except `x` and `y` which are not widely supported). This helps + * avoid implementations where keys are non-enumerable. + * + * @param {Element} el + * Element whose `ClientRect` we want to calculate. + * + * @return {Object|undefined} + * Always returns a plain + */ + function getBoundingClientRect(el) { + if (el && el.getBoundingClientRect && el.parentNode) { + var rect = el.getBoundingClientRect(); + var result = {}; + + ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(function (k) { + if (rect[k] !== undefined) { + result[k] = rect[k]; + } + }); + + if (!result.height) { + result.height = parseFloat(computedStyle(el, 'height')); + } + + if (!result.width) { + result.width = parseFloat(computedStyle(el, 'width')); + } + + return result; + } + } + + /** + * The postion of a DOM element on the page. + * + * @typedef {Object} module:dom~Position + * + * @property {number} left + * Pixels to the left + * + * @property {number} top + * Pixels on top + */ + + /** + * Offset Left. + * getBoundingClientRect technique from + * John Resig + * + * @see http://ejohn.org/blog/getboundingclientrect-is-awesome/ + * + * @param {Element} el + * Element from which to get offset + * + * @return {module:dom~Position} + * The position of the element that was passed in. + */ + function findPosition(el) { + var box = void 0; + + if (el.getBoundingClientRect && el.parentNode) { + box = el.getBoundingClientRect(); + } + + if (!box) { + return { + left: 0, + top: 0 + }; + } + + var docEl = document_1.documentElement; + var body = document_1.body; + + var clientLeft = docEl.clientLeft || body.clientLeft || 0; + var scrollLeft = window_1.pageXOffset || body.scrollLeft; + var left = box.left + scrollLeft - clientLeft; + + var clientTop = docEl.clientTop || body.clientTop || 0; + var scrollTop = window_1.pageYOffset || body.scrollTop; + var top = box.top + scrollTop - clientTop; + + // Android sometimes returns slightly off decimal values, so need to round + return { + left: Math.round(left), + top: Math.round(top) + }; + } + + /** + * x and y coordinates for a dom element or mouse pointer + * + * @typedef {Object} Dom~Coordinates + * + * @property {number} x + * x coordinate in pixels + * + * @property {number} y + * y coordinate in pixels + */ + + /** + * Get pointer position in element + * Returns an object with x and y coordinates. + * The base on the coordinates are the bottom left of the element. + * + * @param {Element} el + * Element on which to get the pointer position on + * + * @param {EventTarget~Event} event + * Event object + * + * @return {Dom~Coordinates} + * A Coordinates object corresponding to the mouse position. + * + */ + function getPointerPosition(el, event) { + var position = {}; + var box = findPosition(el); + var boxW = el.offsetWidth; + var boxH = el.offsetHeight; + + var boxY = box.top; + var boxX = box.left; + var pageY = event.pageY; + var pageX = event.pageX; + + if (event.changedTouches) { + pageX = event.changedTouches[0].pageX; + pageY = event.changedTouches[0].pageY; + } + + position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH)); + position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW)); + + return position; + } + + /** + * Determines, via duck typing, whether or not a value is a text node. + * + * @param {Mixed} value + * Check if this value is a text node. + * + * @return {boolean} + * - True if it is a text node + * - False otherwise + */ + function isTextNode(value) { + return isObject(value) && value.nodeType === 3; + } + + /** + * Empties the contents of an element. + * + * @param {Element} el + * The element to empty children from + * + * @return {Element} + * The element with no children + */ + function emptyEl(el) { + while (el.firstChild) { + el.removeChild(el.firstChild); + } + return el; + } + + /** + * Normalizes content for eventual insertion into the DOM. + * + * This allows a wide range of content definition methods, but protects + * from falling into the trap of simply writing to `innerHTML`, which is + * an XSS concern. + * + * The content for an element can be passed in multiple types and + * combinations, whose behavior is as follows: + * + * @param {String|Element|TextNode|Array|Function} content + * - String: Normalized into a text node. + * - Element/TextNode: Passed through. + * - Array: A one-dimensional array of strings, elements, nodes, or functions + * (which return single strings, elements, or nodes). + * - Function: If the sole argument, is expected to produce a string, element, + * node, or array as defined above. + * + * @return {Array} + * All of the content that was passed in normalized. + */ + function normalizeContent(content) { + + // First, invoke content if it is a function. If it produces an array, + // that needs to happen before normalization. + if (typeof content === 'function') { + content = content(); + } + + // Next up, normalize to an array, so one or many items can be normalized, + // filtered, and returned. + return (Array.isArray(content) ? content : [content]).map(function (value) { + + // First, invoke value if it is a function to produce a new value, + // which will be subsequently normalized to a Node of some kind. + if (typeof value === 'function') { + value = value(); + } + + if (isEl(value) || isTextNode(value)) { + return value; + } + + if (typeof value === 'string' && /\S/.test(value)) { + return document_1.createTextNode(value); + } + }).filter(function (value) { + return value; + }); + } + + /** + * Normalizes and appends content to an element. + * + * @param {Element} el + * Element to append normalized content to. + * + * + * @param {String|Element|TextNode|Array|Function} content + * See the `content` argument of {@link dom:normalizeContent} + * + * @return {Element} + * The element with appended normalized content. + */ + function appendContent(el, content) { + normalizeContent(content).forEach(function (node) { + return el.appendChild(node); + }); + return el; + } + + /** + * Normalizes and inserts content into an element; this is identical to + * `appendContent()`, except it empties the element first. + * + * @param {Element} el + * Element to insert normalized content into. + * + * @param {String|Element|TextNode|Array|Function} content + * See the `content` argument of {@link dom:normalizeContent} + * + * @return {Element} + * The element with inserted normalized content. + * + */ + function insertContent(el, content) { + return appendContent(emptyEl(el), content); + } + + /** + * Check if event was a single left click + * + * @param {EventTarget~Event} event + * Event object + * + * @return {boolean} + * - True if a left click + * - False if not a left click + */ + function isSingleLeftClick(event) { + // Note: if you create something draggable, be sure to + // call it on both `mousedown` and `mousemove` event, + // otherwise `mousedown` should be enough for a button + + if (event.button === undefined && event.buttons === undefined) { + // Why do we need `buttons` ? + // Because, middle mouse sometimes have this: + // e.button === 0 and e.buttons === 4 + // Furthermore, we want to prevent combination click, something like + // HOLD middlemouse then left click, that would be + // e.button === 0, e.buttons === 5 + // just `button` is not gonna work + + // Alright, then what this block does ? + // this is for chrome `simulate mobile devices` + // I want to support this as well + + return true; + } + + if (event.button === 0 && event.buttons === undefined) { + // Touch screen, sometimes on some specific device, `buttons` + // doesn't have anything (safari on ios, blackberry...) + + return true; + } + + if (event.button !== 0 || event.buttons !== 1) { + // This is the reason we have those if else block above + // if any special case we can catch and let it slide + // we do it above, when get to here, this definitely + // is-not-left-click + + return false; + } + + return true; + } + + /** + * Finds a single DOM element matching `selector` within the optional + * `context` of another DOM element (defaulting to `document`). + * + * @param {string} selector + * A valid CSS selector, which will be passed to `querySelector`. + * + * @param {Element|String} [context=document] + * A DOM element within which to query. Can also be a selector + * string in which case the first matching element will be used + * as context. If missing (or no element matches selector), falls + * back to `document`. + * + * @return {Element|null} + * The element that was found or null. + */ + var $ = createQuerier('querySelector'); + + /** + * Finds a all DOM elements matching `selector` within the optional + * `context` of another DOM element (defaulting to `document`). + * + * @param {string} selector + * A valid CSS selector, which will be passed to `querySelectorAll`. + * + * @param {Element|String} [context=document] + * A DOM element within which to query. Can also be a selector + * string in which case the first matching element will be used + * as context. If missing (or no element matches selector), falls + * back to `document`. + * + * @return {NodeList} + * A element list of elements that were found. Will be empty if none were found. + * + */ + var $$ = createQuerier('querySelectorAll'); + + var Dom = /*#__PURE__*/Object.freeze({ + isReal: isReal, + isEl: isEl, + isInFrame: isInFrame, + createEl: createEl, + textContent: textContent, + prependTo: prependTo, + hasClass: hasClass, + addClass: addClass, + removeClass: removeClass, + toggleClass: toggleClass, + setAttributes: setAttributes, + getAttributes: getAttributes, + getAttribute: getAttribute, + setAttribute: setAttribute, + removeAttribute: removeAttribute, + blockTextSelection: blockTextSelection, + unblockTextSelection: unblockTextSelection, + getBoundingClientRect: getBoundingClientRect, + findPosition: findPosition, + getPointerPosition: getPointerPosition, + isTextNode: isTextNode, + emptyEl: emptyEl, + normalizeContent: normalizeContent, + appendContent: appendContent, + insertContent: insertContent, + isSingleLeftClick: isSingleLeftClick, + $: $, + $$: $$ + }); + + /** + * @file guid.js + * @module guid + */ + + /** + * Unique ID for an element or function + * @type {Number} + */ + var _guid = 1; + + /** + * Get a unique auto-incrementing ID by number that has not been returned before. + * + * @return {number} + * A new unique ID. + */ + function newGUID() { + return _guid++; + } + + /** + * @file dom-data.js + * @module dom-data + */ + + /** + * Element Data Store. + * + * Allows for binding data to an element without putting it directly on the + * element. Ex. Event listeners are stored here. + * (also from jsninja.com, slightly modified and updated for closure compiler) + * + * @type {Object} + * @private + */ + var elData = {}; + + /* + * Unique attribute name to store an element's guid in + * + * @type {String} + * @constant + * @private + */ + var elIdAttr = 'vdata' + new Date().getTime(); + + /** + * Returns the cache object where data for an element is stored + * + * @param {Element} el + * Element to store data for. + * + * @return {Object} + * The cache object for that el that was passed in. + */ + function getData(el) { + var id = el[elIdAttr]; + + if (!id) { + id = el[elIdAttr] = newGUID(); + } + + if (!elData[id]) { + elData[id] = {}; + } + + return elData[id]; + } + + /** + * Returns whether or not an element has cached data + * + * @param {Element} el + * Check if this element has cached data. + * + * @return {boolean} + * - True if the DOM element has cached data. + * - False otherwise. + */ + function hasData(el) { + var id = el[elIdAttr]; + + if (!id) { + return false; + } + + return !!Object.getOwnPropertyNames(elData[id]).length; + } + + /** + * Delete data for the element from the cache and the guid attr from getElementById + * + * @param {Element} el + * Remove cached data for this element. + */ + function removeData(el) { + var id = el[elIdAttr]; + + if (!id) { + return; + } + + // Remove all stored data + delete elData[id]; + + // Remove the elIdAttr property from the DOM node + try { + delete el[elIdAttr]; + } catch (e) { + if (el.removeAttribute) { + el.removeAttribute(elIdAttr); + } else { + // IE doesn't appear to support removeAttribute on the document element + el[elIdAttr] = null; + } + } + } + + /** + * @file events.js. An Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/) + * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible) + * This should work very similarly to jQuery's events, however it's based off the book version which isn't as + * robust as jquery's, so there's probably some differences. + * + * @module events + */ + + /** + * Clean up the listener cache and dispatchers + * + * @param {Element|Object} elem + * Element to clean up + * + * @param {string} type + * Type of event to clean up + */ + function _cleanUpEvents(elem, type) { + var data = getData(elem); + + // Remove the events of a particular type if there are none left + if (data.handlers[type].length === 0) { + delete data.handlers[type]; + // data.handlers[type] = null; + // Setting to null was causing an error with data.handlers + + // Remove the meta-handler from the element + if (elem.removeEventListener) { + elem.removeEventListener(type, data.dispatcher, false); + } else if (elem.detachEvent) { + elem.detachEvent('on' + type, data.dispatcher); + } + } + + // Remove the events object if there are no types left + if (Object.getOwnPropertyNames(data.handlers).length <= 0) { + delete data.handlers; + delete data.dispatcher; + delete data.disabled; + } + + // Finally remove the element data if there is no data left + if (Object.getOwnPropertyNames(data).length === 0) { + removeData(elem); + } + } + + /** + * Loops through an array of event types and calls the requested method for each type. + * + * @param {Function} fn + * The event method we want to use. + * + * @param {Element|Object} elem + * Element or object to bind listeners to + * + * @param {string} type + * Type of event to bind to. + * + * @param {EventTarget~EventListener} callback + * Event listener. + */ + function _handleMultipleEvents(fn, elem, types, callback) { + types.forEach(function (type) { + // Call the event method for each one of the types + fn(elem, type, callback); + }); + } + + /** + * Fix a native event to have standard property values + * + * @param {Object} event + * Event object to fix. + * + * @return {Object} + * Fixed event object. + */ + function fixEvent(event) { + + function returnTrue() { + return true; + } + + function returnFalse() { + return false; + } + + // Test if fixing up is needed + // Used to check if !event.stopPropagation instead of isPropagationStopped + // But native events return true for stopPropagation, but don't have + // other expected methods like isPropagationStopped. Seems to be a problem + // with the Javascript Ninja code. So we're just overriding all events now. + if (!event || !event.isPropagationStopped) { + var old = event || window_1.event; + + event = {}; + // Clone the old object so that we can modify the values event = {}; + // IE8 Doesn't like when you mess with native event properties + // Firefox returns false for event.hasOwnProperty('type') and other props + // which makes copying more difficult. + // TODO: Probably best to create a whitelist of event props + for (var key in old) { + // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y + // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation + // and webkitMovementX/Y + if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') { + // Chrome 32+ warns if you try to copy deprecated returnValue, but + // we still want to if preventDefault isn't supported (IE8). + if (!(key === 'returnValue' && old.preventDefault)) { + event[key] = old[key]; + } + } + } + + // The event occurred on this element + if (!event.target) { + event.target = event.srcElement || document_1; + } + + // Handle which other element the event is related to + if (!event.relatedTarget) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Stop the default browser action + event.preventDefault = function () { + if (old.preventDefault) { + old.preventDefault(); + } + event.returnValue = false; + old.returnValue = false; + event.defaultPrevented = true; + }; + + event.defaultPrevented = false; + + // Stop the event from bubbling + event.stopPropagation = function () { + if (old.stopPropagation) { + old.stopPropagation(); + } + event.cancelBubble = true; + old.cancelBubble = true; + event.isPropagationStopped = returnTrue; + }; + + event.isPropagationStopped = returnFalse; + + // Stop the event from bubbling and executing other handlers + event.stopImmediatePropagation = function () { + if (old.stopImmediatePropagation) { + old.stopImmediatePropagation(); + } + event.isImmediatePropagationStopped = returnTrue; + event.stopPropagation(); + }; + + event.isImmediatePropagationStopped = returnFalse; + + // Handle mouse position + if (event.clientX !== null && event.clientX !== undefined) { + var doc = document_1.documentElement; + var body = document_1.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Handle key presses + event.which = event.charCode || event.keyCode; + + // Fix button for mouse clicks: + // 0 == left; 1 == middle; 2 == right + if (event.button !== null && event.button !== undefined) { + + // The following is disabled because it does not pass videojs-standard + // and... yikes. + /* eslint-disable */ + event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0; + /* eslint-enable */ + } + } + + // Returns fixed-up instance + return event; + } + + /** + * Whether passive event listeners are supported + */ + var _supportsPassive = false; + + (function () { + try { + var opts = Object.defineProperty({}, 'passive', { + get: function get() { + _supportsPassive = true; + } + }); + + window_1.addEventListener('test', null, opts); + window_1.removeEventListener('test', null, opts); + } catch (e) { + // disregard + } + })(); + + /** + * Touch events Chrome expects to be passive + */ + var passiveEvents = ['touchstart', 'touchmove']; + + /** + * Add an event listener to element + * It stores the handler function in a separate cache object + * and adds a generic handler to the element's event, + * along with a unique id (guid) to the element. + * + * @param {Element|Object} elem + * Element or object to bind listeners to + * + * @param {string|string[]} type + * Type of event to bind to. + * + * @param {EventTarget~EventListener} fn + * Event listener. + */ + function on(elem, type, fn) { + if (Array.isArray(type)) { + return _handleMultipleEvents(on, elem, type, fn); + } + + var data = getData(elem); + + // We need a place to store all our handler data + if (!data.handlers) { + data.handlers = {}; + } + + if (!data.handlers[type]) { + data.handlers[type] = []; + } + + if (!fn.guid) { + fn.guid = newGUID(); + } + + data.handlers[type].push(fn); + + if (!data.dispatcher) { + data.disabled = false; + + data.dispatcher = function (event, hash) { + + if (data.disabled) { + return; + } + + event = fixEvent(event); + + var handlers = data.handlers[event.type]; + + if (handlers) { + // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off. + var handlersCopy = handlers.slice(0); + + for (var m = 0, n = handlersCopy.length; m < n; m++) { + if (event.isImmediatePropagationStopped()) { + break; + } else { + try { + handlersCopy[m].call(elem, event, hash); + } catch (e) { + log$1.error(e); + } + } + } + } + }; + } + + if (data.handlers[type].length === 1) { + if (elem.addEventListener) { + var options = false; + + if (_supportsPassive && passiveEvents.indexOf(type) > -1) { + options = {passive: true}; + } + elem.addEventListener(type, data.dispatcher, options); + } else if (elem.attachEvent) { + elem.attachEvent('on' + type, data.dispatcher); + } + } + } + + /** + * Removes event listeners from an element + * + * @param {Element|Object} elem + * Object to remove listeners from. + * + * @param {string|string[]} [type] + * Type of listener to remove. Don't include to remove all events from element. + * + * @param {EventTarget~EventListener} [fn] + * Specific listener to remove. Don't include to remove listeners for an event + * type. + */ + function off(elem, type, fn) { + // Don't want to add a cache object through getElData if not needed + if (!hasData(elem)) { + return; + } + + var data = getData(elem); + + // If no events exist, nothing to unbind + if (!data.handlers) { + return; + } + + if (Array.isArray(type)) { + return _handleMultipleEvents(off, elem, type, fn); + } + + // Utility function + var removeType = function removeType(el, t) { + data.handlers[t] = []; + _cleanUpEvents(el, t); + }; + + // Are we removing all bound events? + if (type === undefined) { + for (var t in data.handlers) { + if (Object.prototype.hasOwnProperty.call(data.handlers || {}, t)) { + removeType(elem, t); + } + } + return; + } + + var handlers = data.handlers[type]; + + // If no handlers exist, nothing to unbind + if (!handlers) { + return; + } + + // If no listener was provided, remove all listeners for type + if (!fn) { + removeType(elem, type); + return; + } + + // We're only removing a single handler + if (fn.guid) { + for (var n = 0; n < handlers.length; n++) { + if (handlers[n].guid === fn.guid) { + handlers.splice(n--, 1); + } + } + } + + _cleanUpEvents(elem, type); + } + + /** + * Trigger an event for an element + * + * @param {Element|Object} elem + * Element to trigger an event on + * + * @param {EventTarget~Event|string} event + * A string (the type) or an event object with a type attribute + * + * @param {Object} [hash] + * data hash to pass along with the event + * + * @return {boolean|undefined} + * - Returns the opposite of `defaultPrevented` if default was prevented + * - Otherwise returns undefined + */ + function trigger(elem, event, hash) { + // Fetches element data and a reference to the parent (for bubbling). + // Don't want to add a data object to cache for every parent, + // so checking hasElData first. + var elemData = hasData(elem) ? getData(elem) : {}; + var parent = elem.parentNode || elem.ownerDocument; + // type = event.type || event, + // handler; + + // If an event name was passed as a string, creates an event out of it + if (typeof event === 'string') { + event = {type: event, target: elem}; + } else if (!event.target) { + event.target = elem; + } + + // Normalizes the event properties. + event = fixEvent(event); + + // If the passed element has a dispatcher, executes the established handlers. + if (elemData.dispatcher) { + elemData.dispatcher.call(elem, event, hash); + } + + // Unless explicitly stopped or the event does not bubble (e.g. media events) + // recursively calls this function to bubble the event up the DOM. + if (parent && !event.isPropagationStopped() && event.bubbles === true) { + trigger.call(null, parent, event, hash); + + // If at the top of the DOM, triggers the default action unless disabled. + } else if (!parent && !event.defaultPrevented) { + var targetData = getData(event.target); + + // Checks if the target has a default action for this event. + if (event.target[event.type]) { + // Temporarily disables event dispatching on the target as we have already executed the handler. + targetData.disabled = true; + // Executes the default action. + if (typeof event.target[event.type] === 'function') { + event.target[event.type](); + } + // Re-enables event dispatching. + targetData.disabled = false; + } + } + + // Inform the triggerer if the default was prevented by returning false + return !event.defaultPrevented; + } + + /** + * Trigger a listener only once for an event + * + * @param {Element|Object} elem + * Element or object to bind to. + * + * @param {string|string[]} type + * Name/type of event + * + * @param {Event~EventListener} fn + * Event Listener function + */ + function one(elem, type, fn) { + if (Array.isArray(type)) { + return _handleMultipleEvents(one, elem, type, fn); + } + var func = function func() { + off(elem, type, func); + fn.apply(this, arguments); + }; + + // copy the guid to the new function so it can removed using the original function's ID + func.guid = fn.guid = fn.guid || newGUID(); + on(elem, type, func); + } + + var Events = /*#__PURE__*/Object.freeze({ + fixEvent: fixEvent, + on: on, + off: off, + trigger: trigger, + one: one + }); + + /** + * @file setup.js - Functions for setting up a player without + * user interaction based on the data-setup `attribute` of the video tag. + * + * @module setup + */ + + var _windowLoaded = false; + var videojs = void 0; + + /** + * Set up any tags that have a data-setup `attribute` when the player is started. + */ + var autoSetup = function autoSetup() { + + // Protect against breakage in non-browser environments and check global autoSetup option. + if (!isReal() || videojs.options.autoSetup === false) { + return; + } + + var vids = Array.prototype.slice.call(document_1.getElementsByTagName('video')); + var audios = Array.prototype.slice.call(document_1.getElementsByTagName('audio')); + var divs = Array.prototype.slice.call(document_1.getElementsByTagName('video-js')); + var mediaEls = vids.concat(audios, divs); + + // Check if any media elements exist + if (mediaEls && mediaEls.length > 0) { + + for (var i = 0, e = mediaEls.length; i < e; i++) { + var mediaEl = mediaEls[i]; + + // Check if element exists, has getAttribute func. + if (mediaEl && mediaEl.getAttribute) { + + // Make sure this player hasn't already been set up. + if (mediaEl.player === undefined) { + var options = mediaEl.getAttribute('data-setup'); + + // Check if data-setup attr exists. + // We only auto-setup if they've added the data-setup attr. + if (options !== null) { + // Create new video.js instance. + videojs(mediaEl); + } + } + + // If getAttribute isn't defined, we need to wait for the DOM. + } else { + autoSetupTimeout(1); + break; + } + } + + // No videos were found, so keep looping unless page is finished loading. + } else if (!_windowLoaded) { + autoSetupTimeout(1); + } + }; + + /** + * Wait until the page is loaded before running autoSetup. This will be called in + * autoSetup if `hasLoaded` returns false. + * + * @param {number} wait + * How long to wait in ms + * + * @param {module:videojs} [vjs] + * The videojs library function + */ + function autoSetupTimeout(wait, vjs) { + if (vjs) { + videojs = vjs; + } + + window_1.setTimeout(autoSetup, wait); + } + + if (isReal() && document_1.readyState === 'complete') { + _windowLoaded = true; + } else { + /** + * Listen for the load event on window, and set _windowLoaded to true. + * + * @listens load + */ + one(window_1, 'load', function () { + _windowLoaded = true; + }); + } + + /** + * @file stylesheet.js + * @module stylesheet + */ + + /** + * Create a DOM syle element given a className for it. + * + * @param {string} className + * The className to add to the created style element. + * + * @return {Element} + * The element that was created. + */ + var createStyleElement = function createStyleElement(className) { + var style = document_1.createElement('style'); + + style.className = className; + + return style; + }; + + /** + * Add text to a DOM element. + * + * @param {Element} el + * The Element to add text content to. + * + * @param {string} content + * The text to add to the element. + */ + var setTextContent = function setTextContent(el, content) { + if (el.styleSheet) { + el.styleSheet.cssText = content; + } else { + el.textContent = content; + } + }; + + /** + * @file fn.js + * @module fn + */ + + /** + * Bind (a.k.a proxy or Context). A simple method for changing the context of a function + * It also stores a unique id on the function so it can be easily removed from events. + * + * @param {Mixed} context + * The object to bind as scope. + * + * @param {Function} fn + * The function to be bound to a scope. + * + * @param {number} [uid] + * An optional unique ID for the function to be set + * + * @return {Function} + * The new function that will be bound into the context given + */ + var bind = function bind(context, fn, uid) { + // Make sure the function has a unique ID + if (!fn.guid) { + fn.guid = newGUID(); + } + + // Create the new function that changes the context + var bound = function bound() { + return fn.apply(context, arguments); + }; + + // Allow for the ability to individualize this function + // Needed in the case where multiple objects might share the same prototype + // IF both items add an event listener with the same function, then you try to remove just one + // it will remove both because they both have the same guid. + // when using this, you need to use the bind method when you remove the listener as well. + // currently used in text tracks + bound.guid = uid ? uid + '_' + fn.guid : fn.guid; + + return bound; + }; + + /** + * Wraps the given function, `fn`, with a new function that only invokes `fn` + * at most once per every `wait` milliseconds. + * + * @param {Function} fn + * The function to be throttled. + * + * @param {Number} wait + * The number of milliseconds by which to throttle. + * + * @return {Function} + */ + var throttle = function throttle(fn, wait) { + var last = Date.now(); + + var throttled = function throttled() { + var now = Date.now(); + + if (now - last >= wait) { + fn.apply(undefined, arguments); + last = now; + } + }; + + return throttled; + }; + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. + * + * Inspired by lodash and underscore implementations. + * + * @param {Function} func + * The function to wrap with debounce behavior. + * + * @param {number} wait + * The number of milliseconds to wait after the last invocation. + * + * @param {boolean} [immediate] + * Whether or not to invoke the function immediately upon creation. + * + * @param {Object} [context=window] + * The "context" in which the debounced function should debounce. For + * example, if this function should be tied to a Video.js player, + * the player can be passed here. Alternatively, defaults to the + * global `window` object. + * + * @return {Function} + * A debounced function. + */ + var debounce = function debounce(func, wait, immediate) { + var context = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : window_1; + + var timeout = void 0; + + /* eslint-disable consistent-this */ + return function () { + var self = this; + var args = arguments; + + var _later = function later() { + timeout = null; + _later = null; + if (!immediate) { + func.apply(self, args); + } + }; + + if (!timeout && immediate) { + func.apply(self, args); + } + + context.clearTimeout(timeout); + timeout = context.setTimeout(_later, wait); + }; + /* eslint-enable consistent-this */ + }; + + /** + * @file src/js/event-target.js + */ + + /** + * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It + * adds shorthand functions that wrap around lengthy functions. For example: + * the `on` function is a wrapper around `addEventListener`. + * + * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget} + * @class EventTarget + */ + var EventTarget = function EventTarget() { + }; + + /** + * A Custom DOM event. + * + * @typedef {Object} EventTarget~Event + * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent} + */ + + /** + * All event listeners should follow the following format. + * + * @callback EventTarget~EventListener + * @this {EventTarget} + * + * @param {EventTarget~Event} event + * the event that triggered this function + * + * @param {Object} [hash] + * hash of data sent during the event + */ + + /** + * An object containing event names as keys and booleans as values. + * + * > NOTE: If an event name is set to a true value here {@link EventTarget#trigger} + * will have extra functionality. See that function for more information. + * + * @property EventTarget.prototype.allowedEvents_ + * @private + */ + EventTarget.prototype.allowedEvents_ = {}; + + /** + * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a + * function that will get called when an event with a certain name gets triggered. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {EventTarget~EventListener} fn + * The function to call with `EventTarget`s + */ + EventTarget.prototype.on = function (type, fn) { + // Remove the addEventListener alias before calling Events.on + // so we don't get into an infinite type loop + var ael = this.addEventListener; + + this.addEventListener = function () { + }; + on(this, type, fn); + this.addEventListener = ael; + }; + + /** + * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic + * the standard DOM API. + * + * @function + * @see {@link EventTarget#on} + */ + EventTarget.prototype.addEventListener = EventTarget.prototype.on; + + /** + * Removes an `event listener` for a specific event from an instance of `EventTarget`. + * This makes it so that the `event listener` will no longer get called when the + * named event happens. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {EventTarget~EventListener} fn + * The function to remove. + */ + EventTarget.prototype.off = function (type, fn) { + off(this, type, fn); + }; + + /** + * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic + * the standard DOM API. + * + * @function + * @see {@link EventTarget#off} + */ + EventTarget.prototype.removeEventListener = EventTarget.prototype.off; + + /** + * This function will add an `event listener` that gets triggered only once. After the + * first trigger it will get removed. This is like adding an `event listener` + * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {EventTarget~EventListener} fn + * The function to be called once for each event name. + */ + EventTarget.prototype.one = function (type, fn) { + // Remove the addEventListener alialing Events.on + // so we don't get into an infinite type loop + var ael = this.addEventListener; + + this.addEventListener = function () { + }; + one(this, type, fn); + this.addEventListener = ael; + }; + + /** + * This function causes an event to happen. This will then cause any `event listeners` + * that are waiting for that event, to get called. If there are no `event listeners` + * for an event then nothing will happen. + * + * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`. + * Trigger will also call the `on` + `uppercaseEventName` function. + * + * Example: + * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call + * `onClick` if it exists. + * + * @param {string|EventTarget~Event|Object} event + * The name of the event, an `Event`, or an object with a key of type set to + * an event name. + */ + EventTarget.prototype.trigger = function (event) { + var type = event.type || event; + + if (typeof event === 'string') { + event = {type: type}; + } + event = fixEvent(event); + + if (this.allowedEvents_[type] && this['on' + type]) { + this['on' + type](event); + } + + trigger(this, event); + }; + + /** + * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic + * the standard DOM API. + * + * @function + * @see {@link EventTarget#trigger} + */ + EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger; + + /** + * @file mixins/evented.js + * @module evented + */ + + /** + * Returns whether or not an object has had the evented mixin applied. + * + * @param {Object} object + * An object to test. + * + * @return {boolean} + * Whether or not the object appears to be evented. + */ + var isEvented = function isEvented(object) { + return object instanceof EventTarget || !!object.eventBusEl_ && ['on', 'one', 'off', 'trigger'].every(function (k) { + return typeof object[k] === 'function'; + }); + }; + + /** + * Whether a value is a valid event type - non-empty string or array. + * + * @private + * @param {string|Array} type + * The type value to test. + * + * @return {boolean} + * Whether or not the type is a valid event type. + */ + var isValidEventType = function isValidEventType(type) { + return ( + // The regex here verifies that the `type` contains at least one non- + // whitespace character. + typeof type === 'string' && /\S/.test(type) || Array.isArray(type) && !!type.length + ); + }; + + /** + * Validates a value to determine if it is a valid event target. Throws if not. + * + * @private + * @throws {Error} + * If the target does not appear to be a valid event target. + * + * @param {Object} target + * The object to test. + */ + var validateTarget = function validateTarget(target) { + if (!target.nodeName && !isEvented(target)) { + throw new Error('Invalid target; must be a DOM node or evented object.'); + } + }; + + /** + * Validates a value to determine if it is a valid event target. Throws if not. + * + * @private + * @throws {Error} + * If the type does not appear to be a valid event type. + * + * @param {string|Array} type + * The type to test. + */ + var validateEventType = function validateEventType(type) { + if (!isValidEventType(type)) { + throw new Error('Invalid event type; must be a non-empty string or array.'); + } + }; + + /** + * Validates a value to determine if it is a valid listener. Throws if not. + * + * @private + * @throws {Error} + * If the listener is not a function. + * + * @param {Function} listener + * The listener to test. + */ + var validateListener = function validateListener(listener) { + if (typeof listener !== 'function') { + throw new Error('Invalid listener; must be a function.'); + } + }; + + /** + * Takes an array of arguments given to `on()` or `one()`, validates them, and + * normalizes them into an object. + * + * @private + * @param {Object} self + * The evented object on which `on()` or `one()` was called. This + * object will be bound as the `this` value for the listener. + * + * @param {Array} args + * An array of arguments passed to `on()` or `one()`. + * + * @return {Object} + * An object containing useful values for `on()` or `one()` calls. + */ + var normalizeListenArgs = function normalizeListenArgs(self, args) { + + // If the number of arguments is less than 3, the target is always the + // evented object itself. + var isTargetingSelf = args.length < 3 || args[0] === self || args[0] === self.eventBusEl_; + var target = void 0; + var type = void 0; + var listener = void 0; + + if (isTargetingSelf) { + target = self.eventBusEl_; + + // Deal with cases where we got 3 arguments, but we are still listening to + // the evented object itself. + if (args.length >= 3) { + args.shift(); + } + + type = args[0]; + listener = args[1]; + } else { + target = args[0]; + type = args[1]; + listener = args[2]; + } + + validateTarget(target); + validateEventType(type); + validateListener(listener); + + listener = bind(self, listener); + + return {isTargetingSelf: isTargetingSelf, target: target, type: type, listener: listener}; + }; + + /** + * Adds the listener to the event type(s) on the target, normalizing for + * the type of target. + * + * @private + * @param {Element|Object} target + * A DOM node or evented object. + * + * @param {string} method + * The event binding method to use ("on" or "one"). + * + * @param {string|Array} type + * One or more event type(s). + * + * @param {Function} listener + * A listener function. + */ + var listen = function listen(target, method, type, listener) { + validateTarget(target); + + if (target.nodeName) { + Events[method](target, type, listener); + } else { + target[method](type, listener); + } + }; + + /** + * Contains methods that provide event capabilities to an object which is passed + * to {@link module:evented|evented}. + * + * @mixin EventedMixin + */ + var EventedMixin = { + + /** + * Add a listener to an event (or events) on this object or another evented + * object. + * + * @param {string|Array|Element|Object} targetOrType + * If this is a string or array, it represents the event type(s) + * that will trigger the listener. + * + * Another evented object can be passed here instead, which will + * cause the listener to listen for events on _that_ object. + * + * In either case, the listener's `this` value will be bound to + * this object. + * + * @param {string|Array|Function} typeOrListener + * If the first argument was a string or array, this should be the + * listener function. Otherwise, this is a string or array of event + * type(s). + * + * @param {Function} [listener] + * If the first argument was another evented object, this will be + * the listener function. + */ + on: function on$$1() { + var _this = this; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + var _normalizeListenArgs = normalizeListenArgs(this, args), + isTargetingSelf = _normalizeListenArgs.isTargetingSelf, + target = _normalizeListenArgs.target, + type = _normalizeListenArgs.type, + listener = _normalizeListenArgs.listener; + + listen(target, 'on', type, listener); + + // If this object is listening to another evented object. + if (!isTargetingSelf) { + + // If this object is disposed, remove the listener. + var removeListenerOnDispose = function removeListenerOnDispose() { + return _this.off(target, type, listener); + }; + + // Use the same function ID as the listener so we can remove it later it + // using the ID of the original listener. + removeListenerOnDispose.guid = listener.guid; + + // Add a listener to the target's dispose event as well. This ensures + // that if the target is disposed BEFORE this object, we remove the + // removal listener that was just added. Otherwise, we create a memory leak. + var removeRemoverOnTargetDispose = function removeRemoverOnTargetDispose() { + return _this.off('dispose', removeListenerOnDispose); + }; + + // Use the same function ID as the listener so we can remove it later + // it using the ID of the original listener. + removeRemoverOnTargetDispose.guid = listener.guid; + + listen(this, 'on', 'dispose', removeListenerOnDispose); + listen(target, 'on', 'dispose', removeRemoverOnTargetDispose); + } + }, + + + /** + * Add a listener to an event (or events) on this object or another evented + * object. The listener will only be called once and then removed. + * + * @param {string|Array|Element|Object} targetOrType + * If this is a string or array, it represents the event type(s) + * that will trigger the listener. + * + * Another evented object can be passed here instead, which will + * cause the listener to listen for events on _that_ object. + * + * In either case, the listener's `this` value will be bound to + * this object. + * + * @param {string|Array|Function} typeOrListener + * If the first argument was a string or array, this should be the + * listener function. Otherwise, this is a string or array of event + * type(s). + * + * @param {Function} [listener] + * If the first argument was another evented object, this will be + * the listener function. + */ + one: function one$$1() { + var _this2 = this; + + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + var _normalizeListenArgs2 = normalizeListenArgs(this, args), + isTargetingSelf = _normalizeListenArgs2.isTargetingSelf, + target = _normalizeListenArgs2.target, + type = _normalizeListenArgs2.type, + listener = _normalizeListenArgs2.listener; + + // Targeting this evented object. + + + if (isTargetingSelf) { + listen(target, 'one', type, listener); + + // Targeting another evented object. + } else { + var wrapper = function wrapper() { + for (var _len3 = arguments.length, largs = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + largs[_key3] = arguments[_key3]; + } + + _this2.off(target, type, wrapper); + listener.apply(null, largs); + }; + + // Use the same function ID as the listener so we can remove it later + // it using the ID of the original listener. + wrapper.guid = listener.guid; + listen(target, 'one', type, wrapper); + } + }, + + + /** + * Removes listener(s) from event(s) on an evented object. + * + * @param {string|Array|Element|Object} [targetOrType] + * If this is a string or array, it represents the event type(s). + * + * Another evented object can be passed here instead, in which case + * ALL 3 arguments are _required_. + * + * @param {string|Array|Function} [typeOrListener] + * If the first argument was a string or array, this may be the + * listener function. Otherwise, this is a string or array of event + * type(s). + * + * @param {Function} [listener] + * If the first argument was another evented object, this will be + * the listener function; otherwise, _all_ listeners bound to the + * event type(s) will be removed. + */ + off: function off$$1(targetOrType, typeOrListener, listener) { + + // Targeting this evented object. + if (!targetOrType || isValidEventType(targetOrType)) { + off(this.eventBusEl_, targetOrType, typeOrListener); + + // Targeting another evented object. + } else { + var target = targetOrType; + var type = typeOrListener; + + // Fail fast and in a meaningful way! + validateTarget(target); + validateEventType(type); + validateListener(listener); + + // Ensure there's at least a guid, even if the function hasn't been used + listener = bind(this, listener); + + // Remove the dispose listener on this evented object, which was given + // the same guid as the event listener in on(). + this.off('dispose', listener); + + if (target.nodeName) { + off(target, type, listener); + off(target, 'dispose', listener); + } else if (isEvented(target)) { + target.off(type, listener); + target.off('dispose', listener); + } + } + }, + + + /** + * Fire an event on this evented object, causing its listeners to be called. + * + * @param {string|Object} event + * An event type or an object with a type property. + * + * @param {Object} [hash] + * An additional object to pass along to listeners. + * + * @returns {boolean} + * Whether or not the default behavior was prevented. + */ + trigger: function trigger$$1(event, hash) { + return trigger(this.eventBusEl_, event, hash); + } + }; + + /** + * Applies {@link module:evented~EventedMixin|EventedMixin} to a target object. + * + * @param {Object} target + * The object to which to add event methods. + * + * @param {Object} [options={}] + * Options for customizing the mixin behavior. + * + * @param {String} [options.eventBusKey] + * By default, adds a `eventBusEl_` DOM element to the target object, + * which is used as an event bus. If the target object already has a + * DOM element that should be used, pass its key here. + * + * @return {Object} + * The target object. + */ + function evented(target) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var eventBusKey = options.eventBusKey; + + // Set or create the eventBusEl_. + + if (eventBusKey) { + if (!target[eventBusKey].nodeName) { + throw new Error('The eventBusKey "' + eventBusKey + '" does not refer to an element.'); + } + target.eventBusEl_ = target[eventBusKey]; + } else { + target.eventBusEl_ = createEl('span', {className: 'vjs-event-bus'}); + } + + assign(target, EventedMixin); + + // When any evented object is disposed, it removes all its listeners. + target.on('dispose', function () { + target.off(); + window_1.setTimeout(function () { + target.eventBusEl_ = null; + }, 0); + }); + + return target; + } + + /** + * @file mixins/stateful.js + * @module stateful + */ + + /** + * Contains methods that provide statefulness to an object which is passed + * to {@link module:stateful}. + * + * @mixin StatefulMixin + */ + var StatefulMixin = { + + /** + * A hash containing arbitrary keys and values representing the state of + * the object. + * + * @type {Object} + */ + state: {}, + + /** + * Set the state of an object by mutating its + * {@link module:stateful~StatefulMixin.state|state} object in place. + * + * @fires module:stateful~StatefulMixin#statechanged + * @param {Object|Function} stateUpdates + * A new set of properties to shallow-merge into the plugin state. + * Can be a plain object or a function returning a plain object. + * + * @returns {Object|undefined} + * An object containing changes that occurred. If no changes + * occurred, returns `undefined`. + */ + setState: function setState(stateUpdates) { + var _this = this; + + // Support providing the `stateUpdates` state as a function. + if (typeof stateUpdates === 'function') { + stateUpdates = stateUpdates(); + } + + var changes = void 0; + + each(stateUpdates, function (value, key) { + + // Record the change if the value is different from what's in the + // current state. + if (_this.state[key] !== value) { + changes = changes || {}; + changes[key] = { + from: _this.state[key], + to: value + }; + } + + _this.state[key] = value; + }); + + // Only trigger "statechange" if there were changes AND we have a trigger + // function. This allows us to not require that the target object be an + // evented object. + if (changes && isEvented(this)) { + + /** + * An event triggered on an object that is both + * {@link module:stateful|stateful} and {@link module:evented|evented} + * indicating that its state has changed. + * + * @event module:stateful~StatefulMixin#statechanged + * @type {Object} + * @property {Object} changes + * A hash containing the properties that were changed and + * the values they were changed `from` and `to`. + */ + this.trigger({ + changes: changes, + type: 'statechanged' + }); + } + + return changes; + } + }; + + /** + * Applies {@link module:stateful~StatefulMixin|StatefulMixin} to a target + * object. + * + * If the target object is {@link module:evented|evented} and has a + * `handleStateChanged` method, that method will be automatically bound to the + * `statechanged` event on itself. + * + * @param {Object} target + * The object to be made stateful. + * + * @param {Object} [defaultState] + * A default set of properties to populate the newly-stateful object's + * `state` property. + * + * @returns {Object} + * Returns the `target`. + */ + function stateful(target, defaultState) { + assign(target, StatefulMixin); + + // This happens after the mixing-in because we need to replace the `state` + // added in that step. + target.state = assign({}, target.state, defaultState); + + // Auto-bind the `handleStateChanged` method of the target object if it exists. + if (typeof target.handleStateChanged === 'function' && isEvented(target)) { + target.on('statechanged', target.handleStateChanged); + } + + return target; + } + + /** + * @file to-title-case.js + * @module to-title-case + */ + + /** + * Uppercase the first letter of a string. + * + * @param {string} string + * String to be uppercased + * + * @return {string} + * The string with an uppercased first letter + */ + function toTitleCase(string) { + if (typeof string !== 'string') { + return string; + } + + return string.charAt(0).toUpperCase() + string.slice(1); + } + + /** + * Compares the TitleCase versions of the two strings for equality. + * + * @param {string} str1 + * The first string to compare + * + * @param {string} str2 + * The second string to compare + * + * @return {boolean} + * Whether the TitleCase versions of the strings are equal + */ + function titleCaseEquals(str1, str2) { + return toTitleCase(str1) === toTitleCase(str2); + } + + /** + * @file merge-options.js + * @module merge-options + */ + + /** + * Deep-merge one or more options objects, recursively merging **only** plain + * object properties. + * + * @param {Object[]} sources + * One or more objects to merge into a new object. + * + * @returns {Object} + * A new object that is the merged result of all sources. + */ + function mergeOptions() { + var result = {}; + + for (var _len = arguments.length, sources = Array(_len), _key = 0; _key < _len; _key++) { + sources[_key] = arguments[_key]; + } + + sources.forEach(function (source) { + if (!source) { + return; + } + + each(source, function (value, key) { + if (!isPlain(value)) { + result[key] = value; + return; + } + + if (!isPlain(result[key])) { + result[key] = {}; + } + + result[key] = mergeOptions(result[key], value); + }); + }); + + return result; + } + + /** + * Player Component - Base class for all UI objects + * + * @file component.js + */ + + /** + * Base class for all UI Components. + * Components are UI objects which represent both a javascript object and an element + * in the DOM. They can be children of other components, and can have + * children themselves. + * + * Components can also use methods from {@link EventTarget} + */ + + var Component = function () { + + /** + * A callback that is called when a component is ready. Does not have any + * paramters and any callback value will be ignored. + * + * @callback Component~ReadyCallback + * @this Component + */ + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Object[]} [options.children] + * An array of children objects to intialize this component with. Children objects have + * a name property that will be used if more than one component of the same type needs to be + * added. + * + * @param {Component~ReadyCallback} [ready] + * Function that gets called when the `Component` is ready. + */ + function Component(player, options, ready) { + classCallCheck(this, Component); + + + // The component might be the player itself and we can't pass `this` to super + if (!player && this.play) { + this.player_ = player = this; // eslint-disable-line + } else { + this.player_ = player; + } + + // Make a copy of prototype.options_ to protect against overriding defaults + this.options_ = mergeOptions({}, this.options_); + + // Updated options with supplied options + options = this.options_ = mergeOptions(this.options_, options); + + // Get ID from options or options element if one is supplied + this.id_ = options.id || options.el && options.el.id; + + // If there was no ID from the options, generate one + if (!this.id_) { + // Don't require the player ID function in the case of mock players + var id = player && player.id && player.id() || 'no_player'; + + this.id_ = id + '_component_' + newGUID(); + } + + this.name_ = options.name || null; + + // Create element if one wasn't provided in options + if (options.el) { + this.el_ = options.el; + } else if (options.createEl !== false) { + this.el_ = this.createEl(); + } + + // if evented is anything except false, we want to mixin in evented + if (options.evented !== false) { + // Make this an evented object and use `el_`, if available, as its event bus + evented(this, {eventBusKey: this.el_ ? 'el_' : null}); + } + stateful(this, this.constructor.defaultState); + + this.children_ = []; + this.childIndex_ = {}; + this.childNameIndex_ = {}; + + // Add any child components in options + if (options.initChildren !== false) { + this.initChildren(); + } + + this.ready(ready); + // Don't want to trigger ready here or it will before init is actually + // finished for all children that run this constructor + + if (options.reportTouchActivity !== false) { + this.enableTouchActivity(); + } + } + + /** + * Dispose of the `Component` and all child components. + * + * @fires Component#dispose + */ + + + Component.prototype.dispose = function dispose() { + + /** + * Triggered when a `Component` is disposed. + * + * @event Component#dispose + * @type {EventTarget~Event} + * + * @property {boolean} [bubbles=false] + * set to false so that the close event does not + * bubble up + */ + this.trigger({type: 'dispose', bubbles: false}); + + // Dispose all children. + if (this.children_) { + for (var i = this.children_.length - 1; i >= 0; i--) { + if (this.children_[i].dispose) { + this.children_[i].dispose(); + } + } + } + + // Delete child references + this.children_ = null; + this.childIndex_ = null; + this.childNameIndex_ = null; + + if (this.el_) { + // Remove element from DOM + if (this.el_.parentNode) { + this.el_.parentNode.removeChild(this.el_); + } + + removeData(this.el_); + this.el_ = null; + } + + // remove reference to the player after disposing of the element + this.player_ = null; + }; + + /** + * Return the {@link Player} that the `Component` has attached to. + * + * @return {Player} + * The player that this `Component` has attached to. + */ + + + Component.prototype.player = function player() { + return this.player_; + }; + + /** + * Deep merge of options objects with new options. + * > Note: When both `obj` and `options` contain properties whose values are objects. + * The two properties get merged using {@link module:mergeOptions} + * + * @param {Object} obj + * The object that contains new options. + * + * @return {Object} + * A new object of `this.options_` and `obj` merged together. + * + * @deprecated since version 5 + */ + + + Component.prototype.options = function options(obj) { + log$1.warn('this.options() has been deprecated and will be moved to the constructor in 6.0'); + + if (!obj) { + return this.options_; + } + + this.options_ = mergeOptions(this.options_, obj); + return this.options_; + }; + + /** + * Get the `Component`s DOM element + * + * @return {Element} + * The DOM element for this `Component`. + */ + + + Component.prototype.el = function el() { + return this.el_; + }; + + /** + * Create the `Component`s DOM element. + * + * @param {string} [tagName] + * Element's DOM node type. e.g. 'div' + * + * @param {Object} [properties] + * An object of properties that should be set. + * + * @param {Object} [attributes] + * An object of attributes that should be set. + * + * @return {Element} + * The element that gets created. + */ + + + Component.prototype.createEl = function createEl$$1(tagName, properties, attributes) { + return createEl(tagName, properties, attributes); + }; + + /** + * Localize a string given the string in english. + * + * If tokens are provided, it'll try and run a simple token replacement on the provided string. + * The tokens it looks for look like `{1}` with the index being 1-indexed into the tokens array. + * + * If a `defaultValue` is provided, it'll use that over `string`, + * if a value isn't found in provided language files. + * This is useful if you want to have a descriptive key for token replacement + * but have a succinct localized string and not require `en.json` to be included. + * + * Currently, it is used for the progress bar timing. + * ```js + * { + * "progress bar timing: currentTime={1} duration={2}": "{1} of {2}" + * } + * ``` + * It is then used like so: + * ```js + * this.localize('progress bar timing: currentTime={1} duration{2}', + * [this.player_.currentTime(), this.player_.duration()], + * '{1} of {2}'); + * ``` + * + * Which outputs something like: `01:23 of 24:56`. + * + * + * @param {string} string + * The string to localize and the key to lookup in the language files. + * @param {string[]} [tokens] + * If the current item has token replacements, provide the tokens here. + * @param {string} [defaultValue] + * Defaults to `string`. Can be a default value to use for token replacement + * if the lookup key is needed to be separate. + * + * @return {string} + * The localized string or if no localization exists the english string. + */ + + + Component.prototype.localize = function localize(string, tokens) { + var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : string; + + var code = this.player_.language && this.player_.language(); + var languages = this.player_.languages && this.player_.languages(); + var language = languages && languages[code]; + var primaryCode = code && code.split('-')[0]; + var primaryLang = languages && languages[primaryCode]; + + var localizedString = defaultValue; + + if (language && language[string]) { + localizedString = language[string]; + } else if (primaryLang && primaryLang[string]) { + localizedString = primaryLang[string]; + } + + if (tokens) { + localizedString = localizedString.replace(/\{(\d+)\}/g, function (match, index) { + var value = tokens[index - 1]; + var ret = value; + + if (typeof value === 'undefined') { + ret = match; + } + + return ret; + }); + } + + return localizedString; + }; + + /** + * Return the `Component`s DOM element. This is where children get inserted. + * This will usually be the the same as the element returned in {@link Component#el}. + * + * @return {Element} + * The content element for this `Component`. + */ + + + Component.prototype.contentEl = function contentEl() { + return this.contentEl_ || this.el_; + }; + + /** + * Get this `Component`s ID + * + * @return {string} + * The id of this `Component` + */ + + + Component.prototype.id = function id() { + return this.id_; + }; + + /** + * Get the `Component`s name. The name gets used to reference the `Component` + * and is set during registration. + * + * @return {string} + * The name of this `Component`. + */ + + + Component.prototype.name = function name() { + return this.name_; + }; + + /** + * Get an array of all child components + * + * @return {Array} + * The children + */ + + + Component.prototype.children = function children() { + return this.children_; + }; + + /** + * Returns the child `Component` with the given `id`. + * + * @param {string} id + * The id of the child `Component` to get. + * + * @return {Component|undefined} + * The child `Component` with the given `id` or undefined. + */ + + + Component.prototype.getChildById = function getChildById(id) { + return this.childIndex_[id]; + }; + + /** + * Returns the child `Component` with the given `name`. + * + * @param {string} name + * The name of the child `Component` to get. + * + * @return {Component|undefined} + * The child `Component` with the given `name` or undefined. + */ + + + Component.prototype.getChild = function getChild(name) { + if (!name) { + return; + } + + name = toTitleCase(name); + + return this.childNameIndex_[name]; + }; + + /** + * Add a child `Component` inside the current `Component`. + * + * + * @param {string|Component} child + * The name or instance of a child to add. + * + * @param {Object} [options={}] + * The key/value store of options that will get passed to children of + * the child. + * + * @param {number} [index=this.children_.length] + * The index to attempt to add a child into. + * + * @return {Component} + * The `Component` that gets added as a child. When using a string the + * `Component` will get created by this process. + */ + + + Component.prototype.addChild = function addChild(child) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.children_.length; + + var component = void 0; + var componentName = void 0; + + // If child is a string, create component with options + if (typeof child === 'string') { + componentName = toTitleCase(child); + + var componentClassName = options.componentClass || componentName; + + // Set name through options + options.name = componentName; + + // Create a new object & element for this controls set + // If there's no .player_, this is a player + var ComponentClass = Component.getComponent(componentClassName); + + if (!ComponentClass) { + throw new Error('Component ' + componentClassName + ' does not exist'); + } + + // data stored directly on the videojs object may be + // misidentified as a component to retain + // backwards-compatibility with 4.x. check to make sure the + // component class can be instantiated. + if (typeof ComponentClass !== 'function') { + return null; + } + + component = new ComponentClass(this.player_ || this, options); + + // child is a component instance + } else { + component = child; + } + + this.children_.splice(index, 0, component); + + if (typeof component.id === 'function') { + this.childIndex_[component.id()] = component; + } + + // If a name wasn't used to create the component, check if we can use the + // name function of the component + componentName = componentName || component.name && toTitleCase(component.name()); + + if (componentName) { + this.childNameIndex_[componentName] = component; + } + + // Add the UI object's element to the container div (box) + // Having an element is not required + if (typeof component.el === 'function' && component.el()) { + var childNodes = this.contentEl().children; + var refNode = childNodes[index] || null; + + this.contentEl().insertBefore(component.el(), refNode); + } + + // Return so it can stored on parent object if desired. + return component; + }; + + /** + * Remove a child `Component` from this `Component`s list of children. Also removes + * the child `Component`s element from this `Component`s element. + * + * @param {Component} component + * The child `Component` to remove. + */ + + + Component.prototype.removeChild = function removeChild(component) { + if (typeof component === 'string') { + component = this.getChild(component); + } + + if (!component || !this.children_) { + return; + } + + var childFound = false; + + for (var i = this.children_.length - 1; i >= 0; i--) { + if (this.children_[i] === component) { + childFound = true; + this.children_.splice(i, 1); + break; + } + } + + if (!childFound) { + return; + } + + this.childIndex_[component.id()] = null; + this.childNameIndex_[component.name()] = null; + + var compEl = component.el(); + + if (compEl && compEl.parentNode === this.contentEl()) { + this.contentEl().removeChild(component.el()); + } + }; + + /** + * Add and initialize default child `Component`s based upon options. + */ + + + Component.prototype.initChildren = function initChildren() { + var _this = this; + + var children = this.options_.children; + + if (children) { + // `this` is `parent` + var parentOptions = this.options_; + + var handleAdd = function handleAdd(child) { + var name = child.name; + var opts = child.opts; + + // Allow options for children to be set at the parent options + // e.g. videojs(id, { controlBar: false }); + // instead of videojs(id, { children: { controlBar: false }); + if (parentOptions[name] !== undefined) { + opts = parentOptions[name]; + } + + // Allow for disabling default components + // e.g. options['children']['posterImage'] = false + if (opts === false) { + return; + } + + // Allow options to be passed as a simple boolean if no configuration + // is necessary. + if (opts === true) { + opts = {}; + } + + // We also want to pass the original player options + // to each component as well so they don't need to + // reach back into the player for options later. + opts.playerOptions = _this.options_.playerOptions; + + // Create and add the child component. + // Add a direct reference to the child by name on the parent instance. + // If two of the same component are used, different names should be supplied + // for each + var newChild = _this.addChild(name, opts); + + if (newChild) { + _this[name] = newChild; + } + }; + + // Allow for an array of children details to passed in the options + var workingChildren = void 0; + var Tech = Component.getComponent('Tech'); + + if (Array.isArray(children)) { + workingChildren = children; + } else { + workingChildren = Object.keys(children); + } + + workingChildren + // children that are in this.options_ but also in workingChildren would + // give us extra children we do not want. So, we want to filter them out. + .concat(Object.keys(this.options_).filter(function (child) { + return !workingChildren.some(function (wchild) { + if (typeof wchild === 'string') { + return child === wchild; + } + return child === wchild.name; + }); + })).map(function (child) { + var name = void 0; + var opts = void 0; + + if (typeof child === 'string') { + name = child; + opts = children[name] || _this.options_[name] || {}; + } else { + name = child.name; + opts = child; + } + + return {name: name, opts: opts}; + }).filter(function (child) { + // we have to make sure that child.name isn't in the techOrder since + // techs are registerd as Components but can't aren't compatible + // See https://github.com/videojs/video.js/issues/2772 + var c = Component.getComponent(child.opts.componentClass || toTitleCase(child.name)); + + return c && !Tech.isTech(c); + }).forEach(handleAdd); + } + }; + + /** + * Builds the default DOM class name. Should be overriden by sub-components. + * + * @return {string} + * The DOM class name for this object. + * + * @abstract + */ + + + Component.prototype.buildCSSClass = function buildCSSClass() { + // Child classes can include a function that does: + // return 'CLASS NAME' + this._super(); + return ''; + }; + + /** + * Bind a listener to the component's ready state. + * Different from event listeners in that if the ready event has already happened + * it will trigger the function immediately. + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.ready = function ready(fn) { + var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!fn) { + return; + } + + if (!this.isReady_) { + this.readyQueue_ = this.readyQueue_ || []; + this.readyQueue_.push(fn); + return; + } + + if (sync) { + fn.call(this); + } else { + // Call the function asynchronously by default for consistency + this.setTimeout(fn, 1); + } + }; + + /** + * Trigger all the ready listeners for this `Component`. + * + * @fires Component#ready + */ + + + Component.prototype.triggerReady = function triggerReady() { + this.isReady_ = true; + + // Ensure ready is triggered asynchronously + this.setTimeout(function () { + var readyQueue = this.readyQueue_; + + // Reset Ready Queue + this.readyQueue_ = []; + + if (readyQueue && readyQueue.length > 0) { + readyQueue.forEach(function (fn) { + fn.call(this); + }, this); + } + + // Allow for using event listeners also + /** + * Triggered when a `Component` is ready. + * + * @event Component#ready + * @type {EventTarget~Event} + */ + this.trigger('ready'); + }, 1); + }; + + /** + * Find a single DOM element matching a `selector`. This can be within the `Component`s + * `contentEl()` or another custom context. + * + * @param {string} selector + * A valid CSS selector, which will be passed to `querySelector`. + * + * @param {Element|string} [context=this.contentEl()] + * A DOM element within which to query. Can also be a selector string in + * which case the first matching element will get used as context. If + * missing `this.contentEl()` gets used. If `this.contentEl()` returns + * nothing it falls back to `document`. + * + * @return {Element|null} + * the dom element that was found, or null + * + * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors) + */ + + + Component.prototype.$ = function $$$1(selector, context) { + return $(selector, context || this.contentEl()); + }; + + /** + * Finds all DOM element matching a `selector`. This can be within the `Component`s + * `contentEl()` or another custom context. + * + * @param {string} selector + * A valid CSS selector, which will be passed to `querySelectorAll`. + * + * @param {Element|string} [context=this.contentEl()] + * A DOM element within which to query. Can also be a selector string in + * which case the first matching element will get used as context. If + * missing `this.contentEl()` gets used. If `this.contentEl()` returns + * nothing it falls back to `document`. + * + * @return {NodeList} + * a list of dom elements that were found + * + * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors) + */ + + + Component.prototype.$$ = function $$$$1(selector, context) { + return $$(selector, context || this.contentEl()); + }; + + /** + * Check if a component's element has a CSS class name. + * + * @param {string} classToCheck + * CSS class name to check. + * + * @return {boolean} + * - True if the `Component` has the class. + * - False if the `Component` does not have the class` + */ + + + Component.prototype.hasClass = function hasClass$$1(classToCheck) { + return hasClass(this.el_, classToCheck); + }; + + /** + * Add a CSS class name to the `Component`s element. + * + * @param {string} classToAdd + * CSS class name to add + */ + + + Component.prototype.addClass = function addClass$$1(classToAdd) { + addClass(this.el_, classToAdd); + }; + + /** + * Remove a CSS class name from the `Component`s element. + * + * @param {string} classToRemove + * CSS class name to remove + */ + + + Component.prototype.removeClass = function removeClass$$1(classToRemove) { + removeClass(this.el_, classToRemove); + }; + + /** + * Add or remove a CSS class name from the component's element. + * - `classToToggle` gets added when {@link Component#hasClass} would return false. + * - `classToToggle` gets removed when {@link Component#hasClass} would return true. + * + * @param {string} classToToggle + * The class to add or remove based on (@link Component#hasClass} + * + * @param {boolean|Dom~predicate} [predicate] + * An {@link Dom~predicate} function or a boolean + */ + + + Component.prototype.toggleClass = function toggleClass$$1(classToToggle, predicate) { + toggleClass(this.el_, classToToggle, predicate); + }; + + /** + * Show the `Component`s element if it is hidden by removing the + * 'vjs-hidden' class name from it. + */ + + + Component.prototype.show = function show() { + this.removeClass('vjs-hidden'); + }; + + /** + * Hide the `Component`s element if it is currently showing by adding the + * 'vjs-hidden` class name to it. + */ + + + Component.prototype.hide = function hide() { + this.addClass('vjs-hidden'); + }; + + /** + * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing' + * class name to it. Used during fadeIn/fadeOut. + * + * @private + */ + + + Component.prototype.lockShowing = function lockShowing() { + this.addClass('vjs-lock-showing'); + }; + + /** + * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing' + * class name from it. Used during fadeIn/fadeOut. + * + * @private + */ + + + Component.prototype.unlockShowing = function unlockShowing() { + this.removeClass('vjs-lock-showing'); + }; + + /** + * Get the value of an attribute on the `Component`s element. + * + * @param {string} attribute + * Name of the attribute to get the value from. + * + * @return {string|null} + * - The value of the attribute that was asked for. + * - Can be an empty string on some browsers if the attribute does not exist + * or has no value + * - Most browsers will return null if the attibute does not exist or has + * no value. + * + * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute} + */ + + + Component.prototype.getAttribute = function getAttribute$$1(attribute) { + return getAttribute(this.el_, attribute); + }; + + /** + * Set the value of an attribute on the `Component`'s element + * + * @param {string} attribute + * Name of the attribute to set. + * + * @param {string} value + * Value to set the attribute to. + * + * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute} + */ + + + Component.prototype.setAttribute = function setAttribute$$1(attribute, value) { + setAttribute(this.el_, attribute, value); + }; + + /** + * Remove an attribute from the `Component`s element. + * + * @param {string} attribute + * Name of the attribute to remove. + * + * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute} + */ + + + Component.prototype.removeAttribute = function removeAttribute$$1(attribute) { + removeAttribute(this.el_, attribute); + }; + + /** + * Get or set the width of the component based upon the CSS styles. + * See {@link Component#dimension} for more detailed information. + * + * @param {number|string} [num] + * The width that you want to set postfixed with '%', 'px' or nothing. + * + * @param {boolean} [skipListeners] + * Skip the componentresize event trigger + * + * @return {number|string} + * The width when getting, zero if there is no width. Can be a string + * postpixed with '%' or 'px'. + */ + + + Component.prototype.width = function width(num, skipListeners) { + return this.dimension('width', num, skipListeners); + }; + + /** + * Get or set the height of the component based upon the CSS styles. + * See {@link Component#dimension} for more detailed information. + * + * @param {number|string} [num] + * The height that you want to set postfixed with '%', 'px' or nothing. + * + * @param {boolean} [skipListeners] + * Skip the componentresize event trigger + * + * @return {number|string} + * The width when getting, zero if there is no width. Can be a string + * postpixed with '%' or 'px'. + */ + + + Component.prototype.height = function height(num, skipListeners) { + return this.dimension('height', num, skipListeners); + }; + + /** + * Set both the width and height of the `Component` element at the same time. + * + * @param {number|string} width + * Width to set the `Component`s element to. + * + * @param {number|string} height + * Height to set the `Component`s element to. + */ + + + Component.prototype.dimensions = function dimensions(width, height) { + // Skip componentresize listeners on width for optimization + this.width(width, true); + this.height(height); + }; + + /** + * Get or set width or height of the `Component` element. This is the shared code + * for the {@link Component#width} and {@link Component#height}. + * + * Things to know: + * - If the width or height in an number this will return the number postfixed with 'px'. + * - If the width/height is a percent this will return the percent postfixed with '%' + * - Hidden elements have a width of 0 with `window.getComputedStyle`. This function + * defaults to the `Component`s `style.width` and falls back to `window.getComputedStyle`. + * See [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/} + * for more information + * - If you want the computed style of the component, use {@link Component#currentWidth} + * and {@link {Component#currentHeight} + * + * @fires Component#componentresize + * + * @param {string} widthOrHeight + 8 'width' or 'height' + * + * @param {number|string} [num] + 8 New dimension + * + * @param {boolean} [skipListeners] + * Skip componentresize event trigger + * + * @return {number} + * The dimension when getting or 0 if unset + */ + + + Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) { + if (num !== undefined) { + // Set to zero if null or literally NaN (NaN !== NaN) + if (num === null || num !== num) { + num = 0; + } + + // Check if using css width/height (% or px) and adjust + if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) { + this.el_.style[widthOrHeight] = num; + } else if (num === 'auto') { + this.el_.style[widthOrHeight] = ''; + } else { + this.el_.style[widthOrHeight] = num + 'px'; + } + + // skipListeners allows us to avoid triggering the resize event when setting both width and height + if (!skipListeners) { + /** + * Triggered when a component is resized. + * + * @event Component#componentresize + * @type {EventTarget~Event} + */ + this.trigger('componentresize'); + } + + return; + } + + // Not setting a value, so getting it + // Make sure element exists + if (!this.el_) { + return 0; + } + + // Get dimension value from style + var val = this.el_.style[widthOrHeight]; + var pxIndex = val.indexOf('px'); + + if (pxIndex !== -1) { + // Return the pixel value with no 'px' + return parseInt(val.slice(0, pxIndex), 10); + } + + // No px so using % or no style was set, so falling back to offsetWidth/height + // If component has display:none, offset will return 0 + // TODO: handle display:none and no dimension style using px + return parseInt(this.el_['offset' + toTitleCase(widthOrHeight)], 10); + }; + + /** + * Get the width or the height of the `Component` elements computed style. Uses + * `window.getComputedStyle`. + * + * @param {string} widthOrHeight + * A string containing 'width' or 'height'. Whichever one you want to get. + * + * @return {number} + * The dimension that gets asked for or 0 if nothing was set + * for that dimension. + */ + + + Component.prototype.currentDimension = function currentDimension(widthOrHeight) { + var computedWidthOrHeight = 0; + + if (widthOrHeight !== 'width' && widthOrHeight !== 'height') { + throw new Error('currentDimension only accepts width or height value'); + } + + if (typeof window_1.getComputedStyle === 'function') { + var computedStyle = window_1.getComputedStyle(this.el_); + + computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight]; + } + + // remove 'px' from variable and parse as integer + computedWidthOrHeight = parseFloat(computedWidthOrHeight); + + // if the computed value is still 0, it's possible that the browser is lying + // and we want to check the offset values. + // This code also runs wherever getComputedStyle doesn't exist. + if (computedWidthOrHeight === 0) { + var rule = 'offset' + toTitleCase(widthOrHeight); + + computedWidthOrHeight = this.el_[rule]; + } + + return computedWidthOrHeight; + }; + + /** + * An object that contains width and height values of the `Component`s + * computed style. Uses `window.getComputedStyle`. + * + * @typedef {Object} Component~DimensionObject + * + * @property {number} width + * The width of the `Component`s computed style. + * + * @property {number} height + * The height of the `Component`s computed style. + */ + + /** + * Get an object that contains width and height values of the `Component`s + * computed style. + * + * @return {Component~DimensionObject} + * The dimensions of the components element + */ + + + Component.prototype.currentDimensions = function currentDimensions() { + return { + width: this.currentDimension('width'), + height: this.currentDimension('height') + }; + }; + + /** + * Get the width of the `Component`s computed style. Uses `window.getComputedStyle`. + * + * @return {number} width + * The width of the `Component`s computed style. + */ + + + Component.prototype.currentWidth = function currentWidth() { + return this.currentDimension('width'); + }; + + /** + * Get the height of the `Component`s computed style. Uses `window.getComputedStyle`. + * + * @return {number} height + * The height of the `Component`s computed style. + */ + + + Component.prototype.currentHeight = function currentHeight() { + return this.currentDimension('height'); + }; + + /** + * Set the focus to this component + */ + + + Component.prototype.focus = function focus() { + this.el_.focus(); + }; + + /** + * Remove the focus from this component + */ + + + Component.prototype.blur = function blur() { + this.el_.blur(); + }; + + /** + * Emit a 'tap' events when touch event support gets detected. This gets used to + * support toggling the controls through a tap on the video. They get enabled + * because every sub-component would have extra overhead otherwise. + * + * @private + * @fires Component#tap + * @listens Component#touchstart + * @listens Component#touchmove + * @listens Component#touchleave + * @listens Component#touchcancel + * @listens Component#touchend + */ + + + Component.prototype.emitTapEvents = function emitTapEvents() { + // Track the start time so we can determine how long the touch lasted + var touchStart = 0; + var firstTouch = null; + + // Maximum movement allowed during a touch event to still be considered a tap + // Other popular libs use anywhere from 2 (hammer.js) to 15, + // so 10 seems like a nice, round number. + var tapMovementThreshold = 10; + + // The maximum length a touch can be while still being considered a tap + var touchTimeThreshold = 200; + + var couldBeTap = void 0; + + this.on('touchstart', function (event) { + // If more than one finger, don't consider treating this as a click + if (event.touches.length === 1) { + // Copy pageX/pageY from the object + firstTouch = { + pageX: event.touches[0].pageX, + pageY: event.touches[0].pageY + }; + // Record start time so we can detect a tap vs. "touch and hold" + touchStart = new Date().getTime(); + // Reset couldBeTap tracking + couldBeTap = true; + } + }); + + this.on('touchmove', function (event) { + // If more than one finger, don't consider treating this as a click + if (event.touches.length > 1) { + couldBeTap = false; + } else if (firstTouch) { + // Some devices will throw touchmoves for all but the slightest of taps. + // So, if we moved only a small distance, this could still be a tap + var xdiff = event.touches[0].pageX - firstTouch.pageX; + var ydiff = event.touches[0].pageY - firstTouch.pageY; + var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff); + + if (touchDistance > tapMovementThreshold) { + couldBeTap = false; + } + } + }); + + var noTap = function noTap() { + couldBeTap = false; + }; + + // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s + this.on('touchleave', noTap); + this.on('touchcancel', noTap); + + // When the touch ends, measure how long it took and trigger the appropriate + // event + this.on('touchend', function (event) { + firstTouch = null; + // Proceed only if the touchmove/leave/cancel event didn't happen + if (couldBeTap === true) { + // Measure how long the touch lasted + var touchTime = new Date().getTime() - touchStart; + + // Make sure the touch was less than the threshold to be considered a tap + if (touchTime < touchTimeThreshold) { + // Don't let browser turn this into a click + event.preventDefault(); + /** + * Triggered when a `Component` is tapped. + * + * @event Component#tap + * @type {EventTarget~Event} + */ + this.trigger('tap'); + // It may be good to copy the touchend event object and change the + // type to tap, if the other event properties aren't exact after + // Events.fixEvent runs (e.g. event.target) + } + } + }); + }; + + /** + * This function reports user activity whenever touch events happen. This can get + * turned off by any sub-components that wants touch events to act another way. + * + * Report user touch activity when touch events occur. User activity gets used to + * determine when controls should show/hide. It is simple when it comes to mouse + * events, because any mouse event should show the controls. So we capture mouse + * events that bubble up to the player and report activity when that happens. + * With touch events it isn't as easy as `touchstart` and `touchend` toggle player + * controls. So touch events can't help us at the player level either. + * + * User activity gets checked asynchronously. So what could happen is a tap event + * on the video turns the controls off. Then the `touchend` event bubbles up to + * the player. Which, if it reported user activity, would turn the controls right + * back on. We also don't want to completely block touch events from bubbling up. + * Furthermore a `touchmove` event and anything other than a tap, should not turn + * controls back on. + * + * @listens Component#touchstart + * @listens Component#touchmove + * @listens Component#touchend + * @listens Component#touchcancel + */ + + + Component.prototype.enableTouchActivity = function enableTouchActivity() { + // Don't continue if the root player doesn't support reporting user activity + if (!this.player() || !this.player().reportUserActivity) { + return; + } + + // listener for reporting that the user is active + var report = bind(this.player(), this.player().reportUserActivity); + + var touchHolding = void 0; + + this.on('touchstart', function () { + report(); + // For as long as the they are touching the device or have their mouse down, + // we consider them active even if they're not moving their finger or mouse. + // So we want to continue to update that they are active + this.clearInterval(touchHolding); + // report at the same interval as activityCheck + touchHolding = this.setInterval(report, 250); + }); + + var touchEnd = function touchEnd(event) { + report(); + // stop the interval that maintains activity if the touch is holding + this.clearInterval(touchHolding); + }; + + this.on('touchmove', report); + this.on('touchend', touchEnd); + this.on('touchcancel', touchEnd); + }; + + /** + * A callback that has no parameters and is bound into `Component`s context. + * + * @callback Component~GenericCallback + * @this Component + */ + + /** + * Creates a function that runs after an `x` millisecond timeout. This function is a + * wrapper around `window.setTimeout`. There are a few reasons to use this one + * instead though: + * 1. It gets cleared via {@link Component#clearTimeout} when + * {@link Component#dispose} gets called. + * 2. The function callback will gets turned into a {@link Component~GenericCallback} + * + * > Note: You can use `window.clearTimeout` on the id returned by this function. This + * will cause its dispose listener not to get cleaned up! Please use + * {@link Component#clearTimeout} or {@link Component#dispose}. + * + * @param {Component~GenericCallback} fn + * The function that will be run after `timeout`. + * + * @param {number} timeout + * Timeout in milliseconds to delay before executing the specified function. + * + * @return {number} + * Returns a timeout ID that gets used to identify the timeout. It can also + * get used in {@link Component#clearTimeout} to clear the timeout that + * was set. + * + * @listens Component#dispose + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout} + */ + + + Component.prototype.setTimeout = function setTimeout(fn, timeout) { + var _this2 = this; + + fn = bind(this, fn); + + var timeoutId = window_1.setTimeout(fn, timeout); + var disposeFn = function disposeFn() { + return _this2.clearTimeout(timeoutId); + }; + + disposeFn.guid = 'vjs-timeout-' + timeoutId; + + this.on('dispose', disposeFn); + + return timeoutId; + }; + + /** + * Clears a timeout that gets created via `window.setTimeout` or + * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout} + * use this function instead of `window.clearTimout`. If you don't your dispose + * listener will not get cleaned up until {@link Component#dispose}! + * + * @param {number} timeoutId + * The id of the timeout to clear. The return value of + * {@link Component#setTimeout} or `window.setTimeout`. + * + * @return {number} + * Returns the timeout id that was cleared. + * + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout} + */ + + + Component.prototype.clearTimeout = function clearTimeout(timeoutId) { + window_1.clearTimeout(timeoutId); + + var disposeFn = function disposeFn() { + }; + + disposeFn.guid = 'vjs-timeout-' + timeoutId; + + this.off('dispose', disposeFn); + + return timeoutId; + }; + + /** + * Creates a function that gets run every `x` milliseconds. This function is a wrapper + * around `window.setInterval`. There are a few reasons to use this one instead though. + * 1. It gets cleared via {@link Component#clearInterval} when + * {@link Component#dispose} gets called. + * 2. The function callback will be a {@link Component~GenericCallback} + * + * @param {Component~GenericCallback} fn + * The function to run every `x` seconds. + * + * @param {number} interval + * Execute the specified function every `x` milliseconds. + * + * @return {number} + * Returns an id that can be used to identify the interval. It can also be be used in + * {@link Component#clearInterval} to clear the interval. + * + * @listens Component#dispose + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval} + */ + + + Component.prototype.setInterval = function setInterval(fn, interval) { + var _this3 = this; + + fn = bind(this, fn); + + var intervalId = window_1.setInterval(fn, interval); + + var disposeFn = function disposeFn() { + return _this3.clearInterval(intervalId); + }; + + disposeFn.guid = 'vjs-interval-' + intervalId; + + this.on('dispose', disposeFn); + + return intervalId; + }; + + /** + * Clears an interval that gets created via `window.setInterval` or + * {@link Component#setInterval}. If you set an inteval via {@link Component#setInterval} + * use this function instead of `window.clearInterval`. If you don't your dispose + * listener will not get cleaned up until {@link Component#dispose}! + * + * @param {number} intervalId + * The id of the interval to clear. The return value of + * {@link Component#setInterval} or `window.setInterval`. + * + * @return {number} + * Returns the interval id that was cleared. + * + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval} + */ + + + Component.prototype.clearInterval = function clearInterval(intervalId) { + window_1.clearInterval(intervalId); + + var disposeFn = function disposeFn() { + }; + + disposeFn.guid = 'vjs-interval-' + intervalId; + + this.off('dispose', disposeFn); + + return intervalId; + }; + + /** + * Queues up a callback to be passed to requestAnimationFrame (rAF), but + * with a few extra bonuses: + * + * - Supports browsers that do not support rAF by falling back to + * {@link Component#setTimeout}. + * + * - The callback is turned into a {@link Component~GenericCallback} (i.e. + * bound to the component). + * + * - Automatic cancellation of the rAF callback is handled if the component + * is disposed before it is called. + * + * @param {Component~GenericCallback} fn + * A function that will be bound to this component and executed just + * before the browser's next repaint. + * + * @return {number} + * Returns an rAF ID that gets used to identify the timeout. It can + * also be used in {@link Component#cancelAnimationFrame} to cancel + * the animation frame callback. + * + * @listens Component#dispose + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame} + */ + + + Component.prototype.requestAnimationFrame = function requestAnimationFrame(fn) { + var _this4 = this; + + if (this.supportsRaf_) { + fn = bind(this, fn); + + var id = window_1.requestAnimationFrame(fn); + var disposeFn = function disposeFn() { + return _this4.cancelAnimationFrame(id); + }; + + disposeFn.guid = 'vjs-raf-' + id; + this.on('dispose', disposeFn); + + return id; + } + + // Fall back to using a timer. + return this.setTimeout(fn, 1000 / 60); + }; + + /** + * Cancels a queued callback passed to {@link Component#requestAnimationFrame} + * (rAF). + * + * If you queue an rAF callback via {@link Component#requestAnimationFrame}, + * use this function instead of `window.cancelAnimationFrame`. If you don't, + * your dispose listener will not get cleaned up until {@link Component#dispose}! + * + * @param {number} id + * The rAF ID to clear. The return value of {@link Component#requestAnimationFrame}. + * + * @return {number} + * Returns the rAF ID that was cleared. + * + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/cancelAnimationFrame} + */ + + + Component.prototype.cancelAnimationFrame = function cancelAnimationFrame(id) { + if (this.supportsRaf_) { + window_1.cancelAnimationFrame(id); + + var disposeFn = function disposeFn() { + }; + + disposeFn.guid = 'vjs-raf-' + id; + + this.off('dispose', disposeFn); + + return id; + } + + // Fall back to using a timer. + return this.clearTimeout(id); + }; + + /** + * Register a `Component` with `videojs` given the name and the component. + * + * > NOTE: {@link Tech}s should not be registered as a `Component`. {@link Tech}s + * should be registered using {@link Tech.registerTech} or + * {@link videojs:videojs.registerTech}. + * + * > NOTE: This function can also be seen on videojs as + * {@link videojs:videojs.registerComponent}. + * + * @param {string} name + * The name of the `Component` to register. + * + * @param {Component} ComponentToRegister + * The `Component` class to register. + * + * @return {Component} + * The `Component` that was registered. + */ + + + Component.registerComponent = function registerComponent(name, ComponentToRegister) { + if (typeof name !== 'string' || !name) { + throw new Error('Illegal component name, "' + name + '"; must be a non-empty string.'); + } + + var Tech = Component.getComponent('Tech'); + + // We need to make sure this check is only done if Tech has been registered. + var isTech = Tech && Tech.isTech(ComponentToRegister); + var isComp = Component === ComponentToRegister || Component.prototype.isPrototypeOf(ComponentToRegister.prototype); + + if (isTech || !isComp) { + var reason = void 0; + + if (isTech) { + reason = 'techs must be registered using Tech.registerTech()'; + } else { + reason = 'must be a Component subclass'; + } + + throw new Error('Illegal component, "' + name + '"; ' + reason + '.'); + } + + name = toTitleCase(name); + + if (!Component.components_) { + Component.components_ = {}; + } + + var Player = Component.getComponent('Player'); + + if (name === 'Player' && Player && Player.players) { + var players = Player.players; + var playerNames = Object.keys(players); + + // If we have players that were disposed, then their name will still be + // in Players.players. So, we must loop through and verify that the value + // for each item is not null. This allows registration of the Player component + // after all players have been disposed or before any were created. + if (players && playerNames.length > 0 && playerNames.map(function (pname) { + return players[pname]; + }).every(Boolean)) { + throw new Error('Can not register Player component after player has been created.'); + } + } + + Component.components_[name] = ComponentToRegister; + + return ComponentToRegister; + }; + + /** + * Get a `Component` based on the name it was registered with. + * + * @param {string} name + * The Name of the component to get. + * + * @return {Component} + * The `Component` that got registered under the given name. + * + * @deprecated In `videojs` 6 this will not return `Component`s that were not + * registered using {@link Component.registerComponent}. Currently we + * check the global `videojs` object for a `Component` name and + * return that if it exists. + */ + + + Component.getComponent = function getComponent(name) { + if (!name) { + return; + } + + name = toTitleCase(name); + + if (Component.components_ && Component.components_[name]) { + return Component.components_[name]; + } + }; + + return Component; + }(); + + /** + * Whether or not this component supports `requestAnimationFrame`. + * + * This is exposed primarily for testing purposes. + * + * @private + * @type {Boolean} + */ + + + Component.prototype.supportsRaf_ = typeof window_1.requestAnimationFrame === 'function' && typeof window_1.cancelAnimationFrame === 'function'; + + Component.registerComponent('Component', Component); + + /** + * @file browser.js + * @module browser + */ + + var USER_AGENT = window_1.navigator && window_1.navigator.userAgent || ''; + var webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT); + var appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null; + + /* + * Device is an iPhone + * + * @type {Boolean} + * @constant + * @private + */ + var IS_IPAD = /iPad/i.test(USER_AGENT); + + // The Facebook app's UIWebView identifies as both an iPhone and iPad, so + // to identify iPhones, we need to exclude iPads. + // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/ + var IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD; + var IS_IPOD = /iPod/i.test(USER_AGENT); + var IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD; + + var IOS_VERSION = function () { + var match = USER_AGENT.match(/OS (\d+)_/i); + + if (match && match[1]) { + return match[1]; + } + return null; + }(); + + var IS_ANDROID = /Android/i.test(USER_AGENT); + var ANDROID_VERSION = function () { + // This matches Android Major.Minor.Patch versions + // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned + var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i); + + if (!match) { + return null; + } + + var major = match[1] && parseFloat(match[1]); + var minor = match[2] && parseFloat(match[2]); + + if (major && minor) { + return parseFloat(match[1] + '.' + match[2]); + } else if (major) { + return major; + } + return null; + }(); + + var IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537; + + var IS_FIREFOX = /Firefox/i.test(USER_AGENT); + var IS_EDGE = /Edge/i.test(USER_AGENT); + var IS_CHROME = !IS_EDGE && /Chrome/i.test(USER_AGENT); + var CHROME_VERSION = function () { + var match = USER_AGENT.match(/Chrome\/(\d+)/); + + if (match && match[1]) { + return parseFloat(match[1]); + } + return null; + }(); + var IE_VERSION = function () { + var result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT); + var version = result && parseFloat(result[1]); + + if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) { + // IE 11 has a different user agent string than other IE versions + version = 11.0; + } + + return version; + }(); + + var IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE; + var IS_ANY_SAFARI = IS_SAFARI || IS_IOS; + + var TOUCH_ENABLED = isReal() && ('ontouchstart' in window_1 || window_1.DocumentTouch && window_1.document instanceof window_1.DocumentTouch); + + var browser = /*#__PURE__*/Object.freeze({ + IS_IPAD: IS_IPAD, + IS_IPHONE: IS_IPHONE, + IS_IPOD: IS_IPOD, + IS_IOS: IS_IOS, + IOS_VERSION: IOS_VERSION, + IS_ANDROID: IS_ANDROID, + ANDROID_VERSION: ANDROID_VERSION, + IS_NATIVE_ANDROID: IS_NATIVE_ANDROID, + IS_FIREFOX: IS_FIREFOX, + IS_EDGE: IS_EDGE, + IS_CHROME: IS_CHROME, + CHROME_VERSION: CHROME_VERSION, + IE_VERSION: IE_VERSION, + IS_SAFARI: IS_SAFARI, + IS_ANY_SAFARI: IS_ANY_SAFARI, + TOUCH_ENABLED: TOUCH_ENABLED + }); + + /** + * @file time-ranges.js + * @module time-ranges + */ + + /** + * Returns the time for the specified index at the start or end + * of a TimeRange object. + * + * @function time-ranges:indexFunction + * + * @param {number} [index=0] + * The range number to return the time for. + * + * @return {number} + * The time that offset at the specified index. + * + * @depricated index must be set to a value, in the future this will throw an error. + */ + + /** + * An object that contains ranges of time for various reasons. + * + * @typedef {Object} TimeRange + * + * @property {number} length + * The number of time ranges represented by this Object + * + * @property {time-ranges:indexFunction} start + * Returns the time offset at which a specified time range begins. + * + * @property {time-ranges:indexFunction} end + * Returns the time offset at which a specified time range ends. + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges + */ + + /** + * Check if any of the time ranges are over the maximum index. + * + * @param {string} fnName + * The function name to use for logging + * + * @param {number} index + * The index to check + * + * @param {number} maxIndex + * The maximum possible index + * + * @throws {Error} if the timeRanges provided are over the maxIndex + */ + function rangeCheck(fnName, index, maxIndex) { + if (typeof index !== 'number' || index < 0 || index > maxIndex) { + throw new Error('Failed to execute \'' + fnName + '\' on \'TimeRanges\': The index provided (' + index + ') is non-numeric or out of bounds (0-' + maxIndex + ').'); + } + } + + /** + * Get the time for the specified index at the start or end + * of a TimeRange object. + * + * @param {string} fnName + * The function name to use for logging + * + * @param {string} valueIndex + * The property that should be used to get the time. should be 'start' or 'end' + * + * @param {Array} ranges + * An array of time ranges + * + * @param {Array} [rangeIndex=0] + * The index to start the search at + * + * @return {number} + * The time that offset at the specified index. + * + * + * @depricated rangeIndex must be set to a value, in the future this will throw an error. + * @throws {Error} if rangeIndex is more than the length of ranges + */ + function getRange(fnName, valueIndex, ranges, rangeIndex) { + rangeCheck(fnName, rangeIndex, ranges.length - 1); + return ranges[rangeIndex][valueIndex]; + } + + /** + * Create a time range object given ranges of time. + * + * @param {Array} [ranges] + * An array of time ranges. + */ + function createTimeRangesObj(ranges) { + if (ranges === undefined || ranges.length === 0) { + return { + length: 0, + start: function start() { + throw new Error('This TimeRanges object is empty'); + }, + end: function end() { + throw new Error('This TimeRanges object is empty'); + } + }; + } + return { + length: ranges.length, + start: getRange.bind(null, 'start', 0, ranges), + end: getRange.bind(null, 'end', 1, ranges) + }; + } + + /** + * Should create a fake `TimeRange` object which mimics an HTML5 time range instance. + * + * @param {number|Array} start + * The start of a single range or an array of ranges + * + * @param {number} end + * The end of a single range. + * + * @private + */ + function createTimeRanges(start, end) { + if (Array.isArray(start)) { + return createTimeRangesObj(start); + } else if (start === undefined || end === undefined) { + return createTimeRangesObj(); + } + return createTimeRangesObj([[start, end]]); + } + + /** + * @file buffer.js + * @module buffer + */ + + /** + * Compute the percentage of the media that has been buffered. + * + * @param {TimeRange} buffered + * The current `TimeRange` object representing buffered time ranges + * + * @param {number} duration + * Total duration of the media + * + * @return {number} + * Percent buffered of the total duration in decimal form. + */ + function bufferedPercent(buffered, duration) { + var bufferedDuration = 0; + var start = void 0; + var end = void 0; + + if (!duration) { + return 0; + } + + if (!buffered || !buffered.length) { + buffered = createTimeRanges(0, 0); + } + + for (var i = 0; i < buffered.length; i++) { + start = buffered.start(i); + end = buffered.end(i); + + // buffered end can be bigger than duration by a very small fraction + if (end > duration) { + end = duration; + } + + bufferedDuration += end - start; + } + + return bufferedDuration / duration; + } + + /** + * @file fullscreen-api.js + * @module fullscreen-api + * @private + */ + + /** + * Store the browser-specific methods for the fullscreen API. + * + * @type {Object} + * @see [Specification]{@link https://fullscreen.spec.whatwg.org} + * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js} + */ + var FullscreenApi = {}; + + // browser API methods + var apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'], + // WebKit + ['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'], + // Old WebKit (Safari 5.1) + ['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'], + // Mozilla + ['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'], + // Microsoft + ['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']]; + + var specApi = apiMap[0]; + var browserApi = void 0; + + // determine the supported set of functions + for (var i = 0; i < apiMap.length; i++) { + // check for exitFullscreen function + if (apiMap[i][1] in document_1) { + browserApi = apiMap[i]; + break; + } + } + + // map the browser API names to the spec API names + if (browserApi) { + for (var _i = 0; _i < browserApi.length; _i++) { + FullscreenApi[specApi[_i]] = browserApi[_i]; + } + } + + /** + * @file media-error.js + */ + + /** + * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class. + * + * @param {number|string|Object|MediaError} value + * This can be of multiple types: + * - number: should be a standard error code + * - string: an error message (the code will be 0) + * - Object: arbitrary properties + * - `MediaError` (native): used to populate a video.js `MediaError` object + * - `MediaError` (video.js): will return itself if it's already a + * video.js `MediaError` object. + * + * @see [MediaError Spec]{@link https://dev.w3.org/html5/spec-author-view/video.html#mediaerror} + * @see [Encrypted MediaError Spec]{@link https://www.w3.org/TR/2013/WD-encrypted-media-20130510/#error-codes} + * + * @class MediaError + */ + function MediaError(value) { + + // Allow redundant calls to this constructor to avoid having `instanceof` + // checks peppered around the code. + if (value instanceof MediaError) { + return value; + } + + if (typeof value === 'number') { + this.code = value; + } else if (typeof value === 'string') { + // default code is zero, so this is a custom error + this.message = value; + } else if (isObject(value)) { + + // We assign the `code` property manually because native `MediaError` objects + // do not expose it as an own/enumerable property of the object. + if (typeof value.code === 'number') { + this.code = value.code; + } + + assign(this, value); + } + + if (!this.message) { + this.message = MediaError.defaultMessages[this.code] || ''; + } + } + + /** + * The error code that refers two one of the defined `MediaError` types + * + * @type {Number} + */ + MediaError.prototype.code = 0; + + /** + * An optional message that to show with the error. Message is not part of the HTML5 + * video spec but allows for more informative custom errors. + * + * @type {String} + */ + MediaError.prototype.message = ''; + + /** + * An optional status code that can be set by plugins to allow even more detail about + * the error. For example a plugin might provide a specific HTTP status code and an + * error message for that code. Then when the plugin gets that error this class will + * know how to display an error message for it. This allows a custom message to show + * up on the `Player` error overlay. + * + * @type {Array} + */ + MediaError.prototype.status = null; + + /** + * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the + * specification listed under {@link MediaError} for more information. + * + * @enum {array} + * @readonly + * @property {string} 0 - MEDIA_ERR_CUSTOM + * @property {string} 1 - MEDIA_ERR_CUSTOM + * @property {string} 2 - MEDIA_ERR_ABORTED + * @property {string} 3 - MEDIA_ERR_NETWORK + * @property {string} 4 - MEDIA_ERR_SRC_NOT_SUPPORTED + * @property {string} 5 - MEDIA_ERR_ENCRYPTED + */ + MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED']; + + /** + * The default `MediaError` messages based on the {@link MediaError.errorTypes}. + * + * @type {Array} + * @constant + */ + MediaError.defaultMessages = { + 1: 'You aborted the media playback', + 2: 'A network error caused the media download to fail part-way.', + 3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.', + 4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.', + 5: 'The media is encrypted and we do not have the keys to decrypt it.' + }; + + // Add types as properties on MediaError + // e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; + for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { + MediaError[MediaError.errorTypes[errNum]] = errNum; + // values should be accessible on both the class and instance + MediaError.prototype[MediaError.errorTypes[errNum]] = errNum; + } + + var tuple = SafeParseTuple; + + function SafeParseTuple(obj, reviver) { + var json; + var error = null; + + try { + json = JSON.parse(obj, reviver); + } catch (err) { + error = err; + } + + return [error, json]; + } + + /** + * Returns whether an object is `Promise`-like (i.e. has a `then` method). + * + * @param {Object} value + * An object that may or may not be `Promise`-like. + * + * @return {Boolean} + * Whether or not the object is `Promise`-like. + */ + function isPromise(value) { + return value !== undefined && value !== null && typeof value.then === 'function'; + } + + /** + * Silence a Promise-like object. + * + * This is useful for avoiding non-harmful, but potentially confusing "uncaught + * playOld promise" rejection error messages. + * + * @param {Object} value + * An object that may or may not be `Promise`-like. + */ + function silencePromise(value) { + if (isPromise(value)) { + value.then(null, function (e) { + }); + } + } + + /** + * @file text-track-list-converter.js Utilities for capturing text track state and + * re-creating tracks based on a capture. + * + * @module text-track-list-converter + */ + + /** + * Examine a single {@link TextTrack} and return a JSON-compatible javascript object that + * represents the {@link TextTrack}'s state. + * + * @param {TextTrack} track + * The text track to query. + * + * @return {Object} + * A serializable javascript representation of the TextTrack. + * @private + */ + var trackToJson_ = function trackToJson_(track) { + var ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce(function (acc, prop, i) { + + if (track[prop]) { + acc[prop] = track[prop]; + } + + return acc; + }, { + cues: track.cues && Array.prototype.map.call(track.cues, function (cue) { + return { + startTime: cue.startTime, + endTime: cue.endTime, + text: cue.text, + id: cue.id + }; + }) + }); + + return ret; + }; + + /** + * Examine a {@link Tech} and return a JSON-compatible javascript array that represents the + * state of all {@link TextTrack}s currently configured. The return array is compatible with + * {@link text-track-list-converter:jsonToTextTracks}. + * + * @param {Tech} tech + * The tech object to query + * + * @return {Array} + * A serializable javascript representation of the {@link Tech}s + * {@link TextTrackList}. + */ + var textTracksToJson = function textTracksToJson(tech) { + + var trackEls = tech.$$('track'); + + var trackObjs = Array.prototype.map.call(trackEls, function (t) { + return t.track; + }); + var tracks = Array.prototype.map.call(trackEls, function (trackEl) { + var json = trackToJson_(trackEl.track); + + if (trackEl.src) { + json.src = trackEl.src; + } + return json; + }); + + return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) { + return trackObjs.indexOf(track) === -1; + }).map(trackToJson_)); + }; + + /** + * Create a set of remote {@link TextTrack}s on a {@link Tech} based on an array of javascript + * object {@link TextTrack} representations. + * + * @param {Array} json + * An array of `TextTrack` representation objects, like those that would be + * produced by `textTracksToJson`. + * + * @param {Tech} tech + * The `Tech` to create the `TextTrack`s on. + */ + var jsonToTextTracks = function jsonToTextTracks(json, tech) { + json.forEach(function (track) { + var addedTrack = tech.addRemoteTextTrack(track).track; + + if (!track.src && track.cues) { + track.cues.forEach(function (cue) { + return addedTrack.addCue(cue); + }); + } + }); + + return tech.textTracks(); + }; + + var textTrackConverter = { + textTracksToJson: textTracksToJson, + jsonToTextTracks: jsonToTextTracks, + trackToJson_: trackToJson_ + }; + + /** + * @file modal-dialog.js + */ + + var MODAL_CLASS_NAME = 'vjs-modal-dialog'; + var ESC = 27; + + /** + * The `ModalDialog` displays over the video and its controls, which blocks + * interaction with the player until it is closed. + * + * Modal dialogs include a "Close" button and will close when that button + * is activated - or when ESC is pressed anywhere. + * + * @extends Component + */ + + var ModalDialog = function (_Component) { + inherits(ModalDialog, _Component); + + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Mixed} [options.content=undefined] + * Provide customized content for this modal. + * + * @param {string} [options.description] + * A text description for the modal, primarily for accessibility. + * + * @param {boolean} [options.fillAlways=false] + * Normally, modals are automatically filled only the first time + * they open. This tells the modal to refresh its content + * every time it opens. + * + * @param {string} [options.label] + * A text label for the modal, primarily for accessibility. + * + * @param {boolean} [options.temporary=true] + * If `true`, the modal can only be opened once; it will be + * disposed as soon as it's closed. + * + * @param {boolean} [options.uncloseable=false] + * If `true`, the user will not be able to close the modal + * through the UI in the normal ways. Programmatic closing is + * still possible. + */ + function ModalDialog(player, options) { + classCallCheck(this, ModalDialog); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false; + + _this.closeable(!_this.options_.uncloseable); + _this.content(_this.options_.content); + + // Make sure the contentEl is defined AFTER any children are initialized + // because we only want the contents of the modal in the contentEl + // (not the UI elements like the close button). + _this.contentEl_ = createEl('div', { + className: MODAL_CLASS_NAME + '-content' + }, { + role: 'document' + }); + + _this.descEl_ = createEl('p', { + className: MODAL_CLASS_NAME + '-description vjs-control-text', + id: _this.el().getAttribute('aria-describedby') + }); + + textContent(_this.descEl_, _this.description()); + _this.el_.appendChild(_this.descEl_); + _this.el_.appendChild(_this.contentEl_); + return _this; + } + + /** + * Create the `ModalDialog`'s DOM element + * + * @return {Element} + * The DOM element that gets created. + */ + + + ModalDialog.prototype.createEl = function createEl$$1() { + return _Component.prototype.createEl.call(this, 'div', { + className: this.buildCSSClass(), + tabIndex: -1 + }, { + 'aria-describedby': this.id() + '_description', + 'aria-hidden': 'true', + 'aria-label': this.label(), + 'role': 'dialog' + }); + }; + + ModalDialog.prototype.dispose = function dispose() { + this.contentEl_ = null; + this.descEl_ = null; + this.previouslyActiveEl_ = null; + + _Component.prototype.dispose.call(this); + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + ModalDialog.prototype.buildCSSClass = function buildCSSClass() { + return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this); + }; + + /** + * Handles `keydown` events on the document, looking for ESC, which closes + * the modal. + * + * @param {EventTarget~Event} e + * The keypress that triggered this event. + * + * @listens keydown + */ + + + ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) { + if (e.which === ESC && this.closeable()) { + this.close(); + } + }; + + /** + * Returns the label string for this modal. Primarily used for accessibility. + * + * @return {string} + * the localized or raw label of this modal. + */ + + + ModalDialog.prototype.label = function label() { + return this.localize(this.options_.label || 'Modal Window'); + }; + + /** + * Returns the description string for this modal. Primarily used for + * accessibility. + * + * @return {string} + * The localized or raw description of this modal. + */ + + + ModalDialog.prototype.description = function description() { + var desc = this.options_.description || this.localize('This is a modal window.'); + + // Append a universal closeability message if the modal is closeable. + if (this.closeable()) { + desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.'); + } + + return desc; + }; + + /** + * Opens the modal. + * + * @fires ModalDialog#beforemodalopen + * @fires ModalDialog#modalopen + */ + + + ModalDialog.prototype.open = function open() { + if (!this.opened_) { + var player = this.player(); + + /** + * Fired just before a `ModalDialog` is opened. + * + * @event ModalDialog#beforemodalopen + * @type {EventTarget~Event} + */ + this.trigger('beforemodalopen'); + this.opened_ = true; + + // Fill content if the modal has never opened before and + // never been filled. + if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) { + this.fill(); + } + + // If the player was playing, pause it and take note of its previously + // playing state. + this.wasPlaying_ = !player.paused(); + + if (this.options_.pauseOnOpen && this.wasPlaying_) { + player.pause(); + } + + if (this.closeable()) { + this.on(this.el_.ownerDocument, 'keydown', bind(this, this.handleKeyPress)); + } + + // Hide controls and note if they were enabled. + this.hadControls_ = player.controls(); + player.controls(false); + + this.show(); + this.conditionalFocus_(); + this.el().setAttribute('aria-hidden', 'false'); + + /** + * Fired just after a `ModalDialog` is opened. + * + * @event ModalDialog#modalopen + * @type {EventTarget~Event} + */ + this.trigger('modalopen'); + this.hasBeenOpened_ = true; + } + }; + + /** + * If the `ModalDialog` is currently open or closed. + * + * @param {boolean} [value] + * If given, it will open (`true`) or close (`false`) the modal. + * + * @return {boolean} + * the current open state of the modaldialog + */ + + + ModalDialog.prototype.opened = function opened(value) { + if (typeof value === 'boolean') { + this[value ? 'open' : 'close'](); + } + return this.opened_; + }; + + /** + * Closes the modal, does nothing if the `ModalDialog` is + * not open. + * + * @fires ModalDialog#beforemodalclose + * @fires ModalDialog#modalclose + */ + + + ModalDialog.prototype.close = function close() { + if (!this.opened_) { + return; + } + var player = this.player(); + + /** + * Fired just before a `ModalDialog` is closed. + * + * @event ModalDialog#beforemodalclose + * @type {EventTarget~Event} + */ + this.trigger('beforemodalclose'); + this.opened_ = false; + + if (this.wasPlaying_ && this.options_.pauseOnOpen) { + player.play(); + } + + if (this.closeable()) { + this.off(this.el_.ownerDocument, 'keydown', bind(this, this.handleKeyPress)); + } + + if (this.hadControls_) { + player.controls(true); + } + + this.hide(); + this.el().setAttribute('aria-hidden', 'true'); + + /** + * Fired just after a `ModalDialog` is closed. + * + * @event ModalDialog#modalclose + * @type {EventTarget~Event} + */ + this.trigger('modalclose'); + this.conditionalBlur_(); + + if (this.options_.temporary) { + this.dispose(); + } + }; + + /** + * Check to see if the `ModalDialog` is closeable via the UI. + * + * @param {boolean} [value] + * If given as a boolean, it will set the `closeable` option. + * + * @return {boolean} + * Returns the final value of the closable option. + */ + + + ModalDialog.prototype.closeable = function closeable(value) { + if (typeof value === 'boolean') { + var closeable = this.closeable_ = !!value; + var close = this.getChild('closeButton'); + + // If this is being made closeable and has no close button, add one. + if (closeable && !close) { + + // The close button should be a child of the modal - not its + // content element, so temporarily change the content element. + var temp = this.contentEl_; + + this.contentEl_ = this.el_; + close = this.addChild('closeButton', {controlText: 'Close Modal Dialog'}); + this.contentEl_ = temp; + this.on(close, 'close', this.close); + } + + // If this is being made uncloseable and has a close button, remove it. + if (!closeable && close) { + this.off(close, 'close', this.close); + this.removeChild(close); + close.dispose(); + } + } + return this.closeable_; + }; + + /** + * Fill the modal's content element with the modal's "content" option. + * The content element will be emptied before this change takes place. + */ + + + ModalDialog.prototype.fill = function fill() { + this.fillWith(this.content()); + }; + + /** + * Fill the modal's content element with arbitrary content. + * The content element will be emptied before this change takes place. + * + * @fires ModalDialog#beforemodalfill + * @fires ModalDialog#modalfill + * + * @param {Mixed} [content] + * The same rules apply to this as apply to the `content` option. + */ + + + ModalDialog.prototype.fillWith = function fillWith(content) { + var contentEl = this.contentEl(); + var parentEl = contentEl.parentNode; + var nextSiblingEl = contentEl.nextSibling; + + /** + * Fired just before a `ModalDialog` is filled with content. + * + * @event ModalDialog#beforemodalfill + * @type {EventTarget~Event} + */ + this.trigger('beforemodalfill'); + this.hasBeenFilled_ = true; + + // Detach the content element from the DOM before performing + // manipulation to avoid modifying the live DOM multiple times. + parentEl.removeChild(contentEl); + this.empty(); + insertContent(contentEl, content); + /** + * Fired just after a `ModalDialog` is filled with content. + * + * @event ModalDialog#modalfill + * @type {EventTarget~Event} + */ + this.trigger('modalfill'); + + // Re-inject the re-filled content element. + if (nextSiblingEl) { + parentEl.insertBefore(contentEl, nextSiblingEl); + } else { + parentEl.appendChild(contentEl); + } + + // make sure that the close button is last in the dialog DOM + var closeButton = this.getChild('closeButton'); + + if (closeButton) { + parentEl.appendChild(closeButton.el_); + } + }; + + /** + * Empties the content element. This happens anytime the modal is filled. + * + * @fires ModalDialog#beforemodalempty + * @fires ModalDialog#modalempty + */ + + + ModalDialog.prototype.empty = function empty() { + /** + * Fired just before a `ModalDialog` is emptied. + * + * @event ModalDialog#beforemodalempty + * @type {EventTarget~Event} + */ + this.trigger('beforemodalempty'); + emptyEl(this.contentEl()); + + /** + * Fired just after a `ModalDialog` is emptied. + * + * @event ModalDialog#modalempty + * @type {EventTarget~Event} + */ + this.trigger('modalempty'); + }; + + /** + * Gets or sets the modal content, which gets normalized before being + * rendered into the DOM. + * + * This does not update the DOM or fill the modal, but it is called during + * that process. + * + * @param {Mixed} [value] + * If defined, sets the internal content value to be used on the + * next call(s) to `fill`. This value is normalized before being + * inserted. To "clear" the internal content value, pass `null`. + * + * @return {Mixed} + * The current content of the modal dialog + */ + + + ModalDialog.prototype.content = function content(value) { + if (typeof value !== 'undefined') { + this.content_ = value; + } + return this.content_; + }; + + /** + * conditionally focus the modal dialog if focus was previously on the player. + * + * @private + */ + + + ModalDialog.prototype.conditionalFocus_ = function conditionalFocus_() { + var activeEl = document_1.activeElement; + var playerEl = this.player_.el_; + + this.previouslyActiveEl_ = null; + + if (playerEl.contains(activeEl) || playerEl === activeEl) { + this.previouslyActiveEl_ = activeEl; + + this.focus(); + + this.on(document_1, 'keydown', this.handleKeyDown); + } + }; + + /** + * conditionally blur the element and refocus the last focused element + * + * @private + */ + + + ModalDialog.prototype.conditionalBlur_ = function conditionalBlur_() { + if (this.previouslyActiveEl_) { + this.previouslyActiveEl_.focus(); + this.previouslyActiveEl_ = null; + } + + this.off(document_1, 'keydown', this.handleKeyDown); + }; + + /** + * Keydown handler. Attached when modal is focused. + * + * @listens keydown + */ + + + ModalDialog.prototype.handleKeyDown = function handleKeyDown(event) { + // exit early if it isn't a tab key + if (event.which !== 9) { + return; + } + + var focusableEls = this.focusableEls_(); + var activeEl = this.el_.querySelector(':focus'); + var focusIndex = void 0; + + for (var i = 0; i < focusableEls.length; i++) { + if (activeEl === focusableEls[i]) { + focusIndex = i; + break; + } + } + + if (document_1.activeElement === this.el_) { + focusIndex = 0; + } + + if (event.shiftKey && focusIndex === 0) { + focusableEls[focusableEls.length - 1].focus(); + event.preventDefault(); + } else if (!event.shiftKey && focusIndex === focusableEls.length - 1) { + focusableEls[0].focus(); + event.preventDefault(); + } + }; + + /** + * get all focusable elements + * + * @private + */ + + + ModalDialog.prototype.focusableEls_ = function focusableEls_() { + var allChildren = this.el_.querySelectorAll('*'); + + return Array.prototype.filter.call(allChildren, function (child) { + return (child instanceof window_1.HTMLAnchorElement || child instanceof window_1.HTMLAreaElement) && child.hasAttribute('href') || (child instanceof window_1.HTMLInputElement || child instanceof window_1.HTMLSelectElement || child instanceof window_1.HTMLTextAreaElement || child instanceof window_1.HTMLButtonElement) && !child.hasAttribute('disabled') || child instanceof window_1.HTMLIFrameElement || child instanceof window_1.HTMLObjectElement || child instanceof window_1.HTMLEmbedElement || child.hasAttribute('tabindex') && child.getAttribute('tabindex') !== -1 || child.hasAttribute('contenteditable'); + }); + }; + + return ModalDialog; + }(Component); + + /** + * Default options for `ModalDialog` default options. + * + * @type {Object} + * @private + */ + + + ModalDialog.prototype.options_ = { + pauseOnOpen: true, + temporary: true + }; + + Component.registerComponent('ModalDialog', ModalDialog); + + /** + * @file track-list.js + */ + + /** + * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and + * {@link VideoTrackList} + * + * @extends EventTarget + */ + + var TrackList = function (_EventTarget) { + inherits(TrackList, _EventTarget); + + /** + * Create an instance of this class + * + * @param {Track[]} tracks + * A list of tracks to initialize the list with. + * + * @abstract + */ + function TrackList() { + var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + classCallCheck(this, TrackList); + + var _this = possibleConstructorReturn(this, _EventTarget.call(this)); + + _this.tracks_ = []; + + /** + * @memberof TrackList + * @member {number} length + * The current number of `Track`s in the this Trackist. + * @instance + */ + Object.defineProperty(_this, 'length', { + get: function get$$1() { + return this.tracks_.length; + } + }); + + for (var i = 0; i < tracks.length; i++) { + _this.addTrack(tracks[i]); + } + return _this; + } + + /** + * Add a {@link Track} to the `TrackList` + * + * @param {Track} track + * The audio, video, or text track to add to the list. + * + * @fires TrackList#addtrack + */ + + + TrackList.prototype.addTrack = function addTrack(track) { + var index = this.tracks_.length; + + if (!('' + index in this)) { + Object.defineProperty(this, index, { + get: function get$$1() { + return this.tracks_[index]; + } + }); + } + + // Do not add duplicate tracks + if (this.tracks_.indexOf(track) === -1) { + this.tracks_.push(track); + /** + * Triggered when a track is added to a track list. + * + * @event TrackList#addtrack + * @type {EventTarget~Event} + * @property {Track} track + * A reference to track that was added. + */ + this.trigger({ + track: track, + type: 'addtrack' + }); + } + }; + + /** + * Remove a {@link Track} from the `TrackList` + * + * @param {Track} rtrack + * The audio, video, or text track to remove from the list. + * + * @fires TrackList#removetrack + */ + + + TrackList.prototype.removeTrack = function removeTrack(rtrack) { + var track = void 0; + + for (var i = 0, l = this.length; i < l; i++) { + if (this[i] === rtrack) { + track = this[i]; + if (track.off) { + track.off(); + } + + this.tracks_.splice(i, 1); + + break; + } + } + + if (!track) { + return; + } + + /** + * Triggered when a track is removed from track list. + * + * @event TrackList#removetrack + * @type {EventTarget~Event} + * @property {Track} track + * A reference to track that was removed. + */ + this.trigger({ + track: track, + type: 'removetrack' + }); + }; + + /** + * Get a Track from the TrackList by a tracks id + * + * @param {String} id - the id of the track to get + * @method getTrackById + * @return {Track} + * @private + */ + + + TrackList.prototype.getTrackById = function getTrackById(id) { + var result = null; + + for (var i = 0, l = this.length; i < l; i++) { + var track = this[i]; + + if (track.id === id) { + result = track; + break; + } + } + + return result; + }; + + return TrackList; + }(EventTarget); + + /** + * Triggered when a different track is selected/enabled. + * + * @event TrackList#change + * @type {EventTarget~Event} + */ + + /** + * Events that can be called with on + eventName. See {@link EventHandler}. + * + * @property {Object} TrackList#allowedEvents_ + * @private + */ + + + TrackList.prototype.allowedEvents_ = { + change: 'change', + addtrack: 'addtrack', + removetrack: 'removetrack' + }; + + // emulate attribute EventHandler support to allow for feature detection + for (var event in TrackList.prototype.allowedEvents_) { + TrackList.prototype['on' + event] = null; + } + + /** + * @file audio-track-list.js + */ + + /** + * Anywhere we call this function we diverge from the spec + * as we only support one enabled audiotrack at a time + * + * @param {AudioTrackList} list + * list to work on + * + * @param {AudioTrack} track + * The track to skip + * + * @private + */ + var disableOthers = function disableOthers(list, track) { + for (var i = 0; i < list.length; i++) { + if (!Object.keys(list[i]).length || track.id === list[i].id) { + continue; + } + // another audio track is enabled, disable it + list[i].enabled = false; + } + }; + + /** + * The current list of {@link AudioTrack} for a media file. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist} + * @extends TrackList + */ + + var AudioTrackList = function (_TrackList) { + inherits(AudioTrackList, _TrackList); + + /** + * Create an instance of this class. + * + * @param {AudioTrack[]} [tracks=[]] + * A list of `AudioTrack` to instantiate the list with. + */ + function AudioTrackList() { + var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + classCallCheck(this, AudioTrackList); + + // make sure only 1 track is enabled + // sorted from last index to first index + for (var i = tracks.length - 1; i >= 0; i--) { + if (tracks[i].enabled) { + disableOthers(tracks, tracks[i]); + break; + } + } + + var _this = possibleConstructorReturn(this, _TrackList.call(this, tracks)); + + _this.changing_ = false; + return _this; + } + + /** + * Add an {@link AudioTrack} to the `AudioTrackList`. + * + * @param {AudioTrack} track + * The AudioTrack to add to the list + * + * @fires TrackList#addtrack + */ + + + AudioTrackList.prototype.addTrack = function addTrack(track) { + var _this2 = this; + + if (track.enabled) { + disableOthers(this, track); + } + + _TrackList.prototype.addTrack.call(this, track); + // native tracks don't have this + if (!track.addEventListener) { + return; + } + + /** + * @listens AudioTrack#enabledchange + * @fires TrackList#change + */ + track.addEventListener('enabledchange', function () { + // when we are disabling other tracks (since we don't support + // more than one track at a time) we will set changing_ + // to true so that we don't trigger additional change events + if (_this2.changing_) { + return; + } + _this2.changing_ = true; + disableOthers(_this2, track); + _this2.changing_ = false; + _this2.trigger('change'); + }); + }; + + return AudioTrackList; + }(TrackList); + + /** + * @file video-track-list.js + */ + + /** + * Un-select all other {@link VideoTrack}s that are selected. + * + * @param {VideoTrackList} list + * list to work on + * + * @param {VideoTrack} track + * The track to skip + * + * @private + */ + var disableOthers$1 = function disableOthers(list, track) { + for (var i = 0; i < list.length; i++) { + if (!Object.keys(list[i]).length || track.id === list[i].id) { + continue; + } + // another video track is enabled, disable it + list[i].selected = false; + } + }; + + /** + * The current list of {@link VideoTrack} for a video. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist} + * @extends TrackList + */ + + var VideoTrackList = function (_TrackList) { + inherits(VideoTrackList, _TrackList); + + /** + * Create an instance of this class. + * + * @param {VideoTrack[]} [tracks=[]] + * A list of `VideoTrack` to instantiate the list with. + */ + function VideoTrackList() { + var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + classCallCheck(this, VideoTrackList); + + // make sure only 1 track is enabled + // sorted from last index to first index + for (var i = tracks.length - 1; i >= 0; i--) { + if (tracks[i].selected) { + disableOthers$1(tracks, tracks[i]); + break; + } + } + + var _this = possibleConstructorReturn(this, _TrackList.call(this, tracks)); + + _this.changing_ = false; + + /** + * @member {number} VideoTrackList#selectedIndex + * The current index of the selected {@link VideoTrack`}. + */ + Object.defineProperty(_this, 'selectedIndex', { + get: function get$$1() { + for (var _i = 0; _i < this.length; _i++) { + if (this[_i].selected) { + return _i; + } + } + return -1; + }, + set: function set$$1() { + } + }); + return _this; + } + + /** + * Add a {@link VideoTrack} to the `VideoTrackList`. + * + * @param {VideoTrack} track + * The VideoTrack to add to the list + * + * @fires TrackList#addtrack + */ + + + VideoTrackList.prototype.addTrack = function addTrack(track) { + var _this2 = this; + + if (track.selected) { + disableOthers$1(this, track); + } + + _TrackList.prototype.addTrack.call(this, track); + // native tracks don't have this + if (!track.addEventListener) { + return; + } + + /** + * @listens VideoTrack#selectedchange + * @fires TrackList#change + */ + track.addEventListener('selectedchange', function () { + if (_this2.changing_) { + return; + } + _this2.changing_ = true; + disableOthers$1(_this2, track); + _this2.changing_ = false; + _this2.trigger('change'); + }); + }; + + return VideoTrackList; + }(TrackList); + + /** + * @file text-track-list.js + */ + + /** + * The current list of {@link TextTrack} for a media file. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist} + * @extends TrackList + */ + + var TextTrackList = function (_TrackList) { + inherits(TextTrackList, _TrackList); + + function TextTrackList() { + classCallCheck(this, TextTrackList); + return possibleConstructorReturn(this, _TrackList.apply(this, arguments)); + } + + /** + * Add a {@link TextTrack} to the `TextTrackList` + * + * @param {TextTrack} track + * The text track to add to the list. + * + * @fires TrackList#addtrack + */ + TextTrackList.prototype.addTrack = function addTrack(track) { + _TrackList.prototype.addTrack.call(this, track); + + /** + * @listens TextTrack#modechange + * @fires TrackList#change + */ + track.addEventListener('modechange', bind(this, function () { + this.trigger('change'); + })); + + var nonLanguageTextTrackKind = ['metadata', 'chapters']; + + if (nonLanguageTextTrackKind.indexOf(track.kind) === -1) { + track.addEventListener('modechange', bind(this, function () { + this.trigger('selectedlanguagechange'); + })); + } + }; + + return TextTrackList; + }(TrackList); + + /** + * @file html-track-element-list.js + */ + + /** + * The current list of {@link HtmlTrackElement}s. + */ + var HtmlTrackElementList = function () { + + /** + * Create an instance of this class. + * + * @param {HtmlTrackElement[]} [tracks=[]] + * A list of `HtmlTrackElement` to instantiate the list with. + */ + function HtmlTrackElementList() { + var trackElements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + classCallCheck(this, HtmlTrackElementList); + + this.trackElements_ = []; + + /** + * @memberof HtmlTrackElementList + * @member {number} length + * The current number of `Track`s in the this Trackist. + * @instance + */ + Object.defineProperty(this, 'length', { + get: function get$$1() { + return this.trackElements_.length; + } + }); + + for (var i = 0, length = trackElements.length; i < length; i++) { + this.addTrackElement_(trackElements[i]); + } + } + + /** + * Add an {@link HtmlTrackElement} to the `HtmlTrackElementList` + * + * @param {HtmlTrackElement} trackElement + * The track element to add to the list. + * + * @private + */ + + + HtmlTrackElementList.prototype.addTrackElement_ = function addTrackElement_(trackElement) { + var index = this.trackElements_.length; + + if (!('' + index in this)) { + Object.defineProperty(this, index, { + get: function get$$1() { + return this.trackElements_[index]; + } + }); + } + + // Do not add duplicate elements + if (this.trackElements_.indexOf(trackElement) === -1) { + this.trackElements_.push(trackElement); + } + }; + + /** + * Get an {@link HtmlTrackElement} from the `HtmlTrackElementList` given an + * {@link TextTrack}. + * + * @param {TextTrack} track + * The track associated with a track element. + * + * @return {HtmlTrackElement|undefined} + * The track element that was found or undefined. + * + * @private + */ + + + HtmlTrackElementList.prototype.getTrackElementByTrack_ = function getTrackElementByTrack_(track) { + var trackElement_ = void 0; + + for (var i = 0, length = this.trackElements_.length; i < length; i++) { + if (track === this.trackElements_[i].track) { + trackElement_ = this.trackElements_[i]; + + break; + } + } + + return trackElement_; + }; + + /** + * Remove a {@link HtmlTrackElement} from the `HtmlTrackElementList` + * + * @param {HtmlTrackElement} trackElement + * The track element to remove from the list. + * + * @private + */ + + + HtmlTrackElementList.prototype.removeTrackElement_ = function removeTrackElement_(trackElement) { + for (var i = 0, length = this.trackElements_.length; i < length; i++) { + if (trackElement === this.trackElements_[i]) { + this.trackElements_.splice(i, 1); + + break; + } + } + }; + + return HtmlTrackElementList; + }(); + + /** + * @file text-track-cue-list.js + */ + + /** + * @typedef {Object} TextTrackCueList~TextTrackCue + * + * @property {string} id + * The unique id for this text track cue + * + * @property {number} startTime + * The start time for this text track cue + * + * @property {number} endTime + * The end time for this text track cue + * + * @property {boolean} pauseOnExit + * Pause when the end time is reached if true. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcue} + */ + + /** + * A List of TextTrackCues. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist} + */ + var TextTrackCueList = function () { + + /** + * Create an instance of this class.. + * + * @param {Array} cues + * A list of cues to be initialized with + */ + function TextTrackCueList(cues) { + classCallCheck(this, TextTrackCueList); + + TextTrackCueList.prototype.setCues_.call(this, cues); + + /** + * @memberof TextTrackCueList + * @member {number} length + * The current number of `TextTrackCue`s in the TextTrackCueList. + * @instance + */ + Object.defineProperty(this, 'length', { + get: function get$$1() { + return this.length_; + } + }); + } + + /** + * A setter for cues in this list. Creates getters + * an an index for the cues. + * + * @param {Array} cues + * An array of cues to set + * + * @private + */ + + + TextTrackCueList.prototype.setCues_ = function setCues_(cues) { + var oldLength = this.length || 0; + var i = 0; + var l = cues.length; + + this.cues_ = cues; + this.length_ = cues.length; + + var defineProp = function defineProp(index) { + if (!('' + index in this)) { + Object.defineProperty(this, '' + index, { + get: function get$$1() { + return this.cues_[index]; + } + }); + } + }; + + if (oldLength < l) { + i = oldLength; + + for (; i < l; i++) { + defineProp.call(this, i); + } + } + }; + + /** + * Get a `TextTrackCue` that is currently in the `TextTrackCueList` by id. + * + * @param {string} id + * The id of the cue that should be searched for. + * + * @return {TextTrackCueList~TextTrackCue|null} + * A single cue or null if none was found. + */ + + + TextTrackCueList.prototype.getCueById = function getCueById(id) { + var result = null; + + for (var i = 0, l = this.length; i < l; i++) { + var cue = this[i]; + + if (cue.id === id) { + result = cue; + break; + } + } + + return result; + }; + + return TextTrackCueList; + }(); + + /** + * @file track-kinds.js + */ + + /** + * All possible `VideoTrackKind`s + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-videotrack-kind + * @typedef VideoTrack~Kind + * @enum + */ + var VideoTrackKind = { + alternative: 'alternative', + captions: 'captions', + main: 'main', + sign: 'sign', + subtitles: 'subtitles', + commentary: 'commentary' + }; + + /** + * All possible `AudioTrackKind`s + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-audiotrack-kind + * @typedef AudioTrack~Kind + * @enum + */ + var AudioTrackKind = { + 'alternative': 'alternative', + 'descriptions': 'descriptions', + 'main': 'main', + 'main-desc': 'main-desc', + 'translation': 'translation', + 'commentary': 'commentary' + }; + + /** + * All possible `TextTrackKind`s + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-texttrack-kind + * @typedef TextTrack~Kind + * @enum + */ + var TextTrackKind = { + subtitles: 'subtitles', + captions: 'captions', + descriptions: 'descriptions', + chapters: 'chapters', + metadata: 'metadata' + }; + + /** + * All possible `TextTrackMode`s + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode + * @typedef TextTrack~Mode + * @enum + */ + var TextTrackMode = { + disabled: 'disabled', + hidden: 'hidden', + showing: 'showing' + }; + + /** + * @file track.js + */ + + /** + * A Track class that contains all of the common functionality for {@link AudioTrack}, + * {@link VideoTrack}, and {@link TextTrack}. + * + * > Note: This class should not be used directly + * + * @see {@link https://html.spec.whatwg.org/multipage/embedded-content.html} + * @extends EventTarget + * @abstract + */ + + var Track = function (_EventTarget) { + inherits(Track, _EventTarget); + + /** + * Create an instance of this class. + * + * @param {Object} [options={}] + * Object of option names and values + * + * @param {string} [options.kind=''] + * A valid kind for the track type you are creating. + * + * @param {string} [options.id='vjs_track_' + Guid.newGUID()] + * A unique id for this AudioTrack. + * + * @param {string} [options.label=''] + * The menu label for this track. + * + * @param {string} [options.language=''] + * A valid two character language code. + * + * @abstract + */ + function Track() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, Track); + + var _this = possibleConstructorReturn(this, _EventTarget.call(this)); + + var trackProps = { + id: options.id || 'vjs_track_' + newGUID(), + kind: options.kind || '', + label: options.label || '', + language: options.language || '' + }; + + /** + * @memberof Track + * @member {string} id + * The id of this track. Cannot be changed after creation. + * @instance + * + * @readonly + */ + + /** + * @memberof Track + * @member {string} kind + * The kind of track that this is. Cannot be changed after creation. + * @instance + * + * @readonly + */ + + /** + * @memberof Track + * @member {string} label + * The label of this track. Cannot be changed after creation. + * @instance + * + * @readonly + */ + + /** + * @memberof Track + * @member {string} language + * The two letter language code for this track. Cannot be changed after + * creation. + * @instance + * + * @readonly + */ + + var _loop = function _loop(key) { + Object.defineProperty(_this, key, { + get: function get$$1() { + return trackProps[key]; + }, + set: function set$$1() { + } + }); + }; + + for (var key in trackProps) { + _loop(key); + } + return _this; + } + + return Track; + }(EventTarget); + + /** + * @file url.js + * @module url + */ + + /** + * @typedef {Object} url:URLObject + * + * @property {string} protocol + * The protocol of the url that was parsed. + * + * @property {string} hostname + * The hostname of the url that was parsed. + * + * @property {string} port + * The port of the url that was parsed. + * + * @property {string} pathname + * The pathname of the url that was parsed. + * + * @property {string} search + * The search query of the url that was parsed. + * + * @property {string} hash + * The hash of the url that was parsed. + * + * @property {string} host + * The host of the url that was parsed. + */ + + /** + * Resolve and parse the elements of a URL. + * + * @param {String} url + * The url to parse + * + * @return {url:URLObject} + * An object of url details + */ + var parseUrl = function parseUrl(url) { + var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host']; + + // add the url to an anchor and let the browser parse the URL + var a = document_1.createElement('a'); + + a.href = url; + + // IE8 (and 9?) Fix + // ie8 doesn't parse the URL correctly until the anchor is actually + // added to the body, and an innerHTML is needed to trigger the parsing + var addToBody = a.host === '' && a.protocol !== 'file:'; + var div = void 0; + + if (addToBody) { + div = document_1.createElement('div'); + div.innerHTML = '<a href="' + url + '"></a>'; + a = div.firstChild; + // prevent the div from affecting layout + div.setAttribute('style', 'display:none; position:absolute;'); + document_1.body.appendChild(div); + } + + // Copy the specific URL properties to a new object + // This is also needed for IE8 because the anchor loses its + // properties when it's removed from the dom + var details = {}; + + for (var i = 0; i < props.length; i++) { + details[props[i]] = a[props[i]]; + } + + // IE9 adds the port to the host property unlike everyone else. If + // a port identifier is added for standard ports, strip it. + if (details.protocol === 'http:') { + details.host = details.host.replace(/:80$/, ''); + } + + if (details.protocol === 'https:') { + details.host = details.host.replace(/:443$/, ''); + } + + if (!details.protocol) { + details.protocol = window_1.location.protocol; + } + + if (addToBody) { + document_1.body.removeChild(div); + } + + return details; + }; + + /** + * Get absolute version of relative URL. Used to tell flash correct URL. + * + * + * @param {string} url + * URL to make absolute + * + * @return {string} + * Absolute URL + * + * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue + */ + var getAbsoluteURL = function getAbsoluteURL(url) { + // Check if absolute URL + if (!url.match(/^https?:\/\//)) { + // Convert to absolute URL. Flash hosted off-site needs an absolute URL. + var div = document_1.createElement('div'); + + div.innerHTML = '<a href="' + url + '">x</a>'; + url = div.firstChild.href; + } + + return url; + }; + + /** + * Returns the extension of the passed file name. It will return an empty string + * if passed an invalid path. + * + * @param {string} path + * The fileName path like '/path/to/file.mp4' + * + * @returns {string} + * The extension in lower case or an empty string if no + * extension could be found. + */ + var getFileExtension = function getFileExtension(path) { + if (typeof path === 'string') { + var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i; + var pathParts = splitPathRe.exec(path); + + if (pathParts) { + return pathParts.pop().toLowerCase(); + } + } + + return ''; + }; + + /** + * Returns whether the url passed is a cross domain request or not. + * + * @param {string} url + * The url to check. + * + * @return {boolean} + * Whether it is a cross domain request or not. + */ + var isCrossOrigin = function isCrossOrigin(url) { + var winLoc = window_1.location; + var urlInfo = parseUrl(url); + + // IE8 protocol relative urls will return ':' for protocol + var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol; + + // Check if url is for another domain/origin + // IE8 doesn't know location.origin, so we won't rely on it here + var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host; + + return crossOrigin; + }; + + var Url = /*#__PURE__*/Object.freeze({ + parseUrl: parseUrl, + getAbsoluteURL: getAbsoluteURL, + getFileExtension: getFileExtension, + isCrossOrigin: isCrossOrigin + }); + + var isFunction_1 = isFunction; + + var toString$1 = Object.prototype.toString; + + function isFunction(fn) { + var string = toString$1.call(fn); + return string === '[object Function]' || typeof fn === 'function' && string !== '[object RegExp]' || typeof window !== 'undefined' && ( + // IE8 and below + fn === window.setTimeout || fn === window.alert || fn === window.confirm || fn === window.prompt); + } + + var isFunction$1 = /*#__PURE__*/Object.freeze({ + default: isFunction_1, + __moduleExports: isFunction_1 + }); + + var trim_1 = createCommonjsModule(function (module, exports) { + exports = module.exports = trim; + + function trim(str) { + return str.replace(/^\s*|\s*$/g, ''); + } + + exports.left = function (str) { + return str.replace(/^\s*/, ''); + }; + + exports.right = function (str) { + return str.replace(/\s*$/, ''); + }; + }); + var trim_2 = trim_1.left; + var trim_3 = trim_1.right; + + var trim = /*#__PURE__*/Object.freeze({ + default: trim_1, + __moduleExports: trim_1, + left: trim_2, + right: trim_3 + }); + + var isFunction$2 = (isFunction$1 && isFunction_1) || isFunction$1; + + var forEach_1 = forEach; + + var toString$2 = Object.prototype.toString; + var hasOwnProperty = Object.prototype.hasOwnProperty; + + function forEach(list, iterator, context) { + if (!isFunction$2(iterator)) { + throw new TypeError('iterator must be a function'); + } + + if (arguments.length < 3) { + context = this; + } + + if (toString$2.call(list) === '[object Array]') forEachArray(list, iterator, context); else if (typeof list === 'string') forEachString(list, iterator, context); else forEachObject(list, iterator, context); + } + + function forEachArray(array, iterator, context) { + for (var i = 0, len = array.length; i < len; i++) { + if (hasOwnProperty.call(array, i)) { + iterator.call(context, array[i], i, array); + } + } + } + + function forEachString(string, iterator, context) { + for (var i = 0, len = string.length; i < len; i++) { + // no such thing as a sparse string. + iterator.call(context, string.charAt(i), i, string); + } + } + + function forEachObject(object, iterator, context) { + for (var k in object) { + if (hasOwnProperty.call(object, k)) { + iterator.call(context, object[k], k, object); + } + } + } + + var forEach$1 = /*#__PURE__*/Object.freeze({ + default: forEach_1, + __moduleExports: forEach_1 + }); + + var trim$1 = (trim && trim_1) || trim; + + var forEach$2 = (forEach$1 && forEach_1) || forEach$1; + + var isArray = function isArray(arg) { + return Object.prototype.toString.call(arg) === '[object Array]'; + }; + + var parseHeaders = function parseHeaders(headers) { + if (!headers) return {}; + + var result = {}; + + forEach$2(trim$1(headers).split('\n'), function (row) { + var index = row.indexOf(':'), + key = trim$1(row.slice(0, index)).toLowerCase(), + value = trim$1(row.slice(index + 1)); + + if (typeof result[key] === 'undefined') { + result[key] = value; + } else if (isArray(result[key])) { + result[key].push(value); + } else { + result[key] = [result[key], value]; + } + }); + + return result; + }; + + var parseHeaders$1 = /*#__PURE__*/Object.freeze({ + default: parseHeaders, + __moduleExports: parseHeaders + }); + + var immutable = extend; + + var hasOwnProperty$1 = Object.prototype.hasOwnProperty; + + function extend() { + var target = {}; + + for (var i = 0; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (hasOwnProperty$1.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + } + + var immutable$1 = /*#__PURE__*/Object.freeze({ + default: immutable, + __moduleExports: immutable + }); + + var parseHeaders$2 = (parseHeaders$1 && parseHeaders) || parseHeaders$1; + + var xtend = (immutable$1 && immutable) || immutable$1; + + var xhr = createXHR; + createXHR.XMLHttpRequest = window_1.XMLHttpRequest || noop; + createXHR.XDomainRequest = "withCredentials" in new createXHR.XMLHttpRequest() ? createXHR.XMLHttpRequest : window_1.XDomainRequest; + + forEachArray$1(["get", "put", "post", "patch", "head", "delete"], function (method) { + createXHR[method === "delete" ? "del" : method] = function (uri, options, callback) { + options = initParams(uri, options, callback); + options.method = method.toUpperCase(); + return _createXHR(options); + }; + }); + + function forEachArray$1(array, iterator) { + for (var i = 0; i < array.length; i++) { + iterator(array[i]); + } + } + + function isEmpty(obj) { + for (var i in obj) { + if (obj.hasOwnProperty(i)) return false; + } + return true; + } + + function initParams(uri, options, callback) { + var params = uri; + + if (isFunction$2(options)) { + callback = options; + if (typeof uri === "string") { + params = {uri: uri}; + } + } else { + params = xtend(options, {uri: uri}); + } + + params.callback = callback; + return params; + } + + function createXHR(uri, options, callback) { + options = initParams(uri, options, callback); + return _createXHR(options); + } + + function _createXHR(options) { + if (typeof options.callback === "undefined") { + throw new Error("callback argument missing"); + } + + var called = false; + var callback = function cbOnce(err, response, body) { + if (!called) { + called = true; + options.callback(err, response, body); + } + }; + + function readystatechange() { + if (xhr.readyState === 4) { + setTimeout(loadFunc, 0); + } + } + + function getBody() { + // Chrome with requestType=blob throws errors arround when even testing access to responseText + var body = undefined; + + if (xhr.response) { + body = xhr.response; + } else { + body = xhr.responseText || getXml(xhr); + } + + if (isJson) { + try { + body = JSON.parse(body); + } catch (e) { + } + } + + return body; + } + + function errorFunc(evt) { + clearTimeout(timeoutTimer); + if (!(evt instanceof Error)) { + evt = new Error("" + (evt || "Unknown XMLHttpRequest Error")); + } + evt.statusCode = 0; + return callback(evt, failureResponse); + } + + // will load the data & process the response in a special response object + function loadFunc() { + if (aborted) return; + var status; + clearTimeout(timeoutTimer); + if (options.useXDR && xhr.status === undefined) { + //IE8 CORS GET successful response doesn't have a status field, but body is fine + status = 200; + } else { + status = xhr.status === 1223 ? 204 : xhr.status; + } + var response = failureResponse; + var err = null; + + if (status !== 0) { + response = { + body: getBody(), + statusCode: status, + method: method, + headers: {}, + url: uri, + rawRequest: xhr + }; + if (xhr.getAllResponseHeaders) { + //remember xhr can in fact be XDR for CORS in IE + response.headers = parseHeaders$2(xhr.getAllResponseHeaders()); + } + } else { + err = new Error("Internal XMLHttpRequest Error"); + } + return callback(err, response, response.body); + } + + var xhr = options.xhr || null; + + if (!xhr) { + if (options.cors || options.useXDR) { + xhr = new createXHR.XDomainRequest(); + } else { + xhr = new createXHR.XMLHttpRequest(); + } + } + + var key; + var aborted; + var uri = xhr.url = options.uri || options.url; + var method = xhr.method = options.method || "GET"; + var body = options.body || options.data; + var headers = xhr.headers = options.headers || {}; + var sync = !!options.sync; + var isJson = false; + var timeoutTimer; + var failureResponse = { + body: undefined, + headers: {}, + statusCode: 0, + method: method, + url: uri, + rawRequest: xhr + }; + + if ("json" in options && options.json !== false) { + isJson = true; + headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json"); //Don't override existing accept header declared by user + if (method !== "GET" && method !== "HEAD") { + headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json"); //Don't override existing accept header declared by user + body = JSON.stringify(options.json === true ? body : options.json); + } + } + + xhr.onreadystatechange = readystatechange; + xhr.onload = loadFunc; + xhr.onerror = errorFunc; + // IE9 must have onprogress be set to a unique function. + xhr.onprogress = function () { + // IE must die + }; + xhr.onabort = function () { + aborted = true; + }; + xhr.ontimeout = errorFunc; + xhr.open(method, uri, !sync, options.username, options.password); + //has to be after open + if (!sync) { + xhr.withCredentials = !!options.withCredentials; + } + // Cannot set timeout with sync request + // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly + // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent + if (!sync && options.timeout > 0) { + timeoutTimer = setTimeout(function () { + if (aborted) return; + aborted = true; //IE9 may still call readystatechange + xhr.abort("timeout"); + var e = new Error("XMLHttpRequest timeout"); + e.code = "ETIMEDOUT"; + errorFunc(e); + }, options.timeout); + } + + if (xhr.setRequestHeader) { + for (key in headers) { + if (headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, headers[key]); + } + } + } else if (options.headers && !isEmpty(options.headers)) { + throw new Error("Headers cannot be set on an XDomainRequest object"); + } + + if ("responseType" in options) { + xhr.responseType = options.responseType; + } + + if ("beforeSend" in options && typeof options.beforeSend === "function") { + options.beforeSend(xhr); + } + + // Microsoft Edge browser sends "undefined" when send is called with undefined value. + // XMLHttpRequest spec says to pass null as body to indicate no body + // See https://github.com/naugtur/xhr/issues/100. + xhr.send(body || null); + + return xhr; + } + + function getXml(xhr) { + if (xhr.responseType === "document") { + return xhr.responseXML; + } + var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror"; + if (xhr.responseType === "" && !firefoxBugTakenEffect) { + return xhr.responseXML; + } + + return null; + } + + function noop() { + } + + /** + * @file text-track.js + */ + + /** + * Takes a webvtt file contents and parses it into cues + * + * @param {string} srcContent + * webVTT file contents + * + * @param {TextTrack} track + * TextTrack to add cues to. Cues come from the srcContent. + * + * @private + */ + var parseCues = function parseCues(srcContent, track) { + var parser = new window_1.WebVTT.Parser(window_1, window_1.vttjs, window_1.WebVTT.StringDecoder()); + var errors = []; + + parser.oncue = function (cue) { + track.addCue(cue); + }; + + parser.onparsingerror = function (error) { + errors.push(error); + }; + + parser.onflush = function () { + track.trigger({ + type: 'loadeddata', + target: track + }); + }; + + parser.parse(srcContent); + if (errors.length > 0) { + if (window_1.console && window_1.console.groupCollapsed) { + window_1.console.groupCollapsed('Text Track parsing errors for ' + track.src); + } + errors.forEach(function (error) { + return log$1.error(error); + }); + if (window_1.console && window_1.console.groupEnd) { + window_1.console.groupEnd(); + } + } + + parser.flush(); + }; + + /** + * Load a `TextTrack` from a specified url. + * + * @param {string} src + * Url to load track from. + * + * @param {TextTrack} track + * Track to add cues to. Comes from the content at the end of `url`. + * + * @private + */ + var loadTrack = function loadTrack(src, track) { + var opts = { + uri: src + }; + var crossOrigin = isCrossOrigin(src); + + if (crossOrigin) { + opts.cors = crossOrigin; + } + + xhr(opts, bind(this, function (err, response, responseBody) { + if (err) { + return log$1.error(err, response); + } + + track.loaded_ = true; + + // Make sure that vttjs has loaded, otherwise, wait till it finished loading + // NOTE: this is only used for the alt/video.novtt.js build + if (typeof window_1.WebVTT !== 'function') { + if (track.tech_) { + var loadHandler = function loadHandler() { + return parseCues(responseBody, track); + }; + + track.tech_.on('vttjsloaded', loadHandler); + track.tech_.on('vttjserror', function () { + log$1.error('vttjs failed to load, stopping trying to process ' + track.src); + track.tech_.off('vttjsloaded', loadHandler); + }); + } + } else { + parseCues(responseBody, track); + } + })); + }; + + /** + * A representation of a single `TextTrack`. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack} + * @extends Track + */ + + var TextTrack = function (_Track) { + inherits(TextTrack, _Track); + + /** + * Create an instance of this class. + * + * @param {Object} options={} + * Object of option names and values + * + * @param {Tech} options.tech + * A reference to the tech that owns this TextTrack. + * + * @param {TextTrack~Kind} [options.kind='subtitles'] + * A valid text track kind. + * + * @param {TextTrack~Mode} [options.mode='disabled'] + * A valid text track mode. + * + * @param {string} [options.id='vjs_track_' + Guid.newGUID()] + * A unique id for this TextTrack. + * + * @param {string} [options.label=''] + * The menu label for this track. + * + * @param {string} [options.language=''] + * A valid two character language code. + * + * @param {string} [options.srclang=''] + * A valid two character language code. An alternative, but deprioritized + * version of `options.language` + * + * @param {string} [options.src] + * A url to TextTrack cues. + * + * @param {boolean} [options.default] + * If this track should default to on or off. + */ + function TextTrack() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, TextTrack); + + if (!options.tech) { + throw new Error('A tech was not provided.'); + } + + var settings = mergeOptions(options, { + kind: TextTrackKind[options.kind] || 'subtitles', + language: options.language || options.srclang || '' + }); + var mode = TextTrackMode[settings.mode] || 'disabled'; + var default_ = settings.default; + + if (settings.kind === 'metadata' || settings.kind === 'chapters') { + mode = 'hidden'; + } + + var _this = possibleConstructorReturn(this, _Track.call(this, settings)); + + _this.tech_ = settings.tech; + + _this.cues_ = []; + _this.activeCues_ = []; + + var cues = new TextTrackCueList(_this.cues_); + var activeCues = new TextTrackCueList(_this.activeCues_); + var changed = false; + var timeupdateHandler = bind(_this, function () { + + // Accessing this.activeCues for the side-effects of updating itself + // due to it's nature as a getter function. Do not remove or cues will + // stop updating! + /* eslint-disable no-unused-expressions */ + this.activeCues; + /* eslint-enable no-unused-expressions */ + if (changed) { + this.trigger('cuechange'); + changed = false; + } + }); + + if (mode !== 'disabled') { + _this.tech_.ready(function () { + _this.tech_.on('timeupdate', timeupdateHandler); + }, true); + } + + Object.defineProperties(_this, { + /** + * @memberof TextTrack + * @member {boolean} default + * If this track was set to be on or off by default. Cannot be changed after + * creation. + * @instance + * + * @readonly + */ + default: { + get: function get$$1() { + return default_; + }, + set: function set$$1() { + } + }, + + /** + * @memberof TextTrack + * @member {string} mode + * Set the mode of this TextTrack to a valid {@link TextTrack~Mode}. Will + * not be set if setting to an invalid mode. + * @instance + * + * @fires TextTrack#modechange + */ + mode: { + get: function get$$1() { + return mode; + }, + set: function set$$1(newMode) { + var _this2 = this; + + if (!TextTrackMode[newMode]) { + return; + } + mode = newMode; + if (mode === 'showing') { + + this.tech_.ready(function () { + _this2.tech_.on('timeupdate', timeupdateHandler); + }, true); + } + /** + * An event that fires when mode changes on this track. This allows + * the TextTrackList that holds this track to act accordingly. + * + * > Note: This is not part of the spec! + * + * @event TextTrack#modechange + * @type {EventTarget~Event} + */ + this.trigger('modechange'); + } + }, + + /** + * @memberof TextTrack + * @member {TextTrackCueList} cues + * The text track cue list for this TextTrack. + * @instance + */ + cues: { + get: function get$$1() { + if (!this.loaded_) { + return null; + } + + return cues; + }, + set: function set$$1() { + } + }, + + /** + * @memberof TextTrack + * @member {TextTrackCueList} activeCues + * The list text track cues that are currently active for this TextTrack. + * @instance + */ + activeCues: { + get: function get$$1() { + if (!this.loaded_) { + return null; + } + + // nothing to do + if (this.cues.length === 0) { + return activeCues; + } + + var ct = this.tech_.currentTime(); + var active = []; + + for (var i = 0, l = this.cues.length; i < l; i++) { + var cue = this.cues[i]; + + if (cue.startTime <= ct && cue.endTime >= ct) { + active.push(cue); + } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) { + active.push(cue); + } + } + + changed = false; + + if (active.length !== this.activeCues_.length) { + changed = true; + } else { + for (var _i = 0; _i < active.length; _i++) { + if (this.activeCues_.indexOf(active[_i]) === -1) { + changed = true; + } + } + } + + this.activeCues_ = active; + activeCues.setCues_(this.activeCues_); + + return activeCues; + }, + set: function set$$1() { + } + } + }); + + if (settings.src) { + _this.src = settings.src; + loadTrack(settings.src, _this); + } else { + _this.loaded_ = true; + } + return _this; + } + + /** + * Add a cue to the internal list of cues. + * + * @param {TextTrack~Cue} cue + * The cue to add to our internal list + */ + + + TextTrack.prototype.addCue = function addCue(originalCue) { + var cue = originalCue; + + if (window_1.vttjs && !(originalCue instanceof window_1.vttjs.VTTCue)) { + cue = new window_1.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text); + + for (var prop in originalCue) { + if (!(prop in cue)) { + cue[prop] = originalCue[prop]; + } + } + + // make sure that `id` is copied over + cue.id = originalCue.id; + cue.originalCue_ = originalCue; + } + + var tracks = this.tech_.textTracks(); + + for (var i = 0; i < tracks.length; i++) { + if (tracks[i] !== this) { + tracks[i].removeCue(cue); + } + } + + this.cues_.push(cue); + this.cues.setCues_(this.cues_); + }; + + /** + * Remove a cue from our internal list + * + * @param {TextTrack~Cue} removeCue + * The cue to remove from our internal list + */ + + + TextTrack.prototype.removeCue = function removeCue(_removeCue) { + var i = this.cues_.length; + + while (i--) { + var cue = this.cues_[i]; + + if (cue === _removeCue || cue.originalCue_ && cue.originalCue_ === _removeCue) { + this.cues_.splice(i, 1); + this.cues.setCues_(this.cues_); + break; + } + } + }; + + return TextTrack; + }(Track); + + /** + * cuechange - One or more cues in the track have become active or stopped being active. + */ + + + TextTrack.prototype.allowedEvents_ = { + cuechange: 'cuechange' + }; + + /** + * A representation of a single `AudioTrack`. If it is part of an {@link AudioTrackList} + * only one `AudioTrack` in the list will be enabled at a time. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack} + * @extends Track + */ + + var AudioTrack = function (_Track) { + inherits(AudioTrack, _Track); + + /** + * Create an instance of this class. + * + * @param {Object} [options={}] + * Object of option names and values + * + * @param {AudioTrack~Kind} [options.kind=''] + * A valid audio track kind + * + * @param {string} [options.id='vjs_track_' + Guid.newGUID()] + * A unique id for this AudioTrack. + * + * @param {string} [options.label=''] + * The menu label for this track. + * + * @param {string} [options.language=''] + * A valid two character language code. + * + * @param {boolean} [options.enabled] + * If this track is the one that is currently playing. If this track is part of + * an {@link AudioTrackList}, only one {@link AudioTrack} will be enabled. + */ + function AudioTrack() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, AudioTrack); + + var settings = mergeOptions(options, { + kind: AudioTrackKind[options.kind] || '' + }); + + var _this = possibleConstructorReturn(this, _Track.call(this, settings)); + + var enabled = false; + + /** + * @memberof AudioTrack + * @member {boolean} enabled + * If this `AudioTrack` is enabled or not. When setting this will + * fire {@link AudioTrack#enabledchange} if the state of enabled is changed. + * @instance + * + * @fires VideoTrack#selectedchange + */ + Object.defineProperty(_this, 'enabled', { + get: function get$$1() { + return enabled; + }, + set: function set$$1(newEnabled) { + // an invalid or unchanged value + if (typeof newEnabled !== 'boolean' || newEnabled === enabled) { + return; + } + enabled = newEnabled; + + /** + * An event that fires when enabled changes on this track. This allows + * the AudioTrackList that holds this track to act accordingly. + * + * > Note: This is not part of the spec! Native tracks will do + * this internally without an event. + * + * @event AudioTrack#enabledchange + * @type {EventTarget~Event} + */ + this.trigger('enabledchange'); + } + }); + + // if the user sets this track to selected then + // set selected to that true value otherwise + // we keep it false + if (settings.enabled) { + _this.enabled = settings.enabled; + } + _this.loaded_ = true; + return _this; + } + + return AudioTrack; + }(Track); + + /** + * A representation of a single `VideoTrack`. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotrack} + * @extends Track + */ + + var VideoTrack = function (_Track) { + inherits(VideoTrack, _Track); + + /** + * Create an instance of this class. + * + * @param {Object} [options={}] + * Object of option names and values + * + * @param {string} [options.kind=''] + * A valid {@link VideoTrack~Kind} + * + * @param {string} [options.id='vjs_track_' + Guid.newGUID()] + * A unique id for this AudioTrack. + * + * @param {string} [options.label=''] + * The menu label for this track. + * + * @param {string} [options.language=''] + * A valid two character language code. + * + * @param {boolean} [options.selected] + * If this track is the one that is currently playing. + */ + function VideoTrack() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, VideoTrack); + + var settings = mergeOptions(options, { + kind: VideoTrackKind[options.kind] || '' + }); + + var _this = possibleConstructorReturn(this, _Track.call(this, settings)); + + var selected = false; + + /** + * @memberof VideoTrack + * @member {boolean} selected + * If this `VideoTrack` is selected or not. When setting this will + * fire {@link VideoTrack#selectedchange} if the state of selected changed. + * @instance + * + * @fires VideoTrack#selectedchange + */ + Object.defineProperty(_this, 'selected', { + get: function get$$1() { + return selected; + }, + set: function set$$1(newSelected) { + // an invalid or unchanged value + if (typeof newSelected !== 'boolean' || newSelected === selected) { + return; + } + selected = newSelected; + + /** + * An event that fires when selected changes on this track. This allows + * the VideoTrackList that holds this track to act accordingly. + * + * > Note: This is not part of the spec! Native tracks will do + * this internally without an event. + * + * @event VideoTrack#selectedchange + * @type {EventTarget~Event} + */ + this.trigger('selectedchange'); + } + }); + + // if the user sets this track to selected then + // set selected to that true value otherwise + // we keep it false + if (settings.selected) { + _this.selected = settings.selected; + } + return _this; + } + + return VideoTrack; + }(Track); + + /** + * @file html-track-element.js + */ + + /** + * @memberof HTMLTrackElement + * @typedef {HTMLTrackElement~ReadyState} + * @enum {number} + */ + var NONE = 0; + var LOADING = 1; + var LOADED = 2; + var ERROR = 3; + + /** + * A single track represented in the DOM. + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement} + * @extends EventTarget + */ + + var HTMLTrackElement = function (_EventTarget) { + inherits(HTMLTrackElement, _EventTarget); + + /** + * Create an instance of this class. + * + * @param {Object} options={} + * Object of option names and values + * + * @param {Tech} options.tech + * A reference to the tech that owns this HTMLTrackElement. + * + * @param {TextTrack~Kind} [options.kind='subtitles'] + * A valid text track kind. + * + * @param {TextTrack~Mode} [options.mode='disabled'] + * A valid text track mode. + * + * @param {string} [options.id='vjs_track_' + Guid.newGUID()] + * A unique id for this TextTrack. + * + * @param {string} [options.label=''] + * The menu label for this track. + * + * @param {string} [options.language=''] + * A valid two character language code. + * + * @param {string} [options.srclang=''] + * A valid two character language code. An alternative, but deprioritized + * vesion of `options.language` + * + * @param {string} [options.src] + * A url to TextTrack cues. + * + * @param {boolean} [options.default] + * If this track should default to on or off. + */ + function HTMLTrackElement() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, HTMLTrackElement); + + var _this = possibleConstructorReturn(this, _EventTarget.call(this)); + + var readyState = void 0; + + var track = new TextTrack(options); + + _this.kind = track.kind; + _this.src = track.src; + _this.srclang = track.language; + _this.label = track.label; + _this.default = track.default; + + Object.defineProperties(_this, { + + /** + * @memberof HTMLTrackElement + * @member {HTMLTrackElement~ReadyState} readyState + * The current ready state of the track element. + * @instance + */ + readyState: { + get: function get$$1() { + return readyState; + } + }, + + /** + * @memberof HTMLTrackElement + * @member {TextTrack} track + * The underlying TextTrack object. + * @instance + * + */ + track: { + get: function get$$1() { + return track; + } + } + }); + + readyState = NONE; + + /** + * @listens TextTrack#loadeddata + * @fires HTMLTrackElement#load + */ + track.addEventListener('loadeddata', function () { + readyState = LOADED; + + _this.trigger({ + type: 'load', + target: _this + }); + }); + return _this; + } + + return HTMLTrackElement; + }(EventTarget); + + HTMLTrackElement.prototype.allowedEvents_ = { + load: 'load' + }; + + HTMLTrackElement.NONE = NONE; + HTMLTrackElement.LOADING = LOADING; + HTMLTrackElement.LOADED = LOADED; + HTMLTrackElement.ERROR = ERROR; + + /* + * This file contains all track properties that are used in + * player.js, tech.js, html5.js and possibly other techs in the future. + */ + + var NORMAL = { + audio: { + ListClass: AudioTrackList, + TrackClass: AudioTrack, + capitalName: 'Audio' + }, + video: { + ListClass: VideoTrackList, + TrackClass: VideoTrack, + capitalName: 'Video' + }, + text: { + ListClass: TextTrackList, + TrackClass: TextTrack, + capitalName: 'Text' + } + }; + + Object.keys(NORMAL).forEach(function (type) { + NORMAL[type].getterName = type + 'Tracks'; + NORMAL[type].privateName = type + 'Tracks_'; + }); + + var REMOTE = { + remoteText: { + ListClass: TextTrackList, + TrackClass: TextTrack, + capitalName: 'RemoteText', + getterName: 'remoteTextTracks', + privateName: 'remoteTextTracks_' + }, + remoteTextEl: { + ListClass: HtmlTrackElementList, + TrackClass: HTMLTrackElement, + capitalName: 'RemoteTextTrackEls', + getterName: 'remoteTextTrackEls', + privateName: 'remoteTextTrackEls_' + } + }; + + var ALL = mergeOptions(NORMAL, REMOTE); + + REMOTE.names = Object.keys(REMOTE); + NORMAL.names = Object.keys(NORMAL); + ALL.names = [].concat(REMOTE.names).concat(NORMAL.names); + + /** + * Copyright 2013 vtt.js Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + var _objCreate = Object.create || function () { + function F() { + } + + return function (o) { + if (arguments.length !== 1) { + throw new Error('Object.create shim only accepts one parameter.'); + } + F.prototype = o; + return new F(); + }; + }(); + + // Creates a new ParserError object from an errorData object. The errorData + // object should have default code and message properties. The default message + // property can be overriden by passing in a message parameter. + // See ParsingError.Errors below for acceptable errors. + function ParsingError(errorData, message) { + this.name = "ParsingError"; + this.code = errorData.code; + this.message = message || errorData.message; + } + + ParsingError.prototype = _objCreate(Error.prototype); + ParsingError.prototype.constructor = ParsingError; + + // ParsingError metadata for acceptable ParsingErrors. + ParsingError.Errors = { + BadSignature: { + code: 0, + message: "Malformed WebVTT signature." + }, + BadTimeStamp: { + code: 1, + message: "Malformed time stamp." + } + }; + + // Try to parse input as a time stamp. + function parseTimeStamp(input) { + + function computeSeconds(h, m, s, f) { + return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000; + } + + var m = input.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/); + if (!m) { + return null; + } + + if (m[3]) { + // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds] + return computeSeconds(m[1], m[2], m[3].replace(":", ""), m[4]); + } else if (m[1] > 59) { + // Timestamp takes the form of [hours]:[minutes].[milliseconds] + // First position is hours as it's over 59. + return computeSeconds(m[1], m[2], 0, m[4]); + } else { + // Timestamp takes the form of [minutes]:[seconds].[milliseconds] + return computeSeconds(0, m[1], m[2], m[4]); + } + } + + // A settings object holds key/value pairs and will ignore anything but the first + // assignment to a specific key. + function Settings() { + this.values = _objCreate(null); + } + + Settings.prototype = { + // Only accept the first assignment to any key. + set: function set(k, v) { + if (!this.get(k) && v !== "") { + this.values[k] = v; + } + }, + // Return the value for a key, or a default value. + // If 'defaultKey' is passed then 'dflt' is assumed to be an object with + // a number of possible default values as properties where 'defaultKey' is + // the key of the property that will be chosen; otherwise it's assumed to be + // a single value. + get: function get(k, dflt, defaultKey) { + if (defaultKey) { + return this.has(k) ? this.values[k] : dflt[defaultKey]; + } + return this.has(k) ? this.values[k] : dflt; + }, + // Check whether we have a value for a key. + has: function has(k) { + return k in this.values; + }, + // Accept a setting if its one of the given alternatives. + alt: function alt(k, v, a) { + for (var n = 0; n < a.length; ++n) { + if (v === a[n]) { + this.set(k, v); + break; + } + } + }, + // Accept a setting if its a valid (signed) integer. + integer: function integer(k, v) { + if (/^-?\d+$/.test(v)) { + // integer + this.set(k, parseInt(v, 10)); + } + }, + // Accept a setting if its a valid percentage. + percent: function percent(k, v) { + var m; + if (m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/)) { + v = parseFloat(v); + if (v >= 0 && v <= 100) { + this.set(k, v); + return true; + } + } + return false; + } + }; + + // Helper function to parse input into groups separated by 'groupDelim', and + // interprete each group as a key/value pair separated by 'keyValueDelim'. + function parseOptions(input, callback, keyValueDelim, groupDelim) { + var groups = groupDelim ? input.split(groupDelim) : [input]; + for (var i in groups) { + if (typeof groups[i] !== "string") { + continue; + } + var kv = groups[i].split(keyValueDelim); + if (kv.length !== 2) { + continue; + } + var k = kv[0]; + var v = kv[1]; + callback(k, v); + } + } + + function parseCue(input, cue, regionList) { + // Remember the original input if we need to throw an error. + var oInput = input; + + // 4.1 WebVTT timestamp + function consumeTimeStamp() { + var ts = parseTimeStamp(input); + if (ts === null) { + throw new ParsingError(ParsingError.Errors.BadTimeStamp, "Malformed timestamp: " + oInput); + } + // Remove time stamp from input. + input = input.replace(/^[^\sa-zA-Z-]+/, ""); + return ts; + } + + // 4.4.2 WebVTT cue settings + function consumeCueSettings(input, cue) { + var settings = new Settings(); + + parseOptions(input, function (k, v) { + switch (k) { + case "region": + // Find the last region we parsed with the same region id. + for (var i = regionList.length - 1; i >= 0; i--) { + if (regionList[i].id === v) { + settings.set(k, regionList[i].region); + break; + } + } + break; + case "vertical": + settings.alt(k, v, ["rl", "lr"]); + break; + case "line": + var vals = v.split(","), + vals0 = vals[0]; + settings.integer(k, vals0); + settings.percent(k, vals0) ? settings.set("snapToLines", false) : null; + settings.alt(k, vals0, ["auto"]); + if (vals.length === 2) { + settings.alt("lineAlign", vals[1], ["start", "middle", "end"]); + } + break; + case "position": + vals = v.split(","); + settings.percent(k, vals[0]); + if (vals.length === 2) { + settings.alt("positionAlign", vals[1], ["start", "middle", "end"]); + } + break; + case "size": + settings.percent(k, v); + break; + case "align": + settings.alt(k, v, ["start", "middle", "end", "left", "right"]); + break; + } + }, /:/, /\s/); + + // Apply default values for any missing fields. + cue.region = settings.get("region", null); + cue.vertical = settings.get("vertical", ""); + cue.line = settings.get("line", "auto"); + cue.lineAlign = settings.get("lineAlign", "start"); + cue.snapToLines = settings.get("snapToLines", true); + cue.size = settings.get("size", 100); + cue.align = settings.get("align", "middle"); + cue.position = settings.get("position", { + start: 0, + left: 0, + middle: 50, + end: 100, + right: 100 + }, cue.align); + cue.positionAlign = settings.get("positionAlign", { + start: "start", + left: "start", + middle: "middle", + end: "end", + right: "end" + }, cue.align); + } + + function skipWhitespace() { + input = input.replace(/^\s+/, ""); + } + + // 4.1 WebVTT cue timings. + skipWhitespace(); + cue.startTime = consumeTimeStamp(); // (1) collect cue start time + skipWhitespace(); + if (input.substr(0, 3) !== "-->") { + // (3) next characters must match "-->" + throw new ParsingError(ParsingError.Errors.BadTimeStamp, "Malformed time stamp (time stamps must be separated by '-->'): " + oInput); + } + input = input.substr(3); + skipWhitespace(); + cue.endTime = consumeTimeStamp(); // (5) collect cue end time + + // 4.1 WebVTT cue settings list. + skipWhitespace(); + consumeCueSettings(input, cue); + } + + var ESCAPE = { + "&": "&", + "<": "<", + ">": ">", + "‎": "\u200E", + "‏": "\u200F", + " ": "\xA0" + }; + + var TAG_NAME = { + c: "span", + i: "i", + b: "b", + u: "u", + ruby: "ruby", + rt: "rt", + v: "span", + lang: "span" + }; + + var TAG_ANNOTATION = { + v: "title", + lang: "lang" + }; + + var NEEDS_PARENT = { + rt: "ruby" + }; + + // Parse content into a document fragment. + function parseContent(window, input) { + function nextToken() { + // Check for end-of-string. + if (!input) { + return null; + } + + // Consume 'n' characters from the input. + function consume(result) { + input = input.substr(result.length); + return result; + } + + var m = input.match(/^([^<]*)(<[^>]*>?)?/); + // If there is some text before the next tag, return it, otherwise return + // the tag. + return consume(m[1] ? m[1] : m[2]); + } + + // Unescape a string 's'. + function unescape1(e) { + return ESCAPE[e]; + } + + function unescape(s) { + while (m = s.match(/&(amp|lt|gt|lrm|rlm|nbsp);/)) { + s = s.replace(m[0], unescape1); + } + return s; + } + + function shouldAdd(current, element) { + return !NEEDS_PARENT[element.localName] || NEEDS_PARENT[element.localName] === current.localName; + } + + // Create an element for this tag. + function createElement(type, annotation) { + var tagName = TAG_NAME[type]; + if (!tagName) { + return null; + } + var element = window.document.createElement(tagName); + element.localName = tagName; + var name = TAG_ANNOTATION[type]; + if (name && annotation) { + element[name] = annotation.trim(); + } + return element; + } + + var rootDiv = window.document.createElement("div"), + current = rootDiv, + t, + tagStack = []; + + while ((t = nextToken()) !== null) { + if (t[0] === '<') { + if (t[1] === "/") { + // If the closing tag matches, move back up to the parent node. + if (tagStack.length && tagStack[tagStack.length - 1] === t.substr(2).replace(">", "")) { + tagStack.pop(); + current = current.parentNode; + } + // Otherwise just ignore the end tag. + continue; + } + var ts = parseTimeStamp(t.substr(1, t.length - 2)); + var node; + if (ts) { + // Timestamps are lead nodes as well. + node = window.document.createProcessingInstruction("timestamp", ts); + current.appendChild(node); + continue; + } + var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/); + // If we can't parse the tag, skip to the next tag. + if (!m) { + continue; + } + // Try to construct an element, and ignore the tag if we couldn't. + node = createElement(m[1], m[3]); + if (!node) { + continue; + } + // Determine if the tag should be added based on the context of where it + // is placed in the cuetext. + if (!shouldAdd(current, node)) { + continue; + } + // Set the class list (as a list of classes, separated by space). + if (m[2]) { + node.className = m[2].substr(1).replace('.', ' '); + } + // Append the node to the current node, and enter the scope of the new + // node. + tagStack.push(m[1]); + current.appendChild(node); + current = node; + continue; + } + + // Text nodes are leaf nodes. + current.appendChild(window.document.createTextNode(unescape(t))); + } + + return rootDiv; + } + + // This is a list of all the Unicode characters that have a strong + // right-to-left category. What this means is that these characters are + // written right-to-left for sure. It was generated by pulling all the strong + // right-to-left characters out of the Unicode data table. That table can + // found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt + var strongRTLRanges = [[0x5be, 0x5be], [0x5c0, 0x5c0], [0x5c3, 0x5c3], [0x5c6, 0x5c6], [0x5d0, 0x5ea], [0x5f0, 0x5f4], [0x608, 0x608], [0x60b, 0x60b], [0x60d, 0x60d], [0x61b, 0x61b], [0x61e, 0x64a], [0x66d, 0x66f], [0x671, 0x6d5], [0x6e5, 0x6e6], [0x6ee, 0x6ef], [0x6fa, 0x70d], [0x70f, 0x710], [0x712, 0x72f], [0x74d, 0x7a5], [0x7b1, 0x7b1], [0x7c0, 0x7ea], [0x7f4, 0x7f5], [0x7fa, 0x7fa], [0x800, 0x815], [0x81a, 0x81a], [0x824, 0x824], [0x828, 0x828], [0x830, 0x83e], [0x840, 0x858], [0x85e, 0x85e], [0x8a0, 0x8a0], [0x8a2, 0x8ac], [0x200f, 0x200f], [0xfb1d, 0xfb1d], [0xfb1f, 0xfb28], [0xfb2a, 0xfb36], [0xfb38, 0xfb3c], [0xfb3e, 0xfb3e], [0xfb40, 0xfb41], [0xfb43, 0xfb44], [0xfb46, 0xfbc1], [0xfbd3, 0xfd3d], [0xfd50, 0xfd8f], [0xfd92, 0xfdc7], [0xfdf0, 0xfdfc], [0xfe70, 0xfe74], [0xfe76, 0xfefc], [0x10800, 0x10805], [0x10808, 0x10808], [0x1080a, 0x10835], [0x10837, 0x10838], [0x1083c, 0x1083c], [0x1083f, 0x10855], [0x10857, 0x1085f], [0x10900, 0x1091b], [0x10920, 0x10939], [0x1093f, 0x1093f], [0x10980, 0x109b7], [0x109be, 0x109bf], [0x10a00, 0x10a00], [0x10a10, 0x10a13], [0x10a15, 0x10a17], [0x10a19, 0x10a33], [0x10a40, 0x10a47], [0x10a50, 0x10a58], [0x10a60, 0x10a7f], [0x10b00, 0x10b35], [0x10b40, 0x10b55], [0x10b58, 0x10b72], [0x10b78, 0x10b7f], [0x10c00, 0x10c48], [0x1ee00, 0x1ee03], [0x1ee05, 0x1ee1f], [0x1ee21, 0x1ee22], [0x1ee24, 0x1ee24], [0x1ee27, 0x1ee27], [0x1ee29, 0x1ee32], [0x1ee34, 0x1ee37], [0x1ee39, 0x1ee39], [0x1ee3b, 0x1ee3b], [0x1ee42, 0x1ee42], [0x1ee47, 0x1ee47], [0x1ee49, 0x1ee49], [0x1ee4b, 0x1ee4b], [0x1ee4d, 0x1ee4f], [0x1ee51, 0x1ee52], [0x1ee54, 0x1ee54], [0x1ee57, 0x1ee57], [0x1ee59, 0x1ee59], [0x1ee5b, 0x1ee5b], [0x1ee5d, 0x1ee5d], [0x1ee5f, 0x1ee5f], [0x1ee61, 0x1ee62], [0x1ee64, 0x1ee64], [0x1ee67, 0x1ee6a], [0x1ee6c, 0x1ee72], [0x1ee74, 0x1ee77], [0x1ee79, 0x1ee7c], [0x1ee7e, 0x1ee7e], [0x1ee80, 0x1ee89], [0x1ee8b, 0x1ee9b], [0x1eea1, 0x1eea3], [0x1eea5, 0x1eea9], [0x1eeab, 0x1eebb], [0x10fffd, 0x10fffd]]; + + function isStrongRTLChar(charCode) { + for (var i = 0; i < strongRTLRanges.length; i++) { + var currentRange = strongRTLRanges[i]; + if (charCode >= currentRange[0] && charCode <= currentRange[1]) { + return true; + } + } + + return false; + } + + function determineBidi(cueDiv) { + var nodeStack = [], + text = "", + charCode; + + if (!cueDiv || !cueDiv.childNodes) { + return "ltr"; + } + + function pushNodes(nodeStack, node) { + for (var i = node.childNodes.length - 1; i >= 0; i--) { + nodeStack.push(node.childNodes[i]); + } + } + + function nextTextNode(nodeStack) { + if (!nodeStack || !nodeStack.length) { + return null; + } + + var node = nodeStack.pop(), + text = node.textContent || node.innerText; + if (text) { + // TODO: This should match all unicode type B characters (paragraph + // separator characters). See issue #115. + var m = text.match(/^.*(\n|\r)/); + if (m) { + nodeStack.length = 0; + return m[0]; + } + return text; + } + if (node.tagName === "ruby") { + return nextTextNode(nodeStack); + } + if (node.childNodes) { + pushNodes(nodeStack, node); + return nextTextNode(nodeStack); + } + } + + pushNodes(nodeStack, cueDiv); + while (text = nextTextNode(nodeStack)) { + for (var i = 0; i < text.length; i++) { + charCode = text.charCodeAt(i); + if (isStrongRTLChar(charCode)) { + return "rtl"; + } + } + } + return "ltr"; + } + + function computeLinePos(cue) { + if (typeof cue.line === "number" && (cue.snapToLines || cue.line >= 0 && cue.line <= 100)) { + return cue.line; + } + if (!cue.track || !cue.track.textTrackList || !cue.track.textTrackList.mediaElement) { + return -1; + } + var track = cue.track, + trackList = track.textTrackList, + count = 0; + for (var i = 0; i < trackList.length && trackList[i] !== track; i++) { + if (trackList[i].mode === "showing") { + count++; + } + } + return ++count * -1; + } + + function StyleBox() { + } + + // Apply styles to a div. If there is no div passed then it defaults to the + // div on 'this'. + StyleBox.prototype.applyStyles = function (styles, div) { + div = div || this.div; + for (var prop in styles) { + if (styles.hasOwnProperty(prop)) { + div.style[prop] = styles[prop]; + } + } + }; + + StyleBox.prototype.formatStyle = function (val, unit) { + return val === 0 ? 0 : val + unit; + }; + + // Constructs the computed display state of the cue (a div). Places the div + // into the overlay which should be a block level element (usually a div). + function CueStyleBox(window, cue, styleOptions) { + StyleBox.call(this); + this.cue = cue; + + // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will + // have inline positioning and will function as the cue background box. + this.cueDiv = parseContent(window, cue.text); + var styles = { + color: "rgba(255, 255, 255, 1)", + backgroundColor: "rgba(0, 0, 0, 0.8)", + position: "relative", + left: 0, + right: 0, + top: 0, + bottom: 0, + display: "inline", + writingMode: cue.vertical === "" ? "horizontal-tb" : cue.vertical === "lr" ? "vertical-lr" : "vertical-rl", + unicodeBidi: "plaintext" + }; + + this.applyStyles(styles, this.cueDiv); + + // Create an absolutely positioned div that will be used to position the cue + // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS + // mirrors of them except "middle" which is "center" in CSS. + this.div = window.document.createElement("div"); + styles = { + direction: determineBidi(this.cueDiv), + writingMode: cue.vertical === "" ? "horizontal-tb" : cue.vertical === "lr" ? "vertical-lr" : "vertical-rl", + unicodeBidi: "plaintext", + textAlign: cue.align === "middle" ? "center" : cue.align, + font: styleOptions.font, + whiteSpace: "pre-line", + position: "absolute" + }; + + this.applyStyles(styles); + this.div.appendChild(this.cueDiv); + + // Calculate the distance from the reference edge of the viewport to the text + // position of the cue box. The reference edge will be resolved later when + // the box orientation styles are applied. + var textPos = 0; + switch (cue.positionAlign) { + case "start": + textPos = cue.position; + break; + case "middle": + textPos = cue.position - cue.size / 2; + break; + case "end": + textPos = cue.position - cue.size; + break; + } + + // Horizontal box orientation; textPos is the distance from the left edge of the + // area to the left edge of the box and cue.size is the distance extending to + // the right from there. + if (cue.vertical === "") { + this.applyStyles({ + left: this.formatStyle(textPos, "%"), + width: this.formatStyle(cue.size, "%") + }); + // Vertical box orientation; textPos is the distance from the top edge of the + // area to the top edge of the box and cue.size is the height extending + // downwards from there. + } else { + this.applyStyles({ + top: this.formatStyle(textPos, "%"), + height: this.formatStyle(cue.size, "%") + }); + } + + this.move = function (box) { + this.applyStyles({ + top: this.formatStyle(box.top, "px"), + bottom: this.formatStyle(box.bottom, "px"), + left: this.formatStyle(box.left, "px"), + right: this.formatStyle(box.right, "px"), + height: this.formatStyle(box.height, "px"), + width: this.formatStyle(box.width, "px") + }); + }; + } + + CueStyleBox.prototype = _objCreate(StyleBox.prototype); + CueStyleBox.prototype.constructor = CueStyleBox; + + // Represents the co-ordinates of an Element in a way that we can easily + // compute things with such as if it overlaps or intersects with another Element. + // Can initialize it with either a StyleBox or another BoxPosition. + function BoxPosition(obj) { + // Either a BoxPosition was passed in and we need to copy it, or a StyleBox + // was passed in and we need to copy the results of 'getBoundingClientRect' + // as the object returned is readonly. All co-ordinate values are in reference + // to the viewport origin (top left). + var lh, height, width, top; + if (obj.div) { + height = obj.div.offsetHeight; + width = obj.div.offsetWidth; + top = obj.div.offsetTop; + + var rects = (rects = obj.div.childNodes) && (rects = rects[0]) && rects.getClientRects && rects.getClientRects(); + obj = obj.div.getBoundingClientRect(); + // In certain cases the outter div will be slightly larger then the sum of + // the inner div's lines. This could be due to bold text, etc, on some platforms. + // In this case we should get the average line height and use that. This will + // result in the desired behaviour. + lh = rects ? Math.max(rects[0] && rects[0].height || 0, obj.height / rects.length) : 0; + } + this.left = obj.left; + this.right = obj.right; + this.top = obj.top || top; + this.height = obj.height || height; + this.bottom = obj.bottom || top + (obj.height || height); + this.width = obj.width || width; + this.lineHeight = lh !== undefined ? lh : obj.lineHeight; + } + + // Move the box along a particular axis. Optionally pass in an amount to move + // the box. If no amount is passed then the default is the line height of the + // box. + BoxPosition.prototype.move = function (axis, toMove) { + toMove = toMove !== undefined ? toMove : this.lineHeight; + switch (axis) { + case "+x": + this.left += toMove; + this.right += toMove; + break; + case "-x": + this.left -= toMove; + this.right -= toMove; + break; + case "+y": + this.top += toMove; + this.bottom += toMove; + break; + case "-y": + this.top -= toMove; + this.bottom -= toMove; + break; + } + }; + + // Check if this box overlaps another box, b2. + BoxPosition.prototype.overlaps = function (b2) { + return this.left < b2.right && this.right > b2.left && this.top < b2.bottom && this.bottom > b2.top; + }; + + // Check if this box overlaps any other boxes in boxes. + BoxPosition.prototype.overlapsAny = function (boxes) { + for (var i = 0; i < boxes.length; i++) { + if (this.overlaps(boxes[i])) { + return true; + } + } + return false; + }; + + // Check if this box is within another box. + BoxPosition.prototype.within = function (container) { + return this.top >= container.top && this.bottom <= container.bottom && this.left >= container.left && this.right <= container.right; + }; + + // Check if this box is entirely within the container or it is overlapping + // on the edge opposite of the axis direction passed. For example, if "+x" is + // passed and the box is overlapping on the left edge of the container, then + // return true. + BoxPosition.prototype.overlapsOppositeAxis = function (container, axis) { + switch (axis) { + case "+x": + return this.left < container.left; + case "-x": + return this.right > container.right; + case "+y": + return this.top < container.top; + case "-y": + return this.bottom > container.bottom; + } + }; + + // Find the percentage of the area that this box is overlapping with another + // box. + BoxPosition.prototype.intersectPercentage = function (b2) { + var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)), + y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)), + intersectArea = x * y; + return intersectArea / (this.height * this.width); + }; + + // Convert the positions from this box to CSS compatible positions using + // the reference container's positions. This has to be done because this + // box's positions are in reference to the viewport origin, whereas, CSS + // values are in referecne to their respective edges. + BoxPosition.prototype.toCSSCompatValues = function (reference) { + return { + top: this.top - reference.top, + bottom: reference.bottom - this.bottom, + left: this.left - reference.left, + right: reference.right - this.right, + height: this.height, + width: this.width + }; + }; + + // Get an object that represents the box's position without anything extra. + // Can pass a StyleBox, HTMLElement, or another BoxPositon. + BoxPosition.getSimpleBoxPosition = function (obj) { + var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0; + var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0; + var top = obj.div ? obj.div.offsetTop : obj.tagName ? obj.offsetTop : 0; + + obj = obj.div ? obj.div.getBoundingClientRect() : obj.tagName ? obj.getBoundingClientRect() : obj; + var ret = { + left: obj.left, + right: obj.right, + top: obj.top || top, + height: obj.height || height, + bottom: obj.bottom || top + (obj.height || height), + width: obj.width || width + }; + return ret; + }; + + // Move a StyleBox to its specified, or next best, position. The containerBox + // is the box that contains the StyleBox, such as a div. boxPositions are + // a list of other boxes that the styleBox can't overlap with. + function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) { + + // Find the best position for a cue box, b, on the video. The axis parameter + // is a list of axis, the order of which, it will move the box along. For example: + // Passing ["+x", "-x"] will move the box first along the x axis in the positive + // direction. If it doesn't find a good position for it there it will then move + // it along the x axis in the negative direction. + function findBestPosition(b, axis) { + var bestPosition, + specifiedPosition = new BoxPosition(b), + percentage = 1; // Highest possible so the first thing we get is better. + + for (var i = 0; i < axis.length; i++) { + while (b.overlapsOppositeAxis(containerBox, axis[i]) || b.within(containerBox) && b.overlapsAny(boxPositions)) { + b.move(axis[i]); + } + // We found a spot where we aren't overlapping anything. This is our + // best position. + if (b.within(containerBox)) { + return b; + } + var p = b.intersectPercentage(containerBox); + // If we're outside the container box less then we were on our last try + // then remember this position as the best position. + if (percentage > p) { + bestPosition = new BoxPosition(b); + percentage = p; + } + // Reset the box position to the specified position. + b = new BoxPosition(specifiedPosition); + } + return bestPosition || specifiedPosition; + } + + var boxPosition = new BoxPosition(styleBox), + cue = styleBox.cue, + linePos = computeLinePos(cue), + axis = []; + + // If we have a line number to align the cue to. + if (cue.snapToLines) { + var size; + switch (cue.vertical) { + case "": + axis = ["+y", "-y"]; + size = "height"; + break; + case "rl": + axis = ["+x", "-x"]; + size = "width"; + break; + case "lr": + axis = ["-x", "+x"]; + size = "width"; + break; + } + + var step = boxPosition.lineHeight, + position = step * Math.round(linePos), + maxPosition = containerBox[size] + step, + initialAxis = axis[0]; + + // If the specified intial position is greater then the max position then + // clamp the box to the amount of steps it would take for the box to + // reach the max position. + if (Math.abs(position) > maxPosition) { + position = position < 0 ? -1 : 1; + position *= Math.ceil(maxPosition / step) * step; + } + + // If computed line position returns negative then line numbers are + // relative to the bottom of the video instead of the top. Therefore, we + // need to increase our initial position by the length or width of the + // video, depending on the writing direction, and reverse our axis directions. + if (linePos < 0) { + position += cue.vertical === "" ? containerBox.height : containerBox.width; + axis = axis.reverse(); + } + + // Move the box to the specified position. This may not be its best + // position. + boxPosition.move(initialAxis, position); + } else { + // If we have a percentage line value for the cue. + var calculatedPercentage = boxPosition.lineHeight / containerBox.height * 100; + + switch (cue.lineAlign) { + case "middle": + linePos -= calculatedPercentage / 2; + break; + case "end": + linePos -= calculatedPercentage; + break; + } + + // Apply initial line position to the cue box. + switch (cue.vertical) { + case "": + styleBox.applyStyles({ + top: styleBox.formatStyle(linePos, "%") + }); + break; + case "rl": + styleBox.applyStyles({ + left: styleBox.formatStyle(linePos, "%") + }); + break; + case "lr": + styleBox.applyStyles({ + right: styleBox.formatStyle(linePos, "%") + }); + break; + } + + axis = ["+y", "-x", "+x", "-y"]; + + // Get the box position again after we've applied the specified positioning + // to it. + boxPosition = new BoxPosition(styleBox); + } + + var bestPosition = findBestPosition(boxPosition, axis); + styleBox.move(bestPosition.toCSSCompatValues(containerBox)); + } + + function WebVTT$1() { + } + + // Nothing + + + // Helper to allow strings to be decoded instead of the default binary utf8 data. + WebVTT$1.StringDecoder = function () { + return { + decode: function decode(data) { + if (!data) { + return ""; + } + if (typeof data !== "string") { + throw new Error("Error - expected string data."); + } + return decodeURIComponent(encodeURIComponent(data)); + } + }; + }; + + WebVTT$1.convertCueToDOMTree = function (window, cuetext) { + if (!window || !cuetext) { + return null; + } + return parseContent(window, cuetext); + }; + + var FONT_SIZE_PERCENT = 0.05; + var FONT_STYLE = "sans-serif"; + var CUE_BACKGROUND_PADDING = "1.5%"; + + // Runs the processing model over the cues and regions passed to it. + // @param overlay A block level element (usually a div) that the computed cues + // and regions will be placed into. + WebVTT$1.processCues = function (window, cues, overlay) { + if (!window || !cues || !overlay) { + return null; + } + + // Remove all previous children. + while (overlay.firstChild) { + overlay.removeChild(overlay.firstChild); + } + + var paddedOverlay = window.document.createElement("div"); + paddedOverlay.style.position = "absolute"; + paddedOverlay.style.left = "0"; + paddedOverlay.style.right = "0"; + paddedOverlay.style.top = "0"; + paddedOverlay.style.bottom = "0"; + paddedOverlay.style.margin = CUE_BACKGROUND_PADDING; + overlay.appendChild(paddedOverlay); + + // Determine if we need to compute the display states of the cues. This could + // be the case if a cue's state has been changed since the last computation or + // if it has not been computed yet. + function shouldCompute(cues) { + for (var i = 0; i < cues.length; i++) { + if (cues[i].hasBeenReset || !cues[i].displayState) { + return true; + } + } + return false; + } + + // We don't need to recompute the cues' display states. Just reuse them. + if (!shouldCompute(cues)) { + for (var i = 0; i < cues.length; i++) { + paddedOverlay.appendChild(cues[i].displayState); + } + return; + } + + var boxPositions = [], + containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay), + fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100; + var styleOptions = { + font: fontSize + "px " + FONT_STYLE + }; + + (function () { + var styleBox, cue; + + for (var i = 0; i < cues.length; i++) { + cue = cues[i]; + + // Compute the intial position and styles of the cue div. + styleBox = new CueStyleBox(window, cue, styleOptions); + paddedOverlay.appendChild(styleBox.div); + + // Move the cue div to it's correct line position. + moveBoxToLinePosition(window, styleBox, containerBox, boxPositions); + + // Remember the computed div so that we don't have to recompute it later + // if we don't have too. + cue.displayState = styleBox.div; + + boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox)); + } + })(); + }; + + WebVTT$1.Parser = function (window, vttjs, decoder) { + if (!decoder) { + decoder = vttjs; + vttjs = {}; + } + if (!vttjs) { + vttjs = {}; + } + + this.window = window; + this.vttjs = vttjs; + this.state = "INITIAL"; + this.buffer = ""; + this.decoder = decoder || new TextDecoder("utf8"); + this.regionList = []; + }; + + WebVTT$1.Parser.prototype = { + // If the error is a ParsingError then report it to the consumer if + // possible. If it's not a ParsingError then throw it like normal. + reportOrThrowError: function reportOrThrowError(e) { + if (e instanceof ParsingError) { + this.onparsingerror && this.onparsingerror(e); + } else { + throw e; + } + }, + parse: function parse(data) { + var self = this; + + // If there is no data then we won't decode it, but will just try to parse + // whatever is in buffer already. This may occur in circumstances, for + // example when flush() is called. + if (data) { + // Try to decode the data that we received. + self.buffer += self.decoder.decode(data, {stream: true}); + } + + function collectNextLine() { + var buffer = self.buffer; + var pos = 0; + while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') { + ++pos; + } + var line = buffer.substr(0, pos); + // Advance the buffer early in case we fail below. + if (buffer[pos] === '\r') { + ++pos; + } + if (buffer[pos] === '\n') { + ++pos; + } + self.buffer = buffer.substr(pos); + return line; + } + + // 3.4 WebVTT region and WebVTT region settings syntax + function parseRegion(input) { + var settings = new Settings(); + + parseOptions(input, function (k, v) { + switch (k) { + case "id": + settings.set(k, v); + break; + case "width": + settings.percent(k, v); + break; + case "lines": + settings.integer(k, v); + break; + case "regionanchor": + case "viewportanchor": + var xy = v.split(','); + if (xy.length !== 2) { + break; + } + // We have to make sure both x and y parse, so use a temporary + // settings object here. + var anchor = new Settings(); + anchor.percent("x", xy[0]); + anchor.percent("y", xy[1]); + if (!anchor.has("x") || !anchor.has("y")) { + break; + } + settings.set(k + "X", anchor.get("x")); + settings.set(k + "Y", anchor.get("y")); + break; + case "scroll": + settings.alt(k, v, ["up"]); + break; + } + }, /=/, /\s/); + + // Create the region, using default values for any values that were not + // specified. + if (settings.has("id")) { + var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)(); + region.width = settings.get("width", 100); + region.lines = settings.get("lines", 3); + region.regionAnchorX = settings.get("regionanchorX", 0); + region.regionAnchorY = settings.get("regionanchorY", 100); + region.viewportAnchorX = settings.get("viewportanchorX", 0); + region.viewportAnchorY = settings.get("viewportanchorY", 100); + region.scroll = settings.get("scroll", ""); + // Register the region. + self.onregion && self.onregion(region); + // Remember the VTTRegion for later in case we parse any VTTCues that + // reference it. + self.regionList.push({ + id: settings.get("id"), + region: region + }); + } + } + + // draft-pantos-http-live-streaming-20 + // https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-3.5 + // 3.5 WebVTT + function parseTimestampMap(input) { + var settings = new Settings(); + + parseOptions(input, function (k, v) { + switch (k) { + case "MPEGT": + settings.integer(k + 'S', v); + break; + case "LOCA": + settings.set(k + 'L', parseTimeStamp(v)); + break; + } + }, /[^\d]:/, /,/); + + self.ontimestampmap && self.ontimestampmap({ + "MPEGTS": settings.get("MPEGTS"), + "LOCAL": settings.get("LOCAL") + }); + } + + // 3.2 WebVTT metadata header syntax + function parseHeader(input) { + if (input.match(/X-TIMESTAMP-MAP/)) { + // This line contains HLS X-TIMESTAMP-MAP metadata + parseOptions(input, function (k, v) { + switch (k) { + case "X-TIMESTAMP-MAP": + parseTimestampMap(v); + break; + } + }, /=/); + } else { + parseOptions(input, function (k, v) { + switch (k) { + case "Region": + // 3.3 WebVTT region metadata header syntax + parseRegion(v); + break; + } + }, /:/); + } + } + + // 5.1 WebVTT file parsing. + try { + var line; + if (self.state === "INITIAL") { + // We can't start parsing until we have the first line. + if (!/\r\n|\n/.test(self.buffer)) { + return this; + } + + line = collectNextLine(); + + var m = line.match(/^WEBVTT([ \t].*)?$/); + if (!m || !m[0]) { + throw new ParsingError(ParsingError.Errors.BadSignature); + } + + self.state = "HEADER"; + } + + var alreadyCollectedLine = false; + while (self.buffer) { + // We can't parse a line until we have the full line. + if (!/\r\n|\n/.test(self.buffer)) { + return this; + } + + if (!alreadyCollectedLine) { + line = collectNextLine(); + } else { + alreadyCollectedLine = false; + } + + switch (self.state) { + case "HEADER": + // 13-18 - Allow a header (metadata) under the WEBVTT line. + if (/:/.test(line)) { + parseHeader(line); + } else if (!line) { + // An empty line terminates the header and starts the body (cues). + self.state = "ID"; + } + continue; + case "NOTE": + // Ignore NOTE blocks. + if (!line) { + self.state = "ID"; + } + continue; + case "ID": + // Check for the start of NOTE blocks. + if (/^NOTE($|[ \t])/.test(line)) { + self.state = "NOTE"; + break; + } + // 19-29 - Allow any number of line terminators, then initialize new cue values. + if (!line) { + continue; + } + self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, ""); + self.state = "CUE"; + // 30-39 - Check if self line contains an optional identifier or timing data. + if (line.indexOf("-->") === -1) { + self.cue.id = line; + continue; + } + // Process line as start of a cue. + /*falls through*/ + case "CUE": + // 40 - Collect cue timings and settings. + try { + parseCue(line, self.cue, self.regionList); + } catch (e) { + self.reportOrThrowError(e); + // In case of an error ignore rest of the cue. + self.cue = null; + self.state = "BADCUE"; + continue; + } + self.state = "CUETEXT"; + continue; + case "CUETEXT": + var hasSubstring = line.indexOf("-->") !== -1; + // 34 - If we have an empty line then report the cue. + // 35 - If we have the special substring '-->' then report the cue, + // but do not collect the line as we need to process the current + // one as a new cue. + if (!line || hasSubstring && (alreadyCollectedLine = true)) { + // We are done parsing self cue. + self.oncue && self.oncue(self.cue); + self.cue = null; + self.state = "ID"; + continue; + } + if (self.cue.text) { + self.cue.text += "\n"; + } + self.cue.text += line; + continue; + case "BADCUE": + // BADCUE + // 54-62 - Collect and discard the remaining cue. + if (!line) { + self.state = "ID"; + } + continue; + } + } + } catch (e) { + self.reportOrThrowError(e); + + // If we are currently parsing a cue, report what we have. + if (self.state === "CUETEXT" && self.cue && self.oncue) { + self.oncue(self.cue); + } + self.cue = null; + // Enter BADWEBVTT state if header was not parsed correctly otherwise + // another exception occurred so enter BADCUE state. + self.state = self.state === "INITIAL" ? "BADWEBVTT" : "BADCUE"; + } + return this; + }, + flush: function flush() { + var self = this; + try { + // Finish decoding the stream. + self.buffer += self.decoder.decode(); + // Synthesize the end of the current cue or region. + if (self.cue || self.state === "HEADER") { + self.buffer += "\n\n"; + self.parse(); + } + // If we've flushed, parsed, and we're still on the INITIAL state then + // that means we don't have enough of the stream to parse the first + // line. + if (self.state === "INITIAL") { + throw new ParsingError(ParsingError.Errors.BadSignature); + } + } catch (e) { + self.reportOrThrowError(e); + } + self.onflush && self.onflush(); + return this; + } + }; + + var vtt = WebVTT$1; + + var vtt$1 = /*#__PURE__*/Object.freeze({ + default: vtt, + __moduleExports: vtt + }); + + /** + * Copyright 2013 vtt.js Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var autoKeyword = "auto"; + var directionSetting = { + "": 1, + "lr": 1, + "rl": 1 + }; + var alignSetting = { + "start": 1, + "middle": 1, + "end": 1, + "left": 1, + "right": 1 + }; + + function findDirectionSetting(value) { + if (typeof value !== "string") { + return false; + } + var dir = directionSetting[value.toLowerCase()]; + return dir ? value.toLowerCase() : false; + } + + function findAlignSetting(value) { + if (typeof value !== "string") { + return false; + } + var align = alignSetting[value.toLowerCase()]; + return align ? value.toLowerCase() : false; + } + + function VTTCue(startTime, endTime, text) { + /** + * Shim implementation specific properties. These properties are not in + * the spec. + */ + + // Lets us know when the VTTCue's data has changed in such a way that we need + // to recompute its display state. This lets us compute its display state + // lazily. + this.hasBeenReset = false; + + /** + * VTTCue and TextTrackCue properties + * http://dev.w3.org/html5/webvtt/#vttcue-interface + */ + + var _id = ""; + var _pauseOnExit = false; + var _startTime = startTime; + var _endTime = endTime; + var _text = text; + var _region = null; + var _vertical = ""; + var _snapToLines = true; + var _line = "auto"; + var _lineAlign = "start"; + var _position = 50; + var _positionAlign = "middle"; + var _size = 50; + var _align = "middle"; + + Object.defineProperties(this, { + "id": { + enumerable: true, + get: function get() { + return _id; + }, + set: function set(value) { + _id = "" + value; + } + }, + + "pauseOnExit": { + enumerable: true, + get: function get() { + return _pauseOnExit; + }, + set: function set(value) { + _pauseOnExit = !!value; + } + }, + + "startTime": { + enumerable: true, + get: function get() { + return _startTime; + }, + set: function set(value) { + if (typeof value !== "number") { + throw new TypeError("Start time must be set to a number."); + } + _startTime = value; + this.hasBeenReset = true; + } + }, + + "endTime": { + enumerable: true, + get: function get() { + return _endTime; + }, + set: function set(value) { + if (typeof value !== "number") { + throw new TypeError("End time must be set to a number."); + } + _endTime = value; + this.hasBeenReset = true; + } + }, + + "text": { + enumerable: true, + get: function get() { + return _text; + }, + set: function set(value) { + _text = "" + value; + this.hasBeenReset = true; + } + }, + + "region": { + enumerable: true, + get: function get() { + return _region; + }, + set: function set(value) { + _region = value; + this.hasBeenReset = true; + } + }, + + "vertical": { + enumerable: true, + get: function get() { + return _vertical; + }, + set: function set(value) { + var setting = findDirectionSetting(value); + // Have to check for false because the setting an be an empty string. + if (setting === false) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _vertical = setting; + this.hasBeenReset = true; + } + }, + + "snapToLines": { + enumerable: true, + get: function get() { + return _snapToLines; + }, + set: function set(value) { + _snapToLines = !!value; + this.hasBeenReset = true; + } + }, + + "line": { + enumerable: true, + get: function get() { + return _line; + }, + set: function set(value) { + if (typeof value !== "number" && value !== autoKeyword) { + throw new SyntaxError("An invalid number or illegal string was specified."); + } + _line = value; + this.hasBeenReset = true; + } + }, + + "lineAlign": { + enumerable: true, + get: function get() { + return _lineAlign; + }, + set: function set(value) { + var setting = findAlignSetting(value); + if (!setting) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _lineAlign = setting; + this.hasBeenReset = true; + } + }, + + "position": { + enumerable: true, + get: function get() { + return _position; + }, + set: function set(value) { + if (value < 0 || value > 100) { + throw new Error("Position must be between 0 and 100."); + } + _position = value; + this.hasBeenReset = true; + } + }, + + "positionAlign": { + enumerable: true, + get: function get() { + return _positionAlign; + }, + set: function set(value) { + var setting = findAlignSetting(value); + if (!setting) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _positionAlign = setting; + this.hasBeenReset = true; + } + }, + + "size": { + enumerable: true, + get: function get() { + return _size; + }, + set: function set(value) { + if (value < 0 || value > 100) { + throw new Error("Size must be between 0 and 100."); + } + _size = value; + this.hasBeenReset = true; + } + }, + + "align": { + enumerable: true, + get: function get() { + return _align; + }, + set: function set(value) { + var setting = findAlignSetting(value); + if (!setting) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _align = setting; + this.hasBeenReset = true; + } + } + }); + + /** + * Other <track> spec defined properties + */ + + // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state + this.displayState = undefined; + } + + /** + * VTTCue methods + */ + + VTTCue.prototype.getCueAsHTML = function () { + // Assume WebVTT.convertCueToDOMTree is on the global. + return WebVTT.convertCueToDOMTree(window, this.text); + }; + + var vttcue = VTTCue; + + var vttcue$1 = /*#__PURE__*/Object.freeze({ + default: vttcue, + __moduleExports: vttcue + }); + + /** + * Copyright 2013 vtt.js Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var scrollSetting = { + "": true, + "up": true + }; + + function findScrollSetting(value) { + if (typeof value !== "string") { + return false; + } + var scroll = scrollSetting[value.toLowerCase()]; + return scroll ? value.toLowerCase() : false; + } + + function isValidPercentValue(value) { + return typeof value === "number" && value >= 0 && value <= 100; + } + + // VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface + function VTTRegion() { + var _width = 100; + var _lines = 3; + var _regionAnchorX = 0; + var _regionAnchorY = 100; + var _viewportAnchorX = 0; + var _viewportAnchorY = 100; + var _scroll = ""; + + Object.defineProperties(this, { + "width": { + enumerable: true, + get: function get() { + return _width; + }, + set: function set(value) { + if (!isValidPercentValue(value)) { + throw new Error("Width must be between 0 and 100."); + } + _width = value; + } + }, + "lines": { + enumerable: true, + get: function get() { + return _lines; + }, + set: function set(value) { + if (typeof value !== "number") { + throw new TypeError("Lines must be set to a number."); + } + _lines = value; + } + }, + "regionAnchorY": { + enumerable: true, + get: function get() { + return _regionAnchorY; + }, + set: function set(value) { + if (!isValidPercentValue(value)) { + throw new Error("RegionAnchorX must be between 0 and 100."); + } + _regionAnchorY = value; + } + }, + "regionAnchorX": { + enumerable: true, + get: function get() { + return _regionAnchorX; + }, + set: function set(value) { + if (!isValidPercentValue(value)) { + throw new Error("RegionAnchorY must be between 0 and 100."); + } + _regionAnchorX = value; + } + }, + "viewportAnchorY": { + enumerable: true, + get: function get() { + return _viewportAnchorY; + }, + set: function set(value) { + if (!isValidPercentValue(value)) { + throw new Error("ViewportAnchorY must be between 0 and 100."); + } + _viewportAnchorY = value; + } + }, + "viewportAnchorX": { + enumerable: true, + get: function get() { + return _viewportAnchorX; + }, + set: function set(value) { + if (!isValidPercentValue(value)) { + throw new Error("ViewportAnchorX must be between 0 and 100."); + } + _viewportAnchorX = value; + } + }, + "scroll": { + enumerable: true, + get: function get() { + return _scroll; + }, + set: function set(value) { + var setting = findScrollSetting(value); + // Have to check for false as an empty string is a legal value. + if (setting === false) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _scroll = setting; + } + } + }); + } + + var vttregion = VTTRegion; + + var vttregion$1 = /*#__PURE__*/Object.freeze({ + default: vttregion, + __moduleExports: vttregion + }); + + var require$$0 = (vtt$1 && vtt) || vtt$1; + + var require$$1 = (vttcue$1 && vttcue) || vttcue$1; + + var require$$2 = (vttregion$1 && vttregion) || vttregion$1; + + var browserIndex = createCommonjsModule(function (module) { + /** + * Copyright 2013 vtt.js Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // Default exports for Node. Export the extended versions of VTTCue and + // VTTRegion in Node since we likely want the capability to convert back and + // forth between JSON. If we don't then it's not that big of a deal since we're + // off browser. + + + var vttjs = module.exports = { + WebVTT: require$$0, + VTTCue: require$$1, + VTTRegion: require$$2 + }; + + window_1.vttjs = vttjs; + window_1.WebVTT = vttjs.WebVTT; + + var cueShim = vttjs.VTTCue; + var regionShim = vttjs.VTTRegion; + var nativeVTTCue = window_1.VTTCue; + var nativeVTTRegion = window_1.VTTRegion; + + vttjs.shim = function () { + window_1.VTTCue = cueShim; + window_1.VTTRegion = regionShim; + }; + + vttjs.restore = function () { + window_1.VTTCue = nativeVTTCue; + window_1.VTTRegion = nativeVTTRegion; + }; + + if (!window_1.VTTCue) { + vttjs.shim(); + } + }); + var browserIndex_1 = browserIndex.WebVTT; + var browserIndex_2 = browserIndex.VTTCue; + var browserIndex_3 = browserIndex.VTTRegion; + + /** + * @file tech.js + */ + + /** + * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string + * that just contains the src url alone. + * * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};` + * `var SourceString = 'http://example.com/some-video.mp4';` + * + * @typedef {Object|string} Tech~SourceObject + * + * @property {string} src + * The url to the source + * + * @property {string} type + * The mime type of the source + */ + + /** + * A function used by {@link Tech} to create a new {@link TextTrack}. + * + * @private + * + * @param {Tech} self + * An instance of the Tech class. + * + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track + * + * @param {string} [language] + * Two letter language abbreviation + * + * @param {Object} [options={}] + * An object with additional text track options + * + * @return {TextTrack} + * The text track that was created. + */ + function createTrackHelper(self, kind, label, language) { + var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + + var tracks = self.textTracks(); + + options.kind = kind; + + if (label) { + options.label = label; + } + if (language) { + options.language = language; + } + options.tech = self; + + var track = new ALL.text.TrackClass(options); + + tracks.addTrack(track); + + return track; + } + + /** + * This is the base class for media playback technology controllers, such as + * {@link Flash} and {@link HTML5} + * + * @extends Component + */ + + var Tech = function (_Component) { + inherits(Tech, _Component); + + /** + * Create an instance of this Tech. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} ready + * Callback function to call when the `HTML5` Tech is ready. + */ + function Tech() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var ready = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () { + }; + classCallCheck(this, Tech); + + // we don't want the tech to report user activity automatically. + // This is done manually in addControlsListeners + options.reportTouchActivity = false; + + // keep track of whether the current source has played at all to + // implement a very limited played() + var _this = possibleConstructorReturn(this, _Component.call(this, null, options, ready)); + + _this.hasStarted_ = false; + _this.on('playing', function () { + this.hasStarted_ = true; + }); + _this.on('loadstart', function () { + this.hasStarted_ = false; + }); + + ALL.names.forEach(function (name) { + var props = ALL[name]; + + if (options && options[props.getterName]) { + _this[props.privateName] = options[props.getterName]; + } + }); + + // Manually track progress in cases where the browser/flash player doesn't report it. + if (!_this.featuresProgressEvents) { + _this.manualProgressOn(); + } + + // Manually track timeupdates in cases where the browser/flash player doesn't report it. + if (!_this.featuresTimeupdateEvents) { + _this.manualTimeUpdatesOn(); + } + + ['Text', 'Audio', 'Video'].forEach(function (track) { + if (options['native' + track + 'Tracks'] === false) { + _this['featuresNative' + track + 'Tracks'] = false; + } + }); + + if (options.nativeCaptions === false || options.nativeTextTracks === false) { + _this.featuresNativeTextTracks = false; + } else if (options.nativeCaptions === true || options.nativeTextTracks === true) { + _this.featuresNativeTextTracks = true; + } + + if (!_this.featuresNativeTextTracks) { + _this.emulateTextTracks(); + } + + _this.autoRemoteTextTracks_ = new ALL.text.ListClass(); + + _this.initTrackListeners(); + + // Turn on component tap events only if not using native controls + if (!options.nativeControlsForTouch) { + _this.emitTapEvents(); + } + + if (_this.constructor) { + _this.name_ = _this.constructor.name || 'Unknown Tech'; + } + return _this; + } + + /** + * A special function to trigger source set in a way that will allow player + * to re-trigger if the player or tech are not ready yet. + * + * @fires Tech#sourceset + * @param {string} src The source string at the time of the source changing. + */ + + + Tech.prototype.triggerSourceset = function triggerSourceset(src) { + var _this2 = this; + + if (!this.isReady_) { + // on initial ready we have to trigger source set + // 1ms after ready so that player can watch for it. + this.one('ready', function () { + return _this2.setTimeout(function () { + return _this2.triggerSourceset(src); + }, 1); + }); + } + + /** + * Fired when the source is set on the tech causing the media element + * to reload. + * + * @see {@link Player#event:sourceset} + * @event Tech#sourceset + * @type {EventTarget~Event} + */ + this.trigger({ + src: src, + type: 'sourceset' + }); + }; + + /* Fallbacks for unsupported event types + ================================================================================ */ + + /** + * Polyfill the `progress` event for browsers that don't support it natively. + * + * @see {@link Tech#trackProgress} + */ + + + Tech.prototype.manualProgressOn = function manualProgressOn() { + this.on('durationchange', this.onDurationChange); + + this.manualProgress = true; + + // Trigger progress watching when a source begins loading + this.one('ready', this.trackProgress); + }; + + /** + * Turn off the polyfill for `progress` events that was created in + * {@link Tech#manualProgressOn} + */ + + + Tech.prototype.manualProgressOff = function manualProgressOff() { + this.manualProgress = false; + this.stopTrackingProgress(); + + this.off('durationchange', this.onDurationChange); + }; + + /** + * This is used to trigger a `progress` event when the buffered percent changes. It + * sets an interval function that will be called every 500 milliseconds to check if the + * buffer end percent has changed. + * + * > This function is called by {@link Tech#manualProgressOn} + * + * @param {EventTarget~Event} event + * The `ready` event that caused this to run. + * + * @listens Tech#ready + * @fires Tech#progress + */ + + + Tech.prototype.trackProgress = function trackProgress(event) { + this.stopTrackingProgress(); + this.progressInterval = this.setInterval(bind(this, function () { + // Don't trigger unless buffered amount is greater than last time + + var numBufferedPercent = this.bufferedPercent(); + + if (this.bufferedPercent_ !== numBufferedPercent) { + /** + * See {@link Player#progress} + * + * @event Tech#progress + * @type {EventTarget~Event} + */ + this.trigger('progress'); + } + + this.bufferedPercent_ = numBufferedPercent; + + if (numBufferedPercent === 1) { + this.stopTrackingProgress(); + } + }), 500); + }; + + /** + * Update our internal duration on a `durationchange` event by calling + * {@link Tech#duration}. + * + * @param {EventTarget~Event} event + * The `durationchange` event that caused this to run. + * + * @listens Tech#durationchange + */ + + + Tech.prototype.onDurationChange = function onDurationChange(event) { + this.duration_ = this.duration(); + }; + + /** + * Get and create a `TimeRange` object for buffering. + * + * @return {TimeRange} + * The time range object that was created. + */ + + + Tech.prototype.buffered = function buffered() { + return createTimeRanges(0, 0); + }; + + /** + * Get the percentage of the current video that is currently buffered. + * + * @return {number} + * A number from 0 to 1 that represents the decimal percentage of the + * video that is buffered. + * + */ + + + Tech.prototype.bufferedPercent = function bufferedPercent$$1() { + return bufferedPercent(this.buffered(), this.duration_); + }; + + /** + * Turn off the polyfill for `progress` events that was created in + * {@link Tech#manualProgressOn} + * Stop manually tracking progress events by clearing the interval that was set in + * {@link Tech#trackProgress}. + */ + + + Tech.prototype.stopTrackingProgress = function stopTrackingProgress() { + this.clearInterval(this.progressInterval); + }; + + /** + * Polyfill the `timeupdate` event for browsers that don't support it. + * + * @see {@link Tech#trackCurrentTime} + */ + + + Tech.prototype.manualTimeUpdatesOn = function manualTimeUpdatesOn() { + this.manualTimeUpdates = true; + + this.on('play', this.trackCurrentTime); + this.on('pause', this.stopTrackingCurrentTime); + }; + + /** + * Turn off the polyfill for `timeupdate` events that was created in + * {@link Tech#manualTimeUpdatesOn} + */ + + + Tech.prototype.manualTimeUpdatesOff = function manualTimeUpdatesOff() { + this.manualTimeUpdates = false; + this.stopTrackingCurrentTime(); + this.off('play', this.trackCurrentTime); + this.off('pause', this.stopTrackingCurrentTime); + }; + + /** + * Sets up an interval function to track current time and trigger `timeupdate` every + * 250 milliseconds. + * + * @listens Tech#play + * @triggers Tech#timeupdate + */ + + + Tech.prototype.trackCurrentTime = function trackCurrentTime() { + if (this.currentTimeInterval) { + this.stopTrackingCurrentTime(); + } + this.currentTimeInterval = this.setInterval(function () { + /** + * Triggered at an interval of 250ms to indicated that time is passing in the video. + * + * @event Tech#timeupdate + * @type {EventTarget~Event} + */ + this.trigger({type: 'timeupdate', target: this, manuallyTriggered: true}); + + // 42 = 24 fps // 250 is what Webkit uses // FF uses 15 + }, 250); + }; + + /** + * Stop the interval function created in {@link Tech#trackCurrentTime} so that the + * `timeupdate` event is no longer triggered. + * + * @listens {Tech#pause} + */ + + + Tech.prototype.stopTrackingCurrentTime = function stopTrackingCurrentTime() { + this.clearInterval(this.currentTimeInterval); + + // #1002 - if the video ends right before the next timeupdate would happen, + // the progress bar won't make it all the way to the end + this.trigger({type: 'timeupdate', target: this, manuallyTriggered: true}); + }; + + /** + * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList}, + * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech. + * + * @fires Component#dispose + */ + + + Tech.prototype.dispose = function dispose() { + + // clear out all tracks because we can't reuse them between techs + this.clearTracks(NORMAL.names); + + // Turn off any manual progress or timeupdate tracking + if (this.manualProgress) { + this.manualProgressOff(); + } + + if (this.manualTimeUpdates) { + this.manualTimeUpdatesOff(); + } + + _Component.prototype.dispose.call(this); + }; + + /** + * Clear out a single `TrackList` or an array of `TrackLists` given their names. + * + * > Note: Techs without source handlers should call this between sources for `video` + * & `audio` tracks. You don't want to use them between tracks! + * + * @param {string[]|string} types + * TrackList names to clear, valid names are `video`, `audio`, and + * `text`. + */ + + + Tech.prototype.clearTracks = function clearTracks(types) { + var _this3 = this; + + types = [].concat(types); + // clear out all tracks because we can't reuse them between techs + types.forEach(function (type) { + var list = _this3[type + 'Tracks']() || []; + var i = list.length; + + while (i--) { + var track = list[i]; + + if (type === 'text') { + _this3.removeRemoteTextTrack(track); + } + list.removeTrack(track); + } + }); + }; + + /** + * Remove any TextTracks added via addRemoteTextTrack that are + * flagged for automatic garbage collection + */ + + + Tech.prototype.cleanupAutoTextTracks = function cleanupAutoTextTracks() { + var list = this.autoRemoteTextTracks_ || []; + var i = list.length; + + while (i--) { + var track = list[i]; + + this.removeRemoteTextTrack(track); + } + }; + + /** + * Reset the tech, which will removes all sources and reset the internal readyState. + * + * @abstract + */ + + + Tech.prototype.reset = function reset() { + }; + + /** + * Get or set an error on the Tech. + * + * @param {MediaError} [err] + * Error to set on the Tech + * + * @return {MediaError|null} + * The current error object on the tech, or null if there isn't one. + */ + + + Tech.prototype.error = function error(err) { + if (err !== undefined) { + this.error_ = new MediaError(err); + this.trigger('error'); + } + return this.error_; + }; + + /** + * Returns the `TimeRange`s that have been played through for the current source. + * + * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`. + * It only checks whether the source has played at all or not. + * + * @return {TimeRange} + * - A single time range if this video has played + * - An empty set of ranges if not. + */ + + + Tech.prototype.played = function played() { + if (this.hasStarted_) { + return createTimeRanges(0, 0); + } + return createTimeRanges(); + }; + + /** + * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was + * previously called. + * + * @fires Tech#timeupdate + */ + + + Tech.prototype.setCurrentTime = function setCurrentTime() { + // improve the accuracy of manual timeupdates + if (this.manualTimeUpdates) { + /** + * A manual `timeupdate` event. + * + * @event Tech#timeupdate + * @type {EventTarget~Event} + */ + this.trigger({type: 'timeupdate', target: this, manuallyTriggered: true}); + } + }; + + /** + * Turn on listeners for {@link VideoTrackList}, {@link {AudioTrackList}, and + * {@link TextTrackList} events. + * + * This adds {@link EventTarget~EventListeners} for `addtrack`, and `removetrack`. + * + * @fires Tech#audiotrackchange + * @fires Tech#videotrackchange + * @fires Tech#texttrackchange + */ + + + Tech.prototype.initTrackListeners = function initTrackListeners() { + var _this4 = this; + + /** + * Triggered when tracks are added or removed on the Tech {@link AudioTrackList} + * + * @event Tech#audiotrackchange + * @type {EventTarget~Event} + */ + + /** + * Triggered when tracks are added or removed on the Tech {@link VideoTrackList} + * + * @event Tech#videotrackchange + * @type {EventTarget~Event} + */ + + /** + * Triggered when tracks are added or removed on the Tech {@link TextTrackList} + * + * @event Tech#texttrackchange + * @type {EventTarget~Event} + */ + NORMAL.names.forEach(function (name) { + var props = NORMAL[name]; + var trackListChanges = function trackListChanges() { + _this4.trigger(name + 'trackchange'); + }; + + var tracks = _this4[props.getterName](); + + tracks.addEventListener('removetrack', trackListChanges); + tracks.addEventListener('addtrack', trackListChanges); + + _this4.on('dispose', function () { + tracks.removeEventListener('removetrack', trackListChanges); + tracks.removeEventListener('addtrack', trackListChanges); + }); + }); + }; + + /** + * Emulate TextTracks using vtt.js if necessary + * + * @fires Tech#vttjsloaded + * @fires Tech#vttjserror + */ + + + Tech.prototype.addWebVttScript_ = function addWebVttScript_() { + var _this5 = this; + + if (window_1.WebVTT) { + return; + } + + // Initially, Tech.el_ is a child of a dummy-div wait until the Component system + // signals that the Tech is ready at which point Tech.el_ is part of the DOM + // before inserting the WebVTT script + if (document_1.body.contains(this.el())) { + + // load via require if available and vtt.js script location was not passed in + // as an option. novtt builds will turn the above require call into an empty object + // which will cause this if check to always fail. + if (!this.options_['vtt.js'] && isPlain(browserIndex) && Object.keys(browserIndex).length > 0) { + this.trigger('vttjsloaded'); + return; + } + + // load vtt.js via the script location option or the cdn of no location was + // passed in + var script = document_1.createElement('script'); + + script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.14.1/vtt.min.js'; + script.onload = function () { + /** + * Fired when vtt.js is loaded. + * + * @event Tech#vttjsloaded + * @type {EventTarget~Event} + */ + _this5.trigger('vttjsloaded'); + }; + script.onerror = function () { + /** + * Fired when vtt.js was not loaded due to an error + * + * @event Tech#vttjsloaded + * @type {EventTarget~Event} + */ + _this5.trigger('vttjserror'); + }; + this.on('dispose', function () { + script.onload = null; + script.onerror = null; + }); + // but have not loaded yet and we set it to true before the inject so that + // we don't overwrite the injected window.WebVTT if it loads right away + window_1.WebVTT = true; + this.el().parentNode.appendChild(script); + } else { + this.ready(this.addWebVttScript_); + } + }; + + /** + * Emulate texttracks + * + */ + + + Tech.prototype.emulateTextTracks = function emulateTextTracks() { + var _this6 = this; + + var tracks = this.textTracks(); + var remoteTracks = this.remoteTextTracks(); + var handleAddTrack = function handleAddTrack(e) { + return tracks.addTrack(e.track); + }; + var handleRemoveTrack = function handleRemoveTrack(e) { + return tracks.removeTrack(e.track); + }; + + remoteTracks.on('addtrack', handleAddTrack); + remoteTracks.on('removetrack', handleRemoveTrack); + + this.addWebVttScript_(); + + var updateDisplay = function updateDisplay() { + return _this6.trigger('texttrackchange'); + }; + + var textTracksChanges = function textTracksChanges() { + updateDisplay(); + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + track.removeEventListener('cuechange', updateDisplay); + if (track.mode === 'showing') { + track.addEventListener('cuechange', updateDisplay); + } + } + }; + + textTracksChanges(); + tracks.addEventListener('change', textTracksChanges); + tracks.addEventListener('addtrack', textTracksChanges); + tracks.addEventListener('removetrack', textTracksChanges); + + this.on('dispose', function () { + remoteTracks.off('addtrack', handleAddTrack); + remoteTracks.off('removetrack', handleRemoveTrack); + tracks.removeEventListener('change', textTracksChanges); + tracks.removeEventListener('addtrack', textTracksChanges); + tracks.removeEventListener('removetrack', textTracksChanges); + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + track.removeEventListener('cuechange', updateDisplay); + } + }); + }; + + /** + * Create and returns a remote {@link TextTrack} object. + * + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track + * + * @param {string} [language] + * Two letter language abbreviation + * + * @return {TextTrack} + * The TextTrack that gets created. + */ + + + Tech.prototype.addTextTrack = function addTextTrack(kind, label, language) { + if (!kind) { + throw new Error('TextTrack kind is required but was not provided'); + } + + return createTrackHelper(this, kind, label, language); + }; + + /** + * Create an emulated TextTrack for use by addRemoteTextTrack + * + * This is intended to be overridden by classes that inherit from + * Tech in order to create native or custom TextTracks. + * + * @param {Object} options + * The object should contain the options to initialize the TextTrack with. + * + * @param {string} [options.kind] + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata). + * + * @param {string} [options.label]. + * Label to identify the text track + * + * @param {string} [options.language] + * Two letter language abbreviation. + * + * @return {HTMLTrackElement} + * The track element that gets created. + */ + + + Tech.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) { + var track = mergeOptions(options, { + tech: this + }); + + return new REMOTE.remoteTextEl.TrackClass(track); + }; + + /** + * Creates a remote text track object and returns an html track element. + * + * > Note: This can be an emulated {@link HTMLTrackElement} or a native one. + * + * @param {Object} options + * See {@link Tech#createRemoteTextTrack} for more detailed properties. + * + * @param {boolean} [manualCleanup=true] + * - When false: the TextTrack will be automatically removed from the video + * element whenever the source changes + * - When True: The TextTrack will have to be cleaned up manually + * + * @return {HTMLTrackElement} + * An Html Track Element. + * + * @deprecated The default functionality for this function will be equivalent + * to "manualCleanup=false" in the future. The manualCleanup parameter will + * also be removed. + */ + + + Tech.prototype.addRemoteTextTrack = function addRemoteTextTrack() { + var _this7 = this; + + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var manualCleanup = arguments[1]; + + var htmlTrackElement = this.createRemoteTextTrack(options); + + if (manualCleanup !== true && manualCleanup !== false) { + // deprecation warning + log$1.warn('Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js'); + manualCleanup = true; + } + + // store HTMLTrackElement and TextTrack to remote list + this.remoteTextTrackEls().addTrackElement_(htmlTrackElement); + this.remoteTextTracks().addTrack(htmlTrackElement.track); + + if (manualCleanup !== true) { + // create the TextTrackList if it doesn't exist + this.ready(function () { + return _this7.autoRemoteTextTracks_.addTrack(htmlTrackElement.track); + }); + } + + return htmlTrackElement; + }; + + /** + * Remove a remote text track from the remote `TextTrackList`. + * + * @param {TextTrack} track + * `TextTrack` to remove from the `TextTrackList` + */ + + + Tech.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { + var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); + + // remove HTMLTrackElement and TextTrack from remote list + this.remoteTextTrackEls().removeTrackElement_(trackElement); + this.remoteTextTracks().removeTrack(track); + this.autoRemoteTextTracks_.removeTrack(track); + }; + + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} + * + * @return {Object} + * An object with supported media playback quality metrics + * + * @abstract + */ + + + Tech.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() { + return {}; + }; + + /** + * A method to set a poster from a `Tech`. + * + * @abstract + */ + + + Tech.prototype.setPoster = function setPoster() { + }; + + /** + * A method to check for the presence of the 'playsinline' <video> attribute. + * + * @abstract + */ + + + Tech.prototype.playsinline = function playsinline() { + }; + + /** + * A method to set or unset the 'playsinline' <video> attribute. + * + * @abstract + */ + + + Tech.prototype.setPlaysinline = function setPlaysinline() { + }; + + /** + * Attempt to force override of native audio tracks. + * + * @param {Boolean} override - If set to true native audio will be overridden, + * otherwise native audio will potentially be used. + * + * @abstract + */ + + + Tech.prototype.overrideNativeAudioTracks = function overrideNativeAudioTracks() { + }; + + /** + * Attempt to force override of native video tracks. + * + * @param {Boolean} override - If set to true native video will be overridden, + * otherwise native video will potentially be used. + * + * @abstract + */ + + + Tech.prototype.overrideNativeVideoTracks = function overrideNativeVideoTracks() { + }; + + /* + * Check if the tech can support the given mime-type. + * + * The base tech does not support any type, but source handlers might + * overwrite this. + * + * @param {string} type + * The mimetype to check for support + * + * @return {string} + * 'probably', 'maybe', or empty string + * + * @see [Spec]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType} + * + * @abstract + */ + + + Tech.prototype.canPlayType = function canPlayType() { + return ''; + }; + + /** + * Check if the type is supported by this tech. + * + * The base tech does not support any type, but source handlers might + * overwrite this. + * + * @param {string} type + * The media type to check + * @return {string} Returns the native video element's response + */ + + + Tech.canPlayType = function canPlayType() { + return ''; + }; + + /** + * Check if the tech can support the given source + * @param {Object} srcObj + * The source object + * @param {Object} options + * The options passed to the tech + * @return {string} 'probably', 'maybe', or '' (empty string) + */ + + + Tech.canPlaySource = function canPlaySource(srcObj, options) { + return Tech.canPlayType(srcObj.type); + }; + + /* + * Return whether the argument is a Tech or not. + * Can be passed either a Class like `Html5` or a instance like `player.tech_` + * + * @param {Object} component + * The item to check + * + * @return {boolean} + * Whether it is a tech or not + * - True if it is a tech + * - False if it is not + */ + + + Tech.isTech = function isTech(component) { + return component.prototype instanceof Tech || component instanceof Tech || component === Tech; + }; + + /** + * Registers a `Tech` into a shared list for videojs. + * + * @param {string} name + * Name of the `Tech` to register. + * + * @param {Object} tech + * The `Tech` class to register. + */ + + + Tech.registerTech = function registerTech(name, tech) { + if (!Tech.techs_) { + Tech.techs_ = {}; + } + + if (!Tech.isTech(tech)) { + throw new Error('Tech ' + name + ' must be a Tech'); + } + + if (!Tech.canPlayType) { + throw new Error('Techs must have a static canPlayType method on them'); + } + if (!Tech.canPlaySource) { + throw new Error('Techs must have a static canPlaySource method on them'); + } + + name = toTitleCase(name); + + Tech.techs_[name] = tech; + if (name !== 'Tech') { + // camel case the techName for use in techOrder + Tech.defaultTechOrder_.push(name); + } + return tech; + }; + + /** + * Get a `Tech` from the shared list by name. + * + * @param {string} name + * `camelCase` or `TitleCase` name of the Tech to get + * + * @return {Tech|undefined} + * The `Tech` or undefined if there was no tech with the name requested. + */ + + + Tech.getTech = function getTech(name) { + if (!name) { + return; + } + + name = toTitleCase(name); + + if (Tech.techs_ && Tech.techs_[name]) { + return Tech.techs_[name]; + } + + if (window_1 && window_1.videojs && window_1.videojs[name]) { + log$1.warn('The ' + name + ' tech was added to the videojs object when it should be registered using videojs.registerTech(name, tech)'); + return window_1.videojs[name]; + } + }; + + return Tech; + }(Component); + + /** + * Get the {@link VideoTrackList} + * + * @returns {VideoTrackList} + * @method Tech.prototype.videoTracks + */ + + /** + * Get the {@link AudioTrackList} + * + * @returns {AudioTrackList} + * @method Tech.prototype.audioTracks + */ + + /** + * Get the {@link TextTrackList} + * + * @returns {TextTrackList} + * @method Tech.prototype.textTracks + */ + + /** + * Get the remote element {@link TextTrackList} + * + * @returns {TextTrackList} + * @method Tech.prototype.remoteTextTracks + */ + + /** + * Get the remote element {@link HtmlTrackElementList} + * + * @returns {HtmlTrackElementList} + * @method Tech.prototype.remoteTextTrackEls + */ + + ALL.names.forEach(function (name) { + var props = ALL[name]; + + Tech.prototype[props.getterName] = function () { + this[props.privateName] = this[props.privateName] || new props.ListClass(); + return this[props.privateName]; + }; + }); + + /** + * List of associated text tracks + * + * @type {TextTrackList} + * @private + * @property Tech#textTracks_ + */ + + /** + * List of associated audio tracks. + * + * @type {AudioTrackList} + * @private + * @property Tech#audioTracks_ + */ + + /** + * List of associated video tracks. + * + * @type {VideoTrackList} + * @private + * @property Tech#videoTracks_ + */ + + /** + * Boolean indicating whether the `Tech` supports volume control. + * + * @type {boolean} + * @default + */ + Tech.prototype.featuresVolumeControl = true; + + /** + * Boolean indicating whether the `Tech` supports fullscreen resize control. + * Resizing plugins using request fullscreen reloads the plugin + * + * @type {boolean} + * @default + */ + Tech.prototype.featuresFullscreenResize = false; + + /** + * Boolean indicating whether the `Tech` supports changing the speed at which the video + * plays. Examples: + * - Set player to playOld 2x (twice) as fast + * - Set player to playOld 0.5x (half) as fast + * + * @type {boolean} + * @default + */ + Tech.prototype.featuresPlaybackRate = false; + + /** + * Boolean indicating whether the `Tech` supports the `progress` event. This is currently + * not triggered by video-js-swf. This will be used to determine if + * {@link Tech#manualProgressOn} should be called. + * + * @type {boolean} + * @default + */ + Tech.prototype.featuresProgressEvents = false; + + /** + * Boolean indicating whether the `Tech` supports the `sourceset` event. + * + * A tech should set this to `true` and then use {@link Tech#triggerSourceset} + * to trigger a {@link Tech#event:sourceset} at the earliest time after getting + * a new source. + * + * @type {boolean} + * @default + */ + Tech.prototype.featuresSourceset = false; + + /** + * Boolean indicating whether the `Tech` supports the `timeupdate` event. This is currently + * not triggered by video-js-swf. This will be used to determine if + * {@link Tech#manualTimeUpdates} should be called. + * + * @type {boolean} + * @default + */ + Tech.prototype.featuresTimeupdateEvents = false; + + /** + * Boolean indicating whether the `Tech` supports the native `TextTrack`s. + * This will help us integrate with native `TextTrack`s if the browser supports them. + * + * @type {boolean} + * @default + */ + Tech.prototype.featuresNativeTextTracks = false; + + /** + * A functional mixin for techs that want to use the Source Handler pattern. + * Source handlers are scripts for handling specific formats. + * The source handler pattern is used for adaptive formats (HLS, DASH) that + * manually load video data and feed it into a Source Buffer (Media Source Extensions) + * Example: `Tech.withSourceHandlers.call(MyTech);` + * + * @param {Tech} _Tech + * The tech to add source handler functions to. + * + * @mixes Tech~SourceHandlerAdditions + */ + Tech.withSourceHandlers = function (_Tech) { + + /** + * Register a source handler + * + * @param {Function} handler + * The source handler class + * + * @param {number} [index] + * Register it at the following index + */ + _Tech.registerSourceHandler = function (handler, index) { + var handlers = _Tech.sourceHandlers; + + if (!handlers) { + handlers = _Tech.sourceHandlers = []; + } + + if (index === undefined) { + // add to the end of the list + index = handlers.length; + } + + handlers.splice(index, 0, handler); + }; + + /** + * Check if the tech can support the given type. Also checks the + * Techs sourceHandlers. + * + * @param {string} type + * The mimetype to check. + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) + */ + _Tech.canPlayType = function (type) { + var handlers = _Tech.sourceHandlers || []; + var can = void 0; + + for (var i = 0; i < handlers.length; i++) { + can = handlers[i].canPlayType(type); + + if (can) { + return can; + } + } + + return ''; + }; + + /** + * Returns the first source handler that supports the source. + * + * TODO: Answer question: should 'probably' be prioritized over 'maybe' + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Object} options + * The options passed to the tech + * + * @return {SourceHandler|null} + * The first source handler that supports the source or null if + * no SourceHandler supports the source + */ + _Tech.selectSourceHandler = function (source, options) { + var handlers = _Tech.sourceHandlers || []; + var can = void 0; + + for (var i = 0; i < handlers.length; i++) { + can = handlers[i].canHandleSource(source, options); + + if (can) { + return handlers[i]; + } + } + + return null; + }; + + /** + * Check if the tech can support the given source. + * + * @param {Tech~SourceObject} srcObj + * The source object + * + * @param {Object} options + * The options passed to the tech + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) + */ + _Tech.canPlaySource = function (srcObj, options) { + var sh = _Tech.selectSourceHandler(srcObj, options); + + if (sh) { + return sh.canHandleSource(srcObj, options); + } + + return ''; + }; + + /** + * When using a source handler, prefer its implementation of + * any function normally provided by the tech. + */ + var deferrable = ['seekable', 'seeking', 'duration']; + + /** + * A wrapper around {@link Tech#seekable} that will call a `SourceHandler`s seekable + * function if it exists, with a fallback to the Techs seekable function. + * + * @method _Tech.seekable + */ + + /** + * A wrapper around {@link Tech#duration} that will call a `SourceHandler`s duration + * function if it exists, otherwise it will fallback to the techs duration function. + * + * @method _Tech.duration + */ + + deferrable.forEach(function (fnName) { + var originalFn = this[fnName]; + + if (typeof originalFn !== 'function') { + return; + } + + this[fnName] = function () { + if (this.sourceHandler_ && this.sourceHandler_[fnName]) { + return this.sourceHandler_[fnName].apply(this.sourceHandler_, arguments); + } + return originalFn.apply(this, arguments); + }; + }, _Tech.prototype); + + /** + * Create a function for setting the source using a source object + * and source handlers. + * Should never be called unless a source handler was found. + * + * @param {Tech~SourceObject} source + * A source object with src and type keys + */ + _Tech.prototype.setSource = function (source) { + var sh = _Tech.selectSourceHandler(source, this.options_); + + if (!sh) { + // Fall back to a native source hander when unsupported sources are + // deliberately set + if (_Tech.nativeSourceHandler) { + sh = _Tech.nativeSourceHandler; + } else { + log$1.error('No source handler found for the current source.'); + } + } + + // Dispose any existing source handler + this.disposeSourceHandler(); + this.off('dispose', this.disposeSourceHandler); + + if (sh !== _Tech.nativeSourceHandler) { + this.currentSource_ = source; + } + + this.sourceHandler_ = sh.handleSource(source, this, this.options_); + this.on('dispose', this.disposeSourceHandler); + }; + + /** + * Clean up any existing SourceHandlers and listeners when the Tech is disposed. + * + * @listens Tech#dispose + */ + _Tech.prototype.disposeSourceHandler = function () { + // if we have a source and get another one + // then we are loading something new + // than clear all of our current tracks + if (this.currentSource_) { + this.clearTracks(['audio', 'video']); + this.currentSource_ = null; + } + + // always clean up auto-text tracks + this.cleanupAutoTextTracks(); + + if (this.sourceHandler_) { + + if (this.sourceHandler_.dispose) { + this.sourceHandler_.dispose(); + } + + this.sourceHandler_ = null; + } + }; + }; + + // The base Tech class needs to be registered as a Component. It is the only + // Tech that can be registered as a Component. + Component.registerComponent('Tech', Tech); + Tech.registerTech('Tech', Tech); + + /** + * A list of techs that should be added to techOrder on Players + * + * @private + */ + Tech.defaultTechOrder_ = []; + + var middlewares = {}; + var middlewareInstances = {}; + + var TERMINATOR = {}; + + function use(type, middleware) { + middlewares[type] = middlewares[type] || []; + middlewares[type].push(middleware); + } + + function setSource(player, src, next) { + player.setTimeout(function () { + return setSourceHelper(src, middlewares[src.type], next, player); + }, 1); + } + + function setTech(middleware, tech) { + middleware.forEach(function (mw) { + return mw.setTech && mw.setTech(tech); + }); + } + + /** + * Calls a getter on the tech first, through each middleware + * from right to left to the player. + */ + function get$1(middleware, tech, method) { + return middleware.reduceRight(middlewareIterator(method), tech[method]()); + } + + /** + * Takes the argument given to the player and calls the setter method on each + * middleware from left to right to the tech. + */ + function set$1(middleware, tech, method, arg) { + return tech[method](middleware.reduce(middlewareIterator(method), arg)); + } + + /** + * Takes the argument given to the player and calls the `call` version of the method + * on each middleware from left to right. + * Then, call the passed in method on the tech and return the result unchanged + * back to the player, through middleware, this time from right to left. + */ + function mediate(middleware, tech, method) { + var arg = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + + var callMethod = 'call' + toTitleCase(method); + var middlewareValue = middleware.reduce(middlewareIterator(callMethod), arg); + var terminated = middlewareValue === TERMINATOR; + var returnValue = terminated ? null : tech[method](middlewareValue); + + executeRight(middleware, method, returnValue, terminated); + + return returnValue; + } + + var allowedGetters = { + buffered: 1, + currentTime: 1, + duration: 1, + seekable: 1, + played: 1, + paused: 1 + }; + + var allowedSetters = { + setCurrentTime: 1 + }; + + var allowedMediators = { + play: 1, + pause: 1 + }; + + function middlewareIterator(method) { + return function (value, mw) { + // if the previous middleware terminated, pass along the termination + if (value === TERMINATOR) { + return TERMINATOR; + } + + if (mw[method]) { + return mw[method](value); + } + + return value; + }; + } + + function executeRight(mws, method, value, terminated) { + for (var i = mws.length - 1; i >= 0; i--) { + var mw = mws[i]; + + if (mw[method]) { + mw[method](terminated, value); + } + } + } + + function clearCacheForPlayer(player) { + middlewareInstances[player.id()] = null; + } + + /** + * { + * [playerId]: [[mwFactory, mwInstance], ...] + * } + */ + function getOrCreateFactory(player, mwFactory) { + var mws = middlewareInstances[player.id()]; + var mw = null; + + if (mws === undefined || mws === null) { + mw = mwFactory(player); + middlewareInstances[player.id()] = [[mwFactory, mw]]; + return mw; + } + + for (var i = 0; i < mws.length; i++) { + var _mws$i = mws[i], + mwf = _mws$i[0], + mwi = _mws$i[1]; + + + if (mwf !== mwFactory) { + continue; + } + + mw = mwi; + } + + if (mw === null) { + mw = mwFactory(player); + mws.push([mwFactory, mw]); + } + + return mw; + } + + function setSourceHelper() { + var src = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var middleware = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + var next = arguments[2]; + var player = arguments[3]; + var acc = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : []; + var lastRun = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; + var mwFactory = middleware[0], + mwrest = middleware.slice(1); + + // if mwFactory is a string, then we're at a fork in the road + + if (typeof mwFactory === 'string') { + setSourceHelper(src, middlewares[mwFactory], next, player, acc, lastRun); + + // if we have an mwFactory, call it with the player to get the mw, + // then call the mw's setSource method + } else if (mwFactory) { + var mw = getOrCreateFactory(player, mwFactory); + + mw.setSource(assign({}, src), function (err, _src) { + + // something happened, try the next middleware on the current level + // make sure to use the old src + if (err) { + return setSourceHelper(src, mwrest, next, player, acc, lastRun); + } + + // we've succeeded, now we need to go deeper + acc.push(mw); + + // if it's the same type, continue down the current chain + // otherwise, we want to go down the new chain + setSourceHelper(_src, src.type === _src.type ? mwrest : middlewares[_src.type], next, player, acc, lastRun); + }); + } else if (mwrest.length) { + setSourceHelper(src, mwrest, next, player, acc, lastRun); + } else if (lastRun) { + next(src, acc); + } else { + setSourceHelper(src, middlewares['*'], next, player, acc, true); + } + } + + /** + * Mimetypes + * + * @see http://hul.harvard.edu/ois/////systems/wax/wax-public-help/mimetypes.htm + * @typedef Mimetypes~Kind + * @enum + */ + var MimetypesKind = { + opus: 'video/ogg', + ogv: 'video/ogg', + mp4: 'video/mp4', + mov: 'video/mp4', + m4v: 'video/mp4', + mkv: 'video/x-matroska', + mp3: 'audio/mpeg', + aac: 'audio/aac', + oga: 'audio/ogg', + m3u8: 'application/x-mpegURL' + }; + + /** + * Get the mimetype of a given src url if possible + * + * @param {string} src + * The url to the src + * + * @return {string} + * return the mimetype if it was known or empty string otherwise + */ + var getMimetype = function getMimetype() { + var src = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + + var ext = getFileExtension(src); + var mimetype = MimetypesKind[ext.toLowerCase()]; + + return mimetype || ''; + }; + + /** + * Find the mime type of a given source string if possible. Uses the player + * source cache. + * + * @param {Player} player + * The player object + * + * @param {string} src + * The source string + * + * @return {string} + * The type that was found + */ + var findMimetype = function findMimetype(player, src) { + if (!src) { + return ''; + } + + // 1. check for the type in the `source` cache + if (player.cache_.source.src === src && player.cache_.source.type) { + return player.cache_.source.type; + } + + // 2. see if we have this source in our `currentSources` cache + var matchingSources = player.cache_.sources.filter(function (s) { + return s.src === src; + }); + + if (matchingSources.length) { + return matchingSources[0].type; + } + + // 3. look for the src url in source elements and use the type there + var sources = player.$$('source'); + + for (var i = 0; i < sources.length; i++) { + var s = sources[i]; + + if (s.type && s.src && s.src === src) { + return s.type; + } + } + + // 4. finally fallback to our list of mime types based on src url extension + return getMimetype(src); + }; + + /** + * @module filter-source + */ + + /** + * Filter out single bad source objects or multiple source objects in an + * array. Also flattens nested source object arrays into a 1 dimensional + * array of source objects. + * + * @param {Tech~SourceObject|Tech~SourceObject[]} src + * The src object to filter + * + * @return {Tech~SourceObject[]} + * An array of sourceobjects containing only valid sources + * + * @private + */ + var filterSource = function filterSource(src) { + // traverse array + if (Array.isArray(src)) { + var newsrc = []; + + src.forEach(function (srcobj) { + srcobj = filterSource(srcobj); + + if (Array.isArray(srcobj)) { + newsrc = newsrc.concat(srcobj); + } else if (isObject(srcobj)) { + newsrc.push(srcobj); + } + }); + + src = newsrc; + } else if (typeof src === 'string' && src.trim()) { + // convert string into object + src = [fixSource({src: src})]; + } else if (isObject(src) && typeof src.src === 'string' && src.src && src.src.trim()) { + // src is already valid + src = [fixSource(src)]; + } else { + // invalid source, turn it into an empty array + src = []; + } + + return src; + }; + + /** + * Checks src mimetype, adding it when possible + * + * @param {Tech~SourceObject} src + * The src object to check + * @return {Tech~SourceObject} + * src Object with known type + */ + function fixSource(src) { + var mimetype = getMimetype(src.src); + + if (!src.type && mimetype) { + src.type = mimetype; + } + + return src; + } + + /** + * @file loader.js + */ + + /** + * The `MediaLoader` is the `Component` that decides which playback technology to load + * when a player is initialized. + * + * @extends Component + */ + + var MediaLoader = function (_Component) { + inherits(MediaLoader, _Component); + + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should attach to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function that is run when this component is ready. + */ + function MediaLoader(player, options, ready) { + classCallCheck(this, MediaLoader); + + // MediaLoader has no element + var options_ = mergeOptions({createEl: false}, options); + + // If there are no sources when the player is initialized, + // load the first supported playback technology. + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options_, ready)); + + if (!options.playerOptions.sources || options.playerOptions.sources.length === 0) { + for (var i = 0, j = options.playerOptions.techOrder; i < j.length; i++) { + var techName = toTitleCase(j[i]); + var tech = Tech.getTech(techName); + + // Support old behavior of techs being registered as components. + // Remove once that deprecated behavior is removed. + if (!techName) { + tech = Component.getComponent(techName); + } + + // Check if the browser supports this technology + if (tech && tech.isSupported()) { + player.loadTech_(techName); + break; + } + } + } else { + // Loop through playback technologies (HTML5, Flash) and check for support. + // Then load the best source. + // A few assumptions here: + // All playback technologies respect preload false. + player.src(options.playerOptions.sources); + } + return _this; + } + + return MediaLoader; + }(Component); + + Component.registerComponent('MediaLoader', MediaLoader); + + /** + * @file clickable-component.js + */ + + /** + * Clickable Component which is clickable or keyboard actionable, + * but is not a native HTML button. + * + * @extends Component + */ + + var ClickableComponent = function (_Component) { + inherits(ClickableComponent, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function ClickableComponent(player, options) { + classCallCheck(this, ClickableComponent); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.emitTapEvents(); + + _this.enable(); + return _this; + } + + /** + * Create the `Component`s DOM element. + * + * @param {string} [tag=div] + * The element's node type. + * + * @param {Object} [props={}] + * An object of properties that should be set on the element. + * + * @param {Object} [attributes={}] + * An object of attributes that should be set on the element. + * + * @return {Element} + * The element that gets created. + */ + + + ClickableComponent.prototype.createEl = function createEl$$1() { + var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div'; + var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + props = assign({ + innerHTML: '<span aria-hidden="true" class="vjs-icon-placeholder"></span>', + className: this.buildCSSClass(), + tabIndex: 0 + }, props); + + if (tag === 'button') { + log$1.error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.'); + } + + // Add ARIA attributes for clickable element which is not a native HTML button + attributes = assign({ + role: 'button' + }, attributes); + + this.tabIndex_ = props.tabIndex; + + var el = _Component.prototype.createEl.call(this, tag, props, attributes); + + this.createControlTextEl(el); + + return el; + }; + + ClickableComponent.prototype.dispose = function dispose() { + // remove controlTextEl_ on dispose + this.controlTextEl_ = null; + + _Component.prototype.dispose.call(this); + }; + + /** + * Create a control text element on this `Component` + * + * @param {Element} [el] + * Parent element for the control text. + * + * @return {Element} + * The control text element that gets created. + */ + + + ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) { + this.controlTextEl_ = createEl('span', { + className: 'vjs-control-text' + }, { + // let the screen reader user know that the text of the element may change + 'aria-live': 'polite' + }); + + if (el) { + el.appendChild(this.controlTextEl_); + } + + this.controlText(this.controlText_, el); + + return this.controlTextEl_; + }; + + /** + * Get or set the localize text to use for the controls on the `Component`. + * + * @param {string} [text] + * Control text for element. + * + * @param {Element} [el=this.el()] + * Element to set the title on. + * + * @return {string} + * - The control text when getting + */ + + + ClickableComponent.prototype.controlText = function controlText(text) { + var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.el(); + + if (text === undefined) { + return this.controlText_ || 'Need Text'; + } + + var localizedText = this.localize(text); + + this.controlText_ = text; + textContent(this.controlTextEl_, localizedText); + if (!this.nonIconControl) { + // Set title attribute if only an icon is shown + el.setAttribute('title', localizedText); + } + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + ClickableComponent.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this); + }; + + /** + * Enable this `Component`s element. + */ + + + ClickableComponent.prototype.enable = function enable() { + if (!this.enabled_) { + this.enabled_ = true; + this.removeClass('vjs-disabled'); + this.el_.setAttribute('aria-disabled', 'false'); + if (typeof this.tabIndex_ !== 'undefined') { + this.el_.setAttribute('tabIndex', this.tabIndex_); + } + this.on(['tap', 'click'], this.handleClick); + this.on('focus', this.handleFocus); + this.on('blur', this.handleBlur); + } + }; + + /** + * Disable this `Component`s element. + */ + + + ClickableComponent.prototype.disable = function disable() { + this.enabled_ = false; + this.addClass('vjs-disabled'); + this.el_.setAttribute('aria-disabled', 'true'); + if (typeof this.tabIndex_ !== 'undefined') { + this.el_.removeAttribute('tabIndex'); + } + this.off(['tap', 'click'], this.handleClick); + this.off('focus', this.handleFocus); + this.off('blur', this.handleBlur); + }; + + /** + * This gets called when a `ClickableComponent` gets: + * - Clicked (via the `click` event, listening starts in the constructor) + * - Tapped (via the `tap` event, listening starts in the constructor) + * - The following things happen in order: + * 1. {@link ClickableComponent#handleFocus} is called via a `focus` event on the + * `ClickableComponent`. + * 2. {@link ClickableComponent#handleFocus} adds a listener for `keydown` on using + * {@link ClickableComponent#handleKeyPress}. + * 3. `ClickableComponent` has not had a `blur` event (`blur` means that focus was lost). The user presses + * the space or enter key. + * 4. {@link ClickableComponent#handleKeyPress} calls this function with the `keydown` + * event as a parameter. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + * @abstract + */ + + + ClickableComponent.prototype.handleClick = function handleClick(event) { + }; + + /** + * This gets called when a `ClickableComponent` gains focus via a `focus` event. + * Turns on listening for `keydown` events. When they happen it + * calls `this.handleKeyPress`. + * + * @param {EventTarget~Event} event + * The `focus` event that caused this function to be called. + * + * @listens focus + */ + + + ClickableComponent.prototype.handleFocus = function handleFocus(event) { + on(document_1, 'keydown', bind(this, this.handleKeyPress)); + }; + + /** + * Called when this ClickableComponent has focus and a key gets pressed down. By + * default it will call `this.handleClick` when the key is space or enter. + * + * @param {EventTarget~Event} event + * The `keydown` event that caused this function to be called. + * + * @listens keydown + */ + + + ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) { + + // Support Space (32) or Enter (13) key operation to fire a click event + if (event.which === 32 || event.which === 13) { + event.preventDefault(); + this.trigger('click'); + } else if (_Component.prototype.handleKeyPress) { + + // Pass keypress handling up for unsupported keys + _Component.prototype.handleKeyPress.call(this, event); + } + }; + + /** + * Called when a `ClickableComponent` loses focus. Turns off the listener for + * `keydown` events. Which Stops `this.handleKeyPress` from getting called. + * + * @param {EventTarget~Event} event + * The `blur` event that caused this function to be called. + * + * @listens blur + */ + + + ClickableComponent.prototype.handleBlur = function handleBlur(event) { + off(document_1, 'keydown', bind(this, this.handleKeyPress)); + }; + + return ClickableComponent; + }(Component); + + Component.registerComponent('ClickableComponent', ClickableComponent); + + /** + * @file poster-image.js + */ + + /** + * A `ClickableComponent` that handles showing the poster image for the player. + * + * @extends ClickableComponent + */ + + var PosterImage = function (_ClickableComponent) { + inherits(PosterImage, _ClickableComponent); + + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should attach to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PosterImage(player, options) { + classCallCheck(this, PosterImage); + + var _this = possibleConstructorReturn(this, _ClickableComponent.call(this, player, options)); + + _this.update(); + player.on('posterchange', bind(_this, _this.update)); + return _this; + } + + /** + * Clean up and dispose of the `PosterImage`. + */ + + + PosterImage.prototype.dispose = function dispose() { + this.player().off('posterchange', this.update); + _ClickableComponent.prototype.dispose.call(this); + }; + + /** + * Create the `PosterImage`s DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + PosterImage.prototype.createEl = function createEl$$1() { + var el = createEl('div', { + className: 'vjs-poster', + + // Don't want poster to be tabbable. + tabIndex: -1 + }); + + return el; + }; + + /** + * An {@link EventTarget~EventListener} for {@link Player#posterchange} events. + * + * @listens Player#posterchange + * + * @param {EventTarget~Event} [event] + * The `Player#posterchange` event that triggered this function. + */ + + + PosterImage.prototype.update = function update(event) { + var url = this.player().poster(); + + this.setSrc(url); + + // If there's no poster source we should display:none on this component + // so it's not still clickable or right-clickable + if (url) { + this.show(); + } else { + this.hide(); + } + }; + + /** + * Set the source of the `PosterImage` depending on the display method. + * + * @param {string} url + * The URL to the source for the `PosterImage`. + */ + + + PosterImage.prototype.setSrc = function setSrc(url) { + var backgroundImage = ''; + + // Any falsy value should stay as an empty string, otherwise + // this will throw an extra error + if (url) { + backgroundImage = 'url("' + url + '")'; + } + + this.el_.style.backgroundImage = backgroundImage; + }; + + /** + * An {@link EventTarget~EventListener} for clicks on the `PosterImage`. See + * {@link ClickableComponent#handleClick} for instances where this will be triggered. + * + * @listens tap + * @listens click + * @listens keydown + * + * @param {EventTarget~Event} event + + The `click`, `tap` or `keydown` event that caused this function to be called. + */ + + + PosterImage.prototype.handleClick = function handleClick(event) { + // We don't want a click to trigger playback when controls are disabled + if (!this.player_.controls()) { + return; + } + + if (this.player_.paused()) { + this.player_.play(); + } else { + this.player_.pause(); + } + }; + + return PosterImage; + }(ClickableComponent); + + Component.registerComponent('PosterImage', PosterImage); + + /** + * @file text-track-display.js + */ + + var darkGray = '#222'; + var lightGray = '#ccc'; + var fontMap = { + monospace: 'monospace', + sansSerif: 'sans-serif', + serif: 'serif', + monospaceSansSerif: '"Andale Mono", "Lucida Console", monospace', + monospaceSerif: '"Courier New", monospace', + proportionalSansSerif: 'sans-serif', + proportionalSerif: 'serif', + casual: '"Comic Sans MS", Impact, fantasy', + script: '"Monotype Corsiva", cursive', + smallcaps: '"Andale Mono", "Lucida Console", monospace, sans-serif' + }; + + /** + * Construct an rgba color from a given hex color code. + * + * @param {number} color + * Hex number for color, like #f0e. + * + * @param {number} opacity + * Value for opacity, 0.0 - 1.0. + * + * @return {string} + * The rgba color that was created, like 'rgba(255, 0, 0, 0.3)'. + * + * @private + */ + function constructColor(color, opacity) { + return 'rgba(' + + // color looks like "#f0e" + parseInt(color[1] + color[1], 16) + ',' + parseInt(color[2] + color[2], 16) + ',' + parseInt(color[3] + color[3], 16) + ',' + opacity + ')'; + } + + /** + * Try to update the style of a DOM element. Some style changes will throw an error, + * particularly in IE8. Those should be noops. + * + * @param {Element} el + * The DOM element to be styled. + * + * @param {string} style + * The CSS property on the element that should be styled. + * + * @param {string} rule + * The style rule that should be applied to the property. + * + * @private + */ + function tryUpdateStyle(el, style, rule) { + try { + el.style[style] = rule; + } catch (e) { + + // Satisfies linter. + return; + } + } + + /** + * The component for displaying text track cues. + * + * @extends Component + */ + + var TextTrackDisplay = function (_Component) { + inherits(TextTrackDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when `TextTrackDisplay` is ready. + */ + function TextTrackDisplay(player, options, ready) { + classCallCheck(this, TextTrackDisplay); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options, ready)); + + player.on('loadstart', bind(_this, _this.toggleDisplay)); + player.on('texttrackchange', bind(_this, _this.updateDisplay)); + player.on('loadstart', bind(_this, _this.preselectTrack)); + + // This used to be called during player init, but was causing an error + // if a track should show by default and the display hadn't loaded yet. + // Should probably be moved to an external track loader when we support + // tracks that don't need a display. + player.ready(bind(_this, function () { + if (player.tech_ && player.tech_.featuresNativeTextTracks) { + this.hide(); + return; + } + + player.on('fullscreenchange', bind(this, this.updateDisplay)); + + var tracks = this.options_.playerOptions.tracks || []; + + for (var i = 0; i < tracks.length; i++) { + this.player_.addRemoteTextTrack(tracks[i], true); + } + + this.preselectTrack(); + })); + return _this; + } + + /** + * Preselect a track following this precedence: + * - matches the previously selected {@link TextTrack}'s language and kind + * - matches the previously selected {@link TextTrack}'s language only + * - is the first default captions track + * - is the first default descriptions track + * + * @listens Player#loadstart + */ + + + TextTrackDisplay.prototype.preselectTrack = function preselectTrack() { + var modes = {captions: 1, subtitles: 1}; + var trackList = this.player_.textTracks(); + var userPref = this.player_.cache_.selectedLanguage; + var firstDesc = void 0; + var firstCaptions = void 0; + var preferredTrack = void 0; + + for (var i = 0; i < trackList.length; i++) { + var track = trackList[i]; + + if (userPref && userPref.enabled && userPref.language === track.language) { + // Always choose the track that matches both language and kind + if (track.kind === userPref.kind) { + preferredTrack = track; + // or choose the first track that matches language + } else if (!preferredTrack) { + preferredTrack = track; + } + + // clear everything if offTextTrackMenuItem was clicked + } else if (userPref && !userPref.enabled) { + preferredTrack = null; + firstDesc = null; + firstCaptions = null; + } else if (track.default) { + if (track.kind === 'descriptions' && !firstDesc) { + firstDesc = track; + } else if (track.kind in modes && !firstCaptions) { + firstCaptions = track; + } + } + } + + // The preferredTrack matches the user preference and takes + // precedence over all the other tracks. + // So, display the preferredTrack before the first default track + // and the subtitles/captions track before the descriptions track + if (preferredTrack) { + preferredTrack.mode = 'showing'; + } else if (firstCaptions) { + firstCaptions.mode = 'showing'; + } else if (firstDesc) { + firstDesc.mode = 'showing'; + } + }; + + /** + * Turn display of {@link TextTrack}'s from the current state into the other state. + * There are only two states: + * - 'shown' + * - 'hidden' + * + * @listens Player#loadstart + */ + + + TextTrackDisplay.prototype.toggleDisplay = function toggleDisplay() { + if (this.player_.tech_ && this.player_.tech_.featuresNativeTextTracks) { + this.hide(); + } else { + this.show(); + } + }; + + /** + * Create the {@link Component}'s DOM element. + * + * @return {Element} + * The element that was created. + */ + + + TextTrackDisplay.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-text-track-display' + }, { + 'aria-live': 'off', + 'aria-atomic': 'true' + }); + }; + + /** + * Clear all displayed {@link TextTrack}s. + */ + + + TextTrackDisplay.prototype.clearDisplay = function clearDisplay() { + if (typeof window_1.WebVTT === 'function') { + window_1.WebVTT.processCues(window_1, [], this.el_); + } + }; + + /** + * Update the displayed TextTrack when a either a {@link Player#texttrackchange} or + * a {@link Player#fullscreenchange} is fired. + * + * @listens Player#texttrackchange + * @listens Player#fullscreenchange + */ + + + TextTrackDisplay.prototype.updateDisplay = function updateDisplay() { + var tracks = this.player_.textTracks(); + + this.clearDisplay(); + + // Track display prioritization model: if multiple tracks are 'showing', + // display the first 'subtitles' or 'captions' track which is 'showing', + // otherwise display the first 'descriptions' track which is 'showing' + + var descriptionsTrack = null; + var captionsSubtitlesTrack = null; + var i = tracks.length; + + while (i--) { + var track = tracks[i]; + + if (track.mode === 'showing') { + if (track.kind === 'descriptions') { + descriptionsTrack = track; + } else { + captionsSubtitlesTrack = track; + } + } + } + + if (captionsSubtitlesTrack) { + if (this.getAttribute('aria-live') !== 'off') { + this.setAttribute('aria-live', 'off'); + } + this.updateForTrack(captionsSubtitlesTrack); + } else if (descriptionsTrack) { + if (this.getAttribute('aria-live') !== 'assertive') { + this.setAttribute('aria-live', 'assertive'); + } + this.updateForTrack(descriptionsTrack); + } + }; + + /** + * Add an {@link TextTrack} to to the {@link Tech}s {@link TextTrackList}. + * + * @param {TextTrack} track + * Text track object to be added to the list. + */ + + + TextTrackDisplay.prototype.updateForTrack = function updateForTrack(track) { + if (typeof window_1.WebVTT !== 'function' || !track.activeCues) { + return; + } + + var cues = []; + + for (var _i = 0; _i < track.activeCues.length; _i++) { + cues.push(track.activeCues[_i]); + } + + window_1.WebVTT.processCues(window_1, cues, this.el_); + + if (!this.player_.textTrackSettings) { + return; + } + + var overrides = this.player_.textTrackSettings.getValues(); + + var i = cues.length; + + while (i--) { + var cue = cues[i]; + + if (!cue) { + continue; + } + + var cueDiv = cue.displayState; + + if (overrides.color) { + cueDiv.firstChild.style.color = overrides.color; + } + if (overrides.textOpacity) { + tryUpdateStyle(cueDiv.firstChild, 'color', constructColor(overrides.color || '#fff', overrides.textOpacity)); + } + if (overrides.backgroundColor) { + cueDiv.firstChild.style.backgroundColor = overrides.backgroundColor; + } + if (overrides.backgroundOpacity) { + tryUpdateStyle(cueDiv.firstChild, 'backgroundColor', constructColor(overrides.backgroundColor || '#000', overrides.backgroundOpacity)); + } + if (overrides.windowColor) { + if (overrides.windowOpacity) { + tryUpdateStyle(cueDiv, 'backgroundColor', constructColor(overrides.windowColor, overrides.windowOpacity)); + } else { + cueDiv.style.backgroundColor = overrides.windowColor; + } + } + if (overrides.edgeStyle) { + if (overrides.edgeStyle === 'dropshadow') { + cueDiv.firstChild.style.textShadow = '2px 2px 3px ' + darkGray + ', 2px 2px 4px ' + darkGray + ', 2px 2px 5px ' + darkGray; + } else if (overrides.edgeStyle === 'raised') { + cueDiv.firstChild.style.textShadow = '1px 1px ' + darkGray + ', 2px 2px ' + darkGray + ', 3px 3px ' + darkGray; + } else if (overrides.edgeStyle === 'depressed') { + cueDiv.firstChild.style.textShadow = '1px 1px ' + lightGray + ', 0 1px ' + lightGray + ', -1px -1px ' + darkGray + ', 0 -1px ' + darkGray; + } else if (overrides.edgeStyle === 'uniform') { + cueDiv.firstChild.style.textShadow = '0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray; + } + } + if (overrides.fontPercent && overrides.fontPercent !== 1) { + var fontSize = window_1.parseFloat(cueDiv.style.fontSize); + + cueDiv.style.fontSize = fontSize * overrides.fontPercent + 'px'; + cueDiv.style.height = 'auto'; + cueDiv.style.top = 'auto'; + cueDiv.style.bottom = '2px'; + } + if (overrides.fontFamily && overrides.fontFamily !== 'default') { + if (overrides.fontFamily === 'small-caps') { + cueDiv.firstChild.style.fontVariant = 'small-caps'; + } else { + cueDiv.firstChild.style.fontFamily = fontMap[overrides.fontFamily]; + } + } + } + }; + + return TextTrackDisplay; + }(Component); + + Component.registerComponent('TextTrackDisplay', TextTrackDisplay); + + /** + * @file loading-spinner.js + */ + + /** + * A loading spinner for use during waiting/loading events. + * + * @extends Component + */ + + var LoadingSpinner = function (_Component) { + inherits(LoadingSpinner, _Component); + + function LoadingSpinner() { + classCallCheck(this, LoadingSpinner); + return possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the `LoadingSpinner`s DOM element. + * + * @return {Element} + * The dom element that gets created. + */ + LoadingSpinner.prototype.createEl = function createEl$$1() { + var isAudio = this.player_.isAudio(); + var playerType = this.localize(isAudio ? 'Audio Player' : 'Video Player'); + var controlText = createEl('span', { + className: 'vjs-control-text', + innerHTML: this.localize('{1} is loading.', [playerType]) + }); + + var el = _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-loading-spinner', + dir: 'ltr' + }); + + el.appendChild(controlText); + + return el; + }; + + return LoadingSpinner; + }(Component); + + Component.registerComponent('LoadingSpinner', LoadingSpinner); + + /** + * @file button.js + */ + + /** + * Base class for all buttons. + * + * @extends ClickableComponent + */ + + var Button = function (_ClickableComponent) { + inherits(Button, _ClickableComponent); + + function Button() { + classCallCheck(this, Button); + return possibleConstructorReturn(this, _ClickableComponent.apply(this, arguments)); + } + + /** + * Create the `Button`s DOM element. + * + * @param {string} [tag="button"] + * The element's node type. This argument is IGNORED: no matter what + * is passed, it will always create a `button` element. + * + * @param {Object} [props={}] + * An object of properties that should be set on the element. + * + * @param {Object} [attributes={}] + * An object of attributes that should be set on the element. + * + * @return {Element} + * The element that gets created. + */ + Button.prototype.createEl = function createEl(tag) { + var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + tag = 'button'; + + props = assign({ + innerHTML: '<span aria-hidden="true" class="vjs-icon-placeholder"></span>', + className: this.buildCSSClass() + }, props); + + // Add attributes for button element + attributes = assign({ + + // Necessary since the default button type is "submit" + type: 'button' + }, attributes); + + var el = Component.prototype.createEl.call(this, tag, props, attributes); + + this.createControlTextEl(el); + + return el; + }; + + /** + * Add a child `Component` inside of this `Button`. + * + * @param {string|Component} child + * The name or instance of a child to add. + * + * @param {Object} [options={}] + * The key/value store of options that will get passed to children of + * the child. + * + * @return {Component} + * The `Component` that gets added as a child. When using a string the + * `Component` will get created by this process. + * + * @deprecated since version 5 + */ + + + Button.prototype.addChild = function addChild(child) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var className = this.constructor.name; + + log$1.warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.'); + + // Avoid the error message generated by ClickableComponent's addChild method + return Component.prototype.addChild.call(this, child, options); + }; + + /** + * Enable the `Button` element so that it can be activated or clicked. Use this with + * {@link Button#disable}. + */ + + + Button.prototype.enable = function enable() { + _ClickableComponent.prototype.enable.call(this); + this.el_.removeAttribute('disabled'); + }; + + /** + * Disable the `Button` element so that it cannot be activated or clicked. Use this with + * {@link Button#enable}. + */ + + + Button.prototype.disable = function disable() { + _ClickableComponent.prototype.disable.call(this); + this.el_.setAttribute('disabled', 'disabled'); + }; + + /** + * This gets called when a `Button` has focus and `keydown` is triggered via a key + * press. + * + * @param {EventTarget~Event} event + * The event that caused this function to get called. + * + * @listens keydown + */ + + + Button.prototype.handleKeyPress = function handleKeyPress(event) { + + // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button. + if (event.which === 32 || event.which === 13) { + return; + } + + // Pass keypress handling up for unsupported keys + _ClickableComponent.prototype.handleKeyPress.call(this, event); + }; + + return Button; + }(ClickableComponent); + + Component.registerComponent('Button', Button); + + /** + * @file big-playOld-button.js + */ + + /** + * The initial playOld button that shows before the video has played. The hiding of the + * `BigPlayButton` get done via CSS and `Player` states. + * + * @extends Button + */ + + var BigPlayButton = function (_Button) { + inherits(BigPlayButton, _Button); + + function BigPlayButton(player, options) { + classCallCheck(this, BigPlayButton); + + var _this = possibleConstructorReturn(this, _Button.call(this, player, options)); + + _this.mouseused_ = false; + + _this.on('mousedown', _this.handleMouseDown); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. Always returns 'vjs-big-playOld-button'. + */ + + + BigPlayButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-big-playOld-button'; + }; + + /** + * This gets called when a `BigPlayButton` "clicked". See {@link ClickableComponent} + * for more detailed information on what a click can be. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + BigPlayButton.prototype.handleClick = function handleClick(event) { + var playPromise = this.player_.play(); + + // exit early if clicked via the mouse + if (this.mouseused_ && event.clientX && event.clientY) { + return; + } + + var cb = this.player_.getChild('controlBar'); + var playToggle = cb && cb.getChild('playToggle'); + + if (!playToggle) { + this.player_.focus(); + return; + } + + var playFocus = function playFocus() { + return playToggle.focus(); + }; + + if (isPromise(playPromise)) { + playPromise.then(playFocus, function () { + }); + } else { + this.setTimeout(playFocus, 1); + } + }; + + BigPlayButton.prototype.handleKeyPress = function handleKeyPress(event) { + this.mouseused_ = false; + + _Button.prototype.handleKeyPress.call(this, event); + }; + + BigPlayButton.prototype.handleMouseDown = function handleMouseDown(event) { + this.mouseused_ = true; + }; + + return BigPlayButton; + }(Button); + + /** + * The text that should display over the `BigPlayButton`s controls. Added to for localization. + * + * @type {string} + * @private + */ + + + BigPlayButton.prototype.controlText_ = 'Play Video'; + + Component.registerComponent('BigPlayButton', BigPlayButton); + + /** + * @file close-button.js + */ + + /** + * The `CloseButton` is a `{@link Button}` that fires a `close` event when + * it gets clicked. + * + * @extends Button + */ + + var CloseButton = function (_Button) { + inherits(CloseButton, _Button); + + /** + * Creates an instance of the this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function CloseButton(player, options) { + classCallCheck(this, CloseButton); + + var _this = possibleConstructorReturn(this, _Button.call(this, player, options)); + + _this.controlText(options && options.controlText || _this.localize('Close')); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + CloseButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this); + }; + + /** + * This gets called when a `CloseButton` gets clicked. See + * {@link ClickableComponent#handleClick} for more information on when this will be + * triggered + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + * @fires CloseButton#close + */ + + + CloseButton.prototype.handleClick = function handleClick(event) { + + /** + * Triggered when the a `CloseButton` is clicked. + * + * @event CloseButton#close + * @type {EventTarget~Event} + * + * @property {boolean} [bubbles=false] + * set to false so that the close event does not + * bubble up to parents if there is no listener + */ + this.trigger({type: 'close', bubbles: false}); + }; + + return CloseButton; + }(Button); + + Component.registerComponent('CloseButton', CloseButton); + + /** + * @file playOld-toggle.js + */ + + /** + * Button to toggle between playOld and pause. + * + * @extends Button + */ + + var PlayToggle = function (_Button) { + inherits(PlayToggle, _Button); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PlayToggle(player, options) { + classCallCheck(this, PlayToggle); + + var _this = possibleConstructorReturn(this, _Button.call(this, player, options)); + + _this.on(player, 'play', _this.handlePlay); + _this.on(player, 'pause', _this.handlePause); + _this.on(player, 'ended', _this.handleEnded); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + PlayToggle.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-playOld-control ' + _Button.prototype.buildCSSClass.call(this); + }; + + /** + * This gets called when an `PlayToggle` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + PlayToggle.prototype.handleClick = function handleClick(event) { + if (this.player_.paused()) { + this.player_.play(); + } else { + this.player_.pause(); + } + }; + + /** + * This gets called once after the video has ended and the user seeks so that + * we can change the replay button back to a playOld button. + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#seeked + */ + + + PlayToggle.prototype.handleSeeked = function handleSeeked(event) { + this.removeClass('vjs-ended'); + + if (this.player_.paused()) { + this.handlePause(event); + } else { + this.handlePlay(event); + } + }; + + /** + * Add the vjs-playing class to the element so it can change appearance. + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#play + */ + + + PlayToggle.prototype.handlePlay = function handlePlay(event) { + this.removeClass('vjs-ended'); + this.removeClass('vjs-paused'); + this.addClass('vjs-playing'); + // change the button text to "Pause" + this.controlText('Pause'); + }; + + /** + * Add the vjs-paused class to the element so it can change appearance. + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#pause + */ + + + PlayToggle.prototype.handlePause = function handlePause(event) { + this.removeClass('vjs-playing'); + this.addClass('vjs-paused'); + // change the button text to "Play" + this.controlText('Play'); + }; + + /** + * Add the vjs-ended class to the element so it can change appearance + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#ended + */ + + + PlayToggle.prototype.handleEnded = function handleEnded(event) { + this.removeClass('vjs-playing'); + this.addClass('vjs-ended'); + // change the button text to "Replay" + this.controlText('Replay'); + + // on the next seek remove the replay button + this.one(this.player_, 'seeked', this.handleSeeked); + }; + + return PlayToggle; + }(Button); + + /** + * The text that should display over the `PlayToggle`s controls. Added for localization. + * + * @type {string} + * @private + */ + + + PlayToggle.prototype.controlText_ = 'Play'; + + Component.registerComponent('PlayToggle', PlayToggle); + + /** + * @file format-time.js + * @module format-time + */ + + /** + * Format seconds as a time string, H:MM:SS or M:SS. Supplying a guide (in seconds) + * will force a number of leading zeros to cover the length of the guide. + * + * @param {number} seconds + * Number of seconds to be turned into a string + * + * @param {number} guide + * Number (in seconds) to model the string after + * + * @return {string} + * Time formatted as H:MM:SS or M:SS + */ + var defaultImplementation = function defaultImplementation(seconds, guide) { + seconds = seconds < 0 ? 0 : seconds; + var s = Math.floor(seconds % 60); + var m = Math.floor(seconds / 60 % 60); + var h = Math.floor(seconds / 3600); + var gm = Math.floor(guide / 60 % 60); + var gh = Math.floor(guide / 3600); + + // handle invalid times + if (isNaN(seconds) || seconds === Infinity) { + // '-' is false for all relational operators (e.g. <, >=) so this setting + // will add the minimum number of fields specified by the guide + h = m = s = '-'; + } + + // Check if we need to show hours + h = h > 0 || gh > 0 ? h + ':' : ''; + + // If hours are showing, we may need to add a leading zero. + // Always show at least one digit of minutes. + m = ((h || gm >= 10) && m < 10 ? '0' + m : m) + ':'; + + // Check if leading zero is need for seconds + s = s < 10 ? '0' + s : s; + + return h + m + s; + }; + + var implementation = defaultImplementation; + + /** + * Replaces the default formatTime implementation with a custom implementation. + * + * @param {Function} customImplementation + * A function which will be used in place of the default formatTime implementation. + * Will receive the current time in seconds and the guide (in seconds) as arguments. + */ + function setFormatTime(customImplementation) { + implementation = customImplementation; + } + + /** + * Resets formatTime to the default implementation. + */ + function resetFormatTime() { + implementation = defaultImplementation; + } + + function formatTime(seconds) { + var guide = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : seconds; + + return implementation(seconds, guide); + } + + /** + * @file time-display.js + */ + + /** + * Displays the time left in the video + * + * @extends Component + */ + + var TimeDisplay = function (_Component) { + inherits(TimeDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function TimeDisplay(player, options) { + classCallCheck(this, TimeDisplay); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.throttledUpdateContent = throttle(bind(_this, _this.updateContent), 25); + _this.on(player, 'timeupdate', _this.throttledUpdateContent); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + TimeDisplay.prototype.createEl = function createEl$$1(plainName) { + var className = this.buildCSSClass(); + var el = _Component.prototype.createEl.call(this, 'div', { + className: className + ' vjs-time-control vjs-control', + innerHTML: '<span class="vjs-control-text">' + this.localize(this.labelText_) + '\xA0</span>' + }); + + this.contentEl_ = createEl('span', { + className: className + '-display' + }, { + // tell screen readers not to automatically read the time as it changes + 'aria-live': 'off' + }); + + this.updateTextNode_(); + el.appendChild(this.contentEl_); + return el; + }; + + TimeDisplay.prototype.dispose = function dispose() { + this.contentEl_ = null; + this.textNode_ = null; + + _Component.prototype.dispose.call(this); + }; + + /** + * Updates the "remaining time" text node with new content using the + * contents of the `formattedTime_` property. + * + * @private + */ + + + TimeDisplay.prototype.updateTextNode_ = function updateTextNode_() { + if (!this.contentEl_) { + return; + } + + while (this.contentEl_.firstChild) { + this.contentEl_.removeChild(this.contentEl_.firstChild); + } + + this.textNode_ = document_1.createTextNode(this.formattedTime_ || this.formatTime_(0)); + this.contentEl_.appendChild(this.textNode_); + }; + + /** + * Generates a formatted time for this component to use in display. + * + * @param {number} time + * A numeric time, in seconds. + * + * @return {string} + * A formatted time + * + * @private + */ + + + TimeDisplay.prototype.formatTime_ = function formatTime_(time) { + return formatTime(time); + }; + + /** + * Updates the time display text node if it has what was passed in changed + * the formatted time. + * + * @param {number} time + * The time to update to + * + * @private + */ + + + TimeDisplay.prototype.updateFormattedTime_ = function updateFormattedTime_(time) { + var formattedTime = this.formatTime_(time); + + if (formattedTime === this.formattedTime_) { + return; + } + + this.formattedTime_ = formattedTime; + this.requestAnimationFrame(this.updateTextNode_); + }; + + /** + * To be filled out in the child class, should update the displayed time + * in accordance with the fact that the current time has changed. + * + * @param {EventTarget~Event} [event] + * The `timeupdate` event that caused this to run. + * + * @listens Player#timeupdate + */ + + + TimeDisplay.prototype.updateContent = function updateContent(event) { + }; + + return TimeDisplay; + }(Component); + + /** + * The text that is added to the `TimeDisplay` for screen reader users. + * + * @type {string} + * @private + */ + + + TimeDisplay.prototype.labelText_ = 'Time'; + + /** + * The text that should display over the `TimeDisplay`s controls. Added to for localization. + * + * @type {string} + * @private + * + * @deprecated in v7; controlText_ is not used in non-active display Components + */ + TimeDisplay.prototype.controlText_ = 'Time'; + + Component.registerComponent('TimeDisplay', TimeDisplay); + + /** + * @file current-time-display.js + */ + + /** + * Displays the current time + * + * @extends Component + */ + + var CurrentTimeDisplay = function (_TimeDisplay) { + inherits(CurrentTimeDisplay, _TimeDisplay); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function CurrentTimeDisplay(player, options) { + classCallCheck(this, CurrentTimeDisplay); + + var _this = possibleConstructorReturn(this, _TimeDisplay.call(this, player, options)); + + _this.on(player, 'ended', _this.handleEnded); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + CurrentTimeDisplay.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-current-time'; + }; + + /** + * Update current time display + * + * @param {EventTarget~Event} [event] + * The `timeupdate` event that caused this function to run. + * + * @listens Player#timeupdate + */ + + + CurrentTimeDisplay.prototype.updateContent = function updateContent(event) { + // Allows for smooth scrubbing, when player can't keep up. + var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); + + this.updateFormattedTime_(time); + }; + + /** + * When the player fires ended there should be no time left. Sadly + * this is not always the case, lets make it seem like that is the case + * for users. + * + * @param {EventTarget~Event} [event] + * The `ended` event that caused this to run. + * + * @listens Player#ended + */ + + + CurrentTimeDisplay.prototype.handleEnded = function handleEnded(event) { + if (!this.player_.duration()) { + return; + } + this.updateFormattedTime_(this.player_.duration()); + }; + + return CurrentTimeDisplay; + }(TimeDisplay); + + /** + * The text that is added to the `CurrentTimeDisplay` for screen reader users. + * + * @type {string} + * @private + */ + + + CurrentTimeDisplay.prototype.labelText_ = 'Current Time'; + + /** + * The text that should display over the `CurrentTimeDisplay`s controls. Added to for localization. + * + * @type {string} + * @private + * + * @deprecated in v7; controlText_ is not used in non-active display Components + */ + CurrentTimeDisplay.prototype.controlText_ = 'Current Time'; + + Component.registerComponent('CurrentTimeDisplay', CurrentTimeDisplay); + + /** + * @file duration-display.js + */ + + /** + * Displays the duration + * + * @extends Component + */ + + var DurationDisplay = function (_TimeDisplay) { + inherits(DurationDisplay, _TimeDisplay); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function DurationDisplay(player, options) { + classCallCheck(this, DurationDisplay); + + // we do not want to/need to throttle duration changes, + // as they should always display the changed duration as + // it has changed + var _this = possibleConstructorReturn(this, _TimeDisplay.call(this, player, options)); + + _this.on(player, 'durationchange', _this.updateContent); + + // Also listen for timeupdate (in the parent) and loadedmetadata because removing those + // listeners could have broken dependent applications/libraries. These + // can likely be removed for 7.0. + _this.on(player, 'loadedmetadata', _this.throttledUpdateContent); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + DurationDisplay.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-duration'; + }; + + /** + * Update duration time display. + * + * @param {EventTarget~Event} [event] + * The `durationchange`, `timeupdate`, or `loadedmetadata` event that caused + * this function to be called. + * + * @listens Player#durationchange + * @listens Player#timeupdate + * @listens Player#loadedmetadata + */ + + + DurationDisplay.prototype.updateContent = function updateContent(event) { + var duration = this.player_.duration(); + + if (duration && this.duration_ !== duration) { + this.duration_ = duration; + this.updateFormattedTime_(duration); + } + }; + + return DurationDisplay; + }(TimeDisplay); + + /** + * The text that is added to the `DurationDisplay` for screen reader users. + * + * @type {string} + * @private + */ + + + DurationDisplay.prototype.labelText_ = 'Duration'; + + /** + * The text that should display over the `DurationDisplay`s controls. Added to for localization. + * + * @type {string} + * @private + * + * @deprecated in v7; controlText_ is not used in non-active display Components + */ + DurationDisplay.prototype.controlText_ = 'Duration'; + + Component.registerComponent('DurationDisplay', DurationDisplay); + + /** + * @file time-divider.js + */ + + /** + * The separator between the current time and duration. + * Can be hidden if it's not needed in the design. + * + * @extends Component + */ + + var TimeDivider = function (_Component) { + inherits(TimeDivider, _Component); + + function TimeDivider() { + classCallCheck(this, TimeDivider); + return possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the component's DOM element + * + * @return {Element} + * The element that was created. + */ + TimeDivider.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-time-control vjs-time-divider', + innerHTML: '<div><span>/</span></div>' + }); + }; + + return TimeDivider; + }(Component); + + Component.registerComponent('TimeDivider', TimeDivider); + + /** + * @file remaining-time-display.js + */ + /** + * Displays the time left in the video + * + * @extends Component + */ + + var RemainingTimeDisplay = function (_TimeDisplay) { + inherits(RemainingTimeDisplay, _TimeDisplay); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function RemainingTimeDisplay(player, options) { + classCallCheck(this, RemainingTimeDisplay); + + var _this = possibleConstructorReturn(this, _TimeDisplay.call(this, player, options)); + + _this.on(player, 'durationchange', _this.throttledUpdateContent); + _this.on(player, 'ended', _this.handleEnded); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + RemainingTimeDisplay.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-remaining-time'; + }; + + /** + * The remaining time display prefixes numbers with a "minus" character. + * + * @param {number} time + * A numeric time, in seconds. + * + * @return {string} + * A formatted time + * + * @private + */ + + + RemainingTimeDisplay.prototype.formatTime_ = function formatTime_(time) { + // TODO: The "-" should be decorative, and not announced by a screen reader + return '-' + _TimeDisplay.prototype.formatTime_.call(this, time); + }; + + /** + * Update remaining time display. + * + * @param {EventTarget~Event} [event] + * The `timeupdate` or `durationchange` event that caused this to run. + * + * @listens Player#timeupdate + * @listens Player#durationchange + */ + + + RemainingTimeDisplay.prototype.updateContent = function updateContent(event) { + if (!this.player_.duration()) { + return; + } + + // @deprecated We should only use remainingTimeDisplay + // as of video.js 7 + if (this.player_.remainingTimeDisplay) { + this.updateFormattedTime_(this.player_.remainingTimeDisplay()); + } else { + this.updateFormattedTime_(this.player_.remainingTime()); + } + }; + + /** + * When the player fires ended there should be no time left. Sadly + * this is not always the case, lets make it seem like that is the case + * for users. + * + * @param {EventTarget~Event} [event] + * The `ended` event that caused this to run. + * + * @listens Player#ended + */ + + + RemainingTimeDisplay.prototype.handleEnded = function handleEnded(event) { + if (!this.player_.duration()) { + return; + } + this.updateFormattedTime_(0); + }; + + return RemainingTimeDisplay; + }(TimeDisplay); + + /** + * The text that is added to the `RemainingTimeDisplay` for screen reader users. + * + * @type {string} + * @private + */ + + + RemainingTimeDisplay.prototype.labelText_ = 'Remaining Time'; + + /** + * The text that should display over the `RemainingTimeDisplay`s controls. Added to for localization. + * + * @type {string} + * @private + * + * @deprecated in v7; controlText_ is not used in non-active display Components + */ + RemainingTimeDisplay.prototype.controlText_ = 'Remaining Time'; + + Component.registerComponent('RemainingTimeDisplay', RemainingTimeDisplay); + + /** + * @file live-display.js + */ + + // TODO - Future make it click to snap to live + + /** + * Displays the live indicator when duration is Infinity. + * + * @extends Component + */ + + var LiveDisplay = function (_Component) { + inherits(LiveDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function LiveDisplay(player, options) { + classCallCheck(this, LiveDisplay); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.updateShowing(); + _this.on(_this.player(), 'durationchange', _this.updateShowing); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + LiveDisplay.prototype.createEl = function createEl$$1() { + var el = _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-live-control vjs-control' + }); + + this.contentEl_ = createEl('div', { + className: 'vjs-live-display', + innerHTML: '<span class="vjs-control-text">' + this.localize('Stream Type') + '\xA0</span>' + this.localize('LIVE') + }, { + 'aria-live': 'off' + }); + + el.appendChild(this.contentEl_); + return el; + }; + + LiveDisplay.prototype.dispose = function dispose() { + this.contentEl_ = null; + + _Component.prototype.dispose.call(this); + }; + + /** + * Check the duration to see if the LiveDisplay should be showing or not. Then show/hide + * it accordingly + * + * @param {EventTarget~Event} [event] + * The {@link Player#durationchange} event that caused this function to run. + * + * @listens Player#durationchange + */ + + + LiveDisplay.prototype.updateShowing = function updateShowing(event) { + if (this.player().duration() === Infinity) { + this.show(); + } else { + this.hide(); + } + }; + + return LiveDisplay; + }(Component); + + Component.registerComponent('LiveDisplay', LiveDisplay); + + /** + * @file slider.js + */ + + /** + * The base functionality for a slider. Can be vertical or horizontal. + * For instance the volume bar or the seek bar on a video is a slider. + * + * @extends Component + */ + + var Slider = function (_Component) { + inherits(Slider, _Component); + + /** + * Create an instance of this class + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function Slider(player, options) { + classCallCheck(this, Slider); + + // Set property names to bar to match with the child Slider class is looking for + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.bar = _this.getChild(_this.options_.barName); + + // Set a horizontal or vertical class on the slider depending on the slider type + _this.vertical(!!_this.options_.vertical); + + _this.enable(); + return _this; + } + + /** + * Are controls are currently enabled for this slider or not. + * + * @return {boolean} + * true if controls are enabled, false otherwise + */ + + + Slider.prototype.enabled = function enabled() { + return this.enabled_; + }; + + /** + * Enable controls for this slider if they are disabled + */ + + + Slider.prototype.enable = function enable() { + if (this.enabled()) { + return; + } + + this.on('mousedown', this.handleMouseDown); + this.on('touchstart', this.handleMouseDown); + this.on('focus', this.handleFocus); + this.on('blur', this.handleBlur); + this.on('click', this.handleClick); + + this.on(this.player_, 'controlsvisible', this.update); + + if (this.playerEvent) { + this.on(this.player_, this.playerEvent, this.update); + } + + this.removeClass('disabled'); + this.setAttribute('tabindex', 0); + + this.enabled_ = true; + }; + + /** + * Disable controls for this slider if they are enabled + */ + + + Slider.prototype.disable = function disable() { + if (!this.enabled()) { + return; + } + var doc = this.bar.el_.ownerDocument; + + this.off('mousedown', this.handleMouseDown); + this.off('touchstart', this.handleMouseDown); + this.off('focus', this.handleFocus); + this.off('blur', this.handleBlur); + this.off('click', this.handleClick); + this.off(this.player_, 'controlsvisible', this.update); + this.off(doc, 'mousemove', this.handleMouseMove); + this.off(doc, 'mouseup', this.handleMouseUp); + this.off(doc, 'touchmove', this.handleMouseMove); + this.off(doc, 'touchend', this.handleMouseUp); + this.removeAttribute('tabindex'); + + this.addClass('disabled'); + + if (this.playerEvent) { + this.off(this.player_, this.playerEvent, this.update); + } + this.enabled_ = false; + }; + + /** + * Create the `Slider`s DOM element. + * + * @param {string} type + * Type of element to create. + * + * @param {Object} [props={}] + * List of properties in Object form. + * + * @param {Object} [attributes={}] + * list of attributes in Object form. + * + * @return {Element} + * The element that gets created. + */ + + + Slider.prototype.createEl = function createEl$$1(type) { + var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + // Add the slider element class to all sub classes + props.className = props.className + ' vjs-slider'; + props = assign({ + tabIndex: 0 + }, props); + + attributes = assign({ + 'role': 'slider', + 'aria-valuenow': 0, + 'aria-valuemin': 0, + 'aria-valuemax': 100, + 'tabIndex': 0 + }, attributes); + + return _Component.prototype.createEl.call(this, type, props, attributes); + }; + + /** + * Handle `mousedown` or `touchstart` events on the `Slider`. + * + * @param {EventTarget~Event} event + * `mousedown` or `touchstart` event that triggered this function + * + * @listens mousedown + * @listens touchstart + * @fires Slider#slideractive + */ + + + Slider.prototype.handleMouseDown = function handleMouseDown(event) { + var doc = this.bar.el_.ownerDocument; + + event.preventDefault(); + blockTextSelection(); + + this.addClass('vjs-sliding'); + /** + * Triggered when the slider is in an active state + * + * @event Slider#slideractive + * @type {EventTarget~Event} + */ + this.trigger('slideractive'); + + this.on(doc, 'mousemove', this.handleMouseMove); + this.on(doc, 'mouseup', this.handleMouseUp); + this.on(doc, 'touchmove', this.handleMouseMove); + this.on(doc, 'touchend', this.handleMouseUp); + + this.handleMouseMove(event); + }; + + /** + * Handle the `mousemove`, `touchmove`, and `mousedown` events on this `Slider`. + * The `mousemove` and `touchmove` events will only only trigger this function during + * `mousedown` and `touchstart`. This is due to {@link Slider#handleMouseDown} and + * {@link Slider#handleMouseUp}. + * + * @param {EventTarget~Event} event + * `mousedown`, `mousemove`, `touchstart`, or `touchmove` event that triggered + * this function + * + * @listens mousemove + * @listens touchmove + */ + + + Slider.prototype.handleMouseMove = function handleMouseMove(event) { + }; + + /** + * Handle `mouseup` or `touchend` events on the `Slider`. + * + * @param {EventTarget~Event} event + * `mouseup` or `touchend` event that triggered this function. + * + * @listens touchend + * @listens mouseup + * @fires Slider#sliderinactive + */ + + + Slider.prototype.handleMouseUp = function handleMouseUp() { + var doc = this.bar.el_.ownerDocument; + + unblockTextSelection(); + + this.removeClass('vjs-sliding'); + /** + * Triggered when the slider is no longer in an active state. + * + * @event Slider#sliderinactive + * @type {EventTarget~Event} + */ + this.trigger('sliderinactive'); + + this.off(doc, 'mousemove', this.handleMouseMove); + this.off(doc, 'mouseup', this.handleMouseUp); + this.off(doc, 'touchmove', this.handleMouseMove); + this.off(doc, 'touchend', this.handleMouseUp); + + this.update(); + }; + + /** + * Update the progress bar of the `Slider`. + * + * @returns {number} + * The percentage of progress the progress bar represents as a + * number from 0 to 1. + */ + + + Slider.prototype.update = function update() { + + // In VolumeBar init we have a setTimeout for update that pops and update + // to the end of the execution stack. The player is destroyed before then + // update will cause an error + if (!this.el_) { + return; + } + + // If scrubbing, we could use a cached value to make the handle keep up + // with the user's mouse. On HTML5 browsers scrubbing is really smooth, but + // some flash players are slow, so we might want to utilize this later. + // var progress = (this.player_.scrubbing()) ? this.player_.getCache().currentTime / this.player_.duration() : this.player_.currentTime() / this.player_.duration(); + var progress = this.getPercent(); + var bar = this.bar; + + // If there's no bar... + if (!bar) { + return; + } + + // Protect against no duration and other division issues + if (typeof progress !== 'number' || progress !== progress || progress < 0 || progress === Infinity) { + progress = 0; + } + + // Convert to a percentage for setting + var percentage = (progress * 100).toFixed(2) + '%'; + var style = bar.el().style; + + // Set the new bar width or height + if (this.vertical()) { + style.height = percentage; + } else { + style.width = percentage; + } + + return progress; + }; + + /** + * Calculate distance for slider + * + * @param {EventTarget~Event} event + * The event that caused this function to run. + * + * @return {number} + * The current position of the Slider. + * - position.x for vertical `Slider`s + * - position.y for horizontal `Slider`s + */ + + + Slider.prototype.calculateDistance = function calculateDistance(event) { + var position = getPointerPosition(this.el_, event); + + if (this.vertical()) { + return position.y; + } + return position.x; + }; + + /** + * Handle a `focus` event on this `Slider`. + * + * @param {EventTarget~Event} event + * The `focus` event that caused this function to run. + * + * @listens focus + */ + + + Slider.prototype.handleFocus = function handleFocus() { + this.on(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress); + }; + + /** + * Handle a `keydown` event on the `Slider`. Watches for left, rigth, up, and down + * arrow keys. This function will only be called when the slider has focus. See + * {@link Slider#handleFocus} and {@link Slider#handleBlur}. + * + * @param {EventTarget~Event} event + * the `keydown` event that caused this function to run. + * + * @listens keydown + */ + + + Slider.prototype.handleKeyPress = function handleKeyPress(event) { + // Left and Down Arrows + if (event.which === 37 || event.which === 40) { + event.preventDefault(); + this.stepBack(); + + // Up and Right Arrows + } else if (event.which === 38 || event.which === 39) { + event.preventDefault(); + this.stepForward(); + } + }; + + /** + * Handle a `blur` event on this `Slider`. + * + * @param {EventTarget~Event} event + * The `blur` event that caused this function to run. + * + * @listens blur + */ + + Slider.prototype.handleBlur = function handleBlur() { + this.off(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress); + }; + + /** + * Listener for click events on slider, used to prevent clicks + * from bubbling up to parent elements like button menus. + * + * @param {Object} event + * Event that caused this object to run + */ + + + Slider.prototype.handleClick = function handleClick(event) { + event.stopImmediatePropagation(); + event.preventDefault(); + }; + + /** + * Get/set if slider is horizontal for vertical + * + * @param {boolean} [bool] + * - true if slider is vertical, + * - false is horizontal + * + * @return {boolean} + * - true if slider is vertical, and getting + * - false if the slider is horizontal, and getting + */ + + + Slider.prototype.vertical = function vertical(bool) { + if (bool === undefined) { + return this.vertical_ || false; + } + + this.vertical_ = !!bool; + + if (this.vertical_) { + this.addClass('vjs-slider-vertical'); + } else { + this.addClass('vjs-slider-horizontal'); + } + }; + + return Slider; + }(Component); + + Component.registerComponent('Slider', Slider); + + /** + * @file load-progress-bar.js + */ + + /** + * Shows loading progress + * + * @extends Component + */ + + var LoadProgressBar = function (_Component) { + inherits(LoadProgressBar, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function LoadProgressBar(player, options) { + classCallCheck(this, LoadProgressBar); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.partEls_ = []; + _this.on(player, 'progress', _this.update); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + LoadProgressBar.prototype.createEl = function createEl$$1() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-load-progress', + innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Loaded') + '</span>: 0%</span>' + }); + }; + + LoadProgressBar.prototype.dispose = function dispose() { + this.partEls_ = null; + + _Component.prototype.dispose.call(this); + }; + + /** + * Update progress bar + * + * @param {EventTarget~Event} [event] + * The `progress` event that caused this function to run. + * + * @listens Player#progress + */ + + + LoadProgressBar.prototype.update = function update(event) { + var buffered = this.player_.buffered(); + var duration = this.player_.duration(); + var bufferedEnd = this.player_.bufferedEnd(); + var children = this.partEls_; + + // get the percent width of a time compared to the total end + var percentify = function percentify(time, end) { + // no NaN + var percent = time / end || 0; + + return (percent >= 1 ? 1 : percent) * 100 + '%'; + }; + + // update the width of the progress bar + this.el_.style.width = percentify(bufferedEnd, duration); + + // add child elements to represent the individual buffered time ranges + for (var i = 0; i < buffered.length; i++) { + var start = buffered.start(i); + var end = buffered.end(i); + var part = children[i]; + + if (!part) { + part = this.el_.appendChild(createEl()); + children[i] = part; + } + + // set the percent based on the width of the progress bar (bufferedEnd) + part.style.left = percentify(start, bufferedEnd); + part.style.width = percentify(end - start, bufferedEnd); + } + + // remove unused buffered range elements + for (var _i = children.length; _i > buffered.length; _i--) { + this.el_.removeChild(children[_i - 1]); + } + children.length = buffered.length; + }; + + return LoadProgressBar; + }(Component); + + Component.registerComponent('LoadProgressBar', LoadProgressBar); + + /** + * @file time-tooltip.js + */ + + /** + * Time tooltips display a time above the progress bar. + * + * @extends Component + */ + + var TimeTooltip = function (_Component) { + inherits(TimeTooltip, _Component); + + function TimeTooltip() { + classCallCheck(this, TimeTooltip); + return possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the time tooltip DOM element + * + * @return {Element} + * The element that was created. + */ + TimeTooltip.prototype.createEl = function createEl$$1() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-time-tooltip' + }); + }; + + /** + * Updates the position of the time tooltip relative to the `SeekBar`. + * + * @param {Object} seekBarRect + * The `ClientRect` for the {@link SeekBar} element. + * + * @param {number} seekBarPoint + * A number from 0 to 1, representing a horizontal reference point + * from the left edge of the {@link SeekBar} + */ + + + TimeTooltip.prototype.update = function update(seekBarRect, seekBarPoint, content) { + var tooltipRect = getBoundingClientRect(this.el_); + var playerRect = getBoundingClientRect(this.player_.el()); + var seekBarPointPx = seekBarRect.width * seekBarPoint; + + // do nothing if either rect isn't available + // for example, if the player isn't in the DOM for testing + if (!playerRect || !tooltipRect) { + return; + } + + // This is the space left of the `seekBarPoint` available within the bounds + // of the player. We calculate any gap between the left edge of the player + // and the left edge of the `SeekBar` and add the number of pixels in the + // `SeekBar` before hitting the `seekBarPoint` + var spaceLeftOfPoint = seekBarRect.left - playerRect.left + seekBarPointPx; + + // This is the space right of the `seekBarPoint` available within the bounds + // of the player. We calculate the number of pixels from the `seekBarPoint` + // to the right edge of the `SeekBar` and add to that any gap between the + // right edge of the `SeekBar` and the player. + var spaceRightOfPoint = seekBarRect.width - seekBarPointPx + (playerRect.right - seekBarRect.right); + + // This is the number of pixels by which the tooltip will need to be pulled + // further to the right to center it over the `seekBarPoint`. + var pullTooltipBy = tooltipRect.width / 2; + + // Adjust the `pullTooltipBy` distance to the left or right depending on + // the results of the space calculations above. + if (spaceLeftOfPoint < pullTooltipBy) { + pullTooltipBy += pullTooltipBy - spaceLeftOfPoint; + } else if (spaceRightOfPoint < pullTooltipBy) { + pullTooltipBy = spaceRightOfPoint; + } + + // Due to the imprecision of decimal/ratio based calculations and varying + // rounding behaviors, there are cases where the spacing adjustment is off + // by a pixel or two. This adds insurance to these calculations. + if (pullTooltipBy < 0) { + pullTooltipBy = 0; + } else if (pullTooltipBy > tooltipRect.width) { + pullTooltipBy = tooltipRect.width; + } + + this.el_.style.right = '-' + pullTooltipBy + 'px'; + textContent(this.el_, content); + }; + + return TimeTooltip; + }(Component); + + Component.registerComponent('TimeTooltip', TimeTooltip); + + /** + * @file playOld-progress-bar.js + */ + + /** + * Used by {@link SeekBar} to display media playback progress as part of the + * {@link ProgressControl}. + * + * @extends Component + */ + + var PlayProgressBar = function (_Component) { + inherits(PlayProgressBar, _Component); + + function PlayProgressBar() { + classCallCheck(this, PlayProgressBar); + return possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the the DOM element for this class. + * + * @return {Element} + * The element that was created. + */ + PlayProgressBar.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-playOld-progress vjs-slider-bar', + innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>' + }); + }; + + /** + * Enqueues updates to its own DOM as well as the DOM of its + * {@link TimeTooltip} child. + * + * @param {Object} seekBarRect + * The `ClientRect` for the {@link SeekBar} element. + * + * @param {number} seekBarPoint + * A number from 0 to 1, representing a horizontal reference point + * from the left edge of the {@link SeekBar} + */ + + + PlayProgressBar.prototype.update = function update(seekBarRect, seekBarPoint) { + var _this2 = this; + + // If there is an existing rAF ID, cancel it so we don't over-queue. + if (this.rafId_) { + this.cancelAnimationFrame(this.rafId_); + } + + this.rafId_ = this.requestAnimationFrame(function () { + var time = _this2.player_.scrubbing() ? _this2.player_.getCache().currentTime : _this2.player_.currentTime(); + + var content = formatTime(time, _this2.player_.duration()); + var timeTooltip = _this2.getChild('timeTooltip'); + + if (timeTooltip) { + timeTooltip.update(seekBarRect, seekBarPoint, content); + } + }); + }; + + return PlayProgressBar; + }(Component); + + /** + * Default options for {@link PlayProgressBar}. + * + * @type {Object} + * @private + */ + + + PlayProgressBar.prototype.options_ = { + children: [] + }; + + // Time tooltips should not be added to a player on mobile devices + if (!IS_IOS && !IS_ANDROID) { + PlayProgressBar.prototype.options_.children.push('timeTooltip'); + } + + Component.registerComponent('PlayProgressBar', PlayProgressBar); + + /** + * @file mouse-time-display.js + */ + + /** + * The {@link MouseTimeDisplay} component tracks mouse movement over the + * {@link ProgressControl}. It displays an indicator and a {@link TimeTooltip} + * indicating the time which is represented by a given point in the + * {@link ProgressControl}. + * + * @extends Component + */ + + var MouseTimeDisplay = function (_Component) { + inherits(MouseTimeDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The {@link Player} that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function MouseTimeDisplay(player, options) { + classCallCheck(this, MouseTimeDisplay); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.update = throttle(bind(_this, _this.update), 25); + return _this; + } + + /** + * Create the DOM element for this class. + * + * @return {Element} + * The element that was created. + */ + + + MouseTimeDisplay.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-mouse-display' + }); + }; + + /** + * Enqueues updates to its own DOM as well as the DOM of its + * {@link TimeTooltip} child. + * + * @param {Object} seekBarRect + * The `ClientRect` for the {@link SeekBar} element. + * + * @param {number} seekBarPoint + * A number from 0 to 1, representing a horizontal reference point + * from the left edge of the {@link SeekBar} + */ + + + MouseTimeDisplay.prototype.update = function update(seekBarRect, seekBarPoint) { + var _this2 = this; + + // If there is an existing rAF ID, cancel it so we don't over-queue. + if (this.rafId_) { + this.cancelAnimationFrame(this.rafId_); + } + + this.rafId_ = this.requestAnimationFrame(function () { + var duration = _this2.player_.duration(); + var content = formatTime(seekBarPoint * duration, duration); + + _this2.el_.style.left = seekBarRect.width * seekBarPoint + 'px'; + _this2.getChild('timeTooltip').update(seekBarRect, seekBarPoint, content); + }); + }; + + return MouseTimeDisplay; + }(Component); + + /** + * Default options for `MouseTimeDisplay` + * + * @type {Object} + * @private + */ + + + MouseTimeDisplay.prototype.options_ = { + children: ['timeTooltip'] + }; + + Component.registerComponent('MouseTimeDisplay', MouseTimeDisplay); + + /** + * @file seek-bar.js + */ + + // The number of seconds the `step*` functions move the timeline. + var STEP_SECONDS = 5; + + // The interval at which the bar should update as it progresses. + var UPDATE_REFRESH_INTERVAL = 30; + + /** + * Seek bar and container for the progress bars. Uses {@link PlayProgressBar} + * as its `bar`. + * + * @extends Slider + */ + + var SeekBar = function (_Slider) { + inherits(SeekBar, _Slider); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function SeekBar(player, options) { + classCallCheck(this, SeekBar); + + var _this = possibleConstructorReturn(this, _Slider.call(this, player, options)); + + _this.setEventHandlers_(); + return _this; + } + + /** + * Sets the event handlers + * + * @private + */ + + + SeekBar.prototype.setEventHandlers_ = function setEventHandlers_() { + var _this2 = this; + + this.update = throttle(bind(this, this.update), UPDATE_REFRESH_INTERVAL); + + this.on(this.player_, 'timeupdate', this.update); + this.on(this.player_, 'ended', this.handleEnded); + + // when playing, let's ensure we smoothly update the playOld progress bar + // via an interval + this.updateInterval = null; + + this.on(this.player_, ['playing'], function () { + _this2.clearInterval(_this2.updateInterval); + + _this2.updateInterval = _this2.setInterval(function () { + _this2.requestAnimationFrame(function () { + _this2.update(); + }); + }, UPDATE_REFRESH_INTERVAL); + }); + + this.on(this.player_, ['ended', 'pause', 'waiting'], function () { + _this2.clearInterval(_this2.updateInterval); + }); + + this.on(this.player_, ['timeupdate', 'ended'], this.update); + }; + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + SeekBar.prototype.createEl = function createEl$$1() { + return _Slider.prototype.createEl.call(this, 'div', { + className: 'vjs-progress-holder' + }, { + 'aria-label': this.localize('Progress Bar') + }); + }; + + /** + * This function updates the playOld progress bar and accessibility + * attributes to whatever is passed in. + * + * @param {number} currentTime + * The currentTime value that should be used for accessibility + * + * @param {number} percent + * The percentage as a decimal that the bar should be filled from 0-1. + * + * @private + */ + + + SeekBar.prototype.update_ = function update_(currentTime, percent) { + var duration = this.player_.duration(); + + // machine readable value of progress bar (percentage complete) + this.el_.setAttribute('aria-valuenow', (percent * 100).toFixed(2)); + + // human readable value of progress bar (time complete) + this.el_.setAttribute('aria-valuetext', this.localize('progress bar timing: currentTime={1} duration={2}', [formatTime(currentTime, duration), formatTime(duration, duration)], '{1} of {2}')); + + // Update the `PlayProgressBar`. + this.bar.update(getBoundingClientRect(this.el_), percent); + }; + + /** + * Update the seek bar's UI. + * + * @param {EventTarget~Event} [event] + * The `timeupdate` or `ended` event that caused this to run. + * + * @listens Player#timeupdate + * + * @returns {number} + * The current percent at a number from 0-1 + */ + + + SeekBar.prototype.update = function update(event) { + var percent = _Slider.prototype.update.call(this); + + this.update_(this.getCurrentTime_(), percent); + return percent; + }; + + /** + * Get the value of current time but allows for smooth scrubbing, + * when player can't keep up. + * + * @return {number} + * The current time value to display + * + * @private + */ + + + SeekBar.prototype.getCurrentTime_ = function getCurrentTime_() { + return this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); + }; + + /** + * We want the seek bar to be full on ended + * no matter what the actual internal values are. so we force it. + * + * @param {EventTarget~Event} [event] + * The `timeupdate` or `ended` event that caused this to run. + * + * @listens Player#ended + */ + + + SeekBar.prototype.handleEnded = function handleEnded(event) { + this.update_(this.player_.duration(), 1); + }; + + /** + * Get the percentage of media played so far. + * + * @return {number} + * The percentage of media played so far (0 to 1). + */ + + + SeekBar.prototype.getPercent = function getPercent() { + var percent = this.getCurrentTime_() / this.player_.duration(); + + return percent >= 1 ? 1 : percent || 0; + }; + + /** + * Handle mouse down on seek bar + * + * @param {EventTarget~Event} event + * The `mousedown` event that caused this to run. + * + * @listens mousedown + */ + + + SeekBar.prototype.handleMouseDown = function handleMouseDown(event) { + if (!isSingleLeftClick(event)) { + return; + } + + // Stop event propagation to prevent double fire in progress-control.js + event.stopPropagation(); + this.player_.scrubbing(true); + + this.videoWasPlaying = !this.player_.paused(); + this.player_.pause(); + + _Slider.prototype.handleMouseDown.call(this, event); + }; + + /** + * Handle mouse move on seek bar + * + * @param {EventTarget~Event} event + * The `mousemove` event that caused this to run. + * + * @listens mousemove + */ + + + SeekBar.prototype.handleMouseMove = function handleMouseMove(event) { + if (!isSingleLeftClick(event)) { + return; + } + + var newTime = this.calculateDistance(event) * this.player_.duration(); + + // Don't let video end while scrubbing. + if (newTime === this.player_.duration()) { + newTime = newTime - 0.1; + } + + // Set new time (tell player to seek to new time) + this.player_.currentTime(newTime); + }; + + SeekBar.prototype.enable = function enable() { + _Slider.prototype.enable.call(this); + var mouseTimeDisplay = this.getChild('mouseTimeDisplay'); + + if (!mouseTimeDisplay) { + return; + } + + mouseTimeDisplay.show(); + }; + + SeekBar.prototype.disable = function disable() { + _Slider.prototype.disable.call(this); + var mouseTimeDisplay = this.getChild('mouseTimeDisplay'); + + if (!mouseTimeDisplay) { + return; + } + + mouseTimeDisplay.hide(); + }; + + /** + * Handle mouse up on seek bar + * + * @param {EventTarget~Event} event + * The `mouseup` event that caused this to run. + * + * @listens mouseup + */ + + + SeekBar.prototype.handleMouseUp = function handleMouseUp(event) { + _Slider.prototype.handleMouseUp.call(this, event); + + // Stop event propagation to prevent double fire in progress-control.js + if (event) { + event.stopPropagation(); + } + this.player_.scrubbing(false); + + /** + * Trigger timeupdate because we're done seeking and the time has changed. + * This is particularly useful for if the player is paused to time the time displays. + * + * @event Tech#timeupdate + * @type {EventTarget~Event} + */ + this.player_.trigger({type: 'timeupdate', target: this, manuallyTriggered: true}); + if (this.videoWasPlaying) { + silencePromise(this.player_.play()); + } + }; + + /** + * Move more quickly fast forward for keyboard-only users + */ + + + SeekBar.prototype.stepForward = function stepForward() { + this.player_.currentTime(this.player_.currentTime() + STEP_SECONDS); + }; + + /** + * Move more quickly rewind for keyboard-only users + */ + + + SeekBar.prototype.stepBack = function stepBack() { + this.player_.currentTime(this.player_.currentTime() - STEP_SECONDS); + }; + + /** + * Toggles the playback state of the player + * This gets called when enter or space is used on the seekbar + * + * @param {EventTarget~Event} event + * The `keydown` event that caused this function to be called + * + */ + + + SeekBar.prototype.handleAction = function handleAction(event) { + if (this.player_.paused()) { + this.player_.play(); + } else { + this.player_.pause(); + } + }; + + /** + * Called when this SeekBar has focus and a key gets pressed down. By + * default it will call `this.handleAction` when the key is space or enter. + * + * @param {EventTarget~Event} event + * The `keydown` event that caused this function to be called. + * + * @listens keydown + */ + + + SeekBar.prototype.handleKeyPress = function handleKeyPress(event) { + + // Support Space (32) or Enter (13) key operation to fire a click event + if (event.which === 32 || event.which === 13) { + event.preventDefault(); + this.handleAction(event); + } else if (_Slider.prototype.handleKeyPress) { + + // Pass keypress handling up for unsupported keys + _Slider.prototype.handleKeyPress.call(this, event); + } + }; + + return SeekBar; + }(Slider); + + /** + * Default options for the `SeekBar` + * + * @type {Object} + * @private + */ + + + SeekBar.prototype.options_ = { + children: ['loadProgressBar', 'playProgressBar'], + barName: 'playProgressBar' + }; + + // MouseTimeDisplay tooltips should not be added to a player on mobile devices + if (!IS_IOS && !IS_ANDROID) { + SeekBar.prototype.options_.children.splice(1, 0, 'mouseTimeDisplay'); + } + + /** + * Call the update event for this Slider when this event happens on the player. + * + * @type {string} + */ + SeekBar.prototype.playerEvent = 'timeupdate'; + + Component.registerComponent('SeekBar', SeekBar); + + /** + * @file progress-control.js + */ + + /** + * The Progress Control component contains the seek bar, load progress, + * and playOld progress. + * + * @extends Component + */ + + var ProgressControl = function (_Component) { + inherits(ProgressControl, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function ProgressControl(player, options) { + classCallCheck(this, ProgressControl); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.handleMouseMove = throttle(bind(_this, _this.handleMouseMove), 25); + _this.throttledHandleMouseSeek = throttle(bind(_this, _this.handleMouseSeek), 25); + + _this.enable(); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + ProgressControl.prototype.createEl = function createEl$$1() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-progress-control vjs-control' + }); + }; + + /** + * When the mouse moves over the `ProgressControl`, the pointer position + * gets passed down to the `MouseTimeDisplay` component. + * + * @param {EventTarget~Event} event + * The `mousemove` event that caused this function to run. + * + * @listen mousemove + */ + + + ProgressControl.prototype.handleMouseMove = function handleMouseMove(event) { + var seekBar = this.getChild('seekBar'); + + if (seekBar) { + var mouseTimeDisplay = seekBar.getChild('mouseTimeDisplay'); + var seekBarEl = seekBar.el(); + var seekBarRect = getBoundingClientRect(seekBarEl); + var seekBarPoint = getPointerPosition(seekBarEl, event).x; + + // The default skin has a gap on either side of the `SeekBar`. This means + // that it's possible to trigger this behavior outside the boundaries of + // the `SeekBar`. This ensures we stay within it at all times. + if (seekBarPoint > 1) { + seekBarPoint = 1; + } else if (seekBarPoint < 0) { + seekBarPoint = 0; + } + + if (mouseTimeDisplay) { + mouseTimeDisplay.update(seekBarRect, seekBarPoint); + } + } + }; + + /** + * A throttled version of the {@link ProgressControl#handleMouseSeek} listener. + * + * @method ProgressControl#throttledHandleMouseSeek + * @param {EventTarget~Event} event + * The `mousemove` event that caused this function to run. + * + * @listen mousemove + * @listen touchmove + */ + + /** + * Handle `mousemove` or `touchmove` events on the `ProgressControl`. + * + * @param {EventTarget~Event} event + * `mousedown` or `touchstart` event that triggered this function + * + * @listens mousemove + * @listens touchmove + */ + + + ProgressControl.prototype.handleMouseSeek = function handleMouseSeek(event) { + var seekBar = this.getChild('seekBar'); + + if (seekBar) { + seekBar.handleMouseMove(event); + } + }; + + /** + * Are controls are currently enabled for this progress control. + * + * @return {boolean} + * true if controls are enabled, false otherwise + */ + + + ProgressControl.prototype.enabled = function enabled() { + return this.enabled_; + }; + + /** + * Disable all controls on the progress control and its children + */ + + + ProgressControl.prototype.disable = function disable() { + this.children().forEach(function (child) { + return child.disable && child.disable(); + }); + + if (!this.enabled()) { + return; + } + + this.off(['mousedown', 'touchstart'], this.handleMouseDown); + this.off(this.el_, 'mousemove', this.handleMouseMove); + this.handleMouseUp(); + + this.addClass('disabled'); + + this.enabled_ = false; + }; + + /** + * Enable all controls on the progress control and its children + */ + + + ProgressControl.prototype.enable = function enable() { + this.children().forEach(function (child) { + return child.enable && child.enable(); + }); + + if (this.enabled()) { + return; + } + + this.on(['mousedown', 'touchstart'], this.handleMouseDown); + this.on(this.el_, 'mousemove', this.handleMouseMove); + this.removeClass('disabled'); + + this.enabled_ = true; + }; + + /** + * Handle `mousedown` or `touchstart` events on the `ProgressControl`. + * + * @param {EventTarget~Event} event + * `mousedown` or `touchstart` event that triggered this function + * + * @listens mousedown + * @listens touchstart + */ + + + ProgressControl.prototype.handleMouseDown = function handleMouseDown(event) { + var doc = this.el_.ownerDocument; + var seekBar = this.getChild('seekBar'); + + if (seekBar) { + seekBar.handleMouseDown(event); + } + + this.on(doc, 'mousemove', this.throttledHandleMouseSeek); + this.on(doc, 'touchmove', this.throttledHandleMouseSeek); + this.on(doc, 'mouseup', this.handleMouseUp); + this.on(doc, 'touchend', this.handleMouseUp); + }; + + /** + * Handle `mouseup` or `touchend` events on the `ProgressControl`. + * + * @param {EventTarget~Event} event + * `mouseup` or `touchend` event that triggered this function. + * + * @listens touchend + * @listens mouseup + */ + + + ProgressControl.prototype.handleMouseUp = function handleMouseUp(event) { + var doc = this.el_.ownerDocument; + var seekBar = this.getChild('seekBar'); + + if (seekBar) { + seekBar.handleMouseUp(event); + } + + this.off(doc, 'mousemove', this.throttledHandleMouseSeek); + this.off(doc, 'touchmove', this.throttledHandleMouseSeek); + this.off(doc, 'mouseup', this.handleMouseUp); + this.off(doc, 'touchend', this.handleMouseUp); + }; + + return ProgressControl; + }(Component); + + /** + * Default options for `ProgressControl` + * + * @type {Object} + * @private + */ + + + ProgressControl.prototype.options_ = { + children: ['seekBar'] + }; + + Component.registerComponent('ProgressControl', ProgressControl); + + /** + * @file fullscreen-toggle.js + */ + + /** + * Toggle fullscreen video + * + * @extends Button + */ + + var FullscreenToggle = function (_Button) { + inherits(FullscreenToggle, _Button); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function FullscreenToggle(player, options) { + classCallCheck(this, FullscreenToggle); + + var _this = possibleConstructorReturn(this, _Button.call(this, player, options)); + + _this.on(player, 'fullscreenchange', _this.handleFullscreenChange); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this); + }; + + /** + * Handles fullscreenchange on the player and change control text accordingly. + * + * @param {EventTarget~Event} [event] + * The {@link Player#fullscreenchange} event that caused this function to be + * called. + * + * @listens Player#fullscreenchange + */ + + + FullscreenToggle.prototype.handleFullscreenChange = function handleFullscreenChange(event) { + if (this.player_.isFullscreen()) { + this.controlText('Non-Fullscreen'); + } else { + this.controlText('Fullscreen'); + } + }; + + /** + * This gets called when an `FullscreenToggle` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + FullscreenToggle.prototype.handleClick = function handleClick(event) { + if (!this.player_.isFullscreen()) { + this.player_.requestFullscreen(); + } else { + this.player_.exitFullscreen(); + } + }; + + return FullscreenToggle; + }(Button); + + /** + * The text that should display over the `FullscreenToggle`s controls. Added for localization. + * + * @type {string} + * @private + */ + + + FullscreenToggle.prototype.controlText_ = 'Fullscreen'; + + Component.registerComponent('FullscreenToggle', FullscreenToggle); + + /** + * Check if volume control is supported and if it isn't hide the + * `Component` that was passed using the `vjs-hidden` class. + * + * @param {Component} self + * The component that should be hidden if volume is unsupported + * + * @param {Player} player + * A reference to the player + * + * @private + */ + var checkVolumeSupport = function checkVolumeSupport(self, player) { + // hide volume controls when they're not supported by the current tech + if (player.tech_ && !player.tech_.featuresVolumeControl) { + self.addClass('vjs-hidden'); + } + + self.on(player, 'loadstart', function () { + if (!player.tech_.featuresVolumeControl) { + self.addClass('vjs-hidden'); + } else { + self.removeClass('vjs-hidden'); + } + }); + }; + + /** + * @file volume-level.js + */ + + /** + * Shows volume level + * + * @extends Component + */ + + var VolumeLevel = function (_Component) { + inherits(VolumeLevel, _Component); + + function VolumeLevel() { + classCallCheck(this, VolumeLevel); + return possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + VolumeLevel.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-volume-level', + innerHTML: '<span class="vjs-control-text"></span>' + }); + }; + + return VolumeLevel; + }(Component); + + Component.registerComponent('VolumeLevel', VolumeLevel); + + /** + * @file volume-bar.js + */ + + /** + * The bar that contains the volume level and can be clicked on to adjust the level + * + * @extends Slider + */ + + var VolumeBar = function (_Slider) { + inherits(VolumeBar, _Slider); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function VolumeBar(player, options) { + classCallCheck(this, VolumeBar); + + var _this = possibleConstructorReturn(this, _Slider.call(this, player, options)); + + _this.on('slideractive', _this.updateLastVolume_); + _this.on(player, 'volumechange', _this.updateARIAAttributes); + player.ready(function () { + return _this.updateARIAAttributes(); + }); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + VolumeBar.prototype.createEl = function createEl$$1() { + return _Slider.prototype.createEl.call(this, 'div', { + className: 'vjs-volume-bar vjs-slider-bar' + }, { + 'aria-label': this.localize('Volume Level'), + 'aria-live': 'polite' + }); + }; + + /** + * Handle mouse down on volume bar + * + * @param {EventTarget~Event} event + * The `mousedown` event that caused this to run. + * + * @listens mousedown + */ + + + VolumeBar.prototype.handleMouseDown = function handleMouseDown(event) { + if (!isSingleLeftClick(event)) { + return; + } + + _Slider.prototype.handleMouseDown.call(this, event); + }; + + /** + * Handle movement events on the {@link VolumeMenuButton}. + * + * @param {EventTarget~Event} event + * The event that caused this function to run. + * + * @listens mousemove + */ + + + VolumeBar.prototype.handleMouseMove = function handleMouseMove(event) { + if (!isSingleLeftClick(event)) { + return; + } + + this.checkMuted(); + this.player_.volume(this.calculateDistance(event)); + }; + + /** + * If the player is muted unmute it. + */ + + + VolumeBar.prototype.checkMuted = function checkMuted() { + if (this.player_.muted()) { + this.player_.muted(false); + } + }; + + /** + * Get percent of volume level + * + * @return {number} + * Volume level percent as a decimal number. + */ + + + VolumeBar.prototype.getPercent = function getPercent() { + if (this.player_.muted()) { + return 0; + } + return this.player_.volume(); + }; + + /** + * Increase volume level for keyboard users + */ + + + VolumeBar.prototype.stepForward = function stepForward() { + this.checkMuted(); + this.player_.volume(this.player_.volume() + 0.1); + }; + + /** + * Decrease volume level for keyboard users + */ + + + VolumeBar.prototype.stepBack = function stepBack() { + this.checkMuted(); + this.player_.volume(this.player_.volume() - 0.1); + }; + + /** + * Update ARIA accessibility attributes + * + * @param {EventTarget~Event} [event] + * The `volumechange` event that caused this function to run. + * + * @listens Player#volumechange + */ + + + VolumeBar.prototype.updateARIAAttributes = function updateARIAAttributes(event) { + var ariaValue = this.player_.muted() ? 0 : this.volumeAsPercentage_(); + + this.el_.setAttribute('aria-valuenow', ariaValue); + this.el_.setAttribute('aria-valuetext', ariaValue + '%'); + }; + + /** + * Returns the current value of the player volume as a percentage + * + * @private + */ + + + VolumeBar.prototype.volumeAsPercentage_ = function volumeAsPercentage_() { + return Math.round(this.player_.volume() * 100); + }; + + /** + * When user starts dragging the VolumeBar, store the volume and listen for + * the end of the drag. When the drag ends, if the volume was set to zero, + * set lastVolume to the stored volume. + * + * @listens slideractive + * @private + */ + + + VolumeBar.prototype.updateLastVolume_ = function updateLastVolume_() { + var _this2 = this; + + var volumeBeforeDrag = this.player_.volume(); + + this.one('sliderinactive', function () { + if (_this2.player_.volume() === 0) { + _this2.player_.lastVolume_(volumeBeforeDrag); + } + }); + }; + + return VolumeBar; + }(Slider); + + /** + * Default options for the `VolumeBar` + * + * @type {Object} + * @private + */ + + + VolumeBar.prototype.options_ = { + children: ['volumeLevel'], + barName: 'volumeLevel' + }; + + /** + * Call the update event for this Slider when this event happens on the player. + * + * @type {string} + */ + VolumeBar.prototype.playerEvent = 'volumechange'; + + Component.registerComponent('VolumeBar', VolumeBar); + + /** + * @file volume-control.js + */ + + /** + * The component for controlling the volume level + * + * @extends Component + */ + + var VolumeControl = function (_Component) { + inherits(VolumeControl, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function VolumeControl(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, VolumeControl); + + options.vertical = options.vertical || false; + + // Pass the vertical option down to the VolumeBar if + // the VolumeBar is turned on. + if (typeof options.volumeBar === 'undefined' || isPlain(options.volumeBar)) { + options.volumeBar = options.volumeBar || {}; + options.volumeBar.vertical = options.vertical; + } + + // hide this control if volume support is missing + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + checkVolumeSupport(_this, player); + + _this.throttledHandleMouseMove = throttle(bind(_this, _this.handleMouseMove), 25); + + _this.on('mousedown', _this.handleMouseDown); + _this.on('touchstart', _this.handleMouseDown); + + // while the slider is active (the mouse has been pressed down and + // is dragging) or in focus we do not want to hide the VolumeBar + _this.on(_this.volumeBar, ['focus', 'slideractive'], function () { + _this.volumeBar.addClass('vjs-slider-active'); + _this.addClass('vjs-slider-active'); + _this.trigger('slideractive'); + }); + + _this.on(_this.volumeBar, ['blur', 'sliderinactive'], function () { + _this.volumeBar.removeClass('vjs-slider-active'); + _this.removeClass('vjs-slider-active'); + _this.trigger('sliderinactive'); + }); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + VolumeControl.prototype.createEl = function createEl() { + var orientationClass = 'vjs-volume-horizontal'; + + if (this.options_.vertical) { + orientationClass = 'vjs-volume-vertical'; + } + + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-volume-control vjs-control ' + orientationClass + }); + }; + + /** + * Handle `mousedown` or `touchstart` events on the `VolumeControl`. + * + * @param {EventTarget~Event} event + * `mousedown` or `touchstart` event that triggered this function + * + * @listens mousedown + * @listens touchstart + */ + + + VolumeControl.prototype.handleMouseDown = function handleMouseDown(event) { + var doc = this.el_.ownerDocument; + + this.on(doc, 'mousemove', this.throttledHandleMouseMove); + this.on(doc, 'touchmove', this.throttledHandleMouseMove); + this.on(doc, 'mouseup', this.handleMouseUp); + this.on(doc, 'touchend', this.handleMouseUp); + }; + + /** + * Handle `mouseup` or `touchend` events on the `VolumeControl`. + * + * @param {EventTarget~Event} event + * `mouseup` or `touchend` event that triggered this function. + * + * @listens touchend + * @listens mouseup + */ + + + VolumeControl.prototype.handleMouseUp = function handleMouseUp(event) { + var doc = this.el_.ownerDocument; + + this.off(doc, 'mousemove', this.throttledHandleMouseMove); + this.off(doc, 'touchmove', this.throttledHandleMouseMove); + this.off(doc, 'mouseup', this.handleMouseUp); + this.off(doc, 'touchend', this.handleMouseUp); + }; + + /** + * Handle `mousedown` or `touchstart` events on the `VolumeControl`. + * + * @param {EventTarget~Event} event + * `mousedown` or `touchstart` event that triggered this function + * + * @listens mousedown + * @listens touchstart + */ + + + VolumeControl.prototype.handleMouseMove = function handleMouseMove(event) { + this.volumeBar.handleMouseMove(event); + }; + + return VolumeControl; + }(Component); + + /** + * Default options for the `VolumeControl` + * + * @type {Object} + * @private + */ + + + VolumeControl.prototype.options_ = { + children: ['volumeBar'] + }; + + Component.registerComponent('VolumeControl', VolumeControl); + + /** + * @file mute-toggle.js + */ + + /** + * A button component for muting the audio. + * + * @extends Button + */ + + var MuteToggle = function (_Button) { + inherits(MuteToggle, _Button); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function MuteToggle(player, options) { + classCallCheck(this, MuteToggle); + + // hide this control if volume support is missing + var _this = possibleConstructorReturn(this, _Button.call(this, player, options)); + + checkVolumeSupport(_this, player); + + _this.on(player, ['loadstart', 'volumechange'], _this.update); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + MuteToggle.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this); + }; + + /** + * This gets called when an `MuteToggle` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + MuteToggle.prototype.handleClick = function handleClick(event) { + var vol = this.player_.volume(); + var lastVolume = this.player_.lastVolume_(); + + if (vol === 0) { + var volumeToSet = lastVolume < 0.1 ? 0.1 : lastVolume; + + this.player_.volume(volumeToSet); + this.player_.muted(false); + } else { + this.player_.muted(this.player_.muted() ? false : true); + } + }; + + /** + * Update the `MuteToggle` button based on the state of `volume` and `muted` + * on the player. + * + * @param {EventTarget~Event} [event] + * The {@link Player#loadstart} event if this function was called + * through an event. + * + * @listens Player#loadstart + * @listens Player#volumechange + */ + + + MuteToggle.prototype.update = function update(event) { + this.updateIcon_(); + this.updateControlText_(); + }; + + /** + * Update the appearance of the `MuteToggle` icon. + * + * Possible states (given `level` variable below): + * - 0: crossed out + * - 1: zero bars of volume + * - 2: one bar of volume + * - 3: two bars of volume + * + * @private + */ + + + MuteToggle.prototype.updateIcon_ = function updateIcon_() { + var vol = this.player_.volume(); + var level = 3; + + if (vol === 0 || this.player_.muted()) { + level = 0; + } else if (vol < 0.33) { + level = 1; + } else if (vol < 0.67) { + level = 2; + } + + // TODO improve muted icon classes + for (var i = 0; i < 4; i++) { + removeClass(this.el_, 'vjs-vol-' + i); + } + addClass(this.el_, 'vjs-vol-' + level); + }; + + /** + * If `muted` has changed on the player, update the control text + * (`title` attribute on `vjs-mute-control` element and content of + * `vjs-control-text` element). + * + * @private + */ + + + MuteToggle.prototype.updateControlText_ = function updateControlText_() { + var soundOff = this.player_.muted() || this.player_.volume() === 0; + var text = soundOff ? 'Unmute' : 'Mute'; + + if (this.controlText() !== text) { + this.controlText(text); + } + }; + + return MuteToggle; + }(Button); + + /** + * The text that should display over the `MuteToggle`s controls. Added for localization. + * + * @type {string} + * @private + */ + + + MuteToggle.prototype.controlText_ = 'Mute'; + + Component.registerComponent('MuteToggle', MuteToggle); + + /** + * @file volume-control.js + */ + + /** + * A Component to contain the MuteToggle and VolumeControl so that + * they can work together. + * + * @extends Component + */ + + var VolumePanel = function (_Component) { + inherits(VolumePanel, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function VolumePanel(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, VolumePanel); + + if (typeof options.inline !== 'undefined') { + options.inline = options.inline; + } else { + options.inline = true; + } + + // pass the inline option down to the VolumeControl as vertical if + // the VolumeControl is on. + if (typeof options.volumeControl === 'undefined' || isPlain(options.volumeControl)) { + options.volumeControl = options.volumeControl || {}; + options.volumeControl.vertical = !options.inline; + } + + // hide this control if volume support is missing + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + checkVolumeSupport(_this, player); + + // while the slider is active (the mouse has been pressed down and + // is dragging) we do not want to hide the VolumeBar + _this.on(_this.volumeControl, ['slideractive'], _this.sliderActive_); + + _this.on(_this.volumeControl, ['sliderinactive'], _this.sliderInactive_); + return _this; + } + + /** + * Add vjs-slider-active class to the VolumePanel + * + * @listens VolumeControl#slideractive + * @private + */ + + + VolumePanel.prototype.sliderActive_ = function sliderActive_() { + this.addClass('vjs-slider-active'); + }; + + /** + * Removes vjs-slider-active class to the VolumePanel + * + * @listens VolumeControl#sliderinactive + * @private + */ + + + VolumePanel.prototype.sliderInactive_ = function sliderInactive_() { + this.removeClass('vjs-slider-active'); + }; + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + VolumePanel.prototype.createEl = function createEl() { + var orientationClass = 'vjs-volume-panel-horizontal'; + + if (!this.options_.inline) { + orientationClass = 'vjs-volume-panel-vertical'; + } + + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-volume-panel vjs-control ' + orientationClass + }); + }; + + return VolumePanel; + }(Component); + + /** + * Default options for the `VolumeControl` + * + * @type {Object} + * @private + */ + + + VolumePanel.prototype.options_ = { + children: ['muteToggle', 'volumeControl'] + }; + + Component.registerComponent('VolumePanel', VolumePanel); + + /** + * @file menu.js + */ + + /** + * The Menu component is used to build popup menus, including subtitle and + * captions selection menus. + * + * @extends Component + */ + + var Menu = function (_Component) { + inherits(Menu, _Component); + + /** + * Create an instance of this class. + * + * @param {Player} player + * the player that this component should attach to + * + * @param {Object} [options] + * Object of option names and values + * + */ + function Menu(player, options) { + classCallCheck(this, Menu); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + if (options) { + _this.menuButton_ = options.menuButton; + } + + _this.focusedChild_ = -1; + + _this.on('keydown', _this.handleKeyPress); + return _this; + } + + /** + * Add a {@link MenuItem} to the menu. + * + * @param {Object|string} component + * The name or instance of the `MenuItem` to add. + * + */ + + + Menu.prototype.addItem = function addItem(component) { + this.addChild(component); + component.on('click', bind(this, function (event) { + // Unpress the associated MenuButton, and move focus back to it + if (this.menuButton_) { + this.menuButton_.unpressButton(); + + // don't focus menu button if item is a caption settings item + // because focus will move elsewhere + if (component.name() !== 'CaptionSettingsMenuItem') { + this.menuButton_.focus(); + } + } + })); + }; + + /** + * Create the `Menu`s DOM element. + * + * @return {Element} + * the element that was created + */ + + + Menu.prototype.createEl = function createEl$$1() { + var contentElType = this.options_.contentElType || 'ul'; + + this.contentEl_ = createEl(contentElType, { + className: 'vjs-menu-content' + }); + + this.contentEl_.setAttribute('role', 'menu'); + + var el = _Component.prototype.createEl.call(this, 'div', { + append: this.contentEl_, + className: 'vjs-menu' + }); + + el.appendChild(this.contentEl_); + + // Prevent clicks from bubbling up. Needed for Menu Buttons, + // where a click on the parent is significant + on(el, 'click', function (event) { + event.preventDefault(); + event.stopImmediatePropagation(); + }); + + return el; + }; + + Menu.prototype.dispose = function dispose() { + this.contentEl_ = null; + + _Component.prototype.dispose.call(this); + }; + + /** + * Handle a `keydown` event on this menu. This listener is added in the constructor. + * + * @param {EventTarget~Event} event + * A `keydown` event that happened on the menu. + * + * @listens keydown + */ + + + Menu.prototype.handleKeyPress = function handleKeyPress(event) { + // Left and Down Arrows + if (event.which === 37 || event.which === 40) { + event.preventDefault(); + this.stepForward(); + + // Up and Right Arrows + } else if (event.which === 38 || event.which === 39) { + event.preventDefault(); + this.stepBack(); + } + }; + + /** + * Move to next (lower) menu item for keyboard users. + */ + + + Menu.prototype.stepForward = function stepForward() { + var stepChild = 0; + + if (this.focusedChild_ !== undefined) { + stepChild = this.focusedChild_ + 1; + } + this.focus(stepChild); + }; + + /** + * Move to previous (higher) menu item for keyboard users. + */ + + + Menu.prototype.stepBack = function stepBack() { + var stepChild = 0; + + if (this.focusedChild_ !== undefined) { + stepChild = this.focusedChild_ - 1; + } + this.focus(stepChild); + }; + + /** + * Set focus on a {@link MenuItem} in the `Menu`. + * + * @param {Object|string} [item=0] + * Index of child item set focus on. + */ + + + Menu.prototype.focus = function focus() { + var item = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + + var children = this.children().slice(); + var haveTitle = children.length && children[0].className && /vjs-menu-title/.test(children[0].className); + + if (haveTitle) { + children.shift(); + } + + if (children.length > 0) { + if (item < 0) { + item = 0; + } else if (item >= children.length) { + item = children.length - 1; + } + + this.focusedChild_ = item; + + children[item].el_.focus(); + } + }; + + return Menu; + }(Component); + + Component.registerComponent('Menu', Menu); + + /** + * @file menu-button.js + */ + + /** + * A `MenuButton` class for any popup {@link Menu}. + * + * @extends Component + */ + + var MenuButton = function (_Component) { + inherits(MenuButton, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function MenuButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, MenuButton); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.menuButton_ = new Button(player, options); + + _this.menuButton_.controlText(_this.controlText_); + _this.menuButton_.el_.setAttribute('aria-haspopup', 'true'); + + // Add buildCSSClass values to the button, not the wrapper + var buttonClass = Button.prototype.buildCSSClass(); + + _this.menuButton_.el_.className = _this.buildCSSClass() + ' ' + buttonClass; + _this.menuButton_.removeClass('vjs-control'); + + _this.addChild(_this.menuButton_); + + _this.update(); + + _this.enabled_ = true; + + _this.on(_this.menuButton_, 'tap', _this.handleClick); + _this.on(_this.menuButton_, 'click', _this.handleClick); + _this.on(_this.menuButton_, 'focus', _this.handleFocus); + _this.on(_this.menuButton_, 'blur', _this.handleBlur); + + _this.on('keydown', _this.handleSubmenuKeyPress); + return _this; + } + + /** + * Update the menu based on the current state of its items. + */ + + + MenuButton.prototype.update = function update() { + var menu = this.createMenu(); + + if (this.menu) { + this.menu.dispose(); + this.removeChild(this.menu); + } + + this.menu = menu; + this.addChild(menu); + + /** + * Track the state of the menu button + * + * @type {Boolean} + * @private + */ + this.buttonPressed_ = false; + this.menuButton_.el_.setAttribute('aria-expanded', 'false'); + + if (this.items && this.items.length <= this.hideThreshold_) { + this.hide(); + } else { + this.show(); + } + }; + + /** + * Create the menu and add all items to it. + * + * @return {Menu} + * The constructed menu + */ + + + MenuButton.prototype.createMenu = function createMenu() { + var menu = new Menu(this.player_, {menuButton: this}); + + /** + * Hide the menu if the number of items is less than or equal to this threshold. This defaults + * to 0 and whenever we add items which can be hidden to the menu we'll increment it. We list + * it here because every time we run `createMenu` we need to reset the value. + * + * @protected + * @type {Number} + */ + this.hideThreshold_ = 0; + + // Add a title list item to the top + if (this.options_.title) { + var title = createEl('li', { + className: 'vjs-menu-title', + innerHTML: toTitleCase(this.options_.title), + tabIndex: -1 + }); + + this.hideThreshold_ += 1; + + menu.children_.unshift(title); + prependTo(title, menu.contentEl()); + } + + this.items = this.createItems(); + + if (this.items) { + // Add menu items to the menu + for (var i = 0; i < this.items.length; i++) { + menu.addItem(this.items[i]); + } + } + + return menu; + }; + + /** + * Create the list of menu items. Specific to each subclass. + * + * @abstract + */ + + + MenuButton.prototype.createItems = function createItems() { + }; + + /** + * Create the `MenuButtons`s DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + MenuButton.prototype.createEl = function createEl$$1() { + return _Component.prototype.createEl.call(this, 'div', { + className: this.buildWrapperCSSClass() + }, {}); + }; + + /** + * Allow sub components to stack CSS class names for the wrapper element + * + * @return {string} + * The constructed wrapper DOM `className` + */ + + + MenuButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() { + var menuButtonClass = 'vjs-menu-button'; + + // If the inline option is passed, we want to use different styles altogether. + if (this.options_.inline === true) { + menuButtonClass += '-inline'; + } else { + menuButtonClass += '-popup'; + } + + // TODO: Fix the CSS so that this isn't necessary + var buttonClass = Button.prototype.buildCSSClass(); + + return 'vjs-menu-button ' + menuButtonClass + ' ' + buttonClass + ' ' + _Component.prototype.buildCSSClass.call(this); + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + MenuButton.prototype.buildCSSClass = function buildCSSClass() { + var menuButtonClass = 'vjs-menu-button'; + + // If the inline option is passed, we want to use different styles altogether. + if (this.options_.inline === true) { + menuButtonClass += '-inline'; + } else { + menuButtonClass += '-popup'; + } + + return 'vjs-menu-button ' + menuButtonClass + ' ' + _Component.prototype.buildCSSClass.call(this); + }; + + /** + * Get or set the localized control text that will be used for accessibility. + * + * > NOTE: This will come from the internal `menuButton_` element. + * + * @param {string} [text] + * Control text for element. + * + * @param {Element} [el=this.menuButton_.el()] + * Element to set the title on. + * + * @return {string} + * - The control text when getting + */ + + + MenuButton.prototype.controlText = function controlText(text) { + var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.menuButton_.el(); + + return this.menuButton_.controlText(text, el); + }; + + /** + * Handle a click on a `MenuButton`. + * See {@link ClickableComponent#handleClick} for instances where this is called. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + MenuButton.prototype.handleClick = function handleClick(event) { + // When you click the button it adds focus, which will show the menu. + // So we'll remove focus when the mouse leaves the button. Focus is needed + // for tab navigation. + + this.one(this.menu.contentEl(), 'mouseleave', bind(this, function (e) { + this.unpressButton(); + this.el_.blur(); + })); + if (this.buttonPressed_) { + this.unpressButton(); + } else { + this.pressButton(); + } + }; + + /** + * Set the focus to the actual button, not to this element + */ + + + MenuButton.prototype.focus = function focus() { + this.menuButton_.focus(); + }; + + /** + * Remove the focus from the actual button, not this element + */ + + + MenuButton.prototype.blur = function blur() { + this.menuButton_.blur(); + }; + + /** + * This gets called when a `MenuButton` gains focus via a `focus` event. + * Turns on listening for `keydown` events. When they happen it + * calls `this.handleKeyPress`. + * + * @param {EventTarget~Event} event + * The `focus` event that caused this function to be called. + * + * @listens focus + */ + + + MenuButton.prototype.handleFocus = function handleFocus() { + on(document_1, 'keydown', bind(this, this.handleKeyPress)); + }; + + /** + * Called when a `MenuButton` loses focus. Turns off the listener for + * `keydown` events. Which Stops `this.handleKeyPress` from getting called. + * + * @param {EventTarget~Event} event + * The `blur` event that caused this function to be called. + * + * @listens blur + */ + + + MenuButton.prototype.handleBlur = function handleBlur() { + off(document_1, 'keydown', bind(this, this.handleKeyPress)); + }; + + /** + * Handle tab, escape, down arrow, and up arrow keys for `MenuButton`. See + * {@link ClickableComponent#handleKeyPress} for instances where this is called. + * + * @param {EventTarget~Event} event + * The `keydown` event that caused this function to be called. + * + * @listens keydown + */ + + + MenuButton.prototype.handleKeyPress = function handleKeyPress(event) { + + // Escape (27) key or Tab (9) key unpress the 'button' + if (event.which === 27 || event.which === 9) { + if (this.buttonPressed_) { + this.unpressButton(); + } + // Don't preventDefault for Tab key - we still want to lose focus + if (event.which !== 9) { + event.preventDefault(); + // Set focus back to the menu button's button + this.menuButton_.el_.focus(); + } + // Up (38) key or Down (40) key press the 'button' + } else if (event.which === 38 || event.which === 40) { + if (!this.buttonPressed_) { + this.pressButton(); + event.preventDefault(); + } + } + }; + + /** + * Handle a `keydown` event on a sub-menu. The listener for this is added in + * the constructor. + * + * @param {EventTarget~Event} event + * Key press event + * + * @listens keydown + */ + + + MenuButton.prototype.handleSubmenuKeyPress = function handleSubmenuKeyPress(event) { + + // Escape (27) key or Tab (9) key unpress the 'button' + if (event.which === 27 || event.which === 9) { + if (this.buttonPressed_) { + this.unpressButton(); + } + // Don't preventDefault for Tab key - we still want to lose focus + if (event.which !== 9) { + event.preventDefault(); + // Set focus back to the menu button's button + this.menuButton_.el_.focus(); + } + } + }; + + /** + * Put the current `MenuButton` into a pressed state. + */ + + + MenuButton.prototype.pressButton = function pressButton() { + if (this.enabled_) { + this.buttonPressed_ = true; + this.menu.lockShowing(); + this.menuButton_.el_.setAttribute('aria-expanded', 'true'); + + // set the focus into the submenu, except on iOS where it is resulting in + // undesired scrolling behavior when the player is in an iframe + if (IS_IOS && isInFrame()) { + // Return early so that the menu isn't focused + return; + } + + this.menu.focus(); + } + }; + + /** + * Take the current `MenuButton` out of a pressed state. + */ + + + MenuButton.prototype.unpressButton = function unpressButton() { + if (this.enabled_) { + this.buttonPressed_ = false; + this.menu.unlockShowing(); + this.menuButton_.el_.setAttribute('aria-expanded', 'false'); + } + }; + + /** + * Disable the `MenuButton`. Don't allow it to be clicked. + */ + + + MenuButton.prototype.disable = function disable() { + this.unpressButton(); + + this.enabled_ = false; + this.addClass('vjs-disabled'); + + this.menuButton_.disable(); + }; + + /** + * Enable the `MenuButton`. Allow it to be clicked. + */ + + + MenuButton.prototype.enable = function enable() { + this.enabled_ = true; + this.removeClass('vjs-disabled'); + + this.menuButton_.enable(); + }; + + return MenuButton; + }(Component); + + Component.registerComponent('MenuButton', MenuButton); + + /** + * @file track-button.js + */ + + /** + * The base class for buttons that toggle specific track types (e.g. subtitles). + * + * @extends MenuButton + */ + + var TrackButton = function (_MenuButton) { + inherits(TrackButton, _MenuButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function TrackButton(player, options) { + classCallCheck(this, TrackButton); + + var tracks = options.tracks; + + var _this = possibleConstructorReturn(this, _MenuButton.call(this, player, options)); + + if (_this.items.length <= 1) { + _this.hide(); + } + + if (!tracks) { + return possibleConstructorReturn(_this); + } + + var updateHandler = bind(_this, _this.update); + + tracks.addEventListener('removetrack', updateHandler); + tracks.addEventListener('addtrack', updateHandler); + _this.player_.on('ready', updateHandler); + + _this.player_.on('dispose', function () { + tracks.removeEventListener('removetrack', updateHandler); + tracks.removeEventListener('addtrack', updateHandler); + }); + return _this; + } + + return TrackButton; + }(MenuButton); + + Component.registerComponent('TrackButton', TrackButton); + + /** + * @file menu-item.js + */ + + /** + * The component for a menu item. `<li>` + * + * @extends ClickableComponent + */ + + var MenuItem = function (_ClickableComponent) { + inherits(MenuItem, _ClickableComponent); + + /** + * Creates an instance of the this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + * + */ + function MenuItem(player, options) { + classCallCheck(this, MenuItem); + + var _this = possibleConstructorReturn(this, _ClickableComponent.call(this, player, options)); + + _this.selectable = options.selectable; + _this.isSelected_ = options.selected || false; + + _this.selected(_this.isSelected_); + + if (_this.selectable) { + // TODO: May need to be either menuitemcheckbox or menuitemradio, + // and may need logical grouping of menu items. + _this.el_.setAttribute('role', 'menuitemcheckbox'); + } else { + _this.el_.setAttribute('role', 'menuitem'); + } + return _this; + } + + /** + * Create the `MenuItem's DOM element + * + * @param {string} [type=li] + * Element's node type, not actually used, always set to `li`. + * + * @param {Object} [props={}] + * An object of properties that should be set on the element + * + * @param {Object} [attrs={}] + * An object of attributes that should be set on the element + * + * @return {Element} + * The element that gets created. + */ + + + MenuItem.prototype.createEl = function createEl(type, props, attrs) { + // The control is textual, not just an icon + this.nonIconControl = true; + + return _ClickableComponent.prototype.createEl.call(this, 'li', assign({ + className: 'vjs-menu-item', + innerHTML: '<span class="vjs-menu-item-text">' + this.localize(this.options_.label) + '</span>', + tabIndex: -1 + }, props), attrs); + }; + + /** + * Any click on a `MenuItem` puts int into the selected state. + * See {@link ClickableComponent#handleClick} for instances where this is called. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + MenuItem.prototype.handleClick = function handleClick(event) { + this.selected(true); + }; + + /** + * Set the state for this menu item as selected or not. + * + * @param {boolean} selected + * if the menu item is selected or not + */ + + + MenuItem.prototype.selected = function selected(_selected) { + if (this.selectable) { + if (_selected) { + this.addClass('vjs-selected'); + this.el_.setAttribute('aria-checked', 'true'); + // aria-checked isn't fully supported by browsers/screen readers, + // so indicate selected state to screen reader in the control text. + this.controlText(', selected'); + this.isSelected_ = true; + } else { + this.removeClass('vjs-selected'); + this.el_.setAttribute('aria-checked', 'false'); + // Indicate un-selected state to screen reader + this.controlText(''); + this.isSelected_ = false; + } + } + }; + + return MenuItem; + }(ClickableComponent); + + Component.registerComponent('MenuItem', MenuItem); + + /** + * @file text-track-menu-item.js + */ + + /** + * The specific menu item type for selecting a language within a text track kind + * + * @extends MenuItem + */ + + var TextTrackMenuItem = function (_MenuItem) { + inherits(TextTrackMenuItem, _MenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function TextTrackMenuItem(player, options) { + classCallCheck(this, TextTrackMenuItem); + + var track = options.track; + var tracks = player.textTracks(); + + // Modify options for parent MenuItem class's init. + options.label = track.label || track.language || 'Unknown'; + options.selected = track.mode === 'showing'; + + var _this = possibleConstructorReturn(this, _MenuItem.call(this, player, options)); + + _this.track = track; + var changeHandler = function changeHandler() { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + _this.handleTracksChange.apply(_this, args); + }; + var selectedLanguageChangeHandler = function selectedLanguageChangeHandler() { + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + _this.handleSelectedLanguageChange.apply(_this, args); + }; + + player.on(['loadstart', 'texttrackchange'], changeHandler); + tracks.addEventListener('change', changeHandler); + tracks.addEventListener('selectedlanguagechange', selectedLanguageChangeHandler); + _this.on('dispose', function () { + player.off(['loadstart', 'texttrackchange'], changeHandler); + tracks.removeEventListener('change', changeHandler); + tracks.removeEventListener('selectedlanguagechange', selectedLanguageChangeHandler); + }); + + // iOS7 doesn't dispatch change events to TextTrackLists when an + // associated track's mode changes. Without something like + // Object.observe() (also not present on iOS7), it's not + // possible to detect changes to the mode attribute and polyfill + // the change event. As a poor substitute, we manually dispatch + // change events whenever the controls modify the mode. + if (tracks.onchange === undefined) { + var event = void 0; + + _this.on(['tap', 'click'], function () { + if (_typeof(window_1.Event) !== 'object') { + // Android 2.3 throws an Illegal Constructor error for window.Event + try { + event = new window_1.Event('change'); + } catch (err) { + // continue regardless of error + } + } + + if (!event) { + event = document_1.createEvent('Event'); + event.initEvent('change', true, true); + } + + tracks.dispatchEvent(event); + }); + } + + // set the default state based on current tracks + _this.handleTracksChange(); + return _this; + } + + /** + * This gets called when an `TextTrackMenuItem` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + TextTrackMenuItem.prototype.handleClick = function handleClick(event) { + var kind = this.track.kind; + var kinds = this.track.kinds; + var tracks = this.player_.textTracks(); + + if (!kinds) { + kinds = [kind]; + } + + _MenuItem.prototype.handleClick.call(this, event); + + if (!tracks) { + return; + } + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + if (track === this.track && kinds.indexOf(track.kind) > -1) { + if (track.mode !== 'showing') { + track.mode = 'showing'; + } + } else if (track.mode !== 'disabled') { + track.mode = 'disabled'; + } + } + }; + + /** + * Handle text track list change + * + * @param {EventTarget~Event} event + * The `change` event that caused this function to be called. + * + * @listens TextTrackList#change + */ + + + TextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { + var shouldBeSelected = this.track.mode === 'showing'; + + // Prevent redundant selected() calls because they may cause + // screen readers to read the appended control text unnecessarily + if (shouldBeSelected !== this.isSelected_) { + this.selected(shouldBeSelected); + } + }; + + TextTrackMenuItem.prototype.handleSelectedLanguageChange = function handleSelectedLanguageChange(event) { + if (this.track.mode === 'showing') { + var selectedLanguage = this.player_.cache_.selectedLanguage; + + // Don't replace the kind of track across the same language + if (selectedLanguage && selectedLanguage.enabled && selectedLanguage.language === this.track.language && selectedLanguage.kind !== this.track.kind) { + return; + } + + this.player_.cache_.selectedLanguage = { + enabled: true, + language: this.track.language, + kind: this.track.kind + }; + } + }; + + TextTrackMenuItem.prototype.dispose = function dispose() { + // remove reference to track object on dispose + this.track = null; + + _MenuItem.prototype.dispose.call(this); + }; + + return TextTrackMenuItem; + }(MenuItem); + + Component.registerComponent('TextTrackMenuItem', TextTrackMenuItem); + + /** + * @file off-text-track-menu-item.js + */ + + /** + * A special menu item for turning of a specific type of text track + * + * @extends TextTrackMenuItem + */ + + var OffTextTrackMenuItem = function (_TextTrackMenuItem) { + inherits(OffTextTrackMenuItem, _TextTrackMenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function OffTextTrackMenuItem(player, options) { + classCallCheck(this, OffTextTrackMenuItem); + + // Create pseudo track info + // Requires options['kind'] + options.track = { + player: player, + kind: options.kind, + kinds: options.kinds, + default: false, + mode: 'disabled' + }; + + if (!options.kinds) { + options.kinds = [options.kind]; + } + + if (options.label) { + options.track.label = options.label; + } else { + options.track.label = options.kinds.join(' and ') + ' off'; + } + + // MenuItem is selectable + options.selectable = true; + + return possibleConstructorReturn(this, _TextTrackMenuItem.call(this, player, options)); + } + + /** + * Handle text track change + * + * @param {EventTarget~Event} event + * The event that caused this function to run + */ + + + OffTextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { + var tracks = this.player().textTracks(); + var shouldBeSelected = true; + + for (var i = 0, l = tracks.length; i < l; i++) { + var track = tracks[i]; + + if (this.options_.kinds.indexOf(track.kind) > -1 && track.mode === 'showing') { + shouldBeSelected = false; + break; + } + } + + // Prevent redundant selected() calls because they may cause + // screen readers to read the appended control text unnecessarily + if (shouldBeSelected !== this.isSelected_) { + this.selected(shouldBeSelected); + } + }; + + OffTextTrackMenuItem.prototype.handleSelectedLanguageChange = function handleSelectedLanguageChange(event) { + var tracks = this.player().textTracks(); + var allHidden = true; + + for (var i = 0, l = tracks.length; i < l; i++) { + var track = tracks[i]; + + if (['captions', 'descriptions', 'subtitles'].indexOf(track.kind) > -1 && track.mode === 'showing') { + allHidden = false; + break; + } + } + + if (allHidden) { + this.player_.cache_.selectedLanguage = { + enabled: false + }; + } + }; + + return OffTextTrackMenuItem; + }(TextTrackMenuItem); + + Component.registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem); + + /** + * @file text-track-button.js + */ + + /** + * The base class for buttons that toggle specific text track types (e.g. subtitles) + * + * @extends MenuButton + */ + + var TextTrackButton = function (_TrackButton) { + inherits(TextTrackButton, _TrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function TextTrackButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, TextTrackButton); + + options.tracks = player.textTracks(); + + return possibleConstructorReturn(this, _TrackButton.call(this, player, options)); + } + + /** + * Create a menu item for each text track + * + * @param {TextTrackMenuItem[]} [items=[]] + * Existing array of items to use during creation + * + * @return {TextTrackMenuItem[]} + * Array of menu items that were created + */ + + + TextTrackButton.prototype.createItems = function createItems() { + var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var TrackMenuItem = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : TextTrackMenuItem; + + + // Label is an override for the [track] off label + // USed to localise captions/subtitles + var label = void 0; + + if (this.label_) { + label = this.label_ + ' off'; + } + // Add an OFF menu item to turn all tracks off + items.push(new OffTextTrackMenuItem(this.player_, { + kinds: this.kinds_, + kind: this.kind_, + label: label + })); + + this.hideThreshold_ += 1; + + var tracks = this.player_.textTracks(); + + if (!Array.isArray(this.kinds_)) { + this.kinds_ = [this.kind_]; + } + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + // only add tracks that are of an appropriate kind and have a label + if (this.kinds_.indexOf(track.kind) > -1) { + + var item = new TrackMenuItem(this.player_, { + track: track, + // MenuItem is selectable + selectable: true + }); + + item.addClass('vjs-' + track.kind + '-menu-item'); + items.push(item); + } + } + + return items; + }; + + return TextTrackButton; + }(TrackButton); + + Component.registerComponent('TextTrackButton', TextTrackButton); + + /** + * @file chapters-track-menu-item.js + */ + + /** + * The chapter track menu item + * + * @extends MenuItem + */ + + var ChaptersTrackMenuItem = function (_MenuItem) { + inherits(ChaptersTrackMenuItem, _MenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function ChaptersTrackMenuItem(player, options) { + classCallCheck(this, ChaptersTrackMenuItem); + + var track = options.track; + var cue = options.cue; + var currentTime = player.currentTime(); + + // Modify options for parent MenuItem class's init. + options.selectable = true; + options.label = cue.text; + options.selected = cue.startTime <= currentTime && currentTime < cue.endTime; + + var _this = possibleConstructorReturn(this, _MenuItem.call(this, player, options)); + + _this.track = track; + _this.cue = cue; + track.addEventListener('cuechange', bind(_this, _this.update)); + return _this; + } + + /** + * This gets called when an `ChaptersTrackMenuItem` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + ChaptersTrackMenuItem.prototype.handleClick = function handleClick(event) { + _MenuItem.prototype.handleClick.call(this); + this.player_.currentTime(this.cue.startTime); + this.update(this.cue.startTime); + }; + + /** + * Update chapter menu item + * + * @param {EventTarget~Event} [event] + * The `cuechange` event that caused this function to run. + * + * @listens TextTrack#cuechange + */ + + + ChaptersTrackMenuItem.prototype.update = function update(event) { + var cue = this.cue; + var currentTime = this.player_.currentTime(); + + // vjs.log(currentTime, cue.startTime); + this.selected(cue.startTime <= currentTime && currentTime < cue.endTime); + }; + + return ChaptersTrackMenuItem; + }(MenuItem); + + Component.registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem); + + /** + * @file chapters-button.js + */ + + /** + * The button component for toggling and selecting chapters + * Chapters act much differently than other text tracks + * Cues are navigation vs. other tracks of alternative languages + * + * @extends TextTrackButton + */ + + var ChaptersButton = function (_TextTrackButton) { + inherits(ChaptersButton, _TextTrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when this function is ready. + */ + function ChaptersButton(player, options, ready) { + classCallCheck(this, ChaptersButton); + return possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready)); + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + ChaptersButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-chapters-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + ChaptersButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() { + return 'vjs-chapters-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this); + }; + + /** + * Update the menu based on the current state of its items. + * + * @param {EventTarget~Event} [event] + * An event that triggered this function to run. + * + * @listens TextTrackList#addtrack + * @listens TextTrackList#removetrack + * @listens TextTrackList#change + */ + + + ChaptersButton.prototype.update = function update(event) { + if (!this.track_ || event && (event.type === 'addtrack' || event.type === 'removetrack')) { + this.setTrack(this.findChaptersTrack()); + } + _TextTrackButton.prototype.update.call(this); + }; + + /** + * Set the currently selected track for the chapters button. + * + * @param {TextTrack} track + * The new track to select. Nothing will change if this is the currently selected + * track. + */ + + + ChaptersButton.prototype.setTrack = function setTrack(track) { + if (this.track_ === track) { + return; + } + + if (!this.updateHandler_) { + this.updateHandler_ = this.update.bind(this); + } + + // here this.track_ refers to the old track instance + if (this.track_) { + var remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_); + + if (remoteTextTrackEl) { + remoteTextTrackEl.removeEventListener('load', this.updateHandler_); + } + + this.track_ = null; + } + + this.track_ = track; + + // here this.track_ refers to the new track instance + if (this.track_) { + this.track_.mode = 'hidden'; + + var _remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_); + + if (_remoteTextTrackEl) { + _remoteTextTrackEl.addEventListener('load', this.updateHandler_); + } + } + }; + + /** + * Find the track object that is currently in use by this ChaptersButton + * + * @return {TextTrack|undefined} + * The current track or undefined if none was found. + */ + + + ChaptersButton.prototype.findChaptersTrack = function findChaptersTrack() { + var tracks = this.player_.textTracks() || []; + + for (var i = tracks.length - 1; i >= 0; i--) { + // We will always choose the last track as our chaptersTrack + var track = tracks[i]; + + if (track.kind === this.kind_) { + return track; + } + } + }; + + /** + * Get the caption for the ChaptersButton based on the track label. This will also + * use the current tracks localized kind as a fallback if a label does not exist. + * + * @return {string} + * The tracks current label or the localized track kind. + */ + + + ChaptersButton.prototype.getMenuCaption = function getMenuCaption() { + if (this.track_ && this.track_.label) { + return this.track_.label; + } + return this.localize(toTitleCase(this.kind_)); + }; + + /** + * Create menu from chapter track + * + * @return {Menu} + * New menu for the chapter buttons + */ + + + ChaptersButton.prototype.createMenu = function createMenu() { + this.options_.title = this.getMenuCaption(); + return _TextTrackButton.prototype.createMenu.call(this); + }; + + /** + * Create a menu item for each text track + * + * @return {TextTrackMenuItem[]} + * Array of menu items + */ + + + ChaptersButton.prototype.createItems = function createItems() { + var items = []; + + if (!this.track_) { + return items; + } + + var cues = this.track_.cues; + + if (!cues) { + return items; + } + + for (var i = 0, l = cues.length; i < l; i++) { + var cue = cues[i]; + var mi = new ChaptersTrackMenuItem(this.player_, {track: this.track_, cue: cue}); + + items.push(mi); + } + + return items; + }; + + return ChaptersButton; + }(TextTrackButton); + + /** + * `kind` of TextTrack to look for to associate it with this menu. + * + * @type {string} + * @private + */ + + + ChaptersButton.prototype.kind_ = 'chapters'; + + /** + * The text that should display over the `ChaptersButton`s controls. Added for localization. + * + * @type {string} + * @private + */ + ChaptersButton.prototype.controlText_ = 'Chapters'; + + Component.registerComponent('ChaptersButton', ChaptersButton); + + /** + * @file descriptions-button.js + */ + + /** + * The button component for toggling and selecting descriptions + * + * @extends TextTrackButton + */ + + var DescriptionsButton = function (_TextTrackButton) { + inherits(DescriptionsButton, _TextTrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when this component is ready. + */ + function DescriptionsButton(player, options, ready) { + classCallCheck(this, DescriptionsButton); + + var _this = possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready)); + + var tracks = player.textTracks(); + var changeHandler = bind(_this, _this.handleTracksChange); + + tracks.addEventListener('change', changeHandler); + _this.on('dispose', function () { + tracks.removeEventListener('change', changeHandler); + }); + return _this; + } + + /** + * Handle text track change + * + * @param {EventTarget~Event} event + * The event that caused this function to run + * + * @listens TextTrackList#change + */ + + + DescriptionsButton.prototype.handleTracksChange = function handleTracksChange(event) { + var tracks = this.player().textTracks(); + var disabled = false; + + // Check whether a track of a different kind is showing + for (var i = 0, l = tracks.length; i < l; i++) { + var track = tracks[i]; + + if (track.kind !== this.kind_ && track.mode === 'showing') { + disabled = true; + break; + } + } + + // If another track is showing, disable this menu button + if (disabled) { + this.disable(); + } else { + this.enable(); + } + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + DescriptionsButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-descriptions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + DescriptionsButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() { + return 'vjs-descriptions-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this); + }; + + return DescriptionsButton; + }(TextTrackButton); + + /** + * `kind` of TextTrack to look for to associate it with this menu. + * + * @type {string} + * @private + */ + + + DescriptionsButton.prototype.kind_ = 'descriptions'; + + /** + * The text that should display over the `DescriptionsButton`s controls. Added for localization. + * + * @type {string} + * @private + */ + DescriptionsButton.prototype.controlText_ = 'Descriptions'; + + Component.registerComponent('DescriptionsButton', DescriptionsButton); + + /** + * @file subtitles-button.js + */ + + /** + * The button component for toggling and selecting subtitles + * + * @extends TextTrackButton + */ + + var SubtitlesButton = function (_TextTrackButton) { + inherits(SubtitlesButton, _TextTrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when this component is ready. + */ + function SubtitlesButton(player, options, ready) { + classCallCheck(this, SubtitlesButton); + return possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready)); + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + SubtitlesButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-subtitles-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + SubtitlesButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() { + return 'vjs-subtitles-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this); + }; + + return SubtitlesButton; + }(TextTrackButton); + + /** + * `kind` of TextTrack to look for to associate it with this menu. + * + * @type {string} + * @private + */ + + + SubtitlesButton.prototype.kind_ = 'subtitles'; + + /** + * The text that should display over the `SubtitlesButton`s controls. Added for localization. + * + * @type {string} + * @private + */ + SubtitlesButton.prototype.controlText_ = 'Subtitles'; + + Component.registerComponent('SubtitlesButton', SubtitlesButton); + + /** + * @file caption-settings-menu-item.js + */ + + /** + * The menu item for caption track settings menu + * + * @extends TextTrackMenuItem + */ + + var CaptionSettingsMenuItem = function (_TextTrackMenuItem) { + inherits(CaptionSettingsMenuItem, _TextTrackMenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function CaptionSettingsMenuItem(player, options) { + classCallCheck(this, CaptionSettingsMenuItem); + + options.track = { + player: player, + kind: options.kind, + label: options.kind + ' settings', + selectable: false, + default: false, + mode: 'disabled' + }; + + // CaptionSettingsMenuItem has no concept of 'selected' + options.selectable = false; + + options.name = 'CaptionSettingsMenuItem'; + + var _this = possibleConstructorReturn(this, _TextTrackMenuItem.call(this, player, options)); + + _this.addClass('vjs-texttrack-settings'); + _this.controlText(', opens ' + options.kind + ' settings dialog'); + return _this; + } + + /** + * This gets called when an `CaptionSettingsMenuItem` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + CaptionSettingsMenuItem.prototype.handleClick = function handleClick(event) { + this.player().getChild('textTrackSettings').open(); + }; + + return CaptionSettingsMenuItem; + }(TextTrackMenuItem); + + Component.registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem); + + /** + * @file captions-button.js + */ + + /** + * The button component for toggling and selecting captions + * + * @extends TextTrackButton + */ + + var CaptionsButton = function (_TextTrackButton) { + inherits(CaptionsButton, _TextTrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when this component is ready. + */ + function CaptionsButton(player, options, ready) { + classCallCheck(this, CaptionsButton); + return possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready)); + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + CaptionsButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-captions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + CaptionsButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() { + return 'vjs-captions-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this); + }; + + /** + * Create caption menu items + * + * @return {CaptionSettingsMenuItem[]} + * The array of current menu items. + */ + + + CaptionsButton.prototype.createItems = function createItems() { + var items = []; + + if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks) && this.player().getChild('textTrackSettings')) { + items.push(new CaptionSettingsMenuItem(this.player_, {kind: this.kind_})); + + this.hideThreshold_ += 1; + } + + return _TextTrackButton.prototype.createItems.call(this, items); + }; + + return CaptionsButton; + }(TextTrackButton); + + /** + * `kind` of TextTrack to look for to associate it with this menu. + * + * @type {string} + * @private + */ + + + CaptionsButton.prototype.kind_ = 'captions'; + + /** + * The text that should display over the `CaptionsButton`s controls. Added for localization. + * + * @type {string} + * @private + */ + CaptionsButton.prototype.controlText_ = 'Captions'; + + Component.registerComponent('CaptionsButton', CaptionsButton); + + /** + * @file subs-caps-menu-item.js + */ + + /** + * SubsCapsMenuItem has an [cc] icon to distinguish captions from subtitles + * in the SubsCapsMenu. + * + * @extends TextTrackMenuItem + */ + + var SubsCapsMenuItem = function (_TextTrackMenuItem) { + inherits(SubsCapsMenuItem, _TextTrackMenuItem); + + function SubsCapsMenuItem() { + classCallCheck(this, SubsCapsMenuItem); + return possibleConstructorReturn(this, _TextTrackMenuItem.apply(this, arguments)); + } + + SubsCapsMenuItem.prototype.createEl = function createEl(type, props, attrs) { + var innerHTML = '<span class="vjs-menu-item-text">' + this.localize(this.options_.label); + + if (this.options_.track.kind === 'captions') { + innerHTML += '\n <span aria-hidden="true" class="vjs-icon-placeholder"></span>\n <span class="vjs-control-text"> ' + this.localize('Captions') + '</span>\n '; + } + + innerHTML += '</span>'; + + var el = _TextTrackMenuItem.prototype.createEl.call(this, type, assign({ + innerHTML: innerHTML + }, props), attrs); + + return el; + }; + + return SubsCapsMenuItem; + }(TextTrackMenuItem); + + Component.registerComponent('SubsCapsMenuItem', SubsCapsMenuItem); + + /** + * @file sub-caps-button.js + */ + /** + * The button component for toggling and selecting captions and/or subtitles + * + * @extends TextTrackButton + */ + + var SubsCapsButton = function (_TextTrackButton) { + inherits(SubsCapsButton, _TextTrackButton); + + function SubsCapsButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, SubsCapsButton); + + // Although North America uses "captions" in most cases for + // "captions and subtitles" other locales use "subtitles" + var _this = possibleConstructorReturn(this, _TextTrackButton.call(this, player, options)); + + _this.label_ = 'subtitles'; + if (['en', 'en-us', 'en-ca', 'fr-ca'].indexOf(_this.player_.language_) > -1) { + _this.label_ = 'captions'; + } + _this.menuButton_.controlText(toTitleCase(_this.label_)); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + SubsCapsButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-subs-caps-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + SubsCapsButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() { + return 'vjs-subs-caps-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this); + }; + + /** + * Create caption/subtitles menu items + * + * @return {CaptionSettingsMenuItem[]} + * The array of current menu items. + */ + + + SubsCapsButton.prototype.createItems = function createItems() { + var items = []; + + if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks) && this.player().getChild('textTrackSettings')) { + items.push(new CaptionSettingsMenuItem(this.player_, {kind: this.label_})); + + this.hideThreshold_ += 1; + } + + items = _TextTrackButton.prototype.createItems.call(this, items, SubsCapsMenuItem); + return items; + }; + + return SubsCapsButton; + }(TextTrackButton); + + /** + * `kind`s of TextTrack to look for to associate it with this menu. + * + * @type {array} + * @private + */ + + + SubsCapsButton.prototype.kinds_ = ['captions', 'subtitles']; + + /** + * The text that should display over the `SubsCapsButton`s controls. + * + * + * @type {string} + * @private + */ + SubsCapsButton.prototype.controlText_ = 'Subtitles'; + + Component.registerComponent('SubsCapsButton', SubsCapsButton); + + /** + * @file audio-track-menu-item.js + */ + + /** + * An {@link AudioTrack} {@link MenuItem} + * + * @extends MenuItem + */ + + var AudioTrackMenuItem = function (_MenuItem) { + inherits(AudioTrackMenuItem, _MenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function AudioTrackMenuItem(player, options) { + classCallCheck(this, AudioTrackMenuItem); + + var track = options.track; + var tracks = player.audioTracks(); + + // Modify options for parent MenuItem class's init. + options.label = track.label || track.language || 'Unknown'; + options.selected = track.enabled; + + var _this = possibleConstructorReturn(this, _MenuItem.call(this, player, options)); + + _this.track = track; + + var changeHandler = function changeHandler() { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + _this.handleTracksChange.apply(_this, args); + }; + + tracks.addEventListener('change', changeHandler); + _this.on('dispose', function () { + tracks.removeEventListener('change', changeHandler); + }); + return _this; + } + + /** + * This gets called when an `AudioTrackMenuItem is "clicked". See {@link ClickableComponent} + * for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + AudioTrackMenuItem.prototype.handleClick = function handleClick(event) { + var tracks = this.player_.audioTracks(); + + _MenuItem.prototype.handleClick.call(this, event); + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + track.enabled = track === this.track; + } + }; + + /** + * Handle any {@link AudioTrack} change. + * + * @param {EventTarget~Event} [event] + * The {@link AudioTrackList#change} event that caused this to run. + * + * @listens AudioTrackList#change + */ + + + AudioTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { + this.selected(this.track.enabled); + }; + + return AudioTrackMenuItem; + }(MenuItem); + + Component.registerComponent('AudioTrackMenuItem', AudioTrackMenuItem); + + /** + * @file audio-track-button.js + */ + + /** + * The base class for buttons that toggle specific {@link AudioTrack} types. + * + * @extends TrackButton + */ + + var AudioTrackButton = function (_TrackButton) { + inherits(AudioTrackButton, _TrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function AudioTrackButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, AudioTrackButton); + + options.tracks = player.audioTracks(); + + return possibleConstructorReturn(this, _TrackButton.call(this, player, options)); + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + AudioTrackButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-audio-button ' + _TrackButton.prototype.buildCSSClass.call(this); + }; + + AudioTrackButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() { + return 'vjs-audio-button ' + _TrackButton.prototype.buildWrapperCSSClass.call(this); + }; + + /** + * Create a menu item for each audio track + * + * @param {AudioTrackMenuItem[]} [items=[]] + * An array of existing menu items to use. + * + * @return {AudioTrackMenuItem[]} + * An array of menu items + */ + + + AudioTrackButton.prototype.createItems = function createItems() { + var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + + // if there's only one audio track, there no point in showing it + this.hideThreshold_ = 1; + + var tracks = this.player_.audioTracks(); + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + items.push(new AudioTrackMenuItem(this.player_, { + track: track, + // MenuItem is selectable + selectable: true + })); + } + + return items; + }; + + return AudioTrackButton; + }(TrackButton); + + /** + * The text that should display over the `AudioTrackButton`s controls. Added for localization. + * + * @type {string} + * @private + */ + + + AudioTrackButton.prototype.controlText_ = 'Audio Track'; + Component.registerComponent('AudioTrackButton', AudioTrackButton); + + /** + * @file playback-rate-menu-item.js + */ + + /** + * The specific menu item type for selecting a playback rate. + * + * @extends MenuItem + */ + + var PlaybackRateMenuItem = function (_MenuItem) { + inherits(PlaybackRateMenuItem, _MenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PlaybackRateMenuItem(player, options) { + classCallCheck(this, PlaybackRateMenuItem); + + var label = options.rate; + var rate = parseFloat(label, 10); + + // Modify options for parent MenuItem class's init. + options.label = label; + options.selected = rate === 1; + options.selectable = true; + + var _this = possibleConstructorReturn(this, _MenuItem.call(this, player, options)); + + _this.label = label; + _this.rate = rate; + + _this.on(player, 'ratechange', _this.update); + return _this; + } + + /** + * This gets called when an `PlaybackRateMenuItem` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + PlaybackRateMenuItem.prototype.handleClick = function handleClick(event) { + _MenuItem.prototype.handleClick.call(this); + this.player().playbackRate(this.rate); + }; + + /** + * Update the PlaybackRateMenuItem when the playbackrate changes. + * + * @param {EventTarget~Event} [event] + * The `ratechange` event that caused this function to run. + * + * @listens Player#ratechange + */ + + + PlaybackRateMenuItem.prototype.update = function update(event) { + this.selected(this.player().playbackRate() === this.rate); + }; + + return PlaybackRateMenuItem; + }(MenuItem); + + /** + * The text that should display over the `PlaybackRateMenuItem`s controls. Added for localization. + * + * @type {string} + * @private + */ + + + PlaybackRateMenuItem.prototype.contentElType = 'button'; + + Component.registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem); + + /** + * @file playback-rate-menu-button.js + */ + + /** + * The component for controlling the playback rate. + * + * @extends MenuButton + */ + + var PlaybackRateMenuButton = function (_MenuButton) { + inherits(PlaybackRateMenuButton, _MenuButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PlaybackRateMenuButton(player, options) { + classCallCheck(this, PlaybackRateMenuButton); + + var _this = possibleConstructorReturn(this, _MenuButton.call(this, player, options)); + + _this.updateVisibility(); + _this.updateLabel(); + + _this.on(player, 'loadstart', _this.updateVisibility); + _this.on(player, 'ratechange', _this.updateLabel); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + PlaybackRateMenuButton.prototype.createEl = function createEl$$1() { + var el = _MenuButton.prototype.createEl.call(this); + + this.labelEl_ = createEl('div', { + className: 'vjs-playback-rate-value', + innerHTML: '1x' + }); + + el.appendChild(this.labelEl_); + + return el; + }; + + PlaybackRateMenuButton.prototype.dispose = function dispose() { + this.labelEl_ = null; + + _MenuButton.prototype.dispose.call(this); + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this); + }; + + PlaybackRateMenuButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() { + return 'vjs-playback-rate ' + _MenuButton.prototype.buildWrapperCSSClass.call(this); + }; + + /** + * Create the playback rate menu + * + * @return {Menu} + * Menu object populated with {@link PlaybackRateMenuItem}s + */ + + + PlaybackRateMenuButton.prototype.createMenu = function createMenu() { + var menu = new Menu(this.player()); + var rates = this.playbackRates(); + + if (rates) { + for (var i = rates.length - 1; i >= 0; i--) { + menu.addChild(new PlaybackRateMenuItem(this.player(), {rate: rates[i] + 'x'})); + } + } + + return menu; + }; + + /** + * Updates ARIA accessibility attributes + */ + + + PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() { + // Current playback rate + this.el().setAttribute('aria-valuenow', this.player().playbackRate()); + }; + + /** + * This gets called when an `PlaybackRateMenuButton` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + PlaybackRateMenuButton.prototype.handleClick = function handleClick(event) { + // select next rate option + var currentRate = this.player().playbackRate(); + var rates = this.playbackRates(); + + // this will select first one if the last one currently selected + var newRate = rates[0]; + + for (var i = 0; i < rates.length; i++) { + if (rates[i] > currentRate) { + newRate = rates[i]; + break; + } + } + this.player().playbackRate(newRate); + }; + + /** + * Get possible playback rates + * + * @return {Array} + * All possible playback rates + */ + + + PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() { + return this.options_.playbackRates || this.options_.playerOptions && this.options_.playerOptions.playbackRates; + }; + + /** + * Get whether playback rates is supported by the tech + * and an array of playback rates exists + * + * @return {boolean} + * Whether changing playback rate is supported + */ + + + PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() { + return this.player().tech_ && this.player().tech_.featuresPlaybackRate && this.playbackRates() && this.playbackRates().length > 0; + }; + + /** + * Hide playback rate controls when they're no playback rate options to select + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#loadstart + */ + + + PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility(event) { + if (this.playbackRateSupported()) { + this.removeClass('vjs-hidden'); + } else { + this.addClass('vjs-hidden'); + } + }; + + /** + * Update button label when rate changed + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#ratechange + */ + + + PlaybackRateMenuButton.prototype.updateLabel = function updateLabel(event) { + if (this.playbackRateSupported()) { + this.labelEl_.innerHTML = this.player().playbackRate() + 'x'; + } + }; + + return PlaybackRateMenuButton; + }(MenuButton); + + /** + * The text that should display over the `FullscreenToggle`s controls. Added for localization. + * + * @type {string} + * @private + */ + + + PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate'; + + Component.registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton); + + /** + * @file spacer.js + */ + + /** + * Just an empty spacer element that can be used as an append point for plugins, etc. + * Also can be used to create space between elements when necessary. + * + * @extends Component + */ + + var Spacer = function (_Component) { + inherits(Spacer, _Component); + + function Spacer() { + classCallCheck(this, Spacer); + return possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + Spacer.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-spacer ' + _Component.prototype.buildCSSClass.call(this); + }; + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + Spacer.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: this.buildCSSClass() + }); + }; + + return Spacer; + }(Component); + + Component.registerComponent('Spacer', Spacer); + + /** + * @file custom-control-spacer.js + */ + + /** + * Spacer specifically meant to be used as an insertion point for new plugins, etc. + * + * @extends Spacer + */ + + var CustomControlSpacer = function (_Spacer) { + inherits(CustomControlSpacer, _Spacer); + + function CustomControlSpacer() { + classCallCheck(this, CustomControlSpacer); + return possibleConstructorReturn(this, _Spacer.apply(this, arguments)); + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + CustomControlSpacer.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-custom-control-spacer ' + _Spacer.prototype.buildCSSClass.call(this); + }; + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + CustomControlSpacer.prototype.createEl = function createEl() { + var el = _Spacer.prototype.createEl.call(this, { + className: this.buildCSSClass() + }); + + // No-flex/table-cell mode requires there be some content + // in the cell to fill the remaining space of the table. + el.innerHTML = '\xA0'; + return el; + }; + + return CustomControlSpacer; + }(Spacer); + + Component.registerComponent('CustomControlSpacer', CustomControlSpacer); + + /** + * @file control-bar.js + */ + + /** + * Container of main controls. + * + * @extends Component + */ + + var ControlBar = function (_Component) { + inherits(ControlBar, _Component); + + function ControlBar() { + classCallCheck(this, ControlBar); + return possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + ControlBar.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-control-bar', + dir: 'ltr' + }); + }; + + return ControlBar; + }(Component); + + /** + * Default options for `ControlBar` + * + * @type {Object} + * @private + */ + + + ControlBar.prototype.options_ = { + children: ['playToggle', 'volumePanel', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subsCapsButton', 'audioTrackButton', 'fullscreenToggle'] + }; + + Component.registerComponent('ControlBar', ControlBar); + + /** + * @file error-display.js + */ + + /** + * A display that indicates an error has occurred. This means that the video + * is unplayable. + * + * @extends ModalDialog + */ + + var ErrorDisplay = function (_ModalDialog) { + inherits(ErrorDisplay, _ModalDialog); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function ErrorDisplay(player, options) { + classCallCheck(this, ErrorDisplay); + + var _this = possibleConstructorReturn(this, _ModalDialog.call(this, player, options)); + + _this.on(player, 'error', _this.open); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + * + * @deprecated Since version 5. + */ + + + ErrorDisplay.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-error-display ' + _ModalDialog.prototype.buildCSSClass.call(this); + }; + + /** + * Gets the localized error message based on the `Player`s error. + * + * @return {string} + * The `Player`s error message localized or an empty string. + */ + + + ErrorDisplay.prototype.content = function content() { + var error = this.player().error(); + + return error ? this.localize(error.message) : ''; + }; + + return ErrorDisplay; + }(ModalDialog); + + /** + * The default options for an `ErrorDisplay`. + * + * @private + */ + + + ErrorDisplay.prototype.options_ = mergeOptions(ModalDialog.prototype.options_, { + pauseOnOpen: false, + fillAlways: true, + temporary: false, + uncloseable: true + }); + + Component.registerComponent('ErrorDisplay', ErrorDisplay); + + /** + * @file text-track-settings.js + */ + + var LOCAL_STORAGE_KEY = 'vjs-text-track-settings'; + + var COLOR_BLACK = ['#000', 'Black']; + var COLOR_BLUE = ['#00F', 'Blue']; + var COLOR_CYAN = ['#0FF', 'Cyan']; + var COLOR_GREEN = ['#0F0', 'Green']; + var COLOR_MAGENTA = ['#F0F', 'Magenta']; + var COLOR_RED = ['#F00', 'Red']; + var COLOR_WHITE = ['#FFF', 'White']; + var COLOR_YELLOW = ['#FF0', 'Yellow']; + + var OPACITY_OPAQUE = ['1', 'Opaque']; + var OPACITY_SEMI = ['0.5', 'Semi-Transparent']; + var OPACITY_TRANS = ['0', 'Transparent']; + + // Configuration for the various <select> elements in the DOM of this component. + // + // Possible keys include: + // + // `default`: + // The default option index. Only needs to be provided if not zero. + // `parser`: + // A function which is used to parse the value from the selected option in + // a customized way. + // `selector`: + // The selector used to find the associated <select> element. + var selectConfigs = { + backgroundColor: { + selector: '.vjs-bg-color > select', + id: 'captions-background-color-%s', + label: 'Color', + options: [COLOR_BLACK, COLOR_WHITE, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN] + }, + + backgroundOpacity: { + selector: '.vjs-bg-opacity > select', + id: 'captions-background-opacity-%s', + label: 'Transparency', + options: [OPACITY_OPAQUE, OPACITY_SEMI, OPACITY_TRANS] + }, + + color: { + selector: '.vjs-fg-color > select', + id: 'captions-foreground-color-%s', + label: 'Color', + options: [COLOR_WHITE, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN] + }, + + edgeStyle: { + selector: '.vjs-edge-style > select', + id: '%s', + label: 'Text Edge Style', + options: [['none', 'None'], ['raised', 'Raised'], ['depressed', 'Depressed'], ['uniform', 'Uniform'], ['dropshadow', 'Dropshadow']] + }, + + fontFamily: { + selector: '.vjs-font-family > select', + id: 'captions-font-family-%s', + label: 'Font Family', + options: [['proportionalSansSerif', 'Proportional Sans-Serif'], ['monospaceSansSerif', 'Monospace Sans-Serif'], ['proportionalSerif', 'Proportional Serif'], ['monospaceSerif', 'Monospace Serif'], ['casual', 'Casual'], ['script', 'Script'], ['small-caps', 'Small Caps']] + }, + + fontPercent: { + selector: '.vjs-font-percent > select', + id: 'captions-font-size-%s', + label: 'Font Size', + options: [['0.50', '50%'], ['0.75', '75%'], ['1.00', '100%'], ['1.25', '125%'], ['1.50', '150%'], ['1.75', '175%'], ['2.00', '200%'], ['3.00', '300%'], ['4.00', '400%']], + default: 2, + parser: function parser(v) { + return v === '1.00' ? null : Number(v); + } + }, + + textOpacity: { + selector: '.vjs-text-opacity > select', + id: 'captions-foreground-opacity-%s', + label: 'Transparency', + options: [OPACITY_OPAQUE, OPACITY_SEMI] + }, + + // Options for this object are defined below. + windowColor: { + selector: '.vjs-window-color > select', + id: 'captions-window-color-%s', + label: 'Color' + }, + + // Options for this object are defined below. + windowOpacity: { + selector: '.vjs-window-opacity > select', + id: 'captions-window-opacity-%s', + label: 'Transparency', + options: [OPACITY_TRANS, OPACITY_SEMI, OPACITY_OPAQUE] + } + }; + + selectConfigs.windowColor.options = selectConfigs.backgroundColor.options; + + /** + * Get the actual value of an option. + * + * @param {string} value + * The value to get + * + * @param {Function} [parser] + * Optional function to adjust the value. + * + * @return {Mixed} + * - Will be `undefined` if no value exists + * - Will be `undefined` if the given value is "none". + * - Will be the actual value otherwise. + * + * @private + */ + function parseOptionValue(value, parser) { + if (parser) { + value = parser(value); + } + + if (value && value !== 'none') { + return value; + } + } + + /** + * Gets the value of the selected <option> element within a <select> element. + * + * @param {Element} el + * the element to look in + * + * @param {Function} [parser] + * Optional function to adjust the value. + * + * @return {Mixed} + * - Will be `undefined` if no value exists + * - Will be `undefined` if the given value is "none". + * - Will be the actual value otherwise. + * + * @private + */ + function getSelectedOptionValue(el, parser) { + var value = el.options[el.options.selectedIndex].value; + + return parseOptionValue(value, parser); + } + + /** + * Sets the selected <option> element within a <select> element based on a + * given value. + * + * @param {Element} el + * The element to look in. + * + * @param {string} value + * the property to look on. + * + * @param {Function} [parser] + * Optional function to adjust the value before comparing. + * + * @private + */ + function setSelectedOption(el, value, parser) { + if (!value) { + return; + } + + for (var i = 0; i < el.options.length; i++) { + if (parseOptionValue(el.options[i].value, parser) === value) { + el.selectedIndex = i; + break; + } + } + } + + /** + * Manipulate Text Tracks settings. + * + * @extends ModalDialog + */ + + var TextTrackSettings = function (_ModalDialog) { + inherits(TextTrackSettings, _ModalDialog); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function TextTrackSettings(player, options) { + classCallCheck(this, TextTrackSettings); + + options.temporary = false; + + var _this = possibleConstructorReturn(this, _ModalDialog.call(this, player, options)); + + _this.updateDisplay = bind(_this, _this.updateDisplay); + + // fill the modal and pretend we have opened it + _this.fill(); + _this.hasBeenOpened_ = _this.hasBeenFilled_ = true; + + _this.endDialog = createEl('p', { + className: 'vjs-control-text', + textContent: _this.localize('End of dialog window.') + }); + _this.el().appendChild(_this.endDialog); + + _this.setDefaults(); + + // Grab `persistTextTrackSettings` from the player options if not passed in child options + if (options.persistTextTrackSettings === undefined) { + _this.options_.persistTextTrackSettings = _this.options_.playerOptions.persistTextTrackSettings; + } + + _this.on(_this.$('.vjs-done-button'), 'click', function () { + _this.saveSettings(); + _this.close(); + }); + + _this.on(_this.$('.vjs-default-button'), 'click', function () { + _this.setDefaults(); + _this.updateDisplay(); + }); + + each(selectConfigs, function (config) { + _this.on(_this.$(config.selector), 'change', _this.updateDisplay); + }); + + if (_this.options_.persistTextTrackSettings) { + _this.restoreSettings(); + } + return _this; + } + + TextTrackSettings.prototype.dispose = function dispose() { + this.endDialog = null; + + _ModalDialog.prototype.dispose.call(this); + }; + + /** + * Create a <select> element with configured options. + * + * @param {string} key + * Configuration key to use during creation. + * + * @return {string} + * An HTML string. + * + * @private + */ + + + TextTrackSettings.prototype.createElSelect_ = function createElSelect_(key) { + var _this2 = this; + + var legendId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; + var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'label'; + + var config = selectConfigs[key]; + var id = config.id.replace('%s', this.id_); + var selectLabelledbyIds = [legendId, id].join(' ').trim(); + + return ['<' + type + ' id="' + id + '" class="' + (type === 'label' ? 'vjs-label' : '') + '">', this.localize(config.label), '</' + type + '>', '<select aria-labelledby="' + selectLabelledbyIds + '">'].concat(config.options.map(function (o) { + var optionId = id + '-' + o[1].replace(/\W+/g, ''); + + return ['<option id="' + optionId + '" value="' + o[0] + '" ', 'aria-labelledby="' + selectLabelledbyIds + ' ' + optionId + '">', _this2.localize(o[1]), '</option>'].join(''); + })).concat('</select>').join(''); + }; + + /** + * Create foreground color element for the component + * + * @return {string} + * An HTML string. + * + * @private + */ + + + TextTrackSettings.prototype.createElFgColor_ = function createElFgColor_() { + var legendId = 'captions-text-legend-' + this.id_; + + return ['<fieldset class="vjs-fg-color vjs-track-setting">', '<legend id="' + legendId + '">', this.localize('Text'), '</legend>', this.createElSelect_('color', legendId), '<span class="vjs-text-opacity vjs-opacity">', this.createElSelect_('textOpacity', legendId), '</span>', '</fieldset>'].join(''); + }; + + /** + * Create background color element for the component + * + * @return {string} + * An HTML string. + * + * @private + */ + + + TextTrackSettings.prototype.createElBgColor_ = function createElBgColor_() { + var legendId = 'captions-background-' + this.id_; + + return ['<fieldset class="vjs-bg-color vjs-track-setting">', '<legend id="' + legendId + '">', this.localize('Background'), '</legend>', this.createElSelect_('backgroundColor', legendId), '<span class="vjs-bg-opacity vjs-opacity">', this.createElSelect_('backgroundOpacity', legendId), '</span>', '</fieldset>'].join(''); + }; + + /** + * Create window color element for the component + * + * @return {string} + * An HTML string. + * + * @private + */ + + + TextTrackSettings.prototype.createElWinColor_ = function createElWinColor_() { + var legendId = 'captions-window-' + this.id_; + + return ['<fieldset class="vjs-window-color vjs-track-setting">', '<legend id="' + legendId + '">', this.localize('Window'), '</legend>', this.createElSelect_('windowColor', legendId), '<span class="vjs-window-opacity vjs-opacity">', this.createElSelect_('windowOpacity', legendId), '</span>', '</fieldset>'].join(''); + }; + + /** + * Create color elements for the component + * + * @return {Element} + * The element that was created + * + * @private + */ + + + TextTrackSettings.prototype.createElColors_ = function createElColors_() { + return createEl('div', { + className: 'vjs-track-settings-colors', + innerHTML: [this.createElFgColor_(), this.createElBgColor_(), this.createElWinColor_()].join('') + }); + }; + + /** + * Create font elements for the component + * + * @return {Element} + * The element that was created. + * + * @private + */ + + + TextTrackSettings.prototype.createElFont_ = function createElFont_() { + return createEl('div', { + className: 'vjs-track-settings-font', + innerHTML: ['<fieldset class="vjs-font-percent vjs-track-setting">', this.createElSelect_('fontPercent', '', 'legend'), '</fieldset>', '<fieldset class="vjs-edge-style vjs-track-setting">', this.createElSelect_('edgeStyle', '', 'legend'), '</fieldset>', '<fieldset class="vjs-font-family vjs-track-setting">', this.createElSelect_('fontFamily', '', 'legend'), '</fieldset>'].join('') + }); + }; + + /** + * Create controls for the component + * + * @return {Element} + * The element that was created. + * + * @private + */ + + + TextTrackSettings.prototype.createElControls_ = function createElControls_() { + var defaultsDescription = this.localize('restore all settings to the default values'); + + return createEl('div', { + className: 'vjs-track-settings-controls', + innerHTML: ['<button class="vjs-default-button" title="' + defaultsDescription + '">', this.localize('Reset'), '<span class="vjs-control-text"> ' + defaultsDescription + '</span>', '</button>', '<button class="vjs-done-button">' + this.localize('Done') + '</button>'].join('') + }); + }; + + TextTrackSettings.prototype.content = function content() { + return [this.createElColors_(), this.createElFont_(), this.createElControls_()]; + }; + + TextTrackSettings.prototype.label = function label() { + return this.localize('Caption Settings Dialog'); + }; + + TextTrackSettings.prototype.description = function description() { + return this.localize('Beginning of dialog window. Escape will cancel and close the window.'); + }; + + TextTrackSettings.prototype.buildCSSClass = function buildCSSClass() { + return _ModalDialog.prototype.buildCSSClass.call(this) + ' vjs-text-track-settings'; + }; + + /** + * Gets an object of text track settings (or null). + * + * @return {Object} + * An object with config values parsed from the DOM or localStorage. + */ + + + TextTrackSettings.prototype.getValues = function getValues() { + var _this3 = this; + + return reduce(selectConfigs, function (accum, config, key) { + var value = getSelectedOptionValue(_this3.$(config.selector), config.parser); + + if (value !== undefined) { + accum[key] = value; + } + + return accum; + }, {}); + }; + + /** + * Sets text track settings from an object of values. + * + * @param {Object} values + * An object with config values parsed from the DOM or localStorage. + */ + + + TextTrackSettings.prototype.setValues = function setValues(values) { + var _this4 = this; + + each(selectConfigs, function (config, key) { + setSelectedOption(_this4.$(config.selector), values[key], config.parser); + }); + }; + + /** + * Sets all `<select>` elements to their default values. + */ + + + TextTrackSettings.prototype.setDefaults = function setDefaults() { + var _this5 = this; + + each(selectConfigs, function (config) { + var index = config.hasOwnProperty('default') ? config.default : 0; + + _this5.$(config.selector).selectedIndex = index; + }); + }; + + /** + * Restore texttrack settings from localStorage + */ + + + TextTrackSettings.prototype.restoreSettings = function restoreSettings() { + var values = void 0; + + try { + values = JSON.parse(window_1.localStorage.getItem(LOCAL_STORAGE_KEY)); + } catch (err) { + log$1.warn(err); + } + + if (values) { + this.setValues(values); + } + }; + + /** + * Save text track settings to localStorage + */ + + + TextTrackSettings.prototype.saveSettings = function saveSettings() { + if (!this.options_.persistTextTrackSettings) { + return; + } + + var values = this.getValues(); + + try { + if (Object.keys(values).length) { + window_1.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(values)); + } else { + window_1.localStorage.removeItem(LOCAL_STORAGE_KEY); + } + } catch (err) { + log$1.warn(err); + } + }; + + /** + * Update display of text track settings + */ + + + TextTrackSettings.prototype.updateDisplay = function updateDisplay() { + var ttDisplay = this.player_.getChild('textTrackDisplay'); + + if (ttDisplay) { + ttDisplay.updateDisplay(); + } + }; + + /** + * conditionally blur the element and refocus the captions button + * + * @private + */ + + + TextTrackSettings.prototype.conditionalBlur_ = function conditionalBlur_() { + this.previouslyActiveEl_ = null; + this.off(document_1, 'keydown', this.handleKeyDown); + + var cb = this.player_.controlBar; + var subsCapsBtn = cb && cb.subsCapsButton; + var ccBtn = cb && cb.captionsButton; + + if (subsCapsBtn) { + subsCapsBtn.focus(); + } else if (ccBtn) { + ccBtn.focus(); + } + }; + + return TextTrackSettings; + }(ModalDialog); + + Component.registerComponent('TextTrackSettings', TextTrackSettings); + + /** + * @file resize-manager.js + */ + + /** + * A Resize Manager. It is in charge of triggering `playerresize` on the player in the right conditions. + * + * It'll either create an iframe and use a debounced resize handler on it or use the new {@link https://wicg.github.io/ResizeObserver/|ResizeObserver}. + * + * If the ResizeObserver is available natively, it will be used. A polyfill can be passed in as an option. + * If a `playerresize` event is not needed, the ResizeManager component can be removed from the player, see the example below. + * @example <caption>How to disable the resize manager</caption> + * const player = videojs('#vid', { + * resizeManager: false + * }); + * + * @see {@link https://wicg.github.io/ResizeObserver/|ResizeObserver specification} + * + * @extends Component + */ + + var ResizeManager = function (_Component) { + inherits(ResizeManager, _Component); + + /** + * Create the ResizeManager. + * + * @param {Object} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of ResizeManager options. + * + * @param {Object} [options.ResizeObserver] + * A polyfill for ResizeObserver can be passed in here. + * If this is set to null it will ignore the native ResizeObserver and fall back to the iframe fallback. + */ + function ResizeManager(player, options) { + classCallCheck(this, ResizeManager); + + var RESIZE_OBSERVER_AVAILABLE = options.ResizeObserver || window_1.ResizeObserver; + + // if `null` was passed, we want to disable the ResizeObserver + if (options.ResizeObserver === null) { + RESIZE_OBSERVER_AVAILABLE = false; + } + + // Only create an element when ResizeObserver isn't available + var options_ = mergeOptions({createEl: !RESIZE_OBSERVER_AVAILABLE}, options); + + var _this = possibleConstructorReturn(this, _Component.call(this, player, options_)); + + _this.ResizeObserver = options.ResizeObserver || window_1.ResizeObserver; + _this.loadListener_ = null; + _this.resizeObserver_ = null; + _this.debouncedHandler_ = debounce(function () { + _this.resizeHandler(); + }, 100, false, player); + + if (RESIZE_OBSERVER_AVAILABLE) { + _this.resizeObserver_ = new _this.ResizeObserver(_this.debouncedHandler_); + _this.resizeObserver_.observe(player.el()); + } else { + _this.loadListener_ = function () { + if (_this.el_.contentWindow) { + on(_this.el_.contentWindow, 'resize', _this.debouncedHandler_); + } + _this.off('load', _this.loadListener_); + }; + + _this.on('load', _this.loadListener_); + } + return _this; + } + + ResizeManager.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'iframe', { + className: 'vjs-resize-manager' + }); + }; + + /** + * Called when a resize is triggered on the iframe or a resize is observed via the ResizeObserver + * + * @fires Player#playerresize + */ + + + ResizeManager.prototype.resizeHandler = function resizeHandler() { + /** + * Called when the player size has changed + * + * @event Player#playerresize + * @type {EventTarget~Event} + */ + this.player_.trigger('playerresize'); + }; + + ResizeManager.prototype.dispose = function dispose() { + if (this.resizeObserver_) { + this.resizeObserver_.unobserve(this.player_.el()); + this.resizeObserver_.disconnect(); + } + + if (this.el_ && this.el_.contentWindow) { + off(this.el_.contentWindow, 'resize', this.debouncedHandler_); + } + + if (this.loadListener_) { + this.off('load', this.loadListener_); + } + + this.ResizeObserver = null; + this.resizeObserver = null; + this.debouncedHandler_ = null; + this.loadListener_ = null; + }; + + return ResizeManager; + }(Component); + + Component.registerComponent('ResizeManager', ResizeManager); + + /** + * This function is used to fire a sourceset when there is something + * similar to `mediaEl.load()` being called. It will try to find the source via + * the `src` attribute and then the `<source>` elements. It will then fire `sourceset` + * with the source that was found or empty string if we cannot know. If it cannot + * find a source then `sourceset` will not be fired. + * + * @param {Html5} tech + * The tech object that sourceset was setup on + * + * @return {boolean} + * returns false if the sourceset was not fired and true otherwise. + */ + var sourcesetLoad = function sourcesetLoad(tech) { + var el = tech.el(); + + // if `el.src` is set, that source will be loaded. + if (el.hasAttribute('src')) { + tech.triggerSourceset(el.src); + return true; + } + + /** + * Since there isn't a src property on the media element, source elements will be used for + * implementing the source selection algorithm. This happens asynchronously and + * for most cases were there is more than one source we cannot tell what source will + * be loaded, without re-implementing the source selection algorithm. At this time we are not + * going to do that. There are three special cases that we do handle here though: + * + * 1. If there are no sources, do not fire `sourceset`. + * 2. If there is only one `<source>` with a `src` property/attribute that is our `src` + * 3. If there is more than one `<source>` but all of them have the same `src` url. + * That will be our src. + */ + var sources = tech.$$('source'); + var srcUrls = []; + var src = ''; + + // if there are no sources, do not fire sourceset + if (!sources.length) { + return false; + } + + // only count valid/non-duplicate source elements + for (var i = 0; i < sources.length; i++) { + var url = sources[i].src; + + if (url && srcUrls.indexOf(url) === -1) { + srcUrls.push(url); + } + } + + // there were no valid sources + if (!srcUrls.length) { + return false; + } + + // there is only one valid source element url + // use that + if (srcUrls.length === 1) { + src = srcUrls[0]; + } + + tech.triggerSourceset(src); + return true; + }; + + /** + * our implementation of an `innerHTML` descriptor for browsers + * that do not have one. + */ + var innerHTMLDescriptorPolyfill = Object.defineProperty({}, 'innerHTML', { + get: function get() { + return this.cloneNode(true).innerHTML; + }, + set: function set(v) { + // make a dummy node to use innerHTML on + var dummy = document_1.createElement(this.nodeName.toLowerCase()); + + // set innerHTML to the value provided + dummy.innerHTML = v; + + // make a document fragment to hold the nodes from dummy + var docFrag = document_1.createDocumentFragment(); + + // copy all of the nodes created by the innerHTML on dummy + // to the document fragment + while (dummy.childNodes.length) { + docFrag.appendChild(dummy.childNodes[0]); + } + + // remove content + this.innerText = ''; + + // now we add all of that html in one by appending the + // document fragment. This is how innerHTML does it. + window_1.Element.prototype.appendChild.call(this, docFrag); + + // then return the result that innerHTML's setter would + return this.innerHTML; + } + }); + + /** + * Get a property descriptor given a list of priorities and the + * property to get. + */ + var getDescriptor = function getDescriptor(priority, prop) { + var descriptor = {}; + + for (var i = 0; i < priority.length; i++) { + descriptor = Object.getOwnPropertyDescriptor(priority[i], prop); + + if (descriptor && descriptor.set && descriptor.get) { + break; + } + } + + descriptor.enumerable = true; + descriptor.configurable = true; + + return descriptor; + }; + + var getInnerHTMLDescriptor = function getInnerHTMLDescriptor(tech) { + return getDescriptor([tech.el(), window_1.HTMLMediaElement.prototype, window_1.Element.prototype, innerHTMLDescriptorPolyfill], 'innerHTML'); + }; + + /** + * Patches browser internal functions so that we can tell synchronously + * if a `<source>` was appended to the media element. For some reason this + * causes a `sourceset` if the the media element is ready and has no source. + * This happens when: + * - The page has just loaded and the media element does not have a source. + * - The media element was emptied of all sources, then `load()` was called. + * + * It does this by patching the following functions/properties when they are supported: + * + * - `append()` - can be used to add a `<source>` element to the media element + * - `appendChild()` - can be used to add a `<source>` element to the media element + * - `insertAdjacentHTML()` - can be used to add a `<source>` element to the media element + * - `innerHTML` - can be used to add a `<source>` element to the media element + * + * @param {Html5} tech + * The tech object that sourceset is being setup on. + */ + var firstSourceWatch = function firstSourceWatch(tech) { + var el = tech.el(); + + // make sure firstSourceWatch isn't setup twice. + if (el.resetSourceWatch_) { + return; + } + + var old = {}; + var innerDescriptor = getInnerHTMLDescriptor(tech); + var appendWrapper = function appendWrapper(appendFn) { + return function () { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + var retval = appendFn.apply(el, args); + + sourcesetLoad(tech); + + return retval; + }; + }; + + ['append', 'appendChild', 'insertAdjacentHTML'].forEach(function (k) { + if (!el[k]) { + return; + } + + // store the old function + old[k] = el[k]; + + // call the old function with a sourceset if a source + // was loaded + el[k] = appendWrapper(old[k]); + }); + + Object.defineProperty(el, 'innerHTML', mergeOptions(innerDescriptor, { + set: appendWrapper(innerDescriptor.set) + })); + + el.resetSourceWatch_ = function () { + el.resetSourceWatch_ = null; + Object.keys(old).forEach(function (k) { + el[k] = old[k]; + }); + + Object.defineProperty(el, 'innerHTML', innerDescriptor); + }; + + // on the first sourceset, we need to revert our changes + tech.one('sourceset', el.resetSourceWatch_); + }; + + /** + * our implementation of a `src` descriptor for browsers + * that do not have one. + */ + var srcDescriptorPolyfill = Object.defineProperty({}, 'src', { + get: function get() { + if (this.hasAttribute('src')) { + return getAbsoluteURL(window_1.Element.prototype.getAttribute.call(this, 'src')); + } + + return ''; + }, + set: function set(v) { + window_1.Element.prototype.setAttribute.call(this, 'src', v); + + return v; + } + }); + + var getSrcDescriptor = function getSrcDescriptor(tech) { + return getDescriptor([tech.el(), window_1.HTMLMediaElement.prototype, srcDescriptorPolyfill], 'src'); + }; + + /** + * setup `sourceset` handling on the `Html5` tech. This function + * patches the following element properties/functions: + * + * - `src` - to determine when `src` is set + * - `setAttribute()` - to determine when `src` is set + * - `load()` - this re-triggers the source selection algorithm, and can + * cause a sourceset. + * + * If there is no source when we are adding `sourceset` support or during a `load()` + * we also patch the functions listed in `firstSourceWatch`. + * + * @param {Html5} tech + * The tech to patch + */ + var setupSourceset = function setupSourceset(tech) { + if (!tech.featuresSourceset) { + return; + } + + var el = tech.el(); + + // make sure sourceset isn't setup twice. + if (el.resetSourceset_) { + return; + } + + var srcDescriptor = getSrcDescriptor(tech); + var oldSetAttribute = el.setAttribute; + var oldLoad = el.load; + + Object.defineProperty(el, 'src', mergeOptions(srcDescriptor, { + set: function set(v) { + var retval = srcDescriptor.set.call(el, v); + + // we use the getter here to get the actual value set on src + tech.triggerSourceset(el.src); + + return retval; + } + })); + + el.setAttribute = function (n, v) { + var retval = oldSetAttribute.call(el, n, v); + + if (/src/i.test(n)) { + tech.triggerSourceset(el.src); + } + + return retval; + }; + + el.load = function () { + var retval = oldLoad.call(el); + + // if load was called, but there was no source to fire + // sourceset on. We have to watch for a source append + // as that can trigger a `sourceset` when the media element + // has no source + if (!sourcesetLoad(tech)) { + tech.triggerSourceset(''); + firstSourceWatch(tech); + } + + return retval; + }; + + if (el.currentSrc) { + tech.triggerSourceset(el.currentSrc); + } else if (!sourcesetLoad(tech)) { + firstSourceWatch(tech); + } + + el.resetSourceset_ = function () { + el.resetSourceset_ = null; + el.load = oldLoad; + el.setAttribute = oldSetAttribute; + Object.defineProperty(el, 'src', srcDescriptor); + if (el.resetSourceWatch_) { + el.resetSourceWatch_(); + } + }; + }; + + var _templateObject$1 = taggedTemplateLiteralLoose(['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n This may prevent text tracks from loading.'], ['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n This may prevent text tracks from loading.']); + + /** + * HTML5 Media Controller - Wrapper for HTML5 Media API + * + * @mixes Tech~SourceHandlerAdditions + * @extends Tech + */ + + var Html5 = function (_Tech) { + inherits(Html5, _Tech); + + /** + * Create an instance of this Tech. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} ready + * Callback function to call when the `HTML5` Tech is ready. + */ + function Html5(options, ready) { + classCallCheck(this, Html5); + + var _this = possibleConstructorReturn(this, _Tech.call(this, options, ready)); + + var source = options.source; + var crossoriginTracks = false; + + // Set the source if one is provided + // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted) + // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source + // anyway so the error gets fired. + if (source && (_this.el_.currentSrc !== source.src || options.tag && options.tag.initNetworkState_ === 3)) { + _this.setSource(source); + } else { + _this.handleLateInit_(_this.el_); + } + + // setup sourceset after late sourceset/init + if (options.enableSourceset) { + _this.setupSourcesetHandling_(); + } + + if (_this.el_.hasChildNodes()) { + + var nodes = _this.el_.childNodes; + var nodesLength = nodes.length; + var removeNodes = []; + + while (nodesLength--) { + var node = nodes[nodesLength]; + var nodeName = node.nodeName.toLowerCase(); + + if (nodeName === 'track') { + if (!_this.featuresNativeTextTracks) { + // Empty video tag tracks so the built-in player doesn't use them also. + // This may not be fast enough to stop HTML5 browsers from reading the tags + // so we'll need to turn off any default tracks if we're manually doing + // captions and subtitles. videoElement.textTracks + removeNodes.push(node); + } else { + // store HTMLTrackElement and TextTrack to remote list + _this.remoteTextTrackEls().addTrackElement_(node); + _this.remoteTextTracks().addTrack(node.track); + _this.textTracks().addTrack(node.track); + if (!crossoriginTracks && !_this.el_.hasAttribute('crossorigin') && isCrossOrigin(node.src)) { + crossoriginTracks = true; + } + } + } + } + + for (var i = 0; i < removeNodes.length; i++) { + _this.el_.removeChild(removeNodes[i]); + } + } + + _this.proxyNativeTracks_(); + if (_this.featuresNativeTextTracks && crossoriginTracks) { + log$1.warn(tsml(_templateObject$1)); + } + + // prevent iOS Safari from disabling metadata text tracks during native playback + _this.restoreMetadataTracksInIOSNativePlayer_(); + + // Determine if native controls should be used + // Our goal should be to get the custom controls on mobile solid everywhere + // so we can remove this all together. Right now this will block custom + // controls on touch enabled laptops like the Chrome Pixel + if ((TOUCH_ENABLED || IS_IPHONE || IS_NATIVE_ANDROID) && options.nativeControlsForTouch === true) { + _this.setControls(true); + } + + // on iOS, we want to proxy `webkitbeginfullscreen` and `webkitendfullscreen` + // into a `fullscreenchange` event + _this.proxyWebkitFullscreen_(); + + _this.triggerReady(); + return _this; + } + + /** + * Dispose of `HTML5` media element and remove all tracks. + */ + + + Html5.prototype.dispose = function dispose() { + if (this.el_.resetSourceset_) { + this.el_.resetSourceset_(); + } + Html5.disposeMediaElement(this.el_); + this.options_ = null; + + // tech will handle clearing of the emulated track list + _Tech.prototype.dispose.call(this); + }; + + /** + * Modify the media element so that we can detect when + * the source is changed. Fires `sourceset` just after the source has changed + */ + + + Html5.prototype.setupSourcesetHandling_ = function setupSourcesetHandling_() { + setupSourceset(this); + }; + + /** + * When a captions track is enabled in the iOS Safari native player, all other + * tracks are disabled (including metadata tracks), which nulls all of their + * associated cue points. This will restore metadata tracks to their pre-fullscreen + * state in those cases so that cue points are not needlessly lost. + * + * @private + */ + + + Html5.prototype.restoreMetadataTracksInIOSNativePlayer_ = function restoreMetadataTracksInIOSNativePlayer_() { + var textTracks = this.textTracks(); + var metadataTracksPreFullscreenState = void 0; + + // captures a snapshot of every metadata track's current state + var takeMetadataTrackSnapshot = function takeMetadataTrackSnapshot() { + metadataTracksPreFullscreenState = []; + + for (var i = 0; i < textTracks.length; i++) { + var track = textTracks[i]; + + if (track.kind === 'metadata') { + metadataTracksPreFullscreenState.push({ + track: track, + storedMode: track.mode + }); + } + } + }; + + // snapshot each metadata track's initial state, and update the snapshot + // each time there is a track 'change' event + takeMetadataTrackSnapshot(); + textTracks.addEventListener('change', takeMetadataTrackSnapshot); + + this.on('dispose', function () { + return textTracks.removeEventListener('change', takeMetadataTrackSnapshot); + }); + + var restoreTrackMode = function restoreTrackMode() { + for (var i = 0; i < metadataTracksPreFullscreenState.length; i++) { + var storedTrack = metadataTracksPreFullscreenState[i]; + + if (storedTrack.track.mode === 'disabled' && storedTrack.track.mode !== storedTrack.storedMode) { + storedTrack.track.mode = storedTrack.storedMode; + } + } + // we only want this handler to be executed on the first 'change' event + textTracks.removeEventListener('change', restoreTrackMode); + }; + + // when we enter fullscreen playback, stop updating the snapshot and + // restore all track modes to their pre-fullscreen state + this.on('webkitbeginfullscreen', function () { + textTracks.removeEventListener('change', takeMetadataTrackSnapshot); + + // remove the listener before adding it just in case it wasn't previously removed + textTracks.removeEventListener('change', restoreTrackMode); + textTracks.addEventListener('change', restoreTrackMode); + }); + + // start updating the snapshot again after leaving fullscreen + this.on('webkitendfullscreen', function () { + // remove the listener before adding it just in case it wasn't previously removed + textTracks.removeEventListener('change', takeMetadataTrackSnapshot); + textTracks.addEventListener('change', takeMetadataTrackSnapshot); + + // remove the restoreTrackMode handler in case it wasn't triggered during fullscreen playback + textTracks.removeEventListener('change', restoreTrackMode); + }); + }; + + /** + * Attempt to force override of tracks for the given type + * + * @param {String} type - Track type to override, possible values include 'Audio', + * 'Video', and 'Text'. + * @param {Boolean} override - If set to true native audio/video will be overridden, + * otherwise native audio/video will potentially be used. + * @private + */ + + + Html5.prototype.overrideNative_ = function overrideNative_(type, override) { + var _this2 = this; + + // If there is no behavioral change don't add/remove listeners + if (override !== this['featuresNative' + type + 'Tracks']) { + return; + } + + var lowerCaseType = type.toLowerCase(); + + if (this[lowerCaseType + 'TracksListeners_']) { + Object.keys(this[lowerCaseType + 'TracksListeners_']).forEach(function (eventName) { + var elTracks = _this2.el()[lowerCaseType + 'Tracks']; + + elTracks.removeEventListener(eventName, _this2[lowerCaseType + 'TracksListeners_'][eventName]); + }); + } + + this['featuresNative' + type + 'Tracks'] = !override; + this[lowerCaseType + 'TracksListeners_'] = null; + + this.proxyNativeTracksForType_(lowerCaseType); + }; + + /** + * Attempt to force override of native audio tracks. + * + * @param {Boolean} override - If set to true native audio will be overridden, + * otherwise native audio will potentially be used. + */ + + + Html5.prototype.overrideNativeAudioTracks = function overrideNativeAudioTracks(override) { + this.overrideNative_('Audio', override); + }; + + /** + * Attempt to force override of native video tracks. + * + * @param {Boolean} override - If set to true native video will be overridden, + * otherwise native video will potentially be used. + */ + + + Html5.prototype.overrideNativeVideoTracks = function overrideNativeVideoTracks(override) { + this.overrideNative_('Video', override); + }; + + /** + * Proxy native track list events for the given type to our track + * lists if the browser we are playing in supports that type of track list. + * + * @param {string} name - Track type; values include 'audio', 'video', and 'text' + * @private + */ + + + Html5.prototype.proxyNativeTracksForType_ = function proxyNativeTracksForType_(name) { + var _this3 = this; + + var props = NORMAL[name]; + var elTracks = this.el()[props.getterName]; + var techTracks = this[props.getterName](); + + if (!this['featuresNative' + props.capitalName + 'Tracks'] || !elTracks || !elTracks.addEventListener) { + return; + } + var listeners = { + change: function change(e) { + techTracks.trigger({ + type: 'change', + target: techTracks, + currentTarget: techTracks, + srcElement: techTracks + }); + }, + addtrack: function addtrack(e) { + techTracks.addTrack(e.track); + }, + removetrack: function removetrack(e) { + techTracks.removeTrack(e.track); + } + }; + var removeOldTracks = function removeOldTracks() { + var removeTracks = []; + + for (var i = 0; i < techTracks.length; i++) { + var found = false; + + for (var j = 0; j < elTracks.length; j++) { + if (elTracks[j] === techTracks[i]) { + found = true; + break; + } + } + + if (!found) { + removeTracks.push(techTracks[i]); + } + } + + while (removeTracks.length) { + techTracks.removeTrack(removeTracks.shift()); + } + }; + + this[props.getterName + 'Listeners_'] = listeners; + + Object.keys(listeners).forEach(function (eventName) { + var listener = listeners[eventName]; + + elTracks.addEventListener(eventName, listener); + _this3.on('dispose', function (e) { + return elTracks.removeEventListener(eventName, listener); + }); + }); + + // Remove (native) tracks that are not used anymore + this.on('loadstart', removeOldTracks); + this.on('dispose', function (e) { + return _this3.off('loadstart', removeOldTracks); + }); + }; + + /** + * Proxy all native track list events to our track lists if the browser we are playing + * in supports that type of track list. + * + * @private + */ + + + Html5.prototype.proxyNativeTracks_ = function proxyNativeTracks_() { + var _this4 = this; + + NORMAL.names.forEach(function (name) { + _this4.proxyNativeTracksForType_(name); + }); + }; + + /** + * Create the `Html5` Tech's DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + Html5.prototype.createEl = function createEl$$1() { + var el = this.options_.tag; + + // Check if this browser supports moving the element into the box. + // On the iPhone video will break if you move the element, + // So we have to create a brand new element. + // If we ingested the player div, we do not need to move the media element. + if (!el || !(this.options_.playerElIngest || this.movingMediaElementInDOM)) { + + // If the original tag is still there, clone and remove it. + if (el) { + var clone = el.cloneNode(true); + + if (el.parentNode) { + el.parentNode.insertBefore(clone, el); + } + Html5.disposeMediaElement(el); + el = clone; + } else { + el = document_1.createElement('video'); + + // determine if native controls should be used + var tagAttributes = this.options_.tag && getAttributes(this.options_.tag); + var attributes = mergeOptions({}, tagAttributes); + + if (!TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) { + delete attributes.controls; + } + + setAttributes(el, assign(attributes, { + id: this.options_.techId, + class: 'vjs-tech' + })); + } + + el.playerId = this.options_.playerId; + } + + if (typeof this.options_.preload !== 'undefined') { + setAttribute(el, 'preload', this.options_.preload); + } + + // Update specific tag settings, in case they were overridden + // `autoplay` has to be *last* so that `muted` and `playsinline` are present + // when iOS/Safari or other browsers attempt to autoplay. + var settingsAttrs = ['loop', 'muted', 'playsinline', 'autoplay']; + + for (var i = 0; i < settingsAttrs.length; i++) { + var attr = settingsAttrs[i]; + var value = this.options_[attr]; + + if (typeof value !== 'undefined') { + if (value) { + setAttribute(el, attr, attr); + } else { + removeAttribute(el, attr); + } + el[attr] = value; + } + } + + return el; + }; + + /** + * This will be triggered if the loadstart event has already fired, before videojs was + * ready. Two known examples of when this can happen are: + * 1. If we're loading the playback object after it has started loading + * 2. The media is already playing the (often with autoplay on) then + * + * This function will fire another loadstart so that videojs can catchup. + * + * @fires Tech#loadstart + * + * @return {undefined} + * returns nothing. + */ + + + Html5.prototype.handleLateInit_ = function handleLateInit_(el) { + if (el.networkState === 0 || el.networkState === 3) { + // The video element hasn't started loading the source yet + // or didn't find a source + return; + } + + if (el.readyState === 0) { + // NetworkState is set synchronously BUT loadstart is fired at the + // end of the current stack, usually before setInterval(fn, 0). + // So at this point we know loadstart may have already fired or is + // about to fire, and either way the player hasn't seen it yet. + // We don't want to fire loadstart prematurely here and cause a + // double loadstart so we'll wait and see if it happens between now + // and the next loop, and fire it if not. + // HOWEVER, we also want to make sure it fires before loadedmetadata + // which could also happen between now and the next loop, so we'll + // watch for that also. + var loadstartFired = false; + var setLoadstartFired = function setLoadstartFired() { + loadstartFired = true; + }; + + this.on('loadstart', setLoadstartFired); + + var triggerLoadstart = function triggerLoadstart() { + // We did miss the original loadstart. Make sure the player + // sees loadstart before loadedmetadata + if (!loadstartFired) { + this.trigger('loadstart'); + } + }; + + this.on('loadedmetadata', triggerLoadstart); + + this.ready(function () { + this.off('loadstart', setLoadstartFired); + this.off('loadedmetadata', triggerLoadstart); + + if (!loadstartFired) { + // We did miss the original native loadstart. Fire it now. + this.trigger('loadstart'); + } + }); + + return; + } + + // From here on we know that loadstart already fired and we missed it. + // The other readyState events aren't as much of a problem if we double + // them, so not going to go to as much trouble as loadstart to prevent + // that unless we find reason to. + var eventsToTrigger = ['loadstart']; + + // loadedmetadata: newly equal to HAVE_METADATA (1) or greater + eventsToTrigger.push('loadedmetadata'); + + // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater + if (el.readyState >= 2) { + eventsToTrigger.push('loadeddata'); + } + + // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater + if (el.readyState >= 3) { + eventsToTrigger.push('canplay'); + } + + // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4) + if (el.readyState >= 4) { + eventsToTrigger.push('canplaythrough'); + } + + // We still need to give the player time to add event listeners + this.ready(function () { + eventsToTrigger.forEach(function (type) { + this.trigger(type); + }, this); + }); + }; + + /** + * Set current time for the `HTML5` tech. + * + * @param {number} seconds + * Set the current time of the media to this. + */ + + + Html5.prototype.setCurrentTime = function setCurrentTime(seconds) { + try { + this.el_.currentTime = seconds; + } catch (e) { + log$1(e, 'Video is not ready. (Video.js)'); + // this.warning(VideoJS.warnings.videoNotReady); + } + }; + + /** + * Get the current duration of the HTML5 media element. + * + * @return {number} + * The duration of the media or 0 if there is no duration. + */ + + + Html5.prototype.duration = function duration() { + var _this5 = this; + + // Android Chrome will report duration as Infinity for VOD HLS until after + // playback has started, which triggers the live display erroneously. + // Return NaN if playback has not started and trigger a durationupdate once + // the duration can be reliably known. + if (this.el_.duration === Infinity && IS_ANDROID && IS_CHROME && this.el_.currentTime === 0) { + // Wait for the first `timeupdate` with currentTime > 0 - there may be + // several with 0 + var checkProgress = function checkProgress() { + if (_this5.el_.currentTime > 0) { + // Trigger durationchange for genuinely live video + if (_this5.el_.duration === Infinity) { + _this5.trigger('durationchange'); + } + _this5.off('timeupdate', checkProgress); + } + }; + + this.on('timeupdate', checkProgress); + return NaN; + } + return this.el_.duration || NaN; + }; + + /** + * Get the current width of the HTML5 media element. + * + * @return {number} + * The width of the HTML5 media element. + */ + + + Html5.prototype.width = function width() { + return this.el_.offsetWidth; + }; + + /** + * Get the current height of the HTML5 media element. + * + * @return {number} + * The height of the HTML5 media element. + */ + + + Html5.prototype.height = function height() { + return this.el_.offsetHeight; + }; + + /** + * Proxy iOS `webkitbeginfullscreen` and `webkitendfullscreen` into + * `fullscreenchange` event. + * + * @private + * @fires fullscreenchange + * @listens webkitendfullscreen + * @listens webkitbeginfullscreen + * @listens webkitbeginfullscreen + */ + + + Html5.prototype.proxyWebkitFullscreen_ = function proxyWebkitFullscreen_() { + var _this6 = this; + + if (!('webkitDisplayingFullscreen' in this.el_)) { + return; + } + + var endFn = function endFn() { + this.trigger('fullscreenchange', {isFullscreen: false}); + }; + + var beginFn = function beginFn() { + if ('webkitPresentationMode' in this.el_ && this.el_.webkitPresentationMode !== 'picture-in-picture') { + this.one('webkitendfullscreen', endFn); + + this.trigger('fullscreenchange', {isFullscreen: true}); + } + }; + + this.on('webkitbeginfullscreen', beginFn); + this.on('dispose', function () { + _this6.off('webkitbeginfullscreen', beginFn); + _this6.off('webkitendfullscreen', endFn); + }); + }; + + /** + * Check if fullscreen is supported on the current playback device. + * + * @return {boolean} + * - True if fullscreen is supported. + * - False if fullscreen is not supported. + */ + + + Html5.prototype.supportsFullScreen = function supportsFullScreen() { + if (typeof this.el_.webkitEnterFullScreen === 'function') { + var userAgent = window_1.navigator && window_1.navigator.userAgent || ''; + + // Seems to be broken in Chromium/Chrome && Safari in Leopard + if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) { + return true; + } + } + return false; + }; + + /** + * Request that the `HTML5` Tech enter fullscreen. + */ + + + Html5.prototype.enterFullScreen = function enterFullScreen() { + var video = this.el_; + + if (video.paused && video.networkState <= video.HAVE_METADATA) { + // attempt to prime the video element for programmatic access + // this isn't necessary on the desktop but shouldn't hurt + this.el_.play(); + + // playing and pausing synchronously during the transition to fullscreen + // can get iOS ~6.1 devices into a playOld/pause loop + this.setTimeout(function () { + video.pause(); + video.webkitEnterFullScreen(); + }, 0); + } else { + video.webkitEnterFullScreen(); + } + }; + + /** + * Request that the `HTML5` Tech exit fullscreen. + */ + + + Html5.prototype.exitFullScreen = function exitFullScreen() { + this.el_.webkitExitFullScreen(); + }; + + /** + * A getter/setter for the `Html5` Tech's source object. + * > Note: Please use {@link Html5#setSource} + * + * @param {Tech~SourceObject} [src] + * The source object you want to set on the `HTML5` techs element. + * + * @return {Tech~SourceObject|undefined} + * - The current source object when a source is not passed in. + * - undefined when setting + * + * @deprecated Since version 5. + */ + + + Html5.prototype.src = function src(_src) { + if (_src === undefined) { + return this.el_.src; + } + + // Setting src through `src` instead of `setSrc` will be deprecated + this.setSrc(_src); + }; + + /** + * Reset the tech by removing all sources and then calling + * {@link Html5.resetMediaElement}. + */ + + + Html5.prototype.reset = function reset() { + Html5.resetMediaElement(this.el_); + }; + + /** + * Get the current source on the `HTML5` Tech. Falls back to returning the source from + * the HTML5 media element. + * + * @return {Tech~SourceObject} + * The current source object from the HTML5 tech. With a fallback to the + * elements source. + */ + + + Html5.prototype.currentSrc = function currentSrc() { + if (this.currentSource_) { + return this.currentSource_.src; + } + return this.el_.currentSrc; + }; + + /** + * Set controls attribute for the HTML5 media Element. + * + * @param {string} val + * Value to set the controls attribute to + */ + + + Html5.prototype.setControls = function setControls(val) { + this.el_.controls = !!val; + }; + + /** + * Create and returns a remote {@link TextTrack} object. + * + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track + * + * @param {string} [language] + * Two letter language abbreviation + * + * @return {TextTrack} + * The TextTrack that gets created. + */ + + + Html5.prototype.addTextTrack = function addTextTrack(kind, label, language) { + if (!this.featuresNativeTextTracks) { + return _Tech.prototype.addTextTrack.call(this, kind, label, language); + } + + return this.el_.addTextTrack(kind, label, language); + }; + + /** + * Creates either native TextTrack or an emulated TextTrack depending + * on the value of `featuresNativeTextTracks` + * + * @param {Object} options + * The object should contain the options to initialize the TextTrack with. + * + * @param {string} [options.kind] + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata). + * + * @param {string} [options.label] + * Label to identify the text track + * + * @param {string} [options.language] + * Two letter language abbreviation. + * + * @param {boolean} [options.default] + * Default this track to on. + * + * @param {string} [options.id] + * The internal id to assign this track. + * + * @param {string} [options.src] + * A source url for the track. + * + * @return {HTMLTrackElement} + * The track element that gets created. + */ + + + Html5.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) { + if (!this.featuresNativeTextTracks) { + return _Tech.prototype.createRemoteTextTrack.call(this, options); + } + var htmlTrackElement = document_1.createElement('track'); + + if (options.kind) { + htmlTrackElement.kind = options.kind; + } + if (options.label) { + htmlTrackElement.label = options.label; + } + if (options.language || options.srclang) { + htmlTrackElement.srclang = options.language || options.srclang; + } + if (options.default) { + htmlTrackElement.default = options.default; + } + if (options.id) { + htmlTrackElement.id = options.id; + } + if (options.src) { + htmlTrackElement.src = options.src; + } + + return htmlTrackElement; + }; + + /** + * Creates a remote text track object and returns an html track element. + * + * @param {Object} options The object should contain values for + * kind, language, label, and src (location of the WebVTT file) + * @param {Boolean} [manualCleanup=true] if set to false, the TextTrack will be + * automatically removed from the video element whenever the source changes + * @return {HTMLTrackElement} An Html Track Element. + * This can be an emulated {@link HTMLTrackElement} or a native one. + * @deprecated The default value of the "manualCleanup" parameter will default + * to "false" in upcoming versions of Video.js + */ + + + Html5.prototype.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) { + var htmlTrackElement = _Tech.prototype.addRemoteTextTrack.call(this, options, manualCleanup); + + if (this.featuresNativeTextTracks) { + this.el().appendChild(htmlTrackElement); + } + + return htmlTrackElement; + }; + + /** + * Remove remote `TextTrack` from `TextTrackList` object + * + * @param {TextTrack} track + * `TextTrack` object to remove + */ + + + Html5.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { + _Tech.prototype.removeRemoteTextTrack.call(this, track); + + if (this.featuresNativeTextTracks) { + var tracks = this.$$('track'); + + var i = tracks.length; + + while (i--) { + if (track === tracks[i] || track === tracks[i].track) { + this.el().removeChild(tracks[i]); + } + } + } + }; + + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} + * + * @return {Object} + * An object with supported media playback quality metrics + */ + + + Html5.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() { + if (typeof this.el().getVideoPlaybackQuality === 'function') { + return this.el().getVideoPlaybackQuality(); + } + + var videoPlaybackQuality = {}; + + if (typeof this.el().webkitDroppedFrameCount !== 'undefined' && typeof this.el().webkitDecodedFrameCount !== 'undefined') { + videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount; + videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount; + } + + if (window_1.performance && typeof window_1.performance.now === 'function') { + videoPlaybackQuality.creationTime = window_1.performance.now(); + } else if (window_1.performance && window_1.performance.timing && typeof window_1.performance.timing.navigationStart === 'number') { + videoPlaybackQuality.creationTime = window_1.Date.now() - window_1.performance.timing.navigationStart; + } + + return videoPlaybackQuality; + }; + + return Html5; + }(Tech); + + /* HTML5 Support Testing ---------------------------------------------------- */ + + if (isReal()) { + + /** + * Element for testing browser HTML5 media capabilities + * + * @type {Element} + * @constant + * @private + */ + Html5.TEST_VID = document_1.createElement('video'); + var track = document_1.createElement('track'); + + track.kind = 'captions'; + track.srclang = 'en'; + track.label = 'English'; + Html5.TEST_VID.appendChild(track); + } + + /** + * Check if HTML5 media is supported by this browser/device. + * + * @return {boolean} + * - True if HTML5 media is supported. + * - False if HTML5 media is not supported. + */ + Html5.isSupported = function () { + // IE with no Media Player is a LIAR! (#984) + try { + Html5.TEST_VID.volume = 0.5; + } catch (e) { + return false; + } + + return !!(Html5.TEST_VID && Html5.TEST_VID.canPlayType); + }; + + /** + * Check if the tech can support the given type + * + * @param {string} type + * The mimetype to check + * @return {string} 'probably', 'maybe', or '' (empty string) + */ + Html5.canPlayType = function (type) { + return Html5.TEST_VID.canPlayType(type); + }; + + /** + * Check if the tech can support the given source + * @param {Object} srcObj + * The source object + * @param {Object} options + * The options passed to the tech + * @return {string} 'probably', 'maybe', or '' (empty string) + */ + Html5.canPlaySource = function (srcObj, options) { + return Html5.canPlayType(srcObj.type); + }; + + /** + * Check if the volume can be changed in this browser/device. + * Volume cannot be changed in a lot of mobile devices. + * Specifically, it can't be changed from 1 on iOS. + * + * @return {boolean} + * - True if volume can be controlled + * - False otherwise + */ + Html5.canControlVolume = function () { + // IE will error if Windows Media Player not installed #3315 + try { + var volume = Html5.TEST_VID.volume; + + Html5.TEST_VID.volume = volume / 2 + 0.1; + return volume !== Html5.TEST_VID.volume; + } catch (e) { + return false; + } + }; + + /** + * Check if the playback rate can be changed in this browser/device. + * + * @return {boolean} + * - True if playback rate can be controlled + * - False otherwise + */ + Html5.canControlPlaybackRate = function () { + // Playback rate API is implemented in Android Chrome, but doesn't do anything + // https://github.com/videojs/video.js/issues/3180 + if (IS_ANDROID && IS_CHROME && CHROME_VERSION < 58) { + return false; + } + // IE will error if Windows Media Player not installed #3315 + try { + var playbackRate = Html5.TEST_VID.playbackRate; + + Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1; + return playbackRate !== Html5.TEST_VID.playbackRate; + } catch (e) { + return false; + } + }; + + /** + * Check if we can override a video/audio elements attributes, with + * Object.defineProperty. + * + * @return {boolean} + * - True if builtin attributes can be overridden + * - False otherwise + */ + Html5.canOverrideAttributes = function () { + // if we cannot overwrite the src/innerHTML property, there is no support + // iOS 7 safari for instance cannot do this. + try { + var noop = function noop() { + }; + + Object.defineProperty(document_1.createElement('video'), 'src', {get: noop, set: noop}); + Object.defineProperty(document_1.createElement('audio'), 'src', {get: noop, set: noop}); + Object.defineProperty(document_1.createElement('video'), 'innerHTML', {get: noop, set: noop}); + Object.defineProperty(document_1.createElement('audio'), 'innerHTML', {get: noop, set: noop}); + } catch (e) { + return false; + } + + return true; + }; + + /** + * Check to see if native `TextTrack`s are supported by this browser/device. + * + * @return {boolean} + * - True if native `TextTrack`s are supported. + * - False otherwise + */ + Html5.supportsNativeTextTracks = function () { + return IS_ANY_SAFARI; + }; + + /** + * Check to see if native `VideoTrack`s are supported by this browser/device + * + * @return {boolean} + * - True if native `VideoTrack`s are supported. + * - False otherwise + */ + Html5.supportsNativeVideoTracks = function () { + return !!(Html5.TEST_VID && Html5.TEST_VID.videoTracks); + }; + + /** + * Check to see if native `AudioTrack`s are supported by this browser/device + * + * @return {boolean} + * - True if native `AudioTrack`s are supported. + * - False otherwise + */ + Html5.supportsNativeAudioTracks = function () { + return !!(Html5.TEST_VID && Html5.TEST_VID.audioTracks); + }; + + /** + * An array of events available on the Html5 tech. + * + * @private + * @type {Array} + */ + Html5.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'resize', 'volumechange']; + + /** + * Boolean indicating whether the `Tech` supports volume control. + * + * @type {boolean} + * @default {@link Html5.canControlVolume} + */ + Html5.prototype.featuresVolumeControl = Html5.canControlVolume(); + + /** + * Boolean indicating whether the `Tech` supports changing the speed at which the media + * plays. Examples: + * - Set player to playOld 2x (twice) as fast + * - Set player to playOld 0.5x (half) as fast + * + * @type {boolean} + * @default {@link Html5.canControlPlaybackRate} + */ + Html5.prototype.featuresPlaybackRate = Html5.canControlPlaybackRate(); + + /** + * Boolean indicating whether the `Tech` supports the `sourceset` event. + * + * @type {boolean} + * @default + */ + Html5.prototype.featuresSourceset = Html5.canOverrideAttributes(); + + /** + * Boolean indicating whether the `HTML5` tech currently supports the media element + * moving in the DOM. iOS breaks if you move the media element, so this is set this to + * false there. Everywhere else this should be true. + * + * @type {boolean} + * @default + */ + Html5.prototype.movingMediaElementInDOM = !IS_IOS; + + // TODO: Previous comment: No longer appears to be used. Can probably be removed. + // Is this true? + /** + * Boolean indicating whether the `HTML5` tech currently supports automatic media resize + * when going into fullscreen. + * + * @type {boolean} + * @default + */ + Html5.prototype.featuresFullscreenResize = true; + + /** + * Boolean indicating whether the `HTML5` tech currently supports the progress event. + * If this is false, manual `progress` events will be triggered instead. + * + * @type {boolean} + * @default + */ + Html5.prototype.featuresProgressEvents = true; + + /** + * Boolean indicating whether the `HTML5` tech currently supports the timeupdate event. + * If this is false, manual `timeupdate` events will be triggered instead. + * + * @default + */ + Html5.prototype.featuresTimeupdateEvents = true; + + /** + * Boolean indicating whether the `HTML5` tech currently supports native `TextTrack`s. + * + * @type {boolean} + * @default {@link Html5.supportsNativeTextTracks} + */ + Html5.prototype.featuresNativeTextTracks = Html5.supportsNativeTextTracks(); + + /** + * Boolean indicating whether the `HTML5` tech currently supports native `VideoTrack`s. + * + * @type {boolean} + * @default {@link Html5.supportsNativeVideoTracks} + */ + Html5.prototype.featuresNativeVideoTracks = Html5.supportsNativeVideoTracks(); + + /** + * Boolean indicating whether the `HTML5` tech currently supports native `AudioTrack`s. + * + * @type {boolean} + * @default {@link Html5.supportsNativeAudioTracks} + */ + Html5.prototype.featuresNativeAudioTracks = Html5.supportsNativeAudioTracks(); + + // HTML5 Feature detection and Device Fixes --------------------------------- // + var canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType; + var mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; + + Html5.patchCanPlayType = function () { + + // Android 4.0 and above can playOld HLS to some extent but it reports being unable to do so + // Firefox and Chrome report correctly + if (ANDROID_VERSION >= 4.0 && !IS_FIREFOX && !IS_CHROME) { + Html5.TEST_VID.constructor.prototype.canPlayType = function (type) { + if (type && mpegurlRE.test(type)) { + return 'maybe'; + } + return canPlayType.call(this, type); + }; + } + }; + + Html5.unpatchCanPlayType = function () { + var r = Html5.TEST_VID.constructor.prototype.canPlayType; + + Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType; + return r; + }; + + // by default, patch the media element + Html5.patchCanPlayType(); + + Html5.disposeMediaElement = function (el) { + if (!el) { + return; + } + + if (el.parentNode) { + el.parentNode.removeChild(el); + } + + // remove any child track or source nodes to prevent their loading + while (el.hasChildNodes()) { + el.removeChild(el.firstChild); + } + + // remove any src reference. not setting `src=''` because that causes a warning + // in firefox + el.removeAttribute('src'); + + // force the media element to update its loading state by calling load() + // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793) + if (typeof el.load === 'function') { + // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) + (function () { + try { + el.load(); + } catch (e) { + // not supported + } + })(); + } + }; + + Html5.resetMediaElement = function (el) { + if (!el) { + return; + } + + var sources = el.querySelectorAll('source'); + var i = sources.length; + + while (i--) { + el.removeChild(sources[i]); + } + + // remove any src reference. + // not setting `src=''` because that throws an error + el.removeAttribute('src'); + + if (typeof el.load === 'function') { + // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) + (function () { + try { + el.load(); + } catch (e) { + // satisfy linter + } + })(); + } + }; + + /* Native HTML5 element property wrapping ----------------------------------- */ + // Wrap native boolean attributes with getters that check both property and attribute + // The list is as followed: + // muted, defaultMuted, autoplay, controls, loop, playsinline + [ + /** + * Get the value of `muted` from the media element. `muted` indicates + * that the volume for the media should be set to silent. This does not actually change + * the `volume` attribute. + * + * @method Html5#muted + * @return {boolean} + * - True if the value of `volume` should be ignored and the audio set to silent. + * - False if the value of `volume` should be used. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} + */ + 'muted', + + /** + * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates + * whether the media should start muted or not. Only changes the default state of the + * media. `muted` and `defaultMuted` can have different values. {@link Html5#muted} indicates the + * current state. + * + * @method Html5#defaultMuted + * @return {boolean} + * - The value of `defaultMuted` from the media element. + * - True indicates that the media should start muted. + * - False indicates that the media should not start muted + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} + */ + 'defaultMuted', + + /** + * Get the value of `autoplay` from the media element. `autoplay` indicates + * that the media should start to playOld as soon as the page is ready. + * + * @method Html5#autoplay + * @return {boolean} + * - The value of `autoplay` from the media element. + * - True indicates that the media should start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} + */ + 'autoplay', + + /** + * Get the value of `controls` from the media element. `controls` indicates + * whether the native media controls should be shown or hidden. + * + * @method Html5#controls + * @return {boolean} + * - The value of `controls` from the media element. + * - True indicates that native controls should be showing. + * - False indicates that native controls should be hidden. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls} + */ + 'controls', + + /** + * Get the value of `loop` from the media element. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Html5#loop + * @return {boolean} + * - The value of `loop` from the media element. + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} + */ + 'loop', + + /** + * Get the value of `playsinline` from the media element. `playsinline` indicates + * to the browser that non-fullscreen playback is preferred when fullscreen + * playback is the native default, such as in iOS Safari. + * + * @method Html5#playsinline + * @return {boolean} + * - The value of `playsinline` from the media element. + * - True indicates that the media should playOld inline. + * - False indicates that the media should not playOld inline. + * + * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} + */ + 'playsinline'].forEach(function (prop) { + Html5.prototype[prop] = function () { + return this.el_[prop] || this.el_.hasAttribute(prop); + }; + }); + + // Wrap native boolean attributes with setters that set both property and attribute + // The list is as followed: + // setMuted, setDefaultMuted, setAutoplay, setLoop, setPlaysinline + // setControls is special-cased above + [ + /** + * Set the value of `muted` on the media element. `muted` indicates that the current + * audio level should be silent. + * + * @method Html5#setMuted + * @param {boolean} muted + * - True if the audio should be set to silent + * - False otherwise + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} + */ + 'muted', + + /** + * Set the value of `defaultMuted` on the media element. `defaultMuted` indicates that the current + * audio level should be silent, but will only effect the muted level on intial playback.. + * + * @method Html5.prototype.setDefaultMuted + * @param {boolean} defaultMuted + * - True if the audio should be set to silent + * - False otherwise + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} + */ + 'defaultMuted', + + /** + * Set the value of `autoplay` on the media element. `autoplay` indicates + * that the media should start to playOld as soon as the page is ready. + * + * @method Html5#setAutoplay + * @param {boolean} autoplay + * - True indicates that the media should start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} + */ + 'autoplay', + + /** + * Set the value of `loop` on the media element. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Html5#setLoop + * @param {boolean} loop + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} + */ + 'loop', + + /** + * Set the value of `playsinline` from the media element. `playsinline` indicates + * to the browser that non-fullscreen playback is preferred when fullscreen + * playback is the native default, such as in iOS Safari. + * + * @method Html5#setPlaysinline + * @param {boolean} playsinline + * - True indicates that the media should playOld inline. + * - False indicates that the media should not playOld inline. + * + * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} + */ + 'playsinline'].forEach(function (prop) { + Html5.prototype['set' + toTitleCase(prop)] = function (v) { + this.el_[prop] = v; + + if (v) { + this.el_.setAttribute(prop, prop); + } else { + this.el_.removeAttribute(prop); + } + }; + }); + + // Wrap native properties with a getter + // The list is as followed + // paused, currentTime, buffered, volume, poster, preload, error, seeking + // seekable, ended, playbackRate, defaultPlaybackRate, played, networkState + // readyState, videoWidth, videoHeight + [ + /** + * Get the value of `paused` from the media element. `paused` indicates whether the media element + * is currently paused or not. + * + * @method Html5#paused + * @return {boolean} + * The value of `paused` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused} + */ + 'paused', + + /** + * Get the value of `currentTime` from the media element. `currentTime` indicates + * the current second that the media is at in playback. + * + * @method Html5#currentTime + * @return {number} + * The value of `currentTime` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime} + */ + 'currentTime', + + /** + * Get the value of `buffered` from the media element. `buffered` is a `TimeRange` + * object that represents the parts of the media that are already downloaded and + * available for playback. + * + * @method Html5#buffered + * @return {TimeRange} + * The value of `buffered` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered} + */ + 'buffered', + + /** + * Get the value of `volume` from the media element. `volume` indicates + * the current playback volume of audio for a media. `volume` will be a value from 0 + * (silent) to 1 (loudest and default). + * + * @method Html5#volume + * @return {number} + * The value of `volume` from the media element. Value will be between 0-1. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume} + */ + 'volume', + + /** + * Get the value of `poster` from the media element. `poster` indicates + * that the url of an image file that can/will be shown when no media data is available. + * + * @method Html5#poster + * @return {string} + * The value of `poster` from the media element. Value will be a url to an + * image. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster} + */ + 'poster', + + /** + * Get the value of `preload` from the media element. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Html5#preload + * @return {string} + * The value of `preload` from the media element. Will be 'none', 'metadata', + * or 'auto'. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload} + */ + 'preload', + + /** + * Get the value of the `error` from the media element. `error` indicates any + * MediaError that may have occurred during playback. If error returns null there is no + * current error. + * + * @method Html5#error + * @return {MediaError|null} + * The value of `error` from the media element. Will be `MediaError` if there + * is a current error and null otherwise. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error} + */ + 'error', + + /** + * Get the value of `seeking` from the media element. `seeking` indicates whether the + * media is currently seeking to a new position or not. + * + * @method Html5#seeking + * @return {boolean} + * - The value of `seeking` from the media element. + * - True indicates that the media is currently seeking to a new position. + * - False indicates that the media is not seeking to a new position at this time. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking} + */ + 'seeking', + + /** + * Get the value of `seekable` from the media element. `seekable` returns a + * `TimeRange` object indicating ranges of time that can currently be `seeked` to. + * + * @method Html5#seekable + * @return {TimeRange} + * The value of `seekable` from the media element. A `TimeRange` object + * indicating the current ranges of time that can be seeked to. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable} + */ + 'seekable', + + /** + * Get the value of `ended` from the media element. `ended` indicates whether + * the media has reached the end or not. + * + * @method Html5#ended + * @return {boolean} + * - The value of `ended` from the media element. + * - True indicates that the media has ended. + * - False indicates that the media has not ended. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended} + */ + 'ended', + + /** + * Get the value of `playbackRate` from the media element. `playbackRate` indicates + * the rate at which the media is currently playing back. Examples: + * - if playbackRate is set to 2, media will playOld twice as fast. + * - if playbackRate is set to 0.5, media will playOld half as fast. + * + * @method Html5#playbackRate + * @return {number} + * The value of `playbackRate` from the media element. A number indicating + * the current playback speed of the media, where 1 is normal speed. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate} + */ + 'playbackRate', + + /** + * Get the value of `defaultPlaybackRate` from the media element. `defaultPlaybackRate` indicates + * the rate at which the media is currently playing back. This value will not indicate the current + * `playbackRate` after playback has started, use {@link Html5#playbackRate} for that. + * + * Examples: + * - if defaultPlaybackRate is set to 2, media will playOld twice as fast. + * - if defaultPlaybackRate is set to 0.5, media will playOld half as fast. + * + * @method Html5.prototype.defaultPlaybackRate + * @return {number} + * The value of `defaultPlaybackRate` from the media element. A number indicating + * the current playback speed of the media, where 1 is normal speed. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate} + */ + 'defaultPlaybackRate', + + /** + * Get the value of `played` from the media element. `played` returns a `TimeRange` + * object representing points in the media timeline that have been played. + * + * @method Html5#played + * @return {TimeRange} + * The value of `played` from the media element. A `TimeRange` object indicating + * the ranges of time that have been played. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played} + */ + 'played', + + /** + * Get the value of `networkState` from the media element. `networkState` indicates + * the current network state. It returns an enumeration from the following list: + * - 0: NETWORK_EMPTY + * - 1: NETWORK_IDLE + * - 2: NETWORK_LOADING + * - 3: NETWORK_NO_SOURCE + * + * @method Html5#networkState + * @return {number} + * The value of `networkState` from the media element. This will be a number + * from the list in the description. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate} + */ + 'networkState', + + /** + * Get the value of `readyState` from the media element. `readyState` indicates + * the current state of the media element. It returns an enumeration from the + * following list: + * - 0: HAVE_NOTHING + * - 1: HAVE_METADATA + * - 2: HAVE_CURRENT_DATA + * - 3: HAVE_FUTURE_DATA + * - 4: HAVE_ENOUGH_DATA + * + * @method Html5#readyState + * @return {number} + * The value of `readyState` from the media element. This will be a number + * from the list in the description. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states} + */ + 'readyState', + + /** + * Get the value of `videoWidth` from the video element. `videoWidth` indicates + * the current width of the video in css pixels. + * + * @method Html5#videoWidth + * @return {number} + * The value of `videoWidth` from the video element. This will be a number + * in css pixels. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth} + */ + 'videoWidth', + + /** + * Get the value of `videoHeight` from the video element. `videoHeight` indicates + * the current height of the video in css pixels. + * + * @method Html5#videoHeight + * @return {number} + * The value of `videoHeight` from the video element. This will be a number + * in css pixels. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth} + */ + 'videoHeight'].forEach(function (prop) { + Html5.prototype[prop] = function () { + return this.el_[prop]; + }; + }); + + // Wrap native properties with a setter in this format: + // set + toTitleCase(name) + // The list is as follows: + // setVolume, setSrc, setPoster, setPreload, setPlaybackRate, setDefaultPlaybackRate + [ + /** + * Set the value of `volume` on the media element. `volume` indicates the current + * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and + * so on. + * + * @method Html5#setVolume + * @param {number} percentAsDecimal + * The volume percent as a decimal. Valid range is from 0-1. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume} + */ + 'volume', + + /** + * Set the value of `src` on the media element. `src` indicates the current + * {@link Tech~SourceObject} for the media. + * + * @method Html5#setSrc + * @param {Tech~SourceObject} src + * The source object to set as the current source. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src} + */ + 'src', + + /** + * Set the value of `poster` on the media element. `poster` is the url to + * an image file that can/will be shown when no media data is available. + * + * @method Html5#setPoster + * @param {string} poster + * The url to an image that should be used as the `poster` for the media + * element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster} + */ + 'poster', + + /** + * Set the value of `preload` on the media element. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Html5#setPreload + * @param {string} preload + * The value of `preload` to set on the media element. Must be 'none', 'metadata', + * or 'auto'. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload} + */ + 'preload', + + /** + * Set the value of `playbackRate` on the media element. `playbackRate` indicates + * the rate at which the media should playOld back. Examples: + * - if playbackRate is set to 2, media will playOld twice as fast. + * - if playbackRate is set to 0.5, media will playOld half as fast. + * + * @method Html5#setPlaybackRate + * @return {number} + * The value of `playbackRate` from the media element. A number indicating + * the current playback speed of the media, where 1 is normal speed. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate} + */ + 'playbackRate', + + /** + * Set the value of `defaultPlaybackRate` on the media element. `defaultPlaybackRate` indicates + * the rate at which the media should playOld back upon initial startup. Changing this value + * after a video has started will do nothing. Instead you should used {@link Html5#setPlaybackRate}. + * + * Example Values: + * - if playbackRate is set to 2, media will playOld twice as fast. + * - if playbackRate is set to 0.5, media will playOld half as fast. + * + * @method Html5.prototype.setDefaultPlaybackRate + * @return {number} + * The value of `defaultPlaybackRate` from the media element. A number indicating + * the current playback speed of the media, where 1 is normal speed. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultplaybackrate} + */ + 'defaultPlaybackRate'].forEach(function (prop) { + Html5.prototype['set' + toTitleCase(prop)] = function (v) { + this.el_[prop] = v; + }; + }); + + // wrap native functions with a function + // The list is as follows: + // pause, load, playOld + [ + /** + * A wrapper around the media elements `pause` function. This will call the `HTML5` + * media elements `pause` function. + * + * @method Html5#pause + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause} + */ + 'pause', + + /** + * A wrapper around the media elements `load` function. This will call the `HTML5`s + * media element `load` function. + * + * @method Html5#load + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load} + */ + 'load', + + /** + * A wrapper around the media elements `playOld` function. This will call the `HTML5`s + * media element `playOld` function. + * + * @method Html5#playOld + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-play} + */ + 'play'].forEach(function (prop) { + Html5.prototype[prop] = function () { + return this.el_[prop](); + }; + }); + + Tech.withSourceHandlers(Html5); + + /** + * Native source handler for Html5, simply passes the source to the media element. + * + * @property {Tech~SourceObject} source + * The source object + * + * @property {Html5} tech + * The instance of the HTML5 tech. + */ + Html5.nativeSourceHandler = {}; + + /** + * Check if the media element can playOld the given mime type. + * + * @param {string} type + * The mimetype to check + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) + */ + Html5.nativeSourceHandler.canPlayType = function (type) { + // IE without MediaPlayer throws an error (#519) + try { + return Html5.TEST_VID.canPlayType(type); + } catch (e) { + return ''; + } + }; + + /** + * Check if the media element can handle a source natively. + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Object} [options] + * Options to be passed to the tech. + * + * @return {string} + * 'probably', 'maybe', or '' (empty string). + */ + Html5.nativeSourceHandler.canHandleSource = function (source, options) { + + // If a type was provided we should rely on that + if (source.type) { + return Html5.nativeSourceHandler.canPlayType(source.type); + + // If no type, fall back to checking 'video/[EXTENSION]' + } else if (source.src) { + var ext = getFileExtension(source.src); + + return Html5.nativeSourceHandler.canPlayType('video/' + ext); + } + + return ''; + }; + + /** + * Pass the source to the native media element. + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Html5} tech + * The instance of the Html5 tech + * + * @param {Object} [options] + * The options to pass to the source + */ + Html5.nativeSourceHandler.handleSource = function (source, tech, options) { + tech.setSrc(source.src); + }; + + /** + * A noop for the native dispose function, as cleanup is not needed. + */ + Html5.nativeSourceHandler.dispose = function () { + }; + + // Register the native source handler + Html5.registerSourceHandler(Html5.nativeSourceHandler); + + Tech.registerTech('Html5', Html5); + + var _templateObject$2 = taggedTemplateLiteralLoose(['\n Using the tech directly can be dangerous. I hope you know what you\'re doing.\n See https://github.com/videojs/video.js/issues/2617 for more info.\n '], ['\n Using the tech directly can be dangerous. I hope you know what you\'re doing.\n See https://github.com/videojs/video.js/issues/2617 for more info.\n ']); + + // The following tech events are simply re-triggered + // on the player when they happen + var TECH_EVENTS_RETRIGGER = [ + /** + * Fired while the user agent is downloading media data. + * + * @event Player#progress + * @type {EventTarget~Event} + */ + /** + * Retrigger the `progress` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechProgress_ + * @fires Player#progress + * @listens Tech#progress + */ + 'progress', + + /** + * Fires when the loading of an audio/video is aborted. + * + * @event Player#abort + * @type {EventTarget~Event} + */ + /** + * Retrigger the `abort` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechAbort_ + * @fires Player#abort + * @listens Tech#abort + */ + 'abort', + + /** + * Fires when the browser is intentionally not getting media data. + * + * @event Player#suspend + * @type {EventTarget~Event} + */ + /** + * Retrigger the `suspend` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechSuspend_ + * @fires Player#suspend + * @listens Tech#suspend + */ + 'suspend', + + /** + * Fires when the current playlist is empty. + * + * @event Player#emptied + * @type {EventTarget~Event} + */ + /** + * Retrigger the `emptied` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechEmptied_ + * @fires Player#emptied + * @listens Tech#emptied + */ + 'emptied', + /** + * Fires when the browser is trying to get media data, but data is not available. + * + * @event Player#stalled + * @type {EventTarget~Event} + */ + /** + * Retrigger the `stalled` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechStalled_ + * @fires Player#stalled + * @listens Tech#stalled + */ + 'stalled', + + /** + * Fires when the browser has loaded meta data for the audio/video. + * + * @event Player#loadedmetadata + * @type {EventTarget~Event} + */ + /** + * Retrigger the `stalled` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechLoadedmetadata_ + * @fires Player#loadedmetadata + * @listens Tech#loadedmetadata + */ + 'loadedmetadata', + + /** + * Fires when the browser has loaded the current frame of the audio/video. + * + * @event Player#loadeddata + * @type {event} + */ + /** + * Retrigger the `loadeddata` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechLoaddeddata_ + * @fires Player#loadeddata + * @listens Tech#loadeddata + */ + 'loadeddata', + + /** + * Fires when the current playback position has changed. + * + * @event Player#timeupdate + * @type {event} + */ + /** + * Retrigger the `timeupdate` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechTimeUpdate_ + * @fires Player#timeupdate + * @listens Tech#timeupdate + */ + 'timeupdate', + + /** + * Fires when the video's intrinsic dimensions change + * + * @event Player#resize + * @type {event} + */ + /** + * Retrigger the `resize` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechResize_ + * @fires Player#resize + * @listens Tech#resize + */ + 'resize', + + /** + * Fires when the volume has been changed + * + * @event Player#volumechange + * @type {event} + */ + /** + * Retrigger the `volumechange` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechVolumechange_ + * @fires Player#volumechange + * @listens Tech#volumechange + */ + 'volumechange', + + /** + * Fires when the text track has been changed + * + * @event Player#texttrackchange + * @type {event} + */ + /** + * Retrigger the `texttrackchange` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechTexttrackchange_ + * @fires Player#texttrackchange + * @listens Tech#texttrackchange + */ + 'texttrackchange']; + + // events to queue when playback rate is zero + // this is a hash for the sole purpose of mapping non-camel-cased event names + // to camel-cased function names + var TECH_EVENTS_QUEUE = { + canplay: 'CanPlay', + canplaythrough: 'CanPlayThrough', + playing: 'Playing', + seeked: 'Seeked' + }; + + /** + * An instance of the `Player` class is created when any of the Video.js setup methods + * are used to initialize a video. + * + * After an instance has been created it can be accessed globally in two ways: + * 1. By calling `videojs('example_video_1');` + * 2. By using it directly via `videojs.players.example_video_1;` + * + * @extends Component + */ + + var Player = function (_Component) { + inherits(Player, _Component); + + /** + * Create an instance of this class. + * + * @param {Element} tag + * The original video DOM element used for configuring options. + * + * @param {Object} [options] + * Object of option names and values. + * + * @param {Component~ReadyCallback} [ready] + * Ready callback function. + */ + function Player(tag, options, ready) { + classCallCheck(this, Player); + + // Make sure tag ID exists + tag.id = tag.id || options.id || 'vjs_video_' + newGUID(); + + // Set Options + // The options argument overrides options set in the video tag + // which overrides globally set options. + // This latter part coincides with the load order + // (tag must exist before Player) + options = assign(Player.getTagSettings(tag), options); + + // Delay the initialization of children because we need to set up + // player properties first, and can't use `this` before `super()` + options.initChildren = false; + + // Same with creating the element + options.createEl = false; + + // don't auto mixin the evented mixin + options.evented = false; + + // we don't want the player to report touch activity on itself + // see enableTouchActivity in Component + options.reportTouchActivity = false; + + // If language is not set, get the closest lang attribute + if (!options.language) { + if (typeof tag.closest === 'function') { + var closest = tag.closest('[lang]'); + + if (closest && closest.getAttribute) { + options.language = closest.getAttribute('lang'); + } + } else { + var element = tag; + + while (element && element.nodeType === 1) { + if (getAttributes(element).hasOwnProperty('lang')) { + options.language = element.getAttribute('lang'); + break; + } + element = element.parentNode; + } + } + } + + // Run base component initializing with new options + + // Tracks when a tech changes the poster + var _this = possibleConstructorReturn(this, _Component.call(this, null, options, ready)); + + _this.isPosterFromTech_ = false; + + // Holds callback info that gets queued when playback rate is zero + // and a seek is happening + _this.queuedCallbacks_ = []; + + // Turn off API access because we're loading a new tech that might load asynchronously + _this.isReady_ = false; + + // Init state hasStarted_ + _this.hasStarted_ = false; + + // Init state userActive_ + _this.userActive_ = false; + + // if the global option object was accidentally blown away by + // someone, bail early with an informative error + if (!_this.options_ || !_this.options_.techOrder || !_this.options_.techOrder.length) { + throw new Error('No techOrder specified. Did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?'); + } + + // Store the original tag used to set options + _this.tag = tag; + + // Store the tag attributes used to restore html5 element + _this.tagAttributes = tag && getAttributes(tag); + + // Update current language + _this.language(_this.options_.language); + + // Update Supported Languages + if (options.languages) { + // Normalise player option languages to lowercase + var languagesToLower = {}; + + Object.getOwnPropertyNames(options.languages).forEach(function (name$$1) { + languagesToLower[name$$1.toLowerCase()] = options.languages[name$$1]; + }); + _this.languages_ = languagesToLower; + } else { + _this.languages_ = Player.prototype.options_.languages; + } + + // Cache for video property values. + _this.cache_ = {}; + + // Set poster + _this.poster_ = options.poster || ''; + + // Set controls + _this.controls_ = !!options.controls; + + // Set default values for lastVolume + _this.cache_.lastVolume = 1; + + // Original tag settings stored in options + // now remove immediately so native controls don't flash. + // May be turned back on by HTML5 tech if nativeControlsForTouch is true + tag.controls = false; + tag.removeAttribute('controls'); + + /* + * Store the internal state of scrubbing + * + * @private + * @return {Boolean} True if the user is scrubbing + */ + _this.scrubbing_ = false; + + _this.el_ = _this.createEl(); + + // Set default value for lastPlaybackRate + _this.cache_.lastPlaybackRate = _this.defaultPlaybackRate(); + + // Make this an evented object and use `el_` as its event bus. + evented(_this, {eventBusKey: 'el_'}); + + // We also want to pass the original player options to each component and plugin + // as well so they don't need to reach back into the player for options later. + // We also need to do another copy of this.options_ so we don't end up with + // an infinite loop. + var playerOptionsCopy = mergeOptions(_this.options_); + + // Load plugins + if (options.plugins) { + var plugins = options.plugins; + + Object.keys(plugins).forEach(function (name$$1) { + if (typeof this[name$$1] === 'function') { + this[name$$1](plugins[name$$1]); + } else { + throw new Error('plugin "' + name$$1 + '" does not exist'); + } + }, _this); + } + + _this.options_.playerOptions = playerOptionsCopy; + + _this.middleware_ = []; + + _this.initChildren(); + + // Set isAudio based on whether or not an audio tag was used + _this.isAudio(tag.nodeName.toLowerCase() === 'audio'); + + // Update controls className. Can't do this when the controls are initially + // set because the element doesn't exist yet. + if (_this.controls()) { + _this.addClass('vjs-controls-enabled'); + } else { + _this.addClass('vjs-controls-disabled'); + } + + // Set ARIA label and region role depending on player type + _this.el_.setAttribute('role', 'region'); + if (_this.isAudio()) { + _this.el_.setAttribute('aria-label', _this.localize('Audio Player')); + } else { + _this.el_.setAttribute('aria-label', _this.localize('Video Player')); + } + + if (_this.isAudio()) { + _this.addClass('vjs-audio'); + } + + if (_this.flexNotSupported_()) { + _this.addClass('vjs-no-flex'); + } + + // TODO: Make this smarter. Toggle user state between touching/mousing + // using events, since devices can have both touch and mouse events. + // if (browser.TOUCH_ENABLED) { + // this.addClass('vjs-touch-enabled'); + // } + + // iOS Safari has broken hover handling + if (!IS_IOS) { + _this.addClass('vjs-workinghover'); + } + + // Make player easily findable by ID + Player.players[_this.id_] = _this; + + // Add a major version class to aid css in plugins + var majorVersion = version.split('.')[0]; + + _this.addClass('vjs-v' + majorVersion); + + // When the player is first initialized, trigger activity so components + // like the control bar show themselves if needed + _this.userActive(true); + _this.reportUserActivity(); + + _this.one('play', _this.listenForUserActivity_); + _this.on('fullscreenchange', _this.handleFullscreenChange_); + _this.on('stageclick', _this.handleStageClick_); + + _this.changingSrc_ = false; + _this.playWaitingForReady_ = false; + _this.playOnLoadstart_ = null; + return _this; + } + + /** + * Destroys the video player and does any necessary cleanup. + * + * This is especially helpful if you are dynamically adding and removing videos + * to/from the DOM. + * + * @fires Player#dispose + */ + + + Player.prototype.dispose = function dispose() { + /** + * Called when the player is being disposed of. + * + * @event Player#dispose + * @type {EventTarget~Event} + */ + this.trigger('dispose'); + // prevent dispose from being called twice + this.off('dispose'); + + if (this.styleEl_ && this.styleEl_.parentNode) { + this.styleEl_.parentNode.removeChild(this.styleEl_); + this.styleEl_ = null; + } + + // Kill reference to this player + Player.players[this.id_] = null; + + if (this.tag && this.tag.player) { + this.tag.player = null; + } + + if (this.el_ && this.el_.player) { + this.el_.player = null; + } + + if (this.tech_) { + this.tech_.dispose(); + this.isPosterFromTech_ = false; + this.poster_ = ''; + } + + if (this.playerElIngest_) { + this.playerElIngest_ = null; + } + + if (this.tag) { + this.tag = null; + } + + clearCacheForPlayer(this); + + // the actual .el_ is removed here + _Component.prototype.dispose.call(this); + }; + + /** + * Create the `Player`'s DOM element. + * + * @return {Element} + * The DOM element that gets created. + */ + + + Player.prototype.createEl = function createEl$$1() { + var tag = this.tag; + var el = void 0; + var playerElIngest = this.playerElIngest_ = tag.parentNode && tag.parentNode.hasAttribute && tag.parentNode.hasAttribute('data-vjs-player'); + var divEmbed = this.tag.tagName.toLowerCase() === 'video-js'; + + if (playerElIngest) { + el = this.el_ = tag.parentNode; + } else if (!divEmbed) { + el = this.el_ = _Component.prototype.createEl.call(this, 'div'); + } + + // Copy over all the attributes from the tag, including ID and class + // ID will now reference player box, not the video tag + var attrs = getAttributes(tag); + + if (divEmbed) { + el = this.el_ = tag; + tag = this.tag = document_1.createElement('video'); + while (el.children.length) { + tag.appendChild(el.firstChild); + } + + if (!hasClass(el, 'video-js')) { + addClass(el, 'video-js'); + } + + el.appendChild(tag); + + playerElIngest = this.playerElIngest_ = el; + // move properties over from our custom `video-js` element + // to our new `video` element. This will move things like + // `src` or `controls` that were set via js before the player + // was initialized. + Object.keys(el).forEach(function (k) { + tag[k] = el[k]; + }); + } + + // set tabindex to -1 so we could focus on the player element + tag.setAttribute('tabindex', '-1'); + + // Remove width/height attrs from tag so CSS can make it 100% width/height + tag.removeAttribute('width'); + tag.removeAttribute('height'); + + Object.getOwnPropertyNames(attrs).forEach(function (attr) { + el.setAttribute(attr, attrs[attr]); + + if (divEmbed) { + tag.setAttribute(attr, attrs[attr]); + } + }); + + // Update tag id/class for use as HTML5 playback tech + // Might think we should do this after embedding in container so .vjs-tech class + // doesn't flash 100% width/height, but class only applies with .video-js parent + tag.playerId = tag.id; + tag.id += '_html5_api'; + tag.className = 'vjs-tech'; + + // Make player findable on elements + tag.player = el.player = this; + // Default state of video is paused + this.addClass('vjs-paused'); + + // Add a style element in the player that we'll use to set the width/height + // of the player in a way that's still overrideable by CSS, just like the + // video element + if (window_1.VIDEOJS_NO_DYNAMIC_STYLE !== true) { + this.styleEl_ = createStyleElement('vjs-styles-dimensions'); + var defaultsStyleEl = $('.vjs-styles-defaults'); + var head = $('head'); + + head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild); + } + + // Pass in the width/height/aspectRatio options which will update the style el + this.width(this.options_.width); + this.height(this.options_.height); + this.fluid(this.options_.fluid); + this.aspectRatio(this.options_.aspectRatio); + + // Hide any links within the video/audio tag, + // because IE doesn't hide them completely from screen readers. + var links = tag.getElementsByTagName('a'); + + for (var i = 0; i < links.length; i++) { + var linkEl = links.item(i); + + addClass(linkEl, 'vjs-hidden'); + linkEl.setAttribute('hidden', 'hidden'); + } + + // insertElFirst seems to cause the networkState to flicker from 3 to 2, so + // keep track of the original for later so we can know if the source originally failed + tag.initNetworkState_ = tag.networkState; + + // Wrap video tag in div (el/box) container + if (tag.parentNode && !playerElIngest) { + tag.parentNode.insertBefore(el, tag); + } + + // insert the tag as the first child of the player element + // then manually add it to the children array so that this.addChild + // will work properly for other components + // + // Breaks iPhone, fixed in HTML5 setup. + prependTo(tag, el); + this.children_.unshift(tag); + + // Set lang attr on player to ensure CSS :lang() in consistent with player + // if it's been set to something different to the doc + this.el_.setAttribute('lang', this.language_); + + this.el_ = el; + + return el; + }; + + /** + * A getter/setter for the `Player`'s width. Returns the player's configured value. + * To get the current width use `currentWidth()`. + * + * @param {number} [value] + * The value to set the `Player`'s width to. + * + * @return {number} + * The current width of the `Player` when getting. + */ + + + Player.prototype.width = function width(value) { + return this.dimension('width', value); + }; + + /** + * A getter/setter for the `Player`'s height. Returns the player's configured value. + * To get the current height use `currentheight()`. + * + * @param {number} [value] + * The value to set the `Player`'s heigth to. + * + * @return {number} + * The current height of the `Player` when getting. + */ + + + Player.prototype.height = function height(value) { + return this.dimension('height', value); + }; + + /** + * A getter/setter for the `Player`'s width & height. + * + * @param {string} dimension + * This string can be: + * - 'width' + * - 'height' + * + * @param {number} [value] + * Value for dimension specified in the first argument. + * + * @return {number} + * The dimension arguments value when getting (width/height). + */ + + + Player.prototype.dimension = function dimension(_dimension, value) { + var privDimension = _dimension + '_'; + + if (value === undefined) { + return this[privDimension] || 0; + } + + if (value === '') { + // If an empty string is given, reset the dimension to be automatic + this[privDimension] = undefined; + this.updateStyleEl_(); + return; + } + + var parsedVal = parseFloat(value); + + if (isNaN(parsedVal)) { + log$1.error('Improper value "' + value + '" supplied for for ' + _dimension); + return; + } + + this[privDimension] = parsedVal; + this.updateStyleEl_(); + }; + + /** + * A getter/setter/toggler for the vjs-fluid `className` on the `Player`. + * + * @param {boolean} [bool] + * - A value of true adds the class. + * - A value of false removes the class. + * - No value will toggle the fluid class. + * + * @return {boolean|undefined} + * - The value of fluid when getting. + * - `undefined` when setting. + */ + + + Player.prototype.fluid = function fluid(bool) { + if (bool === undefined) { + return !!this.fluid_; + } + + this.fluid_ = !!bool; + + if (bool) { + this.addClass('vjs-fluid'); + } else { + this.removeClass('vjs-fluid'); + } + + this.updateStyleEl_(); + }; + + /** + * Get/Set the aspect ratio + * + * @param {string} [ratio] + * Aspect ratio for player + * + * @return {string|undefined} + * returns the current aspect ratio when getting + */ + + /** + * A getter/setter for the `Player`'s aspect ratio. + * + * @param {string} [ratio] + * The value to set the `Player's aspect ratio to. + * + * @return {string|undefined} + * - The current aspect ratio of the `Player` when getting. + * - undefined when setting + */ + + + Player.prototype.aspectRatio = function aspectRatio(ratio) { + if (ratio === undefined) { + return this.aspectRatio_; + } + + // Check for width:height format + if (!/^\d+\:\d+$/.test(ratio)) { + throw new Error('Improper value supplied for aspect ratio. The format should be width:height, for example 16:9.'); + } + this.aspectRatio_ = ratio; + + // We're assuming if you set an aspect ratio you want fluid mode, + // because in fixed mode you could calculate width and height yourself. + this.fluid(true); + + this.updateStyleEl_(); + }; + + /** + * Update styles of the `Player` element (height, width and aspect ratio). + * + * @private + * @listens Tech#loadedmetadata + */ + + + Player.prototype.updateStyleEl_ = function updateStyleEl_() { + if (window_1.VIDEOJS_NO_DYNAMIC_STYLE === true) { + var _width = typeof this.width_ === 'number' ? this.width_ : this.options_.width; + var _height = typeof this.height_ === 'number' ? this.height_ : this.options_.height; + var techEl = this.tech_ && this.tech_.el(); + + if (techEl) { + if (_width >= 0) { + techEl.width = _width; + } + if (_height >= 0) { + techEl.height = _height; + } + } + + return; + } + + var width = void 0; + var height = void 0; + var aspectRatio = void 0; + var idClass = void 0; + + // The aspect ratio is either used directly or to calculate width and height. + if (this.aspectRatio_ !== undefined && this.aspectRatio_ !== 'auto') { + // Use any aspectRatio that's been specifically set + aspectRatio = this.aspectRatio_; + } else if (this.videoWidth() > 0) { + // Otherwise try to get the aspect ratio from the video metadata + aspectRatio = this.videoWidth() + ':' + this.videoHeight(); + } else { + // Or use a default. The video element's is 2:1, but 16:9 is more common. + aspectRatio = '16:9'; + } + + // Get the ratio as a decimal we can use to calculate dimensions + var ratioParts = aspectRatio.split(':'); + var ratioMultiplier = ratioParts[1] / ratioParts[0]; + + if (this.width_ !== undefined) { + // Use any width that's been specifically set + width = this.width_; + } else if (this.height_ !== undefined) { + // Or calulate the width from the aspect ratio if a height has been set + width = this.height_ / ratioMultiplier; + } else { + // Or use the video's metadata, or use the video el's default of 300 + width = this.videoWidth() || 300; + } + + if (this.height_ !== undefined) { + // Use any height that's been specifically set + height = this.height_; + } else { + // Otherwise calculate the height from the ratio and the width + height = width * ratioMultiplier; + } + + // Ensure the CSS class is valid by starting with an alpha character + if (/^[^a-zA-Z]/.test(this.id())) { + idClass = 'dimensions-' + this.id(); + } else { + idClass = this.id() + '-dimensions'; + } + + // Ensure the right class is still on the player for the style element + this.addClass(idClass); + + setTextContent(this.styleEl_, '\n .' + idClass + ' {\n width: ' + width + 'px;\n height: ' + height + 'px;\n }\n\n .' + idClass + '.vjs-fluid {\n padding-top: ' + ratioMultiplier * 100 + '%;\n }\n '); + }; + + /** + * Load/Create an instance of playback {@link Tech} including element + * and API methods. Then append the `Tech` element in `Player` as a child. + * + * @param {string} techName + * name of the playback technology + * + * @param {string} source + * video source + * + * @private + */ + + + Player.prototype.loadTech_ = function loadTech_(techName, source) { + var _this2 = this; + + // Pause and remove current playback technology + if (this.tech_) { + this.unloadTech_(); + } + + var titleTechName = toTitleCase(techName); + var camelTechName = techName.charAt(0).toLowerCase() + techName.slice(1); + + // get rid of the HTML5 video tag as soon as we are using another tech + if (titleTechName !== 'Html5' && this.tag) { + Tech.getTech('Html5').disposeMediaElement(this.tag); + this.tag.player = null; + this.tag = null; + } + + this.techName_ = titleTechName; + + // Turn off API access because we're loading a new tech that might load asynchronously + this.isReady_ = false; + + // Grab tech-specific options from player options and add source and parent element to use. + var techOptions = { + source: source, + 'nativeControlsForTouch': this.options_.nativeControlsForTouch, + 'playerId': this.id(), + 'techId': this.id() + '_' + titleTechName + '_api', + 'autoplay': this.options_.autoplay, + 'playsinline': this.options_.playsinline, + 'preload': this.options_.preload, + 'loop': this.options_.loop, + 'muted': this.options_.muted, + 'poster': this.poster(), + 'language': this.language(), + 'playerElIngest': this.playerElIngest_ || false, + 'vtt.js': this.options_['vtt.js'], + 'canOverridePoster': !!this.options_.techCanOverridePoster, + 'enableSourceset': this.options_.enableSourceset + }; + + ALL.names.forEach(function (name$$1) { + var props = ALL[name$$1]; + + techOptions[props.getterName] = _this2[props.privateName]; + }); + + assign(techOptions, this.options_[titleTechName]); + assign(techOptions, this.options_[camelTechName]); + assign(techOptions, this.options_[techName.toLowerCase()]); + + if (this.tag) { + techOptions.tag = this.tag; + } + + if (source && source.src === this.cache_.src && this.cache_.currentTime > 0) { + techOptions.startTime = this.cache_.currentTime; + } + + // Initialize tech instance + var TechClass = Tech.getTech(techName); + + if (!TechClass) { + throw new Error('No Tech named \'' + titleTechName + '\' exists! \'' + titleTechName + '\' should be registered using videojs.registerTech()\''); + } + + this.tech_ = new TechClass(techOptions); + + // player.triggerReady is always async, so don't need this to be async + this.tech_.ready(bind(this, this.handleTechReady_), true); + + textTrackConverter.jsonToTextTracks(this.textTracksJson_ || [], this.tech_); + + // Listen to all HTML5-defined events and trigger them on the player + TECH_EVENTS_RETRIGGER.forEach(function (event) { + _this2.on(_this2.tech_, event, _this2['handleTech' + toTitleCase(event) + '_']); + }); + + Object.keys(TECH_EVENTS_QUEUE).forEach(function (event) { + _this2.on(_this2.tech_, event, function (eventObj) { + if (_this2.tech_.playbackRate() === 0 && _this2.tech_.seeking()) { + _this2.queuedCallbacks_.push({ + callback: _this2['handleTech' + TECH_EVENTS_QUEUE[event] + '_'].bind(_this2), + event: eventObj + }); + return; + } + _this2['handleTech' + TECH_EVENTS_QUEUE[event] + '_'](eventObj); + }); + }); + + this.on(this.tech_, 'loadstart', this.handleTechLoadStart_); + this.on(this.tech_, 'sourceset', this.handleTechSourceset_); + this.on(this.tech_, 'waiting', this.handleTechWaiting_); + this.on(this.tech_, 'ended', this.handleTechEnded_); + this.on(this.tech_, 'seeking', this.handleTechSeeking_); + this.on(this.tech_, 'play', this.handleTechPlay_); + this.on(this.tech_, 'firstplay', this.handleTechFirstPlay_); + this.on(this.tech_, 'pause', this.handleTechPause_); + this.on(this.tech_, 'durationchange', this.handleTechDurationChange_); + this.on(this.tech_, 'fullscreenchange', this.handleTechFullscreenChange_); + this.on(this.tech_, 'error', this.handleTechError_); + this.on(this.tech_, 'loadedmetadata', this.updateStyleEl_); + this.on(this.tech_, 'posterchange', this.handleTechPosterChange_); + this.on(this.tech_, 'textdata', this.handleTechTextData_); + this.on(this.tech_, 'ratechange', this.handleTechRateChange_); + + this.usingNativeControls(this.techGet_('controls')); + + if (this.controls() && !this.usingNativeControls()) { + this.addTechControlsListeners_(); + } + + // Add the tech element in the DOM if it was not already there + // Make sure to not insert the original video element if using Html5 + if (this.tech_.el().parentNode !== this.el() && (titleTechName !== 'Html5' || !this.tag)) { + prependTo(this.tech_.el(), this.el()); + } + + // Get rid of the original video tag reference after the first tech is loaded + if (this.tag) { + this.tag.player = null; + this.tag = null; + } + }; + + /** + * Unload and dispose of the current playback {@link Tech}. + * + * @private + */ + + + Player.prototype.unloadTech_ = function unloadTech_() { + var _this3 = this; + + // Save the current text tracks so that we can reuse the same text tracks with the next tech + ALL.names.forEach(function (name$$1) { + var props = ALL[name$$1]; + + _this3[props.privateName] = _this3[props.getterName](); + }); + this.textTracksJson_ = textTrackConverter.textTracksToJson(this.tech_); + + this.isReady_ = false; + + this.tech_.dispose(); + + this.tech_ = false; + + if (this.isPosterFromTech_) { + this.poster_ = ''; + this.trigger('posterchange'); + } + + this.isPosterFromTech_ = false; + }; + + /** + * Return a reference to the current {@link Tech}. + * It will print a warning by default about the danger of using the tech directly + * but any argument that is passed in will silence the warning. + * + * @param {*} [safety] + * Anything passed in to silence the warning + * + * @return {Tech} + * The Tech + */ + + + Player.prototype.tech = function tech(safety) { + if (safety === undefined) { + log$1.warn(tsml(_templateObject$2)); + } + + return this.tech_; + }; + + /** + * Set up click and touch listeners for the playback element + * + * - On desktops: a click on the video itself will toggle playback + * - On mobile devices: a click on the video toggles controls + * which is done by toggling the user state between active and + * inactive + * - A tap can signal that a user has become active or has become inactive + * e.g. a quick tap on an iPhone movie should reveal the controls. Another + * quick tap should hide them again (signaling the user is in an inactive + * viewing state) + * - In addition to this, we still want the user to be considered inactive after + * a few seconds of inactivity. + * + * > Note: the only part of iOS interaction we can't mimic with this setup + * is a touch and hold on the video element counting as activity in order to + * keep the controls showing, but that shouldn't be an issue. A touch and hold + * on any controls will still keep the user active + * + * @private + */ + + + Player.prototype.addTechControlsListeners_ = function addTechControlsListeners_() { + // Make sure to remove all the previous listeners in case we are called multiple times. + this.removeTechControlsListeners_(); + + // Some browsers (Chrome & IE) don't trigger a click on a flash swf, but do + // trigger mousedown/up. + // http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object + // Any touch events are set to block the mousedown event from happening + this.on(this.tech_, 'mousedown', this.handleTechClick_); + + // If the controls were hidden we don't want that to change without a tap event + // so we'll check if the controls were already showing before reporting user + // activity + this.on(this.tech_, 'touchstart', this.handleTechTouchStart_); + this.on(this.tech_, 'touchmove', this.handleTechTouchMove_); + this.on(this.tech_, 'touchend', this.handleTechTouchEnd_); + + // The tap listener needs to come after the touchend listener because the tap + // listener cancels out any reportedUserActivity when setting userActive(false) + this.on(this.tech_, 'tap', this.handleTechTap_); + }; + + /** + * Remove the listeners used for click and tap controls. This is needed for + * toggling to controls disabled, where a tap/touch should do nothing. + * + * @private + */ + + + Player.prototype.removeTechControlsListeners_ = function removeTechControlsListeners_() { + // We don't want to just use `this.off()` because there might be other needed + // listeners added by techs that extend this. + this.off(this.tech_, 'tap', this.handleTechTap_); + this.off(this.tech_, 'touchstart', this.handleTechTouchStart_); + this.off(this.tech_, 'touchmove', this.handleTechTouchMove_); + this.off(this.tech_, 'touchend', this.handleTechTouchEnd_); + this.off(this.tech_, 'mousedown', this.handleTechClick_); + }; + + /** + * Player waits for the tech to be ready + * + * @private + */ + + + Player.prototype.handleTechReady_ = function handleTechReady_() { + this.triggerReady(); + + // Keep the same volume as before + if (this.cache_.volume) { + this.techCall_('setVolume', this.cache_.volume); + } + + // Look if the tech found a higher resolution poster while loading + this.handleTechPosterChange_(); + + // Update the duration if available + this.handleTechDurationChange_(); + + // Chrome and Safari both have issues with autoplay. + // In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work. + // In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays) + // This fixes both issues. Need to wait for API, so it updates displays correctly + if ((this.src() || this.currentSrc()) && this.tag && this.options_.autoplay && this.paused()) { + try { + // Chrome Fix. Fixed in Chrome v16. + delete this.tag.poster; + } catch (e) { + log$1('deleting tag.poster throws in some browsers', e); + } + } + }; + + /** + * Retrigger the `loadstart` event that was triggered by the {@link Tech}. This + * function will also trigger {@link Player#firstplay} if it is the first loadstart + * for a video. + * + * @fires Player#loadstart + * @fires Player#firstplay + * @listens Tech#loadstart + * @private + */ + + + Player.prototype.handleTechLoadStart_ = function handleTechLoadStart_() { + // TODO: Update to use `emptied` event instead. See #1277. + + this.removeClass('vjs-ended'); + this.removeClass('vjs-seeking'); + + // reset the error state + this.error(null); + + // If it's already playing we want to trigger a firstplay event now. + // The firstplay event relies on both the playOld and loadstart events + // which can happen in any order for a new source + if (!this.paused()) { + /** + * Fired when the user agent begins looking for media data + * + * @event Player#loadstart + * @type {EventTarget~Event} + */ + this.trigger('loadstart'); + this.trigger('firstplay'); + } else { + // reset the hasStarted state + this.hasStarted(false); + this.trigger('loadstart'); + } + }; + + /** + * Update the internal source caches so that we return the correct source from + * `src()`, `currentSource()`, and `currentSources()`. + * + * > Note: `currentSources` will not be updated if the source that is passed in exists + * in the current `currentSources` cache. + * + * + * @param {Tech~SourceObject} srcObj + * A string or object source to update our caches to. + */ + + + Player.prototype.updateSourceCaches_ = function updateSourceCaches_() { + var srcObj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + + + var src = srcObj; + var type = ''; + + if (typeof src !== 'string') { + src = srcObj.src; + type = srcObj.type; + } + // make sure all the caches are set to default values + // to prevent null checking + this.cache_.source = this.cache_.source || {}; + this.cache_.sources = this.cache_.sources || []; + + // try to get the type of the src that was passed in + if (src && !type) { + type = findMimetype(this, src); + } + + // update `currentSource` cache always + this.cache_.source = {src: src, type: type}; + + var matchingSources = this.cache_.sources.filter(function (s) { + return s.src && s.src === src; + }); + var sourceElSources = []; + var sourceEls = this.$$('source'); + var matchingSourceEls = []; + + for (var i = 0; i < sourceEls.length; i++) { + var sourceObj = getAttributes(sourceEls[i]); + + sourceElSources.push(sourceObj); + + if (sourceObj.src && sourceObj.src === src) { + matchingSourceEls.push(sourceObj.src); + } + } + + // if we have matching source els but not matching sources + // the current source cache is not up to date + if (matchingSourceEls.length && !matchingSources.length) { + this.cache_.sources = sourceElSources; + // if we don't have matching source or source els set the + // sources cache to the `currentSource` cache + } else if (!matchingSources.length) { + this.cache_.sources = [this.cache_.source]; + } + + // update the tech `src` cache + this.cache_.src = src; + }; + + /** + * *EXPERIMENTAL* Fired when the source is set or changed on the {@link Tech} + * causing the media element to reload. + * + * It will fire for the initial source and each subsequent source. + * This event is a custom event from Video.js and is triggered by the {@link Tech}. + * + * The event object for this event contains a `src` property that will contain the source + * that was available when the event was triggered. This is generally only necessary if Video.js + * is switching techs while the source was being changed. + * + * It is also fired when `load` is called on the player (or media element) + * because the {@link https://html.spec.whatwg.org/multipage/media.html#dom-media-load|specification for `load`} + * says that the resource selection algorithm needs to be aborted and restarted. + * In this case, it is very likely that the `src` property will be set to the + * empty string `""` to indicate we do not know what the source will be but + * that it is changing. + * + * *This event is currently still experimental and may change in minor releases.* + * __To use this, pass `enableSourceset` option to the player.__ + * + * @event Player#sourceset + * @type {EventTarget~Event} + * @prop {string} src + * The source url available when the `sourceset` was triggered. + * It will be an empty string if we cannot know what the source is + * but know that the source will change. + */ + /** + * Retrigger the `sourceset` event that was triggered by the {@link Tech}. + * + * @fires Player#sourceset + * @listens Tech#sourceset + * @private + */ + + + Player.prototype.handleTechSourceset_ = function handleTechSourceset_(event) { + var _this4 = this; + + // only update the source cache when the source + // was not updated using the player api + if (!this.changingSrc_) { + // update the source to the intial source right away + // in some cases this will be empty string + this.updateSourceCaches_(event.src); + + // if the `sourceset` `src` was an empty string + // wait for a `loadstart` to update the cache to `currentSrc`. + // If a sourceset happens before a `loadstart`, we reset the state + // as this function will be called again. + if (!event.src) { + var updateCache = function updateCache(e) { + if (e.type !== 'sourceset') { + _this4.updateSourceCaches_(_this4.techGet_('currentSrc')); + } + + _this4.tech_.off(['sourceset', 'loadstart'], updateCache); + }; + + this.tech_.one(['sourceset', 'loadstart'], updateCache); + } + } + + this.trigger({ + src: event.src, + type: 'sourceset' + }); + }; + + /** + * Add/remove the vjs-has-started class + * + * @fires Player#firstplay + * + * @param {boolean} request + * - true: adds the class + * - false: remove the class + * + * @return {boolean} + * the boolean value of hasStarted_ + */ + + + Player.prototype.hasStarted = function hasStarted(request) { + if (request === undefined) { + // act as getter, if we have no request to change + return this.hasStarted_; + } + + if (request === this.hasStarted_) { + return; + } + + this.hasStarted_ = request; + + if (this.hasStarted_) { + this.addClass('vjs-has-started'); + this.trigger('firstplay'); + } else { + this.removeClass('vjs-has-started'); + } + }; + + /** + * Fired whenever the media begins or resumes playback + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play} + * @fires Player#play + * @listens Tech#play + * @private + */ + + + Player.prototype.handleTechPlay_ = function handleTechPlay_() { + this.removeClass('vjs-ended'); + this.removeClass('vjs-paused'); + this.addClass('vjs-playing'); + + // hide the poster when the user hits playOld + this.hasStarted(true); + /** + * Triggered whenever an {@link Tech#play} event happens. Indicates that + * playback has started or resumed. + * + * @event Player#play + * @type {EventTarget~Event} + */ + this.trigger('play'); + }; + + /** + * Retrigger the `ratechange` event that was triggered by the {@link Tech}. + * + * If there were any events queued while the playback rate was zero, fire + * those events now. + * + * @private + * @method Player#handleTechRateChange_ + * @fires Player#ratechange + * @listens Tech#ratechange + */ + + + Player.prototype.handleTechRateChange_ = function handleTechRateChange_() { + if (this.tech_.playbackRate() > 0 && this.cache_.lastPlaybackRate === 0) { + this.queuedCallbacks_.forEach(function (queued) { + return queued.callback(queued.event); + }); + this.queuedCallbacks_ = []; + } + this.cache_.lastPlaybackRate = this.tech_.playbackRate(); + /** + * Fires when the playing speed of the audio/video is changed + * + * @event Player#ratechange + * @type {event} + */ + this.trigger('ratechange'); + }; + + /** + * Retrigger the `waiting` event that was triggered by the {@link Tech}. + * + * @fires Player#waiting + * @listens Tech#waiting + * @private + */ + + + Player.prototype.handleTechWaiting_ = function handleTechWaiting_() { + var _this5 = this; + + this.addClass('vjs-waiting'); + /** + * A readyState change on the DOM element has caused playback to stop. + * + * @event Player#waiting + * @type {EventTarget~Event} + */ + this.trigger('waiting'); + this.one('timeupdate', function () { + return _this5.removeClass('vjs-waiting'); + }); + }; + + /** + * Retrigger the `canplay` event that was triggered by the {@link Tech}. + * > Note: This is not consistent between browsers. See #1351 + * + * @fires Player#canplay + * @listens Tech#canplay + * @private + */ + + + Player.prototype.handleTechCanPlay_ = function handleTechCanPlay_() { + this.removeClass('vjs-waiting'); + /** + * The media has a readyState of HAVE_FUTURE_DATA or greater. + * + * @event Player#canplay + * @type {EventTarget~Event} + */ + this.trigger('canplay'); + }; + + /** + * Retrigger the `canplaythrough` event that was triggered by the {@link Tech}. + * + * @fires Player#canplaythrough + * @listens Tech#canplaythrough + * @private + */ + + + Player.prototype.handleTechCanPlayThrough_ = function handleTechCanPlayThrough_() { + this.removeClass('vjs-waiting'); + /** + * The media has a readyState of HAVE_ENOUGH_DATA or greater. This means that the + * entire media file can be played without buffering. + * + * @event Player#canplaythrough + * @type {EventTarget~Event} + */ + this.trigger('canplaythrough'); + }; + + /** + * Retrigger the `playing` event that was triggered by the {@link Tech}. + * + * @fires Player#playing + * @listens Tech#playing + * @private + */ + + + Player.prototype.handleTechPlaying_ = function handleTechPlaying_() { + this.removeClass('vjs-waiting'); + /** + * The media is no longer blocked from playback, and has started playing. + * + * @event Player#playing + * @type {EventTarget~Event} + */ + this.trigger('playing'); + }; + + /** + * Retrigger the `seeking` event that was triggered by the {@link Tech}. + * + * @fires Player#seeking + * @listens Tech#seeking + * @private + */ + + + Player.prototype.handleTechSeeking_ = function handleTechSeeking_() { + this.addClass('vjs-seeking'); + /** + * Fired whenever the player is jumping to a new time + * + * @event Player#seeking + * @type {EventTarget~Event} + */ + this.trigger('seeking'); + }; + + /** + * Retrigger the `seeked` event that was triggered by the {@link Tech}. + * + * @fires Player#seeked + * @listens Tech#seeked + * @private + */ + + + Player.prototype.handleTechSeeked_ = function handleTechSeeked_() { + this.removeClass('vjs-seeking'); + /** + * Fired when the player has finished jumping to a new time + * + * @event Player#seeked + * @type {EventTarget~Event} + */ + this.trigger('seeked'); + }; + + /** + * Retrigger the `firstplay` event that was triggered by the {@link Tech}. + * + * @fires Player#firstplay + * @listens Tech#firstplay + * @deprecated As of 6.0 firstplay event is deprecated. + * @deprecated As of 6.0 passing the `starttime` option to the player and the firstplay event are deprecated. + * @private + */ + + + Player.prototype.handleTechFirstPlay_ = function handleTechFirstPlay_() { + // If the first starttime attribute is specified + // then we will start at the given offset in seconds + if (this.options_.starttime) { + log$1.warn('Passing the `starttime` option to the player will be deprecated in 6.0'); + this.currentTime(this.options_.starttime); + } + + this.addClass('vjs-has-started'); + /** + * Fired the first time a video is played. Not part of the HLS spec, and this is + * probably not the best implementation yet, so use sparingly. If you don't have a + * reason to prevent playback, use `myPlayer.one('playOld');` instead. + * + * @event Player#firstplay + * @deprecated As of 6.0 firstplay event is deprecated. + * @type {EventTarget~Event} + */ + this.trigger('firstplay'); + }; + + /** + * Retrigger the `pause` event that was triggered by the {@link Tech}. + * + * @fires Player#pause + * @listens Tech#pause + * @private + */ + + + Player.prototype.handleTechPause_ = function handleTechPause_() { + this.removeClass('vjs-playing'); + this.addClass('vjs-paused'); + /** + * Fired whenever the media has been paused + * + * @event Player#pause + * @type {EventTarget~Event} + */ + this.trigger('pause'); + }; + + /** + * Retrigger the `ended` event that was triggered by the {@link Tech}. + * + * @fires Player#ended + * @listens Tech#ended + * @private + */ + + + Player.prototype.handleTechEnded_ = function handleTechEnded_() { + this.addClass('vjs-ended'); + if (this.options_.loop) { + this.currentTime(0); + this.play(); + } else if (!this.paused()) { + this.pause(); + } + + /** + * Fired when the end of the media resource is reached (currentTime == duration) + * + * @event Player#ended + * @type {EventTarget~Event} + */ + this.trigger('ended'); + }; + + /** + * Fired when the duration of the media resource is first known or changed + * + * @listens Tech#durationchange + * @private + */ + + + Player.prototype.handleTechDurationChange_ = function handleTechDurationChange_() { + this.duration(this.techGet_('duration')); + }; + + /** + * Handle a click on the media element to playOld/pause + * + * @param {EventTarget~Event} event + * the event that caused this function to trigger + * + * @listens Tech#mousedown + * @private + */ + + + Player.prototype.handleTechClick_ = function handleTechClick_(event) { + if (!isSingleLeftClick(event)) { + return; + } + + // When controls are disabled a click should not toggle playback because + // the click is considered a control + if (!this.controls_) { + return; + } + + if (this.paused()) { + this.play(); + } else { + this.pause(); + } + }; + + /** + * Handle a tap on the media element. It will toggle the user + * activity state, which hides and shows the controls. + * + * @listens Tech#tap + * @private + */ + + + Player.prototype.handleTechTap_ = function handleTechTap_() { + this.userActive(!this.userActive()); + }; + + /** + * Handle touch to start + * + * @listens Tech#touchstart + * @private + */ + + + Player.prototype.handleTechTouchStart_ = function handleTechTouchStart_() { + this.userWasActive = this.userActive(); + }; + + /** + * Handle touch to move + * + * @listens Tech#touchmove + * @private + */ + + + Player.prototype.handleTechTouchMove_ = function handleTechTouchMove_() { + if (this.userWasActive) { + this.reportUserActivity(); + } + }; + + /** + * Handle touch to end + * + * @param {EventTarget~Event} event + * the touchend event that triggered + * this function + * + * @listens Tech#touchend + * @private + */ + + + Player.prototype.handleTechTouchEnd_ = function handleTechTouchEnd_(event) { + // Stop the mouse events from also happening + event.preventDefault(); + }; + + /** + * Fired when the player switches in or out of fullscreen mode + * + * @private + * @listens Player#fullscreenchange + */ + + + Player.prototype.handleFullscreenChange_ = function handleFullscreenChange_() { + if (this.isFullscreen()) { + this.addClass('vjs-fullscreen'); + } else { + this.removeClass('vjs-fullscreen'); + } + }; + + /** + * native click events on the SWF aren't triggered on IE11, Win8.1RT + * use stageclick events triggered from inside the SWF instead + * + * @private + * @listens stageclick + */ + + + Player.prototype.handleStageClick_ = function handleStageClick_() { + this.reportUserActivity(); + }; + + /** + * Handle Tech Fullscreen Change + * + * @param {EventTarget~Event} event + * the fullscreenchange event that triggered this function + * + * @param {Object} data + * the data that was sent with the event + * + * @private + * @listens Tech#fullscreenchange + * @fires Player#fullscreenchange + */ + + + Player.prototype.handleTechFullscreenChange_ = function handleTechFullscreenChange_(event, data) { + if (data) { + this.isFullscreen(data.isFullscreen); + } + /** + * Fired when going in and out of fullscreen. + * + * @event Player#fullscreenchange + * @type {EventTarget~Event} + */ + this.trigger('fullscreenchange'); + }; + + /** + * Fires when an error occurred during the loading of an audio/video. + * + * @private + * @listens Tech#error + */ + + + Player.prototype.handleTechError_ = function handleTechError_() { + var error = this.tech_.error(); + + this.error(error); + }; + + /** + * Retrigger the `textdata` event that was triggered by the {@link Tech}. + * + * @fires Player#textdata + * @listens Tech#textdata + * @private + */ + + + Player.prototype.handleTechTextData_ = function handleTechTextData_() { + var data = null; + + if (arguments.length > 1) { + data = arguments[1]; + } + + /** + * Fires when we get a textdata event from tech + * + * @event Player#textdata + * @type {EventTarget~Event} + */ + this.trigger('textdata', data); + }; + + /** + * Get object for cached values. + * + * @return {Object} + * get the current object cache + */ + + + Player.prototype.getCache = function getCache() { + return this.cache_; + }; + + /** + * Pass values to the playback tech + * + * @param {string} [method] + * the method to call + * + * @param {Object} arg + * the argument to pass + * + * @private + */ + + + Player.prototype.techCall_ = function techCall_(method, arg) { + // If it's not ready yet, call method when it is + + this.ready(function () { + if (method in allowedSetters) { + return set$1(this.middleware_, this.tech_, method, arg); + } else if (method in allowedMediators) { + return mediate(this.middleware_, this.tech_, method, arg); + } + + try { + if (this.tech_) { + this.tech_[method](arg); + } + } catch (e) { + log$1(e); + throw e; + } + }, true); + }; + + /** + * Get calls can't wait for the tech, and sometimes don't need to. + * + * @param {string} method + * Tech method + * + * @return {Function|undefined} + * the method or undefined + * + * @private + */ + + + Player.prototype.techGet_ = function techGet_(method) { + if (!this.tech_ || !this.tech_.isReady_) { + return; + } + + if (method in allowedGetters) { + return get$1(this.middleware_, this.tech_, method); + } else if (method in allowedMediators) { + return mediate(this.middleware_, this.tech_, method); + } + + // Flash likes to die and reload when you hide or reposition it. + // In these cases the object methods go away and we get errors. + // When that happens we'll catch the errors and inform tech that it's not ready any more. + try { + return this.tech_[method](); + } catch (e) { + + // When building additional tech libs, an expected method may not be defined yet + if (this.tech_[method] === undefined) { + log$1('Video.js: ' + method + ' method not defined for ' + this.techName_ + ' playback technology.', e); + throw e; + } + + // When a method isn't available on the object it throws a TypeError + if (e.name === 'TypeError') { + log$1('Video.js: ' + method + ' unavailable on ' + this.techName_ + ' playback technology element.', e); + this.tech_.isReady_ = false; + throw e; + } + + // If error unknown, just log and throw + log$1(e); + throw e; + } + }; + + /** + * Attempt to begin playback at the first opportunity. + * + * @return {Promise|undefined} + * Returns a `Promise` only if the browser returns one and the player + * is ready to begin playback. For some browsers and all non-ready + * situations, this will return `undefined`. + */ + + + Player.prototype.play = function play() { + var _this6 = this; + + // If this is called while we have a playOld queued up on a loadstart, remove + // that listener to avoid getting in a potentially bad state. + if (this.playOnLoadstart_) { + this.off('loadstart', this.playOnLoadstart_); + } + + // If the player/tech is not ready, queue up another call to `playOld()` for + // when it is. This will loop back into this method for another attempt at + // playback when the tech is ready. + if (!this.isReady_) { + + // Bail out if we're already waiting for `ready`! + if (this.playWaitingForReady_) { + return; + } + + this.playWaitingForReady_ = true; + this.ready(function () { + _this6.playWaitingForReady_ = false; + silencePromise(_this6.play()); + }); + + // If the player/tech is ready and we have a source, we can attempt playback. + } else if (!this.changingSrc_ && (this.src() || this.currentSrc())) { + return this.techGet_('play'); + + // If the tech is ready, but we do not have a source, we'll need to wait + // for both the `ready` and a `loadstart` when the source is finally + // resolved by middleware and set on the player. + // + // This can happen if `playOld()` is called while changing sources or before + // one has been set on the player. + } else { + + this.playOnLoadstart_ = function () { + _this6.playOnLoadstart_ = null; + silencePromise(_this6.play()); + }; + + this.one('loadstart', this.playOnLoadstart_); + } + }; + + /** + * Pause the video playback + * + * @return {Player} + * A reference to the player object this function was called on + */ + + + Player.prototype.pause = function pause() { + this.techCall_('pause'); + }; + + /** + * Check if the player is paused or has yet to playOld + * + * @return {boolean} + * - false: if the media is currently playing + * - true: if media is not currently playing + */ + + + Player.prototype.paused = function paused() { + // The initial state of paused should be true (in Safari it's actually false) + return this.techGet_('paused') === false ? false : true; + }; + + /** + * Get a TimeRange object representing the current ranges of time that the user + * has played. + * + * @return {TimeRange} + * A time range object that represents all the increments of time that have + * been played. + */ + + + Player.prototype.played = function played() { + return this.techGet_('played') || createTimeRanges(0, 0); + }; + + /** + * Returns whether or not the user is "scrubbing". Scrubbing is + * when the user has clicked the progress bar handle and is + * dragging it along the progress bar. + * + * @param {boolean} [isScrubbing] + * whether the user is or is not scrubbing + * + * @return {boolean} + * The value of scrubbing when getting + */ + + + Player.prototype.scrubbing = function scrubbing(isScrubbing) { + if (typeof isScrubbing === 'undefined') { + return this.scrubbing_; + } + this.scrubbing_ = !!isScrubbing; + + if (isScrubbing) { + this.addClass('vjs-scrubbing'); + } else { + this.removeClass('vjs-scrubbing'); + } + }; + + /** + * Get or set the current time (in seconds) + * + * @param {number|string} [seconds] + * The time to seek to in seconds + * + * @return {number} + * - the current time in seconds when getting + */ + + + Player.prototype.currentTime = function currentTime(seconds) { + if (typeof seconds !== 'undefined') { + if (seconds < 0) { + seconds = 0; + } + this.techCall_('setCurrentTime', seconds); + return; + } + + // cache last currentTime and return. default to 0 seconds + // + // Caching the currentTime is meant to prevent a massive amount of reads on the tech's + // currentTime when scrubbing, but may not provide much performance benefit afterall. + // Should be tested. Also something has to read the actual current time or the cache will + // never get updated. + this.cache_.currentTime = this.techGet_('currentTime') || 0; + return this.cache_.currentTime; + }; + + /** + * Normally gets the length in time of the video in seconds; + * in all but the rarest use cases an argument will NOT be passed to the method + * + * > **NOTE**: The video must have started loading before the duration can be + * known, and in the case of Flash, may not be known until the video starts + * playing. + * + * @fires Player#durationchange + * + * @param {number} [seconds] + * The duration of the video to set in seconds + * + * @return {number} + * - The duration of the video in seconds when getting + */ + + + Player.prototype.duration = function duration(seconds) { + if (seconds === undefined) { + // return NaN if the duration is not known + return this.cache_.duration !== undefined ? this.cache_.duration : NaN; + } + + seconds = parseFloat(seconds); + + // Standardize on Infinity for signaling video is live + if (seconds < 0) { + seconds = Infinity; + } + + if (seconds !== this.cache_.duration) { + // Cache the last set value for optimized scrubbing (esp. Flash) + this.cache_.duration = seconds; + + if (seconds === Infinity) { + this.addClass('vjs-live'); + } else { + this.removeClass('vjs-live'); + } + /** + * @event Player#durationchange + * @type {EventTarget~Event} + */ + this.trigger('durationchange'); + } + }; + + /** + * Calculates how much time is left in the video. Not part + * of the native video API. + * + * @return {number} + * The time remaining in seconds + */ + + + Player.prototype.remainingTime = function remainingTime() { + return this.duration() - this.currentTime(); + }; + + /** + * A remaining time function that is intented to be used when + * the time is to be displayed directly to the user. + * + * @return {number} + * The rounded time remaining in seconds + */ + + + Player.prototype.remainingTimeDisplay = function remainingTimeDisplay() { + return Math.floor(this.duration()) - Math.floor(this.currentTime()); + }; + + // + // Kind of like an array of portions of the video that have been downloaded. + + /** + * Get a TimeRange object with an array of the times of the video + * that have been downloaded. If you just want the percent of the + * video that's been downloaded, use bufferedPercent. + * + * @see [Buffered Spec]{@link http://dev.w3.org/html5/spec/video.html#dom-media-buffered} + * + * @return {TimeRange} + * A mock TimeRange object (following HTML spec) + */ + + + Player.prototype.buffered = function buffered() { + var buffered = this.techGet_('buffered'); + + if (!buffered || !buffered.length) { + buffered = createTimeRanges(0, 0); + } + + return buffered; + }; + + /** + * Get the percent (as a decimal) of the video that's been downloaded. + * This method is not a part of the native HTML video API. + * + * @return {number} + * A decimal between 0 and 1 representing the percent + * that is buffered 0 being 0% and 1 being 100% + */ + + + Player.prototype.bufferedPercent = function bufferedPercent$$1() { + return bufferedPercent(this.buffered(), this.duration()); + }; + + /** + * Get the ending time of the last buffered time range + * This is used in the progress bar to encapsulate all time ranges. + * + * @return {number} + * The end of the last buffered time range + */ + + + Player.prototype.bufferedEnd = function bufferedEnd() { + var buffered = this.buffered(); + var duration = this.duration(); + var end = buffered.end(buffered.length - 1); + + if (end > duration) { + end = duration; + } + + return end; + }; + + /** + * Get or set the current volume of the media + * + * @param {number} [percentAsDecimal] + * The new volume as a decimal percent: + * - 0 is muted/0%/off + * - 1.0 is 100%/full + * - 0.5 is half volume or 50% + * + * @return {number} + * The current volume as a percent when getting + */ + + + Player.prototype.volume = function volume(percentAsDecimal) { + var vol = void 0; + + if (percentAsDecimal !== undefined) { + // Force value to between 0 and 1 + vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); + this.cache_.volume = vol; + this.techCall_('setVolume', vol); + + if (vol > 0) { + this.lastVolume_(vol); + } + + return; + } + + // Default to 1 when returning current volume. + vol = parseFloat(this.techGet_('volume')); + return isNaN(vol) ? 1 : vol; + }; + + /** + * Get the current muted state, or turn mute on or off + * + * @param {boolean} [muted] + * - true to mute + * - false to unmute + * + * @return {boolean} + * - true if mute is on and getting + * - false if mute is off and getting + */ + + + Player.prototype.muted = function muted(_muted) { + if (_muted !== undefined) { + this.techCall_('setMuted', _muted); + return; + } + return this.techGet_('muted') || false; + }; + + /** + * Get the current defaultMuted state, or turn defaultMuted on or off. defaultMuted + * indicates the state of muted on initial playback. + * + * ```js + * var myPlayer = videojs('some-player-id'); + * + * myPlayer.src("http://www.example.com/path/to/video.mp4"); + * + * // get, should be false + * console.log(myPlayer.defaultMuted()); + * // set to true + * myPlayer.defaultMuted(true); + * // get should be true + * console.log(myPlayer.defaultMuted()); + * ``` + * + * @param {boolean} [defaultMuted] + * - true to mute + * - false to unmute + * + * @return {boolean|Player} + * - true if defaultMuted is on and getting + * - false if defaultMuted is off and getting + * - A reference to the current player when setting + */ + + + Player.prototype.defaultMuted = function defaultMuted(_defaultMuted) { + if (_defaultMuted !== undefined) { + return this.techCall_('setDefaultMuted', _defaultMuted); + } + return this.techGet_('defaultMuted') || false; + }; + + /** + * Get the last volume, or set it + * + * @param {number} [percentAsDecimal] + * The new last volume as a decimal percent: + * - 0 is muted/0%/off + * - 1.0 is 100%/full + * - 0.5 is half volume or 50% + * + * @return {number} + * the current value of lastVolume as a percent when getting + * + * @private + */ + + + Player.prototype.lastVolume_ = function lastVolume_(percentAsDecimal) { + if (percentAsDecimal !== undefined && percentAsDecimal !== 0) { + this.cache_.lastVolume = percentAsDecimal; + return; + } + return this.cache_.lastVolume; + }; + + /** + * Check if current tech can support native fullscreen + * (e.g. with built in controls like iOS, so not our flash swf) + * + * @return {boolean} + * if native fullscreen is supported + */ + + + Player.prototype.supportsFullScreen = function supportsFullScreen() { + return this.techGet_('supportsFullScreen') || false; + }; + + /** + * Check if the player is in fullscreen mode or tell the player that it + * is or is not in fullscreen mode. + * + * > NOTE: As of the latest HTML5 spec, isFullscreen is no longer an official + * property and instead document.fullscreenElement is used. But isFullscreen is + * still a valuable property for internal player workings. + * + * @param {boolean} [isFS] + * Set the players current fullscreen state + * + * @return {boolean} + * - true if fullscreen is on and getting + * - false if fullscreen is off and getting + */ + + + Player.prototype.isFullscreen = function isFullscreen(isFS) { + if (isFS !== undefined) { + this.isFullscreen_ = !!isFS; + return; + } + return !!this.isFullscreen_; + }; + + /** + * Increase the size of the video to full screen + * In some browsers, full screen is not supported natively, so it enters + * "full window mode", where the video fills the browser window. + * In browsers and devices that support native full screen, sometimes the + * browser's default controls will be shown, and not the Video.js custom skin. + * This includes most mobile devices (iOS, Android) and older versions of + * Safari. + * + * @fires Player#fullscreenchange + */ + + + Player.prototype.requestFullscreen = function requestFullscreen() { + var fsApi = FullscreenApi; + + this.isFullscreen(true); + + if (fsApi.requestFullscreen) { + // the browser supports going fullscreen at the element level so we can + // take the controls fullscreen as well as the video + + // Trigger fullscreenchange event after change + // We have to specifically add this each time, and remove + // when canceling fullscreen. Otherwise if there's multiple + // players on a page, they would all be reacting to the same fullscreen + // events + on(document_1, fsApi.fullscreenchange, bind(this, function documentFullscreenChange(e) { + this.isFullscreen(document_1[fsApi.fullscreenElement]); + + // If cancelling fullscreen, remove event listener. + if (this.isFullscreen() === false) { + off(document_1, fsApi.fullscreenchange, documentFullscreenChange); + } + /** + * @event Player#fullscreenchange + * @type {EventTarget~Event} + */ + this.trigger('fullscreenchange'); + })); + + this.el_[fsApi.requestFullscreen](); + } else if (this.tech_.supportsFullScreen()) { + // we can't take the video.js controls fullscreen but we can go fullscreen + // with native controls + this.techCall_('enterFullScreen'); + } else { + // fullscreen isn't supported so we'll just stretch the video element to + // fill the viewport + this.enterFullWindow(); + /** + * @event Player#fullscreenchange + * @type {EventTarget~Event} + */ + this.trigger('fullscreenchange'); + } + }; + + /** + * Return the video to its normal size after having been in full screen mode + * + * @fires Player#fullscreenchange + */ + + + Player.prototype.exitFullscreen = function exitFullscreen() { + var fsApi = FullscreenApi; + + this.isFullscreen(false); + + // Check for browser element fullscreen support + if (fsApi.requestFullscreen) { + document_1[fsApi.exitFullscreen](); + } else if (this.tech_.supportsFullScreen()) { + this.techCall_('exitFullScreen'); + } else { + this.exitFullWindow(); + /** + * @event Player#fullscreenchange + * @type {EventTarget~Event} + */ + this.trigger('fullscreenchange'); + } + }; + + /** + * When fullscreen isn't supported we can stretch the + * video container to as wide as the browser will let us. + * + * @fires Player#enterFullWindow + */ + + + Player.prototype.enterFullWindow = function enterFullWindow() { + this.isFullWindow = true; + + // Storing original doc overflow value to return to when fullscreen is off + this.docOrigOverflow = document_1.documentElement.style.overflow; + + // Add listener for esc key to exit fullscreen + on(document_1, 'keydown', bind(this, this.fullWindowOnEscKey)); + + // Hide any scroll bars + document_1.documentElement.style.overflow = 'hidden'; + + // Apply fullscreen styles + addClass(document_1.body, 'vjs-full-window'); + + /** + * @event Player#enterFullWindow + * @type {EventTarget~Event} + */ + this.trigger('enterFullWindow'); + }; + + /** + * Check for call to either exit full window or + * full screen on ESC key + * + * @param {string} event + * Event to check for key press + */ + + + Player.prototype.fullWindowOnEscKey = function fullWindowOnEscKey(event) { + if (event.keyCode === 27) { + if (this.isFullscreen() === true) { + this.exitFullscreen(); + } else { + this.exitFullWindow(); + } + } + }; + + /** + * Exit full window + * + * @fires Player#exitFullWindow + */ + + + Player.prototype.exitFullWindow = function exitFullWindow() { + this.isFullWindow = false; + off(document_1, 'keydown', this.fullWindowOnEscKey); + + // Unhide scroll bars. + document_1.documentElement.style.overflow = this.docOrigOverflow; + + // Remove fullscreen styles + removeClass(document_1.body, 'vjs-full-window'); + + // Resize the box, controller, and poster to original sizes + // this.positionAll(); + /** + * @event Player#exitFullWindow + * @type {EventTarget~Event} + */ + this.trigger('exitFullWindow'); + }; + + /** + * Check whether the player can playOld a given mimetype + * + * @see https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-navigator-canplaytype + * + * @param {string} type + * The mimetype to check + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) + */ + + + Player.prototype.canPlayType = function canPlayType(type) { + var can = void 0; + + // Loop through each playback technology in the options order + for (var i = 0, j = this.options_.techOrder; i < j.length; i++) { + var techName = j[i]; + var tech = Tech.getTech(techName); + + // Support old behavior of techs being registered as components. + // Remove once that deprecated behavior is removed. + if (!tech) { + tech = Component.getComponent(techName); + } + + // Check if the current tech is defined before continuing + if (!tech) { + log$1.error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.'); + continue; + } + + // Check if the browser supports this technology + if (tech.isSupported()) { + can = tech.canPlayType(type); + + if (can) { + return can; + } + } + } + + return ''; + }; + + /** + * Select source based on tech-order or source-order + * Uses source-order selection if `options.sourceOrder` is truthy. Otherwise, + * defaults to tech-order selection + * + * @param {Array} sources + * The sources for a media asset + * + * @return {Object|boolean} + * Object of source and tech order or false + */ + + + Player.prototype.selectSource = function selectSource(sources) { + var _this7 = this; + + // Get only the techs specified in `techOrder` that exist and are supported by the + // current platform + var techs = this.options_.techOrder.map(function (techName) { + return [techName, Tech.getTech(techName)]; + }).filter(function (_ref) { + var techName = _ref[0], + tech = _ref[1]; + + // Check if the current tech is defined before continuing + if (tech) { + // Check if the browser supports this technology + return tech.isSupported(); + } + + log$1.error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.'); + return false; + }); + + // Iterate over each `innerArray` element once per `outerArray` element and execute + // `tester` with both. If `tester` returns a non-falsy value, exit early and return + // that value. + var findFirstPassingTechSourcePair = function findFirstPassingTechSourcePair(outerArray, innerArray, tester) { + var found = void 0; + + outerArray.some(function (outerChoice) { + return innerArray.some(function (innerChoice) { + found = tester(outerChoice, innerChoice); + + if (found) { + return true; + } + }); + }); + + return found; + }; + + var foundSourceAndTech = void 0; + var flip = function flip(fn) { + return function (a, b) { + return fn(b, a); + }; + }; + var finder = function finder(_ref2, source) { + var techName = _ref2[0], + tech = _ref2[1]; + + if (tech.canPlaySource(source, _this7.options_[techName.toLowerCase()])) { + return {source: source, tech: techName}; + } + }; + + // Depending on the truthiness of `options.sourceOrder`, we swap the order of techs and sources + // to select from them based on their priority. + if (this.options_.sourceOrder) { + // Source-first ordering + foundSourceAndTech = findFirstPassingTechSourcePair(sources, techs, flip(finder)); + } else { + // Tech-first ordering + foundSourceAndTech = findFirstPassingTechSourcePair(techs, sources, finder); + } + + return foundSourceAndTech || false; + }; + + /** + * Get or set the video source. + * + * @param {Tech~SourceObject|Tech~SourceObject[]|string} [source] + * A SourceObject, an array of SourceObjects, or a string referencing + * a URL to a media source. It is _highly recommended_ that an object + * or array of objects is used here, so that source selection + * algorithms can take the `type` into account. + * + * If not provided, this method acts as a getter. + * + * @return {string|undefined} + * If the `source` argument is missing, returns the current source + * URL. Otherwise, returns nothing/undefined. + */ + + + Player.prototype.src = function src(source) { + var _this8 = this; + + // getter usage + if (typeof source === 'undefined') { + return this.cache_.src || ''; + } + // filter out invalid sources and turn our source into + // an array of source objects + var sources = filterSource(source); + + // if a source was passed in then it is invalid because + // it was filtered to a zero length Array. So we have to + // show an error + if (!sources.length) { + this.setTimeout(function () { + this.error({code: 4, message: this.localize(this.options_.notSupportedMessage)}); + }, 0); + return; + } + + // intial sources + this.changingSrc_ = true; + + this.cache_.sources = sources; + this.updateSourceCaches_(sources[0]); + + // middlewareSource is the source after it has been changed by middleware + setSource(this, sources[0], function (middlewareSource, mws) { + _this8.middleware_ = mws; + + // since sourceSet is async we have to update the cache again after we select a source since + // the source that is selected could be out of order from the cache update above this callback. + _this8.cache_.sources = sources; + _this8.updateSourceCaches_(middlewareSource); + + var err = _this8.src_(middlewareSource); + + if (err) { + if (sources.length > 1) { + return _this8.src(sources.slice(1)); + } + + _this8.changingSrc_ = false; + + // We need to wrap this in a timeout to give folks a chance to add error event handlers + _this8.setTimeout(function () { + this.error({code: 4, message: this.localize(this.options_.notSupportedMessage)}); + }, 0); + + // we could not find an appropriate tech, but let's still notify the delegate that this is it + // this needs a better comment about why this is needed + _this8.triggerReady(); + + return; + } + + setTech(mws, _this8.tech_); + }); + }; + + /** + * Set the source object on the tech, returns a boolean that indicates whether + * there is a tech that can playOld the source or not + * + * @param {Tech~SourceObject} source + * The source object to set on the Tech + * + * @return {Boolean} + * - True if there is no Tech to playback this source + * - False otherwise + * + * @private + */ + + + Player.prototype.src_ = function src_(source) { + var _this9 = this; + + var sourceTech = this.selectSource([source]); + + if (!sourceTech) { + return true; + } + + if (!titleCaseEquals(sourceTech.tech, this.techName_)) { + this.changingSrc_ = true; + // load this technology with the chosen source + this.loadTech_(sourceTech.tech, sourceTech.source); + this.tech_.ready(function () { + _this9.changingSrc_ = false; + }); + return false; + } + + // wait until the tech is ready to set the source + // and set it synchronously if possible (#2326) + this.ready(function () { + + // The setSource tech method was added with source handlers + // so older techs won't support it + // We need to check the direct prototype for the case where subclasses + // of the tech do not support source handlers + if (this.tech_.constructor.prototype.hasOwnProperty('setSource')) { + this.techCall_('setSource', source); + } else { + this.techCall_('src', source.src); + } + + this.changingSrc_ = false; + }, true); + + return false; + }; + + /** + * Begin loading the src data. + */ + + + Player.prototype.load = function load() { + this.techCall_('load'); + }; + + /** + * Reset the player. Loads the first tech in the techOrder, + * and calls `reset` on the tech`. + */ + + + Player.prototype.reset = function reset() { + this.loadTech_(this.options_.techOrder[0], null); + this.techCall_('reset'); + }; + + /** + * Returns all of the current source objects. + * + * @return {Tech~SourceObject[]} + * The current source objects + */ + + + Player.prototype.currentSources = function currentSources() { + var source = this.currentSource(); + var sources = []; + + // assume `{}` or `{ src }` + if (Object.keys(source).length !== 0) { + sources.push(source); + } + + return this.cache_.sources || sources; + }; + + /** + * Returns the current source object. + * + * @return {Tech~SourceObject} + * The current source object + */ + + + Player.prototype.currentSource = function currentSource() { + return this.cache_.source || {}; + }; + + /** + * Returns the fully qualified URL of the current source value e.g. http://mysite.com/video.mp4 + * Can be used in conjunction with `currentType` to assist in rebuilding the current source object. + * + * @return {string} + * The current source + */ + + + Player.prototype.currentSrc = function currentSrc() { + return this.currentSource() && this.currentSource().src || ''; + }; + + /** + * Get the current source type e.g. video/mp4 + * This can allow you rebuild the current source object so that you could load the same + * source and tech later + * + * @return {string} + * The source MIME type + */ + + + Player.prototype.currentType = function currentType() { + return this.currentSource() && this.currentSource().type || ''; + }; + + /** + * Get or set the preload attribute + * + * @param {boolean} [value] + * - true means that we should preload + * - false means that we should not preload + * + * @return {string} + * The preload attribute value when getting + */ + + + Player.prototype.preload = function preload(value) { + if (value !== undefined) { + this.techCall_('setPreload', value); + this.options_.preload = value; + return; + } + return this.techGet_('preload'); + }; + + /** + * Get or set the autoplay attribute. + * + * @param {boolean} [value] + * - true means that we should autoplay + * - false means that we should not autoplay + * + * @return {string} + * The current value of autoplay when getting + */ + + + Player.prototype.autoplay = function autoplay(value) { + if (value !== undefined) { + this.techCall_('setAutoplay', value); + this.options_.autoplay = value; + return; + } + return this.techGet_('autoplay', value); + }; + + /** + * Set or unset the playsinline attribute. + * Playsinline tells the browser that non-fullscreen playback is preferred. + * + * @param {boolean} [value] + * - true means that we should try to playOld inline by default + * - false means that we should use the browser's default playback mode, + * which in most cases is inline. iOS Safari is a notable exception + * and plays fullscreen by default. + * + * @return {string|Player} + * - the current value of playsinline + * - the player when setting + * + * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} + */ + + + Player.prototype.playsinline = function playsinline(value) { + if (value !== undefined) { + this.techCall_('setPlaysinline', value); + this.options_.playsinline = value; + return this; + } + return this.techGet_('playsinline'); + }; + + /** + * Get or set the loop attribute on the video element. + * + * @param {boolean} [value] + * - true means that we should loop the video + * - false means that we should not loop the video + * + * @return {string} + * The current value of loop when getting + */ + + + Player.prototype.loop = function loop(value) { + if (value !== undefined) { + this.techCall_('setLoop', value); + this.options_.loop = value; + return; + } + return this.techGet_('loop'); + }; + + /** + * Get or set the poster image source url + * + * @fires Player#posterchange + * + * @param {string} [src] + * Poster image source URL + * + * @return {string} + * The current value of poster when getting + */ + + + Player.prototype.poster = function poster(src) { + if (src === undefined) { + return this.poster_; + } + + // The correct way to remove a poster is to set as an empty string + // other falsey values will throw errors + if (!src) { + src = ''; + } + + if (src === this.poster_) { + return; + } + + // update the internal poster variable + this.poster_ = src; + + // update the tech's poster + this.techCall_('setPoster', src); + + this.isPosterFromTech_ = false; + + // alert components that the poster has been set + /** + * This event fires when the poster image is changed on the player. + * + * @event Player#posterchange + * @type {EventTarget~Event} + */ + this.trigger('posterchange'); + }; + + /** + * Some techs (e.g. YouTube) can provide a poster source in an + * asynchronous way. We want the poster component to use this + * poster source so that it covers up the tech's controls. + * (YouTube's playOld button). However we only want to use this + * source if the player user hasn't set a poster through + * the normal APIs. + * + * @fires Player#posterchange + * @listens Tech#posterchange + * @private + */ + + + Player.prototype.handleTechPosterChange_ = function handleTechPosterChange_() { + if ((!this.poster_ || this.options_.techCanOverridePoster) && this.tech_ && this.tech_.poster) { + var newPoster = this.tech_.poster() || ''; + + if (newPoster !== this.poster_) { + this.poster_ = newPoster; + this.isPosterFromTech_ = true; + + // Let components know the poster has changed + this.trigger('posterchange'); + } + } + }; + + /** + * Get or set whether or not the controls are showing. + * + * @fires Player#controlsenabled + * + * @param {boolean} [bool] + * - true to turn controls on + * - false to turn controls off + * + * @return {boolean} + * The current value of controls when getting + */ + + + Player.prototype.controls = function controls(bool) { + if (bool === undefined) { + return !!this.controls_; + } + + bool = !!bool; + + // Don't trigger a change event unless it actually changed + if (this.controls_ === bool) { + return; + } + + this.controls_ = bool; + + if (this.usingNativeControls()) { + this.techCall_('setControls', bool); + } + + if (this.controls_) { + this.removeClass('vjs-controls-disabled'); + this.addClass('vjs-controls-enabled'); + /** + * @event Player#controlsenabled + * @type {EventTarget~Event} + */ + this.trigger('controlsenabled'); + if (!this.usingNativeControls()) { + this.addTechControlsListeners_(); + } + } else { + this.removeClass('vjs-controls-enabled'); + this.addClass('vjs-controls-disabled'); + /** + * @event Player#controlsdisabled + * @type {EventTarget~Event} + */ + this.trigger('controlsdisabled'); + if (!this.usingNativeControls()) { + this.removeTechControlsListeners_(); + } + } + }; + + /** + * Toggle native controls on/off. Native controls are the controls built into + * devices (e.g. default iPhone controls), Flash, or other techs + * (e.g. Vimeo Controls) + * **This should only be set by the current tech, because only the tech knows + * if it can support native controls** + * + * @fires Player#usingnativecontrols + * @fires Player#usingcustomcontrols + * + * @param {boolean} [bool] + * - true to turn native controls on + * - false to turn native controls off + * + * @return {boolean} + * The current value of native controls when getting + */ + + + Player.prototype.usingNativeControls = function usingNativeControls(bool) { + if (bool === undefined) { + return !!this.usingNativeControls_; + } + + bool = !!bool; + + // Don't trigger a change event unless it actually changed + if (this.usingNativeControls_ === bool) { + return; + } + + this.usingNativeControls_ = bool; + + if (this.usingNativeControls_) { + this.addClass('vjs-using-native-controls'); + + /** + * player is using the native device controls + * + * @event Player#usingnativecontrols + * @type {EventTarget~Event} + */ + this.trigger('usingnativecontrols'); + } else { + this.removeClass('vjs-using-native-controls'); + + /** + * player is using the custom HTML controls + * + * @event Player#usingcustomcontrols + * @type {EventTarget~Event} + */ + this.trigger('usingcustomcontrols'); + } + }; + + /** + * Set or get the current MediaError + * + * @fires Player#error + * + * @param {MediaError|string|number} [err] + * A MediaError or a string/number to be turned + * into a MediaError + * + * @return {MediaError|null} + * The current MediaError when getting (or null) + */ + + + Player.prototype.error = function error(err) { + if (err === undefined) { + return this.error_ || null; + } + + // restoring to default + if (err === null) { + this.error_ = err; + this.removeClass('vjs-error'); + if (this.errorDisplay) { + this.errorDisplay.close(); + } + return; + } + + this.error_ = new MediaError(err); + + // add the vjs-error classname to the player + this.addClass('vjs-error'); + + // log the name of the error type and any message + // IE11 logs "[object object]" and required you to expand message to see error object + log$1.error('(CODE:' + this.error_.code + ' ' + MediaError.errorTypes[this.error_.code] + ')', this.error_.message, this.error_); + + /** + * @event Player#error + * @type {EventTarget~Event} + */ + this.trigger('error'); + + return; + }; + + /** + * Report user activity + * + * @param {Object} event + * Event object + */ + + + Player.prototype.reportUserActivity = function reportUserActivity(event) { + this.userActivity_ = true; + }; + + /** + * Get/set if user is active + * + * @fires Player#useractive + * @fires Player#userinactive + * + * @param {boolean} [bool] + * - true if the user is active + * - false if the user is inactive + * + * @return {boolean} + * The current value of userActive when getting + */ + + + Player.prototype.userActive = function userActive(bool) { + if (bool === undefined) { + return this.userActive_; + } + + bool = !!bool; + + if (bool === this.userActive_) { + return; + } + + this.userActive_ = bool; + + if (this.userActive_) { + this.userActivity_ = true; + this.removeClass('vjs-user-inactive'); + this.addClass('vjs-user-active'); + /** + * @event Player#useractive + * @type {EventTarget~Event} + */ + this.trigger('useractive'); + return; + } + + // Chrome/Safari/IE have bugs where when you change the cursor it can + // trigger a mousemove event. This causes an issue when you're hiding + // the cursor when the user is inactive, and a mousemove signals user + // activity. Making it impossible to go into inactive mode. Specifically + // this happens in fullscreen when we really need to hide the cursor. + // + // When this gets resolved in ALL browsers it can be removed + // https://code.google.com/p/chromium/issues/detail?id=103041 + if (this.tech_) { + this.tech_.one('mousemove', function (e) { + e.stopPropagation(); + e.preventDefault(); + }); + } + + this.userActivity_ = false; + this.removeClass('vjs-user-active'); + this.addClass('vjs-user-inactive'); + /** + * @event Player#userinactive + * @type {EventTarget~Event} + */ + this.trigger('userinactive'); + }; + + /** + * Listen for user activity based on timeout value + * + * @private + */ + + + Player.prototype.listenForUserActivity_ = function listenForUserActivity_() { + var mouseInProgress = void 0; + var lastMoveX = void 0; + var lastMoveY = void 0; + var handleActivity = bind(this, this.reportUserActivity); + + var handleMouseMove = function handleMouseMove(e) { + // #1068 - Prevent mousemove spamming + // Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=366970 + if (e.screenX !== lastMoveX || e.screenY !== lastMoveY) { + lastMoveX = e.screenX; + lastMoveY = e.screenY; + handleActivity(); + } + }; + + var handleMouseDown = function handleMouseDown() { + handleActivity(); + // For as long as the they are touching the device or have their mouse down, + // we consider them active even if they're not moving their finger or mouse. + // So we want to continue to update that they are active + this.clearInterval(mouseInProgress); + // Setting userActivity=true now and setting the interval to the same time + // as the activityCheck interval (250) should ensure we never miss the + // next activityCheck + mouseInProgress = this.setInterval(handleActivity, 250); + }; + + var handleMouseUp = function handleMouseUp(event) { + handleActivity(); + // Stop the interval that maintains activity if the mouse/touch is down + this.clearInterval(mouseInProgress); + }; + + // Any mouse movement will be considered user activity + this.on('mousedown', handleMouseDown); + this.on('mousemove', handleMouseMove); + this.on('mouseup', handleMouseUp); + + // Listen for keyboard navigation + // Shouldn't need to use inProgress interval because of key repeat + this.on('keydown', handleActivity); + this.on('keyup', handleActivity); + + // Run an interval every 250 milliseconds instead of stuffing everything into + // the mousemove/touchmove function itself, to prevent performance degradation. + // `this.reportUserActivity` simply sets this.userActivity_ to true, which + // then gets picked up by this loop + // http://ejohn.org/blog/learning-from-twitter/ + var inactivityTimeout = void 0; + + this.setInterval(function () { + // Check to see if mouse/touch activity has happened + if (!this.userActivity_) { + return; + } + + // Reset the activity tracker + this.userActivity_ = false; + + // If the user state was inactive, set the state to active + this.userActive(true); + + // Clear any existing inactivity timeout to start the timer over + this.clearTimeout(inactivityTimeout); + + var timeout = this.options_.inactivityTimeout; + + if (timeout <= 0) { + return; + } + + // In <timeout> milliseconds, if no more activity has occurred the + // user will be considered inactive + inactivityTimeout = this.setTimeout(function () { + // Protect against the case where the inactivityTimeout can trigger just + // before the next user activity is picked up by the activity check loop + // causing a flicker + if (!this.userActivity_) { + this.userActive(false); + } + }, timeout); + }, 250); + }; + + /** + * Gets or sets the current playback rate. A playback rate of + * 1.0 represents normal speed and 0.5 would indicate half-speed + * playback, for instance. + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate + * + * @param {number} [rate] + * New playback rate to set. + * + * @return {number} + * The current playback rate when getting or 1.0 + */ + + + Player.prototype.playbackRate = function playbackRate(rate) { + if (rate !== undefined) { + // NOTE: this.cache_.lastPlaybackRate is set from the tech handler + // that is registered above + this.techCall_('setPlaybackRate', rate); + return; + } + + if (this.tech_ && this.tech_.featuresPlaybackRate) { + return this.cache_.lastPlaybackRate || this.techGet_('playbackRate'); + } + return 1.0; + }; + + /** + * Gets or sets the current default playback rate. A default playback rate of + * 1.0 represents normal speed and 0.5 would indicate half-speed playback, for instance. + * defaultPlaybackRate will only represent what the initial playbackRate of a video was, not + * not the current playbackRate. + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-defaultplaybackrate + * + * @param {number} [rate] + * New default playback rate to set. + * + * @return {number|Player} + * - The default playback rate when getting or 1.0 + * - the player when setting + */ + + + Player.prototype.defaultPlaybackRate = function defaultPlaybackRate(rate) { + if (rate !== undefined) { + return this.techCall_('setDefaultPlaybackRate', rate); + } + + if (this.tech_ && this.tech_.featuresPlaybackRate) { + return this.techGet_('defaultPlaybackRate'); + } + return 1.0; + }; + + /** + * Gets or sets the audio flag + * + * @param {boolean} bool + * - true signals that this is an audio player + * - false signals that this is not an audio player + * + * @return {boolean} + * The current value of isAudio when getting + */ + + + Player.prototype.isAudio = function isAudio(bool) { + if (bool !== undefined) { + this.isAudio_ = !!bool; + return; + } + + return !!this.isAudio_; + }; + + /** + * A helper method for adding a {@link TextTrack} to our + * {@link TextTrackList}. + * + * In addition to the W3C settings we allow adding additional info through options. + * + * @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack + * + * @param {string} [kind] + * the kind of TextTrack you are adding + * + * @param {string} [label] + * the label to give the TextTrack label + * + * @param {string} [language] + * the language to set on the TextTrack + * + * @return {TextTrack|undefined} + * the TextTrack that was added or undefined + * if there is no tech + */ + + + Player.prototype.addTextTrack = function addTextTrack(kind, label, language) { + if (this.tech_) { + return this.tech_.addTextTrack(kind, label, language); + } + }; + + /** + * Create a remote {@link TextTrack} and an {@link HTMLTrackElement}. It will + * automatically removed from the video element whenever the source changes, unless + * manualCleanup is set to false. + * + * @param {Object} options + * Options to pass to {@link HTMLTrackElement} during creation. See + * {@link HTMLTrackElement} for object properties that you should use. + * + * @param {boolean} [manualCleanup=true] if set to false, the TextTrack will be + * + * @return {HtmlTrackElement} + * the HTMLTrackElement that was created and added + * to the HtmlTrackElementList and the remote + * TextTrackList + * + * @deprecated The default value of the "manualCleanup" parameter will default + * to "false" in upcoming versions of Video.js + */ + + + Player.prototype.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) { + if (this.tech_) { + return this.tech_.addRemoteTextTrack(options, manualCleanup); + } + }; + + /** + * Remove a remote {@link TextTrack} from the respective + * {@link TextTrackList} and {@link HtmlTrackElementList}. + * + * @param {Object} track + * Remote {@link TextTrack} to remove + * + * @return {undefined} + * does not return anything + */ + + + Player.prototype.removeRemoteTextTrack = function removeRemoteTextTrack() { + var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + _ref3$track = _ref3.track, + track = _ref3$track === undefined ? arguments[0] : _ref3$track; + + // destructure the input into an object with a track argument, defaulting to arguments[0] + // default the whole argument to an empty object if nothing was passed in + + if (this.tech_) { + return this.tech_.removeRemoteTextTrack(track); + } + }; + + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} + * + * @return {Object|undefined} + * An object with supported media playback quality metrics or undefined if there + * is no tech or the tech does not support it. + */ + + + Player.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() { + return this.techGet_('getVideoPlaybackQuality'); + }; + + /** + * Get video width + * + * @return {number} + * current video width + */ + + + Player.prototype.videoWidth = function videoWidth() { + return this.tech_ && this.tech_.videoWidth && this.tech_.videoWidth() || 0; + }; + + /** + * Get video height + * + * @return {number} + * current video height + */ + + + Player.prototype.videoHeight = function videoHeight() { + return this.tech_ && this.tech_.videoHeight && this.tech_.videoHeight() || 0; + }; + + /** + * The player's language code + * NOTE: The language should be set in the player options if you want the + * the controls to be built with a specific language. Changing the language + * later will not update controls text. + * + * @param {string} [code] + * the language code to set the player to + * + * @return {string} + * The current language code when getting + */ + + + Player.prototype.language = function language(code) { + if (code === undefined) { + return this.language_; + } + + this.language_ = String(code).toLowerCase(); + }; + + /** + * Get the player's language dictionary + * Merge every time, because a newly added plugin might call videojs.addLanguage() at any time + * Languages specified directly in the player options have precedence + * + * @return {Array} + * An array of of supported languages + */ + + + Player.prototype.languages = function languages() { + return mergeOptions(Player.prototype.options_.languages, this.languages_); + }; + + /** + * returns a JavaScript object reperesenting the current track + * information. **DOES not return it as JSON** + * + * @return {Object} + * Object representing the current of track info + */ + + + Player.prototype.toJSON = function toJSON() { + var options = mergeOptions(this.options_); + var tracks = options.tracks; + + options.tracks = []; + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + // deep merge tracks and null out player so no circular references + track = mergeOptions(track); + track.player = undefined; + options.tracks[i] = track; + } + + return options; + }; + + /** + * Creates a simple modal dialog (an instance of the {@link ModalDialog} + * component) that immediately overlays the player with arbitrary + * content and removes itself when closed. + * + * @param {string|Function|Element|Array|null} content + * Same as {@link ModalDialog#content}'s param of the same name. + * The most straight-forward usage is to provide a string or DOM + * element. + * + * @param {Object} [options] + * Extra options which will be passed on to the {@link ModalDialog}. + * + * @return {ModalDialog} + * the {@link ModalDialog} that was created + */ + + + Player.prototype.createModal = function createModal(content, options) { + var _this10 = this; + + options = options || {}; + options.content = content || ''; + + var modal = new ModalDialog(this, options); + + this.addChild(modal); + modal.on('dispose', function () { + _this10.removeChild(modal); + }); + + modal.open(); + return modal; + }; + + /** + * Gets tag settings + * + * @param {Element} tag + * The player tag + * + * @return {Object} + * An object containing all of the settings + * for a player tag + */ + + + Player.getTagSettings = function getTagSettings(tag) { + var baseOptions = { + sources: [], + tracks: [] + }; + + var tagOptions = getAttributes(tag); + var dataSetup = tagOptions['data-setup']; + + if (hasClass(tag, 'vjs-fluid')) { + tagOptions.fluid = true; + } + + // Check if data-setup attr exists. + if (dataSetup !== null) { + // Parse options JSON + // If empty string, make it a parsable json object. + var _safeParseTuple = tuple(dataSetup || '{}'), + err = _safeParseTuple[0], + data = _safeParseTuple[1]; + + if (err) { + log$1.error(err); + } + assign(tagOptions, data); + } + + assign(baseOptions, tagOptions); + + // Get tag children settings + if (tag.hasChildNodes()) { + var children = tag.childNodes; + + for (var i = 0, j = children.length; i < j; i++) { + var child = children[i]; + // Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/ + var childName = child.nodeName.toLowerCase(); + + if (childName === 'source') { + baseOptions.sources.push(getAttributes(child)); + } else if (childName === 'track') { + baseOptions.tracks.push(getAttributes(child)); + } + } + } + + return baseOptions; + }; + + /** + * Determine whether or not flexbox is supported + * + * @return {boolean} + * - true if flexbox is supported + * - false if flexbox is not supported + */ + + + Player.prototype.flexNotSupported_ = function flexNotSupported_() { + var elem = document_1.createElement('i'); + + // Note: We don't actually use flexBasis (or flexOrder), but it's one of the more + // common flex features that we can rely on when checking for flex support. + return !('flexBasis' in elem.style || 'webkitFlexBasis' in elem.style || 'mozFlexBasis' in elem.style || 'msFlexBasis' in elem.style || + // IE10-specific (2012 flex spec), available for completeness + 'msFlexOrder' in elem.style); + }; + + return Player; + }(Component); + + /** + * Get the {@link VideoTrackList} + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist + * + * @return {VideoTrackList} + * the current video track list + * + * @method Player.prototype.videoTracks + */ + + /** + * Get the {@link AudioTrackList} + * @link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist + * + * @return {AudioTrackList} + * the current audio track list + * + * @method Player.prototype.audioTracks + */ + + /** + * Get the {@link TextTrackList} + * + * @link http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks + * + * @return {TextTrackList} + * the current text track list + * + * @method Player.prototype.textTracks + */ + + /** + * Get the remote {@link TextTrackList} + * + * @return {TextTrackList} + * The current remote text track list + * + * @method Player.prototype.remoteTextTracks + */ + + /** + * Get the remote {@link HtmlTrackElementList} tracks. + * + * @return {HtmlTrackElementList} + * The current remote text track element list + * + * @method Player.prototype.remoteTextTrackEls + */ + + ALL.names.forEach(function (name$$1) { + var props = ALL[name$$1]; + + Player.prototype[props.getterName] = function () { + if (this.tech_) { + return this.tech_[props.getterName](); + } + + // if we have not yet loadTech_, we create {video,audio,text}Tracks_ + // these will be passed to the tech during loading + this[props.privateName] = this[props.privateName] || new props.ListClass(); + return this[props.privateName]; + }; + }); + + /** + * Global player list + * + * @type {Object} + */ + Player.players = {}; + + var navigator = window_1.navigator; + + /* + * Player instance options, surfaced using options + * options = Player.prototype.options_ + * Make changes in options, not here. + * + * @type {Object} + * @private + */ + Player.prototype.options_ = { + // Default order of fallback technology + techOrder: Tech.defaultTechOrder_, + + html5: {}, + flash: {}, + + // default inactivity timeout + inactivityTimeout: 2000, + + // default playback rates + playbackRates: [], + // Add playback rate selection by adding rates + // 'playbackRates': [0.5, 1, 1.5, 2], + + // Included control sets + children: ['mediaLoader', 'posterImage', 'textTrackDisplay', 'loadingSpinner', 'bigPlayButton', 'controlBar', 'errorDisplay', 'textTrackSettings', 'resizeManager'], + + language: navigator && (navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language) || 'en', + + // locales and their language translations + languages: {}, + + // Default message to show when a video cannot be played. + notSupportedMessage: 'No compatible source was found for this media.' + }; + + [ + /** + * Returns whether or not the player is in the "ended" state. + * + * @return {Boolean} True if the player is in the ended state, false if not. + * @method Player#ended + */ + 'ended', + /** + * Returns whether or not the player is in the "seeking" state. + * + * @return {Boolean} True if the player is in the seeking state, false if not. + * @method Player#seeking + */ + 'seeking', + /** + * Returns the TimeRanges of the media that are currently available + * for seeking to. + * + * @return {TimeRanges} the seekable intervals of the media timeline + * @method Player#seekable + */ + 'seekable', + /** + * Returns the current state of network activity for the element, from + * the codes in the list below. + * - NETWORK_EMPTY (numeric value 0) + * The element has not yet been initialised. All attributes are in + * their initial states. + * - NETWORK_IDLE (numeric value 1) + * The element's resource selection algorithm is active and has + * selected a resource, but it is not actually using the network at + * this time. + * - NETWORK_LOADING (numeric value 2) + * The user agent is actively trying to download data. + * - NETWORK_NO_SOURCE (numeric value 3) + * The element's resource selection algorithm is active, but it has + * not yet found a resource to use. + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states + * @return {number} the current network activity state + * @method Player#networkState + */ + 'networkState', + /** + * Returns a value that expresses the current state of the element + * with respect to rendering the current playback position, from the + * codes in the list below. + * - HAVE_NOTHING (numeric value 0) + * No information regarding the media resource is available. + * - HAVE_METADATA (numeric value 1) + * Enough of the resource has been obtained that the duration of the + * resource is available. + * - HAVE_CURRENT_DATA (numeric value 2) + * Data for the immediate current playback position is available. + * - HAVE_FUTURE_DATA (numeric value 3) + * Data for the immediate current playback position is available, as + * well as enough data for the user agent to advance the current + * playback position in the direction of playback. + * - HAVE_ENOUGH_DATA (numeric value 4) + * The user agent estimates that enough data is available for + * playback to proceed uninterrupted. + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate + * @return {number} the current playback rendering state + * @method Player#readyState + */ + 'readyState'].forEach(function (fn) { + Player.prototype[fn] = function () { + return this.techGet_(fn); + }; + }); + + TECH_EVENTS_RETRIGGER.forEach(function (event) { + Player.prototype['handleTech' + toTitleCase(event) + '_'] = function () { + return this.trigger(event); + }; + }); + + /** + * Fired when the player has initial duration and dimension information + * + * @event Player#loadedmetadata + * @type {EventTarget~Event} + */ + + /** + * Fired when the player has downloaded data at the current playback position + * + * @event Player#loadeddata + * @type {EventTarget~Event} + */ + + /** + * Fired when the current playback position has changed * + * During playback this is fired every 15-250 milliseconds, depending on the + * playback technology in use. + * + * @event Player#timeupdate + * @type {EventTarget~Event} + */ + + /** + * Fired when the volume changes + * + * @event Player#volumechange + * @type {EventTarget~Event} + */ + + /** + * Reports whether or not a player has a plugin available. + * + * This does not report whether or not the plugin has ever been initialized + * on this player. For that, [usingPlugin]{@link Player#usingPlugin}. + * + * @method Player#hasPlugin + * @param {string} name + * The name of a plugin. + * + * @return {boolean} + * Whether or not this player has the requested plugin available. + */ + + /** + * Reports whether or not a player is using a plugin by name. + * + * For basic plugins, this only reports whether the plugin has _ever_ been + * initialized on this player. + * + * @method Player#usingPlugin + * @param {string} name + * The name of a plugin. + * + * @return {boolean} + * Whether or not this player is using the requested plugin. + */ + + Component.registerComponent('Player', Player); + + /** + * @file plugin.js + */ + + /** + * The base plugin name. + * + * @private + * @constant + * @type {string} + */ + var BASE_PLUGIN_NAME = 'plugin'; + + /** + * The key on which a player's active plugins cache is stored. + * + * @private + * @constant + * @type {string} + */ + var PLUGIN_CACHE_KEY = 'activePlugins_'; + + /** + * Stores registered plugins in a private space. + * + * @private + * @type {Object} + */ + var pluginStorage = {}; + + /** + * Reports whether or not a plugin has been registered. + * + * @private + * @param {string} name + * The name of a plugin. + * + * @returns {boolean} + * Whether or not the plugin has been registered. + */ + var pluginExists = function pluginExists(name) { + return pluginStorage.hasOwnProperty(name); + }; + + /** + * Get a single registered plugin by name. + * + * @private + * @param {string} name + * The name of a plugin. + * + * @returns {Function|undefined} + * The plugin (or undefined). + */ + var getPlugin = function getPlugin(name) { + return pluginExists(name) ? pluginStorage[name] : undefined; + }; + + /** + * Marks a plugin as "active" on a player. + * + * Also, ensures that the player has an object for tracking active plugins. + * + * @private + * @param {Player} player + * A Video.js player instance. + * + * @param {string} name + * The name of a plugin. + */ + var markPluginAsActive = function markPluginAsActive(player, name) { + player[PLUGIN_CACHE_KEY] = player[PLUGIN_CACHE_KEY] || {}; + player[PLUGIN_CACHE_KEY][name] = true; + }; + + /** + * Triggers a pair of plugin setup events. + * + * @private + * @param {Player} player + * A Video.js player instance. + * + * @param {Plugin~PluginEventHash} hash + * A plugin event hash. + * + * @param {Boolean} [before] + * If true, prefixes the event name with "before". In other words, + * use this to trigger "beforepluginsetup" instead of "pluginsetup". + */ + var triggerSetupEvent = function triggerSetupEvent(player, hash, before) { + var eventName = (before ? 'before' : '') + 'pluginsetup'; + + player.trigger(eventName, hash); + player.trigger(eventName + ':' + hash.name, hash); + }; + + /** + * Takes a basic plugin function and returns a wrapper function which marks + * on the player that the plugin has been activated. + * + * @private + * @param {string} name + * The name of the plugin. + * + * @param {Function} plugin + * The basic plugin. + * + * @returns {Function} + * A wrapper function for the given plugin. + */ + var createBasicPlugin = function createBasicPlugin(name, plugin) { + var basicPluginWrapper = function basicPluginWrapper() { + + // We trigger the "beforepluginsetup" and "pluginsetup" events on the player + // regardless, but we want the hash to be consistent with the hash provided + // for advanced plugins. + // + // The only potentially counter-intuitive thing here is the `instance` in + // the "pluginsetup" event is the value returned by the `plugin` function. + triggerSetupEvent(this, {name: name, plugin: plugin, instance: null}, true); + + var instance = plugin.apply(this, arguments); + + markPluginAsActive(this, name); + triggerSetupEvent(this, {name: name, plugin: plugin, instance: instance}); + + return instance; + }; + + Object.keys(plugin).forEach(function (prop) { + basicPluginWrapper[prop] = plugin[prop]; + }); + + return basicPluginWrapper; + }; + + /** + * Takes a plugin sub-class and returns a factory function for generating + * instances of it. + * + * This factory function will replace itself with an instance of the requested + * sub-class of Plugin. + * + * @private + * @param {string} name + * The name of the plugin. + * + * @param {Plugin} PluginSubClass + * The advanced plugin. + * + * @returns {Function} + */ + var createPluginFactory = function createPluginFactory(name, PluginSubClass) { + + // Add a `name` property to the plugin prototype so that each plugin can + // refer to itself by name. + PluginSubClass.prototype.name = name; + + return function () { + triggerSetupEvent(this, {name: name, plugin: PluginSubClass, instance: null}, true); + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + var instance = new (Function.prototype.bind.apply(PluginSubClass, [null].concat([this].concat(args))))(); + + // The plugin is replaced by a function that returns the current instance. + this[name] = function () { + return instance; + }; + + triggerSetupEvent(this, instance.getEventHash()); + + return instance; + }; + }; + + /** + * Parent class for all advanced plugins. + * + * @mixes module:evented~EventedMixin + * @mixes module:stateful~StatefulMixin + * @fires Player#beforepluginsetup + * @fires Player#beforepluginsetup:$name + * @fires Player#pluginsetup + * @fires Player#pluginsetup:$name + * @listens Player#dispose + * @throws {Error} + * If attempting to instantiate the base {@link Plugin} class + * directly instead of via a sub-class. + */ + + var Plugin = function () { + + /** + * Creates an instance of this class. + * + * Sub-classes should call `super` to ensure plugins are properly initialized. + * + * @param {Player} player + * A Video.js player instance. + */ + function Plugin(player) { + classCallCheck(this, Plugin); + + if (this.constructor === Plugin) { + throw new Error('Plugin must be sub-classed; not directly instantiated.'); + } + + this.player = player; + + // Make this object evented, but remove the added `trigger` method so we + // use the prototype version instead. + evented(this); + delete this.trigger; + + stateful(this, this.constructor.defaultState); + markPluginAsActive(player, this.name); + + // Auto-bind the dispose method so we can use it as a listener and unbind + // it later easily. + this.dispose = bind(this, this.dispose); + + // If the player is disposed, dispose the plugin. + player.on('dispose', this.dispose); + } + + /** + * Get the version of the plugin that was set on <pluginName>.VERSION + */ + + + Plugin.prototype.version = function version() { + return this.constructor.VERSION; + }; + + /** + * Each event triggered by plugins includes a hash of additional data with + * conventional properties. + * + * This returns that object or mutates an existing hash. + * + * @param {Object} [hash={}] + * An object to be used as event an event hash. + * + * @returns {Plugin~PluginEventHash} + * An event hash object with provided properties mixed-in. + */ + + + Plugin.prototype.getEventHash = function getEventHash() { + var hash = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + hash.name = this.name; + hash.plugin = this.constructor; + hash.instance = this; + return hash; + }; + + /** + * Triggers an event on the plugin object and overrides + * {@link module:evented~EventedMixin.trigger|EventedMixin.trigger}. + * + * @param {string|Object} event + * An event type or an object with a type property. + * + * @param {Object} [hash={}] + * Additional data hash to merge with a + * {@link Plugin~PluginEventHash|PluginEventHash}. + * + * @returns {boolean} + * Whether or not default was prevented. + */ + + + Plugin.prototype.trigger = function trigger$$1(event) { + var hash = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + return trigger(this.eventBusEl_, event, this.getEventHash(hash)); + }; + + /** + * Handles "statechanged" events on the plugin. No-op by default, override by + * subclassing. + * + * @abstract + * @param {Event} e + * An event object provided by a "statechanged" event. + * + * @param {Object} e.changes + * An object describing changes that occurred with the "statechanged" + * event. + */ + + + Plugin.prototype.handleStateChanged = function handleStateChanged(e) { + }; + + /** + * Disposes a plugin. + * + * Subclasses can override this if they want, but for the sake of safety, + * it's probably best to subscribe the "dispose" event. + * + * @fires Plugin#dispose + */ + + + Plugin.prototype.dispose = function dispose() { + var name = this.name, + player = this.player; + + /** + * Signals that a advanced plugin is about to be disposed. + * + * @event Plugin#dispose + * @type {EventTarget~Event} + */ + + this.trigger('dispose'); + this.off(); + player.off('dispose', this.dispose); + + // Eliminate any possible sources of leaking memory by clearing up + // references between the player and the plugin instance and nulling out + // the plugin's state and replacing methods with a function that throws. + player[PLUGIN_CACHE_KEY][name] = false; + this.player = this.state = null; + + // Finally, replace the plugin name on the player with a new factory + // function, so that the plugin is ready to be set up again. + player[name] = createPluginFactory(name, pluginStorage[name]); + }; + + /** + * Determines if a plugin is a basic plugin (i.e. not a sub-class of `Plugin`). + * + * @param {string|Function} plugin + * If a string, matches the name of a plugin. If a function, will be + * tested directly. + * + * @returns {boolean} + * Whether or not a plugin is a basic plugin. + */ + + + Plugin.isBasic = function isBasic(plugin) { + var p = typeof plugin === 'string' ? getPlugin(plugin) : plugin; + + return typeof p === 'function' && !Plugin.prototype.isPrototypeOf(p.prototype); + }; + + /** + * Register a Video.js plugin. + * + * @param {string} name + * The name of the plugin to be registered. Must be a string and + * must not match an existing plugin or a method on the `Player` + * prototype. + * + * @param {Function} plugin + * A sub-class of `Plugin` or a function for basic plugins. + * + * @returns {Function} + * For advanced plugins, a factory function for that plugin. For + * basic plugins, a wrapper function that initializes the plugin. + */ + + + Plugin.registerPlugin = function registerPlugin(name, plugin) { + if (typeof name !== 'string') { + throw new Error('Illegal plugin name, "' + name + '", must be a string, was ' + (typeof name === 'undefined' ? 'undefined' : _typeof(name)) + '.'); + } + + if (pluginExists(name)) { + log$1.warn('A plugin named "' + name + '" already exists. You may want to avoid re-registering plugins!'); + } else if (Player.prototype.hasOwnProperty(name)) { + throw new Error('Illegal plugin name, "' + name + '", cannot share a name with an existing player method!'); + } + + if (typeof plugin !== 'function') { + throw new Error('Illegal plugin for "' + name + '", must be a function, was ' + (typeof plugin === 'undefined' ? 'undefined' : _typeof(plugin)) + '.'); + } + + pluginStorage[name] = plugin; + + // Add a player prototype method for all sub-classed plugins (but not for + // the base Plugin class). + if (name !== BASE_PLUGIN_NAME) { + if (Plugin.isBasic(plugin)) { + Player.prototype[name] = createBasicPlugin(name, plugin); + } else { + Player.prototype[name] = createPluginFactory(name, plugin); + } + } + + return plugin; + }; + + /** + * De-register a Video.js plugin. + * + * @param {string} name + * The name of the plugin to be deregistered. + */ + + + Plugin.deregisterPlugin = function deregisterPlugin(name) { + if (name === BASE_PLUGIN_NAME) { + throw new Error('Cannot de-register base plugin.'); + } + if (pluginExists(name)) { + delete pluginStorage[name]; + delete Player.prototype[name]; + } + }; + + /** + * Gets an object containing multiple Video.js plugins. + * + * @param {Array} [names] + * If provided, should be an array of plugin names. Defaults to _all_ + * plugin names. + * + * @returns {Object|undefined} + * An object containing plugin(s) associated with their name(s) or + * `undefined` if no matching plugins exist). + */ + + + Plugin.getPlugins = function getPlugins() { + var names = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Object.keys(pluginStorage); + + var result = void 0; + + names.forEach(function (name) { + var plugin = getPlugin(name); + + if (plugin) { + result = result || {}; + result[name] = plugin; + } + }); + + return result; + }; + + /** + * Gets a plugin's version, if available + * + * @param {string} name + * The name of a plugin. + * + * @returns {string} + * The plugin's version or an empty string. + */ + + + Plugin.getPluginVersion = function getPluginVersion(name) { + var plugin = getPlugin(name); + + return plugin && plugin.VERSION || ''; + }; + + return Plugin; + }(); + + /** + * Gets a plugin by name if it exists. + * + * @static + * @method getPlugin + * @memberOf Plugin + * @param {string} name + * The name of a plugin. + * + * @returns {Function|undefined} + * The plugin (or `undefined`). + */ + + + Plugin.getPlugin = getPlugin; + + /** + * The name of the base plugin class as it is registered. + * + * @type {string} + */ + Plugin.BASE_PLUGIN_NAME = BASE_PLUGIN_NAME; + + Plugin.registerPlugin(BASE_PLUGIN_NAME, Plugin); + + /** + * Documented in player.js + * + * @ignore + */ + Player.prototype.usingPlugin = function (name) { + return !!this[PLUGIN_CACHE_KEY] && this[PLUGIN_CACHE_KEY][name] === true; + }; + + /** + * Documented in player.js + * + * @ignore + */ + Player.prototype.hasPlugin = function (name) { + return !!pluginExists(name); + }; + + /** + * @file extend.js + * @module extend + */ + + /** + * A combination of node inherits and babel's inherits (after transpile). + * Both work the same but node adds `super_` to the subClass + * and Bable adds the superClass as __proto__. Both seem useful. + * + * @param {Object} subClass + * The class to inherit to + * + * @param {Object} superClass + * The class to inherit from + * + * @private + */ + var _inherits = function _inherits(subClass, superClass) { + if (typeof superClass !== 'function' && superClass !== null) { + throw new TypeError('Super expression must either be null or a function, not ' + (typeof superClass === 'undefined' ? 'undefined' : _typeof(superClass))); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + + if (superClass) { + // node + subClass.super_ = superClass; + } + }; + + /** + * Function for subclassing using the same inheritance that + * videojs uses internally + * + * @static + * @const + * + * @param {Object} superClass + * The class to inherit from + * + * @param {Object} [subClassMethods={}] + * The class to inherit to + * + * @return {Object} + * The new object with subClassMethods that inherited superClass. + */ + var extendFn = function extendFn(superClass) { + var subClassMethods = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var subClass = function subClass() { + superClass.apply(this, arguments); + }; + + var methods = {}; + + if ((typeof subClassMethods === 'undefined' ? 'undefined' : _typeof(subClassMethods)) === 'object') { + if (subClassMethods.constructor !== Object.prototype.constructor) { + subClass = subClassMethods.constructor; + } + methods = subClassMethods; + } else if (typeof subClassMethods === 'function') { + subClass = subClassMethods; + } + + _inherits(subClass, superClass); + + // Extend subObj's prototype with functions and other properties from props + for (var name in methods) { + if (methods.hasOwnProperty(name)) { + subClass.prototype[name] = methods[name]; + } + } + + return subClass; + }; + + /** + * @file video.js + * @module videojs + */ + + /** + * Normalize an `id` value by trimming off a leading `#` + * + * @param {string} id + * A string, maybe with a leading `#`. + * + * @returns {string} + * The string, without any leading `#`. + */ + var normalizeId = function normalizeId(id) { + return id.indexOf('#') === 0 ? id.slice(1) : id; + }; + + /** + * Doubles as the main function for users to create a player instance and also + * the main library object. + * The `videojs` function can be used to initialize or retrieve a player. + * + * @param {string|Element} id + * Video element or video element ID + * + * @param {Object} [options] + * Optional options object for config/settings + * + * @param {Component~ReadyCallback} [ready] + * Optional ready callback + * + * @return {Player} + * A player instance + */ + function videojs$1(id, options, ready) { + var player = videojs$1.getPlayer(id); + + if (player) { + if (options) { + log$1.warn('Player "' + id + '" is already initialised. Options will not be applied.'); + } + if (ready) { + player.ready(ready); + } + return player; + } + + var el = typeof id === 'string' ? $('#' + normalizeId(id)) : id; + + if (!isEl(el)) { + throw new TypeError('The element or ID supplied is not valid. (videojs)'); + } + + if (!document_1.body.contains(el)) { + log$1.warn('The element supplied is not included in the DOM'); + } + + options = options || {}; + + videojs$1.hooks('beforesetup').forEach(function (hookFunction) { + var opts = hookFunction(el, mergeOptions(options)); + + if (!isObject(opts) || Array.isArray(opts)) { + log$1.error('please return an object in beforesetup hooks'); + return; + } + + options = mergeOptions(options, opts); + }); + + // We get the current "Player" component here in case an integration has + // replaced it with a custom player. + var PlayerComponent = Component.getComponent('Player'); + + player = new PlayerComponent(el, options, ready); + + videojs$1.hooks('setup').forEach(function (hookFunction) { + return hookFunction(player); + }); + + return player; + } + + /** + * An Object that contains lifecycle hooks as keys which point to an array + * of functions that are run when a lifecycle is triggered + */ + videojs$1.hooks_ = {}; + + /** + * Get a list of hooks for a specific lifecycle + * @function videojs.hooks + * + * @param {string} type + * the lifecyle to get hooks from + * + * @param {Function|Function[]} [fn] + * Optionally add a hook (or hooks) to the lifecycle that your are getting. + * + * @return {Array} + * an array of hooks, or an empty array if there are none. + */ + videojs$1.hooks = function (type, fn) { + videojs$1.hooks_[type] = videojs$1.hooks_[type] || []; + if (fn) { + videojs$1.hooks_[type] = videojs$1.hooks_[type].concat(fn); + } + return videojs$1.hooks_[type]; + }; + + /** + * Add a function hook to a specific videojs lifecycle. + * + * @param {string} type + * the lifecycle to hook the function to. + * + * @param {Function|Function[]} + * The function or array of functions to attach. + */ + videojs$1.hook = function (type, fn) { + videojs$1.hooks(type, fn); + }; + + /** + * Add a function hook that will only run once to a specific videojs lifecycle. + * + * @param {string} type + * the lifecycle to hook the function to. + * + * @param {Function|Function[]} + * The function or array of functions to attach. + */ + videojs$1.hookOnce = function (type, fn) { + videojs$1.hooks(type, [].concat(fn).map(function (original) { + var wrapper = function wrapper() { + videojs$1.removeHook(type, wrapper); + return original.apply(undefined, arguments); + }; + + return wrapper; + })); + }; + + /** + * Remove a hook from a specific videojs lifecycle. + * + * @param {string} type + * the lifecycle that the function hooked to + * + * @param {Function} fn + * The hooked function to remove + * + * @return {boolean} + * The function that was removed or undef + */ + videojs$1.removeHook = function (type, fn) { + var index = videojs$1.hooks(type).indexOf(fn); + + if (index <= -1) { + return false; + } + + videojs$1.hooks_[type] = videojs$1.hooks_[type].slice(); + videojs$1.hooks_[type].splice(index, 1); + + return true; + }; + + // Add default styles + if (window_1.VIDEOJS_NO_DYNAMIC_STYLE !== true && isReal()) { + var style$1 = $('.vjs-styles-defaults'); + + if (!style$1) { + style$1 = createStyleElement('vjs-styles-defaults'); + var head = $('head'); + + if (head) { + head.insertBefore(style$1, head.firstChild); + } + setTextContent(style$1, '\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid {\n padding-top: 56.25%\n }\n '); + } + } + + // Run Auto-load players + // You have to wait at least once in case this script is loaded after your + // video in the DOM (weird behavior only with minified version) + autoSetupTimeout(1, videojs$1); + + /** + * Current software version. Follows semver. + * + * @type {string} + */ + videojs$1.VERSION = version; + + /** + * The global options object. These are the settings that take effect + * if no overrides are specified when the player is created. + * + * @type {Object} + */ + videojs$1.options = Player.prototype.options_; + + /** + * Get an object with the currently created players, keyed by player ID + * + * @return {Object} + * The created players + */ + videojs$1.getPlayers = function () { + return Player.players; + }; + + /** + * Get a single player based on an ID or DOM element. + * + * This is useful if you want to check if an element or ID has an associated + * Video.js player, but not create one if it doesn't. + * + * @param {string|Element} id + * An HTML element - `<video>`, `<audio>`, or `<video-js>` - + * or a string matching the `id` of such an element. + * + * @returns {Player|undefined} + * A player instance or `undefined` if there is no player instance + * matching the argument. + */ + videojs$1.getPlayer = function (id) { + var players = Player.players; + var tag = void 0; + + if (typeof id === 'string') { + var nId = normalizeId(id); + var player = players[nId]; + + if (player) { + return player; + } + + tag = $('#' + nId); + } else { + tag = id; + } + + if (isEl(tag)) { + var _tag = tag, + _player = _tag.player, + playerId = _tag.playerId; + + // Element may have a `player` property referring to an already created + // player instance. If so, return that. + + if (_player || players[playerId]) { + return _player || players[playerId]; + } + } + }; + + /** + * Returns an array of all current players. + * + * @return {Array} + * An array of all players. The array will be in the order that + * `Object.keys` provides, which could potentially vary between + * JavaScript engines. + * + */ + videojs$1.getAllPlayers = function () { + return ( + + // Disposed players leave a key with a `null` value, so we need to make sure + // we filter those out. + Object.keys(Player.players).map(function (k) { + return Player.players[k]; + }).filter(Boolean) + ); + }; + + /** + * Expose players object. + * + * @memberOf videojs + * @property {Object} players + */ + videojs$1.players = Player.players; + + /** + * Get a component class object by name + * + * @borrows Component.getComponent as videojs.getComponent + */ + videojs$1.getComponent = Component.getComponent; + + /** + * Register a component so it can referred to by name. Used when adding to other + * components, either through addChild `component.addChild('myComponent')` or through + * default children options `{ children: ['myComponent'] }`. + * + * > NOTE: You could also just initialize the component before adding. + * `component.addChild(new MyComponent());` + * + * @param {string} name + * The class name of the component + * + * @param {Component} comp + * The component class + * + * @return {Component} + * The newly registered component + */ + videojs$1.registerComponent = function (name$$1, comp) { + if (Tech.isTech(comp)) { + log$1.warn('The ' + name$$1 + ' tech was registered as a component. It should instead be registered using videojs.registerTech(name, tech)'); + } + + Component.registerComponent.call(Component, name$$1, comp); + }; + + /** + * Get a Tech class object by name + * + * @borrows Tech.getTech as videojs.getTech + */ + videojs$1.getTech = Tech.getTech; + + /** + * Register a Tech so it can referred to by name. + * This is used in the tech order for the player. + * + * @borrows Tech.registerTech as videojs.registerTech + */ + videojs$1.registerTech = Tech.registerTech; + + /** + * Register a middleware to a source type. + * + * @param {String} type A string representing a MIME type. + * @param {function(player):object} middleware A middleware factory that takes a player. + */ + videojs$1.use = use; + + /** + * An object that can be returned by a middleware to signify + * that the middleware is being terminated. + * + * @type {object} + * @memberOf {videojs} + * @property {object} middleware.TERMINATOR + */ + Object.defineProperty(videojs$1, 'middleware', { + value: {}, + writeable: false, + enumerable: true + }); + + Object.defineProperty(videojs$1.middleware, 'TERMINATOR', { + value: TERMINATOR, + writeable: false, + enumerable: true + }); + + /** + * A suite of browser and device tests from {@link browser}. + * + * @type {Object} + * @private + */ + videojs$1.browser = browser; + + /** + * Whether or not the browser supports touch events. Included for backward + * compatibility with 4.x, but deprecated. Use `videojs.browser.TOUCH_ENABLED` + * instead going forward. + * + * @deprecated since version 5.0 + * @type {boolean} + */ + videojs$1.TOUCH_ENABLED = TOUCH_ENABLED; + + /** + * Subclass an existing class + * Mimics ES6 subclassing with the `extend` keyword + * + * @borrows extend:extendFn as videojs.extend + */ + videojs$1.extend = extendFn; + + /** + * Merge two options objects recursively + * Performs a deep merge like lodash.merge but **only merges plain objects** + * (not arrays, elements, anything else) + * Other values will be copied directly from the second object. + * + * @borrows merge-options:mergeOptions as videojs.mergeOptions + */ + videojs$1.mergeOptions = mergeOptions; + + /** + * Change the context (this) of a function + * + * > NOTE: as of v5.0 we require an ES5 shim, so you should use the native + * `function() {}.bind(newContext);` instead of this. + * + * @borrows fn:bind as videojs.bind + */ + videojs$1.bind = bind; + + /** + * Register a Video.js plugin. + * + * @borrows plugin:registerPlugin as videojs.registerPlugin + * @method registerPlugin + * + * @param {string} name + * The name of the plugin to be registered. Must be a string and + * must not match an existing plugin or a method on the `Player` + * prototype. + * + * @param {Function} plugin + * A sub-class of `Plugin` or a function for basic plugins. + * + * @return {Function} + * For advanced plugins, a factory function for that plugin. For + * basic plugins, a wrapper function that initializes the plugin. + */ + videojs$1.registerPlugin = Plugin.registerPlugin; + + /** + * Deprecated method to register a plugin with Video.js + * + * @deprecated + * videojs.plugin() is deprecated; use videojs.registerPlugin() instead + * + * @param {string} name + * The plugin name + * + * @param {Plugin|Function} plugin + * The plugin sub-class or function + */ + videojs$1.plugin = function (name$$1, plugin) { + log$1.warn('videojs.plugin() is deprecated; use videojs.registerPlugin() instead'); + return Plugin.registerPlugin(name$$1, plugin); + }; + + /** + * Gets an object containing multiple Video.js plugins. + * + * @param {Array} [names] + * If provided, should be an array of plugin names. Defaults to _all_ + * plugin names. + * + * @return {Object|undefined} + * An object containing plugin(s) associated with their name(s) or + * `undefined` if no matching plugins exist). + */ + videojs$1.getPlugins = Plugin.getPlugins; + + /** + * Gets a plugin by name if it exists. + * + * @param {string} name + * The name of a plugin. + * + * @return {Function|undefined} + * The plugin (or `undefined`). + */ + videojs$1.getPlugin = Plugin.getPlugin; + + /** + * Gets a plugin's version, if available + * + * @param {string} name + * The name of a plugin. + * + * @return {string} + * The plugin's version or an empty string. + */ + videojs$1.getPluginVersion = Plugin.getPluginVersion; + + /** + * Adding languages so that they're available to all players. + * Example: `videojs.addLanguage('es', { 'Hello': 'Hola' });` + * + * @param {string} code + * The language code or dictionary property + * + * @param {Object} data + * The data values to be translated + * + * @return {Object} + * The resulting language dictionary object + */ + videojs$1.addLanguage = function (code, data) { + var _mergeOptions; + + code = ('' + code).toLowerCase(); + + videojs$1.options.languages = mergeOptions(videojs$1.options.languages, (_mergeOptions = {}, _mergeOptions[code] = data, _mergeOptions)); + + return videojs$1.options.languages[code]; + }; + + /** + * Log messages + * + * @borrows log:log as videojs.log + */ + videojs$1.log = log$1; + + /** + * Creates an emulated TimeRange object. + * + * @borrows time-ranges:createTimeRanges as videojs.createTimeRange + */ + /** + * @borrows time-ranges:createTimeRanges as videojs.createTimeRanges + */ + videojs$1.createTimeRange = videojs$1.createTimeRanges = createTimeRanges; + + /** + * Format seconds as a time string, H:MM:SS or M:SS + * Supplying a guide (in seconds) will force a number of leading zeros + * to cover the length of the guide + * + * @borrows format-time:formatTime as videojs.formatTime + */ + videojs$1.formatTime = formatTime; + + /** + * Replaces format-time with a custom implementation, to be used in place of the default. + * + * @borrows format-time:setFormatTime as videojs.setFormatTime + * + * @method setFormatTime + * + * @param {Function} customFn + * A custom format-time function which will be called with the current time and guide (in seconds) as arguments. + * Passed fn should return a string. + */ + videojs$1.setFormatTime = setFormatTime; + + /** + * Resets format-time to the default implementation. + * + * @borrows format-time:resetFormatTime as videojs.resetFormatTime + * + * @method resetFormatTime + */ + videojs$1.resetFormatTime = resetFormatTime; + + /** + * Resolve and parse the elements of a URL + * + * @borrows url:parseUrl as videojs.parseUrl + * + */ + videojs$1.parseUrl = parseUrl; + + /** + * Returns whether the url passed is a cross domain request or not. + * + * @borrows url:isCrossOrigin as videojs.isCrossOrigin + */ + videojs$1.isCrossOrigin = isCrossOrigin; + + /** + * Event target class. + * + * @borrows EventTarget as videojs.EventTarget + */ + videojs$1.EventTarget = EventTarget; + + /** + * Add an event listener to element + * It stores the handler function in a separate cache object + * and adds a generic handler to the element's event, + * along with a unique id (guid) to the element. + * + * @borrows events:on as videojs.on + */ + videojs$1.on = on; + + /** + * Trigger a listener only once for an event + * + * @borrows events:one as videojs.one + */ + videojs$1.one = one; + + /** + * Removes event listeners from an element + * + * @borrows events:off as videojs.off + */ + videojs$1.off = off; + + /** + * Trigger an event for an element + * + * @borrows events:trigger as videojs.trigger + */ + videojs$1.trigger = trigger; + + /** + * A cross-browser XMLHttpRequest wrapper. Here's a simple example: + * + * @param {Object} options + * settings for the request. + * + * @return {XMLHttpRequest|XDomainRequest} + * The request object. + * + * @see https://github.com/Raynos/xhr + */ + videojs$1.xhr = xhr; + + /** + * TextTrack class + * + * @borrows TextTrack as videojs.TextTrack + */ + videojs$1.TextTrack = TextTrack; + + /** + * export the AudioTrack class so that source handlers can create + * AudioTracks and then add them to the players AudioTrackList + * + * @borrows AudioTrack as videojs.AudioTrack + */ + videojs$1.AudioTrack = AudioTrack; + + /** + * export the VideoTrack class so that source handlers can create + * VideoTracks and then add them to the players VideoTrackList + * + * @borrows VideoTrack as videojs.VideoTrack + */ + videojs$1.VideoTrack = VideoTrack; + + /** + * Determines, via duck typing, whether or not a value is a DOM element. + * + * @borrows dom:isEl as videojs.isEl + * @deprecated Use videojs.dom.isEl() instead + */ + + /** + * Determines, via duck typing, whether or not a value is a text node. + * + * @borrows dom:isTextNode as videojs.isTextNode + * @deprecated Use videojs.dom.isTextNode() instead + */ + + /** + * Creates an element and applies properties. + * + * @borrows dom:createEl as videojs.createEl + * @deprecated Use videojs.dom.createEl() instead + */ + + /** + * Check if an element has a CSS class + * + * @borrows dom:hasElClass as videojs.hasClass + * @deprecated Use videojs.dom.hasClass() instead + */ + + /** + * Add a CSS class name to an element + * + * @borrows dom:addElClass as videojs.addClass + * @deprecated Use videojs.dom.addClass() instead + */ + + /** + * Remove a CSS class name from an element + * + * @borrows dom:removeElClass as videojs.removeClass + * @deprecated Use videojs.dom.removeClass() instead + */ + + /** + * Adds or removes a CSS class name on an element depending on an optional + * condition or the presence/absence of the class name. + * + * @borrows dom:toggleElClass as videojs.toggleClass + * @deprecated Use videojs.dom.toggleClass() instead + */ + + /** + * Apply attributes to an HTML element. + * + * @borrows dom:setElAttributes as videojs.setAttribute + * @deprecated Use videojs.dom.setAttributes() instead + */ + + /** + * Get an element's attribute values, as defined on the HTML tag + * Attributes are not the same as properties. They're defined on the tag + * or with setAttribute (which shouldn't be used with HTML) + * This will return true or false for boolean attributes. + * + * @borrows dom:getElAttributes as videojs.getAttributes + * @deprecated Use videojs.dom.getAttributes() instead + */ + + /** + * Empties the contents of an element. + * + * @borrows dom:emptyEl as videojs.emptyEl + * @deprecated Use videojs.dom.emptyEl() instead + */ + + /** + * Normalizes and appends content to an element. + * + * The content for an element can be passed in multiple types and + * combinations, whose behavior is as follows: + * + * - String + * Normalized into a text node. + * + * - Element, TextNode + * Passed through. + * + * - Array + * A one-dimensional array of strings, elements, nodes, or functions (which + * return single strings, elements, or nodes). + * + * - Function + * If the sole argument, is expected to produce a string, element, + * node, or array. + * + * @borrows dom:appendContents as videojs.appendContet + * @deprecated Use videojs.dom.appendContent() instead + */ + + /** + * Normalizes and inserts content into an element; this is identical to + * `appendContent()`, except it empties the element first. + * + * The content for an element can be passed in multiple types and + * combinations, whose behavior is as follows: + * + * - String + * Normalized into a text node. + * + * - Element, TextNode + * Passed through. + * + * - Array + * A one-dimensional array of strings, elements, nodes, or functions (which + * return single strings, elements, or nodes). + * + * - Function + * If the sole argument, is expected to produce a string, element, + * node, or array. + * + * @borrows dom:insertContent as videojs.insertContent + * @deprecated Use videojs.dom.insertContent() instead + */ + ['isEl', 'isTextNode', 'createEl', 'hasClass', 'addClass', 'removeClass', 'toggleClass', 'setAttributes', 'getAttributes', 'emptyEl', 'appendContent', 'insertContent'].forEach(function (k) { + videojs$1[k] = function () { + log$1.warn('videojs.' + k + '() is deprecated; use videojs.dom.' + k + '() instead'); + return Dom[k].apply(null, arguments); + }; + }); + + /** + * A safe getComputedStyle. + * + * This is because in Firefox, if the player is loaded in an iframe with `display:none`, + * then `getComputedStyle` returns `null`, so, we do a null-check to make sure + * that the player doesn't break in these cases. + * See https://bugzilla.mozilla.org/show_bug.cgi?id=548397 for more details. + * + * @borrows computed-style:computedStyle as videojs.computedStyle + */ + videojs$1.computedStyle = computedStyle; + + /** + * Export the Dom utilities for use in external plugins + * and Tech's + */ + videojs$1.dom = Dom; + + /** + * Export the Url utilities for use in external plugins + * and Tech's + */ + videojs$1.url = Url; + + var urlToolkit = createCommonjsModule(function (module, exports) { + // see https://tools.ietf.org/html/rfc1808 + + /* jshint ignore:start */ + (function (root) { + /* jshint ignore:end */ + + var URL_REGEX = /^((?:[a-zA-Z0-9+\-.]+:)?)(\/\/[^\/\;?#]*)?(.*?)??(;.*?)?(\?.*?)?(#.*?)?$/; + var FIRST_SEGMENT_REGEX = /^([^\/;?#]*)(.*)$/; + var SLASH_DOT_REGEX = /(?:\/|^)\.(?=\/)/g; + var SLASH_DOT_DOT_REGEX = /(?:\/|^)\.\.\/(?!\.\.\/).*?(?=\/)/g; + + var URLToolkit = { // jshint ignore:line + // If opts.alwaysNormalize is true then the path will always be normalized even when it starts with / or // + // E.g + // With opts.alwaysNormalize = false (default, spec compliant) + // http://a.com/b/cd + /e/f/../g => http://a.com/e/f/../g + // With opts.alwaysNormalize = true (not spec compliant) + // http://a.com/b/cd + /e/f/../g => http://a.com/e/g + buildAbsoluteURL: function buildAbsoluteURL(baseURL, relativeURL, opts) { + opts = opts || {}; + // remove any remaining space and CRLF + baseURL = baseURL.trim(); + relativeURL = relativeURL.trim(); + if (!relativeURL) { + // 2a) If the embedded URL is entirely empty, it inherits the + // entire base URL (i.e., is set equal to the base URL) + // and we are done. + if (!opts.alwaysNormalize) { + return baseURL; + } + var basePartsForNormalise = URLToolkit.parseURL(baseURL); + if (!basePartsForNormalise) { + throw new Error('Error trying to parse base URL.'); + } + basePartsForNormalise.path = URLToolkit.normalizePath(basePartsForNormalise.path); + return URLToolkit.buildURLFromParts(basePartsForNormalise); + } + var relativeParts = URLToolkit.parseURL(relativeURL); + if (!relativeParts) { + throw new Error('Error trying to parse relative URL.'); + } + if (relativeParts.scheme) { + // 2b) If the embedded URL starts with a scheme name, it is + // interpreted as an absolute URL and we are done. + if (!opts.alwaysNormalize) { + return relativeURL; + } + relativeParts.path = URLToolkit.normalizePath(relativeParts.path); + return URLToolkit.buildURLFromParts(relativeParts); + } + var baseParts = URLToolkit.parseURL(baseURL); + if (!baseParts) { + throw new Error('Error trying to parse base URL.'); + } + if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') { + // If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc + // This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a' + var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path); + baseParts.netLoc = pathParts[1]; + baseParts.path = pathParts[2]; + } + if (baseParts.netLoc && !baseParts.path) { + baseParts.path = '/'; + } + var builtParts = { + // 2c) Otherwise, the embedded URL inherits the scheme of + // the base URL. + scheme: baseParts.scheme, + netLoc: relativeParts.netLoc, + path: null, + params: relativeParts.params, + query: relativeParts.query, + fragment: relativeParts.fragment + }; + if (!relativeParts.netLoc) { + // 3) If the embedded URL's <net_loc> is non-empty, we skip to + // Step 7. Otherwise, the embedded URL inherits the <net_loc> + // (if any) of the base URL. + builtParts.netLoc = baseParts.netLoc; + // 4) If the embedded URL path is preceded by a slash "/", the + // path is not relative and we skip to Step 7. + if (relativeParts.path[0] !== '/') { + if (!relativeParts.path) { + // 5) If the embedded URL path is empty (and not preceded by a + // slash), then the embedded URL inherits the base URL path + builtParts.path = baseParts.path; + // 5a) if the embedded URL's <params> is non-empty, we skip to + // step 7; otherwise, it inherits the <params> of the base + // URL (if any) and + if (!relativeParts.params) { + builtParts.params = baseParts.params; + // 5b) if the embedded URL's <query> is non-empty, we skip to + // step 7; otherwise, it inherits the <query> of the base + // URL (if any) and we skip to step 7. + if (!relativeParts.query) { + builtParts.query = baseParts.query; + } + } + } else { + // 6) The last segment of the base URL's path (anything + // following the rightmost slash "/", or the entire path if no + // slash is present) is removed and the embedded URL's path is + // appended in its place. + var baseURLPath = baseParts.path; + var newPath = baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) + relativeParts.path; + builtParts.path = URLToolkit.normalizePath(newPath); + } + } + } + if (builtParts.path === null) { + builtParts.path = opts.alwaysNormalize ? URLToolkit.normalizePath(relativeParts.path) : relativeParts.path; + } + return URLToolkit.buildURLFromParts(builtParts); + }, + parseURL: function parseURL(url) { + var parts = URL_REGEX.exec(url); + if (!parts) { + return null; + } + return { + scheme: parts[1] || '', + netLoc: parts[2] || '', + path: parts[3] || '', + params: parts[4] || '', + query: parts[5] || '', + fragment: parts[6] || '' + }; + }, + normalizePath: function normalizePath(path) { + // The following operations are + // then applied, in order, to the new path: + // 6a) All occurrences of "./", where "." is a complete path + // segment, are removed. + // 6b) If the path ends with "." as a complete path segment, + // that "." is removed. + path = path.split('').reverse().join('').replace(SLASH_DOT_REGEX, ''); + // 6c) All occurrences of "<segment>/../", where <segment> is a + // complete path segment not equal to "..", are removed. + // Removal of these path segments is performed iteratively, + // removing the leftmost matching pattern on each iteration, + // until no matching pattern remains. + // 6d) If the path ends with "<segment>/..", where <segment> is a + // complete path segment not equal to "..", that + // "<segment>/.." is removed. + while (path.length !== (path = path.replace(SLASH_DOT_DOT_REGEX, '')).length) { + } // jshint ignore:line + return path.split('').reverse().join(''); + }, + buildURLFromParts: function buildURLFromParts(parts) { + return parts.scheme + parts.netLoc + parts.path + parts.params + parts.query + parts.fragment; + } + }; + + /* jshint ignore:start */ + module.exports = URLToolkit; + })(commonjsGlobal); + /* jshint ignore:end */ + }); + + var classCallCheck$1 = function classCallCheck$$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + var _extends$1 = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + var inherits$1 = function inherits$$1(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : _typeof(superClass))); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + }; + + var possibleConstructorReturn$1 = function possibleConstructorReturn$$1(self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && ((typeof call === "undefined" ? "undefined" : _typeof(call)) === "object" || typeof call === "function") ? call : self; + }; + + /** + * @file stream.js + */ + /** + * A lightweight readable stream implemention that handles event dispatching. + * + * @class Stream + */ + var Stream = function () { + function Stream() { + classCallCheck$1(this, Stream); + + this.listeners = {}; + } + + /** + * Add a listener for a specified event type. + * + * @param {String} type the event name + * @param {Function} listener the callback to be invoked when an event of + * the specified type occurs + */ + + Stream.prototype.on = function on(type, listener) { + if (!this.listeners[type]) { + this.listeners[type] = []; + } + this.listeners[type].push(listener); + }; + + /** + * Remove a listener for a specified event type. + * + * @param {String} type the event name + * @param {Function} listener a function previously registered for this + * type of event through `on` + * @return {Boolean} if we could turn it off or not + */ + + Stream.prototype.off = function off(type, listener) { + if (!this.listeners[type]) { + return false; + } + + var index = this.listeners[type].indexOf(listener); + + this.listeners[type].splice(index, 1); + return index > -1; + }; + + /** + * Trigger an event of the specified type on this stream. Any additional + * arguments to this function are passed as parameters to event listeners. + * + * @param {String} type the event name + */ + + Stream.prototype.trigger = function trigger(type) { + var callbacks = this.listeners[type]; + var i = void 0; + var length = void 0; + var args = void 0; + + if (!callbacks) { + return; + } + // Slicing the arguments on every invocation of this method + // can add a significant amount of overhead. Avoid the + // intermediate object creation for the common case of a + // single callback argument + if (arguments.length === 2) { + length = callbacks.length; + for (i = 0; i < length; ++i) { + callbacks[i].call(this, arguments[1]); + } + } else { + args = Array.prototype.slice.call(arguments, 1); + length = callbacks.length; + for (i = 0; i < length; ++i) { + callbacks[i].apply(this, args); + } + } + }; + + /** + * Destroys the stream and cleans up. + */ + + Stream.prototype.dispose = function dispose() { + this.listeners = {}; + }; + /** + * Forwards all `data` events on this stream to the destination stream. The + * destination stream should provide a method `push` to receive the data + * events as they arrive. + * + * @param {Stream} destination the stream that will receive all `data` events + * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options + */ + + Stream.prototype.pipe = function pipe(destination) { + this.on('data', function (data) { + destination.push(data); + }); + }; + + return Stream; + }(); + + /** + * @file m3u8/line-stream.js + */ + /** + * A stream that buffers string input and generates a `data` event for each + * line. + * + * @class LineStream + * @extends Stream + */ + + var LineStream = function (_Stream) { + inherits$1(LineStream, _Stream); + + function LineStream() { + classCallCheck$1(this, LineStream); + + var _this = possibleConstructorReturn$1(this, _Stream.call(this)); + + _this.buffer = ''; + return _this; + } + + /** + * Add new data to be parsed. + * + * @param {String} data the text to process + */ + + LineStream.prototype.push = function push(data) { + var nextNewline = void 0; + + this.buffer += data; + nextNewline = this.buffer.indexOf('\n'); + + for (; nextNewline > -1; nextNewline = this.buffer.indexOf('\n')) { + this.trigger('data', this.buffer.substring(0, nextNewline)); + this.buffer = this.buffer.substring(nextNewline + 1); + } + }; + + return LineStream; + }(Stream); + + /** + * @file m3u8/parse-stream.js + */ + /** + * "forgiving" attribute list psuedo-grammar: + * attributes -> keyvalue (',' keyvalue)* + * keyvalue -> key '=' value + * key -> [^=]* + * value -> '"' [^"]* '"' | [^,]* + */ + var attributeSeparator = function attributeSeparator() { + var key = '[^=]*'; + var value = '"[^"]*"|[^,]*'; + var keyvalue = '(?:' + key + ')=(?:' + value + ')'; + + return new RegExp('(?:^|,)(' + keyvalue + ')'); + }; + + /** + * Parse attributes from a line given the seperator + * + * @param {String} attributes the attibute line to parse + */ + var parseAttributes = function parseAttributes(attributes) { + // split the string using attributes as the separator + var attrs = attributes.split(attributeSeparator()); + var result = {}; + var i = attrs.length; + var attr = void 0; + + while (i--) { + // filter out unmatched portions of the string + if (attrs[i] === '') { + continue; + } + + // split the key and value + attr = /([^=]*)=(.*)/.exec(attrs[i]).slice(1); + // trim whitespace and remove optional quotes around the value + attr[0] = attr[0].replace(/^\s+|\s+$/g, ''); + attr[1] = attr[1].replace(/^\s+|\s+$/g, ''); + attr[1] = attr[1].replace(/^['"](.*)['"]$/g, '$1'); + result[attr[0]] = attr[1]; + } + return result; + }; + + /** + * A line-level M3U8 parser event stream. It expects to receive input one + * line at a time and performs a context-free parse of its contents. A stream + * interpretation of a manifest can be useful if the manifest is expected to + * be too large to fit comfortably into memory or the entirety of the input + * is not immediately available. Otherwise, it's probably much easier to work + * with a regular `Parser` object. + * + * Produces `data` events with an object that captures the parser's + * interpretation of the input. That object has a property `tag` that is one + * of `uri`, `comment`, or `tag`. URIs only have a single additional + * property, `line`, which captures the entirety of the input without + * interpretation. Comments similarly have a single additional property + * `text` which is the input without the leading `#`. + * + * Tags always have a property `tagType` which is the lower-cased version of + * the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance, + * `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized + * tags are given the tag type `unknown` and a single additional property + * `data` with the remainder of the input. + * + * @class ParseStream + * @extends Stream + */ + + var ParseStream = function (_Stream) { + inherits$1(ParseStream, _Stream); + + function ParseStream() { + classCallCheck$1(this, ParseStream); + + var _this = possibleConstructorReturn$1(this, _Stream.call(this)); + + _this.customParsers = []; + return _this; + } + + /** + * Parses an additional line of input. + * + * @param {String} line a single line of an M3U8 file to parse + */ + + ParseStream.prototype.push = function push(line) { + var match = void 0; + var event = void 0; + + // strip whitespace + line = line.replace(/^[\u0000\s]+|[\u0000\s]+$/g, ''); + if (line.length === 0) { + // ignore empty lines + return; + } + + // URIs + if (line[0] !== '#') { + this.trigger('data', { + type: 'uri', + uri: line + }); + return; + } + + for (var i = 0; i < this.customParsers.length; i++) { + if (this.customParsers[i].call(this, line)) { + return; + } + } + + // Comments + if (line.indexOf('#EXT') !== 0) { + this.trigger('data', { + type: 'comment', + text: line.slice(1) + }); + return; + } + + // strip off any carriage returns here so the regex matching + // doesn't have to account for them. + line = line.replace('\r', ''); + + // Tags + match = /^#EXTM3U/.exec(line); + if (match) { + this.trigger('data', { + type: 'tag', + tagType: 'm3u' + }); + return; + } + match = /^#EXTINF:?([0-9\.]*)?,?(.*)?$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'inf' + }; + if (match[1]) { + event.duration = parseFloat(match[1]); + } + if (match[2]) { + event.title = match[2]; + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-TARGETDURATION:?([0-9.]*)?/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'targetduration' + }; + if (match[1]) { + event.duration = parseInt(match[1], 10); + } + this.trigger('data', event); + return; + } + match = /^#ZEN-TOTAL-DURATION:?([0-9.]*)?/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'totalduration' + }; + if (match[1]) { + event.duration = parseInt(match[1], 10); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-VERSION:?([0-9.]*)?/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'version' + }; + if (match[1]) { + event.version = parseInt(match[1], 10); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-MEDIA-SEQUENCE:?(\-?[0-9.]*)?/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'media-sequence' + }; + if (match[1]) { + event.number = parseInt(match[1], 10); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-DISCONTINUITY-SEQUENCE:?(\-?[0-9.]*)?/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'discontinuity-sequence' + }; + if (match[1]) { + event.number = parseInt(match[1], 10); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-PLAYLIST-TYPE:?(.*)?$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'playlist-type' + }; + if (match[1]) { + event.playlistType = match[1]; + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-BYTERANGE:?([0-9.]*)?@?([0-9.]*)?/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'byterange' + }; + if (match[1]) { + event.length = parseInt(match[1], 10); + } + if (match[2]) { + event.offset = parseInt(match[2], 10); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-ALLOW-CACHE:?(YES|NO)?/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'allow-cache' + }; + if (match[1]) { + event.allowed = !/NO/.test(match[1]); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-MAP:?(.*)$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'map' + }; + + if (match[1]) { + var attributes = parseAttributes(match[1]); + + if (attributes.URI) { + event.uri = attributes.URI; + } + if (attributes.BYTERANGE) { + var _attributes$BYTERANGE = attributes.BYTERANGE.split('@'), + length = _attributes$BYTERANGE[0], + offset = _attributes$BYTERANGE[1]; + + event.byterange = {}; + if (length) { + event.byterange.length = parseInt(length, 10); + } + if (offset) { + event.byterange.offset = parseInt(offset, 10); + } + } + } + + this.trigger('data', event); + return; + } + match = /^#EXT-X-STREAM-INF:?(.*)$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'stream-inf' + }; + if (match[1]) { + event.attributes = parseAttributes(match[1]); + + if (event.attributes.RESOLUTION) { + var split = event.attributes.RESOLUTION.split('x'); + var resolution = {}; + + if (split[0]) { + resolution.width = parseInt(split[0], 10); + } + if (split[1]) { + resolution.height = parseInt(split[1], 10); + } + event.attributes.RESOLUTION = resolution; + } + if (event.attributes.BANDWIDTH) { + event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10); + } + if (event.attributes['PROGRAM-ID']) { + event.attributes['PROGRAM-ID'] = parseInt(event.attributes['PROGRAM-ID'], 10); + } + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-MEDIA:?(.*)$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'media' + }; + if (match[1]) { + event.attributes = parseAttributes(match[1]); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-ENDLIST/.exec(line); + if (match) { + this.trigger('data', { + type: 'tag', + tagType: 'endlist' + }); + return; + } + match = /^#EXT-X-DISCONTINUITY/.exec(line); + if (match) { + this.trigger('data', { + type: 'tag', + tagType: 'discontinuity' + }); + return; + } + match = /^#EXT-X-PROGRAM-DATE-TIME:?(.*)$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'program-date-time' + }; + if (match[1]) { + event.dateTimeString = match[1]; + event.dateTimeObject = new Date(match[1]); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-KEY:?(.*)$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'key' + }; + if (match[1]) { + event.attributes = parseAttributes(match[1]); + // parse the IV string into a Uint32Array + if (event.attributes.IV) { + if (event.attributes.IV.substring(0, 2).toLowerCase() === '0x') { + event.attributes.IV = event.attributes.IV.substring(2); + } + + event.attributes.IV = event.attributes.IV.match(/.{8}/g); + event.attributes.IV[0] = parseInt(event.attributes.IV[0], 16); + event.attributes.IV[1] = parseInt(event.attributes.IV[1], 16); + event.attributes.IV[2] = parseInt(event.attributes.IV[2], 16); + event.attributes.IV[3] = parseInt(event.attributes.IV[3], 16); + event.attributes.IV = new Uint32Array(event.attributes.IV); + } + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-START:?(.*)$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'start' + }; + if (match[1]) { + event.attributes = parseAttributes(match[1]); + + event.attributes['TIME-OFFSET'] = parseFloat(event.attributes['TIME-OFFSET']); + event.attributes.PRECISE = /YES/.test(event.attributes.PRECISE); + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-CUE-OUT-CONT:?(.*)?$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'cue-out-cont' + }; + if (match[1]) { + event.data = match[1]; + } else { + event.data = ''; + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-CUE-OUT:?(.*)?$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'cue-out' + }; + if (match[1]) { + event.data = match[1]; + } else { + event.data = ''; + } + this.trigger('data', event); + return; + } + match = /^#EXT-X-CUE-IN:?(.*)?$/.exec(line); + if (match) { + event = { + type: 'tag', + tagType: 'cue-in' + }; + if (match[1]) { + event.data = match[1]; + } else { + event.data = ''; + } + this.trigger('data', event); + return; + } + + // unknown tag type + this.trigger('data', { + type: 'tag', + data: line.slice(4) + }); + }; + + /** + * Add a parser for custom headers + * + * @param {Object} options a map of options for the added parser + * @param {RegExp} options.expression a regular expression to match the custom header + * @param {string} options.customType the custom type to register to the output + * @param {Function} [options.dataParser] function to parse the line into an object + * @param {boolean} [options.segment] should tag data be attached to the segment object + */ + + ParseStream.prototype.addParser = function addParser(_ref) { + var _this2 = this; + + var expression = _ref.expression, + customType = _ref.customType, + dataParser = _ref.dataParser, + segment = _ref.segment; + + if (typeof dataParser !== 'function') { + dataParser = function dataParser(line) { + return line; + }; + } + this.customParsers.push(function (line) { + var match = expression.exec(line); + + if (match) { + _this2.trigger('data', { + type: 'custom', + data: dataParser(line), + customType: customType, + segment: segment + }); + return true; + } + }); + }; + + return ParseStream; + }(Stream); + + /** + * @file m3u8/parser.js + */ + /** + * A parser for M3U8 files. The current interpretation of the input is + * exposed as a property `manifest` on parser objects. It's just two lines to + * create and parse a manifest once you have the contents available as a string: + * + * ```js + * var parser = new m3u8.Parser(); + * parser.push(xhr.responseText); + * ``` + * + * New input can later be applied to update the manifest object by calling + * `push` again. + * + * The parser attempts to create a usable manifest object even if the + * underlying input is somewhat nonsensical. It emits `info` and `warning` + * events during the parse if it encounters input that seems invalid or + * requires some property of the manifest object to be defaulted. + * + * @class Parser + * @extends Stream + */ + + var Parser = function (_Stream) { + inherits$1(Parser, _Stream); + + function Parser() { + classCallCheck$1(this, Parser); + + var _this = possibleConstructorReturn$1(this, _Stream.call(this)); + + _this.lineStream = new LineStream(); + _this.parseStream = new ParseStream(); + _this.lineStream.pipe(_this.parseStream); + + /* eslint-disable consistent-this */ + var self = _this; + /* eslint-enable consistent-this */ + var uris = []; + var currentUri = {}; + // if specified, the active EXT-X-MAP definition + var currentMap = void 0; + // if specified, the active decryption key + var _key = void 0; + var noop = function noop() { + }; + var defaultMediaGroups = { + 'AUDIO': {}, + 'VIDEO': {}, + 'CLOSED-CAPTIONS': {}, + 'SUBTITLES': {} + }; + // group segments into numbered timelines delineated by discontinuities + var currentTimeline = 0; + + // the manifest is empty until the parse stream begins delivering data + _this.manifest = { + allowCache: true, + discontinuityStarts: [], + segments: [] + }; + + // update the manifest with the m3u8 entry from the parse stream + _this.parseStream.on('data', function (entry) { + var mediaGroup = void 0; + var rendition = void 0; + + ({ + tag: function tag() { + // switch based on the tag type + (({ + 'allow-cache': function allowCache() { + this.manifest.allowCache = entry.allowed; + if (!('allowed' in entry)) { + this.trigger('info', { + message: 'defaulting allowCache to YES' + }); + this.manifest.allowCache = true; + } + }, + byterange: function byterange() { + var byterange = {}; + + if ('length' in entry) { + currentUri.byterange = byterange; + byterange.length = entry.length; + + if (!('offset' in entry)) { + this.trigger('info', { + message: 'defaulting offset to zero' + }); + entry.offset = 0; + } + } + if ('offset' in entry) { + currentUri.byterange = byterange; + byterange.offset = entry.offset; + } + }, + endlist: function endlist() { + this.manifest.endList = true; + }, + inf: function inf() { + if (!('mediaSequence' in this.manifest)) { + this.manifest.mediaSequence = 0; + this.trigger('info', { + message: 'defaulting media sequence to zero' + }); + } + if (!('discontinuitySequence' in this.manifest)) { + this.manifest.discontinuitySequence = 0; + this.trigger('info', { + message: 'defaulting discontinuity sequence to zero' + }); + } + if (entry.duration > 0) { + currentUri.duration = entry.duration; + } + + if (entry.duration === 0) { + currentUri.duration = 0.01; + this.trigger('info', { + message: 'updating zero segment duration to a small value' + }); + } + + this.manifest.segments = uris; + }, + key: function key() { + if (!entry.attributes) { + this.trigger('warn', { + message: 'ignoring key declaration without attribute list' + }); + return; + } + // clear the active encryption key + if (entry.attributes.METHOD === 'NONE') { + _key = null; + return; + } + if (!entry.attributes.URI) { + this.trigger('warn', { + message: 'ignoring key declaration without URI' + }); + return; + } + if (!entry.attributes.METHOD) { + this.trigger('warn', { + message: 'defaulting key method to AES-128' + }); + } + + // setup an encryption key for upcoming segments + _key = { + method: entry.attributes.METHOD || 'AES-128', + uri: entry.attributes.URI + }; + + if (typeof entry.attributes.IV !== 'undefined') { + _key.iv = entry.attributes.IV; + } + }, + 'media-sequence': function mediaSequence() { + if (!isFinite(entry.number)) { + this.trigger('warn', { + message: 'ignoring invalid media sequence: ' + entry.number + }); + return; + } + this.manifest.mediaSequence = entry.number; + }, + 'discontinuity-sequence': function discontinuitySequence() { + if (!isFinite(entry.number)) { + this.trigger('warn', { + message: 'ignoring invalid discontinuity sequence: ' + entry.number + }); + return; + } + this.manifest.discontinuitySequence = entry.number; + currentTimeline = entry.number; + }, + 'playlist-type': function playlistType() { + if (!/VOD|EVENT/.test(entry.playlistType)) { + this.trigger('warn', { + message: 'ignoring unknown playlist type: ' + entry.playlist + }); + return; + } + this.manifest.playlistType = entry.playlistType; + }, + map: function map() { + currentMap = {}; + if (entry.uri) { + currentMap.uri = entry.uri; + } + if (entry.byterange) { + currentMap.byterange = entry.byterange; + } + }, + 'stream-inf': function streamInf() { + this.manifest.playlists = uris; + this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups; + + if (!entry.attributes) { + this.trigger('warn', { + message: 'ignoring empty stream-inf attributes' + }); + return; + } + + if (!currentUri.attributes) { + currentUri.attributes = {}; + } + _extends$1(currentUri.attributes, entry.attributes); + }, + media: function media() { + this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups; + + if (!(entry.attributes && entry.attributes.TYPE && entry.attributes['GROUP-ID'] && entry.attributes.NAME)) { + this.trigger('warn', { + message: 'ignoring incomplete or missing media group' + }); + return; + } + + // find the media group, creating defaults as necessary + var mediaGroupType = this.manifest.mediaGroups[entry.attributes.TYPE]; + + mediaGroupType[entry.attributes['GROUP-ID']] = mediaGroupType[entry.attributes['GROUP-ID']] || {}; + mediaGroup = mediaGroupType[entry.attributes['GROUP-ID']]; + + // collect the rendition metadata + rendition = { + 'default': /yes/i.test(entry.attributes.DEFAULT) + }; + if (rendition['default']) { + rendition.autoselect = true; + } else { + rendition.autoselect = /yes/i.test(entry.attributes.AUTOSELECT); + } + if (entry.attributes.LANGUAGE) { + rendition.language = entry.attributes.LANGUAGE; + } + if (entry.attributes.URI) { + rendition.uri = entry.attributes.URI; + } + if (entry.attributes['INSTREAM-ID']) { + rendition.instreamId = entry.attributes['INSTREAM-ID']; + } + if (entry.attributes.CHARACTERISTICS) { + rendition.characteristics = entry.attributes.CHARACTERISTICS; + } + if (entry.attributes.FORCED) { + rendition.forced = /yes/i.test(entry.attributes.FORCED); + } + + // insert the new rendition + mediaGroup[entry.attributes.NAME] = rendition; + }, + discontinuity: function discontinuity() { + currentTimeline += 1; + currentUri.discontinuity = true; + this.manifest.discontinuityStarts.push(uris.length); + }, + 'program-date-time': function programDateTime() { + if (typeof this.manifest.dateTimeString === 'undefined') { + // PROGRAM-DATE-TIME is a media-segment tag, but for backwards + // compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag + // to the manifest object + // TODO: Consider removing this in future major version + this.manifest.dateTimeString = entry.dateTimeString; + this.manifest.dateTimeObject = entry.dateTimeObject; + } + + currentUri.dateTimeString = entry.dateTimeString; + currentUri.dateTimeObject = entry.dateTimeObject; + }, + targetduration: function targetduration() { + if (!isFinite(entry.duration) || entry.duration < 0) { + this.trigger('warn', { + message: 'ignoring invalid target duration: ' + entry.duration + }); + return; + } + this.manifest.targetDuration = entry.duration; + }, + totalduration: function totalduration() { + if (!isFinite(entry.duration) || entry.duration < 0) { + this.trigger('warn', { + message: 'ignoring invalid total duration: ' + entry.duration + }); + return; + } + this.manifest.totalDuration = entry.duration; + }, + start: function start() { + if (!entry.attributes || isNaN(entry.attributes['TIME-OFFSET'])) { + this.trigger('warn', { + message: 'ignoring start declaration without appropriate attribute list' + }); + return; + } + this.manifest.start = { + timeOffset: entry.attributes['TIME-OFFSET'], + precise: entry.attributes.PRECISE + }; + }, + 'cue-out': function cueOut() { + currentUri.cueOut = entry.data; + }, + 'cue-out-cont': function cueOutCont() { + currentUri.cueOutCont = entry.data; + }, + 'cue-in': function cueIn() { + currentUri.cueIn = entry.data; + } + })[entry.tagType] || noop).call(self); + }, + uri: function uri() { + currentUri.uri = entry.uri; + uris.push(currentUri); + + // if no explicit duration was declared, use the target duration + if (this.manifest.targetDuration && !('duration' in currentUri)) { + this.trigger('warn', { + message: 'defaulting segment duration to the target duration' + }); + currentUri.duration = this.manifest.targetDuration; + } + // annotate with encryption information, if necessary + if (_key) { + currentUri.key = _key; + } + currentUri.timeline = currentTimeline; + // annotate with initialization segment information, if necessary + if (currentMap) { + currentUri.map = currentMap; + } + + // prepare for the next URI + currentUri = {}; + }, + comment: function comment() { + // comments are not important for playback + }, + custom: function custom() { + // if this is segment-level data attach the output to the segment + if (entry.segment) { + currentUri.custom = currentUri.custom || {}; + currentUri.custom[entry.customType] = entry.data; + // if this is manifest-level data attach to the top level manifest object + } else { + this.manifest.custom = this.manifest.custom || {}; + this.manifest.custom[entry.customType] = entry.data; + } + } + })[entry.type].call(self); + }); + return _this; + } + + /** + * Parse the input string and update the manifest object. + * + * @param {String} chunk a potentially incomplete portion of the manifest + */ + + Parser.prototype.push = function push(chunk) { + this.lineStream.push(chunk); + }; + + /** + * Flush any remaining input. This can be handy if the last line of an M3U8 + * manifest did not contain a trailing newline but the file has been + * completely received. + */ + + Parser.prototype.end = function end() { + // flush any buffered input + this.lineStream.push('\n'); + }; + /** + * Add an additional parser for non-standard tags + * + * @param {Object} options a map of options for the added parser + * @param {RegExp} options.expression a regular expression to match the custom header + * @param {string} options.type the type to register to the output + * @param {Function} [options.dataParser] function to parse the line into an object + * @param {boolean} [options.segment] should tag data be attached to the segment object + */ + + Parser.prototype.addParser = function addParser(options) { + this.parseStream.addParser(options); + }; + + return Parser; + }(Stream); + + /** + * mpd-parser + * @version 0.6.0 + * @copyright 2018 Brightcove, Inc + * @license Apache-2.0 + */ + + var formatAudioPlaylist = function formatAudioPlaylist(_ref) { + var _attributes; + + var attributes = _ref.attributes, + segments = _ref.segments; + + var playlist = { + attributes: (_attributes = { + NAME: attributes.id, + BANDWIDTH: attributes.bandwidth, + CODECS: attributes.codecs + }, _attributes['PROGRAM-ID'] = 1, _attributes), + uri: '', + endList: (attributes.type || 'static') === 'static', + timeline: attributes.periodIndex, + resolvedUri: '', + targetDuration: attributes.duration, + segments: segments, + mediaSequence: segments.length ? segments[0].number : 1 + }; + + if (attributes.contentProtection) { + playlist.contentProtection = attributes.contentProtection; + } + + return playlist; + }; + + var formatVttPlaylist = function formatVttPlaylist(_ref2) { + var _attributes2; + + var attributes = _ref2.attributes, + segments = _ref2.segments; + + if (typeof segments === 'undefined') { + // vtt tracks may use single file in BaseURL + segments = [{ + uri: attributes.baseUrl, + timeline: attributes.periodIndex, + resolvedUri: attributes.baseUrl || '', + duration: attributes.sourceDuration, + number: 0 + }]; + // targetDuration should be the same duration as the only segment + attributes.duration = attributes.sourceDuration; + } + return { + attributes: (_attributes2 = { + NAME: attributes.id, + BANDWIDTH: attributes.bandwidth + }, _attributes2['PROGRAM-ID'] = 1, _attributes2), + uri: '', + endList: (attributes.type || 'static') === 'static', + timeline: attributes.periodIndex, + resolvedUri: attributes.baseUrl || '', + targetDuration: attributes.duration, + segments: segments, + mediaSequence: segments.length ? segments[0].number : 1 + }; + }; + + var organizeAudioPlaylists = function organizeAudioPlaylists(playlists) { + return playlists.reduce(function (a, playlist) { + var role = playlist.attributes.role && playlist.attributes.role.value || 'main'; + var language = playlist.attributes.lang || ''; + + var label = 'main'; + + if (language) { + label = playlist.attributes.lang + ' (' + role + ')'; + } + + // skip if we already have the highest quality audio for a language + if (a[label] && a[label].playlists[0].attributes.BANDWIDTH > playlist.attributes.bandwidth) { + return a; + } + + a[label] = { + language: language, + autoselect: true, + default: role === 'main', + playlists: [formatAudioPlaylist(playlist)], + uri: '' + }; + + return a; + }, {}); + }; + + var organizeVttPlaylists = function organizeVttPlaylists(playlists) { + return playlists.reduce(function (a, playlist) { + var label = playlist.attributes.lang || 'text'; + + // skip if we already have subtitles + if (a[label]) { + return a; + } + + a[label] = { + language: label, + default: false, + autoselect: false, + playlists: [formatVttPlaylist(playlist)], + uri: '' + }; + + return a; + }, {}); + }; + + var formatVideoPlaylist = function formatVideoPlaylist(_ref3) { + var _attributes3; + + var attributes = _ref3.attributes, + segments = _ref3.segments; + + var playlist = { + attributes: (_attributes3 = { + NAME: attributes.id, + AUDIO: 'audio', + SUBTITLES: 'subs', + RESOLUTION: { + width: attributes.width, + height: attributes.height + }, + CODECS: attributes.codecs, + BANDWIDTH: attributes.bandwidth + }, _attributes3['PROGRAM-ID'] = 1, _attributes3), + uri: '', + endList: (attributes.type || 'static') === 'static', + timeline: attributes.periodIndex, + resolvedUri: '', + targetDuration: attributes.duration, + segments: segments, + mediaSequence: segments.length ? segments[0].number : 1 + }; + + if (attributes.contentProtection) { + playlist.contentProtection = attributes.contentProtection; + } + + return playlist; + }; + + var toM3u8 = function toM3u8(dashPlaylists) { + var _mediaGroups; + + if (!dashPlaylists.length) { + return {}; + } + + // grab all master attributes + var _dashPlaylists$0$attr = dashPlaylists[0].attributes, + duration = _dashPlaylists$0$attr.sourceDuration, + _dashPlaylists$0$attr2 = _dashPlaylists$0$attr.minimumUpdatePeriod, + minimumUpdatePeriod = _dashPlaylists$0$attr2 === undefined ? 0 : _dashPlaylists$0$attr2; + + + var videoOnly = function videoOnly(_ref4) { + var attributes = _ref4.attributes; + return attributes.mimeType === 'video/mp4' || attributes.contentType === 'video'; + }; + var audioOnly = function audioOnly(_ref5) { + var attributes = _ref5.attributes; + return attributes.mimeType === 'audio/mp4' || attributes.contentType === 'audio'; + }; + var vttOnly = function vttOnly(_ref6) { + var attributes = _ref6.attributes; + return attributes.mimeType === 'text/vtt' || attributes.contentType === 'text'; + }; + + var videoPlaylists = dashPlaylists.filter(videoOnly).map(formatVideoPlaylist); + var audioPlaylists = dashPlaylists.filter(audioOnly); + var vttPlaylists = dashPlaylists.filter(vttOnly); + + var master = { + allowCache: true, + discontinuityStarts: [], + segments: [], + endList: true, + mediaGroups: (_mediaGroups = { + AUDIO: {}, + VIDEO: {} + }, _mediaGroups['CLOSED-CAPTIONS'] = {}, _mediaGroups.SUBTITLES = {}, _mediaGroups), + uri: '', + duration: duration, + playlists: videoPlaylists, + minimumUpdatePeriod: minimumUpdatePeriod * 1000 + }; + + if (audioPlaylists.length) { + master.mediaGroups.AUDIO.audio = organizeAudioPlaylists(audioPlaylists); + } + + if (vttPlaylists.length) { + master.mediaGroups.SUBTITLES.subs = organizeVttPlaylists(vttPlaylists); + } + + return master; + }; + + var isObject$1 = function isObject(obj) { + return !!obj && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object'; + }; + + var merge = function merge() { + for (var _len = arguments.length, objects = Array(_len), _key = 0; _key < _len; _key++) { + objects[_key] = arguments[_key]; + } + + return objects.reduce(function (result, source) { + + Object.keys(source).forEach(function (key) { + + if (Array.isArray(result[key]) && Array.isArray(source[key])) { + result[key] = result[key].concat(source[key]); + } else if (isObject$1(result[key]) && isObject$1(source[key])) { + result[key] = merge(result[key], source[key]); + } else { + result[key] = source[key]; + } + }); + return result; + }, {}); + }; + + var resolveUrl = function resolveUrl(baseUrl, relativeUrl) { + // return early if we don't need to resolve + if (/^[a-z]+:/i.test(relativeUrl)) { + return relativeUrl; + } + + // if the base URL is relative then combine with the current location + if (!/\/\//i.test(baseUrl)) { + baseUrl = urlToolkit.buildAbsoluteURL(window_1.location.href, baseUrl); + } + + return urlToolkit.buildAbsoluteURL(baseUrl, relativeUrl); + }; + + /** + * @typedef {Object} SingleUri + * @property {string} uri - relative location of segment + * @property {string} resolvedUri - resolved location of segment + * @property {Object} byterange - Object containing information on how to make byte range + * requests following byte-range-spec per RFC2616. + * @property {String} byterange.length - length of range request + * @property {String} byterange.offset - byte offset of range request + * + * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1 + */ + + /** + * Converts a URLType node (5.3.9.2.3 Table 13) to a segment object + * that conforms to how m3u8-parser is structured + * + * @see https://github.com/videojs/m3u8-parser + * + * @param {string} baseUrl - baseUrl provided by <BaseUrl> nodes + * @param {string} source - source url for segment + * @param {string} range - optional range used for range calls, follows + * @return {SingleUri} full segment information transformed into a format similar + * to m3u8-parser + */ + var urlTypeToSegment = function urlTypeToSegment(_ref7) { + var _ref7$baseUrl = _ref7.baseUrl, + baseUrl = _ref7$baseUrl === undefined ? '' : _ref7$baseUrl, + _ref7$source = _ref7.source, + source = _ref7$source === undefined ? '' : _ref7$source, + _ref7$range = _ref7.range, + range = _ref7$range === undefined ? '' : _ref7$range; + + var init = { + uri: source, + resolvedUri: resolveUrl(baseUrl || '', source) + }; + + if (range) { + var ranges = range.split('-'); + var startRange = parseInt(ranges[0], 10); + var endRange = parseInt(ranges[1], 10); + + init.byterange = { + length: endRange - startRange, + offset: startRange + }; + } + + return init; + }; + + /** + * Calculates the R (repetition) value for a live stream (for the final segment + * in a manifest where the r value is negative 1) + * + * @param {Object} attributes + * Object containing all inherited attributes from parent elements with attribute + * names as keys + * @param {number} time + * current time (typically the total time up until the final segment) + * @param {number} duration + * duration property for the given <S /> + * + * @return {number} + * R value to reach the end of the given period + */ + var getLiveRValue = function getLiveRValue(attributes, time, duration) { + var NOW = attributes.NOW, + clientOffset = attributes.clientOffset, + availabilityStartTime = attributes.availabilityStartTime, + _attributes$timescale = attributes.timescale, + timescale = _attributes$timescale === undefined ? 1 : _attributes$timescale, + _attributes$start = attributes.start, + start = _attributes$start === undefined ? 0 : _attributes$start, + _attributes$minimumUp = attributes.minimumUpdatePeriod, + minimumUpdatePeriod = _attributes$minimumUp === undefined ? 0 : _attributes$minimumUp; + + var now = (NOW + clientOffset) / 1000; + var periodStartWC = availabilityStartTime + start; + var periodEndWC = now + minimumUpdatePeriod; + var periodDuration = periodEndWC - periodStartWC; + + return Math.ceil((periodDuration * timescale - time) / duration); + }; + + /** + * Uses information provided by SegmentTemplate.SegmentTimeline to determine segment + * timing and duration + * + * @param {Object} attributes + * Object containing all inherited attributes from parent elements with attribute + * names as keys + * @param {Object[]} segmentTimeline + * List of objects representing the attributes of each S element contained within + * + * @return {{number: number, duration: number, time: number, timeline: number}[]} + * List of Objects with segment timing and duration info + */ + var parseByTimeline = function parseByTimeline(attributes, segmentTimeline) { + var _attributes$type = attributes.type, + type = _attributes$type === undefined ? 'static' : _attributes$type, + _attributes$minimumUp2 = attributes.minimumUpdatePeriod, + minimumUpdatePeriod = _attributes$minimumUp2 === undefined ? 0 : _attributes$minimumUp2, + _attributes$media = attributes.media, + media = _attributes$media === undefined ? '' : _attributes$media, + sourceDuration = attributes.sourceDuration, + _attributes$timescale2 = attributes.timescale, + timescale = _attributes$timescale2 === undefined ? 1 : _attributes$timescale2, + _attributes$startNumb = attributes.startNumber, + startNumber = _attributes$startNumb === undefined ? 1 : _attributes$startNumb, + timeline = attributes.periodIndex; + + var segments = []; + var time = -1; + + for (var sIndex = 0; sIndex < segmentTimeline.length; sIndex++) { + var S = segmentTimeline[sIndex]; + var duration = S.d; + var repeat = S.r || 0; + var segmentTime = S.t || 0; + + if (time < 0) { + // first segment + time = segmentTime; + } + + if (segmentTime && segmentTime > time) { + // discontinuity + + // TODO: How to handle this type of discontinuity + // timeline++ here would treat it like HLS discontuity and content would + // get appended without gap + // E.G. + // <S t="0" d="1" /> + // <S d="1" /> + // <S d="1" /> + // <S t="5" d="1" /> + // would have $Time$ values of [0, 1, 2, 5] + // should this be appened at time positions [0, 1, 2, 3],(#EXT-X-DISCONTINUITY) + // or [0, 1, 2, gap, gap, 5]? (#EXT-X-GAP) + // does the value of sourceDuration consider this when calculating arbitrary + // negative @r repeat value? + // E.G. Same elements as above with this added at the end + // <S d="1" r="-1" /> + // with a sourceDuration of 10 + // Would the 2 gaps be included in the time duration calculations resulting in + // 8 segments with $Time$ values of [0, 1, 2, 5, 6, 7, 8, 9] or 10 segments + // with $Time$ values of [0, 1, 2, 5, 6, 7, 8, 9, 10, 11] ? + + time = segmentTime; + } + + var count = void 0; + + if (repeat < 0) { + var nextS = sIndex + 1; + + if (nextS === segmentTimeline.length) { + // last segment + if (type === 'dynamic' && minimumUpdatePeriod > 0 && media.indexOf('$Number$') > 0) { + count = getLiveRValue(attributes, time, duration); + } else { + // TODO: This may be incorrect depending on conclusion of TODO above + count = (sourceDuration * timescale - time) / duration; + } + } else { + count = (segmentTimeline[nextS].t - time) / duration; + } + } else { + count = repeat + 1; + } + + var end = startNumber + segments.length + count; + var number = startNumber + segments.length; + + while (number < end) { + segments.push({number: number, duration: duration / timescale, time: time, timeline: timeline}); + time += duration; + number++; + } + } + + return segments; + }; + + var range = function range(start, end) { + var result = []; + + for (var i = start; i < end; i++) { + result.push(i); + } + + return result; + }; + + var flatten = function flatten(lists) { + return lists.reduce(function (x, y) { + return x.concat(y); + }, []); + }; + + var from = function from(list) { + if (!list.length) { + return []; + } + + var result = []; + + for (var i = 0; i < list.length; i++) { + result.push(list[i]); + } + + return result; + }; + + /** + * Functions for calculating the range of available segments in static and dynamic + * manifests. + */ + var segmentRange = { + /** + * Returns the entire range of available segments for a static MPD + * + * @param {Object} attributes + * Inheritied MPD attributes + * @return {{ start: number, end: number }} + * The start and end numbers for available segments + */ + static: function _static(attributes) { + var duration = attributes.duration, + _attributes$timescale3 = attributes.timescale, + timescale = _attributes$timescale3 === undefined ? 1 : _attributes$timescale3, + sourceDuration = attributes.sourceDuration; + + + return { + start: 0, + end: Math.ceil(sourceDuration / (duration / timescale)) + }; + }, + + + /** + * Returns the current live window range of available segments for a dynamic MPD + * + * @param {Object} attributes + * Inheritied MPD attributes + * @return {{ start: number, end: number }} + * The start and end numbers for available segments + */ + dynamic: function dynamic(attributes) { + var NOW = attributes.NOW, + clientOffset = attributes.clientOffset, + availabilityStartTime = attributes.availabilityStartTime, + _attributes$timescale4 = attributes.timescale, + timescale = _attributes$timescale4 === undefined ? 1 : _attributes$timescale4, + duration = attributes.duration, + _attributes$start2 = attributes.start, + start = _attributes$start2 === undefined ? 0 : _attributes$start2, + _attributes$minimumUp3 = attributes.minimumUpdatePeriod, + minimumUpdatePeriod = _attributes$minimumUp3 === undefined ? 0 : _attributes$minimumUp3, + _attributes$timeShift = attributes.timeShiftBufferDepth, + timeShiftBufferDepth = _attributes$timeShift === undefined ? Infinity : _attributes$timeShift; + + var now = (NOW + clientOffset) / 1000; + var periodStartWC = availabilityStartTime + start; + var periodEndWC = now + minimumUpdatePeriod; + var periodDuration = periodEndWC - periodStartWC; + var segmentCount = Math.ceil(periodDuration * timescale / duration); + var availableStart = Math.floor((now - periodStartWC - timeShiftBufferDepth) * timescale / duration); + var availableEnd = Math.floor((now - periodStartWC) * timescale / duration); + + return { + start: Math.max(0, availableStart), + end: Math.min(segmentCount, availableEnd) + }; + } + }; + + /** + * Maps a range of numbers to objects with information needed to build the corresponding + * segment list + * + * @name toSegmentsCallback + * @function + * @param {number} number + * Number of the segment + * @param {number} index + * Index of the number in the range list + * @return {{ number: Number, duration: Number, timeline: Number, time: Number }} + * Object with segment timing and duration info + */ + + /** + * Returns a callback for Array.prototype.map for mapping a range of numbers to + * information needed to build the segment list. + * + * @param {Object} attributes + * Inherited MPD attributes + * @return {toSegmentsCallback} + * Callback map function + */ + var toSegments = function toSegments(attributes) { + return function (number, index) { + var duration = attributes.duration, + _attributes$timescale5 = attributes.timescale, + timescale = _attributes$timescale5 === undefined ? 1 : _attributes$timescale5, + periodIndex = attributes.periodIndex, + _attributes$startNumb2 = attributes.startNumber, + startNumber = _attributes$startNumb2 === undefined ? 1 : _attributes$startNumb2; + + + return { + number: startNumber + number, + duration: duration / timescale, + timeline: periodIndex, + time: index * duration + }; + }; + }; + + /** + * Returns a list of objects containing segment timing and duration info used for + * building the list of segments. This uses the @duration attribute specified + * in the MPD manifest to derive the range of segments. + * + * @param {Object} attributes + * Inherited MPD attributes + * @return {{number: number, duration: number, time: number, timeline: number}[]} + * List of Objects with segment timing and duration info + */ + var parseByDuration = function parseByDuration(attributes) { + var _attributes$type2 = attributes.type, + type = _attributes$type2 === undefined ? 'static' : _attributes$type2, + duration = attributes.duration, + _attributes$timescale6 = attributes.timescale, + timescale = _attributes$timescale6 === undefined ? 1 : _attributes$timescale6, + sourceDuration = attributes.sourceDuration; + + var _segmentRange$type = segmentRange[type](attributes), + start = _segmentRange$type.start, + end = _segmentRange$type.end; + + var segments = range(start, end).map(toSegments(attributes)); + + if (type === 'static') { + var index = segments.length - 1; + + // final segment may be less than full segment duration + segments[index].duration = sourceDuration - duration / timescale * index; + } + + return segments; + }; + + var identifierPattern = /\$([A-z]*)(?:(%0)([0-9]+)d)?\$/g; + + /** + * Replaces template identifiers with corresponding values. To be used as the callback + * for String.prototype.replace + * + * @name replaceCallback + * @function + * @param {string} match + * Entire match of identifier + * @param {string} identifier + * Name of matched identifier + * @param {string} format + * Format tag string. Its presence indicates that padding is expected + * @param {string} width + * Desired length of the replaced value. Values less than this width shall be left + * zero padded + * @return {string} + * Replacement for the matched identifier + */ + + /** + * Returns a function to be used as a callback for String.prototype.replace to replace + * template identifiers + * + * @param {Obect} values + * Object containing values that shall be used to replace known identifiers + * @param {number} values.RepresentationID + * Value of the Representation@id attribute + * @param {number} values.Number + * Number of the corresponding segment + * @param {number} values.Bandwidth + * Value of the Representation@bandwidth attribute. + * @param {number} values.Time + * Timestamp value of the corresponding segment + * @return {replaceCallback} + * Callback to be used with String.prototype.replace to replace identifiers + */ + var identifierReplacement = function identifierReplacement(values) { + return function (match, identifier, format, width) { + if (match === '$$') { + // escape sequence + return '$'; + } + + if (typeof values[identifier] === 'undefined') { + return match; + } + + var value = '' + values[identifier]; + + if (identifier === 'RepresentationID') { + // Format tag shall not be present with RepresentationID + return value; + } + + if (!format) { + width = 1; + } else { + width = parseInt(width, 10); + } + + if (value.length >= width) { + return value; + } + + return '' + new Array(width - value.length + 1).join('0') + value; + }; + }; + + /** + * Constructs a segment url from a template string + * + * @param {string} url + * Template string to construct url from + * @param {Obect} values + * Object containing values that shall be used to replace known identifiers + * @param {number} values.RepresentationID + * Value of the Representation@id attribute + * @param {number} values.Number + * Number of the corresponding segment + * @param {number} values.Bandwidth + * Value of the Representation@bandwidth attribute. + * @param {number} values.Time + * Timestamp value of the corresponding segment + * @return {string} + * Segment url with identifiers replaced + */ + var constructTemplateUrl = function constructTemplateUrl(url, values) { + return url.replace(identifierPattern, identifierReplacement(values)); + }; + + /** + * Generates a list of objects containing timing and duration information about each + * segment needed to generate segment uris and the complete segment object + * + * @param {Object} attributes + * Object containing all inherited attributes from parent elements with attribute + * names as keys + * @param {Object[]|undefined} segmentTimeline + * List of objects representing the attributes of each S element contained within + * the SegmentTimeline element + * @return {{number: number, duration: number, time: number, timeline: number}[]} + * List of Objects with segment timing and duration info + */ + var parseTemplateInfo = function parseTemplateInfo(attributes, segmentTimeline) { + if (!attributes.duration && !segmentTimeline) { + // if neither @duration or SegmentTimeline are present, then there shall be exactly + // one media segment + return [{ + number: attributes.startNumber || 1, + duration: attributes.sourceDuration, + time: 0, + timeline: attributes.periodIndex + }]; + } + + if (attributes.duration) { + return parseByDuration(attributes); + } + + return parseByTimeline(attributes, segmentTimeline); + }; + + /** + * Generates a list of segments using information provided by the SegmentTemplate element + * + * @param {Object} attributes + * Object containing all inherited attributes from parent elements with attribute + * names as keys + * @param {Object[]|undefined} segmentTimeline + * List of objects representing the attributes of each S element contained within + * the SegmentTimeline element + * @return {Object[]} + * List of segment objects + */ + var segmentsFromTemplate = function segmentsFromTemplate(attributes, segmentTimeline) { + var templateValues = { + RepresentationID: attributes.id, + Bandwidth: attributes.bandwidth || 0 + }; + + var _attributes$initializ = attributes.initialization, + initialization = _attributes$initializ === undefined ? {sourceURL: '', range: ''} : _attributes$initializ; + + + var mapSegment = urlTypeToSegment({ + baseUrl: attributes.baseUrl, + source: constructTemplateUrl(initialization.sourceURL, templateValues), + range: initialization.range + }); + + var segments = parseTemplateInfo(attributes, segmentTimeline); + + return segments.map(function (segment) { + templateValues.Number = segment.number; + templateValues.Time = segment.time; + + var uri = constructTemplateUrl(attributes.media || '', templateValues); + + return { + uri: uri, + timeline: segment.timeline, + duration: segment.duration, + resolvedUri: resolveUrl(attributes.baseUrl || '', uri), + map: mapSegment, + number: segment.number + }; + }); + }; + + var errors = { + INVALID_NUMBER_OF_PERIOD: 'INVALID_NUMBER_OF_PERIOD', + DASH_EMPTY_MANIFEST: 'DASH_EMPTY_MANIFEST', + DASH_INVALID_XML: 'DASH_INVALID_XML', + NO_BASE_URL: 'NO_BASE_URL', + MISSING_SEGMENT_INFORMATION: 'MISSING_SEGMENT_INFORMATION', + SEGMENT_TIME_UNSPECIFIED: 'SEGMENT_TIME_UNSPECIFIED', + UNSUPPORTED_UTC_TIMING_SCHEME: 'UNSUPPORTED_UTC_TIMING_SCHEME' + }; + + /** + * Converts a <SegmentUrl> (of type URLType from the DASH spec 5.3.9.2 Table 14) + * to an object that matches the output of a segment in videojs/mpd-parser + * + * @param {Object} attributes + * Object containing all inherited attributes from parent elements with attribute + * names as keys + * @param {Object} segmentUrl + * <SegmentURL> node to translate into a segment object + * @return {Object} translated segment object + */ + var SegmentURLToSegmentObject = function SegmentURLToSegmentObject(attributes, segmentUrl) { + var baseUrl = attributes.baseUrl, + _attributes$initializ2 = attributes.initialization, + initialization = _attributes$initializ2 === undefined ? {} : _attributes$initializ2; + + + var initSegment = urlTypeToSegment({ + baseUrl: baseUrl, + source: initialization.sourceURL, + range: initialization.range + }); + + var segment = urlTypeToSegment({ + baseUrl: baseUrl, + source: segmentUrl.media, + range: segmentUrl.mediaRange + }); + + segment.map = initSegment; + + return segment; + }; + + /** + * Generates a list of segments using information provided by the SegmentList element + * SegmentList (DASH SPEC Section 5.3.9.3.2) contains a set of <SegmentURL> nodes. Each + * node should be translated into segment. + * + * @param {Object} attributes + * Object containing all inherited attributes from parent elements with attribute + * names as keys + * @param {Object[]|undefined} segmentTimeline + * List of objects representing the attributes of each S element contained within + * the SegmentTimeline element + * @return {Object.<Array>} list of segments + */ + var segmentsFromList = function segmentsFromList(attributes, segmentTimeline) { + var duration = attributes.duration, + _attributes$segmentUr = attributes.segmentUrls, + segmentUrls = _attributes$segmentUr === undefined ? [] : _attributes$segmentUr; + + // Per spec (5.3.9.2.1) no way to determine segment duration OR + // if both SegmentTimeline and @duration are defined, it is outside of spec. + + if (!duration && !segmentTimeline || duration && segmentTimeline) { + throw new Error(errors.SEGMENT_TIME_UNSPECIFIED); + } + + var segmentUrlMap = segmentUrls.map(function (segmentUrlObject) { + return SegmentURLToSegmentObject(attributes, segmentUrlObject); + }); + var segmentTimeInfo = void 0; + + if (duration) { + segmentTimeInfo = parseByDuration(attributes); + } + + if (segmentTimeline) { + segmentTimeInfo = parseByTimeline(attributes, segmentTimeline); + } + + var segments = segmentTimeInfo.map(function (segmentTime, index) { + if (segmentUrlMap[index]) { + var segment = segmentUrlMap[index]; + + segment.timeline = segmentTime.timeline; + segment.duration = segmentTime.duration; + segment.number = segmentTime.number; + return segment; + } + // Since we're mapping we should get rid of any blank segments (in case + // the given SegmentTimeline is handling for more elements than we have + // SegmentURLs for). + }).filter(function (segment) { + return segment; + }); + + return segments; + }; + + /** + * Translates SegmentBase into a set of segments. + * (DASH SPEC Section 5.3.9.3.2) contains a set of <SegmentURL> nodes. Each + * node should be translated into segment. + * + * @param {Object} attributes + * Object containing all inherited attributes from parent elements with attribute + * names as keys + * @return {Object.<Array>} list of segments + */ + var segmentsFromBase = function segmentsFromBase(attributes) { + var baseUrl = attributes.baseUrl, + _attributes$initializ3 = attributes.initialization, + initialization = _attributes$initializ3 === undefined ? {} : _attributes$initializ3, + sourceDuration = attributes.sourceDuration, + _attributes$timescale7 = attributes.timescale, + timescale = _attributes$timescale7 === undefined ? 1 : _attributes$timescale7, + _attributes$indexRang = attributes.indexRange, + indexRange = _attributes$indexRang === undefined ? '' : _attributes$indexRang, + duration = attributes.duration; + + // base url is required for SegmentBase to work, per spec (Section 5.3.9.2.1) + + if (!baseUrl) { + throw new Error(errors.NO_BASE_URL); + } + + var initSegment = urlTypeToSegment({ + baseUrl: baseUrl, + source: initialization.sourceURL, + range: initialization.range + }); + var segment = urlTypeToSegment({baseUrl: baseUrl, source: baseUrl, range: indexRange}); + + segment.map = initSegment; + + // If there is a duration, use it, otherwise use the given duration of the source + // (since SegmentBase is only for one total segment) + if (duration) { + var segmentTimeInfo = parseByDuration(attributes); + + if (segmentTimeInfo.length) { + segment.duration = segmentTimeInfo[0].duration; + segment.timeline = segmentTimeInfo[0].timeline; + } + } else if (sourceDuration) { + segment.duration = sourceDuration / timescale; + segment.timeline = 0; + } + + // This is used for mediaSequence + segment.number = 0; + + return [segment]; + }; + + var generateSegments = function generateSegments(_ref8) { + var attributes = _ref8.attributes, + segmentInfo = _ref8.segmentInfo; + + var segmentAttributes = void 0; + var segmentsFn = void 0; + + if (segmentInfo.template) { + segmentsFn = segmentsFromTemplate; + segmentAttributes = merge(attributes, segmentInfo.template); + } else if (segmentInfo.base) { + segmentsFn = segmentsFromBase; + segmentAttributes = merge(attributes, segmentInfo.base); + } else if (segmentInfo.list) { + segmentsFn = segmentsFromList; + segmentAttributes = merge(attributes, segmentInfo.list); + } + + if (!segmentsFn) { + return {attributes: attributes}; + } + + var segments = segmentsFn(segmentAttributes, segmentInfo.timeline); + + // The @duration attribute will be used to determin the playlist's targetDuration which + // must be in seconds. Since we've generated the segment list, we no longer need + // @duration to be in @timescale units, so we can convert it here. + if (segmentAttributes.duration) { + var _segmentAttributes = segmentAttributes, + duration = _segmentAttributes.duration, + _segmentAttributes$ti = _segmentAttributes.timescale, + timescale = _segmentAttributes$ti === undefined ? 1 : _segmentAttributes$ti; + + + segmentAttributes.duration = duration / timescale; + } else if (segments.length) { + // if there is no @duration attribute, use the largest segment duration as + // as target duration + segmentAttributes.duration = segments.reduce(function (max, segment) { + return Math.max(max, Math.ceil(segment.duration)); + }, 0); + } else { + segmentAttributes.duration = 0; + } + + return { + attributes: segmentAttributes, + segments: segments + }; + }; + + var toPlaylists = function toPlaylists(representations) { + return representations.map(generateSegments); + }; + + var findChildren = function findChildren(element, name) { + return from(element.childNodes).filter(function (_ref9) { + var tagName = _ref9.tagName; + return tagName === name; + }); + }; + + var getContent = function getContent(element) { + return element.textContent.trim(); + }; + + var parseDuration = function parseDuration(str) { + var SECONDS_IN_YEAR = 365 * 24 * 60 * 60; + var SECONDS_IN_MONTH = 30 * 24 * 60 * 60; + var SECONDS_IN_DAY = 24 * 60 * 60; + var SECONDS_IN_HOUR = 60 * 60; + var SECONDS_IN_MIN = 60; + + // P10Y10M10DT10H10M10.1S + var durationRegex = /P(?:(\d*)Y)?(?:(\d*)M)?(?:(\d*)D)?(?:T(?:(\d*)H)?(?:(\d*)M)?(?:([\d.]*)S)?)?/; + var match = durationRegex.exec(str); + + if (!match) { + return 0; + } + + var _match$slice = match.slice(1), + year = _match$slice[0], + month = _match$slice[1], + day = _match$slice[2], + hour = _match$slice[3], + minute = _match$slice[4], + second = _match$slice[5]; + + return parseFloat(year || 0) * SECONDS_IN_YEAR + parseFloat(month || 0) * SECONDS_IN_MONTH + parseFloat(day || 0) * SECONDS_IN_DAY + parseFloat(hour || 0) * SECONDS_IN_HOUR + parseFloat(minute || 0) * SECONDS_IN_MIN + parseFloat(second || 0); + }; + + var parseDate = function parseDate(str) { + // Date format without timezone according to ISO 8601 + // YYY-MM-DDThh:mm:ss.ssssss + var dateRegex = /^\d+-\d+-\d+T\d+:\d+:\d+(\.\d+)?$/; + + // If the date string does not specifiy a timezone, we must specifiy UTC. This is + // expressed by ending with 'Z' + if (dateRegex.test(str)) { + str += 'Z'; + } + + return Date.parse(str); + }; + + // TODO: maybe order these in some way that makes it easy to find specific attributes + var parsers = { + /** + * Specifies the duration of the entire Media Presentation. Format is a duration string + * as specified in ISO 8601 + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The duration in seconds + */ + mediaPresentationDuration: function mediaPresentationDuration(value) { + return parseDuration(value); + }, + + + /** + * Specifies the Segment availability start time for all Segments referred to in this + * MPD. For a dynamic manifest, it specifies the anchor for the earliest availability + * time. Format is a date string as specified in ISO 8601 + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The date as seconds from unix epoch + */ + availabilityStartTime: function availabilityStartTime(value) { + return parseDate(value) / 1000; + }, + + + /** + * Specifies the smallest period between potential changes to the MPD. Format is a + * duration string as specified in ISO 8601 + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The duration in seconds + */ + minimumUpdatePeriod: function minimumUpdatePeriod(value) { + return parseDuration(value); + }, + + + /** + * Specifies the duration of the smallest time shifting buffer for any Representation + * in the MPD. Format is a duration string as specified in ISO 8601 + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The duration in seconds + */ + timeShiftBufferDepth: function timeShiftBufferDepth(value) { + return parseDuration(value); + }, + + + /** + * Specifies the PeriodStart time of the Period relative to the availabilityStarttime. + * Format is a duration string as specified in ISO 8601 + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The duration in seconds + */ + start: function start(value) { + return parseDuration(value); + }, + + + /** + * Specifies the width of the visual presentation + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The parsed width + */ + width: function width(value) { + return parseInt(value, 10); + }, + + + /** + * Specifies the height of the visual presentation + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The parsed height + */ + height: function height(value) { + return parseInt(value, 10); + }, + + + /** + * Specifies the bitrate of the representation + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The parsed bandwidth + */ + bandwidth: function bandwidth(value) { + return parseInt(value, 10); + }, + + + /** + * Specifies the number of the first Media Segment in this Representation in the Period + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The parsed number + */ + startNumber: function startNumber(value) { + return parseInt(value, 10); + }, + + + /** + * Specifies the timescale in units per seconds + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The aprsed timescale + */ + timescale: function timescale(value) { + return parseInt(value, 10); + }, + + + /** + * Specifies the constant approximate Segment duration + * NOTE: The <Period> element also contains an @duration attribute. This duration + * specifies the duration of the Period. This attribute is currently not + * supported by the rest of the parser, however we still check for it to prevent + * errors. + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The parsed duration + */ + duration: function duration(value) { + var parsedValue = parseInt(value, 10); + + if (isNaN(parsedValue)) { + return parseDuration(value); + } + + return parsedValue; + }, + + + /** + * Specifies the Segment duration, in units of the value of the @timescale. + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The parsed duration + */ + d: function d(value) { + return parseInt(value, 10); + }, + + + /** + * Specifies the MPD start time, in @timescale units, the first Segment in the series + * starts relative to the beginning of the Period + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The parsed time + */ + t: function t(value) { + return parseInt(value, 10); + }, + + + /** + * Specifies the repeat count of the number of following contiguous Segments with the + * same duration expressed by the value of @d + * + * @param {string} value + * value of attribute as a string + * @return {number} + * The parsed number + */ + r: function r(value) { + return parseInt(value, 10); + }, + + + /** + * Default parser for all other attributes. Acts as a no-op and just returns the value + * as a string + * + * @param {string} value + * value of attribute as a string + * @return {string} + * Unparsed value + */ + DEFAULT: function DEFAULT(value) { + return value; + } + }; + + /** + * Gets all the attributes and values of the provided node, parses attributes with known + * types, and returns an object with attribute names mapped to values. + * + * @param {Node} el + * The node to parse attributes from + * @return {Object} + * Object with all attributes of el parsed + */ + var parseAttributes$1 = function parseAttributes(el) { + if (!(el && el.attributes)) { + return {}; + } + + return from(el.attributes).reduce(function (a, e) { + var parseFn = parsers[e.name] || parsers.DEFAULT; + + a[e.name] = parseFn(e.value); + + return a; + }, {}); + }; + + function decodeB64ToUint8Array(b64Text) { + var decodedString = window_1.atob(b64Text); + var array = new Uint8Array(decodedString.length); + + for (var i = 0; i < decodedString.length; i++) { + array[i] = decodedString.charCodeAt(i); + } + return array; + } + + var keySystemsMap = { + 'urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b': 'org.w3.clearkey', + 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed': 'com.widevine.alpha', + 'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95': 'com.microsoft.playready', + 'urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb': 'com.adobe.primetime' + }; + + /** + * Builds a list of urls that is the product of the reference urls and BaseURL values + * + * @param {string[]} referenceUrls + * List of reference urls to resolve to + * @param {Node[]} baseUrlElements + * List of BaseURL nodes from the mpd + * @return {string[]} + * List of resolved urls + */ + var buildBaseUrls = function buildBaseUrls(referenceUrls, baseUrlElements) { + if (!baseUrlElements.length) { + return referenceUrls; + } + + return flatten(referenceUrls.map(function (reference) { + return baseUrlElements.map(function (baseUrlElement) { + return resolveUrl(reference, getContent(baseUrlElement)); + }); + })); + }; + + /** + * Contains all Segment information for its containing AdaptationSet + * + * @typedef {Object} SegmentInformation + * @property {Object|undefined} template + * Contains the attributes for the SegmentTemplate node + * @property {Object[]|undefined} timeline + * Contains a list of atrributes for each S node within the SegmentTimeline node + * @property {Object|undefined} list + * Contains the attributes for the SegmentList node + * @property {Object|undefined} base + * Contains the attributes for the SegmentBase node + */ + + /** + * Returns all available Segment information contained within the AdaptationSet node + * + * @param {Node} adaptationSet + * The AdaptationSet node to get Segment information from + * @return {SegmentInformation} + * The Segment information contained within the provided AdaptationSet + */ + var getSegmentInformation = function getSegmentInformation(adaptationSet) { + var segmentTemplate = findChildren(adaptationSet, 'SegmentTemplate')[0]; + var segmentList = findChildren(adaptationSet, 'SegmentList')[0]; + var segmentUrls = segmentList && findChildren(segmentList, 'SegmentURL').map(function (s) { + return merge({tag: 'SegmentURL'}, parseAttributes$1(s)); + }); + var segmentBase = findChildren(adaptationSet, 'SegmentBase')[0]; + var segmentTimelineParentNode = segmentList || segmentTemplate; + var segmentTimeline = segmentTimelineParentNode && findChildren(segmentTimelineParentNode, 'SegmentTimeline')[0]; + var segmentInitializationParentNode = segmentList || segmentBase || segmentTemplate; + var segmentInitialization = segmentInitializationParentNode && findChildren(segmentInitializationParentNode, 'Initialization')[0]; + + // SegmentTemplate is handled slightly differently, since it can have both + // @initialization and an <Initialization> node. @initialization can be templated, + // while the node can have a url and range specified. If the <SegmentTemplate> has + // both @initialization and an <Initialization> subelement we opt to override with + // the node, as this interaction is not defined in the spec. + var template = segmentTemplate && parseAttributes$1(segmentTemplate); + + if (template && segmentInitialization) { + template.initialization = segmentInitialization && parseAttributes$1(segmentInitialization); + } else if (template && template.initialization) { + // If it is @initialization we convert it to an object since this is the format that + // later functions will rely on for the initialization segment. This is only valid + // for <SegmentTemplate> + template.initialization = {sourceURL: template.initialization}; + } + + var segmentInfo = { + template: template, + timeline: segmentTimeline && findChildren(segmentTimeline, 'S').map(function (s) { + return parseAttributes$1(s); + }), + list: segmentList && merge(parseAttributes$1(segmentList), { + segmentUrls: segmentUrls, + initialization: parseAttributes$1(segmentInitialization) + }), + base: segmentBase && merge(parseAttributes$1(segmentBase), { + initialization: parseAttributes$1(segmentInitialization) + }) + }; + + Object.keys(segmentInfo).forEach(function (key) { + if (!segmentInfo[key]) { + delete segmentInfo[key]; + } + }); + + return segmentInfo; + }; + + /** + * Contains Segment information and attributes needed to construct a Playlist object + * from a Representation + * + * @typedef {Object} RepresentationInformation + * @property {SegmentInformation} segmentInfo + * Segment information for this Representation + * @property {Object} attributes + * Inherited attributes for this Representation + */ + + /** + * Maps a Representation node to an object containing Segment information and attributes + * + * @name inheritBaseUrlsCallback + * @function + * @param {Node} representation + * Representation node from the mpd + * @return {RepresentationInformation} + * Representation information needed to construct a Playlist object + */ + + /** + * Returns a callback for Array.prototype.map for mapping Representation nodes to + * Segment information and attributes using inherited BaseURL nodes. + * + * @param {Object} adaptationSetAttributes + * Contains attributes inherited by the AdaptationSet + * @param {string[]} adaptationSetBaseUrls + * Contains list of resolved base urls inherited by the AdaptationSet + * @param {SegmentInformation} adaptationSetSegmentInfo + * Contains Segment information for the AdaptationSet + * @return {inheritBaseUrlsCallback} + * Callback map function + */ + var inheritBaseUrls = function inheritBaseUrls(adaptationSetAttributes, adaptationSetBaseUrls, adaptationSetSegmentInfo) { + return function (representation) { + var repBaseUrlElements = findChildren(representation, 'BaseURL'); + var repBaseUrls = buildBaseUrls(adaptationSetBaseUrls, repBaseUrlElements); + var attributes = merge(adaptationSetAttributes, parseAttributes$1(representation)); + var representationSegmentInfo = getSegmentInformation(representation); + + return repBaseUrls.map(function (baseUrl) { + return { + segmentInfo: merge(adaptationSetSegmentInfo, representationSegmentInfo), + attributes: merge(attributes, {baseUrl: baseUrl}) + }; + }); + }; + }; + + /** + * Tranforms a series of content protection nodes to + * an object containing pssh data by key system + * + * @param {Node[]} contentProtectionNodes + * Content protection nodes + * @return {Object} + * Object containing pssh data by key system + */ + var generateKeySystemInformation = function generateKeySystemInformation(contentProtectionNodes) { + return contentProtectionNodes.reduce(function (acc, node) { + var attributes = parseAttributes$1(node); + var keySystem = keySystemsMap[attributes.schemeIdUri]; + + if (keySystem) { + acc[keySystem] = {attributes: attributes}; + + var psshNode = findChildren(node, 'cenc:pssh')[0]; + + if (psshNode) { + var pssh = getContent(psshNode); + var psshBuffer = pssh && decodeB64ToUint8Array(pssh); + + acc[keySystem].pssh = psshBuffer; + } + } + + return acc; + }, {}); + }; + + /** + * Maps an AdaptationSet node to a list of Representation information objects + * + * @name toRepresentationsCallback + * @function + * @param {Node} adaptationSet + * AdaptationSet node from the mpd + * @return {RepresentationInformation[]} + * List of objects containing Representaion information + */ + + /** + * Returns a callback for Array.prototype.map for mapping AdaptationSet nodes to a list of + * Representation information objects + * + * @param {Object} periodAttributes + * Contains attributes inherited by the Period + * @param {string[]} periodBaseUrls + * Contains list of resolved base urls inherited by the Period + * @param {string[]} periodSegmentInfo + * Contains Segment Information at the period level + * @return {toRepresentationsCallback} + * Callback map function + */ + var toRepresentations = function toRepresentations(periodAttributes, periodBaseUrls, periodSegmentInfo) { + return function (adaptationSet) { + var adaptationSetAttributes = parseAttributes$1(adaptationSet); + var adaptationSetBaseUrls = buildBaseUrls(periodBaseUrls, findChildren(adaptationSet, 'BaseURL')); + var role = findChildren(adaptationSet, 'Role')[0]; + var roleAttributes = {role: parseAttributes$1(role)}; + + var attrs = merge(periodAttributes, adaptationSetAttributes, roleAttributes); + + var contentProtection = generateKeySystemInformation(findChildren(adaptationSet, 'ContentProtection')); + + if (Object.keys(contentProtection).length) { + attrs = merge(attrs, {contentProtection: contentProtection}); + } + + var segmentInfo = getSegmentInformation(adaptationSet); + var representations = findChildren(adaptationSet, 'Representation'); + var adaptationSetSegmentInfo = merge(periodSegmentInfo, segmentInfo); + + return flatten(representations.map(inheritBaseUrls(attrs, adaptationSetBaseUrls, adaptationSetSegmentInfo))); + }; + }; + + /** + * Maps an Period node to a list of Representation inforamtion objects for all + * AdaptationSet nodes contained within the Period + * + * @name toAdaptationSetsCallback + * @function + * @param {Node} period + * Period node from the mpd + * @param {number} periodIndex + * Index of the Period within the mpd + * @return {RepresentationInformation[]} + * List of objects containing Representaion information + */ + + /** + * Returns a callback for Array.prototype.map for mapping Period nodes to a list of + * Representation information objects + * + * @param {Object} mpdAttributes + * Contains attributes inherited by the mpd + * @param {string[]} mpdBaseUrls + * Contains list of resolved base urls inherited by the mpd + * @return {toAdaptationSetsCallback} + * Callback map function + */ + var toAdaptationSets = function toAdaptationSets(mpdAttributes, mpdBaseUrls) { + return function (period, periodIndex) { + var periodBaseUrls = buildBaseUrls(mpdBaseUrls, findChildren(period, 'BaseURL')); + var periodAtt = parseAttributes$1(period); + var periodAttributes = merge(mpdAttributes, periodAtt, {periodIndex: periodIndex}); + var adaptationSets = findChildren(period, 'AdaptationSet'); + var periodSegmentInfo = getSegmentInformation(period); + + return flatten(adaptationSets.map(toRepresentations(periodAttributes, periodBaseUrls, periodSegmentInfo))); + }; + }; + + /** + * Traverses the mpd xml tree to generate a list of Representation information objects + * that have inherited attributes from parent nodes + * + * @param {Node} mpd + * The root node of the mpd + * @param {Object} options + * Available options for inheritAttributes + * @param {string} options.manifestUri + * The uri source of the mpd + * @param {number} options.NOW + * Current time per DASH IOP. Default is current time in ms since epoch + * @param {number} options.clientOffset + * Client time difference from NOW (in milliseconds) + * @return {RepresentationInformation[]} + * List of objects containing Representation information + */ + var inheritAttributes = function inheritAttributes(mpd) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var _options$manifestUri = options.manifestUri, + manifestUri = _options$manifestUri === undefined ? '' : _options$manifestUri, + _options$NOW = options.NOW, + NOW = _options$NOW === undefined ? Date.now() : _options$NOW, + _options$clientOffset = options.clientOffset, + clientOffset = _options$clientOffset === undefined ? 0 : _options$clientOffset; + + var periods = findChildren(mpd, 'Period'); + + if (periods.length !== 1) { + // TODO add support for multiperiod + throw new Error(errors.INVALID_NUMBER_OF_PERIOD); + } + + var mpdAttributes = parseAttributes$1(mpd); + var mpdBaseUrls = buildBaseUrls([manifestUri], findChildren(mpd, 'BaseURL')); + + mpdAttributes.sourceDuration = mpdAttributes.mediaPresentationDuration || 0; + mpdAttributes.NOW = NOW; + mpdAttributes.clientOffset = clientOffset; + + return flatten(periods.map(toAdaptationSets(mpdAttributes, mpdBaseUrls))); + }; + + var stringToMpdXml = function stringToMpdXml(manifestString) { + if (manifestString === '') { + throw new Error(errors.DASH_EMPTY_MANIFEST); + } + + var parser = new window_1.DOMParser(); + var xml = parser.parseFromString(manifestString, 'application/xml'); + var mpd = xml && xml.documentElement.tagName === 'MPD' ? xml.documentElement : null; + + if (!mpd || mpd && mpd.getElementsByTagName('parsererror').length > 0) { + throw new Error(errors.DASH_INVALID_XML); + } + + return mpd; + }; + + /** + * Parses the manifest for a UTCTiming node, returning the nodes attributes if found + * + * @param {string} mpd + * XML string of the MPD manifest + * @return {Object|null} + * Attributes of UTCTiming node specified in the manifest. Null if none found + */ + var parseUTCTimingScheme = function parseUTCTimingScheme(mpd) { + var UTCTimingNode = findChildren(mpd, 'UTCTiming')[0]; + + if (!UTCTimingNode) { + return null; + } + + var attributes = parseAttributes$1(UTCTimingNode); + + switch (attributes.schemeIdUri) { + case 'urn:mpeg:dash:utc:http-head:2014': + case 'urn:mpeg:dash:utc:http-head:2012': + attributes.method = 'HEAD'; + break; + case 'urn:mpeg:dash:utc:http-xsdate:2014': + case 'urn:mpeg:dash:utc:http-iso:2014': + case 'urn:mpeg:dash:utc:http-xsdate:2012': + case 'urn:mpeg:dash:utc:http-iso:2012': + attributes.method = 'GET'; + break; + case 'urn:mpeg:dash:utc:direct:2014': + case 'urn:mpeg:dash:utc:direct:2012': + attributes.method = 'DIRECT'; + attributes.value = Date.parse(attributes.value); + break; + case 'urn:mpeg:dash:utc:http-ntp:2014': + case 'urn:mpeg:dash:utc:ntp:2014': + case 'urn:mpeg:dash:utc:sntp:2014': + default: + throw new Error(errors.UNSUPPORTED_UTC_TIMING_SCHEME); + } + + return attributes; + }; + + var parse = function parse(manifestString, options) { + return toM3u8(toPlaylists(inheritAttributes(stringToMpdXml(manifestString), options))); + }; + + /** + * Parses the manifest for a UTCTiming node, returning the nodes attributes if found + * + * @param {string} manifestString + * XML string of the MPD manifest + * @return {Object|null} + * Attributes of UTCTiming node specified in the manifest. Null if none found + */ + var parseUTCTiming = function parseUTCTiming(manifestString) { + return parseUTCTimingScheme(stringToMpdXml(manifestString)); + }; + + var toUnsigned = function toUnsigned(value) { + return value >>> 0; + }; + + var bin = { + toUnsigned: toUnsigned + }; + var bin_1 = bin.toUnsigned; + + var bin$1 = /*#__PURE__*/Object.freeze({ + default: bin, + __moduleExports: bin, + toUnsigned: bin_1 + }); + + var require$$0$1 = (bin$1 && bin) || bin$1; + + var toUnsigned$1 = require$$0$1.toUnsigned; + var _findBox, parseType, timescale, startTime; + + // Find the data for a box specified by its path + _findBox = function findBox(data, path) { + var results = [], + i, + size, + type, + end, + subresults; + + if (!path.length) { + // short-circuit the search for empty paths + return null; + } + + for (i = 0; i < data.byteLength;) { + size = toUnsigned$1(data[i] << 24 | data[i + 1] << 16 | data[i + 2] << 8 | data[i + 3]); + + type = parseType(data.subarray(i + 4, i + 8)); + + end = size > 1 ? i + size : data.byteLength; + + if (type === path[0]) { + if (path.length === 1) { + // this is the end of the path and we've found the box we were + // looking for + results.push(data.subarray(i + 8, end)); + } else { + // recursively search for the next box along the path + subresults = _findBox(data.subarray(i + 8, end), path.slice(1)); + if (subresults.length) { + results = results.concat(subresults); + } + } + } + i = end; + } + + // we've finished searching all of data + return results; + }; + + /** + * Returns the string representation of an ASCII encoded four byte buffer. + * @param buffer {Uint8Array} a four-byte buffer to translate + * @return {string} the corresponding string + */ + parseType = function parseType(buffer) { + var result = ''; + result += String.fromCharCode(buffer[0]); + result += String.fromCharCode(buffer[1]); + result += String.fromCharCode(buffer[2]); + result += String.fromCharCode(buffer[3]); + return result; + }; + + /** + * Parses an MP4 initialization segment and extracts the timescale + * values for any declared tracks. Timescale values indicate the + * number of clock ticks per second to assume for time-based values + * elsewhere in the MP4. + * + * To determine the start time of an MP4, you need two pieces of + * information: the timescale unit and the earliest base media decode + * time. Multiple timescales can be specified within an MP4 but the + * base media decode time is always expressed in the timescale from + * the media header box for the track: + * ``` + * moov > trak > mdia > mdhd.timescale + * ``` + * @param init {Uint8Array} the bytes of the init segment + * @return {object} a hash of track ids to timescale values or null if + * the init segment is malformed. + */ + timescale = function timescale(init) { + var result = {}, + traks = _findBox(init, ['moov', 'trak']); + + // mdhd timescale + return traks.reduce(function (result, trak) { + var tkhd, version, index, id, mdhd; + + tkhd = _findBox(trak, ['tkhd'])[0]; + if (!tkhd) { + return null; + } + version = tkhd[0]; + index = version === 0 ? 12 : 20; + id = toUnsigned$1(tkhd[index] << 24 | tkhd[index + 1] << 16 | tkhd[index + 2] << 8 | tkhd[index + 3]); + + mdhd = _findBox(trak, ['mdia', 'mdhd'])[0]; + if (!mdhd) { + return null; + } + version = mdhd[0]; + index = version === 0 ? 12 : 20; + result[id] = toUnsigned$1(mdhd[index] << 24 | mdhd[index + 1] << 16 | mdhd[index + 2] << 8 | mdhd[index + 3]); + return result; + }, result); + }; + + /** + * Determine the base media decode start time, in seconds, for an MP4 + * fragment. If multiple fragments are specified, the earliest time is + * returned. + * + * The base media decode time can be parsed from track fragment + * metadata: + * ``` + * moof > traf > tfdt.baseMediaDecodeTime + * ``` + * It requires the timescale value from the mdhd to interpret. + * + * @param timescale {object} a hash of track ids to timescale values. + * @return {number} the earliest base media decode start time for the + * fragment, in seconds + */ + startTime = function startTime(timescale, fragment) { + var trafs, baseTimes, result; + + // we need info from two childrend of each track fragment box + trafs = _findBox(fragment, ['moof', 'traf']); + + // determine the start times for each track + baseTimes = [].concat.apply([], trafs.map(function (traf) { + return _findBox(traf, ['tfhd']).map(function (tfhd) { + var id, scale, baseTime; + + // get the track id from the tfhd + id = toUnsigned$1(tfhd[4] << 24 | tfhd[5] << 16 | tfhd[6] << 8 | tfhd[7]); + // assume a 90kHz clock if no timescale was specified + scale = timescale[id] || 90e3; + + // get the base media decode time from the tfdt + baseTime = _findBox(traf, ['tfdt']).map(function (tfdt) { + var version, result; + + version = tfdt[0]; + result = toUnsigned$1(tfdt[4] << 24 | tfdt[5] << 16 | tfdt[6] << 8 | tfdt[7]); + if (version === 1) { + result *= Math.pow(2, 32); + result += toUnsigned$1(tfdt[8] << 24 | tfdt[9] << 16 | tfdt[10] << 8 | tfdt[11]); + } + return result; + })[0]; + baseTime = baseTime || Infinity; + + // convert base time to seconds + return baseTime / scale; + }); + })); + + // return the minimum + result = Math.min.apply(null, baseTimes); + return isFinite(result) ? result : 0; + }; + + var probe = { + parseType: parseType, + timescale: timescale, + startTime: startTime + }; + + var streamTypes = { + H264_STREAM_TYPE: 0x1B, + ADTS_STREAM_TYPE: 0x0F, + METADATA_STREAM_TYPE: 0x15 + }; + var streamTypes_1 = streamTypes.H264_STREAM_TYPE; + var streamTypes_2 = streamTypes.ADTS_STREAM_TYPE; + var streamTypes_3 = streamTypes.METADATA_STREAM_TYPE; + + var streamTypes$1 = /*#__PURE__*/Object.freeze({ + default: streamTypes, + __moduleExports: streamTypes, + H264_STREAM_TYPE: streamTypes_1, + ADTS_STREAM_TYPE: streamTypes_2, + METADATA_STREAM_TYPE: streamTypes_3 + }); + + /** + * mux.js + * + * Copyright (c) 2014 Brightcove + * All rights reserved. + * + * A lightweight readable stream implemention that handles event dispatching. + * Objects that inherit from streams should call init in their constructors. + */ + + var Stream$1 = function Stream() { + this.init = function () { + var listeners = {}; + /** + * Add a listener for a specified event type. + * @param type {string} the event name + * @param listener {function} the callback to be invoked when an event of + * the specified type occurs + */ + this.on = function (type, listener) { + if (!listeners[type]) { + listeners[type] = []; + } + listeners[type] = listeners[type].concat(listener); + }; + /** + * Remove a listener for a specified event type. + * @param type {string} the event name + * @param listener {function} a function previously registered for this + * type of event through `on` + */ + this.off = function (type, listener) { + var index; + if (!listeners[type]) { + return false; + } + index = listeners[type].indexOf(listener); + listeners[type] = listeners[type].slice(); + listeners[type].splice(index, 1); + return index > -1; + }; + /** + * Trigger an event of the specified type on this stream. Any additional + * arguments to this function are passed as parameters to event listeners. + * @param type {string} the event name + */ + this.trigger = function (type) { + var callbacks, i, length, args; + callbacks = listeners[type]; + if (!callbacks) { + return; + } + // Slicing the arguments on every invocation of this method + // can add a significant amount of overhead. Avoid the + // intermediate object creation for the common case of a + // single callback argument + if (arguments.length === 2) { + length = callbacks.length; + for (i = 0; i < length; ++i) { + callbacks[i].call(this, arguments[1]); + } + } else { + args = []; + i = arguments.length; + for (i = 1; i < arguments.length; ++i) { + args.push(arguments[i]); + } + length = callbacks.length; + for (i = 0; i < length; ++i) { + callbacks[i].apply(this, args); + } + } + }; + /** + * Destroys the stream and cleans up. + */ + this.dispose = function () { + listeners = {}; + }; + }; + }; + + /** + * Forwards all `data` events on this stream to the destination stream. The + * destination stream should provide a method `push` to receive the data + * events as they arrive. + * @param destination {stream} the stream that will receive all `data` events + * @param autoFlush {boolean} if false, we will not call `flush` on the destination + * when the current stream emits a 'done' event + * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options + */ + Stream$1.prototype.pipe = function (destination) { + this.on('data', function (data) { + destination.push(data); + }); + + this.on('done', function (flushSource) { + destination.flush(flushSource); + }); + + return destination; + }; + + // Default stream functions that are expected to be overridden to perform + // actual work. These are provided by the prototype as a sort of no-op + // implementation so that we don't have to check for their existence in the + // `pipe` function above. + Stream$1.prototype.push = function (data) { + this.trigger('data', data); + }; + + Stream$1.prototype.flush = function (flushSource) { + this.trigger('done', flushSource); + }; + + var stream = Stream$1; + + var stream$1 = /*#__PURE__*/Object.freeze({ + default: stream, + __moduleExports: stream + }); + + var Stream$2 = (stream$1 && stream) || stream$1; + + var MAX_TS = 8589934592; + + var RO_THRESH = 4294967296; + + var handleRollover = function handleRollover(value, reference) { + var direction = 1; + + if (value > reference) { + // If the current timestamp value is greater than our reference timestamp and we detect a + // timestamp rollover, this means the roll over is happening in the opposite direction. + // Example scenario: Enter a long stream/video just after a rollover occurred. The reference + // point will be set to a small number, e.g. 1. The user then seeks backwards over the + // rollover point. In loading this segment, the timestamp values will be very large, + // e.g. 2^33 - 1. Since this comes before the data we loaded previously, we want to adjust + // the time stamp to be `value - 2^33`. + direction = -1; + } + + // Note: A seek forwards or back that is greater than the RO_THRESH (2^32, ~13 hours) will + // cause an incorrect adjustment. + while (Math.abs(reference - value) > RO_THRESH) { + value += direction * MAX_TS; + } + + return value; + }; + + var TimestampRolloverStream = function TimestampRolloverStream(type) { + var lastDTS, referenceDTS; + + TimestampRolloverStream.prototype.init.call(this); + + this.type_ = type; + + this.push = function (data) { + if (data.type !== this.type_) { + return; + } + + if (referenceDTS === undefined) { + referenceDTS = data.dts; + } + + data.dts = handleRollover(data.dts, referenceDTS); + data.pts = handleRollover(data.pts, referenceDTS); + + lastDTS = data.dts; + + this.trigger('data', data); + }; + + this.flush = function () { + referenceDTS = lastDTS; + this.trigger('done'); + }; + + this.discontinuity = function () { + referenceDTS = void 0; + lastDTS = void 0; + }; + }; + + TimestampRolloverStream.prototype = new Stream$2(); + + var timestampRolloverStream = { + TimestampRolloverStream: TimestampRolloverStream, + handleRollover: handleRollover + }; + var timestampRolloverStream_1 = timestampRolloverStream.TimestampRolloverStream; + var timestampRolloverStream_2 = timestampRolloverStream.handleRollover; + + var timestampRolloverStream$1 = /*#__PURE__*/Object.freeze({ + default: timestampRolloverStream, + __moduleExports: timestampRolloverStream, + TimestampRolloverStream: timestampRolloverStream_1, + handleRollover: timestampRolloverStream_2 + }); + + var StreamTypes = (streamTypes$1 && streamTypes) || streamTypes$1; + + var parsePid = function parsePid(packet) { + var pid = packet[1] & 0x1f; + pid <<= 8; + pid |= packet[2]; + return pid; + }; + + var parsePayloadUnitStartIndicator = function parsePayloadUnitStartIndicator(packet) { + return !!(packet[1] & 0x40); + }; + + var parseAdaptionField = function parseAdaptionField(packet) { + var offset = 0; + // if an adaption field is present, its length is specified by the + // fifth byte of the TS packet header. The adaptation field is + // used to add stuffing to PES packets that don't fill a complete + // TS packet, and to specify some forms of timing and control data + // that we do not currently use. + if ((packet[3] & 0x30) >>> 4 > 0x01) { + offset += packet[4] + 1; + } + return offset; + }; + + var parseType$1 = function parseType(packet, pmtPid) { + var pid = parsePid(packet); + if (pid === 0) { + return 'pat'; + } else if (pid === pmtPid) { + return 'pmt'; + } else if (pmtPid) { + return 'pes'; + } + return null; + }; + + var parsePat = function parsePat(packet) { + var pusi = parsePayloadUnitStartIndicator(packet); + var offset = 4 + parseAdaptionField(packet); + + if (pusi) { + offset += packet[offset] + 1; + } + + return (packet[offset + 10] & 0x1f) << 8 | packet[offset + 11]; + }; + + var parsePmt = function parsePmt(packet) { + var programMapTable = {}; + var pusi = parsePayloadUnitStartIndicator(packet); + var payloadOffset = 4 + parseAdaptionField(packet); + + if (pusi) { + payloadOffset += packet[payloadOffset] + 1; + } + + // PMTs can be sent ahead of the time when they should actually + // take effect. We don't believe this should ever be the case + // for HLS but we'll ignore "forward" PMT declarations if we see + // them. Future PMT declarations have the current_next_indicator + // set to zero. + if (!(packet[payloadOffset + 5] & 0x01)) { + return; + } + + var sectionLength, tableEnd, programInfoLength; + // the mapping table ends at the end of the current section + sectionLength = (packet[payloadOffset + 1] & 0x0f) << 8 | packet[payloadOffset + 2]; + tableEnd = 3 + sectionLength - 4; + + // to determine where the table is, we have to figure out how + // long the program info descriptors are + programInfoLength = (packet[payloadOffset + 10] & 0x0f) << 8 | packet[payloadOffset + 11]; + + // advance the offset to the first entry in the mapping table + var offset = 12 + programInfoLength; + while (offset < tableEnd) { + var i = payloadOffset + offset; + // add an entry that maps the elementary_pid to the stream_type + programMapTable[(packet[i + 1] & 0x1F) << 8 | packet[i + 2]] = packet[i]; + + // move to the next table entry + // skip past the elementary stream descriptors, if present + offset += ((packet[i + 3] & 0x0F) << 8 | packet[i + 4]) + 5; + } + return programMapTable; + }; + + var parsePesType = function parsePesType(packet, programMapTable) { + var pid = parsePid(packet); + var type = programMapTable[pid]; + switch (type) { + case StreamTypes.H264_STREAM_TYPE: + return 'video'; + case StreamTypes.ADTS_STREAM_TYPE: + return 'audio'; + case StreamTypes.METADATA_STREAM_TYPE: + return 'timed-metadata'; + default: + return null; + } + }; + + var parsePesTime = function parsePesTime(packet) { + var pusi = parsePayloadUnitStartIndicator(packet); + if (!pusi) { + return null; + } + + var offset = 4 + parseAdaptionField(packet); + + if (offset >= packet.byteLength) { + // From the H 222.0 MPEG-TS spec + // "For transport stream packets carrying PES packets, stuffing is needed when there + // is insufficient PES packet data to completely fill the transport stream packet + // payload bytes. Stuffing is accomplished by defining an adaptation field longer than + // the sum of the lengths of the data elements in it, so that the payload bytes + // remaining after the adaptation field exactly accommodates the available PES packet + // data." + // + // If the offset is >= the length of the packet, then the packet contains no data + // and instead is just adaption field stuffing bytes + return null; + } + + var pes = null; + var ptsDtsFlags; + + // PES packets may be annotated with a PTS value, or a PTS value + // and a DTS value. Determine what combination of values is + // available to work with. + ptsDtsFlags = packet[offset + 7]; + + // PTS and DTS are normally stored as a 33-bit number. Javascript + // performs all bitwise operations on 32-bit integers but javascript + // supports a much greater range (52-bits) of integer using standard + // mathematical operations. + // We construct a 31-bit value using bitwise operators over the 31 + // most significant bits and then multiply by 4 (equal to a left-shift + // of 2) before we add the final 2 least significant bits of the + // timestamp (equal to an OR.) + if (ptsDtsFlags & 0xC0) { + pes = {}; + // the PTS and DTS are not written out directly. For information + // on how they are encoded, see + // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html + pes.pts = (packet[offset + 9] & 0x0E) << 27 | (packet[offset + 10] & 0xFF) << 20 | (packet[offset + 11] & 0xFE) << 12 | (packet[offset + 12] & 0xFF) << 5 | (packet[offset + 13] & 0xFE) >>> 3; + pes.pts *= 4; // Left shift by 2 + pes.pts += (packet[offset + 13] & 0x06) >>> 1; // OR by the two LSBs + pes.dts = pes.pts; + if (ptsDtsFlags & 0x40) { + pes.dts = (packet[offset + 14] & 0x0E) << 27 | (packet[offset + 15] & 0xFF) << 20 | (packet[offset + 16] & 0xFE) << 12 | (packet[offset + 17] & 0xFF) << 5 | (packet[offset + 18] & 0xFE) >>> 3; + pes.dts *= 4; // Left shift by 2 + pes.dts += (packet[offset + 18] & 0x06) >>> 1; // OR by the two LSBs + } + } + return pes; + }; + + var parseNalUnitType = function parseNalUnitType(type) { + switch (type) { + case 0x05: + return 'slice_layer_without_partitioning_rbsp_idr'; + case 0x06: + return 'sei_rbsp'; + case 0x07: + return 'seq_parameter_set_rbsp'; + case 0x08: + return 'pic_parameter_set_rbsp'; + case 0x09: + return 'access_unit_delimiter_rbsp'; + default: + return null; + } + }; + + var videoPacketContainsKeyFrame = function videoPacketContainsKeyFrame(packet) { + var offset = 4 + parseAdaptionField(packet); + var frameBuffer = packet.subarray(offset); + var frameI = 0; + var frameSyncPoint = 0; + var foundKeyFrame = false; + var nalType; + + // advance the sync point to a NAL start, if necessary + for (; frameSyncPoint < frameBuffer.byteLength - 3; frameSyncPoint++) { + if (frameBuffer[frameSyncPoint + 2] === 1) { + // the sync point is properly aligned + frameI = frameSyncPoint + 5; + break; + } + } + + while (frameI < frameBuffer.byteLength) { + // look at the current byte to determine if we've hit the end of + // a NAL unit boundary + switch (frameBuffer[frameI]) { + case 0: + // skip past non-sync sequences + if (frameBuffer[frameI - 1] !== 0) { + frameI += 2; + break; + } else if (frameBuffer[frameI - 2] !== 0) { + frameI++; + break; + } + + if (frameSyncPoint + 3 !== frameI - 2) { + nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f); + if (nalType === 'slice_layer_without_partitioning_rbsp_idr') { + foundKeyFrame = true; + } + } + + // drop trailing zeroes + do { + frameI++; + } while (frameBuffer[frameI] !== 1 && frameI < frameBuffer.length); + frameSyncPoint = frameI - 2; + frameI += 3; + break; + case 1: + // skip past non-sync sequences + if (frameBuffer[frameI - 1] !== 0 || frameBuffer[frameI - 2] !== 0) { + frameI += 3; + break; + } + + nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f); + if (nalType === 'slice_layer_without_partitioning_rbsp_idr') { + foundKeyFrame = true; + } + frameSyncPoint = frameI - 2; + frameI += 3; + break; + default: + // the current byte isn't a one or zero, so it cannot be part + // of a sync sequence + frameI += 3; + break; + } + } + frameBuffer = frameBuffer.subarray(frameSyncPoint); + frameI -= frameSyncPoint; + frameSyncPoint = 0; + // parse the final nal + if (frameBuffer && frameBuffer.byteLength > 3) { + nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f); + if (nalType === 'slice_layer_without_partitioning_rbsp_idr') { + foundKeyFrame = true; + } + } + + return foundKeyFrame; + }; + + var probe$1 = { + parseType: parseType$1, + parsePat: parsePat, + parsePmt: parsePmt, + parsePayloadUnitStartIndicator: parsePayloadUnitStartIndicator, + parsePesType: parsePesType, + parsePesTime: parsePesTime, + videoPacketContainsKeyFrame: videoPacketContainsKeyFrame + }; + var probe_1$1 = probe$1.parseType; + var probe_2$1 = probe$1.parsePat; + var probe_3$1 = probe$1.parsePmt; + var probe_4 = probe$1.parsePayloadUnitStartIndicator; + var probe_5 = probe$1.parsePesType; + var probe_6 = probe$1.parsePesTime; + var probe_7 = probe$1.videoPacketContainsKeyFrame; + + var probe$2 = /*#__PURE__*/Object.freeze({ + default: probe$1, + __moduleExports: probe$1, + parseType: probe_1$1, + parsePat: probe_2$1, + parsePmt: probe_3$1, + parsePayloadUnitStartIndicator: probe_4, + parsePesType: probe_5, + parsePesTime: probe_6, + videoPacketContainsKeyFrame: probe_7 + }); + + /** + * mux.js + * + * Copyright (c) 2016 Brightcove + * All rights reserved. + * + * Utilities to detect basic properties and metadata about Aac data. + */ + + var ADTS_SAMPLING_FREQUENCIES = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350]; + + var parseSyncSafeInteger = function parseSyncSafeInteger(data) { + return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3]; + }; + + // return a percent-encoded representation of the specified byte range + // @see http://en.wikipedia.org/wiki/Percent-encoding + var percentEncode = function percentEncode(bytes, start, end) { + var i, + result = ''; + for (i = start; i < end; i++) { + result += '%' + ('00' + bytes[i].toString(16)).slice(-2); + } + return result; + }; + + // return the string representation of the specified byte range, + // interpreted as ISO-8859-1. + var parseIso88591 = function parseIso88591(bytes, start, end) { + return unescape(percentEncode(bytes, start, end)); // jshint ignore:line + }; + + var parseId3TagSize = function parseId3TagSize(header, byteIndex) { + var returnSize = header[byteIndex + 6] << 21 | header[byteIndex + 7] << 14 | header[byteIndex + 8] << 7 | header[byteIndex + 9], + flags = header[byteIndex + 5], + footerPresent = (flags & 16) >> 4; + + if (footerPresent) { + return returnSize + 20; + } + return returnSize + 10; + }; + + var parseAdtsSize = function parseAdtsSize(header, byteIndex) { + var lowThree = (header[byteIndex + 5] & 0xE0) >> 5, + middle = header[byteIndex + 4] << 3, + highTwo = header[byteIndex + 3] & 0x3 << 11; + + return highTwo | middle | lowThree; + }; + + var parseType$2 = function parseType(header, byteIndex) { + if (header[byteIndex] === 'I'.charCodeAt(0) && header[byteIndex + 1] === 'D'.charCodeAt(0) && header[byteIndex + 2] === '3'.charCodeAt(0)) { + return 'timed-metadata'; + } else if (header[byteIndex] & 0xff === 0xff && (header[byteIndex + 1] & 0xf0) === 0xf0) { + return 'audio'; + } + return null; + }; + + var parseSampleRate = function parseSampleRate(packet) { + var i = 0; + + while (i + 5 < packet.length) { + if (packet[i] !== 0xFF || (packet[i + 1] & 0xF6) !== 0xF0) { + // If a valid header was not found, jump one forward and attempt to + // find a valid ADTS header starting at the next byte + i++; + continue; + } + return ADTS_SAMPLING_FREQUENCIES[(packet[i + 2] & 0x3c) >>> 2]; + } + + return null; + }; + + var parseAacTimestamp = function parseAacTimestamp(packet) { + var frameStart, frameSize, frame, frameHeader; + + // find the start of the first frame and the end of the tag + frameStart = 10; + if (packet[5] & 0x40) { + // advance the frame start past the extended header + frameStart += 4; // header size field + frameStart += parseSyncSafeInteger(packet.subarray(10, 14)); + } + + // parse one or more ID3 frames + // http://id3.org/id3v2.3.0#ID3v2_frame_overview + do { + // determine the number of bytes in this frame + frameSize = parseSyncSafeInteger(packet.subarray(frameStart + 4, frameStart + 8)); + if (frameSize < 1) { + return null; + } + frameHeader = String.fromCharCode(packet[frameStart], packet[frameStart + 1], packet[frameStart + 2], packet[frameStart + 3]); + + if (frameHeader === 'PRIV') { + frame = packet.subarray(frameStart + 10, frameStart + frameSize + 10); + + for (var i = 0; i < frame.byteLength; i++) { + if (frame[i] === 0) { + var owner = parseIso88591(frame, 0, i); + if (owner === 'com.apple.streaming.transportStreamTimestamp') { + var d = frame.subarray(i + 1); + var size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2; + size *= 4; + size += d[7] & 0x03; + + return size; + } + break; + } + } + } + + frameStart += 10; // advance past the frame header + frameStart += frameSize; // advance past the frame body + } while (frameStart < packet.byteLength); + return null; + }; + + var probe$3 = { + parseId3TagSize: parseId3TagSize, + parseAdtsSize: parseAdtsSize, + parseType: parseType$2, + parseSampleRate: parseSampleRate, + parseAacTimestamp: parseAacTimestamp + }; + var probe_1$2 = probe$3.parseId3TagSize; + var probe_2$2 = probe$3.parseAdtsSize; + var probe_3$2 = probe$3.parseType; + var probe_4$1 = probe$3.parseSampleRate; + var probe_5$1 = probe$3.parseAacTimestamp; + + var probe$4 = /*#__PURE__*/Object.freeze({ + default: probe$3, + __moduleExports: probe$3, + parseId3TagSize: probe_1$2, + parseAdtsSize: probe_2$2, + parseType: probe_3$2, + parseSampleRate: probe_4$1, + parseAacTimestamp: probe_5$1 + }); + + var require$$0$2 = (timestampRolloverStream$1 && timestampRolloverStream) || timestampRolloverStream$1; + + var require$$1$1 = (probe$2 && probe$1) || probe$2; + + var require$$2$1 = (probe$4 && probe$3) || probe$4; + + var handleRollover$1 = require$$0$2.handleRollover; + var probe$5 = {}; + probe$5.ts = require$$1$1; + probe$5.aac = require$$2$1; + + var PES_TIMESCALE = 90000, + MP2T_PACKET_LENGTH = 188, + // bytes + SYNC_BYTE = 0x47; + + var isLikelyAacData = function isLikelyAacData(data) { + if (data[0] === 'I'.charCodeAt(0) && data[1] === 'D'.charCodeAt(0) && data[2] === '3'.charCodeAt(0)) { + return true; + } + return false; + }; + + /** + * walks through segment data looking for pat and pmt packets to parse out + * program map table information + */ + var parsePsi_ = function parsePsi_(bytes, pmt) { + var startIndex = 0, + endIndex = MP2T_PACKET_LENGTH, + packet, + type; + + while (endIndex < bytes.byteLength) { + // Look for a pair of start and end sync bytes in the data.. + if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) { + // We found a packet + packet = bytes.subarray(startIndex, endIndex); + type = probe$5.ts.parseType(packet, pmt.pid); + + switch (type) { + case 'pat': + if (!pmt.pid) { + pmt.pid = probe$5.ts.parsePat(packet); + } + break; + case 'pmt': + if (!pmt.table) { + pmt.table = probe$5.ts.parsePmt(packet); + } + break; + default: + break; + } + + // Found the pat and pmt, we can stop walking the segment + if (pmt.pid && pmt.table) { + return; + } + + startIndex += MP2T_PACKET_LENGTH; + endIndex += MP2T_PACKET_LENGTH; + continue; + } + + // If we get here, we have somehow become de-synchronized and we need to step + // forward one byte at a time until we find a pair of sync bytes that denote + // a packet + startIndex++; + endIndex++; + } + }; + + /** + * walks through the segment data from the start and end to get timing information + * for the first and last audio pes packets + */ + var parseAudioPes_ = function parseAudioPes_(bytes, pmt, result) { + var startIndex = 0, + endIndex = MP2T_PACKET_LENGTH, + packet, + type, + pesType, + pusi, + parsed; + + var endLoop = false; + + // Start walking from start of segment to get first audio packet + while (endIndex < bytes.byteLength) { + // Look for a pair of start and end sync bytes in the data.. + if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) { + // We found a packet + packet = bytes.subarray(startIndex, endIndex); + type = probe$5.ts.parseType(packet, pmt.pid); + + switch (type) { + case 'pes': + pesType = probe$5.ts.parsePesType(packet, pmt.table); + pusi = probe$5.ts.parsePayloadUnitStartIndicator(packet); + if (pesType === 'audio' && pusi) { + parsed = probe$5.ts.parsePesTime(packet); + if (parsed) { + parsed.type = 'audio'; + result.audio.push(parsed); + endLoop = true; + } + } + break; + default: + break; + } + + if (endLoop) { + break; + } + + startIndex += MP2T_PACKET_LENGTH; + endIndex += MP2T_PACKET_LENGTH; + continue; + } + + // If we get here, we have somehow become de-synchronized and we need to step + // forward one byte at a time until we find a pair of sync bytes that denote + // a packet + startIndex++; + endIndex++; + } + + // Start walking from end of segment to get last audio packet + endIndex = bytes.byteLength; + startIndex = endIndex - MP2T_PACKET_LENGTH; + endLoop = false; + while (startIndex >= 0) { + // Look for a pair of start and end sync bytes in the data.. + if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) { + // We found a packet + packet = bytes.subarray(startIndex, endIndex); + type = probe$5.ts.parseType(packet, pmt.pid); + + switch (type) { + case 'pes': + pesType = probe$5.ts.parsePesType(packet, pmt.table); + pusi = probe$5.ts.parsePayloadUnitStartIndicator(packet); + if (pesType === 'audio' && pusi) { + parsed = probe$5.ts.parsePesTime(packet); + if (parsed) { + parsed.type = 'audio'; + result.audio.push(parsed); + endLoop = true; + } + } + break; + default: + break; + } + + if (endLoop) { + break; + } + + startIndex -= MP2T_PACKET_LENGTH; + endIndex -= MP2T_PACKET_LENGTH; + continue; + } + + // If we get here, we have somehow become de-synchronized and we need to step + // forward one byte at a time until we find a pair of sync bytes that denote + // a packet + startIndex--; + endIndex--; + } + }; + + /** + * walks through the segment data from the start and end to get timing information + * for the first and last video pes packets as well as timing information for the first + * key frame. + */ + var parseVideoPes_ = function parseVideoPes_(bytes, pmt, result) { + var startIndex = 0, + endIndex = MP2T_PACKET_LENGTH, + packet, + type, + pesType, + pusi, + parsed, + frame, + i, + pes; + + var endLoop = false; + + var currentFrame = { + data: [], + size: 0 + }; + + // Start walking from start of segment to get first video packet + while (endIndex < bytes.byteLength) { + // Look for a pair of start and end sync bytes in the data.. + if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) { + // We found a packet + packet = bytes.subarray(startIndex, endIndex); + type = probe$5.ts.parseType(packet, pmt.pid); + + switch (type) { + case 'pes': + pesType = probe$5.ts.parsePesType(packet, pmt.table); + pusi = probe$5.ts.parsePayloadUnitStartIndicator(packet); + if (pesType === 'video') { + if (pusi && !endLoop) { + parsed = probe$5.ts.parsePesTime(packet); + if (parsed) { + parsed.type = 'video'; + result.video.push(parsed); + endLoop = true; + } + } + if (!result.firstKeyFrame) { + if (pusi) { + if (currentFrame.size !== 0) { + frame = new Uint8Array(currentFrame.size); + i = 0; + while (currentFrame.data.length) { + pes = currentFrame.data.shift(); + frame.set(pes, i); + i += pes.byteLength; + } + if (probe$5.ts.videoPacketContainsKeyFrame(frame)) { + result.firstKeyFrame = probe$5.ts.parsePesTime(frame); + result.firstKeyFrame.type = 'video'; + } + currentFrame.size = 0; + } + } + currentFrame.data.push(packet); + currentFrame.size += packet.byteLength; + } + } + break; + default: + break; + } + + if (endLoop && result.firstKeyFrame) { + break; + } + + startIndex += MP2T_PACKET_LENGTH; + endIndex += MP2T_PACKET_LENGTH; + continue; + } + + // If we get here, we have somehow become de-synchronized and we need to step + // forward one byte at a time until we find a pair of sync bytes that denote + // a packet + startIndex++; + endIndex++; + } + + // Start walking from end of segment to get last video packet + endIndex = bytes.byteLength; + startIndex = endIndex - MP2T_PACKET_LENGTH; + endLoop = false; + while (startIndex >= 0) { + // Look for a pair of start and end sync bytes in the data.. + if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) { + // We found a packet + packet = bytes.subarray(startIndex, endIndex); + type = probe$5.ts.parseType(packet, pmt.pid); + + switch (type) { + case 'pes': + pesType = probe$5.ts.parsePesType(packet, pmt.table); + pusi = probe$5.ts.parsePayloadUnitStartIndicator(packet); + if (pesType === 'video' && pusi) { + parsed = probe$5.ts.parsePesTime(packet); + if (parsed) { + parsed.type = 'video'; + result.video.push(parsed); + endLoop = true; + } + } + break; + default: + break; + } + + if (endLoop) { + break; + } + + startIndex -= MP2T_PACKET_LENGTH; + endIndex -= MP2T_PACKET_LENGTH; + continue; + } + + // If we get here, we have somehow become de-synchronized and we need to step + // forward one byte at a time until we find a pair of sync bytes that denote + // a packet + startIndex--; + endIndex--; + } + }; + + /** + * Adjusts the timestamp information for the segment to account for + * rollover and convert to seconds based on pes packet timescale (90khz clock) + */ + var adjustTimestamp_ = function adjustTimestamp_(segmentInfo, baseTimestamp) { + if (segmentInfo.audio && segmentInfo.audio.length) { + var audioBaseTimestamp = baseTimestamp; + if (typeof audioBaseTimestamp === 'undefined') { + audioBaseTimestamp = segmentInfo.audio[0].dts; + } + segmentInfo.audio.forEach(function (info) { + info.dts = handleRollover$1(info.dts, audioBaseTimestamp); + info.pts = handleRollover$1(info.pts, audioBaseTimestamp); + // time in seconds + info.dtsTime = info.dts / PES_TIMESCALE; + info.ptsTime = info.pts / PES_TIMESCALE; + }); + } + + if (segmentInfo.video && segmentInfo.video.length) { + var videoBaseTimestamp = baseTimestamp; + if (typeof videoBaseTimestamp === 'undefined') { + videoBaseTimestamp = segmentInfo.video[0].dts; + } + segmentInfo.video.forEach(function (info) { + info.dts = handleRollover$1(info.dts, videoBaseTimestamp); + info.pts = handleRollover$1(info.pts, videoBaseTimestamp); + // time in seconds + info.dtsTime = info.dts / PES_TIMESCALE; + info.ptsTime = info.pts / PES_TIMESCALE; + }); + if (segmentInfo.firstKeyFrame) { + var frame = segmentInfo.firstKeyFrame; + frame.dts = handleRollover$1(frame.dts, videoBaseTimestamp); + frame.pts = handleRollover$1(frame.pts, videoBaseTimestamp); + // time in seconds + frame.dtsTime = frame.dts / PES_TIMESCALE; + frame.ptsTime = frame.dts / PES_TIMESCALE; + } + } + }; + + /** + * inspects the aac data stream for start and end time information + */ + var inspectAac_ = function inspectAac_(bytes) { + var endLoop = false, + audioCount = 0, + sampleRate = null, + timestamp = null, + frameSize = 0, + byteIndex = 0, + packet; + + while (bytes.length - byteIndex >= 3) { + var type = probe$5.aac.parseType(bytes, byteIndex); + switch (type) { + case 'timed-metadata': + // Exit early because we don't have enough to parse + // the ID3 tag header + if (bytes.length - byteIndex < 10) { + endLoop = true; + break; + } + + frameSize = probe$5.aac.parseId3TagSize(bytes, byteIndex); + + // Exit early if we don't have enough in the buffer + // to emit a full packet + if (frameSize > bytes.length) { + endLoop = true; + break; + } + if (timestamp === null) { + packet = bytes.subarray(byteIndex, byteIndex + frameSize); + timestamp = probe$5.aac.parseAacTimestamp(packet); + } + byteIndex += frameSize; + break; + case 'audio': + // Exit early because we don't have enough to parse + // the ADTS frame header + if (bytes.length - byteIndex < 7) { + endLoop = true; + break; + } + + frameSize = probe$5.aac.parseAdtsSize(bytes, byteIndex); + + // Exit early if we don't have enough in the buffer + // to emit a full packet + if (frameSize > bytes.length) { + endLoop = true; + break; + } + if (sampleRate === null) { + packet = bytes.subarray(byteIndex, byteIndex + frameSize); + sampleRate = probe$5.aac.parseSampleRate(packet); + } + audioCount++; + byteIndex += frameSize; + break; + default: + byteIndex++; + break; + } + if (endLoop) { + return null; + } + } + if (sampleRate === null || timestamp === null) { + return null; + } + + var audioTimescale = PES_TIMESCALE / sampleRate; + + var result = { + audio: [{ + type: 'audio', + dts: timestamp, + pts: timestamp + }, { + type: 'audio', + dts: timestamp + audioCount * 1024 * audioTimescale, + pts: timestamp + audioCount * 1024 * audioTimescale + }] + }; + + return result; + }; + + /** + * inspects the transport stream segment data for start and end time information + * of the audio and video tracks (when present) as well as the first key frame's + * start time. + */ + var inspectTs_ = function inspectTs_(bytes) { + var pmt = { + pid: null, + table: null + }; + + var result = {}; + + parsePsi_(bytes, pmt); + + for (var pid in pmt.table) { + if (pmt.table.hasOwnProperty(pid)) { + var type = pmt.table[pid]; + switch (type) { + case StreamTypes.H264_STREAM_TYPE: + result.video = []; + parseVideoPes_(bytes, pmt, result); + if (result.video.length === 0) { + delete result.video; + } + break; + case StreamTypes.ADTS_STREAM_TYPE: + result.audio = []; + parseAudioPes_(bytes, pmt, result); + if (result.audio.length === 0) { + delete result.audio; + } + break; + default: + break; + } + } + } + return result; + }; + + /** + * Inspects segment byte data and returns an object with start and end timing information + * + * @param {Uint8Array} bytes The segment byte data + * @param {Number} baseTimestamp Relative reference timestamp used when adjusting frame + * timestamps for rollover. This value must be in 90khz clock. + * @return {Object} Object containing start and end frame timing info of segment. + */ + var inspect = function inspect(bytes, baseTimestamp) { + var isAacData = isLikelyAacData(bytes); + + var result; + + if (isAacData) { + result = inspectAac_(bytes); + } else { + result = inspectTs_(bytes); + } + + if (!result || !result.audio && !result.video) { + return null; + } + + adjustTimestamp_(result, baseTimestamp); + + return result; + }; + + var tsInspector = { + inspect: inspect + }; + + /* + * pkcs7.pad + * https://github.com/brightcove/pkcs7 + * + * Copyright (c) 2014 Brightcove + * Licensed under the apache2 license. + */ + + /** + * Returns the subarray of a Uint8Array without PKCS#7 padding. + * @param padded {Uint8Array} unencrypted bytes that have been padded + * @return {Uint8Array} the unpadded bytes + * @see http://tools.ietf.org/html/rfc5652 + */ + function unpad(padded) { + return padded.subarray(0, padded.byteLength - padded[padded.byteLength - 1]); + } + + var classCallCheck$2 = function classCallCheck$$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + var createClass$1 = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var inherits$2 = function inherits$$1(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : _typeof(superClass))); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + }; + + var possibleConstructorReturn$2 = function possibleConstructorReturn$$1(self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && ((typeof call === "undefined" ? "undefined" : _typeof(call)) === "object" || typeof call === "function") ? call : self; + }; + + /** + * @file aes.js + * + * This file contains an adaptation of the AES decryption algorithm + * from the Standford Javascript Cryptography Library. That work is + * covered by the following copyright and permissions notice: + * + * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies, either expressed or implied, of the authors. + */ + + /** + * Expand the S-box tables. + * + * @private + */ + var precompute = function precompute() { + var tables = [[[], [], [], [], []], [[], [], [], [], []]]; + var encTable = tables[0]; + var decTable = tables[1]; + var sbox = encTable[4]; + var sboxInv = decTable[4]; + var i = void 0; + var x = void 0; + var xInv = void 0; + var d = []; + var th = []; + var x2 = void 0; + var x4 = void 0; + var x8 = void 0; + var s = void 0; + var tEnc = void 0; + var tDec = void 0; + + // Compute double and third tables + for (i = 0; i < 256; i++) { + th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i; + } + + for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) { + // Compute sbox + s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4; + s = s >> 8 ^ s & 255 ^ 99; + sbox[x] = s; + sboxInv[s] = x; + + // Compute MixColumns + x8 = d[x4 = d[x2 = d[x]]]; + tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100; + tEnc = d[s] * 0x101 ^ s * 0x1010100; + + for (i = 0; i < 4; i++) { + encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8; + decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8; + } + } + + // Compactify. Considerable speedup on Firefox. + for (i = 0; i < 5; i++) { + encTable[i] = encTable[i].slice(0); + decTable[i] = decTable[i].slice(0); + } + return tables; + }; + var aesTables = null; + + /** + * Schedule out an AES key for both encryption and decryption. This + * is a low-level class. Use a cipher mode to do bulk encryption. + * + * @class AES + * @param key {Array} The key as an array of 4, 6 or 8 words. + */ + + var AES = function () { + function AES(key) { + classCallCheck$2(this, AES); + + /** + * The expanded S-box and inverse S-box tables. These will be computed + * on the client so that we don't have to send them down the wire. + * + * There are two tables, _tables[0] is for encryption and + * _tables[1] is for decryption. + * + * The first 4 sub-tables are the expanded S-box with MixColumns. The + * last (_tables[01][4]) is the S-box itself. + * + * @private + */ + // if we have yet to precompute the S-box tables + // do so now + if (!aesTables) { + aesTables = precompute(); + } + // then make a copy of that object for use + this._tables = [[aesTables[0][0].slice(), aesTables[0][1].slice(), aesTables[0][2].slice(), aesTables[0][3].slice(), aesTables[0][4].slice()], [aesTables[1][0].slice(), aesTables[1][1].slice(), aesTables[1][2].slice(), aesTables[1][3].slice(), aesTables[1][4].slice()]]; + var i = void 0; + var j = void 0; + var tmp = void 0; + var encKey = void 0; + var decKey = void 0; + var sbox = this._tables[0][4]; + var decTable = this._tables[1]; + var keyLen = key.length; + var rcon = 1; + + if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) { + throw new Error('Invalid aes key size'); + } + + encKey = key.slice(0); + decKey = []; + this._key = [encKey, decKey]; + + // schedule encryption keys + for (i = keyLen; i < 4 * keyLen + 28; i++) { + tmp = encKey[i - 1]; + + // apply sbox + if (i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) { + tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255]; + + // shift rows and add rcon + if (i % keyLen === 0) { + tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24; + rcon = rcon << 1 ^ (rcon >> 7) * 283; + } + } + + encKey[i] = encKey[i - keyLen] ^ tmp; + } + + // schedule decryption keys + for (j = 0; i; j++, i--) { + tmp = encKey[j & 3 ? i : i - 4]; + if (i <= 4 || j < 4) { + decKey[j] = tmp; + } else { + decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]]; + } + } + } + + /** + * Decrypt 16 bytes, specified as four 32-bit words. + * + * @param {Number} encrypted0 the first word to decrypt + * @param {Number} encrypted1 the second word to decrypt + * @param {Number} encrypted2 the third word to decrypt + * @param {Number} encrypted3 the fourth word to decrypt + * @param {Int32Array} out the array to write the decrypted words + * into + * @param {Number} offset the offset into the output array to start + * writing results + * @return {Array} The plaintext. + */ + + AES.prototype.decrypt = function decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) { + var key = this._key[1]; + // state variables a,b,c,d are loaded with pre-whitened data + var a = encrypted0 ^ key[0]; + var b = encrypted3 ^ key[1]; + var c = encrypted2 ^ key[2]; + var d = encrypted1 ^ key[3]; + var a2 = void 0; + var b2 = void 0; + var c2 = void 0; + + // key.length === 2 ? + var nInnerRounds = key.length / 4 - 2; + var i = void 0; + var kIndex = 4; + var table = this._tables[1]; + + // load up the tables + var table0 = table[0]; + var table1 = table[1]; + var table2 = table[2]; + var table3 = table[3]; + var sbox = table[4]; + + // Inner rounds. Cribbed from OpenSSL. + for (i = 0; i < nInnerRounds; i++) { + a2 = table0[a >>> 24] ^ table1[b >> 16 & 255] ^ table2[c >> 8 & 255] ^ table3[d & 255] ^ key[kIndex]; + b2 = table0[b >>> 24] ^ table1[c >> 16 & 255] ^ table2[d >> 8 & 255] ^ table3[a & 255] ^ key[kIndex + 1]; + c2 = table0[c >>> 24] ^ table1[d >> 16 & 255] ^ table2[a >> 8 & 255] ^ table3[b & 255] ^ key[kIndex + 2]; + d = table0[d >>> 24] ^ table1[a >> 16 & 255] ^ table2[b >> 8 & 255] ^ table3[c & 255] ^ key[kIndex + 3]; + kIndex += 4; + a = a2; + b = b2; + c = c2; + } + + // Last round. + for (i = 0; i < 4; i++) { + out[(3 & -i) + offset] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++]; + a2 = a; + a = b; + b = c; + c = d; + d = a2; + } + }; + + return AES; + }(); + + /** + * @file stream.js + */ + /** + * A lightweight readable stream implemention that handles event dispatching. + * + * @class Stream + */ + var Stream$3 = function () { + function Stream() { + classCallCheck$2(this, Stream); + + this.listeners = {}; + } + + /** + * Add a listener for a specified event type. + * + * @param {String} type the event name + * @param {Function} listener the callback to be invoked when an event of + * the specified type occurs + */ + + Stream.prototype.on = function on(type, listener) { + if (!this.listeners[type]) { + this.listeners[type] = []; + } + this.listeners[type].push(listener); + }; + + /** + * Remove a listener for a specified event type. + * + * @param {String} type the event name + * @param {Function} listener a function previously registered for this + * type of event through `on` + * @return {Boolean} if we could turn it off or not + */ + + Stream.prototype.off = function off(type, listener) { + if (!this.listeners[type]) { + return false; + } + + var index = this.listeners[type].indexOf(listener); + + this.listeners[type].splice(index, 1); + return index > -1; + }; + + /** + * Trigger an event of the specified type on this stream. Any additional + * arguments to this function are passed as parameters to event listeners. + * + * @param {String} type the event name + */ + + Stream.prototype.trigger = function trigger(type) { + var callbacks = this.listeners[type]; + + if (!callbacks) { + return; + } + + // Slicing the arguments on every invocation of this method + // can add a significant amount of overhead. Avoid the + // intermediate object creation for the common case of a + // single callback argument + if (arguments.length === 2) { + var length = callbacks.length; + + for (var i = 0; i < length; ++i) { + callbacks[i].call(this, arguments[1]); + } + } else { + var args = Array.prototype.slice.call(arguments, 1); + var _length = callbacks.length; + + for (var _i = 0; _i < _length; ++_i) { + callbacks[_i].apply(this, args); + } + } + }; + + /** + * Destroys the stream and cleans up. + */ + + Stream.prototype.dispose = function dispose() { + this.listeners = {}; + }; + /** + * Forwards all `data` events on this stream to the destination stream. The + * destination stream should provide a method `push` to receive the data + * events as they arrive. + * + * @param {Stream} destination the stream that will receive all `data` events + * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options + */ + + Stream.prototype.pipe = function pipe(destination) { + this.on('data', function (data) { + destination.push(data); + }); + }; + + return Stream; + }(); + + /** + * @file async-stream.js + */ + /** + * A wrapper around the Stream class to use setTiemout + * and run stream "jobs" Asynchronously + * + * @class AsyncStream + * @extends Stream + */ + + var AsyncStream = function (_Stream) { + inherits$2(AsyncStream, _Stream); + + function AsyncStream() { + classCallCheck$2(this, AsyncStream); + + var _this = possibleConstructorReturn$2(this, _Stream.call(this, Stream$3)); + + _this.jobs = []; + _this.delay = 1; + _this.timeout_ = null; + return _this; + } + + /** + * process an async job + * + * @private + */ + + AsyncStream.prototype.processJob_ = function processJob_() { + this.jobs.shift()(); + if (this.jobs.length) { + this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay); + } else { + this.timeout_ = null; + } + }; + + /** + * push a job into the stream + * + * @param {Function} job the job to push into the stream + */ + + AsyncStream.prototype.push = function push(job) { + this.jobs.push(job); + if (!this.timeout_) { + this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay); + } + }; + + return AsyncStream; + }(Stream$3); + + /** + * @file decrypter.js + * + * An asynchronous implementation of AES-128 CBC decryption with + * PKCS#7 padding. + */ + + /** + * Convert network-order (big-endian) bytes into their little-endian + * representation. + */ + var ntoh = function ntoh(word) { + return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24; + }; + + /** + * Decrypt bytes using AES-128 with CBC and PKCS#7 padding. + * + * @param {Uint8Array} encrypted the encrypted bytes + * @param {Uint32Array} key the bytes of the decryption key + * @param {Uint32Array} initVector the initialization vector (IV) to + * use for the first round of CBC. + * @return {Uint8Array} the decrypted bytes + * + * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard + * @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29 + * @see https://tools.ietf.org/html/rfc2315 + */ + var decrypt = function decrypt(encrypted, key, initVector) { + // word-level access to the encrypted bytes + var encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2); + + var decipher = new AES(Array.prototype.slice.call(key)); + + // byte and word-level access for the decrypted output + var decrypted = new Uint8Array(encrypted.byteLength); + var decrypted32 = new Int32Array(decrypted.buffer); + + // temporary variables for working with the IV, encrypted, and + // decrypted data + var init0 = void 0; + var init1 = void 0; + var init2 = void 0; + var init3 = void 0; + var encrypted0 = void 0; + var encrypted1 = void 0; + var encrypted2 = void 0; + var encrypted3 = void 0; + + // iteration variable + var wordIx = void 0; + + // pull out the words of the IV to ensure we don't modify the + // passed-in reference and easier access + init0 = initVector[0]; + init1 = initVector[1]; + init2 = initVector[2]; + init3 = initVector[3]; + + // decrypt four word sequences, applying cipher-block chaining (CBC) + // to each decrypted block + for (wordIx = 0; wordIx < encrypted32.length; wordIx += 4) { + // convert big-endian (network order) words into little-endian + // (javascript order) + encrypted0 = ntoh(encrypted32[wordIx]); + encrypted1 = ntoh(encrypted32[wordIx + 1]); + encrypted2 = ntoh(encrypted32[wordIx + 2]); + encrypted3 = ntoh(encrypted32[wordIx + 3]); + + // decrypt the block + decipher.decrypt(encrypted0, encrypted1, encrypted2, encrypted3, decrypted32, wordIx); + + // XOR with the IV, and restore network byte-order to obtain the + // plaintext + decrypted32[wordIx] = ntoh(decrypted32[wordIx] ^ init0); + decrypted32[wordIx + 1] = ntoh(decrypted32[wordIx + 1] ^ init1); + decrypted32[wordIx + 2] = ntoh(decrypted32[wordIx + 2] ^ init2); + decrypted32[wordIx + 3] = ntoh(decrypted32[wordIx + 3] ^ init3); + + // setup the IV for the next round + init0 = encrypted0; + init1 = encrypted1; + init2 = encrypted2; + init3 = encrypted3; + } + + return decrypted; + }; + + /** + * The `Decrypter` class that manages decryption of AES + * data through `AsyncStream` objects and the `decrypt` + * function + * + * @param {Uint8Array} encrypted the encrypted bytes + * @param {Uint32Array} key the bytes of the decryption key + * @param {Uint32Array} initVector the initialization vector (IV) to + * @param {Function} done the function to run when done + * @class Decrypter + */ + + var Decrypter = function () { + function Decrypter(encrypted, key, initVector, done) { + classCallCheck$2(this, Decrypter); + + var step = Decrypter.STEP; + var encrypted32 = new Int32Array(encrypted.buffer); + var decrypted = new Uint8Array(encrypted.byteLength); + var i = 0; + + this.asyncStream_ = new AsyncStream(); + + // split up the encryption job and do the individual chunks asynchronously + this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted)); + for (i = step; i < encrypted32.length; i += step) { + initVector = new Uint32Array([ntoh(encrypted32[i - 4]), ntoh(encrypted32[i - 3]), ntoh(encrypted32[i - 2]), ntoh(encrypted32[i - 1])]); + this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted)); + } + // invoke the done() callback when everything is finished + this.asyncStream_.push(function () { + // remove pkcs#7 padding from the decrypted bytes + done(null, unpad(decrypted)); + }); + } + + /** + * a getter for step the maximum number of bytes to process at one time + * + * @return {Number} the value of step 32000 + */ + + /** + * @private + */ + Decrypter.prototype.decryptChunk_ = function decryptChunk_(encrypted, key, initVector, decrypted) { + return function () { + var bytes = decrypt(encrypted, key, initVector); + + decrypted.set(bytes, encrypted.byteOffset); + }; + }; + + createClass$1(Decrypter, null, [{ + key: 'STEP', + get: function get$$1() { + // 4 * 8000; + return 32000; + } + }]); + return Decrypter; + }(); + + /** + * @videojs/http-streaming + * @version 1.0.0 + * @copyright 2018 Brightcove, Inc + * @license Apache-2.0 + */ + + /** + * @file resolve-url.js + */ + + var resolveUrl$1 = function resolveUrl(baseURL, relativeURL) { + // return early if we don't need to resolve + if (/^[a-z]+:/i.test(relativeURL)) { + return relativeURL; + } + + // if the base URL is relative then combine with the current location + if (!/\/\//i.test(baseURL)) { + baseURL = urlToolkit.buildAbsoluteURL(window_1.location.href, baseURL); + } + + return urlToolkit.buildAbsoluteURL(baseURL, relativeURL); + }; + + /** + * @file playlist-loader.js + * + * A state machine that manages the loading, caching, and updating of + * M3U8 playlists. + * + */ + + var mergeOptions$1 = videojs$1.mergeOptions, + EventTarget$1 = videojs$1.EventTarget, + log$2 = videojs$1.log; + + /** + * Loops through all supported media groups in master and calls the provided + * callback for each group + * + * @param {Object} master + * The parsed master manifest object + * @param {Function} callback + * Callback to call for each media group + */ + + var forEachMediaGroup = function forEachMediaGroup(master, callback) { + ['AUDIO', 'SUBTITLES'].forEach(function (mediaType) { + for (var groupKey in master.mediaGroups[mediaType]) { + for (var labelKey in master.mediaGroups[mediaType][groupKey]) { + var mediaProperties = master.mediaGroups[mediaType][groupKey][labelKey]; + + callback(mediaProperties, mediaType, groupKey, labelKey); + } + } + }); + }; + + /** + * Returns a new array of segments that is the result of merging + * properties from an older list of segments onto an updated + * list. No properties on the updated playlist will be overridden. + * + * @param {Array} original the outdated list of segments + * @param {Array} update the updated list of segments + * @param {Number=} offset the index of the first update + * segment in the original segment list. For non-live playlists, + * this should always be zero and does not need to be + * specified. For live playlists, it should be the difference + * between the media sequence numbers in the original and updated + * playlists. + * @return a list of merged segment objects + */ + var updateSegments = function updateSegments(original, update, offset) { + var result = update.slice(); + + offset = offset || 0; + var length = Math.min(original.length, update.length + offset); + + for (var i = offset; i < length; i++) { + result[i - offset] = mergeOptions$1(original[i], result[i - offset]); + } + return result; + }; + + var resolveSegmentUris = function resolveSegmentUris(segment, baseUri) { + if (!segment.resolvedUri) { + segment.resolvedUri = resolveUrl$1(baseUri, segment.uri); + } + if (segment.key && !segment.key.resolvedUri) { + segment.key.resolvedUri = resolveUrl$1(baseUri, segment.key.uri); + } + if (segment.map && !segment.map.resolvedUri) { + segment.map.resolvedUri = resolveUrl$1(baseUri, segment.map.uri); + } + }; + + /** + * Returns a new master playlist that is the result of merging an + * updated media playlist into the original version. If the + * updated media playlist does not match any of the playlist + * entries in the original master playlist, null is returned. + * + * @param {Object} master a parsed master M3U8 object + * @param {Object} media a parsed media M3U8 object + * @return {Object} a new object that represents the original + * master playlist with the updated media playlist merged in, or + * null if the merge produced no change. + */ + var updateMaster = function updateMaster(master, media) { + var result = mergeOptions$1(master, {}); + var playlist = result.playlists[media.uri]; + + if (!playlist) { + return null; + } + + // consider the playlist unchanged if the number of segments is equal and the media + // sequence number is unchanged + if (playlist.segments && media.segments && playlist.segments.length === media.segments.length && playlist.mediaSequence === media.mediaSequence) { + return null; + } + + var mergedPlaylist = mergeOptions$1(playlist, media); + + // if the update could overlap existing segment information, merge the two segment lists + if (playlist.segments) { + mergedPlaylist.segments = updateSegments(playlist.segments, media.segments, media.mediaSequence - playlist.mediaSequence); + } + + // resolve any segment URIs to prevent us from having to do it later + mergedPlaylist.segments.forEach(function (segment) { + resolveSegmentUris(segment, mergedPlaylist.resolvedUri); + }); + + // TODO Right now in the playlists array there are two references to each playlist, one + // that is referenced by index, and one by URI. The index reference may no longer be + // necessary. + for (var i = 0; i < result.playlists.length; i++) { + if (result.playlists[i].uri === media.uri) { + result.playlists[i] = mergedPlaylist; + } + } + result.playlists[media.uri] = mergedPlaylist; + + return result; + }; + + var setupMediaPlaylists = function setupMediaPlaylists(master) { + // setup by-URI lookups and resolve media playlist URIs + var i = master.playlists.length; + + while (i--) { + var playlist = master.playlists[i]; + + master.playlists[playlist.uri] = playlist; + playlist.resolvedUri = resolveUrl$1(master.uri, playlist.uri); + playlist.id = i; + + if (!playlist.attributes) { + // Although the spec states an #EXT-X-STREAM-INF tag MUST have a + // BANDWIDTH attribute, we can playOld the stream without it. This means a poorly + // formatted master playlist may not have an attribute list. An attributes + // property is added here to prevent undefined references when we encounter + // this scenario. + playlist.attributes = {}; + + log$2.warn('Invalid playlist STREAM-INF detected. Missing BANDWIDTH attribute.'); + } + } + }; + + var resolveMediaGroupUris = function resolveMediaGroupUris(master) { + forEachMediaGroup(master, function (properties) { + if (properties.uri) { + properties.resolvedUri = resolveUrl$1(master.uri, properties.uri); + } + }); + }; + + /** + * Calculates the time to wait before refreshing a live playlist + * + * @param {Object} media + * The current media + * @param {Boolean} update + * True if there were any updates from the last refresh, false otherwise + * @return {Number} + * The time in ms to wait before refreshing the live playlist + */ + var refreshDelay = function refreshDelay(media, update) { + var lastSegment = media.segments[media.segments.length - 1]; + var delay = void 0; + + if (update && lastSegment && lastSegment.duration) { + delay = lastSegment.duration * 1000; + } else { + // if the playlist is unchanged since the last reload or last segment duration + // cannot be determined, try again after half the target duration + delay = (media.targetDuration || 10) * 500; + } + return delay; + }; + + /** + * Load a playlist from a remote location + * + * @class PlaylistLoader + * @extends Stream + * @param {String} srcUrl the url to start with + * @param {Boolean} withCredentials the withCredentials xhr option + * @constructor + */ + + var PlaylistLoader = function (_EventTarget) { + inherits(PlaylistLoader, _EventTarget); + + function PlaylistLoader(srcUrl, hls, withCredentials) { + classCallCheck(this, PlaylistLoader); + + var _this2 = possibleConstructorReturn(this, _EventTarget.call(this)); + + _this2.srcUrl = srcUrl; + _this2.hls_ = hls; + _this2.withCredentials = withCredentials; + + if (!_this2.srcUrl) { + throw new Error('A non-empty playlist URL is required'); + } + + // initialize the loader state + _this2.state = 'HAVE_NOTHING'; + + // live playlist staleness timeout + _this2.on('mediaupdatetimeout', function () { + if (_this2.state !== 'HAVE_METADATA') { + // only refresh the media playlist if no other activity is going on + return; + } + + _this2.state = 'HAVE_CURRENT_METADATA'; + + _this2.request = _this2.hls_.xhr({ + uri: resolveUrl$1(_this2.master.uri, _this2.media().uri), + withCredentials: _this2.withCredentials + }, function (error, req) { + // disposed + if (!_this2.request) { + return; + } + + if (error) { + return _this2.playlistRequestError(_this2.request, _this2.media().uri, 'HAVE_METADATA'); + } + + _this2.haveMetadata(_this2.request, _this2.media().uri); + }); + }); + return _this2; + } + + PlaylistLoader.prototype.playlistRequestError = function playlistRequestError(xhr, url, startingState) { + // any in-flight request is now finished + this.request = null; + + if (startingState) { + this.state = startingState; + } + + this.error = { + playlist: this.master.playlists[url], + status: xhr.status, + message: 'HLS playlist request error at URL: ' + url, + responseText: xhr.responseText, + code: xhr.status >= 500 ? 4 : 2 + }; + + this.trigger('error'); + }; + + // update the playlist loader's state in response to a new or + // updated playlist. + + + PlaylistLoader.prototype.haveMetadata = function haveMetadata(xhr, url) { + var _this3 = this; + + // any in-flight request is now finished + this.request = null; + this.state = 'HAVE_METADATA'; + + var parser = new Parser(); + + parser.push(xhr.responseText); + parser.end(); + parser.manifest.uri = url; + // m3u8-parser does not attach an attributes property to media playlists so make + // sure that the property is attached to avoid undefined reference errors + parser.manifest.attributes = parser.manifest.attributes || {}; + + // merge this playlist into the master + var update = updateMaster(this.master, parser.manifest); + + this.targetDuration = parser.manifest.targetDuration; + + if (update) { + this.master = update; + this.media_ = this.master.playlists[parser.manifest.uri]; + } else { + this.trigger('playlistunchanged'); + } + + // refresh live playlists after a target duration passes + if (!this.media().endList) { + window_1.clearTimeout(this.mediaUpdateTimeout); + this.mediaUpdateTimeout = window_1.setTimeout(function () { + _this3.trigger('mediaupdatetimeout'); + }, refreshDelay(this.media(), !!update)); + } + + this.trigger('loadedplaylist'); + }; + + /** + * Abort any outstanding work and clean up. + */ + + + PlaylistLoader.prototype.dispose = function dispose() { + this.stopRequest(); + window_1.clearTimeout(this.mediaUpdateTimeout); + }; + + PlaylistLoader.prototype.stopRequest = function stopRequest() { + if (this.request) { + var oldRequest = this.request; + + this.request = null; + oldRequest.onreadystatechange = null; + oldRequest.abort(); + } + }; + + /** + * When called without any arguments, returns the currently + * active media playlist. When called with a single argument, + * triggers the playlist loader to asynchronously switch to the + * specified media playlist. Calling this method while the + * loader is in the HAVE_NOTHING causes an error to be emitted + * but otherwise has no effect. + * + * @param {Object=} playlist the parsed media playlist + * object to switch to + * @return {Playlist} the current loaded media + */ + + + PlaylistLoader.prototype.media = function media(playlist) { + var _this4 = this; + + // getter + if (!playlist) { + return this.media_; + } + + // setter + if (this.state === 'HAVE_NOTHING') { + throw new Error('Cannot switch media playlist from ' + this.state); + } + + var startingState = this.state; + + // find the playlist object if the target playlist has been + // specified by URI + if (typeof playlist === 'string') { + if (!this.master.playlists[playlist]) { + throw new Error('Unknown playlist URI: ' + playlist); + } + playlist = this.master.playlists[playlist]; + } + + var mediaChange = !this.media_ || playlist.uri !== this.media_.uri; + + // switch to fully loaded playlists immediately + if (this.master.playlists[playlist.uri].endList) { + // abort outstanding playlist requests + if (this.request) { + this.request.onreadystatechange = null; + this.request.abort(); + this.request = null; + } + this.state = 'HAVE_METADATA'; + this.media_ = playlist; + + // trigger media change if the active media has been updated + if (mediaChange) { + this.trigger('mediachanging'); + this.trigger('mediachange'); + } + return; + } + + // switching to the active playlist is a no-op + if (!mediaChange) { + return; + } + + this.state = 'SWITCHING_MEDIA'; + + // there is already an outstanding playlist request + if (this.request) { + if (resolveUrl$1(this.master.uri, playlist.uri) === this.request.url) { + // requesting to switch to the same playlist multiple times + // has no effect after the first + return; + } + this.request.onreadystatechange = null; + this.request.abort(); + this.request = null; + } + + // request the new playlist + if (this.media_) { + this.trigger('mediachanging'); + } + + this.request = this.hls_.xhr({ + uri: resolveUrl$1(this.master.uri, playlist.uri), + withCredentials: this.withCredentials + }, function (error, req) { + // disposed + if (!_this4.request) { + return; + } + + if (error) { + return _this4.playlistRequestError(_this4.request, playlist.uri, startingState); + } + + _this4.haveMetadata(req, playlist.uri); + + // fire loadedmetadata the first time a media playlist is loaded + if (startingState === 'HAVE_MASTER') { + _this4.trigger('loadedmetadata'); + } else { + _this4.trigger('mediachange'); + } + }); + }; + + /** + * pause loading of the playlist + */ + + + PlaylistLoader.prototype.pause = function pause() { + this.stopRequest(); + window_1.clearTimeout(this.mediaUpdateTimeout); + if (this.state === 'HAVE_NOTHING') { + // If we pause the loader before any data has been retrieved, its as if we never + // started, so reset to an unstarted state. + this.started = false; + } + // Need to restore state now that no activity is happening + if (this.state === 'SWITCHING_MEDIA') { + // if the loader was in the process of switching media, it should either return to + // HAVE_MASTER or HAVE_METADATA depending on if the loader has loaded a media + // playlist yet. This is determined by the existence of loader.media_ + if (this.media_) { + this.state = 'HAVE_METADATA'; + } else { + this.state = 'HAVE_MASTER'; + } + } else if (this.state === 'HAVE_CURRENT_METADATA') { + this.state = 'HAVE_METADATA'; + } + }; + + /** + * start loading of the playlist + */ + + + PlaylistLoader.prototype.load = function load(isFinalRendition) { + var _this5 = this; + + window_1.clearTimeout(this.mediaUpdateTimeout); + + var media = this.media(); + + if (isFinalRendition) { + var delay = media ? media.targetDuration / 2 * 1000 : 5 * 1000; + + this.mediaUpdateTimeout = window_1.setTimeout(function () { + return _this5.load(); + }, delay); + return; + } + + if (!this.started) { + this.start(); + return; + } + + if (media && !media.endList) { + this.trigger('mediaupdatetimeout'); + } else { + this.trigger('loadedplaylist'); + } + }; + + /** + * start loading of the playlist + */ + + + PlaylistLoader.prototype.start = function start() { + var _this6 = this; + + this.started = true; + + // request the specified URL + this.request = this.hls_.xhr({ + uri: this.srcUrl, + withCredentials: this.withCredentials + }, function (error, req) { + // disposed + if (!_this6.request) { + return; + } + + // clear the loader's request reference + _this6.request = null; + + if (error) { + _this6.error = { + status: req.status, + message: 'HLS playlist request error at URL: ' + _this6.srcUrl, + responseText: req.responseText, + // MEDIA_ERR_NETWORK + code: 2 + }; + if (_this6.state === 'HAVE_NOTHING') { + _this6.started = false; + } + return _this6.trigger('error'); + } + + var parser = new Parser(); + + parser.push(req.responseText); + parser.end(); + + _this6.state = 'HAVE_MASTER'; + + parser.manifest.uri = _this6.srcUrl; + + // loaded a master playlist + if (parser.manifest.playlists) { + _this6.master = parser.manifest; + + setupMediaPlaylists(_this6.master); + resolveMediaGroupUris(_this6.master); + + _this6.trigger('loadedplaylist'); + if (!_this6.request) { + // no media playlist was specifically selected so start + // from the first listed one + _this6.media(parser.manifest.playlists[0]); + } + return; + } + + // loaded a media playlist + // infer a master playlist if none was previously requested + _this6.master = { + mediaGroups: { + 'AUDIO': {}, + 'VIDEO': {}, + 'CLOSED-CAPTIONS': {}, + 'SUBTITLES': {} + }, + uri: window_1.location.href, + playlists: [{ + uri: _this6.srcUrl, + id: 0 + }] + }; + _this6.master.playlists[_this6.srcUrl] = _this6.master.playlists[0]; + _this6.master.playlists[0].resolvedUri = _this6.srcUrl; + // m3u8-parser does not attach an attributes property to media playlists so make + // sure that the property is attached to avoid undefined reference errors + _this6.master.playlists[0].attributes = _this6.master.playlists[0].attributes || {}; + _this6.haveMetadata(req, _this6.srcUrl); + return _this6.trigger('loadedmetadata'); + }); + }; + + return PlaylistLoader; + }(EventTarget$1); + + /** + * @file playlist.js + * + * Playlist related utilities. + */ + + var createTimeRange = videojs$1.createTimeRange; + + /** + * walk backward until we find a duration we can use + * or return a failure + * + * @param {Playlist} playlist the playlist to walk through + * @param {Number} endSequence the mediaSequence to stop walking on + */ + + var backwardDuration = function backwardDuration(playlist, endSequence) { + var result = 0; + var i = endSequence - playlist.mediaSequence; + // if a start time is available for segment immediately following + // the interval, use it + var segment = playlist.segments[i]; + + // Walk backward until we find the latest segment with timeline + // information that is earlier than endSequence + if (segment) { + if (typeof segment.start !== 'undefined') { + return {result: segment.start, precise: true}; + } + if (typeof segment.end !== 'undefined') { + return { + result: segment.end - segment.duration, + precise: true + }; + } + } + while (i--) { + segment = playlist.segments[i]; + if (typeof segment.end !== 'undefined') { + return {result: result + segment.end, precise: true}; + } + + result += segment.duration; + + if (typeof segment.start !== 'undefined') { + return {result: result + segment.start, precise: true}; + } + } + return {result: result, precise: false}; + }; + + /** + * walk forward until we find a duration we can use + * or return a failure + * + * @param {Playlist} playlist the playlist to walk through + * @param {Number} endSequence the mediaSequence to stop walking on + */ + var forwardDuration = function forwardDuration(playlist, endSequence) { + var result = 0; + var segment = void 0; + var i = endSequence - playlist.mediaSequence; + // Walk forward until we find the earliest segment with timeline + // information + + for (; i < playlist.segments.length; i++) { + segment = playlist.segments[i]; + if (typeof segment.start !== 'undefined') { + return { + result: segment.start - result, + precise: true + }; + } + + result += segment.duration; + + if (typeof segment.end !== 'undefined') { + return { + result: segment.end - result, + precise: true + }; + } + } + // indicate we didn't find a useful duration estimate + return {result: -1, precise: false}; + }; + + /** + * Calculate the media duration from the segments associated with a + * playlist. The duration of a subinterval of the available segments + * may be calculated by specifying an end index. + * + * @param {Object} playlist a media playlist object + * @param {Number=} endSequence an exclusive upper boundary + * for the playlist. Defaults to playlist length. + * @param {Number} expired the amount of time that has dropped + * off the front of the playlist in a live scenario + * @return {Number} the duration between the first available segment + * and end index. + */ + var intervalDuration = function intervalDuration(playlist, endSequence, expired) { + var backward = void 0; + var forward = void 0; + + if (typeof endSequence === 'undefined') { + endSequence = playlist.mediaSequence + playlist.segments.length; + } + + if (endSequence < playlist.mediaSequence) { + return 0; + } + + // do a backward walk to estimate the duration + backward = backwardDuration(playlist, endSequence); + if (backward.precise) { + // if we were able to base our duration estimate on timing + // information provided directly from the Media Source, return + // it + return backward.result; + } + + // walk forward to see if a precise duration estimate can be made + // that way + forward = forwardDuration(playlist, endSequence); + if (forward.precise) { + // we found a segment that has been buffered and so it's + // position is known precisely + return forward.result; + } + + // return the less-precise, playlist-based duration estimate + return backward.result + expired; + }; + + /** + * Calculates the duration of a playlist. If a start and end index + * are specified, the duration will be for the subset of the media + * timeline between those two indices. The total duration for live + * playlists is always Infinity. + * + * @param {Object} playlist a media playlist object + * @param {Number=} endSequence an exclusive upper + * boundary for the playlist. Defaults to the playlist media + * sequence number plus its length. + * @param {Number=} expired the amount of time that has + * dropped off the front of the playlist in a live scenario + * @return {Number} the duration between the start index and end + * index. + */ + var duration = function duration(playlist, endSequence, expired) { + if (!playlist) { + return 0; + } + + if (typeof expired !== 'number') { + expired = 0; + } + + // if a slice of the total duration is not requested, use + // playlist-level duration indicators when they're present + if (typeof endSequence === 'undefined') { + // if present, use the duration specified in the playlist + if (playlist.totalDuration) { + return playlist.totalDuration; + } + + // duration should be Infinity for live playlists + if (!playlist.endList) { + return window_1.Infinity; + } + } + + // calculate the total duration based on the segment durations + return intervalDuration(playlist, endSequence, expired); + }; + + /** + * Calculate the time between two indexes in the current playlist + * neight the start- nor the end-index need to be within the current + * playlist in which case, the targetDuration of the playlist is used + * to approximate the durations of the segments + * + * @param {Object} playlist a media playlist object + * @param {Number} startIndex + * @param {Number} endIndex + * @return {Number} the number of seconds between startIndex and endIndex + */ + var sumDurations = function sumDurations(playlist, startIndex, endIndex) { + var durations = 0; + + if (startIndex > endIndex) { + var _ref = [endIndex, startIndex]; + startIndex = _ref[0]; + endIndex = _ref[1]; + } + + if (startIndex < 0) { + for (var i = startIndex; i < Math.min(0, endIndex); i++) { + durations += playlist.targetDuration; + } + startIndex = 0; + } + + for (var _i2 = startIndex; _i2 < endIndex; _i2++) { + durations += playlist.segments[_i2].duration; + } + + return durations; + }; + + /** + * Determines the media index of the segment corresponding to the safe edge of the live + * window which is the duration of the last segment plus 2 target durations from the end + * of the playlist. + * + * @param {Object} playlist + * a media playlist object + * @return {Number} + * The media index of the segment at the safe live point. 0 if there is no "safe" + * point. + * @function safeLiveIndex + */ + var safeLiveIndex = function safeLiveIndex(playlist) { + if (!playlist.segments.length) { + return 0; + } + + var i = playlist.segments.length - 1; + var distanceFromEnd = playlist.segments[i].duration || playlist.targetDuration; + var safeDistance = distanceFromEnd + playlist.targetDuration * 2; + + while (i--) { + distanceFromEnd += playlist.segments[i].duration; + + if (distanceFromEnd >= safeDistance) { + break; + } + } + + return Math.max(0, i); + }; + + /** + * Calculates the playlist end time + * + * @param {Object} playlist a media playlist object + * @param {Number=} expired the amount of time that has + * dropped off the front of the playlist in a live scenario + * @param {Boolean|false} useSafeLiveEnd a boolean value indicating whether or not the + * playlist end calculation should consider the safe live end + * (truncate the playlist end by three segments). This is normally + * used for calculating the end of the playlist's seekable range. + * @returns {Number} the end time of playlist + * @function playlistEnd + */ + var playlistEnd = function playlistEnd(playlist, expired, useSafeLiveEnd) { + if (!playlist || !playlist.segments) { + return null; + } + if (playlist.endList) { + return duration(playlist); + } + + if (expired === null) { + return null; + } + + expired = expired || 0; + + var endSequence = useSafeLiveEnd ? safeLiveIndex(playlist) : playlist.segments.length; + + return intervalDuration(playlist, playlist.mediaSequence + endSequence, expired); + }; + + /** + * Calculates the interval of time that is currently seekable in a + * playlist. The returned time ranges are relative to the earliest + * moment in the specified playlist that is still available. A full + * seekable implementation for live streams would need to offset + * these values by the duration of content that has expired from the + * stream. + * + * @param {Object} playlist a media playlist object + * dropped off the front of the playlist in a live scenario + * @param {Number=} expired the amount of time that has + * dropped off the front of the playlist in a live scenario + * @return {TimeRanges} the periods of time that are valid targets + * for seeking + */ + var seekable = function seekable(playlist, expired) { + var useSafeLiveEnd = true; + var seekableStart = expired || 0; + var seekableEnd = playlistEnd(playlist, expired, useSafeLiveEnd); + + if (seekableEnd === null) { + return createTimeRange(); + } + return createTimeRange(seekableStart, seekableEnd); + }; + + var isWholeNumber = function isWholeNumber(num) { + return num - Math.floor(num) === 0; + }; + + var roundSignificantDigit = function roundSignificantDigit(increment, num) { + // If we have a whole number, just add 1 to it + if (isWholeNumber(num)) { + return num + increment * 0.1; + } + + var numDecimalDigits = num.toString().split('.')[1].length; + + for (var i = 1; i <= numDecimalDigits; i++) { + var scale = Math.pow(10, i); + var temp = num * scale; + + if (isWholeNumber(temp) || i === numDecimalDigits) { + return (temp + increment) / scale; + } + } + }; + + var ceilLeastSignificantDigit = roundSignificantDigit.bind(null, 1); + var floorLeastSignificantDigit = roundSignificantDigit.bind(null, -1); + + /** + * Determine the index and estimated starting time of the segment that + * contains a specified playback position in a media playlist. + * + * @param {Object} playlist the media playlist to query + * @param {Number} currentTime The number of seconds since the earliest + * possible position to determine the containing segment for + * @param {Number} startIndex + * @param {Number} startTime + * @return {Object} + */ + var getMediaInfoForTime = function getMediaInfoForTime(playlist, currentTime, startIndex, startTime) { + var i = void 0; + var segment = void 0; + var numSegments = playlist.segments.length; + + var time = currentTime - startTime; + + if (time < 0) { + // Walk backward from startIndex in the playlist, adding durations + // until we find a segment that contains `time` and return it + if (startIndex > 0) { + for (i = startIndex - 1; i >= 0; i--) { + segment = playlist.segments[i]; + time += floorLeastSignificantDigit(segment.duration); + if (time > 0) { + return { + mediaIndex: i, + startTime: startTime - sumDurations(playlist, startIndex, i) + }; + } + } + } + // We were unable to find a good segment within the playlist + // so select the first segment + return { + mediaIndex: 0, + startTime: currentTime + }; + } + + // When startIndex is negative, we first walk forward to first segment + // adding target durations. If we "run out of time" before getting to + // the first segment, return the first segment + if (startIndex < 0) { + for (i = startIndex; i < 0; i++) { + time -= playlist.targetDuration; + if (time < 0) { + return { + mediaIndex: 0, + startTime: currentTime + }; + } + } + startIndex = 0; + } + + // Walk forward from startIndex in the playlist, subtracting durations + // until we find a segment that contains `time` and return it + for (i = startIndex; i < numSegments; i++) { + segment = playlist.segments[i]; + time -= ceilLeastSignificantDigit(segment.duration); + if (time < 0) { + return { + mediaIndex: i, + startTime: startTime + sumDurations(playlist, startIndex, i) + }; + } + } + + // We are out of possible candidates so load the last one... + return { + mediaIndex: numSegments - 1, + startTime: currentTime + }; + }; + + /** + * Check whether the playlist is blacklisted or not. + * + * @param {Object} playlist the media playlist object + * @return {boolean} whether the playlist is blacklisted or not + * @function isBlacklisted + */ + var isBlacklisted = function isBlacklisted(playlist) { + return playlist.excludeUntil && playlist.excludeUntil > Date.now(); + }; + + /** + * Check whether the playlist is compatible with current playback configuration or has + * been blacklisted permanently for being incompatible. + * + * @param {Object} playlist the media playlist object + * @return {boolean} whether the playlist is incompatible or not + * @function isIncompatible + */ + var isIncompatible = function isIncompatible(playlist) { + return playlist.excludeUntil && playlist.excludeUntil === Infinity; + }; + + /** + * Check whether the playlist is enabled or not. + * + * @param {Object} playlist the media playlist object + * @return {boolean} whether the playlist is enabled or not + * @function isEnabled + */ + var isEnabled = function isEnabled(playlist) { + var blacklisted = isBlacklisted(playlist); + + return !playlist.disabled && !blacklisted; + }; + + /** + * Check whether the playlist has been manually disabled through the representations api. + * + * @param {Object} playlist the media playlist object + * @return {boolean} whether the playlist is disabled manually or not + * @function isDisabled + */ + var isDisabled = function isDisabled(playlist) { + return playlist.disabled; + }; + + /** + * Returns whether the current playlist is an AES encrypted HLS stream + * + * @return {Boolean} true if it's an AES encrypted HLS stream + */ + var isAes = function isAes(media) { + for (var i = 0; i < media.segments.length; i++) { + if (media.segments[i].key) { + return true; + } + } + return false; + }; + + /** + * Returns whether the current playlist contains fMP4 + * + * @return {Boolean} true if the playlist contains fMP4 + */ + var isFmp4 = function isFmp4(media) { + for (var i = 0; i < media.segments.length; i++) { + if (media.segments[i].map) { + return true; + } + } + return false; + }; + + /** + * Checks if the playlist has a value for the specified attribute + * + * @param {String} attr + * Attribute to check for + * @param {Object} playlist + * The media playlist object + * @return {Boolean} + * Whether the playlist contains a value for the attribute or not + * @function hasAttribute + */ + var hasAttribute = function hasAttribute(attr, playlist) { + return playlist.attributes && playlist.attributes[attr]; + }; + + /** + * Estimates the time required to complete a segment download from the specified playlist + * + * @param {Number} segmentDuration + * Duration of requested segment + * @param {Number} bandwidth + * Current measured bandwidth of the player + * @param {Object} playlist + * The media playlist object + * @param {Number=} bytesReceived + * Number of bytes already received for the request. Defaults to 0 + * @return {Number|NaN} + * The estimated time to request the segment. NaN if bandwidth information for + * the given playlist is unavailable + * @function estimateSegmentRequestTime + */ + var estimateSegmentRequestTime = function estimateSegmentRequestTime(segmentDuration, bandwidth, playlist) { + var bytesReceived = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; + + if (!hasAttribute('BANDWIDTH', playlist)) { + return NaN; + } + + var size = segmentDuration * playlist.attributes.BANDWIDTH; + + return (size - bytesReceived * 8) / bandwidth; + }; + + /* + * Returns whether the current playlist is the lowest rendition + * + * @return {Boolean} true if on lowest rendition + */ + var isLowestEnabledRendition = function isLowestEnabledRendition(master, media) { + if (master.playlists.length === 1) { + return true; + } + + var currentBandwidth = media.attributes.BANDWIDTH || Number.MAX_VALUE; + + return master.playlists.filter(function (playlist) { + if (!isEnabled(playlist)) { + return false; + } + + return (playlist.attributes.BANDWIDTH || 0) < currentBandwidth; + }).length === 0; + }; + + // exports + var Playlist = { + duration: duration, + seekable: seekable, + safeLiveIndex: safeLiveIndex, + getMediaInfoForTime: getMediaInfoForTime, + isEnabled: isEnabled, + isDisabled: isDisabled, + isBlacklisted: isBlacklisted, + isIncompatible: isIncompatible, + playlistEnd: playlistEnd, + isAes: isAes, + isFmp4: isFmp4, + hasAttribute: hasAttribute, + estimateSegmentRequestTime: estimateSegmentRequestTime, + isLowestEnabledRendition: isLowestEnabledRendition + }; + + /** + * @file xhr.js + */ + + var videojsXHR = videojs$1.xhr, + mergeOptions$1$1 = videojs$1.mergeOptions; + + + var xhrFactory = function xhrFactory() { + var xhr = function XhrFunction(options, callback) { + // Add a default timeout for all hls requests + options = mergeOptions$1$1({ + timeout: 45e3 + }, options); + + // Allow an optional user-specified function to modify the option + // object before we construct the xhr request + var beforeRequest = XhrFunction.beforeRequest || videojs$1.Hls.xhr.beforeRequest; + + if (beforeRequest && typeof beforeRequest === 'function') { + var newOptions = beforeRequest(options); + + if (newOptions) { + options = newOptions; + } + } + + var request = videojsXHR(options, function (error, response) { + var reqResponse = request.response; + + if (!error && reqResponse) { + request.responseTime = Date.now(); + request.roundTripTime = request.responseTime - request.requestTime; + request.bytesReceived = reqResponse.byteLength || reqResponse.length; + if (!request.bandwidth) { + request.bandwidth = Math.floor(request.bytesReceived / request.roundTripTime * 8 * 1000); + } + } + + if (response.headers) { + request.responseHeaders = response.headers; + } + + // videojs.xhr now uses a specific code on the error + // object to signal that a request has timed out instead + // of setting a boolean on the request object + if (error && error.code === 'ETIMEDOUT') { + request.timedout = true; + } + + // videojs.xhr no longer considers status codes outside of 200 and 0 + // (for file uris) to be errors, but the old XHR did, so emulate that + // behavior. Status 206 may be used in response to byterange requests. + if (!error && !request.aborted && response.statusCode !== 200 && response.statusCode !== 206 && response.statusCode !== 0) { + error = new Error('XHR Failed with a response of: ' + (request && (reqResponse || request.responseText))); + } + + callback(error, request); + }); + var originalAbort = request.abort; + + request.abort = function () { + request.aborted = true; + return originalAbort.apply(request, arguments); + }; + request.uri = options.uri; + request.requestTime = Date.now(); + return request; + }; + + return xhr; + }; + + /** + * @file bin-utils.js + */ + + /** + * convert a TimeRange to text + * + * @param {TimeRange} range the timerange to use for conversion + * @param {Number} i the iterator on the range to convert + */ + var textRange = function textRange(range, i) { + return range.start(i) + '-' + range.end(i); + }; + + /** + * format a number as hex string + * + * @param {Number} e The number + * @param {Number} i the iterator + */ + var formatHexString = function formatHexString(e, i) { + var value = e.toString(16); + + return '00'.substring(0, 2 - value.length) + value + (i % 2 ? ' ' : ''); + }; + var formatAsciiString = function formatAsciiString(e) { + if (e >= 0x20 && e < 0x7e) { + return String.fromCharCode(e); + } + return '.'; + }; + + /** + * Creates an object for sending to a web worker modifying properties that are TypedArrays + * into a new object with seperated properties for the buffer, byteOffset, and byteLength. + * + * @param {Object} message + * Object of properties and values to send to the web worker + * @return {Object} + * Modified message with TypedArray values expanded + * @function createTransferableMessage + */ + var createTransferableMessage = function createTransferableMessage(message) { + var transferable = {}; + + Object.keys(message).forEach(function (key) { + var value = message[key]; + + if (ArrayBuffer.isView(value)) { + transferable[key] = { + bytes: value.buffer, + byteOffset: value.byteOffset, + byteLength: value.byteLength + }; + } else { + transferable[key] = value; + } + }); + + return transferable; + }; + + /** + * Returns a unique string identifier for a media initialization + * segment. + */ + var initSegmentId = function initSegmentId(initSegment) { + var byterange = initSegment.byterange || { + length: Infinity, + offset: 0 + }; + + return [byterange.length, byterange.offset, initSegment.resolvedUri].join(','); + }; + + /** + * utils to help dump binary data to the console + */ + var hexDump = function hexDump(data) { + var bytes = Array.prototype.slice.call(data); + var step = 16; + var result = ''; + var hex = void 0; + var ascii = void 0; + + for (var j = 0; j < bytes.length / step; j++) { + hex = bytes.slice(j * step, j * step + step).map(formatHexString).join(''); + ascii = bytes.slice(j * step, j * step + step).map(formatAsciiString).join(''); + result += hex + ' ' + ascii + '\n'; + } + + return result; + }; + + var tagDump = function tagDump(_ref2) { + var bytes = _ref2.bytes; + return hexDump(bytes); + }; + + var textRanges = function textRanges(ranges) { + var result = ''; + var i = void 0; + + for (i = 0; i < ranges.length; i++) { + result += textRange(ranges, i) + ' '; + } + return result; + }; + + var utils = /*#__PURE__*/Object.freeze({ + createTransferableMessage: createTransferableMessage, + initSegmentId: initSegmentId, + hexDump: hexDump, + tagDump: tagDump, + textRanges: textRanges + }); + + /** + * ranges + * + * Utilities for working with TimeRanges. + * + */ + + // Fudge factor to account for TimeRanges rounding + var TIME_FUDGE_FACTOR = 1 / 30; + // Comparisons between time values such as current time and the end of the buffered range + // can be misleading because of precision differences or when the current media has poorly + // aligned audio and video, which can cause values to be slightly off from what you would + // expect. This value is what we consider to be safe to use in such comparisons to account + // for these scenarios. + var SAFE_TIME_DELTA = TIME_FUDGE_FACTOR * 3; + var filterRanges = function filterRanges(timeRanges, predicate) { + var results = []; + var i = void 0; + + if (timeRanges && timeRanges.length) { + // Search for ranges that match the predicate + for (i = 0; i < timeRanges.length; i++) { + if (predicate(timeRanges.start(i), timeRanges.end(i))) { + results.push([timeRanges.start(i), timeRanges.end(i)]); + } + } + } + + return videojs$1.createTimeRanges(results); + }; + + /** + * Attempts to find the buffered TimeRange that contains the specified + * time. + * @param {TimeRanges} buffered - the TimeRanges object to query + * @param {number} time - the time to filter on. + * @returns {TimeRanges} a new TimeRanges object + */ + var findRange = function findRange(buffered, time) { + return filterRanges(buffered, function (start, end) { + return start - TIME_FUDGE_FACTOR <= time && end + TIME_FUDGE_FACTOR >= time; + }); + }; + + /** + * Returns the TimeRanges that begin later than the specified time. + * @param {TimeRanges} timeRanges - the TimeRanges object to query + * @param {number} time - the time to filter on. + * @returns {TimeRanges} a new TimeRanges object. + */ + var findNextRange = function findNextRange(timeRanges, time) { + return filterRanges(timeRanges, function (start) { + return start - TIME_FUDGE_FACTOR >= time; + }); + }; + + /** + * Returns gaps within a list of TimeRanges + * @param {TimeRanges} buffered - the TimeRanges object + * @return {TimeRanges} a TimeRanges object of gaps + */ + var findGaps = function findGaps(buffered) { + if (buffered.length < 2) { + return videojs$1.createTimeRanges(); + } + + var ranges = []; + + for (var i = 1; i < buffered.length; i++) { + var start = buffered.end(i - 1); + var end = buffered.start(i); + + ranges.push([start, end]); + } + + return videojs$1.createTimeRanges(ranges); + }; + + /** + * Gets a human readable string for a TimeRange + * + * @param {TimeRange} range + * @returns {String} a human readable string + */ + var printableRange = function printableRange(range) { + var strArr = []; + + if (!range || !range.length) { + return ''; + } + + for (var i = 0; i < range.length; i++) { + strArr.push(range.start(i) + ' => ' + range.end(i)); + } + + return strArr.join(', '); + }; + + /** + * Calculates the amount of time left in seconds until the player hits the end of the + * buffer and causes a rebuffer + * + * @param {TimeRange} buffered + * The state of the buffer + * @param {Numnber} currentTime + * The current time of the player + * @param {Number} playbackRate + * The current playback rate of the player. Defaults to 1. + * @return {Number} + * Time until the player has to start rebuffering in seconds. + * @function timeUntilRebuffer + */ + var timeUntilRebuffer = function timeUntilRebuffer(buffered, currentTime) { + var playbackRate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + + var bufferedEnd = buffered.length ? buffered.end(buffered.length - 1) : 0; + + return (bufferedEnd - currentTime) / playbackRate; + }; + + /** + * Converts a TimeRanges object into an array representation + * @param {TimeRanges} timeRanges + * @returns {Array} + */ + var timeRangesToArray = function timeRangesToArray(timeRanges) { + var timeRangesList = []; + + for (var i = 0; i < timeRanges.length; i++) { + timeRangesList.push({ + start: timeRanges.start(i), + end: timeRanges.end(i) + }); + } + + return timeRangesList; + }; + + /** + * @file create-text-tracks-if-necessary.js + */ + + /** + * Create text tracks on video.js if they exist on a segment. + * + * @param {Object} sourceBuffer the VSB or FSB + * @param {Object} mediaSource the HTML media source + * @param {Object} segment the segment that may contain the text track + * @private + */ + var createTextTracksIfNecessary = function createTextTracksIfNecessary(sourceBuffer, mediaSource, segment) { + var player = mediaSource.player_; + + // create an in-band caption track if one is present in the segment + if (segment.captions && segment.captions.length) { + if (!sourceBuffer.inbandTextTracks_) { + sourceBuffer.inbandTextTracks_ = {}; + } + + for (var trackId in segment.captionStreams) { + if (!sourceBuffer.inbandTextTracks_[trackId]) { + player.tech_.trigger({type: 'usage', name: 'hls-608'}); + var track = player.textTracks().getTrackById(trackId); + + if (track) { + // Resuse an existing track with a CC# id because this was + // very likely created by videojs-contrib-hls from information + // in the m3u8 for us to use + sourceBuffer.inbandTextTracks_[trackId] = track; + } else { + // Otherwise, create a track with the default `CC#` label and + // without a language + sourceBuffer.inbandTextTracks_[trackId] = player.addRemoteTextTrack({ + kind: 'captions', + id: trackId, + label: trackId + }, false).track; + } + } + } + } + + if (segment.metadata && segment.metadata.length && !sourceBuffer.metadataTrack_) { + sourceBuffer.metadataTrack_ = player.addRemoteTextTrack({ + kind: 'metadata', + label: 'Timed Metadata' + }, false).track; + sourceBuffer.metadataTrack_.inBandMetadataTrackDispatchType = segment.metadata.dispatchType; + } + }; + + /** + * @file remove-cues-from-track.js + */ + + /** + * Remove cues from a track on video.js. + * + * @param {Double} start start of where we should remove the cue + * @param {Double} end end of where the we should remove the cue + * @param {Object} track the text track to remove the cues from + * @private + */ + var removeCuesFromTrack = function removeCuesFromTrack(start, end, track) { + var i = void 0; + var cue = void 0; + + if (!track) { + return; + } + + if (!track.cues) { + return; + } + + i = track.cues.length; + + while (i--) { + cue = track.cues[i]; + + // Remove any overlapping cue + if (cue.startTime <= end && cue.endTime >= start) { + track.removeCue(cue); + } + } + }; + + /** + * @file add-text-track-data.js + */ + /** + * Define properties on a cue for backwards compatability, + * but warn the user that the way that they are using it + * is depricated and will be removed at a later date. + * + * @param {Cue} cue the cue to add the properties on + * @private + */ + var deprecateOldCue = function deprecateOldCue(cue) { + Object.defineProperties(cue.frame, { + id: { + get: function get$$1() { + videojs$1.log.warn('cue.frame.id is deprecated. Use cue.value.key instead.'); + return cue.value.key; + } + }, + value: { + get: function get$$1() { + videojs$1.log.warn('cue.frame.value is deprecated. Use cue.value.data instead.'); + return cue.value.data; + } + }, + privateData: { + get: function get$$1() { + videojs$1.log.warn('cue.frame.privateData is deprecated. Use cue.value.data instead.'); + return cue.value.data; + } + } + }); + }; + + var durationOfVideo = function durationOfVideo(duration) { + var dur = void 0; + + if (isNaN(duration) || Math.abs(duration) === Infinity) { + dur = Number.MAX_VALUE; + } else { + dur = duration; + } + return dur; + }; + /** + * Add text track data to a source handler given the captions and + * metadata from the buffer. + * + * @param {Object} sourceHandler the virtual source buffer + * @param {Array} captionArray an array of caption data + * @param {Array} metadataArray an array of meta data + * @private + */ + var addTextTrackData = function addTextTrackData(sourceHandler, captionArray, metadataArray) { + var Cue = window_1.WebKitDataCue || window_1.VTTCue; + + if (captionArray) { + captionArray.forEach(function (caption) { + var track = caption.stream; + + this.inbandTextTracks_[track].addCue(new Cue(caption.startTime + this.timestampOffset, caption.endTime + this.timestampOffset, caption.text)); + }, sourceHandler); + } + + if (metadataArray) { + var videoDuration = durationOfVideo(sourceHandler.mediaSource_.duration); + + metadataArray.forEach(function (metadata) { + var time = metadata.cueTime + this.timestampOffset; + + metadata.frames.forEach(function (frame) { + var cue = new Cue(time, time, frame.value || frame.url || frame.data || ''); + + cue.frame = frame; + cue.value = frame; + deprecateOldCue(cue); + + this.metadataTrack_.addCue(cue); + }, this); + }, sourceHandler); + + // Updating the metadeta cues so that + // the endTime of each cue is the startTime of the next cue + // the endTime of last cue is the duration of the video + if (sourceHandler.metadataTrack_ && sourceHandler.metadataTrack_.cues && sourceHandler.metadataTrack_.cues.length) { + var cues = sourceHandler.metadataTrack_.cues; + var cuesArray = []; + + // Create a copy of the TextTrackCueList... + // ...disregarding cues with a falsey value + for (var i = 0; i < cues.length; i++) { + if (cues[i]) { + cuesArray.push(cues[i]); + } + } + + // Group cues by their startTime value + var cuesGroupedByStartTime = cuesArray.reduce(function (obj, cue) { + var timeSlot = obj[cue.startTime] || []; + + timeSlot.push(cue); + obj[cue.startTime] = timeSlot; + + return obj; + }, {}); + + // Sort startTimes by ascending order + var sortedStartTimes = Object.keys(cuesGroupedByStartTime).sort(function (a, b) { + return Number(a) - Number(b); + }); + + // Map each cue group's endTime to the next group's startTime + sortedStartTimes.forEach(function (startTime, idx) { + var cueGroup = cuesGroupedByStartTime[startTime]; + var nextTime = Number(sortedStartTimes[idx + 1]) || videoDuration; + + // Map each cue's endTime the next group's startTime + cueGroup.forEach(function (cue) { + cue.endTime = nextTime; + }); + }); + } + } + }; + + var win$1 = typeof window !== 'undefined' ? window : {}, + TARGET = typeof Symbol === 'undefined' ? '__target' : Symbol(), + SCRIPT_TYPE = 'application/javascript', + BlobBuilder = win$1.BlobBuilder || win$1.WebKitBlobBuilder || win$1.MozBlobBuilder || win$1.MSBlobBuilder, + URL = win$1.URL || win$1.webkitURL || URL && URL.msURL, + Worker = win$1.Worker; + + /** + * Returns a wrapper around Web Worker code that is constructible. + * + * @function shimWorker + * + * @param { String } filename The name of the file + * @param { Function } fn Function wrapping the code of the worker + */ + function shimWorker(filename, fn) { + return function ShimWorker(forceFallback) { + var o = this; + + if (!fn) { + return new Worker(filename); + } else if (Worker && !forceFallback) { + // Convert the function's inner code to a string to construct the worker + var source = fn.toString().replace(/^function.+?{/, '').slice(0, -1), + objURL = createSourceObject(source); + + this[TARGET] = new Worker(objURL); + wrapTerminate(this[TARGET], objURL); + return this[TARGET]; + } else { + var selfShim = { + postMessage: function postMessage(m) { + if (o.onmessage) { + setTimeout(function () { + o.onmessage({data: m, target: selfShim}); + }); + } + } + }; + + fn.call(selfShim); + this.postMessage = function (m) { + setTimeout(function () { + selfShim.onmessage({data: m, target: o}); + }); + }; + this.isThisThread = true; + } + }; + } + + // Test Worker capabilities + if (Worker) { + var testWorker, + objURL = createSourceObject('self.onmessage = function () {}'), + testArray = new Uint8Array(1); + + try { + testWorker = new Worker(objURL); + + // Native browser on some Samsung devices throws for transferables, let's detect it + testWorker.postMessage(testArray, [testArray.buffer]); + } catch (e) { + Worker = null; + } finally { + URL.revokeObjectURL(objURL); + if (testWorker) { + testWorker.terminate(); + } + } + } + + function createSourceObject(str) { + try { + return URL.createObjectURL(new Blob([str], {type: SCRIPT_TYPE})); + } catch (e) { + var blob = new BlobBuilder(); + blob.append(str); + return URL.createObjectURL(blob.getBlob(type)); + } + } + + function wrapTerminate(worker, objURL) { + if (!worker || !objURL) return; + var term = worker.terminate; + worker.objURL = objURL; + worker.terminate = function () { + if (worker.objURL) URL.revokeObjectURL(worker.objURL); + term.call(worker); + }; + } + + var TransmuxWorker = new shimWorker("./transmuxer-worker.worker.js", function (window, document$$1) { + var self = this; + var transmuxerWorker = function () { + + var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + var win; + + if (typeof window !== "undefined") { + win = window; + } else if (typeof commonjsGlobal !== "undefined") { + win = commonjsGlobal; + } else if (typeof self !== "undefined") { + win = self; + } else { + win = {}; + } + + var window_1$$1 = win; + + /** + * mux.js + * + * Copyright (c) 2015 Brightcove + * All rights reserved. + * + * Functions that generate fragmented MP4s suitable for use with Media + * Source Extensions. + */ + + var UINT32_MAX = Math.pow(2, 32) - 1; + + var box, dinf, esds, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd, trak, tkhd, mdia, mdhd, hdlr, sdtp, stbl, + stsd, traf, trex, trun, types, MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR, AUDIO_HDLR, HDLR_TYPES, VMHD, + SMHD, DREF, STCO, STSC, STSZ, STTS; + + // pre-calculate constants + (function () { + var i; + types = { + avc1: [], // codingname + avcC: [], + btrt: [], + dinf: [], + dref: [], + esds: [], + ftyp: [], + hdlr: [], + mdat: [], + mdhd: [], + mdia: [], + mfhd: [], + minf: [], + moof: [], + moov: [], + mp4a: [], // codingname + mvex: [], + mvhd: [], + sdtp: [], + smhd: [], + stbl: [], + stco: [], + stsc: [], + stsd: [], + stsz: [], + stts: [], + styp: [], + tfdt: [], + tfhd: [], + traf: [], + trak: [], + trun: [], + trex: [], + tkhd: [], + vmhd: [] + }; + + // In environments where Uint8Array is undefined (e.g., IE8), skip set up so that we + // don't throw an error + if (typeof Uint8Array === 'undefined') { + return; + } + + for (i in types) { + if (types.hasOwnProperty(i)) { + types[i] = [i.charCodeAt(0), i.charCodeAt(1), i.charCodeAt(2), i.charCodeAt(3)]; + } + } + + MAJOR_BRAND = new Uint8Array(['i'.charCodeAt(0), 's'.charCodeAt(0), 'o'.charCodeAt(0), 'm'.charCodeAt(0)]); + AVC1_BRAND = new Uint8Array(['a'.charCodeAt(0), 'v'.charCodeAt(0), 'c'.charCodeAt(0), '1'.charCodeAt(0)]); + MINOR_VERSION = new Uint8Array([0, 0, 0, 1]); + VIDEO_HDLR = new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, 0x00, 0x00, // pre_defined + 0x76, 0x69, 0x64, 0x65, // handler_type: 'vide' + 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x00, 0x00, 0x00, // reserved + 0x56, 0x69, 0x64, 0x65, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'VideoHandler' + ]); + AUDIO_HDLR = new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, 0x00, 0x00, // pre_defined + 0x73, 0x6f, 0x75, 0x6e, // handler_type: 'soun' + 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x00, 0x00, 0x00, // reserved + 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'SoundHandler' + ]); + HDLR_TYPES = { + video: VIDEO_HDLR, + audio: AUDIO_HDLR + }; + DREF = new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, 0x00, 0x01, // entry_count + 0x00, 0x00, 0x00, 0x0c, // entry_size + 0x75, 0x72, 0x6c, 0x20, // 'url' type + 0x00, // version 0 + 0x00, 0x00, 0x01 // entry_flags + ]); + SMHD = new Uint8Array([0x00, // version + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, // balance, 0 means centered + 0x00, 0x00 // reserved + ]); + STCO = new Uint8Array([0x00, // version + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, 0x00, 0x00 // entry_count + ]); + STSC = STCO; + STSZ = new Uint8Array([0x00, // version + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, 0x00, 0x00, // sample_size + 0x00, 0x00, 0x00, 0x00 // sample_count + ]); + STTS = STCO; + VMHD = new Uint8Array([0x00, // version + 0x00, 0x00, 0x01, // flags + 0x00, 0x00, // graphicsmode + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // opcolor + ]); + })(); + + box = function box(type) { + var payload = [], + size = 0, + i, + result, + view; + + for (i = 1; i < arguments.length; i++) { + payload.push(arguments[i]); + } + + i = payload.length; + + // calculate the total size we need to allocate + while (i--) { + size += payload[i].byteLength; + } + result = new Uint8Array(size + 8); + view = new DataView(result.buffer, result.byteOffset, result.byteLength); + view.setUint32(0, result.byteLength); + result.set(type, 4); + + // copy the payload into the result + for (i = 0, size = 8; i < payload.length; i++) { + result.set(payload[i], size); + size += payload[i].byteLength; + } + return result; + }; + + dinf = function dinf() { + return box(types.dinf, box(types.dref, DREF)); + }; + + esds = function esds(track) { + return box(types.esds, new Uint8Array([0x00, // version + 0x00, 0x00, 0x00, // flags + + // ES_Descriptor + 0x03, // tag, ES_DescrTag + 0x19, // length + 0x00, 0x00, // ES_ID + 0x00, // streamDependenceFlag, URL_flag, reserved, streamPriority + + // DecoderConfigDescriptor + 0x04, // tag, DecoderConfigDescrTag + 0x11, // length + 0x40, // object type + 0x15, // streamType + 0x00, 0x06, 0x00, // bufferSizeDB + 0x00, 0x00, 0xda, 0xc0, // maxBitrate + 0x00, 0x00, 0xda, 0xc0, // avgBitrate + + // DecoderSpecificInfo + 0x05, // tag, DecoderSpecificInfoTag + 0x02, // length + // ISO/IEC 14496-3, AudioSpecificConfig + // for samplingFrequencyIndex see ISO/IEC 13818-7:2006, 8.1.3.2.2, Table 35 + track.audioobjecttype << 3 | track.samplingfrequencyindex >>> 1, track.samplingfrequencyindex << 7 | track.channelcount << 3, 0x06, 0x01, 0x02 // GASpecificConfig + ])); + }; + + ftyp = function ftyp() { + return box(types.ftyp, MAJOR_BRAND, MINOR_VERSION, MAJOR_BRAND, AVC1_BRAND); + }; + + hdlr = function hdlr(type) { + return box(types.hdlr, HDLR_TYPES[type]); + }; + mdat = function mdat(data) { + return box(types.mdat, data); + }; + mdhd = function mdhd(track) { + var result = new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, 0x00, 0x02, // creation_time + 0x00, 0x00, 0x00, 0x03, // modification_time + 0x00, 0x01, 0x5f, 0x90, // timescale, 90,000 "ticks" per second + + track.duration >>> 24 & 0xFF, track.duration >>> 16 & 0xFF, track.duration >>> 8 & 0xFF, track.duration & 0xFF, // duration + 0x55, 0xc4, // 'und' language (undetermined) + 0x00, 0x00]); + + // Use the sample rate from the track metadata, when it is + // defined. The sample rate can be parsed out of an ADTS header, for + // instance. + if (track.samplerate) { + result[12] = track.samplerate >>> 24 & 0xFF; + result[13] = track.samplerate >>> 16 & 0xFF; + result[14] = track.samplerate >>> 8 & 0xFF; + result[15] = track.samplerate & 0xFF; + } + + return box(types.mdhd, result); + }; + mdia = function mdia(track) { + return box(types.mdia, mdhd(track), hdlr(track.type), minf(track)); + }; + mfhd = function mfhd(sequenceNumber) { + return box(types.mfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // flags + (sequenceNumber & 0xFF000000) >> 24, (sequenceNumber & 0xFF0000) >> 16, (sequenceNumber & 0xFF00) >> 8, sequenceNumber & 0xFF // sequence_number + ])); + }; + minf = function minf(track) { + return box(types.minf, track.type === 'video' ? box(types.vmhd, VMHD) : box(types.smhd, SMHD), dinf(), stbl(track)); + }; + moof = function moof(sequenceNumber, tracks) { + var trackFragments = [], + i = tracks.length; + // build traf boxes for each track fragment + while (i--) { + trackFragments[i] = traf(tracks[i]); + } + return box.apply(null, [types.moof, mfhd(sequenceNumber)].concat(trackFragments)); + }; + /** + * Returns a movie box. + * @param tracks {array} the tracks associated with this movie + * @see ISO/IEC 14496-12:2012(E), section 8.2.1 + */ + moov = function moov(tracks) { + var i = tracks.length, + boxes = []; + + while (i--) { + boxes[i] = trak(tracks[i]); + } + + return box.apply(null, [types.moov, mvhd(0xffffffff)].concat(boxes).concat(mvex(tracks))); + }; + mvex = function mvex(tracks) { + var i = tracks.length, + boxes = []; + + while (i--) { + boxes[i] = trex(tracks[i]); + } + return box.apply(null, [types.mvex].concat(boxes)); + }; + mvhd = function mvhd(duration) { + var bytes = new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, 0x00, 0x01, // creation_time + 0x00, 0x00, 0x00, 0x02, // modification_time + 0x00, 0x01, 0x5f, 0x90, // timescale, 90,000 "ticks" per second + (duration & 0xFF000000) >> 24, (duration & 0xFF0000) >> 16, (duration & 0xFF00) >> 8, duration & 0xFF, // duration + 0x00, 0x01, 0x00, 0x00, // 1.0 rate + 0x01, 0x00, // 1.0 volume + 0x00, 0x00, // reserved + 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined + 0xff, 0xff, 0xff, 0xff // next_track_ID + ]); + return box(types.mvhd, bytes); + }; + + sdtp = function sdtp(track) { + var samples = track.samples || [], + bytes = new Uint8Array(4 + samples.length), + flags, + i; + + // leave the full box header (4 bytes) all zero + + // write the sample table + for (i = 0; i < samples.length; i++) { + flags = samples[i].flags; + + bytes[i + 4] = flags.dependsOn << 4 | flags.isDependedOn << 2 | flags.hasRedundancy; + } + + return box(types.sdtp, bytes); + }; + + stbl = function stbl(track) { + return box(types.stbl, stsd(track), box(types.stts, STTS), box(types.stsc, STSC), box(types.stsz, STSZ), box(types.stco, STCO)); + }; + + (function () { + var videoSample, audioSample; + + stsd = function stsd(track) { + + return box(types.stsd, new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x00, // flags + 0x00, 0x00, 0x00, 0x01]), track.type === 'video' ? videoSample(track) : audioSample(track)); + }; + + videoSample = function videoSample(track) { + var sps = track.sps || [], + pps = track.pps || [], + sequenceParameterSets = [], + pictureParameterSets = [], + i; + + // assemble the SPSs + for (i = 0; i < sps.length; i++) { + sequenceParameterSets.push((sps[i].byteLength & 0xFF00) >>> 8); + sequenceParameterSets.push(sps[i].byteLength & 0xFF); // sequenceParameterSetLength + sequenceParameterSets = sequenceParameterSets.concat(Array.prototype.slice.call(sps[i])); // SPS + } + + // assemble the PPSs + for (i = 0; i < pps.length; i++) { + pictureParameterSets.push((pps[i].byteLength & 0xFF00) >>> 8); + pictureParameterSets.push(pps[i].byteLength & 0xFF); + pictureParameterSets = pictureParameterSets.concat(Array.prototype.slice.call(pps[i])); + } + + return box(types.avc1, new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x01, // data_reference_index + 0x00, 0x00, // pre_defined + 0x00, 0x00, // reserved + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined + (track.width & 0xff00) >> 8, track.width & 0xff, // width + (track.height & 0xff00) >> 8, track.height & 0xff, // height + 0x00, 0x48, 0x00, 0x00, // horizresolution + 0x00, 0x48, 0x00, 0x00, // vertresolution + 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x01, // frame_count + 0x13, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6a, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x2d, 0x68, 0x6c, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compressorname + 0x00, 0x18, // depth = 24 + 0x11, 0x11 // pre_defined = -1 + ]), box(types.avcC, new Uint8Array([0x01, // configurationVersion + track.profileIdc, // AVCProfileIndication + track.profileCompatibility, // profile_compatibility + track.levelIdc, // AVCLevelIndication + 0xff // lengthSizeMinusOne, hard-coded to 4 bytes + ].concat([sps.length // numOfSequenceParameterSets + ]).concat(sequenceParameterSets).concat([pps.length // numOfPictureParameterSets + ]).concat(pictureParameterSets))), // "PPS" + box(types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB + 0x00, 0x2d, 0xc6, 0xc0, // maxBitrate + 0x00, 0x2d, 0xc6, 0xc0])) // avgBitrate + ); + }; + + audioSample = function audioSample(track) { + return box(types.mp4a, new Uint8Array([ + + // SampleEntry, ISO/IEC 14496-12 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x01, // data_reference_index + + // AudioSampleEntry, ISO/IEC 14496-12 + 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x00, 0x00, 0x00, // reserved + (track.channelcount & 0xff00) >> 8, track.channelcount & 0xff, // channelcount + + (track.samplesize & 0xff00) >> 8, track.samplesize & 0xff, // samplesize + 0x00, 0x00, // pre_defined + 0x00, 0x00, // reserved + + (track.samplerate & 0xff00) >> 8, track.samplerate & 0xff, 0x00, 0x00 // samplerate, 16.16 + + // MP4AudioSampleEntry, ISO/IEC 14496-14 + ]), esds(track)); + }; + })(); + + tkhd = function tkhd(track) { + var result = new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x07, // flags + 0x00, 0x00, 0x00, 0x00, // creation_time + 0x00, 0x00, 0x00, 0x00, // modification_time + (track.id & 0xFF000000) >> 24, (track.id & 0xFF0000) >> 16, (track.id & 0xFF00) >> 8, track.id & 0xFF, // track_ID + 0x00, 0x00, 0x00, 0x00, // reserved + (track.duration & 0xFF000000) >> 24, (track.duration & 0xFF0000) >> 16, (track.duration & 0xFF00) >> 8, track.duration & 0xFF, // duration + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved + 0x00, 0x00, // layer + 0x00, 0x00, // alternate_group + 0x01, 0x00, // non-audio track volume + 0x00, 0x00, // reserved + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix + (track.width & 0xFF00) >> 8, track.width & 0xFF, 0x00, 0x00, // width + (track.height & 0xFF00) >> 8, track.height & 0xFF, 0x00, 0x00 // height + ]); + + return box(types.tkhd, result); + }; + + /** + * Generate a track fragment (traf) box. A traf box collects metadata + * about tracks in a movie fragment (moof) box. + */ + traf = function traf(track) { + var trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun, sampleDependencyTable, dataOffset, + upperWordBaseMediaDecodeTime, lowerWordBaseMediaDecodeTime; + + trackFragmentHeader = box(types.tfhd, new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x3a, // flags + (track.id & 0xFF000000) >> 24, (track.id & 0xFF0000) >> 16, (track.id & 0xFF00) >> 8, track.id & 0xFF, // track_ID + 0x00, 0x00, 0x00, 0x01, // sample_description_index + 0x00, 0x00, 0x00, 0x00, // default_sample_duration + 0x00, 0x00, 0x00, 0x00, // default_sample_size + 0x00, 0x00, 0x00, 0x00 // default_sample_flags + ])); + + upperWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime / (UINT32_MAX + 1)); + lowerWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime % (UINT32_MAX + 1)); + + trackFragmentDecodeTime = box(types.tfdt, new Uint8Array([0x01, // version 1 + 0x00, 0x00, 0x00, // flags + // baseMediaDecodeTime + upperWordBaseMediaDecodeTime >>> 24 & 0xFF, upperWordBaseMediaDecodeTime >>> 16 & 0xFF, upperWordBaseMediaDecodeTime >>> 8 & 0xFF, upperWordBaseMediaDecodeTime & 0xFF, lowerWordBaseMediaDecodeTime >>> 24 & 0xFF, lowerWordBaseMediaDecodeTime >>> 16 & 0xFF, lowerWordBaseMediaDecodeTime >>> 8 & 0xFF, lowerWordBaseMediaDecodeTime & 0xFF])); + + // the data offset specifies the number of bytes from the start of + // the containing moof to the first payload byte of the associated + // mdat + dataOffset = 32 + // tfhd + 20 + // tfdt + 8 + // traf header + 16 + // mfhd + 8 + // moof header + 8; // mdat header + + // audio tracks require less metadata + if (track.type === 'audio') { + trackFragmentRun = trun(track, dataOffset); + return box(types.traf, trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun); + } + + // video tracks should contain an independent and disposable samples + // box (sdtp) + // generate one and adjust offsets to match + sampleDependencyTable = sdtp(track); + trackFragmentRun = trun(track, sampleDependencyTable.length + dataOffset); + return box(types.traf, trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun, sampleDependencyTable); + }; + + /** + * Generate a track box. + * @param track {object} a track definition + * @return {Uint8Array} the track box + */ + trak = function trak(track) { + track.duration = track.duration || 0xffffffff; + return box(types.trak, tkhd(track), mdia(track)); + }; + + trex = function trex(track) { + var result = new Uint8Array([0x00, // version 0 + 0x00, 0x00, 0x00, // flags + (track.id & 0xFF000000) >> 24, (track.id & 0xFF0000) >> 16, (track.id & 0xFF00) >> 8, track.id & 0xFF, // track_ID + 0x00, 0x00, 0x00, 0x01, // default_sample_description_index + 0x00, 0x00, 0x00, 0x00, // default_sample_duration + 0x00, 0x00, 0x00, 0x00, // default_sample_size + 0x00, 0x01, 0x00, 0x01 // default_sample_flags + ]); + // the last two bytes of default_sample_flags is the sample + // degradation priority, a hint about the importance of this sample + // relative to others. Lower the degradation priority for all sample + // types other than video. + if (track.type !== 'video') { + result[result.length - 1] = 0x00; + } + + return box(types.trex, result); + }; + + (function () { + var audioTrun, videoTrun, trunHeader; + + // This method assumes all samples are uniform. That is, if a + // duration is present for the first sample, it will be present for + // all subsequent samples. + // see ISO/IEC 14496-12:2012, Section 8.8.8.1 + trunHeader = function trunHeader(samples, offset) { + var durationPresent = 0, + sizePresent = 0, + flagsPresent = 0, + compositionTimeOffset = 0; + + // trun flag constants + if (samples.length) { + if (samples[0].duration !== undefined) { + durationPresent = 0x1; + } + if (samples[0].size !== undefined) { + sizePresent = 0x2; + } + if (samples[0].flags !== undefined) { + flagsPresent = 0x4; + } + if (samples[0].compositionTimeOffset !== undefined) { + compositionTimeOffset = 0x8; + } + } + + return [0x00, // version 0 + 0x00, durationPresent | sizePresent | flagsPresent | compositionTimeOffset, 0x01, // flags + (samples.length & 0xFF000000) >>> 24, (samples.length & 0xFF0000) >>> 16, (samples.length & 0xFF00) >>> 8, samples.length & 0xFF, // sample_count + (offset & 0xFF000000) >>> 24, (offset & 0xFF0000) >>> 16, (offset & 0xFF00) >>> 8, offset & 0xFF // data_offset + ]; + }; + + videoTrun = function videoTrun(track, offset) { + var bytes, samples, sample, i; + + samples = track.samples || []; + offset += 8 + 12 + 16 * samples.length; + + bytes = trunHeader(samples, offset); + + for (i = 0; i < samples.length; i++) { + sample = samples[i]; + bytes = bytes.concat([(sample.duration & 0xFF000000) >>> 24, (sample.duration & 0xFF0000) >>> 16, (sample.duration & 0xFF00) >>> 8, sample.duration & 0xFF, // sample_duration + (sample.size & 0xFF000000) >>> 24, (sample.size & 0xFF0000) >>> 16, (sample.size & 0xFF00) >>> 8, sample.size & 0xFF, // sample_size + sample.flags.isLeading << 2 | sample.flags.dependsOn, sample.flags.isDependedOn << 6 | sample.flags.hasRedundancy << 4 | sample.flags.paddingValue << 1 | sample.flags.isNonSyncSample, sample.flags.degradationPriority & 0xF0 << 8, sample.flags.degradationPriority & 0x0F, // sample_flags + (sample.compositionTimeOffset & 0xFF000000) >>> 24, (sample.compositionTimeOffset & 0xFF0000) >>> 16, (sample.compositionTimeOffset & 0xFF00) >>> 8, sample.compositionTimeOffset & 0xFF // sample_composition_time_offset + ]); + } + return box(types.trun, new Uint8Array(bytes)); + }; + + audioTrun = function audioTrun(track, offset) { + var bytes, samples, sample, i; + + samples = track.samples || []; + offset += 8 + 12 + 8 * samples.length; + + bytes = trunHeader(samples, offset); + + for (i = 0; i < samples.length; i++) { + sample = samples[i]; + bytes = bytes.concat([(sample.duration & 0xFF000000) >>> 24, (sample.duration & 0xFF0000) >>> 16, (sample.duration & 0xFF00) >>> 8, sample.duration & 0xFF, // sample_duration + (sample.size & 0xFF000000) >>> 24, (sample.size & 0xFF0000) >>> 16, (sample.size & 0xFF00) >>> 8, sample.size & 0xFF]); // sample_size + } + + return box(types.trun, new Uint8Array(bytes)); + }; + + trun = function trun(track, offset) { + if (track.type === 'audio') { + return audioTrun(track, offset); + } + + return videoTrun(track, offset); + }; + })(); + + var mp4Generator = { + ftyp: ftyp, + mdat: mdat, + moof: moof, + moov: moov, + initSegment: function initSegment(tracks) { + var fileType = ftyp(), + movie = moov(tracks), + result; + + result = new Uint8Array(fileType.byteLength + movie.byteLength); + result.set(fileType); + result.set(movie, fileType.byteLength); + return result; + } + }; + + /** + * mux.js + * + * Copyright (c) 2014 Brightcove + * All rights reserved. + * + * A lightweight readable stream implemention that handles event dispatching. + * Objects that inherit from streams should call init in their constructors. + */ + + var Stream = function Stream() { + this.init = function () { + var listeners = {}; + /** + * Add a listener for a specified event type. + * @param type {string} the event name + * @param listener {function} the callback to be invoked when an event of + * the specified type occurs + */ + this.on = function (type, listener) { + if (!listeners[type]) { + listeners[type] = []; + } + listeners[type] = listeners[type].concat(listener); + }; + /** + * Remove a listener for a specified event type. + * @param type {string} the event name + * @param listener {function} a function previously registered for this + * type of event through `on` + */ + this.off = function (type, listener) { + var index; + if (!listeners[type]) { + return false; + } + index = listeners[type].indexOf(listener); + listeners[type] = listeners[type].slice(); + listeners[type].splice(index, 1); + return index > -1; + }; + /** + * Trigger an event of the specified type on this stream. Any additional + * arguments to this function are passed as parameters to event listeners. + * @param type {string} the event name + */ + this.trigger = function (type) { + var callbacks, i, length, args; + callbacks = listeners[type]; + if (!callbacks) { + return; + } + // Slicing the arguments on every invocation of this method + // can add a significant amount of overhead. Avoid the + // intermediate object creation for the common case of a + // single callback argument + if (arguments.length === 2) { + length = callbacks.length; + for (i = 0; i < length; ++i) { + callbacks[i].call(this, arguments[1]); + } + } else { + args = []; + i = arguments.length; + for (i = 1; i < arguments.length; ++i) { + args.push(arguments[i]); + } + length = callbacks.length; + for (i = 0; i < length; ++i) { + callbacks[i].apply(this, args); + } + } + }; + /** + * Destroys the stream and cleans up. + */ + this.dispose = function () { + listeners = {}; + }; + }; + }; + + /** + * Forwards all `data` events on this stream to the destination stream. The + * destination stream should provide a method `push` to receive the data + * events as they arrive. + * @param destination {stream} the stream that will receive all `data` events + * @param autoFlush {boolean} if false, we will not call `flush` on the destination + * when the current stream emits a 'done' event + * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options + */ + Stream.prototype.pipe = function (destination) { + this.on('data', function (data) { + destination.push(data); + }); + + this.on('done', function (flushSource) { + destination.flush(flushSource); + }); + + return destination; + }; + + // Default stream functions that are expected to be overridden to perform + // actual work. These are provided by the prototype as a sort of no-op + // implementation so that we don't have to check for their existence in the + // `pipe` function above. + Stream.prototype.push = function (data) { + this.trigger('data', data); + }; + + Stream.prototype.flush = function (flushSource) { + this.trigger('done', flushSource); + }; + + var stream = Stream; + + // ----------------- + // Link To Transport + // ----------------- + + // Supplemental enhancement information (SEI) NAL units have a + // payload type field to indicate how they are to be + // interpreted. CEAS-708 caption content is always transmitted with + // payload type 0x04. + var USER_DATA_REGISTERED_ITU_T_T35 = 4, + RBSP_TRAILING_BITS = 128; + + /** + * Parse a supplemental enhancement information (SEI) NAL unit. + * Stops parsing once a message of type ITU T T35 has been found. + * + * @param bytes {Uint8Array} the bytes of a SEI NAL unit + * @return {object} the parsed SEI payload + * @see Rec. ITU-T H.264, 7.3.2.3.1 + */ + var parseSei = function parseSei(bytes) { + var i = 0, + result = { + payloadType: -1, + payloadSize: 0 + }, + payloadType = 0, + payloadSize = 0; + + // go through the sei_rbsp parsing each each individual sei_message + while (i < bytes.byteLength) { + // stop once we have hit the end of the sei_rbsp + if (bytes[i] === RBSP_TRAILING_BITS) { + break; + } + + // Parse payload type + while (bytes[i] === 0xFF) { + payloadType += 255; + i++; + } + payloadType += bytes[i++]; + + // Parse payload size + while (bytes[i] === 0xFF) { + payloadSize += 255; + i++; + } + payloadSize += bytes[i++]; + + // this sei_message is a 608/708 caption so save it and break + // there can only ever be one caption message in a frame's sei + if (!result.payload && payloadType === USER_DATA_REGISTERED_ITU_T_T35) { + result.payloadType = payloadType; + result.payloadSize = payloadSize; + result.payload = bytes.subarray(i, i + payloadSize); + break; + } + + // skip the payload and parse the next message + i += payloadSize; + payloadType = 0; + payloadSize = 0; + } + + return result; + }; + + // see ANSI/SCTE 128-1 (2013), section 8.1 + var parseUserData = function parseUserData(sei) { + // itu_t_t35_contry_code must be 181 (United States) for + // captions + if (sei.payload[0] !== 181) { + return null; + } + + // itu_t_t35_provider_code should be 49 (ATSC) for captions + if ((sei.payload[1] << 8 | sei.payload[2]) !== 49) { + return null; + } + + // the user_identifier should be "GA94" to indicate ATSC1 data + if (String.fromCharCode(sei.payload[3], sei.payload[4], sei.payload[5], sei.payload[6]) !== 'GA94') { + return null; + } + + // finally, user_data_type_code should be 0x03 for caption data + if (sei.payload[7] !== 0x03) { + return null; + } + + // return the user_data_type_structure and strip the trailing + // marker bits + return sei.payload.subarray(8, sei.payload.length - 1); + }; + + // see CEA-708-D, section 4.4 + var parseCaptionPackets = function parseCaptionPackets(pts, userData) { + var results = [], + i, + count, + offset, + data; + + // if this is just filler, return immediately + if (!(userData[0] & 0x40)) { + return results; + } + + // parse out the cc_data_1 and cc_data_2 fields + count = userData[0] & 0x1f; + for (i = 0; i < count; i++) { + offset = i * 3; + data = { + type: userData[offset + 2] & 0x03, + pts: pts + }; + + // capture cc data when cc_valid is 1 + if (userData[offset + 2] & 0x04) { + data.ccData = userData[offset + 3] << 8 | userData[offset + 4]; + results.push(data); + } + } + return results; + }; + + var CaptionStream = function CaptionStream() { + + CaptionStream.prototype.init.call(this); + + this.captionPackets_ = []; + + this.ccStreams_ = [new Cea608Stream(0, 0), // eslint-disable-line no-use-before-define + new Cea608Stream(0, 1), // eslint-disable-line no-use-before-define + new Cea608Stream(1, 0), // eslint-disable-line no-use-before-define + new Cea608Stream(1, 1) // eslint-disable-line no-use-before-define + ]; + + this.reset(); + + // forward data and done events from CCs to this CaptionStream + this.ccStreams_.forEach(function (cc) { + cc.on('data', this.trigger.bind(this, 'data')); + cc.on('done', this.trigger.bind(this, 'done')); + }, this); + }; + + CaptionStream.prototype = new stream(); + CaptionStream.prototype.push = function (event) { + var sei, userData; + + // only examine SEI NALs + if (event.nalUnitType !== 'sei_rbsp') { + return; + } + + // parse the sei + sei = parseSei(event.escapedRBSP); + + // ignore everything but user_data_registered_itu_t_t35 + if (sei.payloadType !== USER_DATA_REGISTERED_ITU_T_T35) { + return; + } + + // parse out the user data payload + userData = parseUserData(sei); + + // ignore unrecognized userData + if (!userData) { + return; + } + + // Sometimes, the same segment # will be downloaded twice. To stop the + // caption data from being processed twice, we track the latest dts we've + // received and ignore everything with a dts before that. However, since + // data for a specific dts can be split across packets on either side of + // a segment boundary, we need to make sure we *don't* ignore the packets + // from the *next* segment that have dts === this.latestDts_. By constantly + // tracking the number of packets received with dts === this.latestDts_, we + // know how many should be ignored once we start receiving duplicates. + if (event.dts < this.latestDts_) { + // We've started getting older data, so set the flag. + this.ignoreNextEqualDts_ = true; + return; + } else if (event.dts === this.latestDts_ && this.ignoreNextEqualDts_) { + this.numSameDts_--; + if (!this.numSameDts_) { + // We've received the last duplicate packet, time to start processing again + this.ignoreNextEqualDts_ = false; + } + return; + } + + // parse out CC data packets and save them for later + this.captionPackets_ = this.captionPackets_.concat(parseCaptionPackets(event.pts, userData)); + if (this.latestDts_ !== event.dts) { + this.numSameDts_ = 0; + } + this.numSameDts_++; + this.latestDts_ = event.dts; + }; + + CaptionStream.prototype.flush = function () { + // make sure we actually parsed captions before proceeding + if (!this.captionPackets_.length) { + this.ccStreams_.forEach(function (cc) { + cc.flush(); + }, this); + return; + } + + // In Chrome, the Array#sort function is not stable so add a + // presortIndex that we can use to ensure we get a stable-sort + this.captionPackets_.forEach(function (elem, idx) { + elem.presortIndex = idx; + }); + + // sort caption byte-pairs based on their PTS values + this.captionPackets_.sort(function (a, b) { + if (a.pts === b.pts) { + return a.presortIndex - b.presortIndex; + } + return a.pts - b.pts; + }); + + this.captionPackets_.forEach(function (packet) { + if (packet.type < 2) { + // Dispatch packet to the right Cea608Stream + this.dispatchCea608Packet(packet); + } + // this is where an 'else' would go for a dispatching packets + // to a theoretical Cea708Stream that handles SERVICEn data + }, this); + + this.captionPackets_.length = 0; + this.ccStreams_.forEach(function (cc) { + cc.flush(); + }, this); + return; + }; + + CaptionStream.prototype.reset = function () { + this.latestDts_ = null; + this.ignoreNextEqualDts_ = false; + this.numSameDts_ = 0; + this.activeCea608Channel_ = [null, null]; + this.ccStreams_.forEach(function (ccStream) { + ccStream.reset(); + }); + }; + + CaptionStream.prototype.dispatchCea608Packet = function (packet) { + // NOTE: packet.type is the CEA608 field + if (this.setsChannel1Active(packet)) { + this.activeCea608Channel_[packet.type] = 0; + } else if (this.setsChannel2Active(packet)) { + this.activeCea608Channel_[packet.type] = 1; + } + if (this.activeCea608Channel_[packet.type] === null) { + // If we haven't received anything to set the active channel, discard the + // data; we don't want jumbled captions + return; + } + this.ccStreams_[(packet.type << 1) + this.activeCea608Channel_[packet.type]].push(packet); + }; + + CaptionStream.prototype.setsChannel1Active = function (packet) { + return (packet.ccData & 0x7800) === 0x1000; + }; + CaptionStream.prototype.setsChannel2Active = function (packet) { + return (packet.ccData & 0x7800) === 0x1800; + }; + + // ---------------------- + // Session to Application + // ---------------------- + + var CHARACTER_TRANSLATION = { + 0x2a: 0xe1, // á + 0x5c: 0xe9, // é + 0x5e: 0xed, // à + 0x5f: 0xf3, // ó + 0x60: 0xfa, // ú + 0x7b: 0xe7, // ç + 0x7c: 0xf7, // ÷ + 0x7d: 0xd1, // Ñ + 0x7e: 0xf1, // ñ + 0x7f: 0x2588, // â–ˆ + 0x0130: 0xae, // ® + 0x0131: 0xb0, // ° + 0x0132: 0xbd, // ½ + 0x0133: 0xbf, // ¿ + 0x0134: 0x2122, // â„¢ + 0x0135: 0xa2, // ¢ + 0x0136: 0xa3, // £ + 0x0137: 0x266a, // ♪ + 0x0138: 0xe0, // à + 0x0139: 0xa0, // + 0x013a: 0xe8, // è + 0x013b: 0xe2, // â + 0x013c: 0xea, // ê + 0x013d: 0xee, // î + 0x013e: 0xf4, // ô + 0x013f: 0xfb, // û + 0x0220: 0xc1, // à + 0x0221: 0xc9, // É + 0x0222: 0xd3, // Ó + 0x0223: 0xda, // Ú + 0x0224: 0xdc, // Ü + 0x0225: 0xfc, // ü + 0x0226: 0x2018, // ‘ + 0x0227: 0xa1, // ¡ + 0x0228: 0x2a, // * + 0x0229: 0x27, // ' + 0x022a: 0x2014, // — + 0x022b: 0xa9, // © + 0x022c: 0x2120, // â„ + 0x022d: 0x2022, // • + 0x022e: 0x201c, // “ + 0x022f: 0x201d, // †+ 0x0230: 0xc0, // À + 0x0231: 0xc2, //  + 0x0232: 0xc7, // Ç + 0x0233: 0xc8, // È + 0x0234: 0xca, // Ê + 0x0235: 0xcb, // Ë + 0x0236: 0xeb, // ë + 0x0237: 0xce, // ÃŽ + 0x0238: 0xcf, // à + 0x0239: 0xef, // ï + 0x023a: 0xd4, // Ô + 0x023b: 0xd9, // Ù + 0x023c: 0xf9, // ù + 0x023d: 0xdb, // Û + 0x023e: 0xab, // « + 0x023f: 0xbb, // » + 0x0320: 0xc3, // à + 0x0321: 0xe3, // ã + 0x0322: 0xcd, // à + 0x0323: 0xcc, // ÃŒ + 0x0324: 0xec, // ì + 0x0325: 0xd2, // Ã’ + 0x0326: 0xf2, // ò + 0x0327: 0xd5, // Õ + 0x0328: 0xf5, // õ + 0x0329: 0x7b, // { + 0x032a: 0x7d, // } + 0x032b: 0x5c, // \ + 0x032c: 0x5e, // ^ + 0x032d: 0x5f, // _ + 0x032e: 0x7c, // | + 0x032f: 0x7e, // ~ + 0x0330: 0xc4, // Ä + 0x0331: 0xe4, // ä + 0x0332: 0xd6, // Ö + 0x0333: 0xf6, // ö + 0x0334: 0xdf, // ß + 0x0335: 0xa5, // Â¥ + 0x0336: 0xa4, // ¤ + 0x0337: 0x2502, // │ + 0x0338: 0xc5, // Ã… + 0x0339: 0xe5, // Ã¥ + 0x033a: 0xd8, // Ø + 0x033b: 0xf8, // ø + 0x033c: 0x250c, // ┌ + 0x033d: 0x2510, // â” + 0x033e: 0x2514, // â”” + 0x033f: 0x2518 // ┘ + }; + + var getCharFromCode = function getCharFromCode(code) { + if (code === null) { + return ''; + } + code = CHARACTER_TRANSLATION[code] || code; + return String.fromCharCode(code); + }; + + // the index of the last row in a CEA-608 display buffer + var BOTTOM_ROW = 14; + + // This array is used for mapping PACs -> row #, since there's no way of + // getting it through bit logic. + var ROWS = [0x1100, 0x1120, 0x1200, 0x1220, 0x1500, 0x1520, 0x1600, 0x1620, 0x1700, 0x1720, 0x1000, 0x1300, 0x1320, 0x1400, 0x1420]; + + // CEA-608 captions are rendered onto a 34x15 matrix of character + // cells. The "bottom" row is the last element in the outer array. + var createDisplayBuffer = function createDisplayBuffer() { + var result = [], + i = BOTTOM_ROW + 1; + while (i--) { + result.push(''); + } + return result; + }; + + var Cea608Stream = function Cea608Stream(field, dataChannel) { + Cea608Stream.prototype.init.call(this); + + this.field_ = field || 0; + this.dataChannel_ = dataChannel || 0; + + this.name_ = 'CC' + ((this.field_ << 1 | this.dataChannel_) + 1); + + this.setConstants(); + this.reset(); + + this.push = function (packet) { + var data, swap, char0, char1, text; + // remove the parity bits + data = packet.ccData & 0x7f7f; + + // ignore duplicate control codes; the spec demands they're sent twice + if (data === this.lastControlCode_) { + this.lastControlCode_ = null; + return; + } + + // Store control codes + if ((data & 0xf000) === 0x1000) { + this.lastControlCode_ = data; + } else if (data !== this.PADDING_) { + this.lastControlCode_ = null; + } + + char0 = data >>> 8; + char1 = data & 0xff; + + if (data === this.PADDING_) { + return; + } else if (data === this.RESUME_CAPTION_LOADING_) { + this.mode_ = 'popOn'; + } else if (data === this.END_OF_CAPTION_) { + this.clearFormatting(packet.pts); + // if a caption was being displayed, it's gone now + this.flushDisplayed(packet.pts); + + // flip memory + swap = this.displayed_; + this.displayed_ = this.nonDisplayed_; + this.nonDisplayed_ = swap; + + // start measuring the time to display the caption + this.startPts_ = packet.pts; + } else if (data === this.ROLL_UP_2_ROWS_) { + this.topRow_ = BOTTOM_ROW - 1; + this.mode_ = 'rollUp'; + } else if (data === this.ROLL_UP_3_ROWS_) { + this.topRow_ = BOTTOM_ROW - 2; + this.mode_ = 'rollUp'; + } else if (data === this.ROLL_UP_4_ROWS_) { + this.topRow_ = BOTTOM_ROW - 3; + this.mode_ = 'rollUp'; + } else if (data === this.CARRIAGE_RETURN_) { + this.clearFormatting(packet.pts); + this.flushDisplayed(packet.pts); + this.shiftRowsUp_(); + this.startPts_ = packet.pts; + } else if (data === this.BACKSPACE_) { + if (this.mode_ === 'popOn') { + this.nonDisplayed_[BOTTOM_ROW] = this.nonDisplayed_[BOTTOM_ROW].slice(0, -1); + } else { + this.displayed_[BOTTOM_ROW] = this.displayed_[BOTTOM_ROW].slice(0, -1); + } + } else if (data === this.ERASE_DISPLAYED_MEMORY_) { + this.flushDisplayed(packet.pts); + this.displayed_ = createDisplayBuffer(); + } else if (data === this.ERASE_NON_DISPLAYED_MEMORY_) { + this.nonDisplayed_ = createDisplayBuffer(); + } else if (data === this.RESUME_DIRECT_CAPTIONING_) { + this.mode_ = 'paintOn'; + + // Append special characters to caption text + } else if (this.isSpecialCharacter(char0, char1)) { + // Bitmask char0 so that we can apply character transformations + // regardless of field and data channel. + // Then byte-shift to the left and OR with char1 so we can pass the + // entire character code to `getCharFromCode`. + char0 = (char0 & 0x03) << 8; + text = getCharFromCode(char0 | char1); + this[this.mode_](packet.pts, text); + this.column_++; + + // Append extended characters to caption text + } else if (this.isExtCharacter(char0, char1)) { + // Extended characters always follow their "non-extended" equivalents. + // IE if a "è" is desired, you'll always receive "eè"; non-compliant + // decoders are supposed to drop the "è", while compliant decoders + // backspace the "e" and insert "è". + + // Delete the previous character + if (this.mode_ === 'popOn') { + this.nonDisplayed_[this.row_] = this.nonDisplayed_[this.row_].slice(0, -1); + } else { + this.displayed_[BOTTOM_ROW] = this.displayed_[BOTTOM_ROW].slice(0, -1); + } + + // Bitmask char0 so that we can apply character transformations + // regardless of field and data channel. + // Then byte-shift to the left and OR with char1 so we can pass the + // entire character code to `getCharFromCode`. + char0 = (char0 & 0x03) << 8; + text = getCharFromCode(char0 | char1); + this[this.mode_](packet.pts, text); + this.column_++; + + // Process mid-row codes + } else if (this.isMidRowCode(char0, char1)) { + // Attributes are not additive, so clear all formatting + this.clearFormatting(packet.pts); + + // According to the standard, mid-row codes + // should be replaced with spaces, so add one now + this[this.mode_](packet.pts, ' '); + this.column_++; + + if ((char1 & 0xe) === 0xe) { + this.addFormatting(packet.pts, ['i']); + } + + if ((char1 & 0x1) === 0x1) { + this.addFormatting(packet.pts, ['u']); + } + + // Detect offset control codes and adjust cursor + } else if (this.isOffsetControlCode(char0, char1)) { + // Cursor position is set by indent PAC (see below) in 4-column + // increments, with an additional offset code of 1-3 to reach any + // of the 32 columns specified by CEA-608. So all we need to do + // here is increment the column cursor by the given offset. + this.column_ += char1 & 0x03; + + // Detect PACs (Preamble Address Codes) + } else if (this.isPAC(char0, char1)) { + + // There's no logic for PAC -> row mapping, so we have to just + // find the row code in an array and use its index :( + var row = ROWS.indexOf(data & 0x1f20); + + if (row !== this.row_) { + // formatting is only persistent for current row + this.clearFormatting(packet.pts); + this.row_ = row; + } + // All PACs can apply underline, so detect and apply + // (All odd-numbered second bytes set underline) + if (char1 & 0x1 && this.formatting_.indexOf('u') === -1) { + this.addFormatting(packet.pts, ['u']); + } + + if ((data & 0x10) === 0x10) { + // We've got an indent level code. Each successive even number + // increments the column cursor by 4, so we can get the desired + // column position by bit-shifting to the right (to get n/2) + // and multiplying by 4. + this.column_ = ((data & 0xe) >> 1) * 4; + } + + if (this.isColorPAC(char1)) { + // it's a color code, though we only support white, which + // can be either normal or italicized. white italics can be + // either 0x4e or 0x6e depending on the row, so we just + // bitwise-and with 0xe to see if italics should be turned on + if ((char1 & 0xe) === 0xe) { + this.addFormatting(packet.pts, ['i']); + } + } + + // We have a normal character in char0, and possibly one in char1 + } else if (this.isNormalChar(char0)) { + if (char1 === 0x00) { + char1 = null; + } + text = getCharFromCode(char0); + text += getCharFromCode(char1); + this[this.mode_](packet.pts, text); + this.column_ += text.length; + } // finish data processing + }; + }; + Cea608Stream.prototype = new stream(); + // Trigger a cue point that captures the current state of the + // display buffer + Cea608Stream.prototype.flushDisplayed = function (pts) { + var content = this.displayed_ + // remove spaces from the start and end of the string + .map(function (row) { + return row.trim(); + }) + // combine all text rows to display in one cue + .join('\n') + // and remove blank rows from the start and end, but not the middle + .replace(/^\n+|\n+$/g, ''); + + if (content.length) { + this.trigger('data', { + startPts: this.startPts_, + endPts: pts, + text: content, + stream: this.name_ + }); + } + }; + + /** + * Zero out the data, used for startup and on seek + */ + Cea608Stream.prototype.reset = function () { + this.mode_ = 'popOn'; + // When in roll-up mode, the index of the last row that will + // actually display captions. If a caption is shifted to a row + // with a lower index than this, it is cleared from the display + // buffer + this.topRow_ = 0; + this.startPts_ = 0; + this.displayed_ = createDisplayBuffer(); + this.nonDisplayed_ = createDisplayBuffer(); + this.lastControlCode_ = null; + + // Track row and column for proper line-breaking and spacing + this.column_ = 0; + this.row_ = BOTTOM_ROW; + + // This variable holds currently-applied formatting + this.formatting_ = []; + }; + + /** + * Sets up control code and related constants for this instance + */ + Cea608Stream.prototype.setConstants = function () { + // The following attributes have these uses: + // ext_ : char0 for mid-row codes, and the base for extended + // chars (ext_+0, ext_+1, and ext_+2 are char0s for + // extended codes) + // control_: char0 for control codes, except byte-shifted to the + // left so that we can do this.control_ | CONTROL_CODE + // offset_: char0 for tab offset codes + // + // It's also worth noting that control codes, and _only_ control codes, + // differ between field 1 and field2. Field 2 control codes are always + // their field 1 value plus 1. That's why there's the "| field" on the + // control value. + if (this.dataChannel_ === 0) { + this.BASE_ = 0x10; + this.EXT_ = 0x11; + this.CONTROL_ = (0x14 | this.field_) << 8; + this.OFFSET_ = 0x17; + } else if (this.dataChannel_ === 1) { + this.BASE_ = 0x18; + this.EXT_ = 0x19; + this.CONTROL_ = (0x1c | this.field_) << 8; + this.OFFSET_ = 0x1f; + } + + // Constants for the LSByte command codes recognized by Cea608Stream. This + // list is not exhaustive. For a more comprehensive listing and semantics see + // http://www.gpo.gov/fdsys/pkg/CFR-2010-title47-vol1/pdf/CFR-2010-title47-vol1-sec15-119.pdf + // Padding + this.PADDING_ = 0x0000; + // Pop-on Mode + this.RESUME_CAPTION_LOADING_ = this.CONTROL_ | 0x20; + this.END_OF_CAPTION_ = this.CONTROL_ | 0x2f; + // Roll-up Mode + this.ROLL_UP_2_ROWS_ = this.CONTROL_ | 0x25; + this.ROLL_UP_3_ROWS_ = this.CONTROL_ | 0x26; + this.ROLL_UP_4_ROWS_ = this.CONTROL_ | 0x27; + this.CARRIAGE_RETURN_ = this.CONTROL_ | 0x2d; + // paint-on mode (not supported) + this.RESUME_DIRECT_CAPTIONING_ = this.CONTROL_ | 0x29; + // Erasure + this.BACKSPACE_ = this.CONTROL_ | 0x21; + this.ERASE_DISPLAYED_MEMORY_ = this.CONTROL_ | 0x2c; + this.ERASE_NON_DISPLAYED_MEMORY_ = this.CONTROL_ | 0x2e; + }; + + /** + * Detects if the 2-byte packet data is a special character + * + * Special characters have a second byte in the range 0x30 to 0x3f, + * with the first byte being 0x11 (for data channel 1) or 0x19 (for + * data channel 2). + * + * @param {Integer} char0 The first byte + * @param {Integer} char1 The second byte + * @return {Boolean} Whether the 2 bytes are an special character + */ + Cea608Stream.prototype.isSpecialCharacter = function (char0, char1) { + return char0 === this.EXT_ && char1 >= 0x30 && char1 <= 0x3f; + }; + + /** + * Detects if the 2-byte packet data is an extended character + * + * Extended characters have a second byte in the range 0x20 to 0x3f, + * with the first byte being 0x12 or 0x13 (for data channel 1) or + * 0x1a or 0x1b (for data channel 2). + * + * @param {Integer} char0 The first byte + * @param {Integer} char1 The second byte + * @return {Boolean} Whether the 2 bytes are an extended character + */ + Cea608Stream.prototype.isExtCharacter = function (char0, char1) { + return (char0 === this.EXT_ + 1 || char0 === this.EXT_ + 2) && char1 >= 0x20 && char1 <= 0x3f; + }; + + /** + * Detects if the 2-byte packet is a mid-row code + * + * Mid-row codes have a second byte in the range 0x20 to 0x2f, with + * the first byte being 0x11 (for data channel 1) or 0x19 (for data + * channel 2). + * + * @param {Integer} char0 The first byte + * @param {Integer} char1 The second byte + * @return {Boolean} Whether the 2 bytes are a mid-row code + */ + Cea608Stream.prototype.isMidRowCode = function (char0, char1) { + return char0 === this.EXT_ && char1 >= 0x20 && char1 <= 0x2f; + }; + + /** + * Detects if the 2-byte packet is an offset control code + * + * Offset control codes have a second byte in the range 0x21 to 0x23, + * with the first byte being 0x17 (for data channel 1) or 0x1f (for + * data channel 2). + * + * @param {Integer} char0 The first byte + * @param {Integer} char1 The second byte + * @return {Boolean} Whether the 2 bytes are an offset control code + */ + Cea608Stream.prototype.isOffsetControlCode = function (char0, char1) { + return char0 === this.OFFSET_ && char1 >= 0x21 && char1 <= 0x23; + }; + + /** + * Detects if the 2-byte packet is a Preamble Address Code + * + * PACs have a first byte in the range 0x10 to 0x17 (for data channel 1) + * or 0x18 to 0x1f (for data channel 2), with the second byte in the + * range 0x40 to 0x7f. + * + * @param {Integer} char0 The first byte + * @param {Integer} char1 The second byte + * @return {Boolean} Whether the 2 bytes are a PAC + */ + Cea608Stream.prototype.isPAC = function (char0, char1) { + return char0 >= this.BASE_ && char0 < this.BASE_ + 8 && char1 >= 0x40 && char1 <= 0x7f; + }; + + /** + * Detects if a packet's second byte is in the range of a PAC color code + * + * PAC color codes have the second byte be in the range 0x40 to 0x4f, or + * 0x60 to 0x6f. + * + * @param {Integer} char1 The second byte + * @return {Boolean} Whether the byte is a color PAC + */ + Cea608Stream.prototype.isColorPAC = function (char1) { + return char1 >= 0x40 && char1 <= 0x4f || char1 >= 0x60 && char1 <= 0x7f; + }; + + /** + * Detects if a single byte is in the range of a normal character + * + * Normal text bytes are in the range 0x20 to 0x7f. + * + * @param {Integer} char The byte + * @return {Boolean} Whether the byte is a normal character + */ + Cea608Stream.prototype.isNormalChar = function (char) { + return char >= 0x20 && char <= 0x7f; + }; + + // Adds the opening HTML tag for the passed character to the caption text, + // and keeps track of it for later closing + Cea608Stream.prototype.addFormatting = function (pts, format) { + this.formatting_ = this.formatting_.concat(format); + var text = format.reduce(function (text, format) { + return text + '<' + format + '>'; + }, ''); + this[this.mode_](pts, text); + }; + + // Adds HTML closing tags for current formatting to caption text and + // clears remembered formatting + Cea608Stream.prototype.clearFormatting = function (pts) { + if (!this.formatting_.length) { + return; + } + var text = this.formatting_.reverse().reduce(function (text, format) { + return text + '</' + format + '>'; + }, ''); + this.formatting_ = []; + this[this.mode_](pts, text); + }; + + // Mode Implementations + Cea608Stream.prototype.popOn = function (pts, text) { + var baseRow = this.nonDisplayed_[this.row_]; + + // buffer characters + baseRow += text; + this.nonDisplayed_[this.row_] = baseRow; + }; + + Cea608Stream.prototype.rollUp = function (pts, text) { + var baseRow = this.displayed_[BOTTOM_ROW]; + + baseRow += text; + this.displayed_[BOTTOM_ROW] = baseRow; + }; + + Cea608Stream.prototype.shiftRowsUp_ = function () { + var i; + // clear out inactive rows + for (i = 0; i < this.topRow_; i++) { + this.displayed_[i] = ''; + } + // shift displayed rows up + for (i = this.topRow_; i < BOTTOM_ROW; i++) { + this.displayed_[i] = this.displayed_[i + 1]; + } + // clear out the bottom row + this.displayed_[BOTTOM_ROW] = ''; + }; + + // paintOn mode is not implemented + Cea608Stream.prototype.paintOn = function () { + }; + + // exports + var captionStream = { + CaptionStream: CaptionStream, + Cea608Stream: Cea608Stream + }; + + var streamTypes = { + H264_STREAM_TYPE: 0x1B, + ADTS_STREAM_TYPE: 0x0F, + METADATA_STREAM_TYPE: 0x15 + }; + + var MAX_TS = 8589934592; + + var RO_THRESH = 4294967296; + + var handleRollover = function handleRollover(value, reference) { + var direction = 1; + + if (value > reference) { + // If the current timestamp value is greater than our reference timestamp and we detect a + // timestamp rollover, this means the roll over is happening in the opposite direction. + // Example scenario: Enter a long stream/video just after a rollover occurred. The reference + // point will be set to a small number, e.g. 1. The user then seeks backwards over the + // rollover point. In loading this segment, the timestamp values will be very large, + // e.g. 2^33 - 1. Since this comes before the data we loaded previously, we want to adjust + // the time stamp to be `value - 2^33`. + direction = -1; + } + + // Note: A seek forwards or back that is greater than the RO_THRESH (2^32, ~13 hours) will + // cause an incorrect adjustment. + while (Math.abs(reference - value) > RO_THRESH) { + value += direction * MAX_TS; + } + + return value; + }; + + var TimestampRolloverStream = function TimestampRolloverStream(type) { + var lastDTS, referenceDTS; + + TimestampRolloverStream.prototype.init.call(this); + + this.type_ = type; + + this.push = function (data) { + if (data.type !== this.type_) { + return; + } + + if (referenceDTS === undefined) { + referenceDTS = data.dts; + } + + data.dts = handleRollover(data.dts, referenceDTS); + data.pts = handleRollover(data.pts, referenceDTS); + + lastDTS = data.dts; + + this.trigger('data', data); + }; + + this.flush = function () { + referenceDTS = lastDTS; + this.trigger('done'); + }; + + this.discontinuity = function () { + referenceDTS = void 0; + lastDTS = void 0; + }; + }; + + TimestampRolloverStream.prototype = new stream(); + + var timestampRolloverStream = { + TimestampRolloverStream: TimestampRolloverStream, + handleRollover: handleRollover + }; + + var percentEncode = function percentEncode(bytes, start, end) { + var i, + result = ''; + for (i = start; i < end; i++) { + result += '%' + ('00' + bytes[i].toString(16)).slice(-2); + } + return result; + }, + + + // return the string representation of the specified byte range, + // interpreted as UTf-8. + parseUtf8 = function parseUtf8(bytes, start, end) { + return decodeURIComponent(percentEncode(bytes, start, end)); + }, + + + // return the string representation of the specified byte range, + // interpreted as ISO-8859-1. + parseIso88591 = function parseIso88591(bytes, start, end) { + return unescape(percentEncode(bytes, start, end)); // jshint ignore:line + }, + parseSyncSafeInteger = function parseSyncSafeInteger(data) { + return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3]; + }, + tagParsers = { + TXXX: function TXXX(tag) { + var i; + if (tag.data[0] !== 3) { + // ignore frames with unrecognized character encodings + return; + } + + for (i = 1; i < tag.data.length; i++) { + if (tag.data[i] === 0) { + // parse the text fields + tag.description = parseUtf8(tag.data, 1, i); + // do not include the null terminator in the tag value + tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, ''); + break; + } + } + tag.data = tag.value; + }, + WXXX: function WXXX(tag) { + var i; + if (tag.data[0] !== 3) { + // ignore frames with unrecognized character encodings + return; + } + + for (i = 1; i < tag.data.length; i++) { + if (tag.data[i] === 0) { + // parse the description and URL fields + tag.description = parseUtf8(tag.data, 1, i); + tag.url = parseUtf8(tag.data, i + 1, tag.data.length); + break; + } + } + }, + PRIV: function PRIV(tag) { + var i; + + for (i = 0; i < tag.data.length; i++) { + if (tag.data[i] === 0) { + // parse the description and URL fields + tag.owner = parseIso88591(tag.data, 0, i); + break; + } + } + tag.privateData = tag.data.subarray(i + 1); + tag.data = tag.privateData; + } + }, + _MetadataStream; + + _MetadataStream = function MetadataStream(options) { + var settings = { + debug: !!(options && options.debug), + + // the bytes of the program-level descriptor field in MP2T + // see ISO/IEC 13818-1:2013 (E), section 2.6 "Program and + // program element descriptors" + descriptor: options && options.descriptor + }, + + + // the total size in bytes of the ID3 tag being parsed + tagSize = 0, + + + // tag data that is not complete enough to be parsed + buffer = [], + + + // the total number of bytes currently in the buffer + bufferSize = 0, + i; + + _MetadataStream.prototype.init.call(this); + + // calculate the text track in-band metadata track dispatch type + // https://html.spec.whatwg.org/multipage/embedded-content.html#steps-to-expose-a-media-resource-specific-text-track + this.dispatchType = streamTypes.METADATA_STREAM_TYPE.toString(16); + if (settings.descriptor) { + for (i = 0; i < settings.descriptor.length; i++) { + this.dispatchType += ('00' + settings.descriptor[i].toString(16)).slice(-2); + } + } + + this.push = function (chunk) { + var tag, frameStart, frameSize, frame, i, frameHeader; + if (chunk.type !== 'timed-metadata') { + return; + } + + // if data_alignment_indicator is set in the PES header, + // we must have the start of a new ID3 tag. Assume anything + // remaining in the buffer was malformed and throw it out + if (chunk.dataAlignmentIndicator) { + bufferSize = 0; + buffer.length = 0; + } + + // ignore events that don't look like ID3 data + if (buffer.length === 0 && (chunk.data.length < 10 || chunk.data[0] !== 'I'.charCodeAt(0) || chunk.data[1] !== 'D'.charCodeAt(0) || chunk.data[2] !== '3'.charCodeAt(0))) { + if (settings.debug) { + // eslint-disable-next-line no-console + console.log('Skipping unrecognized metadata packet'); + } + return; + } + + // add this chunk to the data we've collected so far + + buffer.push(chunk); + bufferSize += chunk.data.byteLength; + + // grab the size of the entire frame from the ID3 header + if (buffer.length === 1) { + // the frame size is transmitted as a 28-bit integer in the + // last four bytes of the ID3 header. + // The most significant bit of each byte is dropped and the + // results concatenated to recover the actual value. + tagSize = parseSyncSafeInteger(chunk.data.subarray(6, 10)); + + // ID3 reports the tag size excluding the header but it's more + // convenient for our comparisons to include it + tagSize += 10; + } + + // if the entire frame has not arrived, wait for more data + if (bufferSize < tagSize) { + return; + } + + // collect the entire frame so it can be parsed + tag = { + data: new Uint8Array(tagSize), + frames: [], + pts: buffer[0].pts, + dts: buffer[0].dts + }; + for (i = 0; i < tagSize;) { + tag.data.set(buffer[0].data.subarray(0, tagSize - i), i); + i += buffer[0].data.byteLength; + bufferSize -= buffer[0].data.byteLength; + buffer.shift(); + } + + // find the start of the first frame and the end of the tag + frameStart = 10; + if (tag.data[5] & 0x40) { + // advance the frame start past the extended header + frameStart += 4; // header size field + frameStart += parseSyncSafeInteger(tag.data.subarray(10, 14)); + + // clip any padding off the end + tagSize -= parseSyncSafeInteger(tag.data.subarray(16, 20)); + } + + // parse one or more ID3 frames + // http://id3.org/id3v2.3.0#ID3v2_frame_overview + do { + // determine the number of bytes in this frame + frameSize = parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8)); + if (frameSize < 1) { + // eslint-disable-next-line no-console + return console.log('Malformed ID3 frame encountered. Skipping metadata parsing.'); + } + frameHeader = String.fromCharCode(tag.data[frameStart], tag.data[frameStart + 1], tag.data[frameStart + 2], tag.data[frameStart + 3]); + + frame = { + id: frameHeader, + data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10) + }; + frame.key = frame.id; + if (tagParsers[frame.id]) { + tagParsers[frame.id](frame); + + // handle the special PRIV frame used to indicate the start + // time for raw AAC data + if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') { + var d = frame.data, + size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2; + + size *= 4; + size += d[7] & 0x03; + frame.timeStamp = size; + // in raw AAC, all subsequent data will be timestamped based + // on the value of this frame + // we couldn't have known the appropriate pts and dts before + // parsing this ID3 tag so set those values now + if (tag.pts === undefined && tag.dts === undefined) { + tag.pts = frame.timeStamp; + tag.dts = frame.timeStamp; + } + this.trigger('timestamp', frame); + } + } + tag.frames.push(frame); + + frameStart += 10; // advance past the frame header + frameStart += frameSize; // advance past the frame body + } while (frameStart < tagSize); + this.trigger('data', tag); + }; + }; + _MetadataStream.prototype = new stream(); + + var metadataStream = _MetadataStream; + + var TimestampRolloverStream$1 = timestampRolloverStream.TimestampRolloverStream; + + // object types + var _TransportPacketStream, _TransportParseStream, _ElementaryStream; + + // constants + var MP2T_PACKET_LENGTH = 188, + + // bytes + SYNC_BYTE = 0x47; + + /** + * Splits an incoming stream of binary data into MPEG-2 Transport + * Stream packets. + */ + _TransportPacketStream = function TransportPacketStream() { + var buffer = new Uint8Array(MP2T_PACKET_LENGTH), + bytesInBuffer = 0; + + _TransportPacketStream.prototype.init.call(this); + + // Deliver new bytes to the stream. + + this.push = function (bytes) { + var startIndex = 0, + endIndex = MP2T_PACKET_LENGTH, + everything; + + // If there are bytes remaining from the last segment, prepend them to the + // bytes that were pushed in + if (bytesInBuffer) { + everything = new Uint8Array(bytes.byteLength + bytesInBuffer); + everything.set(buffer.subarray(0, bytesInBuffer)); + everything.set(bytes, bytesInBuffer); + bytesInBuffer = 0; + } else { + everything = bytes; + } + + // While we have enough data for a packet + while (endIndex < everything.byteLength) { + // Look for a pair of start and end sync bytes in the data.. + if (everything[startIndex] === SYNC_BYTE && everything[endIndex] === SYNC_BYTE) { + // We found a packet so emit it and jump one whole packet forward in + // the stream + this.trigger('data', everything.subarray(startIndex, endIndex)); + startIndex += MP2T_PACKET_LENGTH; + endIndex += MP2T_PACKET_LENGTH; + continue; + } + // If we get here, we have somehow become de-synchronized and we need to step + // forward one byte at a time until we find a pair of sync bytes that denote + // a packet + startIndex++; + endIndex++; + } + + // If there was some data left over at the end of the segment that couldn't + // possibly be a whole packet, keep it because it might be the start of a packet + // that continues in the next segment + if (startIndex < everything.byteLength) { + buffer.set(everything.subarray(startIndex), 0); + bytesInBuffer = everything.byteLength - startIndex; + } + }; + + this.flush = function () { + // If the buffer contains a whole packet when we are being flushed, emit it + // and empty the buffer. Otherwise hold onto the data because it may be + // important for decoding the next segment + if (bytesInBuffer === MP2T_PACKET_LENGTH && buffer[0] === SYNC_BYTE) { + this.trigger('data', buffer); + bytesInBuffer = 0; + } + this.trigger('done'); + }; + }; + _TransportPacketStream.prototype = new stream(); + + /** + * Accepts an MP2T TransportPacketStream and emits data events with parsed + * forms of the individual transport stream packets. + */ + _TransportParseStream = function TransportParseStream() { + var parsePsi, parsePat, parsePmt, self; + _TransportParseStream.prototype.init.call(this); + self = this; + + this.packetsWaitingForPmt = []; + this.programMapTable = undefined; + + parsePsi = function parsePsi(payload, psi) { + var offset = 0; + + // PSI packets may be split into multiple sections and those + // sections may be split into multiple packets. If a PSI + // section starts in this packet, the payload_unit_start_indicator + // will be true and the first byte of the payload will indicate + // the offset from the current position to the start of the + // section. + if (psi.payloadUnitStartIndicator) { + offset += payload[offset] + 1; + } + + if (psi.type === 'pat') { + parsePat(payload.subarray(offset), psi); + } else { + parsePmt(payload.subarray(offset), psi); + } + }; + + parsePat = function parsePat(payload, pat) { + pat.section_number = payload[7]; // eslint-disable-line camelcase + pat.last_section_number = payload[8]; // eslint-disable-line camelcase + + // skip the PSI header and parse the first PMT entry + self.pmtPid = (payload[10] & 0x1F) << 8 | payload[11]; + pat.pmtPid = self.pmtPid; + }; + + /** + * Parse out the relevant fields of a Program Map Table (PMT). + * @param payload {Uint8Array} the PMT-specific portion of an MP2T + * packet. The first byte in this array should be the table_id + * field. + * @param pmt {object} the object that should be decorated with + * fields parsed from the PMT. + */ + parsePmt = function parsePmt(payload, pmt) { + var sectionLength, tableEnd, programInfoLength, offset; + + // PMTs can be sent ahead of the time when they should actually + // take effect. We don't believe this should ever be the case + // for HLS but we'll ignore "forward" PMT declarations if we see + // them. Future PMT declarations have the current_next_indicator + // set to zero. + if (!(payload[5] & 0x01)) { + return; + } + + // overwrite any existing program map table + self.programMapTable = { + video: null, + audio: null, + 'timed-metadata': {} + }; + + // the mapping table ends at the end of the current section + sectionLength = (payload[1] & 0x0f) << 8 | payload[2]; + tableEnd = 3 + sectionLength - 4; + + // to determine where the table is, we have to figure out how + // long the program info descriptors are + programInfoLength = (payload[10] & 0x0f) << 8 | payload[11]; + + // advance the offset to the first entry in the mapping table + offset = 12 + programInfoLength; + while (offset < tableEnd) { + var streamType = payload[offset]; + var pid = (payload[offset + 1] & 0x1F) << 8 | payload[offset + 2]; + + // only map a single elementary_pid for audio and video stream types + // TODO: should this be done for metadata too? for now maintain behavior of + // multiple metadata streams + if (streamType === streamTypes.H264_STREAM_TYPE && self.programMapTable.video === null) { + self.programMapTable.video = pid; + } else if (streamType === streamTypes.ADTS_STREAM_TYPE && self.programMapTable.audio === null) { + self.programMapTable.audio = pid; + } else if (streamType === streamTypes.METADATA_STREAM_TYPE) { + // map pid to stream type for metadata streams + self.programMapTable['timed-metadata'][pid] = streamType; + } + + // move to the next table entry + // skip past the elementary stream descriptors, if present + offset += ((payload[offset + 3] & 0x0F) << 8 | payload[offset + 4]) + 5; + } + + // record the map on the packet as well + pmt.programMapTable = self.programMapTable; + }; + + /** + * Deliver a new MP2T packet to the stream. + */ + this.push = function (packet) { + var result = {}, + offset = 4; + + result.payloadUnitStartIndicator = !!(packet[1] & 0x40); + + // pid is a 13-bit field starting at the last bit of packet[1] + result.pid = packet[1] & 0x1f; + result.pid <<= 8; + result.pid |= packet[2]; + + // if an adaption field is present, its length is specified by the + // fifth byte of the TS packet header. The adaptation field is + // used to add stuffing to PES packets that don't fill a complete + // TS packet, and to specify some forms of timing and control data + // that we do not currently use. + if ((packet[3] & 0x30) >>> 4 > 0x01) { + offset += packet[offset] + 1; + } + + // parse the rest of the packet based on the type + if (result.pid === 0) { + result.type = 'pat'; + parsePsi(packet.subarray(offset), result); + this.trigger('data', result); + } else if (result.pid === this.pmtPid) { + result.type = 'pmt'; + parsePsi(packet.subarray(offset), result); + this.trigger('data', result); + + // if there are any packets waiting for a PMT to be found, process them now + while (this.packetsWaitingForPmt.length) { + this.processPes_.apply(this, this.packetsWaitingForPmt.shift()); + } + } else if (this.programMapTable === undefined) { + // When we have not seen a PMT yet, defer further processing of + // PES packets until one has been parsed + this.packetsWaitingForPmt.push([packet, offset, result]); + } else { + this.processPes_(packet, offset, result); + } + }; + + this.processPes_ = function (packet, offset, result) { + // set the appropriate stream type + if (result.pid === this.programMapTable.video) { + result.streamType = streamTypes.H264_STREAM_TYPE; + } else if (result.pid === this.programMapTable.audio) { + result.streamType = streamTypes.ADTS_STREAM_TYPE; + } else { + // if not video or audio, it is timed-metadata or unknown + // if unknown, streamType will be undefined + result.streamType = this.programMapTable['timed-metadata'][result.pid]; + } + + result.type = 'pes'; + result.data = packet.subarray(offset); + + this.trigger('data', result); + }; + }; + _TransportParseStream.prototype = new stream(); + _TransportParseStream.STREAM_TYPES = { + h264: 0x1b, + adts: 0x0f + }; + + /** + * Reconsistutes program elementary stream (PES) packets from parsed + * transport stream packets. That is, if you pipe an + * mp2t.TransportParseStream into a mp2t.ElementaryStream, the output + * events will be events which capture the bytes for individual PES + * packets plus relevant metadata that has been extracted from the + * container. + */ + _ElementaryStream = function ElementaryStream() { + var self = this, + + + // PES packet fragments + video = { + data: [], + size: 0 + }, + audio = { + data: [], + size: 0 + }, + timedMetadata = { + data: [], + size: 0 + }, + parsePes = function parsePes(payload, pes) { + var ptsDtsFlags; + + // get the packet length, this will be 0 for video + pes.packetLength = 6 + (payload[4] << 8 | payload[5]); + + // find out if this packets starts a new keyframe + pes.dataAlignmentIndicator = (payload[6] & 0x04) !== 0; + // PES packets may be annotated with a PTS value, or a PTS value + // and a DTS value. Determine what combination of values is + // available to work with. + ptsDtsFlags = payload[7]; + + // PTS and DTS are normally stored as a 33-bit number. Javascript + // performs all bitwise operations on 32-bit integers but javascript + // supports a much greater range (52-bits) of integer using standard + // mathematical operations. + // We construct a 31-bit value using bitwise operators over the 31 + // most significant bits and then multiply by 4 (equal to a left-shift + // of 2) before we add the final 2 least significant bits of the + // timestamp (equal to an OR.) + if (ptsDtsFlags & 0xC0) { + // the PTS and DTS are not written out directly. For information + // on how they are encoded, see + // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html + pes.pts = (payload[9] & 0x0E) << 27 | (payload[10] & 0xFF) << 20 | (payload[11] & 0xFE) << 12 | (payload[12] & 0xFF) << 5 | (payload[13] & 0xFE) >>> 3; + pes.pts *= 4; // Left shift by 2 + pes.pts += (payload[13] & 0x06) >>> 1; // OR by the two LSBs + pes.dts = pes.pts; + if (ptsDtsFlags & 0x40) { + pes.dts = (payload[14] & 0x0E) << 27 | (payload[15] & 0xFF) << 20 | (payload[16] & 0xFE) << 12 | (payload[17] & 0xFF) << 5 | (payload[18] & 0xFE) >>> 3; + pes.dts *= 4; // Left shift by 2 + pes.dts += (payload[18] & 0x06) >>> 1; // OR by the two LSBs + } + } + // the data section starts immediately after the PES header. + // pes_header_data_length specifies the number of header bytes + // that follow the last byte of the field. + pes.data = payload.subarray(9 + payload[8]); + }, + flushStream = function flushStream(stream$$1, type, forceFlush) { + var packetData = new Uint8Array(stream$$1.size), + event = { + type: type + }, + i = 0, + offset = 0, + packetFlushable = false, + fragment; + + // do nothing if there is not enough buffered data for a complete + // PES header + if (!stream$$1.data.length || stream$$1.size < 9) { + return; + } + event.trackId = stream$$1.data[0].pid; + + // reassemble the packet + for (i = 0; i < stream$$1.data.length; i++) { + fragment = stream$$1.data[i]; + + packetData.set(fragment.data, offset); + offset += fragment.data.byteLength; + } + + // parse assembled packet's PES header + parsePes(packetData, event); + + // non-video PES packets MUST have a non-zero PES_packet_length + // check that there is enough stream data to fill the packet + packetFlushable = type === 'video' || event.packetLength <= stream$$1.size; + + // flush pending packets if the conditions are right + if (forceFlush || packetFlushable) { + stream$$1.size = 0; + stream$$1.data.length = 0; + } + + // only emit packets that are complete. this is to avoid assembling + // incomplete PES packets due to poor segmentation + if (packetFlushable) { + self.trigger('data', event); + } + }; + + _ElementaryStream.prototype.init.call(this); + + this.push = function (data) { + ({ + pat: function pat() { + // we have to wait for the PMT to arrive as well before we + // have any meaningful metadata + }, + pes: function pes() { + var stream$$1, streamType; + + switch (data.streamType) { + case streamTypes.H264_STREAM_TYPE: + case streamTypes.H264_STREAM_TYPE: + stream$$1 = video; + streamType = 'video'; + break; + case streamTypes.ADTS_STREAM_TYPE: + stream$$1 = audio; + streamType = 'audio'; + break; + case streamTypes.METADATA_STREAM_TYPE: + stream$$1 = timedMetadata; + streamType = 'timed-metadata'; + break; + default: + // ignore unknown stream types + return; + } + + // if a new packet is starting, we can flush the completed + // packet + if (data.payloadUnitStartIndicator) { + flushStream(stream$$1, streamType, true); + } + + // buffer this fragment until we are sure we've received the + // complete payload + stream$$1.data.push(data); + stream$$1.size += data.data.byteLength; + }, + pmt: function pmt() { + var event = { + type: 'metadata', + tracks: [] + }, + programMapTable = data.programMapTable; + + // translate audio and video streams to tracks + if (programMapTable.video !== null) { + event.tracks.push({ + timelineStartInfo: { + baseMediaDecodeTime: 0 + }, + id: +programMapTable.video, + codec: 'avc', + type: 'video' + }); + } + if (programMapTable.audio !== null) { + event.tracks.push({ + timelineStartInfo: { + baseMediaDecodeTime: 0 + }, + id: +programMapTable.audio, + codec: 'adts', + type: 'audio' + }); + } + + self.trigger('data', event); + } + })[data.type](); + }; + + /** + * Flush any remaining input. Video PES packets may be of variable + * length. Normally, the start of a new video packet can trigger the + * finalization of the previous packet. That is not possible if no + * more video is forthcoming, however. In that case, some other + * mechanism (like the end of the file) has to be employed. When it is + * clear that no additional data is forthcoming, calling this method + * will flush the buffered packets. + */ + this.flush = function () { + // !!THIS ORDER IS IMPORTANT!! + // video first then audio + flushStream(video, 'video'); + flushStream(audio, 'audio'); + flushStream(timedMetadata, 'timed-metadata'); + this.trigger('done'); + }; + }; + _ElementaryStream.prototype = new stream(); + + var m2ts = { + PAT_PID: 0x0000, + MP2T_PACKET_LENGTH: MP2T_PACKET_LENGTH, + TransportPacketStream: _TransportPacketStream, + TransportParseStream: _TransportParseStream, + ElementaryStream: _ElementaryStream, + TimestampRolloverStream: TimestampRolloverStream$1, + CaptionStream: captionStream.CaptionStream, + Cea608Stream: captionStream.Cea608Stream, + MetadataStream: metadataStream + }; + + for (var type in streamTypes) { + if (streamTypes.hasOwnProperty(type)) { + m2ts[type] = streamTypes[type]; + } + } + + var m2ts_1 = m2ts; + + var _AdtsStream; + + var ADTS_SAMPLING_FREQUENCIES = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350]; + + /* + * Accepts a ElementaryStream and emits data events with parsed + * AAC Audio Frames of the individual packets. Input audio in ADTS + * format is unpacked and re-emitted as AAC frames. + * + * @see http://wiki.multimedia.cx/index.php?title=ADTS + * @see http://wiki.multimedia.cx/?title=Understanding_AAC + */ + _AdtsStream = function AdtsStream() { + var buffer; + + _AdtsStream.prototype.init.call(this); + + this.push = function (packet) { + var i = 0, + frameNum = 0, + frameLength, + protectionSkipBytes, + frameEnd, + oldBuffer, + sampleCount, + adtsFrameDuration; + + if (packet.type !== 'audio') { + // ignore non-audio data + return; + } + + // Prepend any data in the buffer to the input data so that we can parse + // aac frames the cross a PES packet boundary + if (buffer) { + oldBuffer = buffer; + buffer = new Uint8Array(oldBuffer.byteLength + packet.data.byteLength); + buffer.set(oldBuffer); + buffer.set(packet.data, oldBuffer.byteLength); + } else { + buffer = packet.data; + } + + // unpack any ADTS frames which have been fully received + // for details on the ADTS header, see http://wiki.multimedia.cx/index.php?title=ADTS + while (i + 5 < buffer.length) { + + // Loook for the start of an ADTS header.. + if (buffer[i] !== 0xFF || (buffer[i + 1] & 0xF6) !== 0xF0) { + // If a valid header was not found, jump one forward and attempt to + // find a valid ADTS header starting at the next byte + i++; + continue; + } + + // The protection skip bit tells us if we have 2 bytes of CRC data at the + // end of the ADTS header + protectionSkipBytes = (~buffer[i + 1] & 0x01) * 2; + + // Frame length is a 13 bit integer starting 16 bits from the + // end of the sync sequence + frameLength = (buffer[i + 3] & 0x03) << 11 | buffer[i + 4] << 3 | (buffer[i + 5] & 0xe0) >> 5; + + sampleCount = ((buffer[i + 6] & 0x03) + 1) * 1024; + adtsFrameDuration = sampleCount * 90000 / ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2]; + + frameEnd = i + frameLength; + + // If we don't have enough data to actually finish this ADTS frame, return + // and wait for more data + if (buffer.byteLength < frameEnd) { + return; + } + + // Otherwise, deliver the complete AAC frame + this.trigger('data', { + pts: packet.pts + frameNum * adtsFrameDuration, + dts: packet.dts + frameNum * adtsFrameDuration, + sampleCount: sampleCount, + audioobjecttype: (buffer[i + 2] >>> 6 & 0x03) + 1, + channelcount: (buffer[i + 2] & 1) << 2 | (buffer[i + 3] & 0xc0) >>> 6, + samplerate: ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2], + samplingfrequencyindex: (buffer[i + 2] & 0x3c) >>> 2, + // assume ISO/IEC 14496-12 AudioSampleEntry default of 16 + samplesize: 16, + data: buffer.subarray(i + 7 + protectionSkipBytes, frameEnd) + }); + + // If the buffer is empty, clear it and return + if (buffer.byteLength === frameEnd) { + buffer = undefined; + return; + } + + frameNum++; + + // Remove the finished frame from the buffer and start the process again + buffer = buffer.subarray(frameEnd); + } + }; + this.flush = function () { + this.trigger('done'); + }; + }; + + _AdtsStream.prototype = new stream(); + + var adts = _AdtsStream; + + var ExpGolomb; + + /** + * Parser for exponential Golomb codes, a variable-bitwidth number encoding + * scheme used by h264. + */ + ExpGolomb = function ExpGolomb(workingData) { + var + // the number of bytes left to examine in workingData + workingBytesAvailable = workingData.byteLength, + + + // the current word being examined + workingWord = 0, + + // :uint + + // the number of bits left to examine in the current word + workingBitsAvailable = 0; // :uint; + + // ():uint + this.length = function () { + return 8 * workingBytesAvailable; + }; + + // ():uint + this.bitsAvailable = function () { + return 8 * workingBytesAvailable + workingBitsAvailable; + }; + + // ():void + this.loadWord = function () { + var position = workingData.byteLength - workingBytesAvailable, + workingBytes = new Uint8Array(4), + availableBytes = Math.min(4, workingBytesAvailable); + + if (availableBytes === 0) { + throw new Error('no bytes available'); + } + + workingBytes.set(workingData.subarray(position, position + availableBytes)); + workingWord = new DataView(workingBytes.buffer).getUint32(0); + + // track the amount of workingData that has been processed + workingBitsAvailable = availableBytes * 8; + workingBytesAvailable -= availableBytes; + }; + + // (count:int):void + this.skipBits = function (count) { + var skipBytes; // :int + if (workingBitsAvailable > count) { + workingWord <<= count; + workingBitsAvailable -= count; + } else { + count -= workingBitsAvailable; + skipBytes = Math.floor(count / 8); + + count -= skipBytes * 8; + workingBytesAvailable -= skipBytes; + + this.loadWord(); + + workingWord <<= count; + workingBitsAvailable -= count; + } + }; + + // (size:int):uint + this.readBits = function (size) { + var bits = Math.min(workingBitsAvailable, size), + + // :uint + valu = workingWord >>> 32 - bits; // :uint + // if size > 31, handle error + workingBitsAvailable -= bits; + if (workingBitsAvailable > 0) { + workingWord <<= bits; + } else if (workingBytesAvailable > 0) { + this.loadWord(); + } + + bits = size - bits; + if (bits > 0) { + return valu << bits | this.readBits(bits); + } + return valu; + }; + + // ():uint + this.skipLeadingZeros = function () { + var leadingZeroCount; // :uint + for (leadingZeroCount = 0; leadingZeroCount < workingBitsAvailable; ++leadingZeroCount) { + if ((workingWord & 0x80000000 >>> leadingZeroCount) !== 0) { + // the first bit of working word is 1 + workingWord <<= leadingZeroCount; + workingBitsAvailable -= leadingZeroCount; + return leadingZeroCount; + } + } + + // we exhausted workingWord and still have not found a 1 + this.loadWord(); + return leadingZeroCount + this.skipLeadingZeros(); + }; + + // ():void + this.skipUnsignedExpGolomb = function () { + this.skipBits(1 + this.skipLeadingZeros()); + }; + + // ():void + this.skipExpGolomb = function () { + this.skipBits(1 + this.skipLeadingZeros()); + }; + + // ():uint + this.readUnsignedExpGolomb = function () { + var clz = this.skipLeadingZeros(); // :uint + return this.readBits(clz + 1) - 1; + }; + + // ():int + this.readExpGolomb = function () { + var valu = this.readUnsignedExpGolomb(); // :int + if (0x01 & valu) { + // the number is odd if the low order bit is set + return 1 + valu >>> 1; // add 1 to make it even, and divide by 2 + } + return -1 * (valu >>> 1); // divide by two then make it negative + }; + + // Some convenience functions + // :Boolean + this.readBoolean = function () { + return this.readBits(1) === 1; + }; + + // ():int + this.readUnsignedByte = function () { + return this.readBits(8); + }; + + this.loadWord(); + }; + + var expGolomb = ExpGolomb; + + var _H264Stream, _NalByteStream; + var PROFILES_WITH_OPTIONAL_SPS_DATA; + + /** + * Accepts a NAL unit byte stream and unpacks the embedded NAL units. + */ + _NalByteStream = function NalByteStream() { + var syncPoint = 0, + i, + buffer; + _NalByteStream.prototype.init.call(this); + + this.push = function (data) { + var swapBuffer; + + if (!buffer) { + buffer = data.data; + } else { + swapBuffer = new Uint8Array(buffer.byteLength + data.data.byteLength); + swapBuffer.set(buffer); + swapBuffer.set(data.data, buffer.byteLength); + buffer = swapBuffer; + } + + // Rec. ITU-T H.264, Annex B + // scan for NAL unit boundaries + + // a match looks like this: + // 0 0 1 .. NAL .. 0 0 1 + // ^ sync point ^ i + // or this: + // 0 0 1 .. NAL .. 0 0 0 + // ^ sync point ^ i + + // advance the sync point to a NAL start, if necessary + for (; syncPoint < buffer.byteLength - 3; syncPoint++) { + if (buffer[syncPoint + 2] === 1) { + // the sync point is properly aligned + i = syncPoint + 5; + break; + } + } + + while (i < buffer.byteLength) { + // look at the current byte to determine if we've hit the end of + // a NAL unit boundary + switch (buffer[i]) { + case 0: + // skip past non-sync sequences + if (buffer[i - 1] !== 0) { + i += 2; + break; + } else if (buffer[i - 2] !== 0) { + i++; + break; + } + + // deliver the NAL unit if it isn't empty + if (syncPoint + 3 !== i - 2) { + this.trigger('data', buffer.subarray(syncPoint + 3, i - 2)); + } + + // drop trailing zeroes + do { + i++; + } while (buffer[i] !== 1 && i < buffer.length); + syncPoint = i - 2; + i += 3; + break; + case 1: + // skip past non-sync sequences + if (buffer[i - 1] !== 0 || buffer[i - 2] !== 0) { + i += 3; + break; + } + + // deliver the NAL unit + this.trigger('data', buffer.subarray(syncPoint + 3, i - 2)); + syncPoint = i - 2; + i += 3; + break; + default: + // the current byte isn't a one or zero, so it cannot be part + // of a sync sequence + i += 3; + break; + } + } + // filter out the NAL units that were delivered + buffer = buffer.subarray(syncPoint); + i -= syncPoint; + syncPoint = 0; + }; + + this.flush = function () { + // deliver the last buffered NAL unit + if (buffer && buffer.byteLength > 3) { + this.trigger('data', buffer.subarray(syncPoint + 3)); + } + // reset the stream state + buffer = null; + syncPoint = 0; + this.trigger('done'); + }; + }; + _NalByteStream.prototype = new stream(); + + // values of profile_idc that indicate additional fields are included in the SPS + // see Recommendation ITU-T H.264 (4/2013), + // 7.3.2.1.1 Sequence parameter set data syntax + PROFILES_WITH_OPTIONAL_SPS_DATA = { + 100: true, + 110: true, + 122: true, + 244: true, + 44: true, + 83: true, + 86: true, + 118: true, + 128: true, + 138: true, + 139: true, + 134: true + }; + + /** + * Accepts input from a ElementaryStream and produces H.264 NAL unit data + * events. + */ + _H264Stream = function H264Stream() { + var nalByteStream = new _NalByteStream(), + self, + trackId, + currentPts, + currentDts, + discardEmulationPreventionBytes, + readSequenceParameterSet, + skipScalingList; + + _H264Stream.prototype.init.call(this); + self = this; + + this.push = function (packet) { + if (packet.type !== 'video') { + return; + } + trackId = packet.trackId; + currentPts = packet.pts; + currentDts = packet.dts; + + nalByteStream.push(packet); + }; + + nalByteStream.on('data', function (data) { + var event = { + trackId: trackId, + pts: currentPts, + dts: currentDts, + data: data + }; + + switch (data[0] & 0x1f) { + case 0x05: + event.nalUnitType = 'slice_layer_without_partitioning_rbsp_idr'; + break; + case 0x06: + event.nalUnitType = 'sei_rbsp'; + event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1)); + break; + case 0x07: + event.nalUnitType = 'seq_parameter_set_rbsp'; + event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1)); + event.config = readSequenceParameterSet(event.escapedRBSP); + break; + case 0x08: + event.nalUnitType = 'pic_parameter_set_rbsp'; + break; + case 0x09: + event.nalUnitType = 'access_unit_delimiter_rbsp'; + break; + + default: + break; + } + self.trigger('data', event); + }); + nalByteStream.on('done', function () { + self.trigger('done'); + }); + + this.flush = function () { + nalByteStream.flush(); + }; + + /** + * Advance the ExpGolomb decoder past a scaling list. The scaling + * list is optionally transmitted as part of a sequence parameter + * set and is not relevant to transmuxing. + * @param count {number} the number of entries in this scaling list + * @param expGolombDecoder {object} an ExpGolomb pointed to the + * start of a scaling list + * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1 + */ + skipScalingList = function skipScalingList(count, expGolombDecoder) { + var lastScale = 8, + nextScale = 8, + j, + deltaScale; + + for (j = 0; j < count; j++) { + if (nextScale !== 0) { + deltaScale = expGolombDecoder.readExpGolomb(); + nextScale = (lastScale + deltaScale + 256) % 256; + } + + lastScale = nextScale === 0 ? lastScale : nextScale; + } + }; + + /** + * Expunge any "Emulation Prevention" bytes from a "Raw Byte + * Sequence Payload" + * @param data {Uint8Array} the bytes of a RBSP from a NAL + * unit + * @return {Uint8Array} the RBSP without any Emulation + * Prevention Bytes + */ + discardEmulationPreventionBytes = function discardEmulationPreventionBytes(data) { + var length = data.byteLength, + emulationPreventionBytesPositions = [], + i = 1, + newLength, + newData; + + // Find all `Emulation Prevention Bytes` + while (i < length - 2) { + if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0x03) { + emulationPreventionBytesPositions.push(i + 2); + i += 2; + } else { + i++; + } + } + + // If no Emulation Prevention Bytes were found just return the original + // array + if (emulationPreventionBytesPositions.length === 0) { + return data; + } + + // Create a new array to hold the NAL unit data + newLength = length - emulationPreventionBytesPositions.length; + newData = new Uint8Array(newLength); + var sourceIndex = 0; + + for (i = 0; i < newLength; sourceIndex++, i++) { + if (sourceIndex === emulationPreventionBytesPositions[0]) { + // Skip this byte + sourceIndex++; + // Remove this position index + emulationPreventionBytesPositions.shift(); + } + newData[i] = data[sourceIndex]; + } + + return newData; + }; + + /** + * Read a sequence parameter set and return some interesting video + * properties. A sequence parameter set is the H264 metadata that + * describes the properties of upcoming video frames. + * @param data {Uint8Array} the bytes of a sequence parameter set + * @return {object} an object with configuration parsed from the + * sequence parameter set, including the dimensions of the + * associated video frames. + */ + readSequenceParameterSet = function readSequenceParameterSet(data) { + var frameCropLeftOffset = 0, + frameCropRightOffset = 0, + frameCropTopOffset = 0, + frameCropBottomOffset = 0, + sarScale = 1, + expGolombDecoder, + profileIdc, + levelIdc, + profileCompatibility, + chromaFormatIdc, + picOrderCntType, + numRefFramesInPicOrderCntCycle, + picWidthInMbsMinus1, + picHeightInMapUnitsMinus1, + frameMbsOnlyFlag, + scalingListCount, + sarRatio, + aspectRatioIdc, + i; + + expGolombDecoder = new expGolomb(data); + profileIdc = expGolombDecoder.readUnsignedByte(); // profile_idc + profileCompatibility = expGolombDecoder.readUnsignedByte(); // constraint_set[0-5]_flag + levelIdc = expGolombDecoder.readUnsignedByte(); // level_idc u(8) + expGolombDecoder.skipUnsignedExpGolomb(); // seq_parameter_set_id + + // some profiles have more optional data we don't need + if (PROFILES_WITH_OPTIONAL_SPS_DATA[profileIdc]) { + chromaFormatIdc = expGolombDecoder.readUnsignedExpGolomb(); + if (chromaFormatIdc === 3) { + expGolombDecoder.skipBits(1); // separate_colour_plane_flag + } + expGolombDecoder.skipUnsignedExpGolomb(); // bit_depth_luma_minus8 + expGolombDecoder.skipUnsignedExpGolomb(); // bit_depth_chroma_minus8 + expGolombDecoder.skipBits(1); // qpprime_y_zero_transform_bypass_flag + if (expGolombDecoder.readBoolean()) { + // seq_scaling_matrix_present_flag + scalingListCount = chromaFormatIdc !== 3 ? 8 : 12; + for (i = 0; i < scalingListCount; i++) { + if (expGolombDecoder.readBoolean()) { + // seq_scaling_list_present_flag[ i ] + if (i < 6) { + skipScalingList(16, expGolombDecoder); + } else { + skipScalingList(64, expGolombDecoder); + } + } + } + } + } + + expGolombDecoder.skipUnsignedExpGolomb(); // log2_max_frame_num_minus4 + picOrderCntType = expGolombDecoder.readUnsignedExpGolomb(); + + if (picOrderCntType === 0) { + expGolombDecoder.readUnsignedExpGolomb(); // log2_max_pic_order_cnt_lsb_minus4 + } else if (picOrderCntType === 1) { + expGolombDecoder.skipBits(1); // delta_pic_order_always_zero_flag + expGolombDecoder.skipExpGolomb(); // offset_for_non_ref_pic + expGolombDecoder.skipExpGolomb(); // offset_for_top_to_bottom_field + numRefFramesInPicOrderCntCycle = expGolombDecoder.readUnsignedExpGolomb(); + for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) { + expGolombDecoder.skipExpGolomb(); // offset_for_ref_frame[ i ] + } + } + + expGolombDecoder.skipUnsignedExpGolomb(); // max_num_ref_frames + expGolombDecoder.skipBits(1); // gaps_in_frame_num_value_allowed_flag + + picWidthInMbsMinus1 = expGolombDecoder.readUnsignedExpGolomb(); + picHeightInMapUnitsMinus1 = expGolombDecoder.readUnsignedExpGolomb(); + + frameMbsOnlyFlag = expGolombDecoder.readBits(1); + if (frameMbsOnlyFlag === 0) { + expGolombDecoder.skipBits(1); // mb_adaptive_frame_field_flag + } + + expGolombDecoder.skipBits(1); // direct_8x8_inference_flag + if (expGolombDecoder.readBoolean()) { + // frame_cropping_flag + frameCropLeftOffset = expGolombDecoder.readUnsignedExpGolomb(); + frameCropRightOffset = expGolombDecoder.readUnsignedExpGolomb(); + frameCropTopOffset = expGolombDecoder.readUnsignedExpGolomb(); + frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb(); + } + if (expGolombDecoder.readBoolean()) { + // vui_parameters_present_flag + if (expGolombDecoder.readBoolean()) { + // aspect_ratio_info_present_flag + aspectRatioIdc = expGolombDecoder.readUnsignedByte(); + switch (aspectRatioIdc) { + case 1: + sarRatio = [1, 1]; + break; + case 2: + sarRatio = [12, 11]; + break; + case 3: + sarRatio = [10, 11]; + break; + case 4: + sarRatio = [16, 11]; + break; + case 5: + sarRatio = [40, 33]; + break; + case 6: + sarRatio = [24, 11]; + break; + case 7: + sarRatio = [20, 11]; + break; + case 8: + sarRatio = [32, 11]; + break; + case 9: + sarRatio = [80, 33]; + break; + case 10: + sarRatio = [18, 11]; + break; + case 11: + sarRatio = [15, 11]; + break; + case 12: + sarRatio = [64, 33]; + break; + case 13: + sarRatio = [160, 99]; + break; + case 14: + sarRatio = [4, 3]; + break; + case 15: + sarRatio = [3, 2]; + break; + case 16: + sarRatio = [2, 1]; + break; + case 255: { + sarRatio = [expGolombDecoder.readUnsignedByte() << 8 | expGolombDecoder.readUnsignedByte(), expGolombDecoder.readUnsignedByte() << 8 | expGolombDecoder.readUnsignedByte()]; + break; + } + } + if (sarRatio) { + sarScale = sarRatio[0] / sarRatio[1]; + } + } + } + return { + profileIdc: profileIdc, + levelIdc: levelIdc, + profileCompatibility: profileCompatibility, + width: Math.ceil(((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale), + height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - frameCropTopOffset * 2 - frameCropBottomOffset * 2 + }; + }; + }; + _H264Stream.prototype = new stream(); + + var h264 = { + H264Stream: _H264Stream, + NalByteStream: _NalByteStream + }; + + // Constants + var _AacStream; + + /** + * Splits an incoming stream of binary data into ADTS and ID3 Frames. + */ + + _AacStream = function AacStream() { + var everything = new Uint8Array(), + timeStamp = 0; + + _AacStream.prototype.init.call(this); + + this.setTimestamp = function (timestamp) { + timeStamp = timestamp; + }; + + this.parseId3TagSize = function (header, byteIndex) { + var returnSize = header[byteIndex + 6] << 21 | header[byteIndex + 7] << 14 | header[byteIndex + 8] << 7 | header[byteIndex + 9], + flags = header[byteIndex + 5], + footerPresent = (flags & 16) >> 4; + + if (footerPresent) { + return returnSize + 20; + } + return returnSize + 10; + }; + + this.parseAdtsSize = function (header, byteIndex) { + var lowThree = (header[byteIndex + 5] & 0xE0) >> 5, + middle = header[byteIndex + 4] << 3, + highTwo = header[byteIndex + 3] & 0x3 << 11; + + return highTwo | middle | lowThree; + }; + + this.push = function (bytes) { + var frameSize = 0, + byteIndex = 0, + bytesLeft, + chunk, + packet, + tempLength; + + // If there are bytes remaining from the last segment, prepend them to the + // bytes that were pushed in + if (everything.length) { + tempLength = everything.length; + everything = new Uint8Array(bytes.byteLength + tempLength); + everything.set(everything.subarray(0, tempLength)); + everything.set(bytes, tempLength); + } else { + everything = bytes; + } + + while (everything.length - byteIndex >= 3) { + if (everything[byteIndex] === 'I'.charCodeAt(0) && everything[byteIndex + 1] === 'D'.charCodeAt(0) && everything[byteIndex + 2] === '3'.charCodeAt(0)) { + + // Exit early because we don't have enough to parse + // the ID3 tag header + if (everything.length - byteIndex < 10) { + break; + } + + // check framesize + frameSize = this.parseId3TagSize(everything, byteIndex); + + // Exit early if we don't have enough in the buffer + // to emit a full packet + if (frameSize > everything.length) { + break; + } + chunk = { + type: 'timed-metadata', + data: everything.subarray(byteIndex, byteIndex + frameSize) + }; + this.trigger('data', chunk); + byteIndex += frameSize; + continue; + } else if (everything[byteIndex] & 0xff === 0xff && (everything[byteIndex + 1] & 0xf0) === 0xf0) { + + // Exit early because we don't have enough to parse + // the ADTS frame header + if (everything.length - byteIndex < 7) { + break; + } + + frameSize = this.parseAdtsSize(everything, byteIndex); + + // Exit early if we don't have enough in the buffer + // to emit a full packet + if (frameSize > everything.length) { + break; + } + + packet = { + type: 'audio', + data: everything.subarray(byteIndex, byteIndex + frameSize), + pts: timeStamp, + dts: timeStamp + }; + this.trigger('data', packet); + byteIndex += frameSize; + continue; + } + byteIndex++; + } + bytesLeft = everything.length - byteIndex; + + if (bytesLeft > 0) { + everything = everything.subarray(byteIndex); + } else { + everything = new Uint8Array(); + } + }; + }; + + _AacStream.prototype = new stream(); + + var aac = _AacStream; + + var highPrefix = [33, 16, 5, 32, 164, 27]; + var lowPrefix = [33, 65, 108, 84, 1, 2, 4, 8, 168, 2, 4, 8, 17, 191, 252]; + var zeroFill = function zeroFill(count) { + var a = []; + while (count--) { + a.push(0); + } + return a; + }; + + var makeTable = function makeTable(metaTable) { + return Object.keys(metaTable).reduce(function (obj, key) { + obj[key] = new Uint8Array(metaTable[key].reduce(function (arr, part) { + return arr.concat(part); + }, [])); + return obj; + }, {}); + }; + + // Frames-of-silence to use for filling in missing AAC frames + var coneOfSilence = { + 96000: [highPrefix, [227, 64], zeroFill(154), [56]], + 88200: [highPrefix, [231], zeroFill(170), [56]], + 64000: [highPrefix, [248, 192], zeroFill(240), [56]], + 48000: [highPrefix, [255, 192], zeroFill(268), [55, 148, 128], zeroFill(54), [112]], + 44100: [highPrefix, [255, 192], zeroFill(268), [55, 163, 128], zeroFill(84), [112]], + 32000: [highPrefix, [255, 192], zeroFill(268), [55, 234], zeroFill(226), [112]], + 24000: [highPrefix, [255, 192], zeroFill(268), [55, 255, 128], zeroFill(268), [111, 112], zeroFill(126), [224]], + 16000: [highPrefix, [255, 192], zeroFill(268), [55, 255, 128], zeroFill(268), [111, 255], zeroFill(269), [223, 108], zeroFill(195), [1, 192]], + 12000: [lowPrefix, zeroFill(268), [3, 127, 248], zeroFill(268), [6, 255, 240], zeroFill(268), [13, 255, 224], zeroFill(268), [27, 253, 128], zeroFill(259), [56]], + 11025: [lowPrefix, zeroFill(268), [3, 127, 248], zeroFill(268), [6, 255, 240], zeroFill(268), [13, 255, 224], zeroFill(268), [27, 255, 192], zeroFill(268), [55, 175, 128], zeroFill(108), [112]], + 8000: [lowPrefix, zeroFill(268), [3, 121, 16], zeroFill(47), [7]] + }; + + var silence = makeTable(coneOfSilence); + + var ONE_SECOND_IN_TS = 90000, + + // 90kHz clock + secondsToVideoTs, + secondsToAudioTs, + videoTsToSeconds, + audioTsToSeconds, + audioTsToVideoTs, + videoTsToAudioTs; + + secondsToVideoTs = function secondsToVideoTs(seconds) { + return seconds * ONE_SECOND_IN_TS; + }; + + secondsToAudioTs = function secondsToAudioTs(seconds, sampleRate) { + return seconds * sampleRate; + }; + + videoTsToSeconds = function videoTsToSeconds(timestamp) { + return timestamp / ONE_SECOND_IN_TS; + }; + + audioTsToSeconds = function audioTsToSeconds(timestamp, sampleRate) { + return timestamp / sampleRate; + }; + + audioTsToVideoTs = function audioTsToVideoTs(timestamp, sampleRate) { + return secondsToVideoTs(audioTsToSeconds(timestamp, sampleRate)); + }; + + videoTsToAudioTs = function videoTsToAudioTs(timestamp, sampleRate) { + return secondsToAudioTs(videoTsToSeconds(timestamp), sampleRate); + }; + + var clock = { + secondsToVideoTs: secondsToVideoTs, + secondsToAudioTs: secondsToAudioTs, + videoTsToSeconds: videoTsToSeconds, + audioTsToSeconds: audioTsToSeconds, + audioTsToVideoTs: audioTsToVideoTs, + videoTsToAudioTs: videoTsToAudioTs + }; + + var H264Stream = h264.H264Stream; + + // constants + var AUDIO_PROPERTIES = ['audioobjecttype', 'channelcount', 'samplerate', 'samplingfrequencyindex', 'samplesize']; + + var VIDEO_PROPERTIES = ['width', 'height', 'profileIdc', 'levelIdc', 'profileCompatibility']; + + var ONE_SECOND_IN_TS$1 = 90000; // 90kHz clock + + // object types + var _VideoSegmentStream, _AudioSegmentStream, _Transmuxer, _CoalesceStream; + + // Helper functions + var createDefaultSample, isLikelyAacData, collectDtsInfo, clearDtsInfo, calculateTrackBaseMediaDecodeTime, + arrayEquals, sumFrameByteLengths; + + /** + * Default sample object + * see ISO/IEC 14496-12:2012, section 8.6.4.3 + */ + createDefaultSample = function createDefaultSample() { + return { + size: 0, + flags: { + isLeading: 0, + dependsOn: 1, + isDependedOn: 0, + hasRedundancy: 0, + degradationPriority: 0 + } + }; + }; + + isLikelyAacData = function isLikelyAacData(data) { + if (data[0] === 'I'.charCodeAt(0) && data[1] === 'D'.charCodeAt(0) && data[2] === '3'.charCodeAt(0)) { + return true; + } + return false; + }; + + /** + * Compare two arrays (even typed) for same-ness + */ + arrayEquals = function arrayEquals(a, b) { + var i; + + if (a.length !== b.length) { + return false; + } + + // compare the value of each element in the array + for (i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + + return true; + }; + + /** + * Sum the `byteLength` properties of the data in each AAC frame + */ + sumFrameByteLengths = function sumFrameByteLengths(array) { + var i, + currentObj, + sum = 0; + + // sum the byteLength's all each nal unit in the frame + for (i = 0; i < array.length; i++) { + currentObj = array[i]; + sum += currentObj.data.byteLength; + } + + return sum; + }; + + /** + * Constructs a single-track, ISO BMFF media segment from AAC data + * events. The output of this stream can be fed to a SourceBuffer + * configured with a suitable initialization segment. + * @param track {object} track metadata configuration + * @param options {object} transmuxer options object + * @param options.keepOriginalTimestamps {boolean} If true, keep the timestamps + * in the source; false to adjust the first segment to start at 0. + */ + _AudioSegmentStream = function AudioSegmentStream(track, options) { + var adtsFrames = [], + sequenceNumber = 0, + earliestAllowedDts = 0, + audioAppendStartTs = 0, + videoBaseMediaDecodeTime = Infinity; + + options = options || {}; + + _AudioSegmentStream.prototype.init.call(this); + + this.push = function (data) { + collectDtsInfo(track, data); + + if (track) { + AUDIO_PROPERTIES.forEach(function (prop) { + track[prop] = data[prop]; + }); + } + + // buffer audio data until end() is called + adtsFrames.push(data); + }; + + this.setEarliestDts = function (earliestDts) { + earliestAllowedDts = earliestDts - track.timelineStartInfo.baseMediaDecodeTime; + }; + + this.setVideoBaseMediaDecodeTime = function (baseMediaDecodeTime) { + videoBaseMediaDecodeTime = baseMediaDecodeTime; + }; + + this.setAudioAppendStart = function (timestamp) { + audioAppendStartTs = timestamp; + }; + + this.flush = function () { + var frames, moof, mdat, boxes; + + // return early if no audio data has been observed + if (adtsFrames.length === 0) { + this.trigger('done', 'AudioSegmentStream'); + return; + } + + frames = this.trimAdtsFramesByEarliestDts_(adtsFrames); + track.baseMediaDecodeTime = calculateTrackBaseMediaDecodeTime(track, options.keepOriginalTimestamps); + + this.prefixWithSilence_(track, frames); + + // we have to build the index from byte locations to + // samples (that is, adts frames) in the audio data + track.samples = this.generateSampleTable_(frames); + + // concatenate the audio data to constuct the mdat + mdat = mp4Generator.mdat(this.concatenateFrameData_(frames)); + + adtsFrames = []; + + moof = mp4Generator.moof(sequenceNumber, [track]); + boxes = new Uint8Array(moof.byteLength + mdat.byteLength); + + // bump the sequence number for next time + sequenceNumber++; + + boxes.set(moof); + boxes.set(mdat, moof.byteLength); + + clearDtsInfo(track); + + this.trigger('data', {track: track, boxes: boxes}); + this.trigger('done', 'AudioSegmentStream'); + }; + + // Possibly pad (prefix) the audio track with silence if appending this track + // would lead to the introduction of a gap in the audio buffer + this.prefixWithSilence_ = function (track, frames) { + var baseMediaDecodeTimeTs, + frameDuration = 0, + audioGapDuration = 0, + audioFillFrameCount = 0, + audioFillDuration = 0, + silentFrame, + i; + + if (!frames.length) { + return; + } + + baseMediaDecodeTimeTs = clock.audioTsToVideoTs(track.baseMediaDecodeTime, track.samplerate); + // determine frame clock duration based on sample rate, round up to avoid overfills + frameDuration = Math.ceil(ONE_SECOND_IN_TS$1 / (track.samplerate / 1024)); + + if (audioAppendStartTs && videoBaseMediaDecodeTime) { + // insert the shortest possible amount (audio gap or audio to video gap) + audioGapDuration = baseMediaDecodeTimeTs - Math.max(audioAppendStartTs, videoBaseMediaDecodeTime); + // number of full frames in the audio gap + audioFillFrameCount = Math.floor(audioGapDuration / frameDuration); + audioFillDuration = audioFillFrameCount * frameDuration; + } + + // don't attempt to fill gaps smaller than a single frame or larger + // than a half second + if (audioFillFrameCount < 1 || audioFillDuration > ONE_SECOND_IN_TS$1 / 2) { + return; + } + + silentFrame = silence[track.samplerate]; + + if (!silentFrame) { + // we don't have a silent frame pregenerated for the sample rate, so use a frame + // from the content instead + silentFrame = frames[0].data; + } + + for (i = 0; i < audioFillFrameCount; i++) { + frames.splice(i, 0, { + data: silentFrame + }); + } + + track.baseMediaDecodeTime -= Math.floor(clock.videoTsToAudioTs(audioFillDuration, track.samplerate)); + }; + + // If the audio segment extends before the earliest allowed dts + // value, remove AAC frames until starts at or after the earliest + // allowed DTS so that we don't end up with a negative baseMedia- + // DecodeTime for the audio track + this.trimAdtsFramesByEarliestDts_ = function (adtsFrames) { + if (track.minSegmentDts >= earliestAllowedDts) { + return adtsFrames; + } + + // We will need to recalculate the earliest segment Dts + track.minSegmentDts = Infinity; + + return adtsFrames.filter(function (currentFrame) { + // If this is an allowed frame, keep it and record it's Dts + if (currentFrame.dts >= earliestAllowedDts) { + track.minSegmentDts = Math.min(track.minSegmentDts, currentFrame.dts); + track.minSegmentPts = track.minSegmentDts; + return true; + } + // Otherwise, discard it + return false; + }); + }; + + // generate the track's raw mdat data from an array of frames + this.generateSampleTable_ = function (frames) { + var i, + currentFrame, + samples = []; + + for (i = 0; i < frames.length; i++) { + currentFrame = frames[i]; + samples.push({ + size: currentFrame.data.byteLength, + duration: 1024 // For AAC audio, all samples contain 1024 samples + }); + } + return samples; + }; + + // generate the track's sample table from an array of frames + this.concatenateFrameData_ = function (frames) { + var i, + currentFrame, + dataOffset = 0, + data = new Uint8Array(sumFrameByteLengths(frames)); + + for (i = 0; i < frames.length; i++) { + currentFrame = frames[i]; + + data.set(currentFrame.data, dataOffset); + dataOffset += currentFrame.data.byteLength; + } + return data; + }; + }; + + _AudioSegmentStream.prototype = new stream(); + + /** + * Constructs a single-track, ISO BMFF media segment from H264 data + * events. The output of this stream can be fed to a SourceBuffer + * configured with a suitable initialization segment. + * @param track {object} track metadata configuration + * @param options {object} transmuxer options object + * @param options.alignGopsAtEnd {boolean} If true, start from the end of the + * gopsToAlignWith list when attempting to align gop pts + * @param options.keepOriginalTimestamps {boolean} If true, keep the timestamps + * in the source; false to adjust the first segment to start at 0. + */ + _VideoSegmentStream = function VideoSegmentStream(track, options) { + var sequenceNumber = 0, + nalUnits = [], + gopsToAlignWith = [], + config, + pps; + + options = options || {}; + + _VideoSegmentStream.prototype.init.call(this); + + delete track.minPTS; + + this.gopCache_ = []; + + this.push = function (nalUnit) { + collectDtsInfo(track, nalUnit); + + // record the track config + if (nalUnit.nalUnitType === 'seq_parameter_set_rbsp' && !config) { + config = nalUnit.config; + track.sps = [nalUnit.data]; + + VIDEO_PROPERTIES.forEach(function (prop) { + track[prop] = config[prop]; + }, this); + } + + if (nalUnit.nalUnitType === 'pic_parameter_set_rbsp' && !pps) { + pps = nalUnit.data; + track.pps = [nalUnit.data]; + } + + // buffer video until flush() is called + nalUnits.push(nalUnit); + }; + + this.flush = function () { + var frames, gopForFusion, gops, moof, mdat, boxes; + + // Throw away nalUnits at the start of the byte stream until + // we find the first AUD + while (nalUnits.length) { + if (nalUnits[0].nalUnitType === 'access_unit_delimiter_rbsp') { + break; + } + nalUnits.shift(); + } + + // Return early if no video data has been observed + if (nalUnits.length === 0) { + this.resetStream_(); + this.trigger('done', 'VideoSegmentStream'); + return; + } + + // Organize the raw nal-units into arrays that represent + // higher-level constructs such as frames and gops + // (group-of-pictures) + frames = this.groupNalsIntoFrames_(nalUnits); + gops = this.groupFramesIntoGops_(frames); + + // If the first frame of this fragment is not a keyframe we have + // a problem since MSE (on Chrome) requires a leading keyframe. + // + // We have two approaches to repairing this situation: + // 1) GOP-FUSION: + // This is where we keep track of the GOPS (group-of-pictures) + // from previous fragments and attempt to find one that we can + // prepend to the current fragment in order to create a valid + // fragment. + // 2) KEYFRAME-PULLING: + // Here we search for the first keyframe in the fragment and + // throw away all the frames between the start of the fragment + // and that keyframe. We then extend the duration and pull the + // PTS of the keyframe forward so that it covers the time range + // of the frames that were disposed of. + // + // #1 is far prefereable over #2 which can cause "stuttering" but + // requires more things to be just right. + if (!gops[0][0].keyFrame) { + // Search for a gop for fusion from our gopCache + gopForFusion = this.getGopForFusion_(nalUnits[0], track); + + if (gopForFusion) { + gops.unshift(gopForFusion); + // Adjust Gops' metadata to account for the inclusion of the + // new gop at the beginning + gops.byteLength += gopForFusion.byteLength; + gops.nalCount += gopForFusion.nalCount; + gops.pts = gopForFusion.pts; + gops.dts = gopForFusion.dts; + gops.duration += gopForFusion.duration; + } else { + // If we didn't find a candidate gop fall back to keyframe-pulling + gops = this.extendFirstKeyFrame_(gops); + } + } + + // Trim gops to align with gopsToAlignWith + if (gopsToAlignWith.length) { + var alignedGops; + + if (options.alignGopsAtEnd) { + alignedGops = this.alignGopsAtEnd_(gops); + } else { + alignedGops = this.alignGopsAtStart_(gops); + } + + if (!alignedGops) { + // save all the nals in the last GOP into the gop cache + this.gopCache_.unshift({ + gop: gops.pop(), + pps: track.pps, + sps: track.sps + }); + + // Keep a maximum of 6 GOPs in the cache + this.gopCache_.length = Math.min(6, this.gopCache_.length); + + // Clear nalUnits + nalUnits = []; + + // return early no gops can be aligned with desired gopsToAlignWith + this.resetStream_(); + this.trigger('done', 'VideoSegmentStream'); + return; + } + + // Some gops were trimmed. clear dts info so minSegmentDts and pts are correct + // when recalculated before sending off to CoalesceStream + clearDtsInfo(track); + + gops = alignedGops; + } + + collectDtsInfo(track, gops); + + // First, we have to build the index from byte locations to + // samples (that is, frames) in the video data + track.samples = this.generateSampleTable_(gops); + + // Concatenate the video data and construct the mdat + mdat = mp4Generator.mdat(this.concatenateNalData_(gops)); + + track.baseMediaDecodeTime = calculateTrackBaseMediaDecodeTime(track, options.keepOriginalTimestamps); + + this.trigger('processedGopsInfo', gops.map(function (gop) { + return { + pts: gop.pts, + dts: gop.dts, + byteLength: gop.byteLength + }; + })); + + // save all the nals in the last GOP into the gop cache + this.gopCache_.unshift({ + gop: gops.pop(), + pps: track.pps, + sps: track.sps + }); + + // Keep a maximum of 6 GOPs in the cache + this.gopCache_.length = Math.min(6, this.gopCache_.length); + + // Clear nalUnits + nalUnits = []; + + this.trigger('baseMediaDecodeTime', track.baseMediaDecodeTime); + this.trigger('timelineStartInfo', track.timelineStartInfo); + + moof = mp4Generator.moof(sequenceNumber, [track]); + + // it would be great to allocate this array up front instead of + // throwing away hundreds of media segment fragments + boxes = new Uint8Array(moof.byteLength + mdat.byteLength); + + // Bump the sequence number for next time + sequenceNumber++; + + boxes.set(moof); + boxes.set(mdat, moof.byteLength); + + this.trigger('data', {track: track, boxes: boxes}); + + this.resetStream_(); + + // Continue with the flush process now + this.trigger('done', 'VideoSegmentStream'); + }; + + this.resetStream_ = function () { + clearDtsInfo(track); + + // reset config and pps because they may differ across segments + // for instance, when we are rendition switching + config = undefined; + pps = undefined; + }; + + // Search for a candidate Gop for gop-fusion from the gop cache and + // return it or return null if no good candidate was found + this.getGopForFusion_ = function (nalUnit) { + var halfSecond = 45000, + + // Half-a-second in a 90khz clock + allowableOverlap = 10000, + + // About 3 frames @ 30fps + nearestDistance = Infinity, + dtsDistance, + nearestGopObj, + currentGop, + currentGopObj, + i; + + // Search for the GOP nearest to the beginning of this nal unit + for (i = 0; i < this.gopCache_.length; i++) { + currentGopObj = this.gopCache_[i]; + currentGop = currentGopObj.gop; + + // Reject Gops with different SPS or PPS + if (!(track.pps && arrayEquals(track.pps[0], currentGopObj.pps[0])) || !(track.sps && arrayEquals(track.sps[0], currentGopObj.sps[0]))) { + continue; + } + + // Reject Gops that would require a negative baseMediaDecodeTime + if (currentGop.dts < track.timelineStartInfo.dts) { + continue; + } + + // The distance between the end of the gop and the start of the nalUnit + dtsDistance = nalUnit.dts - currentGop.dts - currentGop.duration; + + // Only consider GOPS that start before the nal unit and end within + // a half-second of the nal unit + if (dtsDistance >= -allowableOverlap && dtsDistance <= halfSecond) { + + // Always use the closest GOP we found if there is more than + // one candidate + if (!nearestGopObj || nearestDistance > dtsDistance) { + nearestGopObj = currentGopObj; + nearestDistance = dtsDistance; + } + } + } + + if (nearestGopObj) { + return nearestGopObj.gop; + } + return null; + }; + + this.extendFirstKeyFrame_ = function (gops) { + var currentGop; + + if (!gops[0][0].keyFrame && gops.length > 1) { + // Remove the first GOP + currentGop = gops.shift(); + + gops.byteLength -= currentGop.byteLength; + gops.nalCount -= currentGop.nalCount; + + // Extend the first frame of what is now the + // first gop to cover the time period of the + // frames we just removed + gops[0][0].dts = currentGop.dts; + gops[0][0].pts = currentGop.pts; + gops[0][0].duration += currentGop.duration; + } + + return gops; + }; + + // Convert an array of nal units into an array of frames with each frame being + // composed of the nal units that make up that frame + // Also keep track of cummulative data about the frame from the nal units such + // as the frame duration, starting pts, etc. + this.groupNalsIntoFrames_ = function (nalUnits) { + var i, + currentNal, + currentFrame = [], + frames = []; + + currentFrame.byteLength = 0; + + for (i = 0; i < nalUnits.length; i++) { + currentNal = nalUnits[i]; + + // Split on 'aud'-type nal units + if (currentNal.nalUnitType === 'access_unit_delimiter_rbsp') { + // Since the very first nal unit is expected to be an AUD + // only push to the frames array when currentFrame is not empty + if (currentFrame.length) { + currentFrame.duration = currentNal.dts - currentFrame.dts; + frames.push(currentFrame); + } + currentFrame = [currentNal]; + currentFrame.byteLength = currentNal.data.byteLength; + currentFrame.pts = currentNal.pts; + currentFrame.dts = currentNal.dts; + } else { + // Specifically flag key frames for ease of use later + if (currentNal.nalUnitType === 'slice_layer_without_partitioning_rbsp_idr') { + currentFrame.keyFrame = true; + } + currentFrame.duration = currentNal.dts - currentFrame.dts; + currentFrame.byteLength += currentNal.data.byteLength; + currentFrame.push(currentNal); + } + } + + // For the last frame, use the duration of the previous frame if we + // have nothing better to go on + if (frames.length && (!currentFrame.duration || currentFrame.duration <= 0)) { + currentFrame.duration = frames[frames.length - 1].duration; + } + + // Push the final frame + frames.push(currentFrame); + return frames; + }; + + // Convert an array of frames into an array of Gop with each Gop being composed + // of the frames that make up that Gop + // Also keep track of cummulative data about the Gop from the frames such as the + // Gop duration, starting pts, etc. + this.groupFramesIntoGops_ = function (frames) { + var i, + currentFrame, + currentGop = [], + gops = []; + + // We must pre-set some of the values on the Gop since we + // keep running totals of these values + currentGop.byteLength = 0; + currentGop.nalCount = 0; + currentGop.duration = 0; + currentGop.pts = frames[0].pts; + currentGop.dts = frames[0].dts; + + // store some metadata about all the Gops + gops.byteLength = 0; + gops.nalCount = 0; + gops.duration = 0; + gops.pts = frames[0].pts; + gops.dts = frames[0].dts; + + for (i = 0; i < frames.length; i++) { + currentFrame = frames[i]; + + if (currentFrame.keyFrame) { + // Since the very first frame is expected to be an keyframe + // only push to the gops array when currentGop is not empty + if (currentGop.length) { + gops.push(currentGop); + gops.byteLength += currentGop.byteLength; + gops.nalCount += currentGop.nalCount; + gops.duration += currentGop.duration; + } + + currentGop = [currentFrame]; + currentGop.nalCount = currentFrame.length; + currentGop.byteLength = currentFrame.byteLength; + currentGop.pts = currentFrame.pts; + currentGop.dts = currentFrame.dts; + currentGop.duration = currentFrame.duration; + } else { + currentGop.duration += currentFrame.duration; + currentGop.nalCount += currentFrame.length; + currentGop.byteLength += currentFrame.byteLength; + currentGop.push(currentFrame); + } + } + + if (gops.length && currentGop.duration <= 0) { + currentGop.duration = gops[gops.length - 1].duration; + } + gops.byteLength += currentGop.byteLength; + gops.nalCount += currentGop.nalCount; + gops.duration += currentGop.duration; + + // push the final Gop + gops.push(currentGop); + return gops; + }; + + // generate the track's sample table from an array of gops + this.generateSampleTable_ = function (gops, baseDataOffset) { + var h, + i, + sample, + currentGop, + currentFrame, + dataOffset = baseDataOffset || 0, + samples = []; + + for (h = 0; h < gops.length; h++) { + currentGop = gops[h]; + + for (i = 0; i < currentGop.length; i++) { + currentFrame = currentGop[i]; + + sample = createDefaultSample(); + + sample.dataOffset = dataOffset; + sample.compositionTimeOffset = currentFrame.pts - currentFrame.dts; + sample.duration = currentFrame.duration; + sample.size = 4 * currentFrame.length; // Space for nal unit size + sample.size += currentFrame.byteLength; + + if (currentFrame.keyFrame) { + sample.flags.dependsOn = 2; + } + + dataOffset += sample.size; + + samples.push(sample); + } + } + return samples; + }; + + // generate the track's raw mdat data from an array of gops + this.concatenateNalData_ = function (gops) { + var h, + i, + j, + currentGop, + currentFrame, + currentNal, + dataOffset = 0, + nalsByteLength = gops.byteLength, + numberOfNals = gops.nalCount, + totalByteLength = nalsByteLength + 4 * numberOfNals, + data = new Uint8Array(totalByteLength), + view = new DataView(data.buffer); + + // For each Gop.. + for (h = 0; h < gops.length; h++) { + currentGop = gops[h]; + + // For each Frame.. + for (i = 0; i < currentGop.length; i++) { + currentFrame = currentGop[i]; + + // For each NAL.. + for (j = 0; j < currentFrame.length; j++) { + currentNal = currentFrame[j]; + + view.setUint32(dataOffset, currentNal.data.byteLength); + dataOffset += 4; + data.set(currentNal.data, dataOffset); + dataOffset += currentNal.data.byteLength; + } + } + } + return data; + }; + + // trim gop list to the first gop found that has a matching pts with a gop in the list + // of gopsToAlignWith starting from the START of the list + this.alignGopsAtStart_ = function (gops) { + var alignIndex, gopIndex, align, gop, byteLength, nalCount, duration, alignedGops; + + byteLength = gops.byteLength; + nalCount = gops.nalCount; + duration = gops.duration; + alignIndex = gopIndex = 0; + + while (alignIndex < gopsToAlignWith.length && gopIndex < gops.length) { + align = gopsToAlignWith[alignIndex]; + gop = gops[gopIndex]; + + if (align.pts === gop.pts) { + break; + } + + if (gop.pts > align.pts) { + // this current gop starts after the current gop we want to align on, so increment + // align index + alignIndex++; + continue; + } + + // current gop starts before the current gop we want to align on. so increment gop + // index + gopIndex++; + byteLength -= gop.byteLength; + nalCount -= gop.nalCount; + duration -= gop.duration; + } + + if (gopIndex === 0) { + // no gops to trim + return gops; + } + + if (gopIndex === gops.length) { + // all gops trimmed, skip appending all gops + return null; + } + + alignedGops = gops.slice(gopIndex); + alignedGops.byteLength = byteLength; + alignedGops.duration = duration; + alignedGops.nalCount = nalCount; + alignedGops.pts = alignedGops[0].pts; + alignedGops.dts = alignedGops[0].dts; + + return alignedGops; + }; + + // trim gop list to the first gop found that has a matching pts with a gop in the list + // of gopsToAlignWith starting from the END of the list + this.alignGopsAtEnd_ = function (gops) { + var alignIndex, gopIndex, align, gop, alignEndIndex, matchFound; + + alignIndex = gopsToAlignWith.length - 1; + gopIndex = gops.length - 1; + alignEndIndex = null; + matchFound = false; + + while (alignIndex >= 0 && gopIndex >= 0) { + align = gopsToAlignWith[alignIndex]; + gop = gops[gopIndex]; + + if (align.pts === gop.pts) { + matchFound = true; + break; + } + + if (align.pts > gop.pts) { + alignIndex--; + continue; + } + + if (alignIndex === gopsToAlignWith.length - 1) { + // gop.pts is greater than the last alignment candidate. If no match is found + // by the end of this loop, we still want to append gops that come after this + // point + alignEndIndex = gopIndex; + } + + gopIndex--; + } + + if (!matchFound && alignEndIndex === null) { + return null; + } + + var trimIndex; + + if (matchFound) { + trimIndex = gopIndex; + } else { + trimIndex = alignEndIndex; + } + + if (trimIndex === 0) { + return gops; + } + + var alignedGops = gops.slice(trimIndex); + var metadata = alignedGops.reduce(function (total, gop) { + total.byteLength += gop.byteLength; + total.duration += gop.duration; + total.nalCount += gop.nalCount; + return total; + }, {byteLength: 0, duration: 0, nalCount: 0}); + + alignedGops.byteLength = metadata.byteLength; + alignedGops.duration = metadata.duration; + alignedGops.nalCount = metadata.nalCount; + alignedGops.pts = alignedGops[0].pts; + alignedGops.dts = alignedGops[0].dts; + + return alignedGops; + }; + + this.alignGopsWith = function (newGopsToAlignWith) { + gopsToAlignWith = newGopsToAlignWith; + }; + }; + + _VideoSegmentStream.prototype = new stream(); + + /** + * Store information about the start and end of the track and the + * duration for each frame/sample we process in order to calculate + * the baseMediaDecodeTime + */ + collectDtsInfo = function collectDtsInfo(track, data) { + if (typeof data.pts === 'number') { + if (track.timelineStartInfo.pts === undefined) { + track.timelineStartInfo.pts = data.pts; + } + + if (track.minSegmentPts === undefined) { + track.minSegmentPts = data.pts; + } else { + track.minSegmentPts = Math.min(track.minSegmentPts, data.pts); + } + + if (track.maxSegmentPts === undefined) { + track.maxSegmentPts = data.pts; + } else { + track.maxSegmentPts = Math.max(track.maxSegmentPts, data.pts); + } + } + + if (typeof data.dts === 'number') { + if (track.timelineStartInfo.dts === undefined) { + track.timelineStartInfo.dts = data.dts; + } + + if (track.minSegmentDts === undefined) { + track.minSegmentDts = data.dts; + } else { + track.minSegmentDts = Math.min(track.minSegmentDts, data.dts); + } + + if (track.maxSegmentDts === undefined) { + track.maxSegmentDts = data.dts; + } else { + track.maxSegmentDts = Math.max(track.maxSegmentDts, data.dts); + } + } + }; + + /** + * Clear values used to calculate the baseMediaDecodeTime between + * tracks + */ + clearDtsInfo = function clearDtsInfo(track) { + delete track.minSegmentDts; + delete track.maxSegmentDts; + delete track.minSegmentPts; + delete track.maxSegmentPts; + }; + + /** + * Calculate the track's baseMediaDecodeTime based on the earliest + * DTS the transmuxer has ever seen and the minimum DTS for the + * current track + * @param track {object} track metadata configuration + * @param keepOriginalTimestamps {boolean} If true, keep the timestamps + * in the source; false to adjust the first segment to start at 0. + */ + calculateTrackBaseMediaDecodeTime = function calculateTrackBaseMediaDecodeTime(track, keepOriginalTimestamps) { + var baseMediaDecodeTime, + scale, + minSegmentDts = track.minSegmentDts; + + // Optionally adjust the time so the first segment starts at zero. + if (!keepOriginalTimestamps) { + minSegmentDts -= track.timelineStartInfo.dts; + } + + // track.timelineStartInfo.baseMediaDecodeTime is the location, in time, where + // we want the start of the first segment to be placed + baseMediaDecodeTime = track.timelineStartInfo.baseMediaDecodeTime; + + // Add to that the distance this segment is from the very first + baseMediaDecodeTime += minSegmentDts; + + // baseMediaDecodeTime must not become negative + baseMediaDecodeTime = Math.max(0, baseMediaDecodeTime); + + if (track.type === 'audio') { + // Audio has a different clock equal to the sampling_rate so we need to + // scale the PTS values into the clock rate of the track + scale = track.samplerate / ONE_SECOND_IN_TS$1; + baseMediaDecodeTime *= scale; + baseMediaDecodeTime = Math.floor(baseMediaDecodeTime); + } + + return baseMediaDecodeTime; + }; + + /** + * A Stream that can combine multiple streams (ie. audio & video) + * into a single output segment for MSE. Also supports audio-only + * and video-only streams. + */ + _CoalesceStream = function CoalesceStream(options, metadataStream) { + // Number of Tracks per output segment + // If greater than 1, we combine multiple + // tracks into a single segment + this.numberOfTracks = 0; + this.metadataStream = metadataStream; + + if (typeof options.remux !== 'undefined') { + this.remuxTracks = !!options.remux; + } else { + this.remuxTracks = true; + } + + this.pendingTracks = []; + this.videoTrack = null; + this.pendingBoxes = []; + this.pendingCaptions = []; + this.pendingMetadata = []; + this.pendingBytes = 0; + this.emittedTracks = 0; + + _CoalesceStream.prototype.init.call(this); + + // Take output from multiple + this.push = function (output) { + // buffer incoming captions until the associated video segment + // finishes + if (output.text) { + return this.pendingCaptions.push(output); + } + // buffer incoming id3 tags until the final flush + if (output.frames) { + return this.pendingMetadata.push(output); + } + + // Add this track to the list of pending tracks and store + // important information required for the construction of + // the final segment + this.pendingTracks.push(output.track); + this.pendingBoxes.push(output.boxes); + this.pendingBytes += output.boxes.byteLength; + + if (output.track.type === 'video') { + this.videoTrack = output.track; + } + if (output.track.type === 'audio') { + this.audioTrack = output.track; + } + }; + }; + + _CoalesceStream.prototype = new stream(); + _CoalesceStream.prototype.flush = function (flushSource) { + var offset = 0, + event = { + captions: [], + captionStreams: {}, + metadata: [], + info: {} + }, + caption, + id3, + initSegment, + timelineStartPts = 0, + i; + + if (this.pendingTracks.length < this.numberOfTracks) { + if (flushSource !== 'VideoSegmentStream' && flushSource !== 'AudioSegmentStream') { + // Return because we haven't received a flush from a data-generating + // portion of the segment (meaning that we have only recieved meta-data + // or captions.) + return; + } else if (this.remuxTracks) { + // Return until we have enough tracks from the pipeline to remux (if we + // are remuxing audio and video into a single MP4) + return; + } else if (this.pendingTracks.length === 0) { + // In the case where we receive a flush without any data having been + // received we consider it an emitted track for the purposes of coalescing + // `done` events. + // We do this for the case where there is an audio and video track in the + // segment but no audio data. (seen in several playlists with alternate + // audio tracks and no audio present in the main TS segments.) + this.emittedTracks++; + + if (this.emittedTracks >= this.numberOfTracks) { + this.trigger('done'); + this.emittedTracks = 0; + } + return; + } + } + + if (this.videoTrack) { + timelineStartPts = this.videoTrack.timelineStartInfo.pts; + VIDEO_PROPERTIES.forEach(function (prop) { + event.info[prop] = this.videoTrack[prop]; + }, this); + } else if (this.audioTrack) { + timelineStartPts = this.audioTrack.timelineStartInfo.pts; + AUDIO_PROPERTIES.forEach(function (prop) { + event.info[prop] = this.audioTrack[prop]; + }, this); + } + + if (this.pendingTracks.length === 1) { + event.type = this.pendingTracks[0].type; + } else { + event.type = 'combined'; + } + + this.emittedTracks += this.pendingTracks.length; + + initSegment = mp4Generator.initSegment(this.pendingTracks); + + // Create a new typed array to hold the init segment + event.initSegment = new Uint8Array(initSegment.byteLength); + + // Create an init segment containing a moov + // and track definitions + event.initSegment.set(initSegment); + + // Create a new typed array to hold the moof+mdats + event.data = new Uint8Array(this.pendingBytes); + + // Append each moof+mdat (one per track) together + for (i = 0; i < this.pendingBoxes.length; i++) { + event.data.set(this.pendingBoxes[i], offset); + offset += this.pendingBoxes[i].byteLength; + } + + // Translate caption PTS times into second offsets into the + // video timeline for the segment, and add track info + for (i = 0; i < this.pendingCaptions.length; i++) { + caption = this.pendingCaptions[i]; + caption.startTime = caption.startPts - timelineStartPts; + caption.startTime /= 90e3; + caption.endTime = caption.endPts - timelineStartPts; + caption.endTime /= 90e3; + event.captionStreams[caption.stream] = true; + event.captions.push(caption); + } + + // Translate ID3 frame PTS times into second offsets into the + // video timeline for the segment + for (i = 0; i < this.pendingMetadata.length; i++) { + id3 = this.pendingMetadata[i]; + id3.cueTime = id3.pts - timelineStartPts; + id3.cueTime /= 90e3; + event.metadata.push(id3); + } + // We add this to every single emitted segment even though we only need + // it for the first + event.metadata.dispatchType = this.metadataStream.dispatchType; + + // Reset stream state + this.pendingTracks.length = 0; + this.videoTrack = null; + this.pendingBoxes.length = 0; + this.pendingCaptions.length = 0; + this.pendingBytes = 0; + this.pendingMetadata.length = 0; + + // Emit the built segment + this.trigger('data', event); + + // Only emit `done` if all tracks have been flushed and emitted + if (this.emittedTracks >= this.numberOfTracks) { + this.trigger('done'); + this.emittedTracks = 0; + } + }; + /** + * A Stream that expects MP2T binary data as input and produces + * corresponding media segments, suitable for use with Media Source + * Extension (MSE) implementations that support the ISO BMFF byte + * stream format, like Chrome. + */ + _Transmuxer = function Transmuxer(options) { + var self = this, + hasFlushed = true, + videoTrack, + audioTrack; + + _Transmuxer.prototype.init.call(this); + + options = options || {}; + this.baseMediaDecodeTime = options.baseMediaDecodeTime || 0; + this.transmuxPipeline_ = {}; + + this.setupAacPipeline = function () { + var pipeline = {}; + this.transmuxPipeline_ = pipeline; + + pipeline.type = 'aac'; + pipeline.metadataStream = new m2ts_1.MetadataStream(); + + // set up the parsing pipeline + pipeline.aacStream = new aac(); + pipeline.audioTimestampRolloverStream = new m2ts_1.TimestampRolloverStream('audio'); + pipeline.timedMetadataTimestampRolloverStream = new m2ts_1.TimestampRolloverStream('timed-metadata'); + pipeline.adtsStream = new adts(); + pipeline.coalesceStream = new _CoalesceStream(options, pipeline.metadataStream); + pipeline.headOfPipeline = pipeline.aacStream; + + pipeline.aacStream.pipe(pipeline.audioTimestampRolloverStream).pipe(pipeline.adtsStream); + pipeline.aacStream.pipe(pipeline.timedMetadataTimestampRolloverStream).pipe(pipeline.metadataStream).pipe(pipeline.coalesceStream); + + pipeline.metadataStream.on('timestamp', function (frame) { + pipeline.aacStream.setTimestamp(frame.timeStamp); + }); + + pipeline.aacStream.on('data', function (data) { + if (data.type === 'timed-metadata' && !pipeline.audioSegmentStream) { + audioTrack = audioTrack || { + timelineStartInfo: { + baseMediaDecodeTime: self.baseMediaDecodeTime + }, + codec: 'adts', + type: 'audio' + }; + // hook up the audio segment stream to the first track with aac data + pipeline.coalesceStream.numberOfTracks++; + pipeline.audioSegmentStream = new _AudioSegmentStream(audioTrack, options); + // Set up the final part of the audio pipeline + pipeline.adtsStream.pipe(pipeline.audioSegmentStream).pipe(pipeline.coalesceStream); + } + }); + + // Re-emit any data coming from the coalesce stream to the outside world + pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data')); + // Let the consumer know we have finished flushing the entire pipeline + pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done')); + }; + + this.setupTsPipeline = function () { + var pipeline = {}; + this.transmuxPipeline_ = pipeline; + + pipeline.type = 'ts'; + pipeline.metadataStream = new m2ts_1.MetadataStream(); + + // set up the parsing pipeline + pipeline.packetStream = new m2ts_1.TransportPacketStream(); + pipeline.parseStream = new m2ts_1.TransportParseStream(); + pipeline.elementaryStream = new m2ts_1.ElementaryStream(); + pipeline.videoTimestampRolloverStream = new m2ts_1.TimestampRolloverStream('video'); + pipeline.audioTimestampRolloverStream = new m2ts_1.TimestampRolloverStream('audio'); + pipeline.timedMetadataTimestampRolloverStream = new m2ts_1.TimestampRolloverStream('timed-metadata'); + pipeline.adtsStream = new adts(); + pipeline.h264Stream = new H264Stream(); + pipeline.captionStream = new m2ts_1.CaptionStream(); + pipeline.coalesceStream = new _CoalesceStream(options, pipeline.metadataStream); + pipeline.headOfPipeline = pipeline.packetStream; + + // disassemble MPEG2-TS packets into elementary streams + pipeline.packetStream.pipe(pipeline.parseStream).pipe(pipeline.elementaryStream); + + // !!THIS ORDER IS IMPORTANT!! + // demux the streams + pipeline.elementaryStream.pipe(pipeline.videoTimestampRolloverStream).pipe(pipeline.h264Stream); + pipeline.elementaryStream.pipe(pipeline.audioTimestampRolloverStream).pipe(pipeline.adtsStream); + + pipeline.elementaryStream.pipe(pipeline.timedMetadataTimestampRolloverStream).pipe(pipeline.metadataStream).pipe(pipeline.coalesceStream); + + // Hook up CEA-608/708 caption stream + pipeline.h264Stream.pipe(pipeline.captionStream).pipe(pipeline.coalesceStream); + + pipeline.elementaryStream.on('data', function (data) { + var i; + + if (data.type === 'metadata') { + i = data.tracks.length; + + // scan the tracks listed in the metadata + while (i--) { + if (!videoTrack && data.tracks[i].type === 'video') { + videoTrack = data.tracks[i]; + videoTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime; + } else if (!audioTrack && data.tracks[i].type === 'audio') { + audioTrack = data.tracks[i]; + audioTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime; + } + } + + // hook up the video segment stream to the first track with h264 data + if (videoTrack && !pipeline.videoSegmentStream) { + pipeline.coalesceStream.numberOfTracks++; + pipeline.videoSegmentStream = new _VideoSegmentStream(videoTrack, options); + + pipeline.videoSegmentStream.on('timelineStartInfo', function (timelineStartInfo) { + // When video emits timelineStartInfo data after a flush, we forward that + // info to the AudioSegmentStream, if it exists, because video timeline + // data takes precedence. + if (audioTrack) { + audioTrack.timelineStartInfo = timelineStartInfo; + // On the first segment we trim AAC frames that exist before the + // very earliest DTS we have seen in video because Chrome will + // interpret any video track with a baseMediaDecodeTime that is + // non-zero as a gap. + pipeline.audioSegmentStream.setEarliestDts(timelineStartInfo.dts); + } + }); + + pipeline.videoSegmentStream.on('processedGopsInfo', self.trigger.bind(self, 'gopInfo')); + + pipeline.videoSegmentStream.on('baseMediaDecodeTime', function (baseMediaDecodeTime) { + if (audioTrack) { + pipeline.audioSegmentStream.setVideoBaseMediaDecodeTime(baseMediaDecodeTime); + } + }); + + // Set up the final part of the video pipeline + pipeline.h264Stream.pipe(pipeline.videoSegmentStream).pipe(pipeline.coalesceStream); + } + + if (audioTrack && !pipeline.audioSegmentStream) { + // hook up the audio segment stream to the first track with aac data + pipeline.coalesceStream.numberOfTracks++; + pipeline.audioSegmentStream = new _AudioSegmentStream(audioTrack, options); + + // Set up the final part of the audio pipeline + pipeline.adtsStream.pipe(pipeline.audioSegmentStream).pipe(pipeline.coalesceStream); + } + } + }); + + // Re-emit any data coming from the coalesce stream to the outside world + pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data')); + // Let the consumer know we have finished flushing the entire pipeline + pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done')); + }; + + // hook up the segment streams once track metadata is delivered + this.setBaseMediaDecodeTime = function (baseMediaDecodeTime) { + var pipeline = this.transmuxPipeline_; + + this.baseMediaDecodeTime = baseMediaDecodeTime; + if (audioTrack) { + audioTrack.timelineStartInfo.dts = undefined; + audioTrack.timelineStartInfo.pts = undefined; + clearDtsInfo(audioTrack); + audioTrack.timelineStartInfo.baseMediaDecodeTime = baseMediaDecodeTime; + if (pipeline.audioTimestampRolloverStream) { + pipeline.audioTimestampRolloverStream.discontinuity(); + } + } + if (videoTrack) { + if (pipeline.videoSegmentStream) { + pipeline.videoSegmentStream.gopCache_ = []; + pipeline.videoTimestampRolloverStream.discontinuity(); + } + videoTrack.timelineStartInfo.dts = undefined; + videoTrack.timelineStartInfo.pts = undefined; + clearDtsInfo(videoTrack); + pipeline.captionStream.reset(); + videoTrack.timelineStartInfo.baseMediaDecodeTime = baseMediaDecodeTime; + } + + if (pipeline.timedMetadataTimestampRolloverStream) { + pipeline.timedMetadataTimestampRolloverStream.discontinuity(); + } + }; + + this.setAudioAppendStart = function (timestamp) { + if (audioTrack) { + this.transmuxPipeline_.audioSegmentStream.setAudioAppendStart(timestamp); + } + }; + + this.alignGopsWith = function (gopsToAlignWith) { + if (videoTrack && this.transmuxPipeline_.videoSegmentStream) { + this.transmuxPipeline_.videoSegmentStream.alignGopsWith(gopsToAlignWith); + } + }; + + // feed incoming data to the front of the parsing pipeline + this.push = function (data) { + if (hasFlushed) { + var isAac = isLikelyAacData(data); + + if (isAac && this.transmuxPipeline_.type !== 'aac') { + this.setupAacPipeline(); + } else if (!isAac && this.transmuxPipeline_.type !== 'ts') { + this.setupTsPipeline(); + } + hasFlushed = false; + } + this.transmuxPipeline_.headOfPipeline.push(data); + }; + + // flush any buffered data + this.flush = function () { + hasFlushed = true; + // Start at the top of the pipeline and flush all pending work + this.transmuxPipeline_.headOfPipeline.flush(); + }; + + // Caption data has to be reset when seeking outside buffered range + this.resetCaptions = function () { + if (this.transmuxPipeline_.captionStream) { + this.transmuxPipeline_.captionStream.reset(); + } + }; + }; + _Transmuxer.prototype = new stream(); + + var transmuxer = { + Transmuxer: _Transmuxer, + VideoSegmentStream: _VideoSegmentStream, + AudioSegmentStream: _AudioSegmentStream, + AUDIO_PROPERTIES: AUDIO_PROPERTIES, + VIDEO_PROPERTIES: VIDEO_PROPERTIES + }; + + var mp4 = { + generator: mp4Generator, + Transmuxer: transmuxer.Transmuxer, + AudioSegmentStream: transmuxer.AudioSegmentStream, + VideoSegmentStream: transmuxer.VideoSegmentStream + }; + + var classCallCheck$$1 = function classCallCheck$$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + var createClass$$1 = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + /** + * @file transmuxer-worker.js + */ + + /** + * Re-emits transmuxer events by converting them into messages to the + * world outside the worker. + * + * @param {Object} transmuxer the transmuxer to wire events on + * @private + */ + var wireTransmuxerEvents = function wireTransmuxerEvents(transmuxer) { + transmuxer.on('data', function (segment) { + // transfer ownership of the underlying ArrayBuffer + // instead of doing a copy to save memory + // ArrayBuffers are transferable but generic TypedArrays are not + // @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects) + var initArray = segment.initSegment; + + segment.initSegment = { + data: initArray.buffer, + byteOffset: initArray.byteOffset, + byteLength: initArray.byteLength + }; + + var typedArray = segment.data; + + segment.data = typedArray.buffer; + window_1$$1.postMessage({ + action: 'data', + segment: segment, + byteOffset: typedArray.byteOffset, + byteLength: typedArray.byteLength + }, [segment.data]); + }); + + if (transmuxer.captionStream) { + transmuxer.captionStream.on('data', function (caption) { + window_1$$1.postMessage({ + action: 'caption', + data: caption + }); + }); + } + + transmuxer.on('done', function (data) { + window_1$$1.postMessage({action: 'done'}); + }); + + transmuxer.on('gopInfo', function (gopInfo) { + window_1$$1.postMessage({ + action: 'gopInfo', + gopInfo: gopInfo + }); + }); + }; + + /** + * All incoming messages route through this hash. If no function exists + * to handle an incoming message, then we ignore the message. + * + * @class MessageHandlers + * @param {Object} options the options to initialize with + */ + + var MessageHandlers = function () { + function MessageHandlers(options) { + classCallCheck$$1(this, MessageHandlers); + + this.options = options || {}; + this.init(); + } + + /** + * initialize our web worker and wire all the events. + */ + + createClass$$1(MessageHandlers, [{ + key: 'init', + value: function init() { + if (this.transmuxer) { + this.transmuxer.dispose(); + } + this.transmuxer = new mp4.Transmuxer(this.options); + wireTransmuxerEvents(this.transmuxer); + } + + /** + * Adds data (a ts segment) to the start of the transmuxer pipeline for + * processing. + * + * @param {ArrayBuffer} data data to push into the muxer + */ + + }, { + key: 'push', + value: function push(data) { + // Cast array buffer to correct type for transmuxer + var segment = new Uint8Array(data.data, data.byteOffset, data.byteLength); + + this.transmuxer.push(segment); + } + + /** + * Recreate the transmuxer so that the next segment added via `push` + * start with a fresh transmuxer. + */ + + }, { + key: 'reset', + value: function reset() { + this.init(); + } + + /** + * Set the value that will be used as the `baseMediaDecodeTime` time for the + * next segment pushed in. Subsequent segments will have their `baseMediaDecodeTime` + * set relative to the first based on the PTS values. + * + * @param {Object} data used to set the timestamp offset in the muxer + */ + + }, { + key: 'setTimestampOffset', + value: function setTimestampOffset(data) { + var timestampOffset = data.timestampOffset || 0; + + this.transmuxer.setBaseMediaDecodeTime(Math.round(timestampOffset * 90000)); + } + }, { + key: 'setAudioAppendStart', + value: function setAudioAppendStart(data) { + this.transmuxer.setAudioAppendStart(Math.ceil(data.appendStart * 90000)); + } + + /** + * Forces the pipeline to finish processing the last segment and emit it's + * results. + * + * @param {Object} data event data, not really used + */ + + }, { + key: 'flush', + value: function flush(data) { + this.transmuxer.flush(); + } + }, { + key: 'resetCaptions', + value: function resetCaptions() { + this.transmuxer.resetCaptions(); + } + }, { + key: 'alignGopsWith', + value: function alignGopsWith(data) { + this.transmuxer.alignGopsWith(data.gopsToAlignWith.slice()); + } + }]); + return MessageHandlers; + }(); + + /** + * Our web wroker interface so that things can talk to mux.js + * that will be running in a web worker. the scope is passed to this by + * webworkify. + * + * @param {Object} self the scope for the web worker + */ + + var TransmuxerWorker = function TransmuxerWorker(self) { + self.onmessage = function (event) { + if (event.data.action === 'init' && event.data.options) { + this.messageHandlers = new MessageHandlers(event.data.options); + return; + } + + if (!this.messageHandlers) { + this.messageHandlers = new MessageHandlers(); + } + + if (event.data && event.data.action && event.data.action !== 'init') { + if (this.messageHandlers[event.data.action]) { + this.messageHandlers[event.data.action](event.data); + } + } + }; + }; + + var transmuxerWorker = new TransmuxerWorker(self); + + return transmuxerWorker; + }(); + }); + + /** + * @file codec-utils.js + */ + + /** + * Check if a codec string refers to an audio codec. + * + * @param {String} codec codec string to check + * @return {Boolean} if this is an audio codec + * @private + */ + var isAudioCodec = function isAudioCodec(codec) { + return (/mp4a\.\d+.\d+/i.test(codec) + ); + }; + + /** + * Check if a codec string refers to a video codec. + * + * @param {String} codec codec string to check + * @return {Boolean} if this is a video codec + * @private + */ + var isVideoCodec = function isVideoCodec(codec) { + return (/avc1\.[\da-f]+/i.test(codec) + ); + }; + + /** + * Parse a content type header into a type and parameters + * object + * + * @param {String} type the content type header + * @return {Object} the parsed content-type + * @private + */ + var parseContentType = function parseContentType(type) { + var object = {type: '', parameters: {}}; + var parameters = type.trim().split(';'); + + // first parameter should always be content-type + object.type = parameters.shift().trim(); + parameters.forEach(function (parameter) { + var pair = parameter.trim().split('='); + + if (pair.length > 1) { + var name = pair[0].replace(/"/g, '').trim(); + var value = pair[1].replace(/"/g, '').trim(); + + object.parameters[name] = value; + } + }); + + return object; + }; + + /** + * Replace the old apple-style `avc1.<dd>.<dd>` codec string with the standard + * `avc1.<hhhhhh>` + * + * @param {Array} codecs an array of codec strings to fix + * @return {Array} the translated codec array + * @private + */ + var translateLegacyCodecs = function translateLegacyCodecs(codecs) { + return codecs.map(function (codec) { + return codec.replace(/avc1\.(\d+)\.(\d+)/i, function (orig, profile, avcLevel) { + var profileHex = ('00' + Number(profile).toString(16)).slice(-2); + var avcLevelHex = ('00' + Number(avcLevel).toString(16)).slice(-2); + + return 'avc1.' + profileHex + '00' + avcLevelHex; + }); + }); + }; + + /** + * @file virtual-source-buffer.js + */ + + // We create a wrapper around the SourceBuffer so that we can manage the + // state of the `updating` property manually. We have to do this because + // Firefox changes `updating` to false long before triggering `updateend` + // events and that was causing strange problems in videojs-contrib-hls + var makeWrappedSourceBuffer = function makeWrappedSourceBuffer(mediaSource, mimeType) { + var sourceBuffer = mediaSource.addSourceBuffer(mimeType); + var wrapper = Object.create(null); + + wrapper.updating = false; + wrapper.realBuffer_ = sourceBuffer; + + var _loop = function _loop(key) { + if (typeof sourceBuffer[key] === 'function') { + wrapper[key] = function () { + return sourceBuffer[key].apply(sourceBuffer, arguments); + }; + } else if (typeof wrapper[key] === 'undefined') { + Object.defineProperty(wrapper, key, { + get: function get$$1() { + return sourceBuffer[key]; + }, + set: function set$$1(v) { + return sourceBuffer[key] = v; + } + }); + } + }; + + for (var key in sourceBuffer) { + _loop(key); + } + + return wrapper; + }; + + /** + * Returns a list of gops in the buffer that have a pts value of 3 seconds or more in + * front of current time. + * + * @param {Array} buffer + * The current buffer of gop information + * @param {Player} player + * The player instance + * @param {Double} mapping + * Offset to map display time to stream presentation time + * @return {Array} + * List of gops considered safe to append over + */ + var gopsSafeToAlignWith = function gopsSafeToAlignWith(buffer, player, mapping) { + if (!player || !buffer.length) { + return []; + } + + // pts value for current time + 3 seconds to give a bit more wiggle room + var currentTimePts = Math.ceil((player.currentTime() - mapping + 3) * 90000); + + var i = void 0; + + for (i = 0; i < buffer.length; i++) { + if (buffer[i].pts > currentTimePts) { + break; + } + } + + return buffer.slice(i); + }; + + /** + * Appends gop information (timing and byteLength) received by the transmuxer for the + * gops appended in the last call to appendBuffer + * + * @param {Array} buffer + * The current buffer of gop information + * @param {Array} gops + * List of new gop information + * @param {boolean} replace + * If true, replace the buffer with the new gop information. If false, append the + * new gop information to the buffer in the right location of time. + * @return {Array} + * Updated list of gop information + */ + var updateGopBuffer = function updateGopBuffer(buffer, gops, replace) { + if (!gops.length) { + return buffer; + } + + if (replace) { + // If we are in safe append mode, then completely overwrite the gop buffer + // with the most recent appeneded data. This will make sure that when appending + // future segments, we only try to align with gops that are both ahead of current + // time and in the last segment appended. + return gops.slice(); + } + + var start = gops[0].pts; + + var i = 0; + + for (i; i < buffer.length; i++) { + if (buffer[i].pts >= start) { + break; + } + } + + return buffer.slice(0, i).concat(gops); + }; + + /** + * Removes gop information in buffer that overlaps with provided start and end + * + * @param {Array} buffer + * The current buffer of gop information + * @param {Double} start + * position to start the remove at + * @param {Double} end + * position to end the remove at + * @param {Double} mapping + * Offset to map display time to stream presentation time + */ + var removeGopBuffer = function removeGopBuffer(buffer, start, end, mapping) { + var startPts = Math.ceil((start - mapping) * 90000); + var endPts = Math.ceil((end - mapping) * 90000); + var updatedBuffer = buffer.slice(); + + var i = buffer.length; + + while (i--) { + if (buffer[i].pts <= endPts) { + break; + } + } + + if (i === -1) { + // no removal because end of remove range is before start of buffer + return updatedBuffer; + } + + var j = i + 1; + + while (j--) { + if (buffer[j].pts <= startPts) { + break; + } + } + + // clamp remove range start to 0 index + j = Math.max(j, 0); + + updatedBuffer.splice(j, i - j + 1); + + return updatedBuffer; + }; + + /** + * VirtualSourceBuffers exist so that we can transmux non native formats + * into a native format, but keep the same api as a native source buffer. + * It creates a transmuxer, that works in its own thread (a web worker) and + * that transmuxer muxes the data into a native format. VirtualSourceBuffer will + * then send all of that data to the naive sourcebuffer so that it is + * indestinguishable from a natively supported format. + * + * @param {HtmlMediaSource} mediaSource the parent mediaSource + * @param {Array} codecs array of codecs that we will be dealing with + * @class VirtualSourceBuffer + * @extends video.js.EventTarget + */ + + var VirtualSourceBuffer = function (_videojs$EventTarget) { + inherits(VirtualSourceBuffer, _videojs$EventTarget); + + function VirtualSourceBuffer(mediaSource, codecs) { + classCallCheck(this, VirtualSourceBuffer); + + var _this7 = possibleConstructorReturn(this, _videojs$EventTarget.call(this, videojs$1.EventTarget)); + + _this7.timestampOffset_ = 0; + _this7.pendingBuffers_ = []; + _this7.bufferUpdating_ = false; + + _this7.mediaSource_ = mediaSource; + _this7.codecs_ = codecs; + _this7.audioCodec_ = null; + _this7.videoCodec_ = null; + _this7.audioDisabled_ = false; + _this7.appendAudioInitSegment_ = true; + _this7.gopBuffer_ = []; + _this7.timeMapping_ = 0; + _this7.safeAppend_ = videojs$1.browser.IE_VERSION >= 11; + + var options = { + remux: false, + alignGopsAtEnd: _this7.safeAppend_ + }; + + _this7.codecs_.forEach(function (codec) { + if (isAudioCodec(codec)) { + _this7.audioCodec_ = codec; + } else if (isVideoCodec(codec)) { + _this7.videoCodec_ = codec; + } + }); + + // append muxed segments to their respective native buffers as + // soon as they are available + _this7.transmuxer_ = new TransmuxWorker(); + _this7.transmuxer_.postMessage({action: 'init', options: options}); + + _this7.transmuxer_.onmessage = function (event) { + if (event.data.action === 'data') { + return _this7.data_(event); + } + + if (event.data.action === 'done') { + return _this7.done_(event); + } + + if (event.data.action === 'gopInfo') { + return _this7.appendGopInfo_(event); + } + }; + + // this timestampOffset is a property with the side-effect of resetting + // baseMediaDecodeTime in the transmuxer on the setter + Object.defineProperty(_this7, 'timestampOffset', { + get: function get$$1() { + return this.timestampOffset_; + }, + set: function set$$1(val) { + if (typeof val === 'number' && val >= 0) { + this.timestampOffset_ = val; + this.appendAudioInitSegment_ = true; + + // reset gop buffer on timestampoffset as this signals a change in timeline + this.gopBuffer_.length = 0; + this.timeMapping_ = 0; + + // We have to tell the transmuxer to set the baseMediaDecodeTime to + // the desired timestampOffset for the next segment + this.transmuxer_.postMessage({ + action: 'setTimestampOffset', + timestampOffset: val + }); + } + } + }); + + // setting the append window affects both source buffers + Object.defineProperty(_this7, 'appendWindowStart', { + get: function get$$1() { + return (this.videoBuffer_ || this.audioBuffer_).appendWindowStart; + }, + set: function set$$1(start) { + if (this.videoBuffer_) { + this.videoBuffer_.appendWindowStart = start; + } + if (this.audioBuffer_) { + this.audioBuffer_.appendWindowStart = start; + } + } + }); + + // this buffer is "updating" if either of its native buffers are + Object.defineProperty(_this7, 'updating', { + get: function get$$1() { + return !!(this.bufferUpdating_ || !this.audioDisabled_ && this.audioBuffer_ && this.audioBuffer_.updating || this.videoBuffer_ && this.videoBuffer_.updating); + } + }); + + // the buffered property is the intersection of the buffered + // ranges of the native source buffers + Object.defineProperty(_this7, 'buffered', { + get: function get$$1() { + var start = null; + var end = null; + var arity = 0; + var extents = []; + var ranges = []; + + // neither buffer has been created yet + if (!this.videoBuffer_ && !this.audioBuffer_) { + return videojs$1.createTimeRange(); + } + + // only one buffer is configured + if (!this.videoBuffer_) { + return this.audioBuffer_.buffered; + } + if (!this.audioBuffer_) { + return this.videoBuffer_.buffered; + } + + // both buffers are configured + if (this.audioDisabled_) { + return this.videoBuffer_.buffered; + } + + // both buffers are empty + if (this.videoBuffer_.buffered.length === 0 && this.audioBuffer_.buffered.length === 0) { + return videojs$1.createTimeRange(); + } + + // Handle the case where we have both buffers and create an + // intersection of the two + var videoBuffered = this.videoBuffer_.buffered; + var audioBuffered = this.audioBuffer_.buffered; + var count = videoBuffered.length; + + // A) Gather up all start and end times + while (count--) { + extents.push({time: videoBuffered.start(count), type: 'start'}); + extents.push({time: videoBuffered.end(count), type: 'end'}); + } + count = audioBuffered.length; + while (count--) { + extents.push({time: audioBuffered.start(count), type: 'start'}); + extents.push({time: audioBuffered.end(count), type: 'end'}); + } + // B) Sort them by time + extents.sort(function (a, b) { + return a.time - b.time; + }); + + // C) Go along one by one incrementing arity for start and decrementing + // arity for ends + for (count = 0; count < extents.length; count++) { + if (extents[count].type === 'start') { + arity++; + + // D) If arity is ever incremented to 2 we are entering an + // overlapping range + if (arity === 2) { + start = extents[count].time; + } + } else if (extents[count].type === 'end') { + arity--; + + // E) If arity is ever decremented to 1 we leaving an + // overlapping range + if (arity === 1) { + end = extents[count].time; + } + } + + // F) Record overlapping ranges + if (start !== null && end !== null) { + ranges.push([start, end]); + start = null; + end = null; + } + } + + return videojs$1.createTimeRanges(ranges); + } + }); + return _this7; + } + + /** + * When we get a data event from the transmuxer + * we call this function and handle the data that + * was sent to us + * + * @private + * @param {Event} event the data event from the transmuxer + */ + + + VirtualSourceBuffer.prototype.data_ = function data_(event) { + var segment = event.data.segment; + + // Cast ArrayBuffer to TypedArray + segment.data = new Uint8Array(segment.data, event.data.byteOffset, event.data.byteLength); + + segment.initSegment = new Uint8Array(segment.initSegment.data, segment.initSegment.byteOffset, segment.initSegment.byteLength); + + createTextTracksIfNecessary(this, this.mediaSource_, segment); + + // Add the segments to the pendingBuffers array + this.pendingBuffers_.push(segment); + return; + }; + + /** + * When we get a done event from the transmuxer + * we call this function and we process all + * of the pending data that we have been saving in the + * data_ function + * + * @private + * @param {Event} event the done event from the transmuxer + */ + + + VirtualSourceBuffer.prototype.done_ = function done_(event) { + // Don't process and append data if the mediaSource is closed + if (this.mediaSource_.readyState === 'closed') { + this.pendingBuffers_.length = 0; + return; + } + + // All buffers should have been flushed from the muxer + // start processing anything we have received + this.processPendingSegments_(); + return; + }; + + /** + * Create our internal native audio/video source buffers and add + * event handlers to them with the following conditions: + * 1. they do not already exist on the mediaSource + * 2. this VSB has a codec for them + * + * @private + */ + + + VirtualSourceBuffer.prototype.createRealSourceBuffers_ = function createRealSourceBuffers_() { + var _this8 = this; + + var types = ['audio', 'video']; + + types.forEach(function (type) { + // Don't create a SourceBuffer of this type if we don't have a + // codec for it + if (!_this8[type + 'Codec_']) { + return; + } + + // Do nothing if a SourceBuffer of this type already exists + if (_this8[type + 'Buffer_']) { + return; + } + + var buffer = null; + + // If the mediasource already has a SourceBuffer for the codec + // use that + if (_this8.mediaSource_[type + 'Buffer_']) { + buffer = _this8.mediaSource_[type + 'Buffer_']; + // In multiple audio track cases, the audio source buffer is disabled + // on the main VirtualSourceBuffer by the HTMLMediaSource much earlier + // than createRealSourceBuffers_ is called to create the second + // VirtualSourceBuffer because that happens as a side-effect of + // videojs-contrib-hls starting the audioSegmentLoader. As a result, + // the audioBuffer is essentially "ownerless" and no one will toggle + // the `updating` state back to false once the `updateend` event is received + // + // Setting `updating` to false manually will work around this + // situation and allow work to continue + buffer.updating = false; + } else { + var codecProperty = type + 'Codec_'; + var mimeType = type + '/mp4;codecs="' + _this8[codecProperty] + '"'; + + buffer = makeWrappedSourceBuffer(_this8.mediaSource_.nativeMediaSource_, mimeType); + + _this8.mediaSource_[type + 'Buffer_'] = buffer; + } + + _this8[type + 'Buffer_'] = buffer; + + // Wire up the events to the SourceBuffer + ['update', 'updatestart', 'updateend'].forEach(function (event) { + buffer.addEventListener(event, function () { + // if audio is disabled + if (type === 'audio' && _this8.audioDisabled_) { + return; + } + + if (event === 'updateend') { + _this8[type + 'Buffer_'].updating = false; + } + + var shouldTrigger = types.every(function (t) { + // skip checking audio's updating status if audio + // is not enabled + if (t === 'audio' && _this8.audioDisabled_) { + return true; + } + // if the other type if updating we don't trigger + if (type !== t && _this8[t + 'Buffer_'] && _this8[t + 'Buffer_'].updating) { + return false; + } + return true; + }); + + if (shouldTrigger) { + return _this8.trigger(event); + } + }); + }); + }); + }; + + /** + * Emulate the native mediasource function, but our function will + * send all of the proposed segments to the transmuxer so that we + * can transmux them before we append them to our internal + * native source buffers in the correct format. + * + * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/appendBuffer + * @param {Uint8Array} segment the segment to append to the buffer + */ + + + VirtualSourceBuffer.prototype.appendBuffer = function appendBuffer(segment) { + // Start the internal "updating" state + this.bufferUpdating_ = true; + + if (this.audioBuffer_ && this.audioBuffer_.buffered.length) { + var audioBuffered = this.audioBuffer_.buffered; + + this.transmuxer_.postMessage({ + action: 'setAudioAppendStart', + appendStart: audioBuffered.end(audioBuffered.length - 1) + }); + } + + if (this.videoBuffer_) { + this.transmuxer_.postMessage({ + action: 'alignGopsWith', + gopsToAlignWith: gopsSafeToAlignWith(this.gopBuffer_, this.mediaSource_.player_, this.timeMapping_) + }); + } + + this.transmuxer_.postMessage({ + action: 'push', + // Send the typed-array of data as an ArrayBuffer so that + // it can be sent as a "Transferable" and avoid the costly + // memory copy + data: segment.buffer, + + // To recreate the original typed-array, we need information + // about what portion of the ArrayBuffer it was a view into + byteOffset: segment.byteOffset, + byteLength: segment.byteLength + }, [segment.buffer]); + this.transmuxer_.postMessage({action: 'flush'}); + }; + + /** + * Appends gop information (timing and byteLength) received by the transmuxer for the + * gops appended in the last call to appendBuffer + * + * @param {Event} event + * The gopInfo event from the transmuxer + * @param {Array} event.data.gopInfo + * List of gop info to append + */ + + + VirtualSourceBuffer.prototype.appendGopInfo_ = function appendGopInfo_(event) { + this.gopBuffer_ = updateGopBuffer(this.gopBuffer_, event.data.gopInfo, this.safeAppend_); + }; + + /** + * Emulate the native mediasource function and remove parts + * of the buffer from any of our internal buffers that exist + * + * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/remove + * @param {Double} start position to start the remove at + * @param {Double} end position to end the remove at + */ + + + VirtualSourceBuffer.prototype.remove = function remove(start, end) { + if (this.videoBuffer_) { + this.videoBuffer_.updating = true; + this.videoBuffer_.remove(start, end); + this.gopBuffer_ = removeGopBuffer(this.gopBuffer_, start, end, this.timeMapping_); + } + if (!this.audioDisabled_ && this.audioBuffer_) { + this.audioBuffer_.updating = true; + this.audioBuffer_.remove(start, end); + } + + // Remove Metadata Cues (id3) + removeCuesFromTrack(start, end, this.metadataTrack_); + + // Remove Any Captions + if (this.inbandTextTracks_) { + for (var track in this.inbandTextTracks_) { + removeCuesFromTrack(start, end, this.inbandTextTracks_[track]); + } + } + }; + + /** + * Process any segments that the muxer has output + * Concatenate segments together based on type and append them into + * their respective sourceBuffers + * + * @private + */ + + + VirtualSourceBuffer.prototype.processPendingSegments_ = function processPendingSegments_() { + var sortedSegments = { + video: { + segments: [], + bytes: 0 + }, + audio: { + segments: [], + bytes: 0 + }, + captions: [], + metadata: [] + }; + + // Sort segments into separate video/audio arrays and + // keep track of their total byte lengths + sortedSegments = this.pendingBuffers_.reduce(function (segmentObj, segment) { + var type = segment.type; + var data = segment.data; + var initSegment = segment.initSegment; + + segmentObj[type].segments.push(data); + segmentObj[type].bytes += data.byteLength; + + segmentObj[type].initSegment = initSegment; + + // Gather any captions into a single array + if (segment.captions) { + segmentObj.captions = segmentObj.captions.concat(segment.captions); + } + + if (segment.info) { + segmentObj[type].info = segment.info; + } + + // Gather any metadata into a single array + if (segment.metadata) { + segmentObj.metadata = segmentObj.metadata.concat(segment.metadata); + } + + return segmentObj; + }, sortedSegments); + + // Create the real source buffers if they don't exist by now since we + // finally are sure what tracks are contained in the source + if (!this.videoBuffer_ && !this.audioBuffer_) { + // Remove any codecs that may have been specified by default but + // are no longer applicable now + if (sortedSegments.video.bytes === 0) { + this.videoCodec_ = null; + } + if (sortedSegments.audio.bytes === 0) { + this.audioCodec_ = null; + } + + this.createRealSourceBuffers_(); + } + + if (sortedSegments.audio.info) { + this.mediaSource_.trigger({type: 'audioinfo', info: sortedSegments.audio.info}); + } + if (sortedSegments.video.info) { + this.mediaSource_.trigger({type: 'videoinfo', info: sortedSegments.video.info}); + } + + if (this.appendAudioInitSegment_) { + if (!this.audioDisabled_ && this.audioBuffer_) { + sortedSegments.audio.segments.unshift(sortedSegments.audio.initSegment); + sortedSegments.audio.bytes += sortedSegments.audio.initSegment.byteLength; + } + this.appendAudioInitSegment_ = false; + } + + var triggerUpdateend = false; + + // Merge multiple video and audio segments into one and append + if (this.videoBuffer_ && sortedSegments.video.bytes) { + sortedSegments.video.segments.unshift(sortedSegments.video.initSegment); + sortedSegments.video.bytes += sortedSegments.video.initSegment.byteLength; + this.concatAndAppendSegments_(sortedSegments.video, this.videoBuffer_); + // TODO: are video tracks the only ones with text tracks? + addTextTrackData(this, sortedSegments.captions, sortedSegments.metadata); + } else if (this.videoBuffer_ && (this.audioDisabled_ || !this.audioBuffer_)) { + // The transmuxer did not return any bytes of video, meaning it was all trimmed + // for gop alignment. Since we have a video buffer and audio is disabled, updateend + // will never be triggered by this source buffer, which will cause contrib-hls + // to be stuck forever waiting for updateend. If audio is not disabled, updateend + // will be triggered by the audio buffer, which will be sent upwards since the video + // buffer will not be in an updating state. + triggerUpdateend = true; + } + + if (!this.audioDisabled_ && this.audioBuffer_) { + this.concatAndAppendSegments_(sortedSegments.audio, this.audioBuffer_); + } + + this.pendingBuffers_.length = 0; + + if (triggerUpdateend) { + this.trigger('updateend'); + } + + // We are no longer in the internal "updating" state + this.bufferUpdating_ = false; + }; + + /** + * Combine all segments into a single Uint8Array and then append them + * to the destination buffer + * + * @param {Object} segmentObj + * @param {SourceBuffer} destinationBuffer native source buffer to append data to + * @private + */ + + + VirtualSourceBuffer.prototype.concatAndAppendSegments_ = function concatAndAppendSegments_(segmentObj, destinationBuffer) { + var offset = 0; + var tempBuffer = void 0; + + if (segmentObj.bytes) { + tempBuffer = new Uint8Array(segmentObj.bytes); + + // Combine the individual segments into one large typed-array + segmentObj.segments.forEach(function (segment) { + tempBuffer.set(segment, offset); + offset += segment.byteLength; + }); + + try { + destinationBuffer.updating = true; + destinationBuffer.appendBuffer(tempBuffer); + } catch (error) { + if (this.mediaSource_.player_) { + this.mediaSource_.player_.error({ + code: -3, + type: 'APPEND_BUFFER_ERR', + message: error.message, + originalError: error + }); + } + } + } + }; + + /** + * Emulate the native mediasource function. abort any soureBuffer + * actions and throw out any un-appended data. + * + * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/abort + */ + + + VirtualSourceBuffer.prototype.abort = function abort() { + if (this.videoBuffer_) { + this.videoBuffer_.abort(); + } + if (!this.audioDisabled_ && this.audioBuffer_) { + this.audioBuffer_.abort(); + } + if (this.transmuxer_) { + this.transmuxer_.postMessage({action: 'reset'}); + } + this.pendingBuffers_.length = 0; + this.bufferUpdating_ = false; + }; + + return VirtualSourceBuffer; + }(videojs$1.EventTarget); + + /** + * @file html-media-source.js + */ + + /** + * Our MediaSource implementation in HTML, mimics native + * MediaSource where/if possible. + * + * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource + * @class HtmlMediaSource + * @extends videojs.EventTarget + */ + + + var HtmlMediaSource = function (_videojs$EventTarget2) { + inherits(HtmlMediaSource, _videojs$EventTarget2); + + function HtmlMediaSource() { + classCallCheck(this, HtmlMediaSource); + + var _this9 = possibleConstructorReturn(this, _videojs$EventTarget2.call(this)); + + var property = void 0; + + _this9.nativeMediaSource_ = new window_1.MediaSource(); + // delegate to the native MediaSource's methods by default + for (property in _this9.nativeMediaSource_) { + if (!(property in HtmlMediaSource.prototype) && typeof _this9.nativeMediaSource_[property] === 'function') { + _this9[property] = _this9.nativeMediaSource_[property].bind(_this9.nativeMediaSource_); + } + } + + // emulate `duration` and `seekable` until seeking can be + // handled uniformly for live streams + // see https://github.com/w3c/media-source/issues/5 + _this9.duration_ = NaN; + Object.defineProperty(_this9, 'duration', { + get: function get$$1() { + if (this.duration_ === Infinity) { + return this.duration_; + } + return this.nativeMediaSource_.duration; + }, + set: function set$$1(duration) { + this.duration_ = duration; + if (duration !== Infinity) { + this.nativeMediaSource_.duration = duration; + return; + } + } + }); + Object.defineProperty(_this9, 'seekable', { + get: function get$$1() { + if (this.duration_ === Infinity) { + return videojs$1.createTimeRanges([[0, this.nativeMediaSource_.duration]]); + } + return this.nativeMediaSource_.seekable; + } + }); + + Object.defineProperty(_this9, 'readyState', { + get: function get$$1() { + return this.nativeMediaSource_.readyState; + } + }); + + Object.defineProperty(_this9, 'activeSourceBuffers', { + get: function get$$1() { + return this.activeSourceBuffers_; + } + }); + + // the list of virtual and native SourceBuffers created by this + // MediaSource + _this9.sourceBuffers = []; + + _this9.activeSourceBuffers_ = []; + + /** + * update the list of active source buffers based upon various + * imformation from HLS and video.js + * + * @private + */ + _this9.updateActiveSourceBuffers_ = function () { + // Retain the reference but empty the array + _this9.activeSourceBuffers_.length = 0; + + // If there is only one source buffer, then it will always be active and audio will + // be disabled based on the codec of the source buffer + if (_this9.sourceBuffers.length === 1) { + var sourceBuffer = _this9.sourceBuffers[0]; + + sourceBuffer.appendAudioInitSegment_ = true; + sourceBuffer.audioDisabled_ = !sourceBuffer.audioCodec_; + _this9.activeSourceBuffers_.push(sourceBuffer); + return; + } + + // There are 2 source buffers, a combined (possibly video only) source buffer and + // and an audio only source buffer. + // By default, the audio in the combined virtual source buffer is enabled + // and the audio-only source buffer (if it exists) is disabled. + var disableCombined = false; + var disableAudioOnly = true; + + // TODO: maybe we can store the sourcebuffers on the track objects? + // safari may do something like this + for (var i = 0; i < _this9.player_.audioTracks().length; i++) { + var track = _this9.player_.audioTracks()[i]; + + if (track.enabled && track.kind !== 'main') { + // The enabled track is an alternate audio track so disable the audio in + // the combined source buffer and enable the audio-only source buffer. + disableCombined = true; + disableAudioOnly = false; + break; + } + } + + _this9.sourceBuffers.forEach(function (sourceBuffer, index) { + /* eslinst-disable */ + // TODO once codecs are required, we can switch to using the codecs to determine + // what stream is the video stream, rather than relying on videoTracks + /* eslinst-enable */ + + sourceBuffer.appendAudioInitSegment_ = true; + + if (sourceBuffer.videoCodec_ && sourceBuffer.audioCodec_) { + // combined + sourceBuffer.audioDisabled_ = disableCombined; + } else if (sourceBuffer.videoCodec_ && !sourceBuffer.audioCodec_) { + // If the "combined" source buffer is video only, then we do not want + // disable the audio-only source buffer (this is mostly for demuxed + // audio and video hls) + sourceBuffer.audioDisabled_ = true; + disableAudioOnly = false; + } else if (!sourceBuffer.videoCodec_ && sourceBuffer.audioCodec_) { + // audio only + // In the case of audio only with alternate audio and disableAudioOnly is true + // this means we want to disable the audio on the alternate audio sourcebuffer + // but not the main "combined" source buffer. The "combined" source buffer is + // always at index 0, so this ensures audio won't be disabled in both source + // buffers. + sourceBuffer.audioDisabled_ = index ? disableAudioOnly : !disableAudioOnly; + if (sourceBuffer.audioDisabled_) { + return; + } + } + + _this9.activeSourceBuffers_.push(sourceBuffer); + }); + }; + + _this9.onPlayerMediachange_ = function () { + _this9.sourceBuffers.forEach(function (sourceBuffer) { + sourceBuffer.appendAudioInitSegment_ = true; + }); + }; + + _this9.onHlsReset_ = function () { + _this9.sourceBuffers.forEach(function (sourceBuffer) { + if (sourceBuffer.transmuxer_) { + sourceBuffer.transmuxer_.postMessage({action: 'resetCaptions'}); + } + }); + }; + + _this9.onHlsSegmentTimeMapping_ = function (event) { + _this9.sourceBuffers.forEach(function (buffer) { + return buffer.timeMapping_ = event.mapping; + }); + }; + + // Re-emit MediaSource events on the polyfill + ['sourceopen', 'sourceclose', 'sourceended'].forEach(function (eventName) { + this.nativeMediaSource_.addEventListener(eventName, this.trigger.bind(this)); + }, _this9); + + // capture the associated player when the MediaSource is + // successfully attached + _this9.on('sourceopen', function (event) { + // Get the player this MediaSource is attached to + var video = document_1.querySelector('[src="' + _this9.url_ + '"]'); + + if (!video) { + return; + } + + _this9.player_ = videojs$1(video.parentNode); + + // hls-reset is fired by videojs.Hls on to the tech after the main SegmentLoader + // resets its state and flushes the buffer + _this9.player_.tech_.on('hls-reset', _this9.onHlsReset_); + // hls-segment-time-mapping is fired by videojs.Hls on to the tech after the main + // SegmentLoader inspects an MTS segment and has an accurate stream to display + // time mapping + _this9.player_.tech_.on('hls-segment-time-mapping', _this9.onHlsSegmentTimeMapping_); + + if (_this9.player_.audioTracks && _this9.player_.audioTracks()) { + _this9.player_.audioTracks().on('change', _this9.updateActiveSourceBuffers_); + _this9.player_.audioTracks().on('addtrack', _this9.updateActiveSourceBuffers_); + _this9.player_.audioTracks().on('removetrack', _this9.updateActiveSourceBuffers_); + } + + _this9.player_.on('mediachange', _this9.onPlayerMediachange_); + }); + + _this9.on('sourceended', function (event) { + var duration = durationOfVideo(_this9.duration); + + for (var i = 0; i < _this9.sourceBuffers.length; i++) { + var sourcebuffer = _this9.sourceBuffers[i]; + var cues = sourcebuffer.metadataTrack_ && sourcebuffer.metadataTrack_.cues; + + if (cues && cues.length) { + cues[cues.length - 1].endTime = duration; + } + } + }); + + // explicitly terminate any WebWorkers that were created + // by SourceHandlers + _this9.on('sourceclose', function (event) { + this.sourceBuffers.forEach(function (sourceBuffer) { + if (sourceBuffer.transmuxer_) { + sourceBuffer.transmuxer_.terminate(); + } + }); + + this.sourceBuffers.length = 0; + if (!this.player_) { + return; + } + + if (this.player_.audioTracks && this.player_.audioTracks()) { + this.player_.audioTracks().off('change', this.updateActiveSourceBuffers_); + this.player_.audioTracks().off('addtrack', this.updateActiveSourceBuffers_); + this.player_.audioTracks().off('removetrack', this.updateActiveSourceBuffers_); + } + + // We can only change this if the player hasn't been disposed of yet + // because `off` eventually tries to use the el_ property. If it has + // been disposed of, then don't worry about it because there are no + // event handlers left to unbind anyway + if (this.player_.el_) { + this.player_.off('mediachange', this.onPlayerMediachange_); + this.player_.tech_.off('hls-reset', this.onHlsReset_); + this.player_.tech_.off('hls-segment-time-mapping', this.onHlsSegmentTimeMapping_); + } + }); + return _this9; + } + + /** + * Add a range that that can now be seeked to. + * + * @param {Double} start where to start the addition + * @param {Double} end where to end the addition + * @private + */ + + + HtmlMediaSource.prototype.addSeekableRange_ = function addSeekableRange_(start, end) { + var error = void 0; + + if (this.duration !== Infinity) { + error = new Error('MediaSource.addSeekableRange() can only be invoked ' + 'when the duration is Infinity'); + error.name = 'InvalidStateError'; + error.code = 11; + throw error; + } + + if (end > this.nativeMediaSource_.duration || isNaN(this.nativeMediaSource_.duration)) { + this.nativeMediaSource_.duration = end; + } + }; + + /** + * Add a source buffer to the media source. + * + * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/addSourceBuffer + * @param {String} type the content-type of the content + * @return {Object} the created source buffer + */ + + + HtmlMediaSource.prototype.addSourceBuffer = function addSourceBuffer(type) { + var buffer = void 0; + var parsedType = parseContentType(type); + + // Create a VirtualSourceBuffer to transmux MPEG-2 transport + // stream segments into fragmented MP4s + if (/^(video|audio)\/mp2t$/i.test(parsedType.type)) { + var codecs = []; + + if (parsedType.parameters && parsedType.parameters.codecs) { + codecs = parsedType.parameters.codecs.split(','); + codecs = translateLegacyCodecs(codecs); + codecs = codecs.filter(function (codec) { + return isAudioCodec(codec) || isVideoCodec(codec); + }); + } + + if (codecs.length === 0) { + codecs = ['avc1.4d400d', 'mp4a.40.2']; + } + + buffer = new VirtualSourceBuffer(this, codecs); + + if (this.sourceBuffers.length !== 0) { + // If another VirtualSourceBuffer already exists, then we are creating a + // SourceBuffer for an alternate audio track and therefore we know that + // the source has both an audio and video track. + // That means we should trigger the manual creation of the real + // SourceBuffers instead of waiting for the transmuxer to return data + this.sourceBuffers[0].createRealSourceBuffers_(); + buffer.createRealSourceBuffers_(); + + // Automatically disable the audio on the first source buffer if + // a second source buffer is ever created + this.sourceBuffers[0].audioDisabled_ = true; + } + } else { + // delegate to the native implementation + buffer = this.nativeMediaSource_.addSourceBuffer(type); + } + + this.sourceBuffers.push(buffer); + return buffer; + }; + + return HtmlMediaSource; + }(videojs$1.EventTarget); + + /** + * @file videojs-contrib-media-sources.js + */ + + + var urlCount = 0; + + // ------------ + // Media Source + // ------------ + + // store references to the media sources so they can be connected + // to a video element (a swf object) + // TODO: can we store this somewhere local to this module? + videojs$1.mediaSources = {}; + + /** + * Provide a method for a swf object to notify JS that a + * media source is now open. + * + * @param {String} msObjectURL string referencing the MSE Object URL + * @param {String} swfId the swf id + */ + var open = function open(msObjectURL, swfId) { + var mediaSource = videojs$1.mediaSources[msObjectURL]; + + if (mediaSource) { + mediaSource.trigger({type: 'sourceopen', swfId: swfId}); + } else { + throw new Error('Media Source not found (Video.js)'); + } + }; + + /** + * Check to see if the native MediaSource object exists and supports + * an MP4 container with both H.264 video and AAC-LC audio. + * + * @return {Boolean} if native media sources are supported + */ + var supportsNativeMediaSources = function supportsNativeMediaSources() { + return !!window_1.MediaSource && !!window_1.MediaSource.isTypeSupported && window_1.MediaSource.isTypeSupported('video/mp4;codecs="avc1.4d400d,mp4a.40.2"'); + }; + + /** + * An emulation of the MediaSource API so that we can support + * native and non-native functionality. returns an instance of + * HtmlMediaSource. + * + * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/MediaSource + */ + var MediaSource = function MediaSource() { + this.MediaSource = { + open: open, + supportsNativeMediaSources: supportsNativeMediaSources + }; + + if (supportsNativeMediaSources()) { + return new HtmlMediaSource(); + } + + throw new Error('Cannot use create a virtual MediaSource for this video'); + }; + + MediaSource.open = open; + MediaSource.supportsNativeMediaSources = supportsNativeMediaSources; + + /** + * A wrapper around the native URL for our MSE object + * implementation, this object is exposed under videojs.URL + * + * @link https://developer.mozilla.org/en-US/docs/Web/API/URL/URL + */ + var URL$1 = { + /** + * A wrapper around the native createObjectURL for our objects. + * This function maps a native or emulated mediaSource to a blob + * url so that it can be loaded into video.js + * + * @link https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL + * @param {MediaSource} object the object to create a blob url to + */ + createObjectURL: function createObjectURL(object) { + var objectUrlPrefix = 'blob:vjs-media-source/'; + var url = void 0; + + // use the native MediaSource to generate an object URL + if (object instanceof HtmlMediaSource) { + url = window_1.URL.createObjectURL(object.nativeMediaSource_); + object.url_ = url; + return url; + } + // if the object isn't an emulated MediaSource, delegate to the + // native implementation + if (!(object instanceof HtmlMediaSource)) { + url = window_1.URL.createObjectURL(object); + object.url_ = url; + return url; + } + + // build a URL that can be used to map back to the emulated + // MediaSource + url = objectUrlPrefix + urlCount; + + urlCount++; + + // setup the mapping back to object + videojs$1.mediaSources[url] = object; + + return url; + } + }; + + videojs$1.MediaSource = MediaSource; + videojs$1.URL = URL$1; + + var EventTarget$1$1 = videojs$1.EventTarget, + mergeOptions$2 = videojs$1.mergeOptions; + + /** + * Returns a new master manifest that is the result of merging an updated master manifest + * into the original version. + * + * @param {Object} oldMaster + * The old parsed mpd object + * @param {Object} newMaster + * The updated parsed mpd object + * @return {Object} + * A new object representing the original master manifest with the updated media + * playlists merged in + */ + + var updateMaster$1 = function updateMaster$1(oldMaster, newMaster) { + var update = mergeOptions$2(oldMaster, { + // These are top level properties that can be updated + duration: newMaster.duration, + minimumUpdatePeriod: newMaster.minimumUpdatePeriod + }); + + // First update the playlists in playlist list + for (var i = 0; i < newMaster.playlists.length; i++) { + var playlistUpdate = updateMaster(update, newMaster.playlists[i]); + + if (playlistUpdate) { + update = playlistUpdate; + } + } + + // Then update media group playlists + forEachMediaGroup(newMaster, function (properties, type, group, label) { + if (properties.playlists && properties.playlists.length) { + var uri = properties.playlists[0].uri; + var _playlistUpdate = updateMaster(update, properties.playlists[0]); + + if (_playlistUpdate) { + update = _playlistUpdate; + // update the playlist reference within media groups + update.mediaGroups[type][group][label].playlists[0] = update.playlists[uri]; + } + } + }); + + return update; + }; + + var DashPlaylistLoader = function (_EventTarget$) { + inherits(DashPlaylistLoader, _EventTarget$); + + // DashPlaylistLoader must accept either a src url or a playlist because subsequent + // playlist loader setups from media groups will expect to be able to pass a playlist + // (since there aren't external URLs to media playlists with DASH) + function DashPlaylistLoader(srcUrlOrPlaylist, hls, withCredentials, masterPlaylistLoader) { + classCallCheck(this, DashPlaylistLoader); + + var _this10 = possibleConstructorReturn(this, _EventTarget$.call(this)); + + _this10.hls_ = hls; + _this10.withCredentials = withCredentials; + + if (!srcUrlOrPlaylist) { + throw new Error('A non-empty playlist URL or playlist is required'); + } + + // event naming? + _this10.on('minimumUpdatePeriod', function () { + _this10.refreshXml_(); + }); + + // live playlist staleness timeout + _this10.on('mediaupdatetimeout', function () { + _this10.refreshMedia_(); + }); + + // initialize the loader state + if (typeof srcUrlOrPlaylist === 'string') { + _this10.srcUrl = srcUrlOrPlaylist; + _this10.state = 'HAVE_NOTHING'; + return possibleConstructorReturn(_this10); + } + + _this10.masterPlaylistLoader_ = masterPlaylistLoader; + + _this10.state = 'HAVE_METADATA'; + _this10.started = true; + // we only should have one playlist so select it + _this10.media(srcUrlOrPlaylist); + // trigger async to mimic behavior of HLS, where it must request a playlist + window_1.setTimeout(function () { + _this10.trigger('loadedmetadata'); + }, 0); + return _this10; + } + + DashPlaylistLoader.prototype.dispose = function dispose() { + this.stopRequest(); + window_1.clearTimeout(this.mediaUpdateTimeout); + }; + + DashPlaylistLoader.prototype.stopRequest = function stopRequest() { + if (this.request) { + var oldRequest = this.request; + + this.request = null; + oldRequest.onreadystatechange = null; + oldRequest.abort(); + } + }; + + DashPlaylistLoader.prototype.media = function media(playlist) { + // getter + if (!playlist) { + return this.media_; + } + + // setter + if (this.state === 'HAVE_NOTHING') { + throw new Error('Cannot switch media playlist from ' + this.state); + } + + var startingState = this.state; + + // find the playlist object if the target playlist has been specified by URI + if (typeof playlist === 'string') { + if (!this.master.playlists[playlist]) { + throw new Error('Unknown playlist URI: ' + playlist); + } + playlist = this.master.playlists[playlist]; + } + + var mediaChange = !this.media_ || playlist.uri !== this.media_.uri; + + this.state = 'HAVE_METADATA'; + + // switching to the active playlist is a no-op + if (!mediaChange) { + return; + } + + // switching from an already loaded playlist + if (this.media_) { + this.trigger('mediachanging'); + } + + this.media_ = playlist; + + this.refreshMedia_(); + + // trigger media change if the active media has been updated + if (startingState !== 'HAVE_MASTER') { + this.trigger('mediachange'); + } + }; + + DashPlaylistLoader.prototype.pause = function pause() { + this.stopRequest(); + if (this.state === 'HAVE_NOTHING') { + // If we pause the loader before any data has been retrieved, its as if we never + // started, so reset to an unstarted state. + this.started = false; + } + }; + + DashPlaylistLoader.prototype.load = function load() { + // because the playlists are internal to the manifest, load should either load the + // main manifest, or do nothing but trigger an event + if (!this.started) { + this.start(); + return; + } + + this.trigger('loadedplaylist'); + }; + + /** + * Parses the master xml string and updates playlist uri references + * + * @return {Object} + * The parsed mpd manifest object + */ + + + DashPlaylistLoader.prototype.parseMasterXml = function parseMasterXml() { + var master = parse(this.masterXml_, { + manifestUri: this.srcUrl, + clientOffset: this.clientOffset_ + }); + + master.uri = this.srcUrl; + + // Set up phony URIs for the playlists since we won't have external URIs for DASH + // but reference playlists by their URI throughout the project + // TODO: Should we create the dummy uris in mpd-parser as well (leaning towards yes). + for (var i = 0; i < master.playlists.length; i++) { + var phonyUri = 'placeholder-uri-' + i; + + master.playlists[i].uri = phonyUri; + // set up by URI references + master.playlists[phonyUri] = master.playlists[i]; + } + + // set up phony URIs for the media group playlists since we won't have external + // URIs for DASH but reference playlists by their URI throughout the project + forEachMediaGroup(master, function (properties, mediaType, groupKey, labelKey) { + if (properties.playlists && properties.playlists.length) { + var _phonyUri = 'placeholder-uri-' + mediaType + '-' + groupKey + '-' + labelKey; + + properties.playlists[0].uri = _phonyUri; + // setup URI references + master.playlists[_phonyUri] = properties.playlists[0]; + } + }); + + setupMediaPlaylists(master); + resolveMediaGroupUris(master); + + return master; + }; + + DashPlaylistLoader.prototype.start = function start() { + var _this11 = this; + + this.started = true; + + // request the specified URL + this.request = this.hls_.xhr({ + uri: this.srcUrl, + withCredentials: this.withCredentials + }, function (error, req) { + // disposed + if (!_this11.request) { + return; + } + + // clear the loader's request reference + _this11.request = null; + + if (error) { + _this11.error = { + status: req.status, + message: 'DASH playlist request error at URL: ' + _this11.srcUrl, + responseText: req.responseText, + // MEDIA_ERR_NETWORK + code: 2 + }; + if (_this11.state === 'HAVE_NOTHING') { + _this11.started = false; + } + return _this11.trigger('error'); + } + + _this11.masterXml_ = req.responseText; + + if (req.responseHeaders && req.responseHeaders.date) { + _this11.masterLoaded_ = Date.parse(req.responseHeaders.date); + } else { + _this11.masterLoaded_ = Date.now(); + } + + _this11.syncClientServerClock_(_this11.onClientServerClockSync_.bind(_this11)); + }); + }; + + /** + * Parses the master xml for UTCTiming node to sync the client clock to the server + * clock. If the UTCTiming node requires a HEAD or GET request, that request is made. + * + * @param {Function} done + * Function to call when clock sync has completed + */ + + + DashPlaylistLoader.prototype.syncClientServerClock_ = function syncClientServerClock_(done) { + var _this12 = this; + + var utcTiming = parseUTCTiming(this.masterXml_); + + // No UTCTiming element found in the mpd. Use Date header from mpd request as the + // server clock + if (utcTiming === null) { + this.clientOffset_ = this.masterLoaded_ - Date.now(); + return done(); + } + + if (utcTiming.method === 'DIRECT') { + this.clientOffset_ = utcTiming.value - Date.now(); + return done(); + } + + this.request = this.hls_.xhr({ + uri: resolveUrl$1(this.srcUrl, utcTiming.value), + method: utcTiming.method, + withCredentials: this.withCredentials + }, function (error, req) { + // disposed + if (!_this12.request) { + return; + } + + if (error) { + // sync request failed, fall back to using date header from mpd + // TODO: log warning + _this12.clientOffset_ = _this12.masterLoaded_ - Date.now(); + return done(); + } + + var serverTime = void 0; + + if (utcTiming.method === 'HEAD') { + if (!req.responseHeaders || !req.responseHeaders.date) { + // expected date header not preset, fall back to using date header from mpd + // TODO: log warning + serverTime = _this12.masterLoaded_; + } else { + serverTime = Date.parse(req.responseHeaders.date); + } + } else { + serverTime = Date.parse(req.responseText); + } + + _this12.clientOffset_ = serverTime - Date.now(); + + done(); + }); + }; + + /** + * Handler for after client/server clock synchronization has happened. Sets up + * xml refresh timer if specificed by the manifest. + */ + + + DashPlaylistLoader.prototype.onClientServerClockSync_ = function onClientServerClockSync_() { + var _this13 = this; + + this.master = this.parseMasterXml(); + + this.state = 'HAVE_MASTER'; + + this.trigger('loadedplaylist'); + + if (!this.media_) { + // no media playlist was specifically selected so start + // from the first listed one + this.media(this.master.playlists[0]); + } + // trigger loadedmetadata to resolve setup of media groups + // trigger async to mimic behavior of HLS, where it must request a playlist + window_1.setTimeout(function () { + _this13.trigger('loadedmetadata'); + }, 0); + + // TODO: minimumUpdatePeriod can have a value of 0. Currently the manifest will not + // be refreshed when this is the case. The inter-op guide says that when the + // minimumUpdatePeriod is 0, the manifest should outline all currently available + // segments, but future segments may require an update. I think a good solution + // would be to update the manifest at the same rate that the media playlists + // are "refreshed", i.e. every targetDuration. + if (this.master.minimumUpdatePeriod) { + window_1.setTimeout(function () { + _this13.trigger('minimumUpdatePeriod'); + }, this.master.minimumUpdatePeriod); + } + }; + + /** + * Sends request to refresh the master xml and updates the parsed master manifest + * TODO: Does the client offset need to be recalculated when the xml is refreshed? + */ + + + DashPlaylistLoader.prototype.refreshXml_ = function refreshXml_() { + var _this14 = this; + + this.request = this.hls_.xhr({ + uri: this.srcUrl, + withCredentials: this.withCredentials + }, function (error, req) { + // disposed + if (!_this14.request) { + return; + } + + // clear the loader's request reference + _this14.request = null; + + if (error) { + _this14.error = { + status: req.status, + message: 'DASH playlist request error at URL: ' + _this14.srcUrl, + responseText: req.responseText, + // MEDIA_ERR_NETWORK + code: 2 + }; + if (_this14.state === 'HAVE_NOTHING') { + _this14.started = false; + } + return _this14.trigger('error'); + } + + _this14.masterXml_ = req.responseText; + + var newMaster = _this14.parseMasterXml(); + + _this14.master = updateMaster$1(_this14.master, newMaster); + + window_1.setTimeout(function () { + _this14.trigger('minimumUpdatePeriod'); + }, _this14.master.minimumUpdatePeriod); + }); + }; + + /** + * Refreshes the media playlist by re-parsing the master xml and updating playlist + * references. If this is an alternate loader, the updated parsed manifest is retrieved + * from the master loader. + */ + + + DashPlaylistLoader.prototype.refreshMedia_ = function refreshMedia_() { + var _this15 = this; + + var oldMaster = void 0; + var newMaster = void 0; + + if (this.masterPlaylistLoader_) { + oldMaster = this.masterPlaylistLoader_.master; + newMaster = this.masterPlaylistLoader_.parseMasterXml(); + } else { + oldMaster = this.master; + newMaster = this.parseMasterXml(); + } + + var updatedMaster = updateMaster$1(oldMaster, newMaster); + + if (updatedMaster) { + if (this.masterPlaylistLoader_) { + this.masterPlaylistLoader_.master = updatedMaster; + } else { + this.master = updatedMaster; + } + this.media_ = updatedMaster.playlists[this.media_.uri]; + } else { + this.trigger('playlistunchanged'); + } + + if (!this.media().endList) { + this.mediaUpdateTimeout = window_1.setTimeout(function () { + _this15.trigger('mediaupdatetimeout'); + }, refreshDelay(this.media(), !!updatedMaster)); + } + + this.trigger('loadedplaylist'); + }; + + return DashPlaylistLoader; + }(EventTarget$1$1); + + var logger = function logger(source) { + if (videojs$1.log.debug) { + return videojs$1.log.debug.bind(videojs$1, 'VHS:', source + ' >'); + } + + return function () { + }; + }; + + function noop$1() { + } + + /** + * @file source-updater.js + */ + + /** + * A queue of callbacks to be serialized and applied when a + * MediaSource and its associated SourceBuffers are not in the + * updating state. It is used by the segment loader to update the + * underlying SourceBuffers when new data is loaded, for instance. + * + * @class SourceUpdater + * @param {MediaSource} mediaSource the MediaSource to create the + * SourceBuffer from + * @param {String} mimeType the desired MIME type of the underlying + * SourceBuffer + * @param {Object} sourceBufferEmitter an event emitter that fires when a source buffer is + * added to the media source + */ + + var SourceUpdater = function () { + function SourceUpdater(mediaSource, mimeType, type, sourceBufferEmitter) { + classCallCheck(this, SourceUpdater); + + this.callbacks_ = []; + this.pendingCallback_ = null; + this.timestampOffset_ = 0; + this.mediaSource = mediaSource; + this.processedAppend_ = false; + this.type_ = type; + this.mimeType_ = mimeType; + this.logger_ = logger('SourceUpdater[' + type + '][' + mimeType + ']'); + + if (mediaSource.readyState === 'closed') { + mediaSource.addEventListener('sourceopen', this.createSourceBuffer_.bind(this, mimeType, sourceBufferEmitter)); + } else { + this.createSourceBuffer_(mimeType, sourceBufferEmitter); + } + } + + SourceUpdater.prototype.createSourceBuffer_ = function createSourceBuffer_(mimeType, sourceBufferEmitter) { + var _this16 = this; + + this.sourceBuffer_ = this.mediaSource.addSourceBuffer(mimeType); + + this.logger_('created SourceBuffer'); + + if (sourceBufferEmitter) { + sourceBufferEmitter.trigger('sourcebufferadded'); + + if (this.mediaSource.sourceBuffers.length < 2) { + // There's another source buffer we must wait for before we can start updating + // our own (or else we can get into a bad state, i.e., appending video/audio data + // before the other video/audio source buffer is available and leading to a video + // or audio only buffer). + sourceBufferEmitter.on('sourcebufferadded', function () { + _this16.start_(); + }); + return; + } + } + + this.start_(); + }; + + SourceUpdater.prototype.start_ = function start_() { + var _this17 = this; + + this.started_ = true; + + // run completion handlers and process callbacks as updateend + // events fire + this.onUpdateendCallback_ = function () { + var pendingCallback = _this17.pendingCallback_; + + _this17.pendingCallback_ = null; + + _this17.logger_('buffered [' + printableRange(_this17.buffered()) + ']'); + + if (pendingCallback) { + pendingCallback(); + } + + _this17.runCallback_(); + }; + + this.sourceBuffer_.addEventListener('updateend', this.onUpdateendCallback_); + + this.runCallback_(); + }; + + /** + * Aborts the current segment and resets the segment parser. + * + * @param {Function} done function to call when done + * @see http://w3c.github.io/media-source/#widl-SourceBuffer-abort-void + */ + + + SourceUpdater.prototype.abort = function abort(done) { + var _this18 = this; + + if (this.processedAppend_) { + this.queueCallback_(function () { + _this18.sourceBuffer_.abort(); + }, done); + } + }; + + /** + * Queue an update to append an ArrayBuffer. + * + * @param {ArrayBuffer} bytes + * @param {Function} done the function to call when done + * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-appendBuffer-void-ArrayBuffer-data + */ + + + SourceUpdater.prototype.appendBuffer = function appendBuffer(bytes, done) { + var _this19 = this; + + this.processedAppend_ = true; + this.queueCallback_(function () { + _this19.sourceBuffer_.appendBuffer(bytes); + }, done); + }; + + /** + * Indicates what TimeRanges are buffered in the managed SourceBuffer. + * + * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-buffered + */ + + + SourceUpdater.prototype.buffered = function buffered() { + if (!this.sourceBuffer_) { + return videojs$1.createTimeRanges(); + } + return this.sourceBuffer_.buffered; + }; + + /** + * Queue an update to remove a time range from the buffer. + * + * @param {Number} start where to start the removal + * @param {Number} end where to end the removal + * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-remove-void-double-start-unrestricted-double-end + */ + + + SourceUpdater.prototype.remove = function remove(start, end) { + var _this20 = this; + + if (this.processedAppend_) { + this.queueCallback_(function () { + _this20.logger_('remove [' + start + ' => ' + end + ']'); + _this20.sourceBuffer_.remove(start, end); + }, noop$1); + } + }; + + /** + * Whether the underlying sourceBuffer is updating or not + * + * @return {Boolean} the updating status of the SourceBuffer + */ + + + SourceUpdater.prototype.updating = function updating() { + return !this.sourceBuffer_ || this.sourceBuffer_.updating || this.pendingCallback_; + }; + + /** + * Set/get the timestampoffset on the SourceBuffer + * + * @return {Number} the timestamp offset + */ + + + SourceUpdater.prototype.timestampOffset = function timestampOffset(offset) { + var _this21 = this; + + if (typeof offset !== 'undefined') { + this.queueCallback_(function () { + _this21.sourceBuffer_.timestampOffset = offset; + }); + this.timestampOffset_ = offset; + } + return this.timestampOffset_; + }; + + /** + * Queue a callback to run + */ + + + SourceUpdater.prototype.queueCallback_ = function queueCallback_(callback, done) { + this.callbacks_.push([callback.bind(this), done]); + this.runCallback_(); + }; + + /** + * Run a queued callback + */ + + + SourceUpdater.prototype.runCallback_ = function runCallback_() { + var callbacks = void 0; + + if (!this.updating() && this.callbacks_.length && this.started_) { + callbacks = this.callbacks_.shift(); + this.pendingCallback_ = callbacks[1]; + callbacks[0](); + } + }; + + /** + * dispose of the source updater and the underlying sourceBuffer + */ + + + SourceUpdater.prototype.dispose = function dispose() { + this.sourceBuffer_.removeEventListener('updateend', this.onUpdateendCallback_); + if (this.sourceBuffer_ && this.mediaSource.readyState === 'open') { + this.sourceBuffer_.abort(); + } + }; + + return SourceUpdater; + }(); + + var Config = { + GOAL_BUFFER_LENGTH: 30, + MAX_GOAL_BUFFER_LENGTH: 60, + GOAL_BUFFER_LENGTH_RATE: 1, + // A fudge factor to apply to advertised playlist bitrates to account for + // temporary flucations in client bandwidth + BANDWIDTH_VARIANCE: 1.2, + // How much of the buffer must be filled before we consider upswitching + BUFFER_LOW_WATER_LINE: 0, + MAX_BUFFER_LOW_WATER_LINE: 30, + BUFFER_LOW_WATER_LINE_RATE: 1 + }; + + var REQUEST_ERRORS = { + FAILURE: 2, + TIMEOUT: -101, + ABORTED: -102 + }; + + /** + * Turns segment byterange into a string suitable for use in + * HTTP Range requests + * + * @param {Object} byterange - an object with two values defining the start and end + * of a byte-range + */ + var byterangeStr = function byterangeStr(byterange) { + var byterangeStart = void 0; + var byterangeEnd = void 0; + + // `byterangeEnd` is one less than `offset + length` because the HTTP range + // header uses inclusive ranges + byterangeEnd = byterange.offset + byterange.length - 1; + byterangeStart = byterange.offset; + return 'bytes=' + byterangeStart + '-' + byterangeEnd; + }; + + /** + * Defines headers for use in the xhr request for a particular segment. + * + * @param {Object} segment - a simplified copy of the segmentInfo object + * from SegmentLoader + */ + var segmentXhrHeaders = function segmentXhrHeaders(segment) { + var headers = {}; + + if (segment.byterange) { + headers.Range = byterangeStr(segment.byterange); + } + return headers; + }; + + /** + * Abort all requests + * + * @param {Object} activeXhrs - an object that tracks all XHR requests + */ + var abortAll = function abortAll(activeXhrs) { + activeXhrs.forEach(function (xhr) { + xhr.abort(); + }); + }; + + /** + * Gather important bandwidth stats once a request has completed + * + * @param {Object} request - the XHR request from which to gather stats + */ + var getRequestStats = function getRequestStats(request) { + return { + bandwidth: request.bandwidth, + bytesReceived: request.bytesReceived || 0, + roundTripTime: request.roundTripTime || 0 + }; + }; + + /** + * If possible gather bandwidth stats as a request is in + * progress + * + * @param {Event} progressEvent - an event object from an XHR's progress event + */ + var getProgressStats = function getProgressStats(progressEvent) { + var request = progressEvent.target; + var roundTripTime = Date.now() - request.requestTime; + var stats = { + bandwidth: Infinity, + bytesReceived: 0, + roundTripTime: roundTripTime || 0 + }; + + stats.bytesReceived = progressEvent.loaded; + // This can result in Infinity if stats.roundTripTime is 0 but that is ok + // because we should only use bandwidth stats on progress to determine when + // abort a request early due to insufficient bandwidth + stats.bandwidth = Math.floor(stats.bytesReceived / stats.roundTripTime * 8 * 1000); + + return stats; + }; + + /** + * Handle all error conditions in one place and return an object + * with all the information + * + * @param {Error|null} error - if non-null signals an error occured with the XHR + * @param {Object} request - the XHR request that possibly generated the error + */ + var handleErrors = function handleErrors(error, request) { + if (request.timedout) { + return { + status: request.status, + message: 'HLS request timed-out at URL: ' + request.uri, + code: REQUEST_ERRORS.TIMEOUT, + xhr: request + }; + } + + if (request.aborted) { + return { + status: request.status, + message: 'HLS request aborted at URL: ' + request.uri, + code: REQUEST_ERRORS.ABORTED, + xhr: request + }; + } + + if (error) { + return { + status: request.status, + message: 'HLS request errored at URL: ' + request.uri, + code: REQUEST_ERRORS.FAILURE, + xhr: request + }; + } + + return null; + }; + + /** + * Handle responses for key data and convert the key data to the correct format + * for the decryption step later + * + * @param {Object} segment - a simplified copy of the segmentInfo object + * from SegmentLoader + * @param {Function} finishProcessingFn - a callback to execute to continue processing + * this request + */ + var handleKeyResponse = function handleKeyResponse(segment, finishProcessingFn) { + return function (error, request) { + var response = request.response; + var errorObj = handleErrors(error, request); + + if (errorObj) { + return finishProcessingFn(errorObj, segment); + } + + if (response.byteLength !== 16) { + return finishProcessingFn({ + status: request.status, + message: 'Invalid HLS key at URL: ' + request.uri, + code: REQUEST_ERRORS.FAILURE, + xhr: request + }, segment); + } + + var view = new DataView(response); + + segment.key.bytes = new Uint32Array([view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)]); + return finishProcessingFn(null, segment); + }; + }; + + /** + * Handle init-segment responses + * + * @param {Object} segment - a simplified copy of the segmentInfo object + * from SegmentLoader + * @param {Function} finishProcessingFn - a callback to execute to continue processing + * this request + */ + var handleInitSegmentResponse = function handleInitSegmentResponse(segment, finishProcessingFn) { + return function (error, request) { + var response = request.response; + var errorObj = handleErrors(error, request); + + if (errorObj) { + return finishProcessingFn(errorObj, segment); + } + + // stop processing if received empty content + if (response.byteLength === 0) { + return finishProcessingFn({ + status: request.status, + message: 'Empty HLS segment content at URL: ' + request.uri, + code: REQUEST_ERRORS.FAILURE, + xhr: request + }, segment); + } + + segment.map.bytes = new Uint8Array(request.response); + return finishProcessingFn(null, segment); + }; + }; + + /** + * Response handler for segment-requests being sure to set the correct + * property depending on whether the segment is encryped or not + * Also records and keeps track of stats that are used for ABR purposes + * + * @param {Object} segment - a simplified copy of the segmentInfo object + * from SegmentLoader + * @param {Function} finishProcessingFn - a callback to execute to continue processing + * this request + */ + var handleSegmentResponse = function handleSegmentResponse(segment, finishProcessingFn) { + return function (error, request) { + var response = request.response; + var errorObj = handleErrors(error, request); + + if (errorObj) { + return finishProcessingFn(errorObj, segment); + } + + // stop processing if received empty content + if (response.byteLength === 0) { + return finishProcessingFn({ + status: request.status, + message: 'Empty HLS segment content at URL: ' + request.uri, + code: REQUEST_ERRORS.FAILURE, + xhr: request + }, segment); + } + + segment.stats = getRequestStats(request); + + if (segment.key) { + segment.encryptedBytes = new Uint8Array(request.response); + } else { + segment.bytes = new Uint8Array(request.response); + } + + return finishProcessingFn(null, segment); + }; + }; + + /** + * Decrypt the segment via the decryption web worker + * + * @param {WebWorker} decrypter - a WebWorker interface to AES-128 decryption routines + * @param {Object} segment - a simplified copy of the segmentInfo object + * from SegmentLoader + * @param {Function} doneFn - a callback that is executed after decryption has completed + */ + var decryptSegment = function decryptSegment(decrypter, segment, doneFn) { + var decryptionHandler = function decryptionHandler(event) { + if (event.data.source === segment.requestId) { + decrypter.removeEventListener('message', decryptionHandler); + var decrypted = event.data.decrypted; + + segment.bytes = new Uint8Array(decrypted.bytes, decrypted.byteOffset, decrypted.byteLength); + return doneFn(null, segment); + } + }; + + decrypter.addEventListener('message', decryptionHandler); + + // this is an encrypted segment + // incrementally decrypt the segment + decrypter.postMessage(createTransferableMessage({ + source: segment.requestId, + encrypted: segment.encryptedBytes, + key: segment.key.bytes, + iv: segment.key.iv + }), [segment.encryptedBytes.buffer, segment.key.bytes.buffer]); + }; + + /** + * The purpose of this function is to get the most pertinent error from the + * array of errors. + * For instance if a timeout and two aborts occur, then the aborts were + * likely triggered by the timeout so return that error object. + */ + var getMostImportantError = function getMostImportantError(errors) { + return errors.reduce(function (prev, err) { + return err.code > prev.code ? err : prev; + }); + }; + + /** + * This function waits for all XHRs to finish (with either success or failure) + * before continueing processing via it's callback. The function gathers errors + * from each request into a single errors array so that the error status for + * each request can be examined later. + * + * @param {Object} activeXhrs - an object that tracks all XHR requests + * @param {WebWorker} decrypter - a WebWorker interface to AES-128 decryption routines + * @param {Function} doneFn - a callback that is executed after all resources have been + * downloaded and any decryption completed + */ + var waitForCompletion = function waitForCompletion(activeXhrs, decrypter, doneFn) { + var errors = []; + var count = 0; + + return function (error, segment) { + if (error) { + // If there are errors, we have to abort any outstanding requests + abortAll(activeXhrs); + errors.push(error); + } + count += 1; + + if (count === activeXhrs.length) { + // Keep track of when *all* of the requests have completed + segment.endOfAllRequests = Date.now(); + + if (errors.length > 0) { + var worstError = getMostImportantError(errors); + + return doneFn(worstError, segment); + } + if (segment.encryptedBytes) { + return decryptSegment(decrypter, segment, doneFn); + } + // Otherwise, everything is ready just continue + return doneFn(null, segment); + } + }; + }; + + /** + * Simple progress event callback handler that gathers some stats before + * executing a provided callback with the `segment` object + * + * @param {Object} segment - a simplified copy of the segmentInfo object + * from SegmentLoader + * @param {Function} progressFn - a callback that is executed each time a progress event + * is received + * @param {Event} event - the progress event object from XMLHttpRequest + */ + var handleProgress = function handleProgress(segment, progressFn) { + return function (event) { + segment.stats = videojs$1.mergeOptions(segment.stats, getProgressStats(event)); + + // record the time that we receive the first byte of data + if (!segment.stats.firstBytesReceivedAt && segment.stats.bytesReceived) { + segment.stats.firstBytesReceivedAt = Date.now(); + } + + return progressFn(event, segment); + }; + }; + + /** + * Load all resources and does any processing necessary for a media-segment + * + * Features: + * decrypts the media-segment if it has a key uri and an iv + * aborts *all* requests if *any* one request fails + * + * The segment object, at minimum, has the following format: + * { + * resolvedUri: String, + * [byterange]: { + * offset: Number, + * length: Number + * }, + * [key]: { + * resolvedUri: String + * [byterange]: { + * offset: Number, + * length: Number + * }, + * iv: { + * bytes: Uint32Array + * } + * }, + * [map]: { + * resolvedUri: String, + * [byterange]: { + * offset: Number, + * length: Number + * }, + * [bytes]: Uint8Array + * } + * } + * ...where [name] denotes optional properties + * + * @param {Function} xhr - an instance of the xhr wrapper in xhr.js + * @param {Object} xhrOptions - the base options to provide to all xhr requests + * @param {WebWorker} decryptionWorker - a WebWorker interface to AES-128 + * decryption routines + * @param {Object} segment - a simplified copy of the segmentInfo object + * from SegmentLoader + * @param {Function} progressFn - a callback that receives progress events from the main + * segment's xhr request + * @param {Function} doneFn - a callback that is executed only once all requests have + * succeeded or failed + * @returns {Function} a function that, when invoked, immediately aborts all + * outstanding requests + */ + var mediaSegmentRequest = function mediaSegmentRequest(xhr, xhrOptions, decryptionWorker, segment, progressFn, doneFn) { + var activeXhrs = []; + var finishProcessingFn = waitForCompletion(activeXhrs, decryptionWorker, doneFn); + + // optionally, request the decryption key + if (segment.key) { + var keyRequestOptions = videojs$1.mergeOptions(xhrOptions, { + uri: segment.key.resolvedUri, + responseType: 'arraybuffer' + }); + var keyRequestCallback = handleKeyResponse(segment, finishProcessingFn); + var keyXhr = xhr(keyRequestOptions, keyRequestCallback); + + activeXhrs.push(keyXhr); + } + + // optionally, request the associated media init segment + if (segment.map && !segment.map.bytes) { + var initSegmentOptions = videojs$1.mergeOptions(xhrOptions, { + uri: segment.map.resolvedUri, + responseType: 'arraybuffer', + headers: segmentXhrHeaders(segment.map) + }); + var initSegmentRequestCallback = handleInitSegmentResponse(segment, finishProcessingFn); + var initSegmentXhr = xhr(initSegmentOptions, initSegmentRequestCallback); + + activeXhrs.push(initSegmentXhr); + } + + var segmentRequestOptions = videojs$1.mergeOptions(xhrOptions, { + uri: segment.resolvedUri, + responseType: 'arraybuffer', + headers: segmentXhrHeaders(segment) + }); + var segmentRequestCallback = handleSegmentResponse(segment, finishProcessingFn); + var segmentXhr = xhr(segmentRequestOptions, segmentRequestCallback); + + segmentXhr.addEventListener('progress', handleProgress(segment, progressFn)); + activeXhrs.push(segmentXhr); + + return function () { + return abortAll(activeXhrs); + }; + }; + + /** + * @file - codecs.js - Handles tasks regarding codec strings such as translating them to + * codec strings, or translating codec strings into objects that can be examined. + */ + + // Default codec parameters if none were provided for video and/or audio + var defaultCodecs = { + videoCodec: 'avc1', + videoObjectTypeIndicator: '.4d400d', + // AAC-LC + audioProfile: '2' + }; + + /** + * Parses a codec string to retrieve the number of codecs specified, + * the video codec and object type indicator, and the audio profile. + */ + + var parseCodecs = function parseCodecs() { + var codecs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + + var result = { + codecCount: 0 + }; + var parsed = void 0; + + result.codecCount = codecs.split(',').length; + result.codecCount = result.codecCount || 2; + + // parse the video codec + parsed = /(^|\s|,)+(avc[13])([^ ,]*)/i.exec(codecs); + if (parsed) { + result.videoCodec = parsed[2]; + result.videoObjectTypeIndicator = parsed[3]; + } + + // parse the last field of the audio codec + result.audioProfile = /(^|\s|,)+mp4a.[0-9A-Fa-f]+\.([0-9A-Fa-f]+)/i.exec(codecs); + result.audioProfile = result.audioProfile && result.audioProfile[2]; + + return result; + }; + + /** + * Replace codecs in the codec string with the old apple-style `avc1.<dd>.<dd>` to the + * standard `avc1.<hhhhhh>`. + * + * @param codecString {String} the codec string + * @return {String} the codec string with old apple-style codecs replaced + * + * @private + */ + var mapLegacyAvcCodecs = function mapLegacyAvcCodecs(codecString) { + return codecString.replace(/avc1\.(\d+)\.(\d+)/i, function (match) { + return translateLegacyCodecs([match])[0]; + }); + }; + + /** + * Build a media mime-type string from a set of parameters + * @param {String} type either 'audio' or 'video' + * @param {String} container either 'mp2t' or 'mp4' + * @param {Array} codecs an array of codec strings to add + * @return {String} a valid media mime-type + */ + var makeMimeTypeString = function makeMimeTypeString(type, container, codecs) { + // The codecs array is filtered so that falsey values are + // dropped and don't cause Array#join to create spurious + // commas + return type + '/' + container + '; codecs="' + codecs.filter(function (c) { + return !!c; + }).join(', ') + '"'; + }; + + /** + * Returns the type container based on information in the playlist + * @param {Playlist} media the current media playlist + * @return {String} a valid media container type + */ + var getContainerType = function getContainerType(media) { + // An initialization segment means the media playlist is an iframe + // playlist or is using the mp4 container. We don't currently + // support iframe playlists, so assume this is signalling mp4 + // fragments. + if (media.segments && media.segments.length && media.segments[0].map) { + return 'mp4'; + } + return 'mp2t'; + }; + + /** + * Returns a set of codec strings parsed from the playlist or the default + * codec strings if no codecs were specified in the playlist + * @param {Playlist} media the current media playlist + * @return {Object} an object with the video and audio codecs + */ + var getCodecs = function getCodecs(media) { + // if the codecs were explicitly specified, use them instead of the + // defaults + var mediaAttributes = media.attributes || {}; + + if (mediaAttributes.CODECS) { + return parseCodecs(mediaAttributes.CODECS); + } + return defaultCodecs; + }; + + var audioProfileFromDefault = function audioProfileFromDefault(master, audioGroupId) { + if (!master.mediaGroups.AUDIO || !audioGroupId) { + return null; + } + + var audioGroup = master.mediaGroups.AUDIO[audioGroupId]; + + if (!audioGroup) { + return null; + } + + for (var name in audioGroup) { + var audioType = audioGroup[name]; + + if (audioType.default && audioType.playlists) { + // codec should be the same for all playlists within the audio type + return parseCodecs(audioType.playlists[0].attributes.CODECS).audioProfile; + } + } + + return null; + }; + + /** + * Calculates the MIME type strings for a working configuration of + * SourceBuffers to playOld variant streams in a master playlist. If + * there is no possible working configuration, an empty array will be + * returned. + * + * @param master {Object} the m3u8 object for the master playlist + * @param media {Object} the m3u8 object for the variant playlist + * @return {Array} the MIME type strings. If the array has more than + * one entry, the first element should be applied to the video + * SourceBuffer and the second to the audio SourceBuffer. + * + * @private + */ + var mimeTypesForPlaylist = function mimeTypesForPlaylist(master, media) { + var containerType = getContainerType(media); + var codecInfo = getCodecs(media); + var mediaAttributes = media.attributes || {}; + // Default condition for a traditional HLS (no demuxed audio/video) + var isMuxed = true; + var isMaat = false; + + if (!media) { + // Not enough information + return []; + } + + if (master.mediaGroups.AUDIO && mediaAttributes.AUDIO) { + var audioGroup = master.mediaGroups.AUDIO[mediaAttributes.AUDIO]; + + // Handle the case where we are in a multiple-audio track scenario + if (audioGroup) { + isMaat = true; + // Start with the everything demuxed then... + isMuxed = false; + // ...check to see if any audio group tracks are muxed (ie. lacking a uri) + for (var groupId in audioGroup) { + // either a uri is present (if the case of HLS and an external playlist), or + // playlists is present (in the case of DASH where we don't have external audio + // playlists) + if (!audioGroup[groupId].uri && !audioGroup[groupId].playlists) { + isMuxed = true; + break; + } + } + } + } + + // HLS with multiple-audio tracks must always get an audio codec. + // Put another way, there is no way to have a video-only multiple-audio HLS! + if (isMaat && !codecInfo.audioProfile) { + if (!isMuxed) { + // It is possible for codecs to be specified on the audio media group playlist but + // not on the rendition playlist. This is mostly the case for DASH, where audio and + // video are always separate (and separately specified). + codecInfo.audioProfile = audioProfileFromDefault(master, mediaAttributes.AUDIO); + } + + if (!codecInfo.audioProfile) { + videojs$1.log.warn('Multiple audio tracks present but no audio codec string is specified. ' + 'Attempting to use the default audio codec (mp4a.40.2)'); + codecInfo.audioProfile = defaultCodecs.audioProfile; + } + } + + // Generate the final codec strings from the codec object generated above + var codecStrings = {}; + + if (codecInfo.videoCodec) { + codecStrings.video = '' + codecInfo.videoCodec + codecInfo.videoObjectTypeIndicator; + } + + if (codecInfo.audioProfile) { + codecStrings.audio = 'mp4a.40.' + codecInfo.audioProfile; + } + + // Finally, make and return an array with proper mime-types depending on + // the configuration + var justAudio = makeMimeTypeString('audio', containerType, [codecStrings.audio]); + var justVideo = makeMimeTypeString('video', containerType, [codecStrings.video]); + var bothVideoAudio = makeMimeTypeString('video', containerType, [codecStrings.video, codecStrings.audio]); + + if (isMaat) { + if (!isMuxed && codecStrings.video) { + return [justVideo, justAudio]; + } + + if (!isMuxed && !codecStrings.video) { + // There is no muxed content and no video codec string, so this is an audio only + // stream with alternate audio. + return [justAudio, justAudio]; + } + + // There exists the possiblity that this will return a `video/container` + // mime-type for the first entry in the array even when there is only audio. + // This doesn't appear to be a problem and simplifies the code. + return [bothVideoAudio, justAudio]; + } + + // If there is no video codec at all, always just return a single + // audio/<container> mime-type + if (!codecStrings.video) { + return [justAudio]; + } + + // When not using separate audio media groups, audio and video is + // *always* muxed + return [bothVideoAudio]; + }; + + // Utilities + + /** + * Returns the CSS value for the specified property on an element + * using `getComputedStyle`. Firefox has a long-standing issue where + * getComputedStyle() may return null when running in an iframe with + * `display: none`. + * + * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397 + * @param {HTMLElement} el the htmlelement to work on + * @param {string} the proprety to get the style for + */ + var safeGetComputedStyle = function safeGetComputedStyle(el, property) { + var result = void 0; + + if (!el) { + return ''; + } + + result = window_1.getComputedStyle(el); + if (!result) { + return ''; + } + + return result[property]; + }; + + /** + * Resuable stable sort function + * + * @param {Playlists} array + * @param {Function} sortFn Different comparators + * @function stableSort + */ + var stableSort = function stableSort(array, sortFn) { + var newArray = array.slice(); + + array.sort(function (left, right) { + var cmp = sortFn(left, right); + + if (cmp === 0) { + return newArray.indexOf(left) - newArray.indexOf(right); + } + return cmp; + }); + }; + + /** + * A comparator function to sort two playlist object by bandwidth. + * + * @param {Object} left a media playlist object + * @param {Object} right a media playlist object + * @return {Number} Greater than zero if the bandwidth attribute of + * left is greater than the corresponding attribute of right. Less + * than zero if the bandwidth of right is greater than left and + * exactly zero if the two are equal. + */ + var comparePlaylistBandwidth = function comparePlaylistBandwidth(left, right) { + var leftBandwidth = void 0; + var rightBandwidth = void 0; + + if (left.attributes.BANDWIDTH) { + leftBandwidth = left.attributes.BANDWIDTH; + } + leftBandwidth = leftBandwidth || window_1.Number.MAX_VALUE; + if (right.attributes.BANDWIDTH) { + rightBandwidth = right.attributes.BANDWIDTH; + } + rightBandwidth = rightBandwidth || window_1.Number.MAX_VALUE; + + return leftBandwidth - rightBandwidth; + }; + + /** + * A comparator function to sort two playlist object by resolution (width). + * @param {Object} left a media playlist object + * @param {Object} right a media playlist object + * @return {Number} Greater than zero if the resolution.width attribute of + * left is greater than the corresponding attribute of right. Less + * than zero if the resolution.width of right is greater than left and + * exactly zero if the two are equal. + */ + var comparePlaylistResolution = function comparePlaylistResolution(left, right) { + var leftWidth = void 0; + var rightWidth = void 0; + + if (left.attributes.RESOLUTION && left.attributes.RESOLUTION.width) { + leftWidth = left.attributes.RESOLUTION.width; + } + + leftWidth = leftWidth || window_1.Number.MAX_VALUE; + + if (right.attributes.RESOLUTION && right.attributes.RESOLUTION.width) { + rightWidth = right.attributes.RESOLUTION.width; + } + + rightWidth = rightWidth || window_1.Number.MAX_VALUE; + + // NOTE - Fallback to bandwidth sort as appropriate in cases where multiple renditions + // have the same media dimensions/ resolution + if (leftWidth === rightWidth && left.attributes.BANDWIDTH && right.attributes.BANDWIDTH) { + return left.attributes.BANDWIDTH - right.attributes.BANDWIDTH; + } + return leftWidth - rightWidth; + }; + + /** + * Chooses the appropriate media playlist based on bandwidth and player size + * + * @param {Object} master + * Object representation of the master manifest + * @param {Number} playerBandwidth + * Current calculated bandwidth of the player + * @param {Number} playerWidth + * Current width of the player element + * @param {Number} playerHeight + * Current height of the player element + * @return {Playlist} the highest bitrate playlist less than the + * currently detected bandwidth, accounting for some amount of + * bandwidth variance + */ + var simpleSelector = function simpleSelector(master, playerBandwidth, playerWidth, playerHeight) { + // convert the playlists to an intermediary representation to make comparisons easier + var sortedPlaylistReps = master.playlists.map(function (playlist) { + var width = void 0; + var height = void 0; + var bandwidth = void 0; + + width = playlist.attributes.RESOLUTION && playlist.attributes.RESOLUTION.width; + height = playlist.attributes.RESOLUTION && playlist.attributes.RESOLUTION.height; + bandwidth = playlist.attributes.BANDWIDTH; + + bandwidth = bandwidth || window_1.Number.MAX_VALUE; + + return { + bandwidth: bandwidth, + width: width, + height: height, + playlist: playlist + }; + }); + + stableSort(sortedPlaylistReps, function (left, right) { + return left.bandwidth - right.bandwidth; + }); + + // filter out any playlists that have been excluded due to + // incompatible configurations + sortedPlaylistReps = sortedPlaylistReps.filter(function (rep) { + return !Playlist.isIncompatible(rep.playlist); + }); + + // filter out any playlists that have been disabled manually through the representations + // api or blacklisted temporarily due to playback errors. + var enabledPlaylistReps = sortedPlaylistReps.filter(function (rep) { + return Playlist.isEnabled(rep.playlist); + }); + + if (!enabledPlaylistReps.length) { + // if there are no enabled playlists, then they have all been blacklisted or disabled + // by the user through the representations api. In this case, ignore blacklisting and + // fallback to what the user wants by using playlists the user has not disabled. + enabledPlaylistReps = sortedPlaylistReps.filter(function (rep) { + return !Playlist.isDisabled(rep.playlist); + }); + } + + // filter out any variant that has greater effective bitrate + // than the current estimated bandwidth + var bandwidthPlaylistReps = enabledPlaylistReps.filter(function (rep) { + return rep.bandwidth * Config.BANDWIDTH_VARIANCE < playerBandwidth; + }); + + var highestRemainingBandwidthRep = bandwidthPlaylistReps[bandwidthPlaylistReps.length - 1]; + + // get all of the renditions with the same (highest) bandwidth + // and then taking the very first element + var bandwidthBestRep = bandwidthPlaylistReps.filter(function (rep) { + return rep.bandwidth === highestRemainingBandwidthRep.bandwidth; + })[0]; + + // filter out playlists without resolution information + var haveResolution = bandwidthPlaylistReps.filter(function (rep) { + return rep.width && rep.height; + }); + + // sort variants by resolution + stableSort(haveResolution, function (left, right) { + return left.width - right.width; + }); + + // if we have the exact resolution as the player use it + var resolutionBestRepList = haveResolution.filter(function (rep) { + return rep.width === playerWidth && rep.height === playerHeight; + }); + + highestRemainingBandwidthRep = resolutionBestRepList[resolutionBestRepList.length - 1]; + // ensure that we pick the highest bandwidth variant that have exact resolution + var resolutionBestRep = resolutionBestRepList.filter(function (rep) { + return rep.bandwidth === highestRemainingBandwidthRep.bandwidth; + })[0]; + + var resolutionPlusOneList = void 0; + var resolutionPlusOneSmallest = void 0; + var resolutionPlusOneRep = void 0; + + // find the smallest variant that is larger than the player + // if there is no match of exact resolution + if (!resolutionBestRep) { + resolutionPlusOneList = haveResolution.filter(function (rep) { + return rep.width > playerWidth || rep.height > playerHeight; + }); + + // find all the variants have the same smallest resolution + resolutionPlusOneSmallest = resolutionPlusOneList.filter(function (rep) { + return rep.width === resolutionPlusOneList[0].width && rep.height === resolutionPlusOneList[0].height; + }); + + // ensure that we also pick the highest bandwidth variant that + // is just-larger-than the video player + highestRemainingBandwidthRep = resolutionPlusOneSmallest[resolutionPlusOneSmallest.length - 1]; + resolutionPlusOneRep = resolutionPlusOneSmallest.filter(function (rep) { + return rep.bandwidth === highestRemainingBandwidthRep.bandwidth; + })[0]; + } + + // fallback chain of variants + var chosenRep = resolutionPlusOneRep || resolutionBestRep || bandwidthBestRep || enabledPlaylistReps[0] || sortedPlaylistReps[0]; + + return chosenRep ? chosenRep.playlist : null; + }; + + // Playlist Selectors + + /** + * Chooses the appropriate media playlist based on the most recent + * bandwidth estimate and the player size. + * + * Expects to be called within the context of an instance of HlsHandler + * + * @return {Playlist} the highest bitrate playlist less than the + * currently detected bandwidth, accounting for some amount of + * bandwidth variance + */ + var lastBandwidthSelector = function lastBandwidthSelector() { + return simpleSelector(this.playlists.master, this.systemBandwidth, parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10), parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10)); + }; + + /** + * Chooses the appropriate media playlist based on the potential to rebuffer + * + * @param {Object} settings + * Object of information required to use this selector + * @param {Object} settings.master + * Object representation of the master manifest + * @param {Number} settings.currentTime + * The current time of the player + * @param {Number} settings.bandwidth + * Current measured bandwidth + * @param {Number} settings.duration + * Duration of the media + * @param {Number} settings.segmentDuration + * Segment duration to be used in round trip time calculations + * @param {Number} settings.timeUntilRebuffer + * Time left in seconds until the player has to rebuffer + * @param {Number} settings.currentTimeline + * The current timeline segments are being loaded from + * @param {SyncController} settings.syncController + * SyncController for determining if we have a sync point for a given playlist + * @return {Object|null} + * {Object} return.playlist + * The highest bandwidth playlist with the least amount of rebuffering + * {Number} return.rebufferingImpact + * The amount of time in seconds switching to this playlist will rebuffer. A + * negative value means that switching will cause zero rebuffering. + */ + var minRebufferMaxBandwidthSelector = function minRebufferMaxBandwidthSelector(settings) { + var master = settings.master, + currentTime = settings.currentTime, + bandwidth = settings.bandwidth, + duration$$1 = settings.duration, + segmentDuration = settings.segmentDuration, + timeUntilRebuffer = settings.timeUntilRebuffer, + currentTimeline = settings.currentTimeline, + syncController = settings.syncController; + + // filter out any playlists that have been excluded due to + // incompatible configurations + + var compatiblePlaylists = master.playlists.filter(function (playlist) { + return !Playlist.isIncompatible(playlist); + }); + + // filter out any playlists that have been disabled manually through the representations + // api or blacklisted temporarily due to playback errors. + var enabledPlaylists = compatiblePlaylists.filter(Playlist.isEnabled); + + if (!enabledPlaylists.length) { + // if there are no enabled playlists, then they have all been blacklisted or disabled + // by the user through the representations api. In this case, ignore blacklisting and + // fallback to what the user wants by using playlists the user has not disabled. + enabledPlaylists = compatiblePlaylists.filter(function (playlist) { + return !Playlist.isDisabled(playlist); + }); + } + + var bandwidthPlaylists = enabledPlaylists.filter(Playlist.hasAttribute.bind(null, 'BANDWIDTH')); + + var rebufferingEstimates = bandwidthPlaylists.map(function (playlist) { + var syncPoint = syncController.getSyncPoint(playlist, duration$$1, currentTimeline, currentTime); + // If there is no sync point for this playlist, switching to it will require a + // sync request first. This will double the request time + var numRequests = syncPoint ? 1 : 2; + var requestTimeEstimate = Playlist.estimateSegmentRequestTime(segmentDuration, bandwidth, playlist); + var rebufferingImpact = requestTimeEstimate * numRequests - timeUntilRebuffer; + + return { + playlist: playlist, + rebufferingImpact: rebufferingImpact + }; + }); + + var noRebufferingPlaylists = rebufferingEstimates.filter(function (estimate) { + return estimate.rebufferingImpact <= 0; + }); + + // Sort by bandwidth DESC + stableSort(noRebufferingPlaylists, function (a, b) { + return comparePlaylistBandwidth(b.playlist, a.playlist); + }); + + if (noRebufferingPlaylists.length) { + return noRebufferingPlaylists[0]; + } + + stableSort(rebufferingEstimates, function (a, b) { + return a.rebufferingImpact - b.rebufferingImpact; + }); + + return rebufferingEstimates[0] || null; + }; + + /** + * Chooses the appropriate media playlist, which in this case is the lowest bitrate + * one with video. If no renditions with video exist, return the lowest audio rendition. + * + * Expects to be called within the context of an instance of HlsHandler + * + * @return {Object|null} + * {Object} return.playlist + * The lowest bitrate playlist that contains a video codec. If no such rendition + * exists pick the lowest audio rendition. + */ + var lowestBitrateCompatibleVariantSelector = function lowestBitrateCompatibleVariantSelector() { + // filter out any playlists that have been excluded due to + // incompatible configurations or playback errors + var playlists = this.playlists.master.playlists.filter(Playlist.isEnabled); + + // Sort ascending by bitrate + stableSort(playlists, function (a, b) { + return comparePlaylistBandwidth(a, b); + }); + + // Parse and assume that playlists with no video codec have no video + // (this is not necessarily true, although it is generally true). + // + // If an entire manifest has no valid videos everything will get filtered + // out. + var playlistsWithVideo = playlists.filter(function (playlist) { + return parseCodecs(playlist.attributes.CODECS).videoCodec; + }); + + return playlistsWithVideo[0] || null; + }; + + /** + * @file segment-loader.js + */ + + // in ms + var CHECK_BUFFER_DELAY = 500; + + /** + * Determines if we should call endOfStream on the media source based + * on the state of the buffer or if appened segment was the final + * segment in the playlist. + * + * @param {Object} playlist a media playlist object + * @param {Object} mediaSource the MediaSource object + * @param {Number} segmentIndex the index of segment we last appended + * @returns {Boolean} do we need to call endOfStream on the MediaSource + */ + var detectEndOfStream = function detectEndOfStream(playlist, mediaSource, segmentIndex) { + if (!playlist || !mediaSource) { + return false; + } + + var segments = playlist.segments; + + // determine a few boolean values to help make the branch below easier + // to read + var appendedLastSegment = segmentIndex === segments.length; + + // if we've buffered to the end of the video, we need to call endOfStream + // so that MediaSources can trigger the `ended` event when it runs out of + // buffered data instead of waiting for me + return playlist.endList && mediaSource.readyState === 'open' && appendedLastSegment; + }; + + var finite = function finite(num) { + return typeof num === 'number' && isFinite(num); + }; + + var illegalMediaSwitch = function illegalMediaSwitch(loaderType, startingMedia, newSegmentMedia) { + // Although these checks should most likely cover non 'main' types, for now it narrows + // the scope of our checks. + if (loaderType !== 'main' || !startingMedia || !newSegmentMedia) { + return null; + } + + if (!newSegmentMedia.containsAudio && !newSegmentMedia.containsVideo) { + return 'Neither audio nor video found in segment.'; + } + + if (startingMedia.containsVideo && !newSegmentMedia.containsVideo) { + return 'Only audio found in segment when we expected video.' + ' We can\'t switch to audio only from a stream that had video.' + ' To get rid of this message, please add codec information to the manifest.'; + } + + if (!startingMedia.containsVideo && newSegmentMedia.containsVideo) { + return 'Video found in segment when we expected only audio.' + ' We can\'t switch to a stream with video from an audio only stream.' + ' To get rid of this message, please add codec information to the manifest.'; + } + + return null; + }; + + /** + * Calculates a time value that is safe to remove from the back buffer without interupting + * playback. + * + * @param {TimeRange} seekable + * The current seekable range + * @param {Number} currentTime + * The current time of the player + * @param {Number} targetDuration + * The target duration of the current playlist + * @return {Number} + * Time that is safe to remove from the back buffer without interupting playback + */ + var safeBackBufferTrimTime = function safeBackBufferTrimTime(seekable$$1, currentTime, targetDuration) { + var removeToTime = void 0; + + if (seekable$$1.length && seekable$$1.start(0) > 0 && seekable$$1.start(0) < currentTime) { + // If we have a seekable range use that as the limit for what can be removed safely + removeToTime = seekable$$1.start(0); + } else { + // otherwise remove anything older than 30 seconds before the current playOld head + removeToTime = currentTime - 30; + } + + // Don't allow removing from the buffer within target duration of current time + // to avoid the possibility of removing the GOP currently being played which could + // cause playback stalls. + return Math.min(removeToTime, currentTime - targetDuration); + }; + + var segmentInfoString = function segmentInfoString(segmentInfo) { + var _segmentInfo$segment = segmentInfo.segment, + start = _segmentInfo$segment.start, + end = _segmentInfo$segment.end, + _segmentInfo$playlist = segmentInfo.playlist, + seq = _segmentInfo$playlist.mediaSequence, + id = _segmentInfo$playlist.id, + _segmentInfo$playlist2 = _segmentInfo$playlist.segments, + segments = _segmentInfo$playlist2 === undefined ? [] : _segmentInfo$playlist2, + index = segmentInfo.mediaIndex, + timeline = segmentInfo.timeline; + + + return ['appending [' + index + '] of [' + seq + ', ' + (seq + segments.length) + '] from playlist [' + id + ']', '[' + start + ' => ' + end + '] in timeline [' + timeline + ']'].join(' '); + }; + + /** + * An object that manages segment loading and appending. + * + * @class SegmentLoader + * @param {Object} options required and optional options + * @extends videojs.EventTarget + */ + + var SegmentLoader = function (_videojs$EventTarget3) { + inherits(SegmentLoader, _videojs$EventTarget3); + + function SegmentLoader(settings) { + classCallCheck(this, SegmentLoader); + + // check pre-conditions + var _this22 = possibleConstructorReturn(this, _videojs$EventTarget3.call(this)); + + if (!settings) { + throw new TypeError('Initialization settings are required'); + } + if (typeof settings.currentTime !== 'function') { + throw new TypeError('No currentTime getter specified'); + } + if (!settings.mediaSource) { + throw new TypeError('No MediaSource specified'); + } + // public properties + _this22.bandwidth = settings.bandwidth; + _this22.throughput = {rate: 0, count: 0}; + _this22.roundTrip = NaN; + _this22.resetStats_(); + _this22.mediaIndex = null; + + // private settings + _this22.hasPlayed_ = settings.hasPlayed; + _this22.currentTime_ = settings.currentTime; + _this22.seekable_ = settings.seekable; + _this22.seeking_ = settings.seeking; + _this22.duration_ = settings.duration; + _this22.mediaSource_ = settings.mediaSource; + _this22.hls_ = settings.hls; + _this22.loaderType_ = settings.loaderType; + _this22.startingMedia_ = void 0; + _this22.segmentMetadataTrack_ = settings.segmentMetadataTrack; + _this22.goalBufferLength_ = settings.goalBufferLength; + _this22.sourceType_ = settings.sourceType; + _this22.state_ = 'INIT'; + + // private instance variables + _this22.checkBufferTimeout_ = null; + _this22.error_ = void 0; + _this22.currentTimeline_ = -1; + _this22.pendingSegment_ = null; + _this22.mimeType_ = null; + _this22.sourceUpdater_ = null; + _this22.xhrOptions_ = null; + + // Fragmented mp4 playback + _this22.activeInitSegmentId_ = null; + _this22.initSegments_ = {}; + + _this22.decrypter_ = settings.decrypter; + + // Manages the tracking and generation of sync-points, mappings + // between a time in the display time and a segment index within + // a playlist + _this22.syncController_ = settings.syncController; + _this22.syncPoint_ = { + segmentIndex: 0, + time: 0 + }; + + _this22.syncController_.on('syncinfoupdate', function () { + return _this22.trigger('syncinfoupdate'); + }); + + _this22.mediaSource_.addEventListener('sourceopen', function () { + return _this22.ended_ = false; + }); + + // ...for determining the fetch location + _this22.fetchAtBuffer_ = false; + + _this22.logger_ = logger('SegmentLoader[' + _this22.loaderType_ + ']'); + + Object.defineProperty(_this22, 'state', { + get: function get$$1() { + return this.state_; + }, + set: function set$$1(newState) { + if (newState !== this.state_) { + this.logger_(this.state_ + ' -> ' + newState); + this.state_ = newState; + } + } + }); + return _this22; + } + + /** + * reset all of our media stats + * + * @private + */ + + + SegmentLoader.prototype.resetStats_ = function resetStats_() { + this.mediaBytesTransferred = 0; + this.mediaRequests = 0; + this.mediaRequestsAborted = 0; + this.mediaRequestsTimedout = 0; + this.mediaRequestsErrored = 0; + this.mediaTransferDuration = 0; + this.mediaSecondsLoaded = 0; + }; + + /** + * dispose of the SegmentLoader and reset to the default state + */ + + + SegmentLoader.prototype.dispose = function dispose() { + this.state = 'DISPOSED'; + this.pause(); + this.abort_(); + if (this.sourceUpdater_) { + this.sourceUpdater_.dispose(); + } + this.resetStats_(); + }; + + /** + * abort anything that is currently doing on with the SegmentLoader + * and reset to a default state + */ + + + SegmentLoader.prototype.abort = function abort() { + if (this.state !== 'WAITING') { + if (this.pendingSegment_) { + this.pendingSegment_ = null; + } + return; + } + + this.abort_(); + + // We aborted the requests we were waiting on, so reset the loader's state to READY + // since we are no longer "waiting" on any requests. XHR callback is not always run + // when the request is aborted. This will prevent the loader from being stuck in the + // WAITING state indefinitely. + this.state = 'READY'; + + // don't wait for buffer check timeouts to begin fetching the + // next segment + if (!this.paused()) { + this.monitorBuffer_(); + } + }; + + /** + * abort all pending xhr requests and null any pending segements + * + * @private + */ + + + SegmentLoader.prototype.abort_ = function abort_() { + if (this.pendingSegment_) { + this.pendingSegment_.abortRequests(); + } + + // clear out the segment being processed + this.pendingSegment_ = null; + }; + + /** + * set an error on the segment loader and null out any pending segements + * + * @param {Error} error the error to set on the SegmentLoader + * @return {Error} the error that was set or that is currently set + */ + + + SegmentLoader.prototype.error = function error(_error) { + if (typeof _error !== 'undefined') { + this.error_ = _error; + } + + this.pendingSegment_ = null; + return this.error_; + }; + + SegmentLoader.prototype.endOfStream = function endOfStream() { + this.ended_ = true; + this.pause(); + this.trigger('ended'); + }; + + /** + * Indicates which time ranges are buffered + * + * @return {TimeRange} + * TimeRange object representing the current buffered ranges + */ + + + SegmentLoader.prototype.buffered_ = function buffered_() { + if (!this.sourceUpdater_) { + return videojs$1.createTimeRanges(); + } + + return this.sourceUpdater_.buffered(); + }; + + /** + * Gets and sets init segment for the provided map + * + * @param {Object} map + * The map object representing the init segment to get or set + * @param {Boolean=} set + * If true, the init segment for the provided map should be saved + * @return {Object} + * map object for desired init segment + */ + + + SegmentLoader.prototype.initSegment = function initSegment(map) { + var set$$1 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!map) { + return null; + } + + var id = initSegmentId(map); + var storedMap = this.initSegments_[id]; + + if (set$$1 && !storedMap && map.bytes) { + this.initSegments_[id] = storedMap = { + resolvedUri: map.resolvedUri, + byterange: map.byterange, + bytes: map.bytes + }; + } + + return storedMap || map; + }; + + /** + * Returns true if all configuration required for loading is present, otherwise false. + * + * @return {Boolean} True if the all configuration is ready for loading + * @private + */ + + + SegmentLoader.prototype.couldBeginLoading_ = function couldBeginLoading_() { + return this.playlist_ && ( + // the source updater is created when init_ is called, so either having a + // source updater or being in the INIT state with a mimeType is enough + // to say we have all the needed configuration to start loading. + this.sourceUpdater_ || this.mimeType_ && this.state === 'INIT') && !this.paused(); + }; + + /** + * load a playlist and start to fill the buffer + */ + + + SegmentLoader.prototype.load = function load() { + // un-pause + this.monitorBuffer_(); + + // if we don't have a playlist yet, keep waiting for one to be + // specified + if (!this.playlist_) { + return; + } + + // not sure if this is the best place for this + this.syncController_.setDateTimeMapping(this.playlist_); + + // if all the configuration is ready, initialize and begin loading + if (this.state === 'INIT' && this.couldBeginLoading_()) { + return this.init_(); + } + + // if we're in the middle of processing a segment already, don't + // kick off an additional segment request + if (!this.couldBeginLoading_() || this.state !== 'READY' && this.state !== 'INIT') { + return; + } + + this.state = 'READY'; + }; + + /** + * Once all the starting parameters have been specified, begin + * operation. This method should only be invoked from the INIT + * state. + * + * @private + */ + + + SegmentLoader.prototype.init_ = function init_() { + this.state = 'READY'; + this.sourceUpdater_ = new SourceUpdater(this.mediaSource_, this.mimeType_, this.loaderType_, this.sourceBufferEmitter_); + this.resetEverything(); + return this.monitorBuffer_(); + }; + + /** + * set a playlist on the segment loader + * + * @param {PlaylistLoader} media the playlist to set on the segment loader + */ + + + SegmentLoader.prototype.playlist = function playlist(newPlaylist) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + if (!newPlaylist) { + return; + } + + var oldPlaylist = this.playlist_; + var segmentInfo = this.pendingSegment_; + + this.playlist_ = newPlaylist; + this.xhrOptions_ = options; + + // when we haven't started playing yet, the start of a live playlist + // is always our zero-time so force a sync update each time the playlist + // is refreshed from the server + if (!this.hasPlayed_()) { + newPlaylist.syncInfo = { + mediaSequence: newPlaylist.mediaSequence, + time: 0 + }; + } + + var oldId = oldPlaylist ? oldPlaylist.id : null; + + this.logger_('playlist update [' + oldId + ' => ' + newPlaylist.id + ']'); + + // in VOD, this is always a rendition switch (or we updated our syncInfo above) + // in LIVE, we always want to update with new playlists (including refreshes) + this.trigger('syncinfoupdate'); + + // if we were unpaused but waiting for a playlist, start + // buffering now + if (this.state === 'INIT' && this.couldBeginLoading_()) { + return this.init_(); + } + + if (!oldPlaylist || oldPlaylist.uri !== newPlaylist.uri) { + if (this.mediaIndex !== null) { + // we must "resync" the segment loader when we switch renditions and + // the segment loader is already synced to the previous rendition + this.resyncLoader(); + } + + // the rest of this function depends on `oldPlaylist` being defined + return; + } + + // we reloaded the same playlist so we are in a live scenario + // and we will likely need to adjust the mediaIndex + var mediaSequenceDiff = newPlaylist.mediaSequence - oldPlaylist.mediaSequence; + + this.logger_('live window shift [' + mediaSequenceDiff + ']'); + + // update the mediaIndex on the SegmentLoader + // this is important because we can abort a request and this value must be + // equal to the last appended mediaIndex + if (this.mediaIndex !== null) { + this.mediaIndex -= mediaSequenceDiff; + } + + // update the mediaIndex on the SegmentInfo object + // this is important because we will update this.mediaIndex with this value + // in `handleUpdateEnd_` after the segment has been successfully appended + if (segmentInfo) { + segmentInfo.mediaIndex -= mediaSequenceDiff; + + // we need to update the referenced segment so that timing information is + // saved for the new playlist's segment, however, if the segment fell off the + // playlist, we can leave the old reference and just lose the timing info + if (segmentInfo.mediaIndex >= 0) { + segmentInfo.segment = newPlaylist.segments[segmentInfo.mediaIndex]; + } + } + + this.syncController_.saveExpiredSegmentInfo(oldPlaylist, newPlaylist); + }; + + /** + * Prevent the loader from fetching additional segments. If there + * is a segment request outstanding, it will finish processing + * before the loader halts. A segment loader can be unpaused by + * calling load(). + */ + + + SegmentLoader.prototype.pause = function pause() { + if (this.checkBufferTimeout_) { + window_1.clearTimeout(this.checkBufferTimeout_); + + this.checkBufferTimeout_ = null; + } + }; + + /** + * Returns whether the segment loader is fetching additional + * segments when given the opportunity. This property can be + * modified through calls to pause() and load(). + */ + + + SegmentLoader.prototype.paused = function paused() { + return this.checkBufferTimeout_ === null; + }; + + /** + * create/set the following mimetype on the SourceBuffer through a + * SourceUpdater + * + * @param {String} mimeType the mime type string to use + * @param {Object} sourceBufferEmitter an event emitter that fires when a source buffer + * is added to the media source + */ + + + SegmentLoader.prototype.mimeType = function mimeType(_mimeType, sourceBufferEmitter) { + if (this.mimeType_) { + return; + } + + this.mimeType_ = _mimeType; + this.sourceBufferEmitter_ = sourceBufferEmitter; + // if we were unpaused but waiting for a sourceUpdater, start + // buffering now + if (this.state === 'INIT' && this.couldBeginLoading_()) { + this.init_(); + } + }; + + /** + * Delete all the buffered data and reset the SegmentLoader + */ + + + SegmentLoader.prototype.resetEverything = function resetEverything() { + this.ended_ = false; + this.resetLoader(); + this.remove(0, this.duration_()); + this.trigger('reseteverything'); + }; + + /** + * Force the SegmentLoader to resync and start loading around the currentTime instead + * of starting at the end of the buffer + * + * Useful for fast quality changes + */ + + + SegmentLoader.prototype.resetLoader = function resetLoader() { + this.fetchAtBuffer_ = false; + this.resyncLoader(); + }; + + /** + * Force the SegmentLoader to restart synchronization and make a conservative guess + * before returning to the simple walk-forward method + */ + + + SegmentLoader.prototype.resyncLoader = function resyncLoader() { + this.mediaIndex = null; + this.syncPoint_ = null; + this.abort(); + }; + + /** + * Remove any data in the source buffer between start and end times + * @param {Number} start - the start time of the region to remove from the buffer + * @param {Number} end - the end time of the region to remove from the buffer + */ + + + SegmentLoader.prototype.remove = function remove(start, end) { + if (this.sourceUpdater_) { + this.sourceUpdater_.remove(start, end); + } + removeCuesFromTrack(start, end, this.segmentMetadataTrack_); + }; + + /** + * (re-)schedule monitorBufferTick_ to run as soon as possible + * + * @private + */ + + + SegmentLoader.prototype.monitorBuffer_ = function monitorBuffer_() { + if (this.checkBufferTimeout_) { + window_1.clearTimeout(this.checkBufferTimeout_); + } + + this.checkBufferTimeout_ = window_1.setTimeout(this.monitorBufferTick_.bind(this), 1); + }; + + /** + * As long as the SegmentLoader is in the READY state, periodically + * invoke fillBuffer_(). + * + * @private + */ + + + SegmentLoader.prototype.monitorBufferTick_ = function monitorBufferTick_() { + if (this.state === 'READY') { + this.fillBuffer_(); + } + + if (this.checkBufferTimeout_) { + window_1.clearTimeout(this.checkBufferTimeout_); + } + + this.checkBufferTimeout_ = window_1.setTimeout(this.monitorBufferTick_.bind(this), CHECK_BUFFER_DELAY); + }; + + /** + * fill the buffer with segements unless the sourceBuffers are + * currently updating + * + * Note: this function should only ever be called by monitorBuffer_ + * and never directly + * + * @private + */ + + + SegmentLoader.prototype.fillBuffer_ = function fillBuffer_() { + if (this.sourceUpdater_.updating()) { + return; + } + + if (!this.syncPoint_) { + this.syncPoint_ = this.syncController_.getSyncPoint(this.playlist_, this.duration_(), this.currentTimeline_, this.currentTime_()); + } + + // see if we need to begin loading immediately + var segmentInfo = this.checkBuffer_(this.buffered_(), this.playlist_, this.mediaIndex, this.hasPlayed_(), this.currentTime_(), this.syncPoint_); + + if (!segmentInfo) { + return; + } + + var isEndOfStream = detectEndOfStream(this.playlist_, this.mediaSource_, segmentInfo.mediaIndex); + + if (isEndOfStream) { + this.endOfStream(); + return; + } + + if (segmentInfo.mediaIndex === this.playlist_.segments.length - 1 && this.mediaSource_.readyState === 'ended' && !this.seeking_()) { + return; + } + + // We will need to change timestampOffset of the sourceBuffer if either of + // the following conditions are true: + // - The segment.timeline !== this.currentTimeline + // (we are crossing a discontinuity somehow) + // - The "timestampOffset" for the start of this segment is less than + // the currently set timestampOffset + if (segmentInfo.timeline !== this.currentTimeline_ || segmentInfo.startOfSegment !== null && segmentInfo.startOfSegment < this.sourceUpdater_.timestampOffset()) { + this.syncController_.reset(); + segmentInfo.timestampOffset = segmentInfo.startOfSegment; + } + + this.loadSegment_(segmentInfo); + }; + + /** + * Determines what segment request should be made, given current playback + * state. + * + * @param {TimeRanges} buffered - the state of the buffer + * @param {Object} playlist - the playlist object to fetch segments from + * @param {Number} mediaIndex - the previous mediaIndex fetched or null + * @param {Boolean} hasPlayed - a flag indicating whether we have played or not + * @param {Number} currentTime - the playback position in seconds + * @param {Object} syncPoint - a segment info object that describes the + * @returns {Object} a segment request object that describes the segment to load + */ + + + SegmentLoader.prototype.checkBuffer_ = function checkBuffer_(buffered, playlist, mediaIndex, hasPlayed, currentTime, syncPoint) { + var lastBufferedEnd = 0; + var startOfSegment = void 0; + + if (buffered.length) { + lastBufferedEnd = buffered.end(buffered.length - 1); + } + + var bufferedTime = Math.max(0, lastBufferedEnd - currentTime); + + if (!playlist.segments.length) { + return null; + } + + // if there is plenty of content buffered, and the video has + // been played before relax for awhile + if (bufferedTime >= this.goalBufferLength_()) { + return null; + } + + // if the video has not yet played once, and we already have + // one segment downloaded do nothing + if (!hasPlayed && bufferedTime >= 1) { + return null; + } + + // When the syncPoint is null, there is no way of determining a good + // conservative segment index to fetch from + // The best thing to do here is to get the kind of sync-point data by + // making a request + if (syncPoint === null) { + mediaIndex = this.getSyncSegmentCandidate_(playlist); + return this.generateSegmentInfo_(playlist, mediaIndex, null, true); + } + + // Under normal playback conditions fetching is a simple walk forward + if (mediaIndex !== null) { + var segment = playlist.segments[mediaIndex]; + + if (segment && segment.end) { + startOfSegment = segment.end; + } else { + startOfSegment = lastBufferedEnd; + } + return this.generateSegmentInfo_(playlist, mediaIndex + 1, startOfSegment, false); + } + + // There is a sync-point but the lack of a mediaIndex indicates that + // we need to make a good conservative guess about which segment to + // fetch + if (this.fetchAtBuffer_) { + // Find the segment containing the end of the buffer + var mediaSourceInfo = Playlist.getMediaInfoForTime(playlist, lastBufferedEnd, syncPoint.segmentIndex, syncPoint.time); + + mediaIndex = mediaSourceInfo.mediaIndex; + startOfSegment = mediaSourceInfo.startTime; + } else { + // Find the segment containing currentTime + var _mediaSourceInfo = Playlist.getMediaInfoForTime(playlist, currentTime, syncPoint.segmentIndex, syncPoint.time); + + mediaIndex = _mediaSourceInfo.mediaIndex; + startOfSegment = _mediaSourceInfo.startTime; + } + + return this.generateSegmentInfo_(playlist, mediaIndex, startOfSegment, false); + }; + + /** + * The segment loader has no recourse except to fetch a segment in the + * current playlist and use the internal timestamps in that segment to + * generate a syncPoint. This function returns a good candidate index + * for that process. + * + * @param {Object} playlist - the playlist object to look for a + * @returns {Number} An index of a segment from the playlist to load + */ + + + SegmentLoader.prototype.getSyncSegmentCandidate_ = function getSyncSegmentCandidate_(playlist) { + var _this23 = this; + + if (this.currentTimeline_ === -1) { + return 0; + } + + var segmentIndexArray = playlist.segments.map(function (s, i) { + return { + timeline: s.timeline, + segmentIndex: i + }; + }).filter(function (s) { + return s.timeline === _this23.currentTimeline_; + }); + + if (segmentIndexArray.length) { + return segmentIndexArray[Math.min(segmentIndexArray.length - 1, 1)].segmentIndex; + } + + return Math.max(playlist.segments.length - 1, 0); + }; + + SegmentLoader.prototype.generateSegmentInfo_ = function generateSegmentInfo_(playlist, mediaIndex, startOfSegment, isSyncRequest) { + if (mediaIndex < 0 || mediaIndex >= playlist.segments.length) { + return null; + } + + var segment = playlist.segments[mediaIndex]; + + return { + requestId: 'segment-loader-' + Math.random(), + // resolve the segment URL relative to the playlist + uri: segment.resolvedUri, + // the segment's mediaIndex at the time it was requested + mediaIndex: mediaIndex, + // whether or not to update the SegmentLoader's state with this + // segment's mediaIndex + isSyncRequest: isSyncRequest, + startOfSegment: startOfSegment, + // the segment's playlist + playlist: playlist, + // unencrypted bytes of the segment + bytes: null, + // when a key is defined for this segment, the encrypted bytes + encryptedBytes: null, + // The target timestampOffset for this segment when we append it + // to the source buffer + timestampOffset: null, + // The timeline that the segment is in + timeline: segment.timeline, + // The expected duration of the segment in seconds + duration: segment.duration, + // retain the segment in case the playlist updates while doing an async process + segment: segment + }; + }; + + /** + * Determines if the network has enough bandwidth to complete the current segment + * request in a timely manner. If not, the request will be aborted early and bandwidth + * updated to trigger a playlist switch. + * + * @param {Object} stats + * Object containing stats about the request timing and size + * @return {Boolean} True if the request was aborted, false otherwise + * @private + */ + + + SegmentLoader.prototype.abortRequestEarly_ = function abortRequestEarly_(stats) { + if (this.hls_.tech_.paused() || + // Don't abort if the current playlist is on the lowestEnabledRendition + // TODO: Replace using timeout with a boolean indicating whether this playlist is + // the lowestEnabledRendition. + !this.xhrOptions_.timeout || + // Don't abort if we have no bandwidth information to estimate segment sizes + !this.playlist_.attributes.BANDWIDTH) { + return false; + } + + // Wait at least 1 second since the first byte of data has been received before + // using the calculated bandwidth from the progress event to allow the bitrate + // to stabilize + if (Date.now() - (stats.firstBytesReceivedAt || Date.now()) < 1000) { + return false; + } + + var currentTime = this.currentTime_(); + var measuredBandwidth = stats.bandwidth; + var segmentDuration = this.pendingSegment_.duration; + + var requestTimeRemaining = Playlist.estimateSegmentRequestTime(segmentDuration, measuredBandwidth, this.playlist_, stats.bytesReceived); + + // Subtract 1 from the timeUntilRebuffer so we still consider an early abort + // if we are only left with less than 1 second when the request completes. + // A negative timeUntilRebuffering indicates we are already rebuffering + var timeUntilRebuffer$$1 = timeUntilRebuffer(this.buffered_(), currentTime, this.hls_.tech_.playbackRate()) - 1; + + // Only consider aborting early if the estimated time to finish the download + // is larger than the estimated time until the player runs out of forward buffer + if (requestTimeRemaining <= timeUntilRebuffer$$1) { + return false; + } + + var switchCandidate = minRebufferMaxBandwidthSelector({ + master: this.hls_.playlists.master, + currentTime: currentTime, + bandwidth: measuredBandwidth, + duration: this.duration_(), + segmentDuration: segmentDuration, + timeUntilRebuffer: timeUntilRebuffer$$1, + currentTimeline: this.currentTimeline_, + syncController: this.syncController_ + }); + + if (!switchCandidate) { + return; + } + + var rebufferingImpact = requestTimeRemaining - timeUntilRebuffer$$1; + + var timeSavedBySwitching = rebufferingImpact - switchCandidate.rebufferingImpact; + + var minimumTimeSaving = 0.5; + + // If we are already rebuffering, increase the amount of variance we add to the + // potential round trip time of the new request so that we are not too aggressive + // with switching to a playlist that might save us a fraction of a second. + if (timeUntilRebuffer$$1 <= TIME_FUDGE_FACTOR) { + minimumTimeSaving = 1; + } + + if (!switchCandidate.playlist || switchCandidate.playlist.uri === this.playlist_.uri || timeSavedBySwitching < minimumTimeSaving) { + return false; + } + + // set the bandwidth to that of the desired playlist being sure to scale by + // BANDWIDTH_VARIANCE and add one so the playlist selector does not exclude it + // don't trigger a bandwidthupdate as the bandwidth is artifial + this.bandwidth = switchCandidate.playlist.attributes.BANDWIDTH * Config.BANDWIDTH_VARIANCE + 1; + this.abort(); + this.trigger('earlyabort'); + return true; + }; + + /** + * XHR `progress` event handler + * + * @param {Event} + * The XHR `progress` event + * @param {Object} simpleSegment + * A simplified segment object copy + * @private + */ + + + SegmentLoader.prototype.handleProgress_ = function handleProgress_(event, simpleSegment) { + if (!this.pendingSegment_ || simpleSegment.requestId !== this.pendingSegment_.requestId || this.abortRequestEarly_(simpleSegment.stats)) { + return; + } + + this.trigger('progress'); + }; + + /** + * load a specific segment from a request into the buffer + * + * @private + */ + + + SegmentLoader.prototype.loadSegment_ = function loadSegment_(segmentInfo) { + this.state = 'WAITING'; + this.pendingSegment_ = segmentInfo; + this.trimBackBuffer_(segmentInfo); + + segmentInfo.abortRequests = mediaSegmentRequest(this.hls_.xhr, this.xhrOptions_, this.decrypter_, this.createSimplifiedSegmentObj_(segmentInfo), + // progress callback + this.handleProgress_.bind(this), this.segmentRequestFinished_.bind(this)); + }; + + /** + * trim the back buffer so that we don't have too much data + * in the source buffer + * + * @private + * + * @param {Object} segmentInfo - the current segment + */ + + + SegmentLoader.prototype.trimBackBuffer_ = function trimBackBuffer_(segmentInfo) { + var removeToTime = safeBackBufferTrimTime(this.seekable_(), this.currentTime_(), this.playlist_.targetDuration || 10); + + // Chrome has a hard limit of 150MB of + // buffer and a very conservative "garbage collector" + // We manually clear out the old buffer to ensure + // we don't trigger the QuotaExceeded error + // on the source buffer during subsequent appends + + if (removeToTime > 0) { + this.remove(0, removeToTime); + } + }; + + /** + * created a simplified copy of the segment object with just the + * information necessary to perform the XHR and decryption + * + * @private + * + * @param {Object} segmentInfo - the current segment + * @returns {Object} a simplified segment object copy + */ + + + SegmentLoader.prototype.createSimplifiedSegmentObj_ = function createSimplifiedSegmentObj_(segmentInfo) { + var segment = segmentInfo.segment; + var simpleSegment = { + resolvedUri: segment.resolvedUri, + byterange: segment.byterange, + requestId: segmentInfo.requestId + }; + + if (segment.key) { + // if the media sequence is greater than 2^32, the IV will be incorrect + // assuming 10s segments, that would be about 1300 years + var iv = segment.key.iv || new Uint32Array([0, 0, 0, segmentInfo.mediaIndex + segmentInfo.playlist.mediaSequence]); + + simpleSegment.key = { + resolvedUri: segment.key.resolvedUri, + iv: iv + }; + } + + if (segment.map) { + simpleSegment.map = this.initSegment(segment.map); + } + + return simpleSegment; + }; + + /** + * Handle the callback from the segmentRequest function and set the + * associated SegmentLoader state and errors if necessary + * + * @private + */ + + + SegmentLoader.prototype.segmentRequestFinished_ = function segmentRequestFinished_(error, simpleSegment) { + // every request counts as a media request even if it has been aborted + // or canceled due to a timeout + this.mediaRequests += 1; + + if (simpleSegment.stats) { + this.mediaBytesTransferred += simpleSegment.stats.bytesReceived; + this.mediaTransferDuration += simpleSegment.stats.roundTripTime; + } + + // The request was aborted and the SegmentLoader has already been reset + if (!this.pendingSegment_) { + this.mediaRequestsAborted += 1; + return; + } + + // the request was aborted and the SegmentLoader has already started + // another request. this can happen when the timeout for an aborted + // request triggers due to a limitation in the XHR library + // do not count this as any sort of request or we risk double-counting + if (simpleSegment.requestId !== this.pendingSegment_.requestId) { + return; + } + + // an error occurred from the active pendingSegment_ so reset everything + if (error) { + this.pendingSegment_ = null; + this.state = 'READY'; + + // the requests were aborted just record the aborted stat and exit + // this is not a true error condition and nothing corrective needs + // to be done + if (error.code === REQUEST_ERRORS.ABORTED) { + this.mediaRequestsAborted += 1; + return; + } + + this.pause(); + + // the error is really just that at least one of the requests timed-out + // set the bandwidth to a very low value and trigger an ABR switch to + // take emergency action + if (error.code === REQUEST_ERRORS.TIMEOUT) { + this.mediaRequestsTimedout += 1; + this.bandwidth = 1; + this.roundTrip = NaN; + this.trigger('bandwidthupdate'); + return; + } + + // if control-flow has arrived here, then the error is real + // emit an error event to blacklist the current playlist + this.mediaRequestsErrored += 1; + this.error(error); + this.trigger('error'); + return; + } + + // the response was a success so set any bandwidth stats the request + // generated for ABR purposes + this.bandwidth = simpleSegment.stats.bandwidth; + this.roundTrip = simpleSegment.stats.roundTripTime; + + // if this request included an initialization segment, save that data + // to the initSegment cache + if (simpleSegment.map) { + simpleSegment.map = this.initSegment(simpleSegment.map, true); + } + + this.processSegmentResponse_(simpleSegment); + }; + + /** + * Move any important data from the simplified segment object + * back to the real segment object for future phases + * + * @private + */ + + + SegmentLoader.prototype.processSegmentResponse_ = function processSegmentResponse_(simpleSegment) { + var segmentInfo = this.pendingSegment_; + + segmentInfo.bytes = simpleSegment.bytes; + if (simpleSegment.map) { + segmentInfo.segment.map.bytes = simpleSegment.map.bytes; + } + + segmentInfo.endOfAllRequests = simpleSegment.endOfAllRequests; + this.handleSegment_(); + }; + + /** + * append a decrypted segement to the SourceBuffer through a SourceUpdater + * + * @private + */ + + + SegmentLoader.prototype.handleSegment_ = function handleSegment_() { + var _this24 = this; + + if (!this.pendingSegment_) { + this.state = 'READY'; + return; + } + + var segmentInfo = this.pendingSegment_; + var segment = segmentInfo.segment; + var timingInfo = this.syncController_.probeSegmentInfo(segmentInfo); + + // When we have our first timing info, determine what media types this loader is + // dealing with. Although we're maintaining extra state, it helps to preserve the + // separation of segment loader from the actual source buffers. + if (typeof this.startingMedia_ === 'undefined' && timingInfo && ( + // Guard against cases where we're not getting timing info at all until we are + // certain that all streams will provide it. + timingInfo.containsAudio || timingInfo.containsVideo)) { + this.startingMedia_ = { + containsAudio: timingInfo.containsAudio, + containsVideo: timingInfo.containsVideo + }; + } + + var illegalMediaSwitchError = illegalMediaSwitch(this.loaderType_, this.startingMedia_, timingInfo); + + if (illegalMediaSwitchError) { + this.error({ + message: illegalMediaSwitchError, + blacklistDuration: Infinity + }); + this.trigger('error'); + return; + } + + if (segmentInfo.isSyncRequest) { + this.trigger('syncinfoupdate'); + this.pendingSegment_ = null; + this.state = 'READY'; + return; + } + + if (segmentInfo.timestampOffset !== null && segmentInfo.timestampOffset !== this.sourceUpdater_.timestampOffset()) { + this.sourceUpdater_.timestampOffset(segmentInfo.timestampOffset); + // fired when a timestamp offset is set in HLS (can also identify discontinuities) + this.trigger('timestampoffset'); + } + + var timelineMapping = this.syncController_.mappingForTimeline(segmentInfo.timeline); + + if (timelineMapping !== null) { + this.trigger({ + type: 'segmenttimemapping', + mapping: timelineMapping + }); + } + + this.state = 'APPENDING'; + + // if the media initialization segment is changing, append it + // before the content segment + if (segment.map) { + var initId = initSegmentId(segment.map); + + if (!this.activeInitSegmentId_ || this.activeInitSegmentId_ !== initId) { + var initSegment = this.initSegment(segment.map); + + this.sourceUpdater_.appendBuffer(initSegment.bytes, function () { + _this24.activeInitSegmentId_ = initId; + }); + } + } + + segmentInfo.byteLength = segmentInfo.bytes.byteLength; + if (typeof segment.start === 'number' && typeof segment.end === 'number') { + this.mediaSecondsLoaded += segment.end - segment.start; + } else { + this.mediaSecondsLoaded += segment.duration; + } + + this.logger_(segmentInfoString(segmentInfo)); + + this.sourceUpdater_.appendBuffer(segmentInfo.bytes, this.handleUpdateEnd_.bind(this)); + }; + + /** + * callback to run when appendBuffer is finished. detects if we are + * in a good state to do things with the data we got, or if we need + * to wait for more + * + * @private + */ + + + SegmentLoader.prototype.handleUpdateEnd_ = function handleUpdateEnd_() { + if (!this.pendingSegment_) { + this.state = 'READY'; + if (!this.paused()) { + this.monitorBuffer_(); + } + return; + } + + var segmentInfo = this.pendingSegment_; + var segment = segmentInfo.segment; + var isWalkingForward = this.mediaIndex !== null; + + this.pendingSegment_ = null; + this.recordThroughput_(segmentInfo); + this.addSegmentMetadataCue_(segmentInfo); + + this.state = 'READY'; + + this.mediaIndex = segmentInfo.mediaIndex; + this.fetchAtBuffer_ = true; + this.currentTimeline_ = segmentInfo.timeline; + + // We must update the syncinfo to recalculate the seekable range before + // the following conditional otherwise it may consider this a bad "guess" + // and attempt to resync when the post-update seekable window and live + // point would mean that this was the perfect segment to fetch + this.trigger('syncinfoupdate'); + + // If we previously appended a segment that ends more than 3 targetDurations before + // the currentTime_ that means that our conservative guess was too conservative. + // In that case, reset the loader state so that we try to use any information gained + // from the previous request to create a new, more accurate, sync-point. + if (segment.end && this.currentTime_() - segment.end > segmentInfo.playlist.targetDuration * 3) { + this.resetEverything(); + return; + } + + // Don't do a rendition switch unless we have enough time to get a sync segment + // and conservatively guess + if (isWalkingForward) { + this.trigger('bandwidthupdate'); + } + this.trigger('progress'); + + // any time an update finishes and the last segment is in the + // buffer, end the stream. this ensures the "ended" event will + // fire if playback reaches that point. + var isEndOfStream = detectEndOfStream(segmentInfo.playlist, this.mediaSource_, segmentInfo.mediaIndex + 1); + + if (isEndOfStream) { + this.endOfStream(); + } + + if (!this.paused()) { + this.monitorBuffer_(); + } + }; + + /** + * Records the current throughput of the decrypt, transmux, and append + * portion of the semgment pipeline. `throughput.rate` is a the cumulative + * moving average of the throughput. `throughput.count` is the number of + * data points in the average. + * + * @private + * @param {Object} segmentInfo the object returned by loadSegment + */ + + + SegmentLoader.prototype.recordThroughput_ = function recordThroughput_(segmentInfo) { + var rate = this.throughput.rate; + // Add one to the time to ensure that we don't accidentally attempt to divide + // by zero in the case where the throughput is ridiculously high + var segmentProcessingTime = Date.now() - segmentInfo.endOfAllRequests + 1; + // Multiply by 8000 to convert from bytes/millisecond to bits/second + var segmentProcessingThroughput = Math.floor(segmentInfo.byteLength / segmentProcessingTime * 8 * 1000); + + // This is just a cumulative moving average calculation: + // newAvg = oldAvg + (sample - oldAvg) / (sampleCount + 1) + this.throughput.rate += (segmentProcessingThroughput - rate) / ++this.throughput.count; + }; + + /** + * Adds a cue to the segment-metadata track with some metadata information about the + * segment + * + * @private + * @param {Object} segmentInfo + * the object returned by loadSegment + * @method addSegmentMetadataCue_ + */ + + + SegmentLoader.prototype.addSegmentMetadataCue_ = function addSegmentMetadataCue_(segmentInfo) { + if (!this.segmentMetadataTrack_) { + return; + } + + var segment = segmentInfo.segment; + var start = segment.start; + var end = segment.end; + + // Do not try adding the cue if the start and end times are invalid. + if (!finite(start) || !finite(end)) { + return; + } + + removeCuesFromTrack(start, end, this.segmentMetadataTrack_); + + var Cue = window_1.WebKitDataCue || window_1.VTTCue; + var value = { + bandwidth: segmentInfo.playlist.attributes.BANDWIDTH, + resolution: segmentInfo.playlist.attributes.RESOLUTION, + codecs: segmentInfo.playlist.attributes.CODECS, + byteLength: segmentInfo.byteLength, + uri: segmentInfo.uri, + timeline: segmentInfo.timeline, + playlist: segmentInfo.playlist.uri, + start: start, + end: end + }; + var data = JSON.stringify(value); + var cue = new Cue(start, end, data); + + // Attach the metadata to the value property of the cue to keep consistency between + // the differences of WebKitDataCue in safari and VTTCue in other browsers + cue.value = value; + + this.segmentMetadataTrack_.addCue(cue); + }; + + return SegmentLoader; + }(videojs$1.EventTarget); + + /** + * @file vtt-segment-loader.js + */ + + var VTT_LINE_TERMINATORS = new Uint8Array('\n\n'.split('').map(function (char) { + return char.charCodeAt(0); + })); + + var uintToString = function uintToString(uintArray) { + return String.fromCharCode.apply(null, uintArray); + }; + + /** + * An object that manages segment loading and appending. + * + * @class VTTSegmentLoader + * @param {Object} options required and optional options + * @extends videojs.EventTarget + */ + + var VTTSegmentLoader = function (_SegmentLoader) { + inherits(VTTSegmentLoader, _SegmentLoader); + + function VTTSegmentLoader(settings) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, VTTSegmentLoader); + + // SegmentLoader requires a MediaSource be specified or it will throw an error; + // however, VTTSegmentLoader has no need of a media source, so delete the reference + var _this25 = possibleConstructorReturn(this, _SegmentLoader.call(this, settings, options)); + + _this25.mediaSource_ = null; + + _this25.subtitlesTrack_ = null; + return _this25; + } + + /** + * Indicates which time ranges are buffered + * + * @return {TimeRange} + * TimeRange object representing the current buffered ranges + */ + + + VTTSegmentLoader.prototype.buffered_ = function buffered_() { + if (!this.subtitlesTrack_ || !this.subtitlesTrack_.cues.length) { + return videojs$1.createTimeRanges(); + } + + var cues = this.subtitlesTrack_.cues; + var start = cues[0].startTime; + var end = cues[cues.length - 1].startTime; + + return videojs$1.createTimeRanges([[start, end]]); + }; + + /** + * Gets and sets init segment for the provided map + * + * @param {Object} map + * The map object representing the init segment to get or set + * @param {Boolean=} set + * If true, the init segment for the provided map should be saved + * @return {Object} + * map object for desired init segment + */ + + + VTTSegmentLoader.prototype.initSegment = function initSegment(map) { + var set$$1 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!map) { + return null; + } + + var id = initSegmentId(map); + var storedMap = this.initSegments_[id]; + + if (set$$1 && !storedMap && map.bytes) { + // append WebVTT line terminators to the media initialization segment if it exists + // to follow the WebVTT spec (https://w3c.github.io/webvtt/#file-structure) that + // requires two or more WebVTT line terminators between the WebVTT header and the + // rest of the file + var combinedByteLength = VTT_LINE_TERMINATORS.byteLength + map.bytes.byteLength; + var combinedSegment = new Uint8Array(combinedByteLength); + + combinedSegment.set(map.bytes); + combinedSegment.set(VTT_LINE_TERMINATORS, map.bytes.byteLength); + + this.initSegments_[id] = storedMap = { + resolvedUri: map.resolvedUri, + byterange: map.byterange, + bytes: combinedSegment + }; + } + + return storedMap || map; + }; + + /** + * Returns true if all configuration required for loading is present, otherwise false. + * + * @return {Boolean} True if the all configuration is ready for loading + * @private + */ + + + VTTSegmentLoader.prototype.couldBeginLoading_ = function couldBeginLoading_() { + return this.playlist_ && this.subtitlesTrack_ && !this.paused(); + }; + + /** + * Once all the starting parameters have been specified, begin + * operation. This method should only be invoked from the INIT + * state. + * + * @private + */ + + + VTTSegmentLoader.prototype.init_ = function init_() { + this.state = 'READY'; + this.resetEverything(); + return this.monitorBuffer_(); + }; + + /** + * Set a subtitle track on the segment loader to add subtitles to + * + * @param {TextTrack=} track + * The text track to add loaded subtitles to + * @return {TextTrack} + * Returns the subtitles track + */ + + + VTTSegmentLoader.prototype.track = function track(_track) { + if (typeof _track === 'undefined') { + return this.subtitlesTrack_; + } + + this.subtitlesTrack_ = _track; + + // if we were unpaused but waiting for a sourceUpdater, start + // buffering now + if (this.state === 'INIT' && this.couldBeginLoading_()) { + this.init_(); + } + + return this.subtitlesTrack_; + }; + + /** + * Remove any data in the source buffer between start and end times + * @param {Number} start - the start time of the region to remove from the buffer + * @param {Number} end - the end time of the region to remove from the buffer + */ + + + VTTSegmentLoader.prototype.remove = function remove(start, end) { + removeCuesFromTrack(start, end, this.subtitlesTrack_); + }; + + /** + * fill the buffer with segements unless the sourceBuffers are + * currently updating + * + * Note: this function should only ever be called by monitorBuffer_ + * and never directly + * + * @private + */ + + + VTTSegmentLoader.prototype.fillBuffer_ = function fillBuffer_() { + var _this26 = this; + + if (!this.syncPoint_) { + this.syncPoint_ = this.syncController_.getSyncPoint(this.playlist_, this.duration_(), this.currentTimeline_, this.currentTime_()); + } + + // see if we need to begin loading immediately + var segmentInfo = this.checkBuffer_(this.buffered_(), this.playlist_, this.mediaIndex, this.hasPlayed_(), this.currentTime_(), this.syncPoint_); + + segmentInfo = this.skipEmptySegments_(segmentInfo); + + if (!segmentInfo) { + return; + } + + if (this.syncController_.timestampOffsetForTimeline(segmentInfo.timeline) === null) { + // We don't have the timestamp offset that we need to sync subtitles. + // Rerun on a timestamp offset or user interaction. + var checkTimestampOffset = function checkTimestampOffset() { + _this26.state = 'READY'; + if (!_this26.paused()) { + // if not paused, queue a buffer check as soon as possible + _this26.monitorBuffer_(); + } + }; + + this.syncController_.one('timestampoffset', checkTimestampOffset); + this.state = 'WAITING_ON_TIMELINE'; + return; + } + + this.loadSegment_(segmentInfo); + }; + + /** + * Prevents the segment loader from requesting segments we know contain no subtitles + * by walking forward until we find the next segment that we don't know whether it is + * empty or not. + * + * @param {Object} segmentInfo + * a segment info object that describes the current segment + * @return {Object} + * a segment info object that describes the current segment + */ + + + VTTSegmentLoader.prototype.skipEmptySegments_ = function skipEmptySegments_(segmentInfo) { + while (segmentInfo && segmentInfo.segment.empty) { + segmentInfo = this.generateSegmentInfo_(segmentInfo.playlist, segmentInfo.mediaIndex + 1, segmentInfo.startOfSegment + segmentInfo.duration, segmentInfo.isSyncRequest); + } + return segmentInfo; + }; + + /** + * append a decrypted segement to the SourceBuffer through a SourceUpdater + * + * @private + */ + + + VTTSegmentLoader.prototype.handleSegment_ = function handleSegment_() { + var _this27 = this; + + if (!this.pendingSegment_ || !this.subtitlesTrack_) { + this.state = 'READY'; + return; + } + + this.state = 'APPENDING'; + + var segmentInfo = this.pendingSegment_; + var segment = segmentInfo.segment; + + // Make sure that vttjs has loaded, otherwise, wait till it finished loading + if (typeof window_1.WebVTT !== 'function' && this.subtitlesTrack_ && this.subtitlesTrack_.tech_) { + + var loadHandler = function loadHandler() { + _this27.handleSegment_(); + }; + + this.state = 'WAITING_ON_VTTJS'; + this.subtitlesTrack_.tech_.one('vttjsloaded', loadHandler); + this.subtitlesTrack_.tech_.one('vttjserror', function () { + _this27.subtitlesTrack_.tech_.off('vttjsloaded', loadHandler); + _this27.error({ + message: 'Error loading vtt.js' + }); + _this27.state = 'READY'; + _this27.pause(); + _this27.trigger('error'); + }); + + return; + } + + segment.requested = true; + + try { + this.parseVTTCues_(segmentInfo); + } catch (e) { + this.error({ + message: e.message + }); + this.state = 'READY'; + this.pause(); + return this.trigger('error'); + } + + this.updateTimeMapping_(segmentInfo, this.syncController_.timelines[segmentInfo.timeline], this.playlist_); + + if (segmentInfo.isSyncRequest) { + this.trigger('syncinfoupdate'); + this.pendingSegment_ = null; + this.state = 'READY'; + return; + } + + segmentInfo.byteLength = segmentInfo.bytes.byteLength; + + this.mediaSecondsLoaded += segment.duration; + + if (segmentInfo.cues.length) { + // remove any overlapping cues to prevent doubling + this.remove(segmentInfo.cues[0].endTime, segmentInfo.cues[segmentInfo.cues.length - 1].endTime); + } + + segmentInfo.cues.forEach(function (cue) { + _this27.subtitlesTrack_.addCue(cue); + }); + + this.handleUpdateEnd_(); + }; + + /** + * Uses the WebVTT parser to parse the segment response + * + * @param {Object} segmentInfo + * a segment info object that describes the current segment + * @private + */ + + + VTTSegmentLoader.prototype.parseVTTCues_ = function parseVTTCues_(segmentInfo) { + var decoder = void 0; + var decodeBytesToString = false; + + if (typeof window_1.TextDecoder === 'function') { + decoder = new window_1.TextDecoder('utf8'); + } else { + decoder = window_1.WebVTT.StringDecoder(); + decodeBytesToString = true; + } + + var parser = new window_1.WebVTT.Parser(window_1, window_1.vttjs, decoder); + + segmentInfo.cues = []; + segmentInfo.timestampmap = {MPEGTS: 0, LOCAL: 0}; + + parser.oncue = segmentInfo.cues.push.bind(segmentInfo.cues); + parser.ontimestampmap = function (map) { + return segmentInfo.timestampmap = map; + }; + parser.onparsingerror = function (error) { + videojs$1.log.warn('Error encountered when parsing cues: ' + error.message); + }; + + if (segmentInfo.segment.map) { + var mapData = segmentInfo.segment.map.bytes; + + if (decodeBytesToString) { + mapData = uintToString(mapData); + } + + parser.parse(mapData); + } + + var segmentData = segmentInfo.bytes; + + if (decodeBytesToString) { + segmentData = uintToString(segmentData); + } + + parser.parse(segmentData); + parser.flush(); + }; + + /** + * Updates the start and end times of any cues parsed by the WebVTT parser using + * the information parsed from the X-TIMESTAMP-MAP header and a TS to media time mapping + * from the SyncController + * + * @param {Object} segmentInfo + * a segment info object that describes the current segment + * @param {Object} mappingObj + * object containing a mapping from TS to media time + * @param {Object} playlist + * the playlist object containing the segment + * @private + */ + + + VTTSegmentLoader.prototype.updateTimeMapping_ = function updateTimeMapping_(segmentInfo, mappingObj, playlist) { + var segment = segmentInfo.segment; + + if (!mappingObj) { + // If the sync controller does not have a mapping of TS to Media Time for the + // timeline, then we don't have enough information to update the cue + // start/end times + return; + } + + if (!segmentInfo.cues.length) { + // If there are no cues, we also do not have enough information to figure out + // segment timing. Mark that the segment contains no cues so we don't re-request + // an empty segment. + segment.empty = true; + return; + } + + var timestampmap = segmentInfo.timestampmap; + var diff = timestampmap.MPEGTS / 90000 - timestampmap.LOCAL + mappingObj.mapping; + + segmentInfo.cues.forEach(function (cue) { + // First convert cue time to TS time using the timestamp-map provided within the vtt + cue.startTime += diff; + cue.endTime += diff; + }); + + if (!playlist.syncInfo) { + var firstStart = segmentInfo.cues[0].startTime; + var lastStart = segmentInfo.cues[segmentInfo.cues.length - 1].startTime; + + playlist.syncInfo = { + mediaSequence: playlist.mediaSequence + segmentInfo.mediaIndex, + time: Math.min(firstStart, lastStart - segment.duration) + }; + } + }; + + return VTTSegmentLoader; + }(SegmentLoader); + + /** + * @file ad-cue-tags.js + */ + + /** + * Searches for an ad cue that overlaps with the given mediaTime + */ + + + var findAdCue = function findAdCue(track, mediaTime) { + var cues = track.cues; + + for (var i = 0; i < cues.length; i++) { + var cue = cues[i]; + + if (mediaTime >= cue.adStartTime && mediaTime <= cue.adEndTime) { + return cue; + } + } + return null; + }; + + var updateAdCues = function updateAdCues(media, track) { + var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + + if (!media.segments) { + return; + } + + var mediaTime = offset; + var cue = void 0; + + for (var i = 0; i < media.segments.length; i++) { + var segment = media.segments[i]; + + if (!cue) { + // Since the cues will span for at least the segment duration, adding a fudge + // factor of half segment duration will prevent duplicate cues from being + // created when timing info is not exact (e.g. cue start time initialized + // at 10.006677, but next call mediaTime is 10.003332 ) + cue = findAdCue(track, mediaTime + segment.duration / 2); + } + + if (cue) { + if ('cueIn' in segment) { + // Found a CUE-IN so end the cue + cue.endTime = mediaTime; + cue.adEndTime = mediaTime; + mediaTime += segment.duration; + cue = null; + continue; + } + + if (mediaTime < cue.endTime) { + // Already processed this mediaTime for this cue + mediaTime += segment.duration; + continue; + } + + // otherwise extend cue until a CUE-IN is found + cue.endTime += segment.duration; + } else { + if ('cueOut' in segment) { + cue = new window_1.VTTCue(mediaTime, mediaTime + segment.duration, segment.cueOut); + cue.adStartTime = mediaTime; + // Assumes tag format to be + // #EXT-X-CUE-OUT:30 + cue.adEndTime = mediaTime + parseFloat(segment.cueOut); + track.addCue(cue); + } + + if ('cueOutCont' in segment) { + // Entered into the middle of an ad cue + var adOffset = void 0; + var adTotal = void 0; + + // Assumes tag formate to be + // #EXT-X-CUE-OUT-CONT:10/30 + + var _segment$cueOutCont$s = segment.cueOutCont.split('/').map(parseFloat); + + adOffset = _segment$cueOutCont$s[0]; + adTotal = _segment$cueOutCont$s[1]; + + + cue = new window_1.VTTCue(mediaTime, mediaTime + segment.duration, ''); + cue.adStartTime = mediaTime - adOffset; + cue.adEndTime = cue.adStartTime + adTotal; + track.addCue(cue); + } + } + mediaTime += segment.duration; + } + }; + + /** + * @file sync-controller.js + */ + + var tsprobe = tsInspector.inspect; + + var syncPointStrategies = [ + // Stategy "VOD": Handle the VOD-case where the sync-point is *always* + // the equivalence display-time 0 === segment-index 0 + { + name: 'VOD', + run: function run(syncController, playlist, duration$$1, currentTimeline, currentTime) { + if (duration$$1 !== Infinity) { + var syncPoint = { + time: 0, + segmentIndex: 0 + }; + + return syncPoint; + } + return null; + } + }, + // Stategy "ProgramDateTime": We have a program-date-time tag in this playlist + { + name: 'ProgramDateTime', + run: function run(syncController, playlist, duration$$1, currentTimeline, currentTime) { + if (!syncController.datetimeToDisplayTime) { + return null; + } + + var segments = playlist.segments || []; + var syncPoint = null; + var lastDistance = null; + + currentTime = currentTime || 0; + + for (var i = 0; i < segments.length; i++) { + var segment = segments[i]; + + if (segment.dateTimeObject) { + var segmentTime = segment.dateTimeObject.getTime() / 1000; + var segmentStart = segmentTime + syncController.datetimeToDisplayTime; + var distance = Math.abs(currentTime - segmentStart); + + // Once the distance begins to increase, we have passed + // currentTime and can stop looking for better candidates + if (lastDistance !== null && lastDistance < distance) { + break; + } + + lastDistance = distance; + syncPoint = { + time: segmentStart, + segmentIndex: i + }; + } + } + return syncPoint; + } + }, + // Stategy "Segment": We have a known time mapping for a timeline and a + // segment in the current timeline with timing data + { + name: 'Segment', + run: function run(syncController, playlist, duration$$1, currentTimeline, currentTime) { + var segments = playlist.segments || []; + var syncPoint = null; + var lastDistance = null; + + currentTime = currentTime || 0; + + for (var i = 0; i < segments.length; i++) { + var segment = segments[i]; + + if (segment.timeline === currentTimeline && typeof segment.start !== 'undefined') { + var distance = Math.abs(currentTime - segment.start); + + // Once the distance begins to increase, we have passed + // currentTime and can stop looking for better candidates + if (lastDistance !== null && lastDistance < distance) { + break; + } + + if (!syncPoint || lastDistance === null || lastDistance >= distance) { + lastDistance = distance; + syncPoint = { + time: segment.start, + segmentIndex: i + }; + } + } + } + return syncPoint; + } + }, + // Stategy "Discontinuity": We have a discontinuity with a known + // display-time + { + name: 'Discontinuity', + run: function run(syncController, playlist, duration$$1, currentTimeline, currentTime) { + var syncPoint = null; + + currentTime = currentTime || 0; + + if (playlist.discontinuityStarts && playlist.discontinuityStarts.length) { + var lastDistance = null; + + for (var i = 0; i < playlist.discontinuityStarts.length; i++) { + var segmentIndex = playlist.discontinuityStarts[i]; + var discontinuity = playlist.discontinuitySequence + i + 1; + var discontinuitySync = syncController.discontinuities[discontinuity]; + + if (discontinuitySync) { + var distance = Math.abs(currentTime - discontinuitySync.time); + + // Once the distance begins to increase, we have passed + // currentTime and can stop looking for better candidates + if (lastDistance !== null && lastDistance < distance) { + break; + } + + if (!syncPoint || lastDistance === null || lastDistance >= distance) { + lastDistance = distance; + syncPoint = { + time: discontinuitySync.time, + segmentIndex: segmentIndex + }; + } + } + } + } + return syncPoint; + } + }, + // Stategy "Playlist": We have a playlist with a known mapping of + // segment index to display time + { + name: 'Playlist', + run: function run(syncController, playlist, duration$$1, currentTimeline, currentTime) { + if (playlist.syncInfo) { + var syncPoint = { + time: playlist.syncInfo.time, + segmentIndex: playlist.syncInfo.mediaSequence - playlist.mediaSequence + }; + + return syncPoint; + } + return null; + } + }]; + + var SyncController = function (_videojs$EventTarget4) { + inherits(SyncController, _videojs$EventTarget4); + + function SyncController() { + classCallCheck(this, SyncController); + + // Segment Loader state variables... + // ...for synching across variants + var _this28 = possibleConstructorReturn(this, _videojs$EventTarget4.call(this)); + + _this28.inspectCache_ = undefined; + + // ...for synching across variants + _this28.timelines = []; + _this28.discontinuities = []; + _this28.datetimeToDisplayTime = null; + + _this28.logger_ = logger('SyncController'); + return _this28; + } + + /** + * Find a sync-point for the playlist specified + * + * A sync-point is defined as a known mapping from display-time to + * a segment-index in the current playlist. + * + * @param {Playlist} playlist + * The playlist that needs a sync-point + * @param {Number} duration + * Duration of the MediaSource (Infinite if playing a live source) + * @param {Number} currentTimeline + * The last timeline from which a segment was loaded + * @returns {Object} + * A sync-point object + */ + + + SyncController.prototype.getSyncPoint = function getSyncPoint(playlist, duration$$1, currentTimeline, currentTime) { + var syncPoints = this.runStrategies_(playlist, duration$$1, currentTimeline, currentTime); + + if (!syncPoints.length) { + // Signal that we need to attempt to get a sync-point manually + // by fetching a segment in the playlist and constructing + // a sync-point from that information + return null; + } + + // Now find the sync-point that is closest to the currentTime because + // that should result in the most accurate guess about which segment + // to fetch + return this.selectSyncPoint_(syncPoints, {key: 'time', value: currentTime}); + }; + + /** + * Calculate the amount of time that has expired off the playlist during playback + * + * @param {Playlist} playlist + * Playlist object to calculate expired from + * @param {Number} duration + * Duration of the MediaSource (Infinity if playling a live source) + * @returns {Number|null} + * The amount of time that has expired off the playlist during playback. Null + * if no sync-points for the playlist can be found. + */ + + + SyncController.prototype.getExpiredTime = function getExpiredTime(playlist, duration$$1) { + if (!playlist || !playlist.segments) { + return null; + } + + var syncPoints = this.runStrategies_(playlist, duration$$1, playlist.discontinuitySequence, 0); + + // Without sync-points, there is not enough information to determine the expired time + if (!syncPoints.length) { + return null; + } + + var syncPoint = this.selectSyncPoint_(syncPoints, { + key: 'segmentIndex', + value: 0 + }); + + // If the sync-point is beyond the start of the playlist, we want to subtract the + // duration from index 0 to syncPoint.segmentIndex instead of adding. + if (syncPoint.segmentIndex > 0) { + syncPoint.time *= -1; + } + + return Math.abs(syncPoint.time + sumDurations(playlist, syncPoint.segmentIndex, 0)); + }; + + /** + * Runs each sync-point strategy and returns a list of sync-points returned by the + * strategies + * + * @private + * @param {Playlist} playlist + * The playlist that needs a sync-point + * @param {Number} duration + * Duration of the MediaSource (Infinity if playing a live source) + * @param {Number} currentTimeline + * The last timeline from which a segment was loaded + * @returns {Array} + * A list of sync-point objects + */ + + + SyncController.prototype.runStrategies_ = function runStrategies_(playlist, duration$$1, currentTimeline, currentTime) { + var syncPoints = []; + + // Try to find a sync-point in by utilizing various strategies... + for (var i = 0; i < syncPointStrategies.length; i++) { + var strategy = syncPointStrategies[i]; + var syncPoint = strategy.run(this, playlist, duration$$1, currentTimeline, currentTime); + + if (syncPoint) { + syncPoint.strategy = strategy.name; + syncPoints.push({ + strategy: strategy.name, + syncPoint: syncPoint + }); + } + } + + return syncPoints; + }; + + /** + * Selects the sync-point nearest the specified target + * + * @private + * @param {Array} syncPoints + * List of sync-points to select from + * @param {Object} target + * Object specifying the property and value we are targeting + * @param {String} target.key + * Specifies the property to target. Must be either 'time' or 'segmentIndex' + * @param {Number} target.value + * The value to target for the specified key. + * @returns {Object} + * The sync-point nearest the target + */ + + + SyncController.prototype.selectSyncPoint_ = function selectSyncPoint_(syncPoints, target) { + var bestSyncPoint = syncPoints[0].syncPoint; + var bestDistance = Math.abs(syncPoints[0].syncPoint[target.key] - target.value); + var bestStrategy = syncPoints[0].strategy; + + for (var i = 1; i < syncPoints.length; i++) { + var newDistance = Math.abs(syncPoints[i].syncPoint[target.key] - target.value); + + if (newDistance < bestDistance) { + bestDistance = newDistance; + bestSyncPoint = syncPoints[i].syncPoint; + bestStrategy = syncPoints[i].strategy; + } + } + + this.logger_('syncPoint for [' + target.key + ': ' + target.value + '] chosen with strategy' + (' [' + bestStrategy + ']: [time:' + bestSyncPoint.time + ',') + (' segmentIndex:' + bestSyncPoint.segmentIndex + ']')); + + return bestSyncPoint; + }; + + /** + * Save any meta-data present on the segments when segments leave + * the live window to the playlist to allow for synchronization at the + * playlist level later. + * + * @param {Playlist} oldPlaylist - The previous active playlist + * @param {Playlist} newPlaylist - The updated and most current playlist + */ + + + SyncController.prototype.saveExpiredSegmentInfo = function saveExpiredSegmentInfo(oldPlaylist, newPlaylist) { + var mediaSequenceDiff = newPlaylist.mediaSequence - oldPlaylist.mediaSequence; + + // When a segment expires from the playlist and it has a start time + // save that information as a possible sync-point reference in future + for (var i = mediaSequenceDiff - 1; i >= 0; i--) { + var lastRemovedSegment = oldPlaylist.segments[i]; + + if (lastRemovedSegment && typeof lastRemovedSegment.start !== 'undefined') { + newPlaylist.syncInfo = { + mediaSequence: oldPlaylist.mediaSequence + i, + time: lastRemovedSegment.start + }; + this.logger_('playlist refresh sync: [time:' + newPlaylist.syncInfo.time + ',' + (' mediaSequence: ' + newPlaylist.syncInfo.mediaSequence + ']')); + this.trigger('syncinfoupdate'); + break; + } + } + }; + + /** + * Save the mapping from playlist's ProgramDateTime to display. This should + * only ever happen once at the start of playback. + * + * @param {Playlist} playlist - The currently active playlist + */ + + + SyncController.prototype.setDateTimeMapping = function setDateTimeMapping(playlist) { + if (!this.datetimeToDisplayTime && playlist.segments && playlist.segments.length && playlist.segments[0].dateTimeObject) { + var playlistTimestamp = playlist.segments[0].dateTimeObject.getTime() / 1000; + + this.datetimeToDisplayTime = -playlistTimestamp; + } + }; + + /** + * Reset the state of the inspection cache when we do a rendition + * switch + */ + + + SyncController.prototype.reset = function reset() { + this.inspectCache_ = undefined; + }; + + /** + * Probe or inspect a fmp4 or an mpeg2-ts segment to determine the start + * and end of the segment in it's internal "media time". Used to generate + * mappings from that internal "media time" to the display time that is + * shown on the player. + * + * @param {SegmentInfo} segmentInfo - The current active request information + */ + + + SyncController.prototype.probeSegmentInfo = function probeSegmentInfo(segmentInfo) { + var segment = segmentInfo.segment; + var playlist = segmentInfo.playlist; + var timingInfo = void 0; + + if (segment.map) { + timingInfo = this.probeMp4Segment_(segmentInfo); + } else { + timingInfo = this.probeTsSegment_(segmentInfo); + } + + if (timingInfo) { + if (this.calculateSegmentTimeMapping_(segmentInfo, timingInfo)) { + this.saveDiscontinuitySyncInfo_(segmentInfo); + + // If the playlist does not have sync information yet, record that information + // now with segment timing information + if (!playlist.syncInfo) { + playlist.syncInfo = { + mediaSequence: playlist.mediaSequence + segmentInfo.mediaIndex, + time: segment.start + }; + } + } + } + + return timingInfo; + }; + + /** + * Probe an fmp4 or an mpeg2-ts segment to determine the start of the segment + * in it's internal "media time". + * + * @private + * @param {SegmentInfo} segmentInfo - The current active request information + * @return {object} The start and end time of the current segment in "media time" + */ + + + SyncController.prototype.probeMp4Segment_ = function probeMp4Segment_(segmentInfo) { + var segment = segmentInfo.segment; + var timescales = probe.timescale(segment.map.bytes); + var startTime = probe.startTime(timescales, segmentInfo.bytes); + + if (segmentInfo.timestampOffset !== null) { + segmentInfo.timestampOffset -= startTime; + } + + return { + start: startTime, + end: startTime + segment.duration + }; + }; + + /** + * Probe an mpeg2-ts segment to determine the start and end of the segment + * in it's internal "media time". + * + * @private + * @param {SegmentInfo} segmentInfo - The current active request information + * @return {object} The start and end time of the current segment in "media time" + */ + + + SyncController.prototype.probeTsSegment_ = function probeTsSegment_(segmentInfo) { + var timeInfo = tsprobe(segmentInfo.bytes, this.inspectCache_); + var segmentStartTime = void 0; + var segmentEndTime = void 0; + + if (!timeInfo) { + return null; + } + + if (timeInfo.video && timeInfo.video.length === 2) { + this.inspectCache_ = timeInfo.video[1].dts; + segmentStartTime = timeInfo.video[0].dtsTime; + segmentEndTime = timeInfo.video[1].dtsTime; + } else if (timeInfo.audio && timeInfo.audio.length === 2) { + this.inspectCache_ = timeInfo.audio[1].dts; + segmentStartTime = timeInfo.audio[0].dtsTime; + segmentEndTime = timeInfo.audio[1].dtsTime; + } + + return { + start: segmentStartTime, + end: segmentEndTime, + containsVideo: timeInfo.video && timeInfo.video.length === 2, + containsAudio: timeInfo.audio && timeInfo.audio.length === 2 + }; + }; + + SyncController.prototype.timestampOffsetForTimeline = function timestampOffsetForTimeline(timeline) { + if (typeof this.timelines[timeline] === 'undefined') { + return null; + } + return this.timelines[timeline].time; + }; + + SyncController.prototype.mappingForTimeline = function mappingForTimeline(timeline) { + if (typeof this.timelines[timeline] === 'undefined') { + return null; + } + return this.timelines[timeline].mapping; + }; + + /** + * Use the "media time" for a segment to generate a mapping to "display time" and + * save that display time to the segment. + * + * @private + * @param {SegmentInfo} segmentInfo + * The current active request information + * @param {object} timingInfo + * The start and end time of the current segment in "media time" + * @returns {Boolean} + * Returns false if segment time mapping could not be calculated + */ + + + SyncController.prototype.calculateSegmentTimeMapping_ = function calculateSegmentTimeMapping_(segmentInfo, timingInfo) { + var segment = segmentInfo.segment; + var mappingObj = this.timelines[segmentInfo.timeline]; + + if (segmentInfo.timestampOffset !== null) { + mappingObj = { + time: segmentInfo.startOfSegment, + mapping: segmentInfo.startOfSegment - timingInfo.start + }; + this.timelines[segmentInfo.timeline] = mappingObj; + this.trigger('timestampoffset'); + + this.logger_('time mapping for timeline ' + segmentInfo.timeline + ': ' + ('[time: ' + mappingObj.time + '] [mapping: ' + mappingObj.mapping + ']')); + + segment.start = segmentInfo.startOfSegment; + segment.end = timingInfo.end + mappingObj.mapping; + } else if (mappingObj) { + segment.start = timingInfo.start + mappingObj.mapping; + segment.end = timingInfo.end + mappingObj.mapping; + } else { + return false; + } + + return true; + }; + + /** + * Each time we have discontinuity in the playlist, attempt to calculate the location + * in display of the start of the discontinuity and save that. We also save an accuracy + * value so that we save values with the most accuracy (closest to 0.) + * + * @private + * @param {SegmentInfo} segmentInfo - The current active request information + */ + + + SyncController.prototype.saveDiscontinuitySyncInfo_ = function saveDiscontinuitySyncInfo_(segmentInfo) { + var playlist = segmentInfo.playlist; + var segment = segmentInfo.segment; + + // If the current segment is a discontinuity then we know exactly where + // the start of the range and it's accuracy is 0 (greater accuracy values + // mean more approximation) + if (segment.discontinuity) { + this.discontinuities[segment.timeline] = { + time: segment.start, + accuracy: 0 + }; + } else if (playlist.discontinuityStarts && playlist.discontinuityStarts.length) { + // Search for future discontinuities that we can provide better timing + // information for and save that information for sync purposes + for (var i = 0; i < playlist.discontinuityStarts.length; i++) { + var segmentIndex = playlist.discontinuityStarts[i]; + var discontinuity = playlist.discontinuitySequence + i + 1; + var mediaIndexDiff = segmentIndex - segmentInfo.mediaIndex; + var accuracy = Math.abs(mediaIndexDiff); + + if (!this.discontinuities[discontinuity] || this.discontinuities[discontinuity].accuracy > accuracy) { + var time = void 0; + + if (mediaIndexDiff < 0) { + time = segment.start - sumDurations(playlist, segmentInfo.mediaIndex, segmentIndex); + } else { + time = segment.end + sumDurations(playlist, segmentInfo.mediaIndex + 1, segmentIndex); + } + + this.discontinuities[discontinuity] = { + time: time, + accuracy: accuracy + }; + } + } + } + }; + + return SyncController; + }(videojs$1.EventTarget); + + var Decrypter$1 = new shimWorker("./decrypter-worker.worker.js", function (window, document$$1) { + var self = this; + var decrypterWorker = function () { + + var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + var win; + + if (typeof window !== "undefined") { + win = window; + } else if (typeof commonjsGlobal !== "undefined") { + win = commonjsGlobal; + } else if (typeof self !== "undefined") { + win = self; + } else { + win = {}; + } + + var window_1$$1 = win; + + /* + * pkcs7.pad + * https://github.com/brightcove/pkcs7 + * + * Copyright (c) 2014 Brightcove + * Licensed under the apache2 license. + */ + + /** + * Returns the subarray of a Uint8Array without PKCS#7 padding. + * @param padded {Uint8Array} unencrypted bytes that have been padded + * @return {Uint8Array} the unpadded bytes + * @see http://tools.ietf.org/html/rfc5652 + */ + function unpad(padded) { + return padded.subarray(0, padded.byteLength - padded[padded.byteLength - 1]); + } + + var classCallCheck$$1 = function classCallCheck$$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + var createClass$$1 = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var inherits$$1 = function inherits$$1(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === 'undefined' ? 'undefined' : _typeof(superClass))); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + }; + + var possibleConstructorReturn$$1 = function possibleConstructorReturn$$1(self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && ((typeof call === 'undefined' ? 'undefined' : _typeof(call)) === "object" || typeof call === "function") ? call : self; + }; + + /** + * @file aes.js + * + * This file contains an adaptation of the AES decryption algorithm + * from the Standford Javascript Cryptography Library. That work is + * covered by the following copyright and permissions notice: + * + * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies, either expressed or implied, of the authors. + */ + + /** + * Expand the S-box tables. + * + * @private + */ + var precompute = function precompute() { + var tables = [[[], [], [], [], []], [[], [], [], [], []]]; + var encTable = tables[0]; + var decTable = tables[1]; + var sbox = encTable[4]; + var sboxInv = decTable[4]; + var i = void 0; + var x = void 0; + var xInv = void 0; + var d = []; + var th = []; + var x2 = void 0; + var x4 = void 0; + var x8 = void 0; + var s = void 0; + var tEnc = void 0; + var tDec = void 0; + + // Compute double and third tables + for (i = 0; i < 256; i++) { + th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i; + } + + for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) { + // Compute sbox + s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4; + s = s >> 8 ^ s & 255 ^ 99; + sbox[x] = s; + sboxInv[s] = x; + + // Compute MixColumns + x8 = d[x4 = d[x2 = d[x]]]; + tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100; + tEnc = d[s] * 0x101 ^ s * 0x1010100; + + for (i = 0; i < 4; i++) { + encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8; + decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8; + } + } + + // Compactify. Considerable speedup on Firefox. + for (i = 0; i < 5; i++) { + encTable[i] = encTable[i].slice(0); + decTable[i] = decTable[i].slice(0); + } + return tables; + }; + var aesTables = null; + + /** + * Schedule out an AES key for both encryption and decryption. This + * is a low-level class. Use a cipher mode to do bulk encryption. + * + * @class AES + * @param key {Array} The key as an array of 4, 6 or 8 words. + */ + + var AES = function () { + function AES(key) { + classCallCheck$$1(this, AES); + + /** + * The expanded S-box and inverse S-box tables. These will be computed + * on the client so that we don't have to send them down the wire. + * + * There are two tables, _tables[0] is for encryption and + * _tables[1] is for decryption. + * + * The first 4 sub-tables are the expanded S-box with MixColumns. The + * last (_tables[01][4]) is the S-box itself. + * + * @private + */ + // if we have yet to precompute the S-box tables + // do so now + if (!aesTables) { + aesTables = precompute(); + } + // then make a copy of that object for use + this._tables = [[aesTables[0][0].slice(), aesTables[0][1].slice(), aesTables[0][2].slice(), aesTables[0][3].slice(), aesTables[0][4].slice()], [aesTables[1][0].slice(), aesTables[1][1].slice(), aesTables[1][2].slice(), aesTables[1][3].slice(), aesTables[1][4].slice()]]; + var i = void 0; + var j = void 0; + var tmp = void 0; + var encKey = void 0; + var decKey = void 0; + var sbox = this._tables[0][4]; + var decTable = this._tables[1]; + var keyLen = key.length; + var rcon = 1; + + if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) { + throw new Error('Invalid aes key size'); + } + + encKey = key.slice(0); + decKey = []; + this._key = [encKey, decKey]; + + // schedule encryption keys + for (i = keyLen; i < 4 * keyLen + 28; i++) { + tmp = encKey[i - 1]; + + // apply sbox + if (i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) { + tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255]; + + // shift rows and add rcon + if (i % keyLen === 0) { + tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24; + rcon = rcon << 1 ^ (rcon >> 7) * 283; + } + } + + encKey[i] = encKey[i - keyLen] ^ tmp; + } + + // schedule decryption keys + for (j = 0; i; j++, i--) { + tmp = encKey[j & 3 ? i : i - 4]; + if (i <= 4 || j < 4) { + decKey[j] = tmp; + } else { + decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]]; + } + } + } + + /** + * Decrypt 16 bytes, specified as four 32-bit words. + * + * @param {Number} encrypted0 the first word to decrypt + * @param {Number} encrypted1 the second word to decrypt + * @param {Number} encrypted2 the third word to decrypt + * @param {Number} encrypted3 the fourth word to decrypt + * @param {Int32Array} out the array to write the decrypted words + * into + * @param {Number} offset the offset into the output array to start + * writing results + * @return {Array} The plaintext. + */ + + AES.prototype.decrypt = function decrypt$$1(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) { + var key = this._key[1]; + // state variables a,b,c,d are loaded with pre-whitened data + var a = encrypted0 ^ key[0]; + var b = encrypted3 ^ key[1]; + var c = encrypted2 ^ key[2]; + var d = encrypted1 ^ key[3]; + var a2 = void 0; + var b2 = void 0; + var c2 = void 0; + + // key.length === 2 ? + var nInnerRounds = key.length / 4 - 2; + var i = void 0; + var kIndex = 4; + var table = this._tables[1]; + + // load up the tables + var table0 = table[0]; + var table1 = table[1]; + var table2 = table[2]; + var table3 = table[3]; + var sbox = table[4]; + + // Inner rounds. Cribbed from OpenSSL. + for (i = 0; i < nInnerRounds; i++) { + a2 = table0[a >>> 24] ^ table1[b >> 16 & 255] ^ table2[c >> 8 & 255] ^ table3[d & 255] ^ key[kIndex]; + b2 = table0[b >>> 24] ^ table1[c >> 16 & 255] ^ table2[d >> 8 & 255] ^ table3[a & 255] ^ key[kIndex + 1]; + c2 = table0[c >>> 24] ^ table1[d >> 16 & 255] ^ table2[a >> 8 & 255] ^ table3[b & 255] ^ key[kIndex + 2]; + d = table0[d >>> 24] ^ table1[a >> 16 & 255] ^ table2[b >> 8 & 255] ^ table3[c & 255] ^ key[kIndex + 3]; + kIndex += 4; + a = a2; + b = b2; + c = c2; + } + + // Last round. + for (i = 0; i < 4; i++) { + out[(3 & -i) + offset] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++]; + a2 = a; + a = b; + b = c; + c = d; + d = a2; + } + }; + + return AES; + }(); + + /** + * @file stream.js + */ + /** + * A lightweight readable stream implemention that handles event dispatching. + * + * @class Stream + */ + var Stream = function () { + function Stream() { + classCallCheck$$1(this, Stream); + + this.listeners = {}; + } + + /** + * Add a listener for a specified event type. + * + * @param {String} type the event name + * @param {Function} listener the callback to be invoked when an event of + * the specified type occurs + */ + + Stream.prototype.on = function on(type, listener) { + if (!this.listeners[type]) { + this.listeners[type] = []; + } + this.listeners[type].push(listener); + }; + + /** + * Remove a listener for a specified event type. + * + * @param {String} type the event name + * @param {Function} listener a function previously registered for this + * type of event through `on` + * @return {Boolean} if we could turn it off or not + */ + + Stream.prototype.off = function off(type, listener) { + if (!this.listeners[type]) { + return false; + } + + var index = this.listeners[type].indexOf(listener); + + this.listeners[type].splice(index, 1); + return index > -1; + }; + + /** + * Trigger an event of the specified type on this stream. Any additional + * arguments to this function are passed as parameters to event listeners. + * + * @param {String} type the event name + */ + + Stream.prototype.trigger = function trigger(type) { + var callbacks = this.listeners[type]; + + if (!callbacks) { + return; + } + + // Slicing the arguments on every invocation of this method + // can add a significant amount of overhead. Avoid the + // intermediate object creation for the common case of a + // single callback argument + if (arguments.length === 2) { + var length = callbacks.length; + + for (var i = 0; i < length; ++i) { + callbacks[i].call(this, arguments[1]); + } + } else { + var args = Array.prototype.slice.call(arguments, 1); + var _length = callbacks.length; + + for (var _i = 0; _i < _length; ++_i) { + callbacks[_i].apply(this, args); + } + } + }; + + /** + * Destroys the stream and cleans up. + */ + + Stream.prototype.dispose = function dispose() { + this.listeners = {}; + }; + /** + * Forwards all `data` events on this stream to the destination stream. The + * destination stream should provide a method `push` to receive the data + * events as they arrive. + * + * @param {Stream} destination the stream that will receive all `data` events + * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options + */ + + Stream.prototype.pipe = function pipe(destination) { + this.on('data', function (data) { + destination.push(data); + }); + }; + + return Stream; + }(); + + /** + * @file async-stream.js + */ + /** + * A wrapper around the Stream class to use setTiemout + * and run stream "jobs" Asynchronously + * + * @class AsyncStream + * @extends Stream + */ + + var AsyncStream$$1 = function (_Stream) { + inherits$$1(AsyncStream$$1, _Stream); + + function AsyncStream$$1() { + classCallCheck$$1(this, AsyncStream$$1); + + var _this = possibleConstructorReturn$$1(this, _Stream.call(this, Stream)); + + _this.jobs = []; + _this.delay = 1; + _this.timeout_ = null; + return _this; + } + + /** + * process an async job + * + * @private + */ + + AsyncStream$$1.prototype.processJob_ = function processJob_() { + this.jobs.shift()(); + if (this.jobs.length) { + this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay); + } else { + this.timeout_ = null; + } + }; + + /** + * push a job into the stream + * + * @param {Function} job the job to push into the stream + */ + + AsyncStream$$1.prototype.push = function push(job) { + this.jobs.push(job); + if (!this.timeout_) { + this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay); + } + }; + + return AsyncStream$$1; + }(Stream); + + /** + * @file decrypter.js + * + * An asynchronous implementation of AES-128 CBC decryption with + * PKCS#7 padding. + */ + + /** + * Convert network-order (big-endian) bytes into their little-endian + * representation. + */ + var ntoh = function ntoh(word) { + return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24; + }; + + /** + * Decrypt bytes using AES-128 with CBC and PKCS#7 padding. + * + * @param {Uint8Array} encrypted the encrypted bytes + * @param {Uint32Array} key the bytes of the decryption key + * @param {Uint32Array} initVector the initialization vector (IV) to + * use for the first round of CBC. + * @return {Uint8Array} the decrypted bytes + * + * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard + * @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29 + * @see https://tools.ietf.org/html/rfc2315 + */ + var decrypt$$1 = function decrypt$$1(encrypted, key, initVector) { + // word-level access to the encrypted bytes + var encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2); + + var decipher = new AES(Array.prototype.slice.call(key)); + + // byte and word-level access for the decrypted output + var decrypted = new Uint8Array(encrypted.byteLength); + var decrypted32 = new Int32Array(decrypted.buffer); + + // temporary variables for working with the IV, encrypted, and + // decrypted data + var init0 = void 0; + var init1 = void 0; + var init2 = void 0; + var init3 = void 0; + var encrypted0 = void 0; + var encrypted1 = void 0; + var encrypted2 = void 0; + var encrypted3 = void 0; + + // iteration variable + var wordIx = void 0; + + // pull out the words of the IV to ensure we don't modify the + // passed-in reference and easier access + init0 = initVector[0]; + init1 = initVector[1]; + init2 = initVector[2]; + init3 = initVector[3]; + + // decrypt four word sequences, applying cipher-block chaining (CBC) + // to each decrypted block + for (wordIx = 0; wordIx < encrypted32.length; wordIx += 4) { + // convert big-endian (network order) words into little-endian + // (javascript order) + encrypted0 = ntoh(encrypted32[wordIx]); + encrypted1 = ntoh(encrypted32[wordIx + 1]); + encrypted2 = ntoh(encrypted32[wordIx + 2]); + encrypted3 = ntoh(encrypted32[wordIx + 3]); + + // decrypt the block + decipher.decrypt(encrypted0, encrypted1, encrypted2, encrypted3, decrypted32, wordIx); + + // XOR with the IV, and restore network byte-order to obtain the + // plaintext + decrypted32[wordIx] = ntoh(decrypted32[wordIx] ^ init0); + decrypted32[wordIx + 1] = ntoh(decrypted32[wordIx + 1] ^ init1); + decrypted32[wordIx + 2] = ntoh(decrypted32[wordIx + 2] ^ init2); + decrypted32[wordIx + 3] = ntoh(decrypted32[wordIx + 3] ^ init3); + + // setup the IV for the next round + init0 = encrypted0; + init1 = encrypted1; + init2 = encrypted2; + init3 = encrypted3; + } + + return decrypted; + }; + + /** + * The `Decrypter` class that manages decryption of AES + * data through `AsyncStream` objects and the `decrypt` + * function + * + * @param {Uint8Array} encrypted the encrypted bytes + * @param {Uint32Array} key the bytes of the decryption key + * @param {Uint32Array} initVector the initialization vector (IV) to + * @param {Function} done the function to run when done + * @class Decrypter + */ + + var Decrypter$$1 = function () { + function Decrypter$$1(encrypted, key, initVector, done) { + classCallCheck$$1(this, Decrypter$$1); + + var step = Decrypter$$1.STEP; + var encrypted32 = new Int32Array(encrypted.buffer); + var decrypted = new Uint8Array(encrypted.byteLength); + var i = 0; + + this.asyncStream_ = new AsyncStream$$1(); + + // split up the encryption job and do the individual chunks asynchronously + this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted)); + for (i = step; i < encrypted32.length; i += step) { + initVector = new Uint32Array([ntoh(encrypted32[i - 4]), ntoh(encrypted32[i - 3]), ntoh(encrypted32[i - 2]), ntoh(encrypted32[i - 1])]); + this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted)); + } + // invoke the done() callback when everything is finished + this.asyncStream_.push(function () { + // remove pkcs#7 padding from the decrypted bytes + done(null, unpad(decrypted)); + }); + } + + /** + * a getter for step the maximum number of bytes to process at one time + * + * @return {Number} the value of step 32000 + */ + + /** + * @private + */ + Decrypter$$1.prototype.decryptChunk_ = function decryptChunk_(encrypted, key, initVector, decrypted) { + return function () { + var bytes = decrypt$$1(encrypted, key, initVector); + + decrypted.set(bytes, encrypted.byteOffset); + }; + }; + + createClass$$1(Decrypter$$1, null, [{ + key: 'STEP', + get: function get$$1() { + // 4 * 8000; + return 32000; + } + }]); + return Decrypter$$1; + }(); + + /** + * @file bin-utils.js + */ + + /** + * Creates an object for sending to a web worker modifying properties that are TypedArrays + * into a new object with seperated properties for the buffer, byteOffset, and byteLength. + * + * @param {Object} message + * Object of properties and values to send to the web worker + * @return {Object} + * Modified message with TypedArray values expanded + * @function createTransferableMessage + */ + var createTransferableMessage = function createTransferableMessage(message) { + var transferable = {}; + + Object.keys(message).forEach(function (key) { + var value = message[key]; + + if (ArrayBuffer.isView(value)) { + transferable[key] = { + bytes: value.buffer, + byteOffset: value.byteOffset, + byteLength: value.byteLength + }; + } else { + transferable[key] = value; + } + }); + + return transferable; + }; + + /** + * Our web worker interface so that things can talk to aes-decrypter + * that will be running in a web worker. the scope is passed to this by + * webworkify. + * + * @param {Object} self + * the scope for the web worker + */ + var DecrypterWorker = function DecrypterWorker(self) { + self.onmessage = function (event) { + var data = event.data; + var encrypted = new Uint8Array(data.encrypted.bytes, data.encrypted.byteOffset, data.encrypted.byteLength); + var key = new Uint32Array(data.key.bytes, data.key.byteOffset, data.key.byteLength / 4); + var iv = new Uint32Array(data.iv.bytes, data.iv.byteOffset, data.iv.byteLength / 4); + + /* eslint-disable no-new, handle-callback-err */ + new Decrypter$$1(encrypted, key, iv, function (err, bytes) { + window_1$$1.postMessage(createTransferableMessage({ + source: data.source, + decrypted: bytes + }), [bytes.buffer]); + }); + /* eslint-enable */ + }; + }; + + var decrypterWorker = new DecrypterWorker(self); + + return decrypterWorker; + }(); + }); + + /** + * Convert the properties of an HLS track into an audioTrackKind. + * + * @private + */ + var audioTrackKind_ = function audioTrackKind_(properties) { + var kind = properties.default ? 'main' : 'alternative'; + + if (properties.characteristics && properties.characteristics.indexOf('public.accessibility.describes-video') >= 0) { + kind = 'main-desc'; + } + + return kind; + }; + + /** + * Pause provided segment loader and playlist loader if active + * + * @param {SegmentLoader} segmentLoader + * SegmentLoader to pause + * @param {Object} mediaType + * Active media type + * @function stopLoaders + */ + var stopLoaders = function stopLoaders(segmentLoader, mediaType) { + segmentLoader.abort(); + segmentLoader.pause(); + + if (mediaType && mediaType.activePlaylistLoader) { + mediaType.activePlaylistLoader.pause(); + mediaType.activePlaylistLoader = null; + } + }; + + /** + * Start loading provided segment loader and playlist loader + * + * @param {PlaylistLoader} playlistLoader + * PlaylistLoader to start loading + * @param {Object} mediaType + * Active media type + * @function startLoaders + */ + var startLoaders = function startLoaders(playlistLoader, mediaType) { + // Segment loader will be started after `loadedmetadata` or `loadedplaylist` from the + // playlist loader + mediaType.activePlaylistLoader = playlistLoader; + playlistLoader.load(); + }; + + /** + * Returns a function to be called when the media group changes. It performs a + * non-destructive (preserve the buffer) resync of the SegmentLoader. This is because a + * change of group is merely a rendition switch of the same content at another encoding, + * rather than a change of content, such as switching audio from English to Spanish. + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @return {Function} + * Handler for a non-destructive resync of SegmentLoader when the active media + * group changes. + * @function onGroupChanged + */ + var onGroupChanged = function onGroupChanged(type, settings) { + return function () { + var _settings$segmentLoad = settings.segmentLoaders, + segmentLoader = _settings$segmentLoad[type], + mainSegmentLoader = _settings$segmentLoad.main, + mediaType = settings.mediaTypes[type]; + + var activeTrack = mediaType.activeTrack(); + var activeGroup = mediaType.activeGroup(activeTrack); + var previousActiveLoader = mediaType.activePlaylistLoader; + + stopLoaders(segmentLoader, mediaType); + + if (!activeGroup) { + // there is no group active + return; + } + + if (!activeGroup.playlistLoader) { + if (previousActiveLoader) { + // The previous group had a playlist loader but the new active group does not + // this means we are switching from demuxed to muxed audio. In this case we want to + // do a destructive reset of the main segment loader and not restart the audio + // loaders. + mainSegmentLoader.resetEverything(); + } + return; + } + + // Non-destructive resync + segmentLoader.resyncLoader(); + + startLoaders(activeGroup.playlistLoader, mediaType); + }; + }; + + /** + * Returns a function to be called when the media track changes. It performs a + * destructive reset of the SegmentLoader to ensure we start loading as close to + * currentTime as possible. + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @return {Function} + * Handler for a destructive reset of SegmentLoader when the active media + * track changes. + * @function onTrackChanged + */ + var onTrackChanged = function onTrackChanged(type, settings) { + return function () { + var _settings$segmentLoad2 = settings.segmentLoaders, + segmentLoader = _settings$segmentLoad2[type], + mainSegmentLoader = _settings$segmentLoad2.main, + mediaType = settings.mediaTypes[type]; + + var activeTrack = mediaType.activeTrack(); + var activeGroup = mediaType.activeGroup(activeTrack); + var previousActiveLoader = mediaType.activePlaylistLoader; + + stopLoaders(segmentLoader, mediaType); + + if (!activeGroup) { + // there is no group active so we do not want to restart loaders + return; + } + + if (!activeGroup.playlistLoader) { + // when switching from demuxed audio/video to muxed audio/video (noted by no playlist + // loader for the audio group), we want to do a destructive reset of the main segment + // loader and not restart the audio loaders + mainSegmentLoader.resetEverything(); + return; + } + + if (previousActiveLoader === activeGroup.playlistLoader) { + // Nothing has actually changed. This can happen because track change events can fire + // multiple times for a "single" change. One for enabling the new active track, and + // one for disabling the track that was active + startLoaders(activeGroup.playlistLoader, mediaType); + return; + } + + if (segmentLoader.track) { + // For WebVTT, set the new text track in the segmentloader + segmentLoader.track(activeTrack); + } + + // destructive reset + segmentLoader.resetEverything(); + + startLoaders(activeGroup.playlistLoader, mediaType); + }; + }; + + var onError = { + /** + * Returns a function to be called when a SegmentLoader or PlaylistLoader encounters + * an error. + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @return {Function} + * Error handler. Logs warning (or error if the playlist is blacklisted) to + * console and switches back to default audio track. + * @function onError.AUDIO + */ + AUDIO: function AUDIO(type, settings) { + return function () { + var segmentLoader = settings.segmentLoaders[type], + mediaType = settings.mediaTypes[type], + blacklistCurrentPlaylist = settings.blacklistCurrentPlaylist; + + + stopLoaders(segmentLoader, mediaType); + + // switch back to default audio track + var activeTrack = mediaType.activeTrack(); + var activeGroup = mediaType.activeGroup(); + var id = (activeGroup.filter(function (group) { + return group.default; + })[0] || activeGroup[0]).id; + var defaultTrack = mediaType.tracks[id]; + + if (activeTrack === defaultTrack) { + // Default track encountered an error. All we can do now is blacklist the current + // rendition and hope another will switch audio groups + blacklistCurrentPlaylist({ + message: 'Problem encountered loading the default audio track.' + }); + return; + } + + videojs$1.log.warn('Problem encountered loading the alternate audio track.' + 'Switching back to default.'); + + for (var trackId in mediaType.tracks) { + mediaType.tracks[trackId].enabled = mediaType.tracks[trackId] === defaultTrack; + } + + mediaType.onTrackChanged(); + }; + }, + /** + * Returns a function to be called when a SegmentLoader or PlaylistLoader encounters + * an error. + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @return {Function} + * Error handler. Logs warning to console and disables the active subtitle track + * @function onError.SUBTITLES + */ + SUBTITLES: function SUBTITLES(type, settings) { + return function () { + var segmentLoader = settings.segmentLoaders[type], + mediaType = settings.mediaTypes[type]; + + + videojs$1.log.warn('Problem encountered loading the subtitle track.' + 'Disabling subtitle track.'); + + stopLoaders(segmentLoader, mediaType); + + var track = mediaType.activeTrack(); + + if (track) { + track.mode = 'disabled'; + } + + mediaType.onTrackChanged(); + }; + } + }; + + var setupListeners = { + /** + * Setup event listeners for audio playlist loader + * + * @param {String} type + * MediaGroup type + * @param {PlaylistLoader|null} playlistLoader + * PlaylistLoader to register listeners on + * @param {Object} settings + * Object containing required information for media groups + * @function setupListeners.AUDIO + */ + AUDIO: function AUDIO(type, playlistLoader, settings) { + if (!playlistLoader) { + // no playlist loader means audio will be muxed with the video + return; + } + + var tech = settings.tech, + requestOptions = settings.requestOptions, + segmentLoader = settings.segmentLoaders[type]; + + + playlistLoader.on('loadedmetadata', function () { + var media = playlistLoader.media(); + + segmentLoader.playlist(media, requestOptions); + + // if the video is already playing, or if this isn't a live video and preload + // permits, start downloading segments + if (!tech.paused() || media.endList && tech.preload() !== 'none') { + segmentLoader.load(); + } + }); + + playlistLoader.on('loadedplaylist', function () { + segmentLoader.playlist(playlistLoader.media(), requestOptions); + + // If the player isn't paused, ensure that the segment loader is running + if (!tech.paused()) { + segmentLoader.load(); + } + }); + + playlistLoader.on('error', onError[type](type, settings)); + }, + /** + * Setup event listeners for subtitle playlist loader + * + * @param {String} type + * MediaGroup type + * @param {PlaylistLoader|null} playlistLoader + * PlaylistLoader to register listeners on + * @param {Object} settings + * Object containing required information for media groups + * @function setupListeners.SUBTITLES + */ + SUBTITLES: function SUBTITLES(type, playlistLoader, settings) { + var tech = settings.tech, + requestOptions = settings.requestOptions, + segmentLoader = settings.segmentLoaders[type], + mediaType = settings.mediaTypes[type]; + + + playlistLoader.on('loadedmetadata', function () { + var media = playlistLoader.media(); + + segmentLoader.playlist(media, requestOptions); + segmentLoader.track(mediaType.activeTrack()); + + // if the video is already playing, or if this isn't a live video and preload + // permits, start downloading segments + if (!tech.paused() || media.endList && tech.preload() !== 'none') { + segmentLoader.load(); + } + }); + + playlistLoader.on('loadedplaylist', function () { + segmentLoader.playlist(playlistLoader.media(), requestOptions); + + // If the player isn't paused, ensure that the segment loader is running + if (!tech.paused()) { + segmentLoader.load(); + } + }); + + playlistLoader.on('error', onError[type](type, settings)); + } + }; + + var byGroupId = function byGroupId(type, groupId) { + return function (playlist) { + return playlist.attributes[type] === groupId; + }; + }; + + var byResolvedUri = function byResolvedUri(resolvedUri) { + return function (playlist) { + return playlist.resolvedUri === resolvedUri; + }; + }; + + var initialize = { + /** + * Setup PlaylistLoaders and AudioTracks for the audio groups + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @function initialize.AUDIO + */ + 'AUDIO': function AUDIO(type, settings) { + var hls = settings.hls, + sourceType = settings.sourceType, + segmentLoader = settings.segmentLoaders[type], + withCredentials = settings.requestOptions.withCredentials, + _settings$master = settings.master, + mediaGroups = _settings$master.mediaGroups, + playlists = _settings$master.playlists, + _settings$mediaTypes$ = settings.mediaTypes[type], + groups = _settings$mediaTypes$.groups, + tracks = _settings$mediaTypes$.tracks, + masterPlaylistLoader = settings.masterPlaylistLoader; + + // force a default if we have none + + if (!mediaGroups[type] || Object.keys(mediaGroups[type]).length === 0) { + mediaGroups[type] = {main: {default: {default: true}}}; + } + + for (var groupId in mediaGroups[type]) { + if (!groups[groupId]) { + groups[groupId] = []; + } + + // List of playlists that have an AUDIO attribute value matching the current + // group ID + var groupPlaylists = playlists.filter(byGroupId(type, groupId)); + + for (var variantLabel in mediaGroups[type][groupId]) { + var properties = mediaGroups[type][groupId][variantLabel]; + + // List of playlists for the current group ID that have a matching uri with + // this alternate audio variant + var matchingPlaylists = groupPlaylists.filter(byResolvedUri(properties.resolvedUri)); + + if (matchingPlaylists.length) { + // If there is a playlist that has the same uri as this audio variant, assume + // that the playlist is audio only. We delete the resolvedUri property here + // to prevent a playlist loader from being created so that we don't have + // both the main and audio segment loaders loading the same audio segments + // from the same playlist. + delete properties.resolvedUri; + } + + var playlistLoader = void 0; + + if (properties.resolvedUri) { + playlistLoader = new PlaylistLoader(properties.resolvedUri, hls, withCredentials); + } else if (properties.playlists && sourceType === 'dash') { + playlistLoader = new DashPlaylistLoader(properties.playlists[0], hls, withCredentials, masterPlaylistLoader); + } else { + // no resolvedUri means the audio is muxed with the video when using this + // audio track + playlistLoader = null; + } + + properties = videojs$1.mergeOptions({id: variantLabel, playlistLoader: playlistLoader}, properties); + + setupListeners[type](type, properties.playlistLoader, settings); + + groups[groupId].push(properties); + + if (typeof tracks[variantLabel] === 'undefined') { + var track = new videojs$1.AudioTrack({ + id: variantLabel, + kind: audioTrackKind_(properties), + enabled: false, + language: properties.language, + default: properties.default, + label: variantLabel + }); + + tracks[variantLabel] = track; + } + } + } + + // setup single error event handler for the segment loader + segmentLoader.on('error', onError[type](type, settings)); + }, + /** + * Setup PlaylistLoaders and TextTracks for the subtitle groups + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @function initialize.SUBTITLES + */ + 'SUBTITLES': function SUBTITLES(type, settings) { + var tech = settings.tech, + hls = settings.hls, + sourceType = settings.sourceType, + segmentLoader = settings.segmentLoaders[type], + withCredentials = settings.requestOptions.withCredentials, + mediaGroups = settings.master.mediaGroups, + _settings$mediaTypes$2 = settings.mediaTypes[type], + groups = _settings$mediaTypes$2.groups, + tracks = _settings$mediaTypes$2.tracks, + masterPlaylistLoader = settings.masterPlaylistLoader; + + + for (var groupId in mediaGroups[type]) { + if (!groups[groupId]) { + groups[groupId] = []; + } + + for (var variantLabel in mediaGroups[type][groupId]) { + if (mediaGroups[type][groupId][variantLabel].forced) { + // Subtitle playlists with the forced attribute are not selectable in Safari. + // According to Apple's HLS Authoring Specification: + // If content has forced subtitles and regular subtitles in a given language, + // the regular subtitles track in that language MUST contain both the forced + // subtitles and the regular subtitles for that language. + // Because of this requirement and that Safari does not add forced subtitles, + // forced subtitles are skipped here to maintain consistent experience across + // all platforms + continue; + } + + var properties = mediaGroups[type][groupId][variantLabel]; + + var playlistLoader = void 0; + + if (sourceType === 'hls') { + playlistLoader = new PlaylistLoader(properties.resolvedUri, hls, withCredentials); + } else if (sourceType === 'dash') { + playlistLoader = new DashPlaylistLoader(properties.playlists[0], hls, withCredentials, masterPlaylistLoader); + } + + properties = videojs$1.mergeOptions({ + id: variantLabel, + playlistLoader: playlistLoader + }, properties); + + setupListeners[type](type, properties.playlistLoader, settings); + + groups[groupId].push(properties); + + if (typeof tracks[variantLabel] === 'undefined') { + var track = tech.addRemoteTextTrack({ + id: variantLabel, + kind: 'subtitles', + enabled: false, + language: properties.language, + label: variantLabel + }, false).track; + + tracks[variantLabel] = track; + } + } + } + + // setup single error event handler for the segment loader + segmentLoader.on('error', onError[type](type, settings)); + }, + /** + * Setup TextTracks for the closed-caption groups + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @function initialize['CLOSED-CAPTIONS'] + */ + 'CLOSED-CAPTIONS': function CLOSEDCAPTIONS(type, settings) { + var tech = settings.tech, + mediaGroups = settings.master.mediaGroups, + _settings$mediaTypes$3 = settings.mediaTypes[type], + groups = _settings$mediaTypes$3.groups, + tracks = _settings$mediaTypes$3.tracks; + + + for (var groupId in mediaGroups[type]) { + if (!groups[groupId]) { + groups[groupId] = []; + } + + for (var variantLabel in mediaGroups[type][groupId]) { + var properties = mediaGroups[type][groupId][variantLabel]; + + // We only support CEA608 captions for now, so ignore anything that + // doesn't use a CCx INSTREAM-ID + if (!properties.instreamId.match(/CC\d/)) { + continue; + } + + // No PlaylistLoader is required for Closed-Captions because the captions are + // embedded within the video stream + groups[groupId].push(videojs$1.mergeOptions({id: variantLabel}, properties)); + + if (typeof tracks[variantLabel] === 'undefined') { + var track = tech.addRemoteTextTrack({ + id: properties.instreamId, + kind: 'captions', + enabled: false, + language: properties.language, + label: variantLabel + }, false).track; + + tracks[variantLabel] = track; + } + } + } + } + }; + + /** + * Returns a function used to get the active group of the provided type + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @return {Function} + * Function that returns the active media group for the provided type. Takes an + * optional parameter {TextTrack} track. If no track is provided, a list of all + * variants in the group, otherwise the variant corresponding to the provided + * track is returned. + * @function activeGroup + */ + var activeGroup = function activeGroup(type, settings) { + return function (track) { + var masterPlaylistLoader = settings.masterPlaylistLoader, + groups = settings.mediaTypes[type].groups; + + + var media = masterPlaylistLoader.media(); + + if (!media) { + return null; + } + + var variants = null; + + if (media.attributes[type]) { + variants = groups[media.attributes[type]]; + } + + variants = variants || groups.main; + + if (typeof track === 'undefined') { + return variants; + } + + if (track === null) { + // An active track was specified so a corresponding group is expected. track === null + // means no track is currently active so there is no corresponding group + return null; + } + + return variants.filter(function (props) { + return props.id === track.id; + })[0] || null; + }; + }; + + var activeTrack = { + /** + * Returns a function used to get the active track of type provided + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @return {Function} + * Function that returns the active media track for the provided type. Returns + * null if no track is active + * @function activeTrack.AUDIO + */ + AUDIO: function AUDIO(type, settings) { + return function () { + var tracks = settings.mediaTypes[type].tracks; + + + for (var id in tracks) { + if (tracks[id].enabled) { + return tracks[id]; + } + } + + return null; + }; + }, + /** + * Returns a function used to get the active track of type provided + * + * @param {String} type + * MediaGroup type + * @param {Object} settings + * Object containing required information for media groups + * @return {Function} + * Function that returns the active media track for the provided type. Returns + * null if no track is active + * @function activeTrack.SUBTITLES + */ + SUBTITLES: function SUBTITLES(type, settings) { + return function () { + var tracks = settings.mediaTypes[type].tracks; + + + for (var id in tracks) { + if (tracks[id].mode === 'showing') { + return tracks[id]; + } + } + + return null; + }; + } + }; + + /** + * Setup PlaylistLoaders and Tracks for media groups (Audio, Subtitles, + * Closed-Captions) specified in the master manifest. + * + * @param {Object} settings + * Object containing required information for setting up the media groups + * @param {SegmentLoader} settings.segmentLoaders.AUDIO + * Audio segment loader + * @param {SegmentLoader} settings.segmentLoaders.SUBTITLES + * Subtitle segment loader + * @param {SegmentLoader} settings.segmentLoaders.main + * Main segment loader + * @param {Tech} settings.tech + * The tech of the player + * @param {Object} settings.requestOptions + * XHR request options used by the segment loaders + * @param {PlaylistLoader} settings.masterPlaylistLoader + * PlaylistLoader for the master source + * @param {HlsHandler} settings.hls + * HLS SourceHandler + * @param {Object} settings.master + * The parsed master manifest + * @param {Object} settings.mediaTypes + * Object to store the loaders, tracks, and utility methods for each media type + * @param {Function} settings.blacklistCurrentPlaylist + * Blacklists the current rendition and forces a rendition switch. + * @function setupMediaGroups + */ + var setupMediaGroups = function setupMediaGroups(settings) { + ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(function (type) { + initialize[type](type, settings); + }); + + var mediaTypes = settings.mediaTypes, + masterPlaylistLoader = settings.masterPlaylistLoader, + tech = settings.tech, + hls = settings.hls; + + // setup active group and track getters and change event handlers + + ['AUDIO', 'SUBTITLES'].forEach(function (type) { + mediaTypes[type].activeGroup = activeGroup(type, settings); + mediaTypes[type].activeTrack = activeTrack[type](type, settings); + mediaTypes[type].onGroupChanged = onGroupChanged(type, settings); + mediaTypes[type].onTrackChanged = onTrackChanged(type, settings); + }); + + // DO NOT enable the default subtitle or caption track. + // DO enable the default audio track + var audioGroup = mediaTypes.AUDIO.activeGroup(); + var groupId = (audioGroup.filter(function (group) { + return group.default; + })[0] || audioGroup[0]).id; + + mediaTypes.AUDIO.tracks[groupId].enabled = true; + mediaTypes.AUDIO.onTrackChanged(); + + masterPlaylistLoader.on('mediachange', function () { + ['AUDIO', 'SUBTITLES'].forEach(function (type) { + return mediaTypes[type].onGroupChanged(); + }); + }); + + // custom audio track change event handler for usage event + var onAudioTrackChanged = function onAudioTrackChanged() { + mediaTypes.AUDIO.onTrackChanged(); + tech.trigger({type: 'usage', name: 'hls-audio-change'}); + }; + + tech.audioTracks().addEventListener('change', onAudioTrackChanged); + tech.remoteTextTracks().addEventListener('change', mediaTypes.SUBTITLES.onTrackChanged); + + hls.on('dispose', function () { + tech.audioTracks().removeEventListener('change', onAudioTrackChanged); + tech.remoteTextTracks().removeEventListener('change', mediaTypes.SUBTITLES.onTrackChanged); + }); + + // clear existing audio tracks and add the ones we just created + tech.clearTracks('audio'); + + for (var id in mediaTypes.AUDIO.tracks) { + tech.audioTracks().addTrack(mediaTypes.AUDIO.tracks[id]); + } + }; + + /** + * Creates skeleton object used to store the loaders, tracks, and utility methods for each + * media type + * + * @return {Object} + * Object to store the loaders, tracks, and utility methods for each media type + * @function createMediaTypes + */ + var createMediaTypes = function createMediaTypes() { + var mediaTypes = {}; + + ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(function (type) { + mediaTypes[type] = { + groups: {}, + tracks: {}, + activePlaylistLoader: null, + activeGroup: noop$1, + activeTrack: noop$1, + onGroupChanged: noop$1, + onTrackChanged: noop$1 + }; + }); + + return mediaTypes; + }; + + /** + * @file master-playlist-controller.js + */ + + var ABORT_EARLY_BLACKLIST_SECONDS = 60 * 2; + + var Hls = void 0; + + // SegmentLoader stats that need to have each loader's + // values summed to calculate the final value + var loaderStats = ['mediaRequests', 'mediaRequestsAborted', 'mediaRequestsTimedout', 'mediaRequestsErrored', 'mediaTransferDuration', 'mediaBytesTransferred']; + var sumLoaderStat = function sumLoaderStat(stat) { + return this.audioSegmentLoader_[stat] + this.mainSegmentLoader_[stat]; + }; + + /** + * the master playlist controller controller all interactons + * between playlists and segmentloaders. At this time this mainly + * involves a master playlist and a series of audio playlists + * if they are available + * + * @class MasterPlaylistController + * @extends videojs.EventTarget + */ + + var MasterPlaylistController = function (_videojs$EventTarget5) { + inherits(MasterPlaylistController, _videojs$EventTarget5); + + function MasterPlaylistController(options) { + classCallCheck(this, MasterPlaylistController); + + var _this29 = possibleConstructorReturn(this, _videojs$EventTarget5.call(this)); + + var url = options.url, + withCredentials = options.withCredentials, + tech = options.tech, + bandwidth = options.bandwidth, + externHls = options.externHls, + useCueTags = options.useCueTags, + blacklistDuration = options.blacklistDuration, + enableLowInitialPlaylist = options.enableLowInitialPlaylist, + sourceType = options.sourceType; + + + if (!url) { + throw new Error('A non-empty playlist URL is required'); + } + + Hls = externHls; + + _this29.withCredentials = withCredentials; + _this29.tech_ = tech; + _this29.hls_ = tech.hls; + _this29.sourceType_ = sourceType; + _this29.useCueTags_ = useCueTags; + _this29.blacklistDuration = blacklistDuration; + _this29.enableLowInitialPlaylist = enableLowInitialPlaylist; + if (_this29.useCueTags_) { + _this29.cueTagsTrack_ = _this29.tech_.addTextTrack('metadata', 'ad-cues'); + _this29.cueTagsTrack_.inBandMetadataTrackDispatchType = ''; + } + + _this29.requestOptions_ = { + withCredentials: _this29.withCredentials, + timeout: null + }; + + _this29.mediaTypes_ = createMediaTypes(); + + _this29.mediaSource = new videojs$1.MediaSource(); + + // load the media source into the player + _this29.mediaSource.addEventListener('sourceopen', _this29.handleSourceOpen_.bind(_this29)); + + _this29.seekable_ = videojs$1.createTimeRanges(); + _this29.hasPlayed_ = function () { + return false; + }; + + _this29.syncController_ = new SyncController(options); + _this29.segmentMetadataTrack_ = tech.addRemoteTextTrack({ + kind: 'metadata', + label: 'segment-metadata' + }, false).track; + + _this29.decrypter_ = new Decrypter$1(); + + var segmentLoaderSettings = { + hls: _this29.hls_, + mediaSource: _this29.mediaSource, + currentTime: _this29.tech_.currentTime.bind(_this29.tech_), + seekable: function seekable() { + return _this29.seekable(); + }, + seeking: function seeking() { + return _this29.tech_.seeking(); + }, + duration: function duration() { + return _this29.mediaSource.duration; + }, + hasPlayed: function hasPlayed() { + return _this29.hasPlayed_(); + }, + goalBufferLength: function goalBufferLength() { + return _this29.goalBufferLength(); + }, + bandwidth: bandwidth, + syncController: _this29.syncController_, + decrypter: _this29.decrypter_, + sourceType: _this29.sourceType_ + }; + + _this29.masterPlaylistLoader_ = _this29.sourceType_ === 'dash' ? new DashPlaylistLoader(url, _this29.hls_, _this29.withCredentials) : new PlaylistLoader(url, _this29.hls_, _this29.withCredentials); + _this29.setupMasterPlaylistLoaderListeners_(); + + // setup segment loaders + // combined audio/video or just video when alternate audio track is selected + _this29.mainSegmentLoader_ = new SegmentLoader(videojs$1.mergeOptions(segmentLoaderSettings, { + segmentMetadataTrack: _this29.segmentMetadataTrack_, + loaderType: 'main' + }), options); + + // alternate audio track + _this29.audioSegmentLoader_ = new SegmentLoader(videojs$1.mergeOptions(segmentLoaderSettings, { + loaderType: 'audio' + }), options); + + _this29.subtitleSegmentLoader_ = new VTTSegmentLoader(videojs$1.mergeOptions(segmentLoaderSettings, { + loaderType: 'vtt' + }), options); + + _this29.setupSegmentLoaderListeners_(); + + // Create SegmentLoader stat-getters + loaderStats.forEach(function (stat) { + _this29[stat + '_'] = sumLoaderStat.bind(_this29, stat); + }); + + _this29.logger_ = logger('MPC'); + + _this29.masterPlaylistLoader_.load(); + return _this29; + } + + /** + * Register event handlers on the master playlist loader. A helper + * function for construction time. + * + * @private + */ + + + MasterPlaylistController.prototype.setupMasterPlaylistLoaderListeners_ = function setupMasterPlaylistLoaderListeners_() { + var _this30 = this; + + this.masterPlaylistLoader_.on('loadedmetadata', function () { + var media = _this30.masterPlaylistLoader_.media(); + var requestTimeout = _this30.masterPlaylistLoader_.targetDuration * 1.5 * 1000; + + // If we don't have any more available playlists, we don't want to + // timeout the request. + if (isLowestEnabledRendition(_this30.masterPlaylistLoader_.master, _this30.masterPlaylistLoader_.media())) { + _this30.requestOptions_.timeout = 0; + } else { + _this30.requestOptions_.timeout = requestTimeout; + } + + // if this isn't a live video and preload permits, start + // downloading segments + if (media.endList && _this30.tech_.preload() !== 'none') { + _this30.mainSegmentLoader_.playlist(media, _this30.requestOptions_); + _this30.mainSegmentLoader_.load(); + } + + setupMediaGroups({ + sourceType: _this30.sourceType_, + segmentLoaders: { + AUDIO: _this30.audioSegmentLoader_, + SUBTITLES: _this30.subtitleSegmentLoader_, + main: _this30.mainSegmentLoader_ + }, + tech: _this30.tech_, + requestOptions: _this30.requestOptions_, + masterPlaylistLoader: _this30.masterPlaylistLoader_, + hls: _this30.hls_, + master: _this30.master(), + mediaTypes: _this30.mediaTypes_, + blacklistCurrentPlaylist: _this30.blacklistCurrentPlaylist.bind(_this30) + }); + + _this30.triggerPresenceUsage_(_this30.master(), media); + + try { + _this30.setupSourceBuffers_(); + } catch (e) { + videojs$1.log.warn('Failed to create SourceBuffers', e); + return _this30.mediaSource.endOfStream('decode'); + } + _this30.setupFirstPlay(); + + _this30.trigger('selectedinitialmedia'); + }); + + this.masterPlaylistLoader_.on('loadedplaylist', function () { + var updatedPlaylist = _this30.masterPlaylistLoader_.media(); + + if (!updatedPlaylist) { + // blacklist any variants that are not supported by the browser before selecting + // an initial media as the playlist selectors do not consider browser support + _this30.excludeUnsupportedVariants_(); + + var selectedMedia = void 0; + + if (_this30.enableLowInitialPlaylist) { + selectedMedia = _this30.selectInitialPlaylist(); + } + + if (!selectedMedia) { + selectedMedia = _this30.selectPlaylist(); + } + + _this30.initialMedia_ = selectedMedia; + _this30.masterPlaylistLoader_.media(_this30.initialMedia_); + return; + } + + if (_this30.useCueTags_) { + _this30.updateAdCues_(updatedPlaylist); + } + + // TODO: Create a new event on the PlaylistLoader that signals + // that the segments have changed in some way and use that to + // update the SegmentLoader instead of doing it twice here and + // on `mediachange` + _this30.mainSegmentLoader_.playlist(updatedPlaylist, _this30.requestOptions_); + _this30.updateDuration(); + + // If the player isn't paused, ensure that the segment loader is running, + // as it is possible that it was temporarily stopped while waiting for + // a playlist (e.g., in case the playlist errored and we re-requested it). + if (!_this30.tech_.paused()) { + _this30.mainSegmentLoader_.load(); + } + + if (!updatedPlaylist.endList) { + var addSeekableRange = function addSeekableRange() { + var seekable$$1 = _this30.seekable(); + + if (seekable$$1.length !== 0) { + _this30.mediaSource.addSeekableRange_(seekable$$1.start(0), seekable$$1.end(0)); + } + }; + + if (_this30.duration() !== Infinity) { + var onDurationchange = function onDurationchange() { + if (_this30.duration() === Infinity) { + addSeekableRange(); + } else { + _this30.tech_.one('durationchange', onDurationchange); + } + }; + + _this30.tech_.one('durationchange', onDurationchange); + } else { + addSeekableRange(); + } + } + }); + + this.masterPlaylistLoader_.on('error', function () { + _this30.blacklistCurrentPlaylist(_this30.masterPlaylistLoader_.error); + }); + + this.masterPlaylistLoader_.on('mediachanging', function () { + _this30.mainSegmentLoader_.abort(); + _this30.mainSegmentLoader_.pause(); + }); + + this.masterPlaylistLoader_.on('mediachange', function () { + var media = _this30.masterPlaylistLoader_.media(); + var requestTimeout = _this30.masterPlaylistLoader_.targetDuration * 1.5 * 1000; + + // If we don't have any more available playlists, we don't want to + // timeout the request. + if (isLowestEnabledRendition(_this30.masterPlaylistLoader_.master, _this30.masterPlaylistLoader_.media())) { + _this30.requestOptions_.timeout = 0; + } else { + _this30.requestOptions_.timeout = requestTimeout; + } + + // TODO: Create a new event on the PlaylistLoader that signals + // that the segments have changed in some way and use that to + // update the SegmentLoader instead of doing it twice here and + // on `loadedplaylist` + _this30.mainSegmentLoader_.playlist(media, _this30.requestOptions_); + _this30.mainSegmentLoader_.load(); + + _this30.tech_.trigger({ + type: 'mediachange', + bubbles: true + }); + }); + + this.masterPlaylistLoader_.on('playlistunchanged', function () { + var updatedPlaylist = _this30.masterPlaylistLoader_.media(); + var playlistOutdated = _this30.stuckAtPlaylistEnd_(updatedPlaylist); + + if (playlistOutdated) { + // Playlist has stopped updating and we're stuck at its end. Try to + // blacklist it and switch to another playlist in the hope that that + // one is updating (and give the player a chance to re-adjust to the + // safe live point). + _this30.blacklistCurrentPlaylist({ + message: 'Playlist no longer updating.' + }); + // useful for monitoring QoS + _this30.tech_.trigger('playliststuck'); + } + }); + + this.masterPlaylistLoader_.on('renditiondisabled', function () { + _this30.tech_.trigger({type: 'usage', name: 'hls-rendition-disabled'}); + }); + this.masterPlaylistLoader_.on('renditionenabled', function () { + _this30.tech_.trigger({type: 'usage', name: 'hls-rendition-enabled'}); + }); + }; + + /** + * A helper function for triggerring presence usage events once per source + * + * @private + */ + + + MasterPlaylistController.prototype.triggerPresenceUsage_ = function triggerPresenceUsage_(master, media) { + var mediaGroups = master.mediaGroups || {}; + var defaultDemuxed = true; + var audioGroupKeys = Object.keys(mediaGroups.AUDIO); + + for (var mediaGroup in mediaGroups.AUDIO) { + for (var label in mediaGroups.AUDIO[mediaGroup]) { + var properties = mediaGroups.AUDIO[mediaGroup][label]; + + if (!properties.uri) { + defaultDemuxed = false; + } + } + } + + if (defaultDemuxed) { + this.tech_.trigger({type: 'usage', name: 'hls-demuxed'}); + } + + if (Object.keys(mediaGroups.SUBTITLES).length) { + this.tech_.trigger({type: 'usage', name: 'hls-webvtt'}); + } + + if (Hls.Playlist.isAes(media)) { + this.tech_.trigger({type: 'usage', name: 'hls-aes'}); + } + + if (Hls.Playlist.isFmp4(media)) { + this.tech_.trigger({type: 'usage', name: 'hls-fmp4'}); + } + + if (audioGroupKeys.length && Object.keys(mediaGroups.AUDIO[audioGroupKeys[0]]).length > 1) { + this.tech_.trigger({type: 'usage', name: 'hls-alternate-audio'}); + } + + if (this.useCueTags_) { + this.tech_.trigger({type: 'usage', name: 'hls-playlist-cue-tags'}); + } + }; + /** + * Register event handlers on the segment loaders. A helper function + * for construction time. + * + * @private + */ + + + MasterPlaylistController.prototype.setupSegmentLoaderListeners_ = function setupSegmentLoaderListeners_() { + var _this31 = this; + + this.mainSegmentLoader_.on('bandwidthupdate', function () { + var nextPlaylist = _this31.selectPlaylist(); + var currentPlaylist = _this31.masterPlaylistLoader_.media(); + var buffered = _this31.tech_.buffered(); + var forwardBuffer = buffered.length ? buffered.end(buffered.length - 1) - _this31.tech_.currentTime() : 0; + + var bufferLowWaterLine = _this31.bufferLowWaterLine(); + + // If the playlist is live, then we want to not take low water line into account. + // This is because in LIVE, the player plays 3 segments from the end of the + // playlist, and if `BUFFER_LOW_WATER_LINE` is greater than the duration availble + // in those segments, a viewer will never experience a rendition upswitch. + if (!currentPlaylist.endList || + // For the same reason as LIVE, we ignore the low water line when the VOD + // duration is below the max potential low water line + _this31.duration() < Config.MAX_BUFFER_LOW_WATER_LINE || + // we want to switch down to lower resolutions quickly to continue playback, but + nextPlaylist.attributes.BANDWIDTH < currentPlaylist.attributes.BANDWIDTH || + // ensure we have some buffer before we switch up to prevent us running out of + // buffer while loading a higher rendition. + forwardBuffer >= bufferLowWaterLine) { + _this31.masterPlaylistLoader_.media(nextPlaylist); + } + + _this31.tech_.trigger('bandwidthupdate'); + }); + this.mainSegmentLoader_.on('progress', function () { + _this31.trigger('progress'); + }); + + this.mainSegmentLoader_.on('error', function () { + _this31.blacklistCurrentPlaylist(_this31.mainSegmentLoader_.error()); + }); + + this.mainSegmentLoader_.on('syncinfoupdate', function () { + _this31.onSyncInfoUpdate_(); + }); + + this.mainSegmentLoader_.on('timestampoffset', function () { + _this31.tech_.trigger({type: 'usage', name: 'hls-timestamp-offset'}); + }); + this.audioSegmentLoader_.on('syncinfoupdate', function () { + _this31.onSyncInfoUpdate_(); + }); + + this.mainSegmentLoader_.on('ended', function () { + _this31.onEndOfStream(); + }); + + this.mainSegmentLoader_.on('earlyabort', function () { + _this31.blacklistCurrentPlaylist({ + message: 'Aborted early because there isn\'t enough bandwidth to complete the ' + 'request without rebuffering.' + }, ABORT_EARLY_BLACKLIST_SECONDS); + }); + + this.mainSegmentLoader_.on('reseteverything', function () { + // If playing an MTS stream, a videojs.MediaSource is listening for + // hls-reset to reset caption parsing state in the transmuxer + _this31.tech_.trigger('hls-reset'); + }); + + this.mainSegmentLoader_.on('segmenttimemapping', function (event) { + // If playing an MTS stream in html, a videojs.MediaSource is listening for + // hls-segment-time-mapping update its internal mapping of stream to display time + _this31.tech_.trigger({ + type: 'hls-segment-time-mapping', + mapping: event.mapping + }); + }); + + this.audioSegmentLoader_.on('ended', function () { + _this31.onEndOfStream(); + }); + }; + + MasterPlaylistController.prototype.mediaSecondsLoaded_ = function mediaSecondsLoaded_() { + return Math.max(this.audioSegmentLoader_.mediaSecondsLoaded + this.mainSegmentLoader_.mediaSecondsLoaded); + }; + + /** + * Call load on our SegmentLoaders + */ + + + MasterPlaylistController.prototype.load = function load() { + this.mainSegmentLoader_.load(); + if (this.mediaTypes_.AUDIO.activePlaylistLoader) { + this.audioSegmentLoader_.load(); + } + if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) { + this.subtitleSegmentLoader_.load(); + } + }; + + /** + * Re-tune playback quality level for the current player + * conditions. This method may perform destructive actions, like + * removing already buffered content, to readjust the currently + * active playlist quickly. + * + * @private + */ + + + MasterPlaylistController.prototype.fastQualityChange_ = function fastQualityChange_() { + var media = this.selectPlaylist(); + + if (media !== this.masterPlaylistLoader_.media()) { + this.masterPlaylistLoader_.media(media); + + this.mainSegmentLoader_.resetLoader(); + // don't need to reset audio as it is reset when media changes + } + }; + + /** + * Begin playback. + */ + + + MasterPlaylistController.prototype.play = function play() { + if (this.setupFirstPlay()) { + return; + } + + if (this.tech_.ended()) { + this.tech_.setCurrentTime(0); + } + + if (this.hasPlayed_()) { + this.load(); + } + + var seekable$$1 = this.tech_.seekable(); + + // if the viewer has paused and we fell out of the live window, + // seek forward to the live point + if (this.tech_.duration() === Infinity) { + if (this.tech_.currentTime() < seekable$$1.start(0)) { + return this.tech_.setCurrentTime(seekable$$1.end(seekable$$1.length - 1)); + } + } + }; + + /** + * Seek to the latest media position if this is a live video and the + * player and video are loaded and initialized. + */ + + + MasterPlaylistController.prototype.setupFirstPlay = function setupFirstPlay() { + var _this32 = this; + + var media = this.masterPlaylistLoader_.media(); + + // Check that everything is ready to begin buffering for the first call to playOld + // If 1) there is no active media + // 2) the player is paused + // 3) the first playOld has already been setup + // then exit early + if (!media || this.tech_.paused() || this.hasPlayed_()) { + return false; + } + + // when the video is a live stream + if (!media.endList) { + var seekable$$1 = this.seekable(); + + if (!seekable$$1.length) { + // without a seekable range, the player cannot seek to begin buffering at the live + // point + return false; + } + + if (videojs$1.browser.IE_VERSION && this.tech_.readyState() === 0) { + // IE11 throws an InvalidStateError if you try to set currentTime while the + // readyState is 0, so it must be delayed until the tech fires loadedmetadata. + this.tech_.one('loadedmetadata', function () { + _this32.trigger('firstplay'); + _this32.tech_.setCurrentTime(seekable$$1.end(0)); + _this32.hasPlayed_ = function () { + return true; + }; + }); + + return false; + } + + // trigger firstplay to inform the source handler to ignore the next seek event + this.trigger('firstplay'); + // seek to the live point + this.tech_.setCurrentTime(seekable$$1.end(0)); + } + + this.hasPlayed_ = function () { + return true; + }; + // we can begin loading now that everything is ready + this.load(); + return true; + }; + + /** + * handle the sourceopen event on the MediaSource + * + * @private + */ + + + MasterPlaylistController.prototype.handleSourceOpen_ = function handleSourceOpen_() { + // Only attempt to create the source buffer if none already exist. + // handleSourceOpen is also called when we are "re-opening" a source buffer + // after `endOfStream` has been called (in response to a seek for instance) + try { + this.setupSourceBuffers_(); + } catch (e) { + videojs$1.log.warn('Failed to create Source Buffers', e); + return this.mediaSource.endOfStream('decode'); + } + + // if autoplay is enabled, begin playback. This is duplicative of + // code in video.js but is required because playOld() must be invoked + // *after* the media source has opened. + if (this.tech_.autoplay()) { + var playPromise = this.tech_.play(); + + // Catch/silence error when a pause interrupts a playOld request + // on browsers which return a promise + if (typeof playPromise !== 'undefined' && typeof playPromise.then === 'function') { + playPromise.then(null, function (e) { + }); + } + } + + this.trigger('sourceopen'); + }; + + /** + * Calls endOfStream on the media source when all active stream types have called + * endOfStream + * + * @param {string} streamType + * Stream type of the segment loader that called endOfStream + * @private + */ + + + MasterPlaylistController.prototype.onEndOfStream = function onEndOfStream() { + var isEndOfStream = this.mainSegmentLoader_.ended_; + + if (this.mediaTypes_.AUDIO.activePlaylistLoader) { + // if the audio playlist loader exists, then alternate audio is active + if (!this.mainSegmentLoader_.startingMedia_ || this.mainSegmentLoader_.startingMedia_.containsVideo) { + // if we do not know if the main segment loader contains video yet or if we + // definitively know the main segment loader contains video, then we need to wait + // for both main and audio segment loaders to call endOfStream + isEndOfStream = isEndOfStream && this.audioSegmentLoader_.ended_; + } else { + // otherwise just rely on the audio loader + isEndOfStream = this.audioSegmentLoader_.ended_; + } + } + + if (isEndOfStream) { + this.mediaSource.endOfStream(); + } + }; + + /** + * Check if a playlist has stopped being updated + * @param {Object} playlist the media playlist object + * @return {boolean} whether the playlist has stopped being updated or not + */ + + + MasterPlaylistController.prototype.stuckAtPlaylistEnd_ = function stuckAtPlaylistEnd_(playlist) { + var seekable$$1 = this.seekable(); + + if (!seekable$$1.length) { + // playlist doesn't have enough information to determine whether we are stuck + return false; + } + + var expired = this.syncController_.getExpiredTime(playlist, this.mediaSource.duration); + + if (expired === null) { + return false; + } + + // does not use the safe live end to calculate playlist end, since we + // don't want to say we are stuck while there is still content + var absolutePlaylistEnd = Hls.Playlist.playlistEnd(playlist, expired); + var currentTime = this.tech_.currentTime(); + var buffered = this.tech_.buffered(); + + if (!buffered.length) { + // return true if the playhead reached the absolute end of the playlist + return absolutePlaylistEnd - currentTime <= SAFE_TIME_DELTA; + } + var bufferedEnd = buffered.end(buffered.length - 1); + + // return true if there is too little buffer left and buffer has reached absolute + // end of playlist + return bufferedEnd - currentTime <= SAFE_TIME_DELTA && absolutePlaylistEnd - bufferedEnd <= SAFE_TIME_DELTA; + }; + + /** + * Blacklists a playlist when an error occurs for a set amount of time + * making it unavailable for selection by the rendition selection algorithm + * and then forces a new playlist (rendition) selection. + * + * @param {Object=} error an optional error that may include the playlist + * to blacklist + * @param {Number=} blacklistDuration an optional number of seconds to blacklist the + * playlist + */ + + + MasterPlaylistController.prototype.blacklistCurrentPlaylist = function blacklistCurrentPlaylist() { + var error = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var blacklistDuration = arguments[1]; + + var currentPlaylist = void 0; + var nextPlaylist = void 0; + + // If the `error` was generated by the playlist loader, it will contain + // the playlist we were trying to load (but failed) and that should be + // blacklisted instead of the currently selected playlist which is likely + // out-of-date in this scenario + currentPlaylist = error.playlist || this.masterPlaylistLoader_.media(); + + blacklistDuration = blacklistDuration || error.blacklistDuration || this.blacklistDuration; + + // If there is no current playlist, then an error occurred while we were + // trying to load the master OR while we were disposing of the tech + if (!currentPlaylist) { + this.error = error; + + try { + return this.mediaSource.endOfStream('network'); + } catch (e) { + return this.trigger('error'); + } + } + + var isFinalRendition = this.masterPlaylistLoader_.master.playlists.filter(isEnabled).length === 1; + + if (isFinalRendition) { + // Never blacklisting this playlist because it's final rendition + videojs$1.log.warn('Problem encountered with the current ' + 'HLS playlist. Trying again since it is the final playlist.'); + + this.tech_.trigger('retryplaylist'); + return this.masterPlaylistLoader_.load(isFinalRendition); + } + // Blacklist this playlist + currentPlaylist.excludeUntil = Date.now() + blacklistDuration * 1000; + this.tech_.trigger('blacklistplaylist'); + this.tech_.trigger({type: 'usage', name: 'hls-rendition-blacklisted'}); + + // Select a new playlist + nextPlaylist = this.selectPlaylist(); + videojs$1.log.warn('Problem encountered with the current HLS playlist.' + (error.message ? ' ' + error.message : '') + ' Switching to another playlist.'); + + return this.masterPlaylistLoader_.media(nextPlaylist); + }; + + /** + * Pause all segment loaders + */ + + + MasterPlaylistController.prototype.pauseLoading = function pauseLoading() { + this.mainSegmentLoader_.pause(); + if (this.mediaTypes_.AUDIO.activePlaylistLoader) { + this.audioSegmentLoader_.pause(); + } + if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) { + this.subtitleSegmentLoader_.pause(); + } + }; + + /** + * set the current time on all segment loaders + * + * @param {TimeRange} currentTime the current time to set + * @return {TimeRange} the current time + */ + + + MasterPlaylistController.prototype.setCurrentTime = function setCurrentTime(currentTime) { + var buffered = findRange(this.tech_.buffered(), currentTime); + + if (!(this.masterPlaylistLoader_ && this.masterPlaylistLoader_.media())) { + // return immediately if the metadata is not ready yet + return 0; + } + + // it's clearly an edge-case but don't thrown an error if asked to + // seek within an empty playlist + if (!this.masterPlaylistLoader_.media().segments) { + return 0; + } + + // In flash playback, the segment loaders should be reset on every seek, even + // in buffer seeks. If the seek location is already buffered, continue buffering as + // usual + // TODO: redo this comment + if (buffered && buffered.length) { + return currentTime; + } + + // cancel outstanding requests so we begin buffering at the new + // location + this.mainSegmentLoader_.resetEverything(); + this.mainSegmentLoader_.abort(); + if (this.mediaTypes_.AUDIO.activePlaylistLoader) { + this.audioSegmentLoader_.resetEverything(); + this.audioSegmentLoader_.abort(); + } + if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) { + this.subtitleSegmentLoader_.resetEverything(); + this.subtitleSegmentLoader_.abort(); + } + + // start segment loader loading in case they are paused + this.load(); + }; + + /** + * get the current duration + * + * @return {TimeRange} the duration + */ + + + MasterPlaylistController.prototype.duration = function duration() { + if (!this.masterPlaylistLoader_) { + return 0; + } + + if (this.mediaSource) { + return this.mediaSource.duration; + } + + return Hls.Playlist.duration(this.masterPlaylistLoader_.media()); + }; + + /** + * check the seekable range + * + * @return {TimeRange} the seekable range + */ + + + MasterPlaylistController.prototype.seekable = function seekable() { + return this.seekable_; + }; + + MasterPlaylistController.prototype.onSyncInfoUpdate_ = function onSyncInfoUpdate_() { + var mainSeekable = void 0; + var audioSeekable = void 0; + + if (!this.masterPlaylistLoader_) { + return; + } + + var media = this.masterPlaylistLoader_.media(); + + if (!media) { + return; + } + + var expired = this.syncController_.getExpiredTime(media, this.mediaSource.duration); + + if (expired === null) { + // not enough information to update seekable + return; + } + + mainSeekable = Hls.Playlist.seekable(media, expired); + + if (mainSeekable.length === 0) { + return; + } + + if (this.mediaTypes_.AUDIO.activePlaylistLoader) { + media = this.mediaTypes_.AUDIO.activePlaylistLoader.media(); + expired = this.syncController_.getExpiredTime(media, this.mediaSource.duration); + + if (expired === null) { + return; + } + + audioSeekable = Hls.Playlist.seekable(media, expired); + + if (audioSeekable.length === 0) { + return; + } + } + + if (!audioSeekable) { + // seekable has been calculated based on buffering video data so it + // can be returned directly + this.seekable_ = mainSeekable; + } else if (audioSeekable.start(0) > mainSeekable.end(0) || mainSeekable.start(0) > audioSeekable.end(0)) { + // seekables are pretty far off, rely on main + this.seekable_ = mainSeekable; + } else { + this.seekable_ = videojs$1.createTimeRanges([[audioSeekable.start(0) > mainSeekable.start(0) ? audioSeekable.start(0) : mainSeekable.start(0), audioSeekable.end(0) < mainSeekable.end(0) ? audioSeekable.end(0) : mainSeekable.end(0)]]); + } + + this.logger_('seekable updated [' + printableRange(this.seekable_) + ']'); + + this.tech_.trigger('seekablechanged'); + }; + + /** + * Update the player duration + */ + + + MasterPlaylistController.prototype.updateDuration = function updateDuration() { + var _this33 = this; + + var oldDuration = this.mediaSource.duration; + var newDuration = Hls.Playlist.duration(this.masterPlaylistLoader_.media()); + var buffered = this.tech_.buffered(); + var setDuration = function setDuration() { + _this33.mediaSource.duration = newDuration; + _this33.tech_.trigger('durationchange'); + + _this33.mediaSource.removeEventListener('sourceopen', setDuration); + }; + + if (buffered.length > 0) { + newDuration = Math.max(newDuration, buffered.end(buffered.length - 1)); + } + + // if the duration has changed, invalidate the cached value + if (oldDuration !== newDuration) { + // update the duration + if (this.mediaSource.readyState !== 'open') { + this.mediaSource.addEventListener('sourceopen', setDuration); + } else { + setDuration(); + } + } + }; + + /** + * dispose of the MasterPlaylistController and everything + * that it controls + */ + + + MasterPlaylistController.prototype.dispose = function dispose() { + var _this34 = this; + + this.decrypter_.terminate(); + this.masterPlaylistLoader_.dispose(); + this.mainSegmentLoader_.dispose(); + + ['AUDIO', 'SUBTITLES'].forEach(function (type) { + var groups = _this34.mediaTypes_[type].groups; + + for (var id in groups) { + groups[id].forEach(function (group) { + if (group.playlistLoader) { + group.playlistLoader.dispose(); + } + }); + } + }); + + this.audioSegmentLoader_.dispose(); + this.subtitleSegmentLoader_.dispose(); + }; + + /** + * return the master playlist object if we have one + * + * @return {Object} the master playlist object that we parsed + */ + + + MasterPlaylistController.prototype.master = function master() { + return this.masterPlaylistLoader_.master; + }; + + /** + * return the currently selected playlist + * + * @return {Object} the currently selected playlist object that we parsed + */ + + + MasterPlaylistController.prototype.media = function media() { + // playlist loader will not return media if it has not been fully loaded + return this.masterPlaylistLoader_.media() || this.initialMedia_; + }; + + /** + * setup our internal source buffers on our segment Loaders + * + * @private + */ + + + MasterPlaylistController.prototype.setupSourceBuffers_ = function setupSourceBuffers_() { + var media = this.masterPlaylistLoader_.media(); + var mimeTypes = void 0; + + // wait until a media playlist is available and the Media Source is + // attached + if (!media || this.mediaSource.readyState !== 'open') { + return; + } + + mimeTypes = mimeTypesForPlaylist(this.masterPlaylistLoader_.master, media); + if (mimeTypes.length < 1) { + this.error = 'No compatible SourceBuffer configuration for the variant stream:' + media.resolvedUri; + return this.mediaSource.endOfStream('decode'); + } + + this.configureLoaderMimeTypes_(mimeTypes); + // exclude any incompatible variant streams from future playlist + // selection + this.excludeIncompatibleVariants_(media); + }; + + MasterPlaylistController.prototype.configureLoaderMimeTypes_ = function configureLoaderMimeTypes_(mimeTypes) { + // If the content is demuxed, we can't start appending segments to a source buffer + // until both source buffers are set up, or else the browser may not let us add the + // second source buffer (it will assume we are playing either audio only or video + // only). + var sourceBufferEmitter = + // If there is more than one mime type + mimeTypes.length > 1 && + // and the first mime type does not have muxed video and audio + mimeTypes[0].indexOf(',') === -1 && + // and the two mime types are different (they can be the same in the case of audio + // only with alternate audio) + mimeTypes[0] !== mimeTypes[1] ? + // then we want to wait on the second source buffer + new videojs$1.EventTarget() : + // otherwise there is no need to wait as the content is either audio only, + // video only, or muxed content. + null; + + this.mainSegmentLoader_.mimeType(mimeTypes[0], sourceBufferEmitter); + if (mimeTypes[1]) { + this.audioSegmentLoader_.mimeType(mimeTypes[1], sourceBufferEmitter); + } + }; + + /** + * Blacklists playlists with codecs that are unsupported by the browser. + */ + + + MasterPlaylistController.prototype.excludeUnsupportedVariants_ = function excludeUnsupportedVariants_() { + this.master().playlists.forEach(function (variant) { + if (variant.attributes.CODECS && window_1.MediaSource && window_1.MediaSource.isTypeSupported && !window_1.MediaSource.isTypeSupported('video/mp4; codecs="' + mapLegacyAvcCodecs(variant.attributes.CODECS) + '"')) { + variant.excludeUntil = Infinity; + } + }); + }; + + /** + * Blacklist playlists that are known to be codec or + * stream-incompatible with the SourceBuffer configuration. For + * instance, Media Source Extensions would cause the video element to + * stall waiting for video data if you switched from a variant with + * video and audio to an audio-only one. + * + * @param {Object} media a media playlist compatible with the current + * set of SourceBuffers. Variants in the current master playlist that + * do not appear to have compatible codec or stream configurations + * will be excluded from the default playlist selection algorithm + * indefinitely. + * @private + */ + + + MasterPlaylistController.prototype.excludeIncompatibleVariants_ = function excludeIncompatibleVariants_(media) { + var codecCount = 2; + var videoCodec = null; + var codecs = void 0; + + if (media.attributes.CODECS) { + codecs = parseCodecs(media.attributes.CODECS); + videoCodec = codecs.videoCodec; + codecCount = codecs.codecCount; + } + + this.master().playlists.forEach(function (variant) { + var variantCodecs = { + codecCount: 2, + videoCodec: null + }; + + if (variant.attributes.CODECS) { + variantCodecs = parseCodecs(variant.attributes.CODECS); + } + + // if the streams differ in the presence or absence of audio or + // video, they are incompatible + if (variantCodecs.codecCount !== codecCount) { + variant.excludeUntil = Infinity; + } + + // if h.264 is specified on the current playlist, some flavor of + // it must be specified on all compatible variants + if (variantCodecs.videoCodec !== videoCodec) { + variant.excludeUntil = Infinity; + } + }); + }; + + MasterPlaylistController.prototype.updateAdCues_ = function updateAdCues_(media) { + var offset = 0; + var seekable$$1 = this.seekable(); + + if (seekable$$1.length) { + offset = seekable$$1.start(0); + } + + updateAdCues(media, this.cueTagsTrack_, offset); + }; + + /** + * Calculates the desired forward buffer length based on current time + * + * @return {Number} Desired forward buffer length in seconds + */ + + + MasterPlaylistController.prototype.goalBufferLength = function goalBufferLength() { + var currentTime = this.tech_.currentTime(); + var initial = Config.GOAL_BUFFER_LENGTH; + var rate = Config.GOAL_BUFFER_LENGTH_RATE; + var max = Math.max(initial, Config.MAX_GOAL_BUFFER_LENGTH); + + return Math.min(initial + currentTime * rate, max); + }; + + /** + * Calculates the desired buffer low water line based on current time + * + * @return {Number} Desired buffer low water line in seconds + */ + + + MasterPlaylistController.prototype.bufferLowWaterLine = function bufferLowWaterLine() { + var currentTime = this.tech_.currentTime(); + var initial = Config.BUFFER_LOW_WATER_LINE; + var rate = Config.BUFFER_LOW_WATER_LINE_RATE; + var max = Math.max(initial, Config.MAX_BUFFER_LOW_WATER_LINE); + + return Math.min(initial + currentTime * rate, max); + }; + + return MasterPlaylistController; + }(videojs$1.EventTarget); + + /** + * Returns a function that acts as the Enable/disable playlist function. + * + * @param {PlaylistLoader} loader - The master playlist loader + * @param {String} playlistUri - uri of the playlist + * @param {Function} changePlaylistFn - A function to be called after a + * playlist's enabled-state has been changed. Will NOT be called if a + * playlist's enabled-state is unchanged + * @param {Boolean=} enable - Value to set the playlist enabled-state to + * or if undefined returns the current enabled-state for the playlist + * @return {Function} Function for setting/getting enabled + */ + + + var enableFunction = function enableFunction(loader, playlistUri, changePlaylistFn) { + return function (enable) { + var playlist = loader.master.playlists[playlistUri]; + var incompatible = isIncompatible(playlist); + var currentlyEnabled = isEnabled(playlist); + + if (typeof enable === 'undefined') { + return currentlyEnabled; + } + + if (enable) { + delete playlist.disabled; + } else { + playlist.disabled = true; + } + + if (enable !== currentlyEnabled && !incompatible) { + // Ensure the outside world knows about our changes + changePlaylistFn(); + if (enable) { + loader.trigger('renditionenabled'); + } else { + loader.trigger('renditiondisabled'); + } + } + return enable; + }; + }; + + /** + * The representation object encapsulates the publicly visible information + * in a media playlist along with a setter/getter-type function (enabled) + * for changing the enabled-state of a particular playlist entry + * + * @class Representation + */ + + var Representation = function Representation(hlsHandler, playlist, id) { + classCallCheck(this, Representation); + + // Get a reference to a bound version of fastQualityChange_ + var fastChangeFunction = hlsHandler.masterPlaylistController_.fastQualityChange_.bind(hlsHandler.masterPlaylistController_); + + // some playlist attributes are optional + if (playlist.attributes.RESOLUTION) { + var resolution = playlist.attributes.RESOLUTION; + + this.width = resolution.width; + this.height = resolution.height; + } + + this.bandwidth = playlist.attributes.BANDWIDTH; + + // The id is simply the ordinality of the media playlist + // within the master playlist + this.id = id; + + // Partially-apply the enableFunction to create a playlist- + // specific variant + this.enabled = enableFunction(hlsHandler.playlists, playlist.uri, fastChangeFunction); + }; + + /** + * A mixin function that adds the `representations` api to an instance + * of the HlsHandler class + * @param {HlsHandler} hlsHandler - An instance of HlsHandler to add the + * representation API into + */ + + + var renditionSelectionMixin = function renditionSelectionMixin(hlsHandler) { + var playlists = hlsHandler.playlists; + + // Add a single API-specific function to the HlsHandler instance + hlsHandler.representations = function () { + return playlists.master.playlists.filter(function (media) { + return !isIncompatible(media); + }).map(function (e, i) { + return new Representation(hlsHandler, e, e.uri); + }); + }; + }; + + /** + * @file playback-watcher.js + * + * Playback starts, and now my watch begins. It shall not end until my death. I shall + * take no wait, hold no uncleared timeouts, father no bad seeks. I shall wear no crowns + * and win no glory. I shall live and die at my post. I am the corrector of the underflow. + * I am the watcher of gaps. I am the shield that guards the realms of seekable. I pledge + * my life and honor to the Playback Watch, for this Player and all the Players to come. + */ + + // Set of events that reset the playback-watcher time check logic and clear the timeout + var timerCancelEvents = ['seeking', 'seeked', 'pause', 'playing', 'error']; + + /** + * @class PlaybackWatcher + */ + + var PlaybackWatcher = function () { + /** + * Represents an PlaybackWatcher object. + * @constructor + * @param {object} options an object that includes the tech and settings + */ + function PlaybackWatcher(options) { + var _this35 = this; + + classCallCheck(this, PlaybackWatcher); + + this.tech_ = options.tech; + this.seekable = options.seekable; + + this.consecutiveUpdates = 0; + this.lastRecordedTime = null; + this.timer_ = null; + this.checkCurrentTimeTimeout_ = null; + this.logger_ = logger('PlaybackWatcher'); + + this.logger_('initialize'); + + var canPlayHandler = function canPlayHandler() { + return _this35.monitorCurrentTime_(); + }; + var waitingHandler = function waitingHandler() { + return _this35.techWaiting_(); + }; + var cancelTimerHandler = function cancelTimerHandler() { + return _this35.cancelTimer_(); + }; + var fixesBadSeeksHandler = function fixesBadSeeksHandler() { + return _this35.fixesBadSeeks_(); + }; + + this.tech_.on('seekablechanged', fixesBadSeeksHandler); + this.tech_.on('waiting', waitingHandler); + this.tech_.on(timerCancelEvents, cancelTimerHandler); + this.tech_.on('canplay', canPlayHandler); + + // Define the dispose function to clean up our events + this.dispose = function () { + _this35.logger_('dispose'); + _this35.tech_.off('seekablechanged', fixesBadSeeksHandler); + _this35.tech_.off('waiting', waitingHandler); + _this35.tech_.off(timerCancelEvents, cancelTimerHandler); + _this35.tech_.off('canplay', canPlayHandler); + if (_this35.checkCurrentTimeTimeout_) { + window_1.clearTimeout(_this35.checkCurrentTimeTimeout_); + } + _this35.cancelTimer_(); + }; + } + + /** + * Periodically check current time to see if playback stopped + * + * @private + */ + + + PlaybackWatcher.prototype.monitorCurrentTime_ = function monitorCurrentTime_() { + this.checkCurrentTime_(); + + if (this.checkCurrentTimeTimeout_) { + window_1.clearTimeout(this.checkCurrentTimeTimeout_); + } + + // 42 = 24 fps // 250 is what Webkit uses // FF uses 15 + this.checkCurrentTimeTimeout_ = window_1.setTimeout(this.monitorCurrentTime_.bind(this), 250); + }; + + /** + * The purpose of this function is to emulate the "waiting" event on + * browsers that do not emit it when they are waiting for more + * data to continue playback + * + * @private + */ + + + PlaybackWatcher.prototype.checkCurrentTime_ = function checkCurrentTime_() { + if (this.tech_.seeking() && this.fixesBadSeeks_()) { + this.consecutiveUpdates = 0; + this.lastRecordedTime = this.tech_.currentTime(); + return; + } + + if (this.tech_.paused() || this.tech_.seeking()) { + return; + } + + var currentTime = this.tech_.currentTime(); + var buffered = this.tech_.buffered(); + + if (this.lastRecordedTime === currentTime && (!buffered.length || currentTime + SAFE_TIME_DELTA >= buffered.end(buffered.length - 1))) { + // If current time is at the end of the final buffered region, then any playback + // stall is most likely caused by buffering in a low bandwidth environment. The tech + // should fire a `waiting` event in this scenario, but due to browser and tech + // inconsistencies. Calling `techWaiting_` here allows us to simulate + // responding to a native `waiting` event when the tech fails to emit one. + return this.techWaiting_(); + } + + if (this.consecutiveUpdates >= 5 && currentTime === this.lastRecordedTime) { + this.consecutiveUpdates++; + this.waiting_(); + } else if (currentTime === this.lastRecordedTime) { + this.consecutiveUpdates++; + } else { + this.consecutiveUpdates = 0; + this.lastRecordedTime = currentTime; + } + }; + + /** + * Cancels any pending timers and resets the 'timeupdate' mechanism + * designed to detect that we are stalled + * + * @private + */ + + + PlaybackWatcher.prototype.cancelTimer_ = function cancelTimer_() { + this.consecutiveUpdates = 0; + + if (this.timer_) { + this.logger_('cancelTimer_'); + clearTimeout(this.timer_); + } + + this.timer_ = null; + }; + + /** + * Fixes situations where there's a bad seek + * + * @return {Boolean} whether an action was taken to fix the seek + * @private + */ + + + PlaybackWatcher.prototype.fixesBadSeeks_ = function fixesBadSeeks_() { + var seeking = this.tech_.seeking(); + var seekable = this.seekable(); + var currentTime = this.tech_.currentTime(); + var seekTo = void 0; + + if (seeking && this.afterSeekableWindow_(seekable, currentTime)) { + var seekableEnd = seekable.end(seekable.length - 1); + + // sync to live point (if VOD, our seekable was updated and we're simply adjusting) + seekTo = seekableEnd; + } + + if (seeking && this.beforeSeekableWindow_(seekable, currentTime)) { + var seekableStart = seekable.start(0); + + // sync to the beginning of the live window + // provide a buffer of .1 seconds to handle rounding/imprecise numbers + seekTo = seekableStart + SAFE_TIME_DELTA; + } + + if (typeof seekTo !== 'undefined') { + this.logger_('Trying to seek outside of seekable at time ' + currentTime + ' with ' + ('seekable range ' + printableRange(seekable) + '. Seeking to ') + (seekTo + '.')); + + this.tech_.setCurrentTime(seekTo); + return true; + } + + return false; + }; + + /** + * Handler for situations when we determine the player is waiting. + * + * @private + */ + + + PlaybackWatcher.prototype.waiting_ = function waiting_() { + if (this.techWaiting_()) { + return; + } + + // All tech waiting checks failed. Use last resort correction + var currentTime = this.tech_.currentTime(); + var buffered = this.tech_.buffered(); + var currentRange = findRange(buffered, currentTime); + + // Sometimes the player can stall for unknown reasons within a contiguous buffered + // region with no indication that anything is amiss (seen in Firefox). Seeking to + // currentTime is usually enough to kickstart the player. This checks that the player + // is currently within a buffered region before attempting a corrective seek. + // Chrome does not appear to continue `timeupdate` events after a `waiting` event + // until there is ~ 3 seconds of forward buffer available. PlaybackWatcher should also + // make sure there is ~3 seconds of forward buffer before taking any corrective action + // to avoid triggering an `unknownwaiting` event when the network is slow. + if (currentRange.length && currentTime + 3 <= currentRange.end(0)) { + this.cancelTimer_(); + this.tech_.setCurrentTime(currentTime); + + this.logger_('Stopped at ' + currentTime + ' while inside a buffered region ' + ('[' + currentRange.start(0) + ' -> ' + currentRange.end(0) + ']. Attempting to resume ') + 'playback by seeking to the current time.'); + + // unknown waiting corrections may be useful for monitoring QoS + this.tech_.trigger({type: 'usage', name: 'hls-unknown-waiting'}); + return; + } + }; + + /** + * Handler for situations when the tech fires a `waiting` event + * + * @return {Boolean} + * True if an action (or none) was needed to correct the waiting. False if no + * checks passed + * @private + */ + + + PlaybackWatcher.prototype.techWaiting_ = function techWaiting_() { + var seekable = this.seekable(); + var currentTime = this.tech_.currentTime(); + + if (this.tech_.seeking() && this.fixesBadSeeks_()) { + // Tech is seeking or bad seek fixed, no action needed + return true; + } + + if (this.tech_.seeking() || this.timer_ !== null) { + // Tech is seeking or already waiting on another action, no action needed + return true; + } + + if (this.beforeSeekableWindow_(seekable, currentTime)) { + var livePoint = seekable.end(seekable.length - 1); + + this.logger_('Fell out of live window at time ' + currentTime + '. Seeking to ' + ('live point (seekable end) ' + livePoint)); + this.cancelTimer_(); + this.tech_.setCurrentTime(livePoint); + + // live window resyncs may be useful for monitoring QoS + this.tech_.trigger({type: 'usage', name: 'hls-live-resync'}); + return true; + } + + var buffered = this.tech_.buffered(); + var nextRange = findNextRange(buffered, currentTime); + + if (this.videoUnderflow_(nextRange, buffered, currentTime)) { + // Even though the video underflowed and was stuck in a gap, the audio overplayed + // the gap, leading currentTime into a buffered range. Seeking to currentTime + // allows the video to catch up to the audio position without losing any audio + // (only suffering ~3 seconds of frozen video and a pause in audio playback). + this.cancelTimer_(); + this.tech_.setCurrentTime(currentTime); + + // video underflow may be useful for monitoring QoS + this.tech_.trigger({type: 'usage', name: 'hls-video-underflow'}); + return true; + } + + // check for gap + if (nextRange.length > 0) { + var difference = nextRange.start(0) - currentTime; + + this.logger_('Stopped at ' + currentTime + ', setting timer for ' + difference + ', seeking ' + ('to ' + nextRange.start(0))); + + this.timer_ = setTimeout(this.skipTheGap_.bind(this), difference * 1000, currentTime); + return true; + } + + // All checks failed. Returning false to indicate failure to correct waiting + return false; + }; + + PlaybackWatcher.prototype.afterSeekableWindow_ = function afterSeekableWindow_(seekable, currentTime) { + if (!seekable.length) { + // we can't make a solid case if there's no seekable, default to false + return false; + } + + if (currentTime > seekable.end(seekable.length - 1) + SAFE_TIME_DELTA) { + return true; + } + + return false; + }; + + PlaybackWatcher.prototype.beforeSeekableWindow_ = function beforeSeekableWindow_(seekable, currentTime) { + if (seekable.length && + // can't fall before 0 and 0 seekable start identifies VOD stream + seekable.start(0) > 0 && currentTime < seekable.start(0) - SAFE_TIME_DELTA) { + return true; + } + + return false; + }; + + PlaybackWatcher.prototype.videoUnderflow_ = function videoUnderflow_(nextRange, buffered, currentTime) { + if (nextRange.length === 0) { + // Even if there is no available next range, there is still a possibility we are + // stuck in a gap due to video underflow. + var gap = this.gapFromVideoUnderflow_(buffered, currentTime); + + if (gap) { + this.logger_('Encountered a gap in video from ' + gap.start + ' to ' + gap.end + '. ' + ('Seeking to current time ' + currentTime)); + + return true; + } + } + + return false; + }; + + /** + * Timer callback. If playback still has not proceeded, then we seek + * to the start of the next buffered region. + * + * @private + */ + + + PlaybackWatcher.prototype.skipTheGap_ = function skipTheGap_(scheduledCurrentTime) { + var buffered = this.tech_.buffered(); + var currentTime = this.tech_.currentTime(); + var nextRange = findNextRange(buffered, currentTime); + + this.cancelTimer_(); + + if (nextRange.length === 0 || currentTime !== scheduledCurrentTime) { + return; + } + + this.logger_('skipTheGap_:', 'currentTime:', currentTime, 'scheduled currentTime:', scheduledCurrentTime, 'nextRange start:', nextRange.start(0)); + + // only seek if we still have not played + this.tech_.setCurrentTime(nextRange.start(0) + TIME_FUDGE_FACTOR); + + this.tech_.trigger({type: 'usage', name: 'hls-gap-skip'}); + }; + + PlaybackWatcher.prototype.gapFromVideoUnderflow_ = function gapFromVideoUnderflow_(buffered, currentTime) { + // At least in Chrome, if there is a gap in the video buffer, the audio will continue + // playing for ~3 seconds after the video gap starts. This is done to account for + // video buffer underflow/underrun (note that this is not done when there is audio + // buffer underflow/underrun -- in that case the video will stop as soon as it + // encounters the gap, as audio stalls are more noticeable/jarring to a user than + // video stalls). The player's time will reflect the playthrough of audio, so the + // time will appear as if we are in a buffered region, even if we are stuck in a + // "gap." + // + // Example: + // video buffer: 0 => 10.1, 10.2 => 20 + // audio buffer: 0 => 20 + // overall buffer: 0 => 10.1, 10.2 => 20 + // current time: 13 + // + // Chrome's video froze at 10 seconds, where the video buffer encountered the gap, + // however, the audio continued playing until it reached ~3 seconds past the gap + // (13 seconds), at which point it stops as well. Since current time is past the + // gap, findNextRange will return no ranges. + // + // To check for this issue, we see if there is a gap that starts somewhere within + // a 3 second range (3 seconds +/- 1 second) back from our current time. + var gaps = findGaps(buffered); + + for (var i = 0; i < gaps.length; i++) { + var start = gaps.start(i); + var end = gaps.end(i); + + // gap is starts no more than 4 seconds back + if (currentTime - start < 4 && currentTime - start > 2) { + return { + start: start, + end: end + }; + } + } + + return null; + }; + + return PlaybackWatcher; + }(); + + var defaultOptions = { + errorInterval: 30, + getSource: function getSource(next) { + var tech = this.tech({IWillNotUseThisInPlugins: true}); + var sourceObj = tech.currentSource_; + + return next(sourceObj); + } + }; + + /** + * Main entry point for the plugin + * + * @param {Player} player a reference to a videojs Player instance + * @param {Object} [options] an object with plugin options + * @private + */ + var initPlugin = function initPlugin(player, options) { + var lastCalled = 0; + var seekTo = 0; + var localOptions = videojs$1.mergeOptions(defaultOptions, options); + + player.ready(function () { + player.trigger({type: 'usage', name: 'hls-error-reload-initialized'}); + }); + + /** + * Player modifications to perform that must wait until `loadedmetadata` + * has been triggered + * + * @private + */ + var loadedMetadataHandler = function loadedMetadataHandler() { + if (seekTo) { + player.currentTime(seekTo); + } + }; + + /** + * Set the source on the player element, playOld, and seek if necessary + * + * @param {Object} sourceObj An object specifying the source url and mime-type to playOld + * @private + */ + var setSource = function setSource(sourceObj) { + if (sourceObj === null || sourceObj === undefined) { + return; + } + seekTo = player.duration() !== Infinity && player.currentTime() || 0; + + player.one('loadedmetadata', loadedMetadataHandler); + + player.src(sourceObj); + player.trigger({type: 'usage', name: 'hls-error-reload'}); + player.play(); + }; + + /** + * Attempt to get a source from either the built-in getSource function + * or a custom function provided via the options + * + * @private + */ + var errorHandler = function errorHandler() { + // Do not attempt to reload the source if a source-reload occurred before + // 'errorInterval' time has elapsed since the last source-reload + if (Date.now() - lastCalled < localOptions.errorInterval * 1000) { + player.trigger({type: 'usage', name: 'hls-error-reload-canceled'}); + return; + } + + if (!localOptions.getSource || typeof localOptions.getSource !== 'function') { + videojs$1.log.error('ERROR: reloadSourceOnError - The option getSource must be a function!'); + return; + } + lastCalled = Date.now(); + + return localOptions.getSource.call(player, setSource); + }; + + /** + * Unbind any event handlers that were bound by the plugin + * + * @private + */ + var cleanupEvents = function cleanupEvents() { + player.off('loadedmetadata', loadedMetadataHandler); + player.off('error', errorHandler); + player.off('dispose', cleanupEvents); + }; + + /** + * Cleanup before re-initializing the plugin + * + * @param {Object} [newOptions] an object with plugin options + * @private + */ + var reinitPlugin = function reinitPlugin(newOptions) { + cleanupEvents(); + initPlugin(player, newOptions); + }; + + player.on('error', errorHandler); + player.on('dispose', cleanupEvents); + + // Overwrite the plugin function so that we can correctly cleanup before + // initializing the plugin + player.reloadSourceOnError = reinitPlugin; + }; + + /** + * Reload the source when an error is detected as long as there + * wasn't an error previously within the last 30 seconds + * + * @param {Object} [options] an object with plugin options + */ + var reloadSourceOnError = function reloadSourceOnError(options) { + initPlugin(this, options); + }; + + var version$3 = "1.0.0"; + + /** + * @file videojs-http-streaming.js + * + * The main file for the HLS project. + * License: https://github.com/videojs/videojs-http-streaming/blob/master/LICENSE + */ + + var Hls$1 = { + PlaylistLoader: PlaylistLoader, + Playlist: Playlist, + Decrypter: Decrypter, + AsyncStream: AsyncStream, + decrypt: decrypt, + utils: utils, + + STANDARD_PLAYLIST_SELECTOR: lastBandwidthSelector, + INITIAL_PLAYLIST_SELECTOR: lowestBitrateCompatibleVariantSelector, + comparePlaylistBandwidth: comparePlaylistBandwidth, + comparePlaylistResolution: comparePlaylistResolution, + + xhr: xhrFactory() + }; + + // 0.5 MB/s + var INITIAL_BANDWIDTH = 4194304; + + // Define getter/setters for config properites + ['GOAL_BUFFER_LENGTH', 'MAX_GOAL_BUFFER_LENGTH', 'GOAL_BUFFER_LENGTH_RATE', 'BUFFER_LOW_WATER_LINE', 'MAX_BUFFER_LOW_WATER_LINE', 'BUFFER_LOW_WATER_LINE_RATE', 'BANDWIDTH_VARIANCE'].forEach(function (prop) { + Object.defineProperty(Hls$1, prop, { + get: function get$$1() { + videojs$1.log.warn('using Hls.' + prop + ' is UNSAFE be sure you know what you are doing'); + return Config[prop]; + }, + set: function set$$1(value) { + videojs$1.log.warn('using Hls.' + prop + ' is UNSAFE be sure you know what you are doing'); + + if (typeof value !== 'number' || value < 0) { + videojs$1.log.warn('value of Hls.' + prop + ' must be greater than or equal to 0'); + return; + } + + Config[prop] = value; + } + }); + }); + + var simpleTypeFromSourceType = function simpleTypeFromSourceType(type) { + var mpegurlRE = /^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i; + + if (mpegurlRE.test(type)) { + return 'hls'; + } + + var dashRE = /^application\/dash\+xml/i; + + if (dashRE.test(type)) { + return 'dash'; + } + + return null; + }; + + /** + * Updates the selectedIndex of the QualityLevelList when a mediachange happens in hls. + * + * @param {QualityLevelList} qualityLevels The QualityLevelList to update. + * @param {PlaylistLoader} playlistLoader PlaylistLoader containing the new media info. + * @function handleHlsMediaChange + */ + var handleHlsMediaChange = function handleHlsMediaChange(qualityLevels, playlistLoader) { + var newPlaylist = playlistLoader.media(); + var selectedIndex = -1; + + for (var i = 0; i < qualityLevels.length; i++) { + if (qualityLevels[i].id === newPlaylist.uri) { + selectedIndex = i; + break; + } + } + + qualityLevels.selectedIndex_ = selectedIndex; + qualityLevels.trigger({ + selectedIndex: selectedIndex, + type: 'change' + }); + }; + + /** + * Adds quality levels to list once playlist metadata is available + * + * @param {QualityLevelList} qualityLevels The QualityLevelList to attach events to. + * @param {Object} hls Hls object to listen to for media events. + * @function handleHlsLoadedMetadata + */ + var handleHlsLoadedMetadata = function handleHlsLoadedMetadata(qualityLevels, hls) { + hls.representations().forEach(function (rep) { + qualityLevels.addQualityLevel(rep); + }); + handleHlsMediaChange(qualityLevels, hls.playlists); + }; + + // HLS is a source handler, not a tech. Make sure attempts to use it + // as one do not cause exceptions. + Hls$1.canPlaySource = function () { + return videojs$1.log.warn('HLS is no longer a tech. Please remove it from ' + 'your player\'s techOrder.'); + }; + + var emeKeySystems = function emeKeySystems(keySystemOptions, videoPlaylist, audioPlaylist) { + if (!keySystemOptions) { + return keySystemOptions; + } + + // upsert the content types based on the selected playlist + var keySystemContentTypes = {}; + + for (var keySystem in keySystemOptions) { + keySystemContentTypes[keySystem] = { + audioContentType: 'audio/mp4; codecs="' + audioPlaylist.attributes.CODECS + '"', + videoContentType: 'video/mp4; codecs="' + videoPlaylist.attributes.CODECS + '"' + }; + + if (videoPlaylist.contentProtection && videoPlaylist.contentProtection[keySystem] && videoPlaylist.contentProtection[keySystem].pssh) { + keySystemContentTypes[keySystem].pssh = videoPlaylist.contentProtection[keySystem].pssh; + } + + // videojs-contrib-eme accepts the option of specifying: 'com.some.cdm': 'url' + // so we need to prevent overwriting the URL entirely + if (typeof keySystemOptions[keySystem] === 'string') { + keySystemContentTypes[keySystem].url = keySystemOptions[keySystem]; + } + } + + return videojs$1.mergeOptions(keySystemOptions, keySystemContentTypes); + }; + + var setupEmeOptions = function setupEmeOptions(hlsHandler) { + if (hlsHandler.options_.sourceType !== 'dash') { + return; + } + var player = videojs$1.players[hlsHandler.tech_.options_.playerId]; + + if (player.eme) { + var sourceOptions = emeKeySystems(hlsHandler.source_.keySystems, hlsHandler.playlists.media(), hlsHandler.masterPlaylistController_.mediaTypes_.AUDIO.activePlaylistLoader.media()); + + if (sourceOptions) { + player.currentSource().keySystems = sourceOptions; + } + } + }; + + /** + * Whether the browser has built-in HLS support. + */ + Hls$1.supportsNativeHls = function () { + var video = document_1.createElement('video'); + + // native HLS is definitely not supported if HTML5 video isn't + if (!videojs$1.getTech('Html5').isSupported()) { + return false; + } + + // HLS manifests can go by many mime-types + var canPlay = [ + // Apple santioned + 'application/vnd.apple.mpegurl', + // Apple sanctioned for backwards compatibility + 'audio/mpegurl', + // Very common + 'audio/x-mpegurl', + // Very common + 'application/x-mpegurl', + // Included for completeness + 'video/x-mpegurl', 'video/mpegurl', 'application/mpegurl']; + + return canPlay.some(function (canItPlay) { + return (/maybe|probably/i.test(video.canPlayType(canItPlay)) + ); + }); + }(); + + Hls$1.supportsNativeDash = function () { + if (!videojs$1.getTech('Html5').isSupported()) { + return false; + } + + return (/maybe|probably/i.test(document_1.createElement('video').canPlayType('application/dash+xml')) + ); + }(); + + Hls$1.supportsTypeNatively = function (type) { + if (type === 'hls') { + return Hls$1.supportsNativeHls; + } + + if (type === 'dash') { + return Hls$1.supportsNativeDash; + } + + return false; + }; + + /** + * HLS is a source handler, not a tech. Make sure attempts to use it + * as one do not cause exceptions. + */ + Hls$1.isSupported = function () { + return videojs$1.log.warn('HLS is no longer a tech. Please remove it from ' + 'your player\'s techOrder.'); + }; + + var Component$1 = videojs$1.getComponent('Component'); + + /** + * The Hls Handler object, where we orchestrate all of the parts + * of HLS to interact with video.js + * + * @class HlsHandler + * @extends videojs.Component + * @param {Object} source the soruce object + * @param {Tech} tech the parent tech object + * @param {Object} options optional and required options + */ + + var HlsHandler = function (_Component) { + inherits(HlsHandler, _Component); + + function HlsHandler(source, tech, options) { + classCallCheck(this, HlsHandler); + + // tech.player() is deprecated but setup a reference to HLS for + // backwards-compatibility + var _this36 = possibleConstructorReturn(this, _Component.call(this, tech, options.hls)); + + if (tech.options_ && tech.options_.playerId) { + var _player = videojs$1(tech.options_.playerId); + + if (!_player.hasOwnProperty('hls')) { + Object.defineProperty(_player, 'hls', { + get: function get$$1() { + videojs$1.log.warn('player.hls is deprecated. Use player.tech_.hls instead.'); + tech.trigger({type: 'usage', name: 'hls-player-access'}); + return _this36; + } + }); + } + + // Set up a reference to the HlsHandler from player.vhs. This allows users to start + // migrating from player.tech_.hls... to player.vhs... for API access. Although this + // isn't the most appropriate form of reference for video.js (since all APIs should + // be provided through core video.js), it is a common pattern for plugins, and vhs + // will act accordingly. + _player.vhs = _this36; + // deprecated, for backwards compatibility + _player.dash = _this36; + } + + _this36.tech_ = tech; + _this36.source_ = source; + _this36.stats = {}; + _this36.ignoreNextSeekingEvent_ = false; + _this36.setOptions_(); + + // overriding native HLS only works if audio tracks have been emulated + // error early if we're misconfigured: + if (_this36.options_.overrideNative && (tech.featuresNativeVideoTracks || tech.featuresNativeAudioTracks)) { + throw new Error('Overriding native HLS requires emulated tracks. ' + 'See https://git.io/vMpjB'); + } + + // listen for fullscreenchange events for this player so that we + // can adjust our quality selection quickly + _this36.on(document_1, ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange'], function (event) { + var fullscreenElement = document_1.fullscreenElement || document_1.webkitFullscreenElement || document_1.mozFullScreenElement || document_1.msFullscreenElement; + + if (fullscreenElement && fullscreenElement.contains(_this36.tech_.el())) { + _this36.masterPlaylistController_.fastQualityChange_(); + } + }); + + _this36.on(_this36.tech_, 'seeking', function () { + if (this.ignoreNextSeekingEvent_) { + this.ignoreNextSeekingEvent_ = false; + return; + } + + this.setCurrentTime(this.tech_.currentTime()); + }); + _this36.on(_this36.tech_, 'error', function () { + if (this.masterPlaylistController_) { + this.masterPlaylistController_.pauseLoading(); + } + }); + + _this36.on(_this36.tech_, 'play', _this36.play); + return _this36; + } + + HlsHandler.prototype.setOptions_ = function setOptions_() { + var _this37 = this; + + // defaults + this.options_.withCredentials = this.options_.withCredentials || false; + + if (typeof this.options_.blacklistDuration !== 'number') { + this.options_.blacklistDuration = 5 * 60; + } + + // start playlist selection at a reasonable bandwidth for + // broadband internet (0.5 MB/s) or mobile (0.0625 MB/s) + if (typeof this.options_.bandwidth !== 'number') { + this.options_.bandwidth = INITIAL_BANDWIDTH; + } + + // If the bandwidth number is unchanged from the initial setting + // then this takes precedence over the enableLowInitialPlaylist option + this.options_.enableLowInitialPlaylist = this.options_.enableLowInitialPlaylist && this.options_.bandwidth === INITIAL_BANDWIDTH; + + // grab options passed to player.src + ['withCredentials', 'bandwidth'].forEach(function (option) { + if (typeof _this37.source_[option] !== 'undefined') { + _this37.options_[option] = _this37.source_[option]; + } + }); + + this.bandwidth = this.options_.bandwidth; + }; + /** + * called when player.src gets called, handle a new source + * + * @param {Object} src the source object to handle + */ + + + HlsHandler.prototype.src = function src(_src, type) { + var _this38 = this; + + // do nothing if the src is falsey + if (!_src) { + return; + } + this.setOptions_(); + // add master playlist controller options + this.options_.url = this.source_.src; + this.options_.tech = this.tech_; + this.options_.externHls = Hls$1; + this.options_.sourceType = simpleTypeFromSourceType(type); + + this.masterPlaylistController_ = new MasterPlaylistController(this.options_); + this.playbackWatcher_ = new PlaybackWatcher(videojs$1.mergeOptions(this.options_, { + seekable: function seekable() { + return _this38.seekable(); + } + })); + + this.masterPlaylistController_.on('error', function () { + var player = videojs$1.players[_this38.tech_.options_.playerId]; + + player.error(_this38.masterPlaylistController_.error); + }); + + // `this` in selectPlaylist should be the HlsHandler for backwards + // compatibility with < v2 + this.masterPlaylistController_.selectPlaylist = this.selectPlaylist ? this.selectPlaylist.bind(this) : Hls$1.STANDARD_PLAYLIST_SELECTOR.bind(this); + + this.masterPlaylistController_.selectInitialPlaylist = Hls$1.INITIAL_PLAYLIST_SELECTOR.bind(this); + + // re-expose some internal objects for backwards compatibility with < v2 + this.playlists = this.masterPlaylistController_.masterPlaylistLoader_; + this.mediaSource = this.masterPlaylistController_.mediaSource; + + // Proxy assignment of some properties to the master playlist + // controller. Using a custom property for backwards compatibility + // with < v2 + Object.defineProperties(this, { + selectPlaylist: { + get: function get$$1() { + return this.masterPlaylistController_.selectPlaylist; + }, + set: function set$$1(selectPlaylist) { + this.masterPlaylistController_.selectPlaylist = selectPlaylist.bind(this); + } + }, + throughput: { + get: function get$$1() { + return this.masterPlaylistController_.mainSegmentLoader_.throughput.rate; + }, + set: function set$$1(throughput) { + this.masterPlaylistController_.mainSegmentLoader_.throughput.rate = throughput; + // By setting `count` to 1 the throughput value becomes the starting value + // for the cumulative average + this.masterPlaylistController_.mainSegmentLoader_.throughput.count = 1; + } + }, + bandwidth: { + get: function get$$1() { + return this.masterPlaylistController_.mainSegmentLoader_.bandwidth; + }, + set: function set$$1(bandwidth) { + this.masterPlaylistController_.mainSegmentLoader_.bandwidth = bandwidth; + // setting the bandwidth manually resets the throughput counter + // `count` is set to zero that current value of `rate` isn't included + // in the cumulative average + this.masterPlaylistController_.mainSegmentLoader_.throughput = { + rate: 0, + count: 0 + }; + } + }, + /** + * `systemBandwidth` is a combination of two serial processes bit-rates. The first + * is the network bitrate provided by `bandwidth` and the second is the bitrate of + * the entire process after that - decryption, transmuxing, and appending - provided + * by `throughput`. + * + * Since the two process are serial, the overall system bandwidth is given by: + * sysBandwidth = 1 / (1 / bandwidth + 1 / throughput) + */ + systemBandwidth: { + get: function get$$1() { + var invBandwidth = 1 / (this.bandwidth || 1); + var invThroughput = void 0; + + if (this.throughput > 0) { + invThroughput = 1 / this.throughput; + } else { + invThroughput = 0; + } + + var systemBitrate = Math.floor(1 / (invBandwidth + invThroughput)); + + return systemBitrate; + }, + set: function set$$1() { + videojs$1.log.error('The "systemBandwidth" property is read-only'); + } + } + }); + + Object.defineProperties(this.stats, { + bandwidth: { + get: function get$$1() { + return _this38.bandwidth || 0; + }, + enumerable: true + }, + mediaRequests: { + get: function get$$1() { + return _this38.masterPlaylistController_.mediaRequests_() || 0; + }, + enumerable: true + }, + mediaRequestsAborted: { + get: function get$$1() { + return _this38.masterPlaylistController_.mediaRequestsAborted_() || 0; + }, + enumerable: true + }, + mediaRequestsTimedout: { + get: function get$$1() { + return _this38.masterPlaylistController_.mediaRequestsTimedout_() || 0; + }, + enumerable: true + }, + mediaRequestsErrored: { + get: function get$$1() { + return _this38.masterPlaylistController_.mediaRequestsErrored_() || 0; + }, + enumerable: true + }, + mediaTransferDuration: { + get: function get$$1() { + return _this38.masterPlaylistController_.mediaTransferDuration_() || 0; + }, + enumerable: true + }, + mediaBytesTransferred: { + get: function get$$1() { + return _this38.masterPlaylistController_.mediaBytesTransferred_() || 0; + }, + enumerable: true + }, + mediaSecondsLoaded: { + get: function get$$1() { + return _this38.masterPlaylistController_.mediaSecondsLoaded_() || 0; + }, + enumerable: true + }, + buffered: { + get: function get$$1() { + return timeRangesToArray(_this38.tech_.buffered()); + }, + enumerable: true + }, + currentTime: { + get: function get$$1() { + return _this38.tech_.currentTime(); + }, + enumerable: true + }, + currentSource: { + get: function get$$1() { + return _this38.tech_.currentSource_; + }, + enumerable: true + }, + currentTech: { + get: function get$$1() { + return _this38.tech_.name_; + }, + enumerable: true + }, + duration: { + get: function get$$1() { + return _this38.tech_.duration(); + }, + enumerable: true + }, + master: { + get: function get$$1() { + return _this38.playlists.master; + }, + enumerable: true + }, + playerDimensions: { + get: function get$$1() { + return _this38.tech_.currentDimensions(); + }, + enumerable: true + }, + seekable: { + get: function get$$1() { + return timeRangesToArray(_this38.tech_.seekable()); + }, + enumerable: true + }, + timestamp: { + get: function get$$1() { + return Date.now(); + }, + enumerable: true + }, + videoPlaybackQuality: { + get: function get$$1() { + return _this38.tech_.getVideoPlaybackQuality(); + }, + enumerable: true + } + }); + + this.tech_.one('canplay', this.masterPlaylistController_.setupFirstPlay.bind(this.masterPlaylistController_)); + + this.masterPlaylistController_.on('selectedinitialmedia', function () { + // Add the manual rendition mix-in to HlsHandler + renditionSelectionMixin(_this38); + setupEmeOptions(_this38); + }); + + // the bandwidth of the primary segment loader is our best + // estimate of overall bandwidth + this.on(this.masterPlaylistController_, 'progress', function () { + this.tech_.trigger('progress'); + }); + + // In the live case, we need to ignore the very first `seeking` event since + // that will be the result of the seek-to-live behavior + this.on(this.masterPlaylistController_, 'firstplay', function () { + this.ignoreNextSeekingEvent_ = true; + }); + + this.tech_.ready(function () { + return _this38.setupQualityLevels_(); + }); + + // do nothing if the tech has been disposed already + // this can occur if someone sets the src in player.ready(), for instance + if (!this.tech_.el()) { + return; + } + + this.tech_.src(videojs$1.URL.createObjectURL(this.masterPlaylistController_.mediaSource)); + }; + + /** + * Initializes the quality levels and sets listeners to update them. + * + * @method setupQualityLevels_ + * @private + */ + + + HlsHandler.prototype.setupQualityLevels_ = function setupQualityLevels_() { + var _this39 = this; + + var player = videojs$1.players[this.tech_.options_.playerId]; + + if (player && player.qualityLevels) { + this.qualityLevels_ = player.qualityLevels(); + + this.masterPlaylistController_.on('selectedinitialmedia', function () { + handleHlsLoadedMetadata(_this39.qualityLevels_, _this39); + }); + + this.playlists.on('mediachange', function () { + handleHlsMediaChange(_this39.qualityLevels_, _this39.playlists); + }); + } + }; + + /** + * Begin playing the video. + */ + + + HlsHandler.prototype.play = function play() { + this.masterPlaylistController_.play(); + }; + + /** + * a wrapper around the function in MasterPlaylistController + */ + + + HlsHandler.prototype.setCurrentTime = function setCurrentTime(currentTime) { + this.masterPlaylistController_.setCurrentTime(currentTime); + }; + + /** + * a wrapper around the function in MasterPlaylistController + */ + + + HlsHandler.prototype.duration = function duration() { + return this.masterPlaylistController_.duration(); + }; + + /** + * a wrapper around the function in MasterPlaylistController + */ + + + HlsHandler.prototype.seekable = function seekable() { + return this.masterPlaylistController_.seekable(); + }; + + /** + * Abort all outstanding work and cleanup. + */ + + + HlsHandler.prototype.dispose = function dispose() { + if (this.playbackWatcher_) { + this.playbackWatcher_.dispose(); + } + if (this.masterPlaylistController_) { + this.masterPlaylistController_.dispose(); + } + if (this.qualityLevels_) { + this.qualityLevels_.dispose(); + } + _Component.prototype.dispose.call(this); + }; + + return HlsHandler; + }(Component$1); + + /** + * The Source Handler object, which informs video.js what additional + * MIME types are supported and sets up playback. It is registered + * automatically to the appropriate tech based on the capabilities of + * the browser it is running in. It is not necessary to use or modify + * this object in normal usage. + */ + + + var HlsSourceHandler = { + name: 'videojs-http-streaming', + VERSION: version$3, + canHandleSource: function canHandleSource(srcObj) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var localOptions = videojs$1.mergeOptions(videojs$1.options, options); + + return HlsSourceHandler.canPlayType(srcObj.type, localOptions); + }, + handleSource: function handleSource(source, tech) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + var localOptions = videojs$1.mergeOptions(videojs$1.options, options); + + tech.hls = new HlsHandler(source, tech, localOptions); + tech.hls.xhr = xhrFactory(); + + tech.hls.src(source.src, source.type); + return tech.hls; + }, + canPlayType: function canPlayType(type) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var _videojs$mergeOptions = videojs$1.mergeOptions(videojs$1.options, options), + overrideNative = _videojs$mergeOptions.hls.overrideNative; + + var supportedType = simpleTypeFromSourceType(type); + var canUseMsePlayback = supportedType && (!Hls$1.supportsTypeNatively(supportedType) || overrideNative); + + return canUseMsePlayback ? 'maybe' : ''; + } + }; + + if (typeof videojs$1.MediaSource === 'undefined' || typeof videojs$1.URL === 'undefined') { + videojs$1.MediaSource = MediaSource; + videojs$1.URL = URL$1; + } + + // register source handlers with the appropriate techs + if (MediaSource.supportsNativeMediaSources()) { + videojs$1.getTech('Html5').registerSourceHandler(HlsSourceHandler, 0); + } + + videojs$1.HlsHandler = HlsHandler; + videojs$1.HlsSourceHandler = HlsSourceHandler; + videojs$1.Hls = Hls$1; + if (!videojs$1.use) { + videojs$1.registerComponent('Hls', Hls$1); + } + videojs$1.options.hls = videojs$1.options.hls || {}; + + if (videojs$1.registerPlugin) { + videojs$1.registerPlugin('reloadSourceOnError', reloadSourceOnError); + } else { + videojs$1.plugin('reloadSourceOnError', reloadSourceOnError); + } + + return videojs$1; + +}))); diff --git a/form/src/assets/libs/video-js-7.0.0/video.min.js b/form/src/assets/libs/video-js-7.0.0/video.min.js new file mode 100644 index 0000000000000000000000000000000000000000..5d05e6c367da32195e17120c2ca8742682025e31 --- /dev/null +++ b/form/src/assets/libs/video-js-7.0.0/video.min.js @@ -0,0 +1,12 @@ +/** + * @license + * Video.js 7.0.0 <http://videojs.com/> + * Copyright Brightcove, Inc. <https://www.brightcove.com/> + * Available under Apache License Version 2.0 + * <https://github.com/videojs/video.js/blob/master/LICENSE> + * + * Includes vtt.js <https://github.com/mozilla/vtt.js> + * Available under Apache License Version 2.0 + * <https://github.com/mozilla/vtt.js/blob/master/LICENSE> + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.videojs=e()}(this,function(){var d="7.0.0",t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function e(t,e){return t(e={exports:{}},e.exports),e.exports}var i,g="undefined"!=typeof window?window:"undefined"!=typeof t?t:"undefined"!=typeof self?self:{},r={},n=Object.freeze({default:r}),s=n&&r||n,a="undefined"!=typeof t?t:"undefined"!=typeof window?window:{};"undefined"!=typeof document?i=document:(i=a["__GLOBAL_DOCUMENT_CACHE@4"])||(i=a["__GLOBAL_DOCUMENT_CACHE@4"]=s);var p=i,o=void 0,u="info",l=[],c=function(t,e){var i=o.levels[u],r=new RegExp("^("+i+")$");if("log"!==t&&e.unshift(t.toUpperCase()+":"),l&&l.push([].concat(e)),e.unshift("VIDEOJS:"),g.console){var n=g.console[t];n||"debug"!==t||(n=g.console.info||g.console.log),n&&i&&r.test(t)&&n[Array.isArray(e)?"apply":"call"](g.console,e)}};(o=function(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];c("log",e)}).levels={all:"debug|log|warn|error",off:"",debug:"debug|log|warn|error",info:"log|warn|error",warn:"warn|error",error:"error",DEFAULT:u},o.level=function(t){if("string"==typeof t){if(!o.levels.hasOwnProperty(t))throw new Error('"'+t+'" in not a valid log level');u=t}return u},o.history=function(){return l?[].concat(l):[]},o.history.clear=function(){l&&(l.length=0)},o.history.disable=function(){null!==l&&(l.length=0,l=null)},o.history.enable=function(){null===l&&(l=[])},o.error=function(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];return c("error",e)},o.warn=function(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];return c("warn",e)},o.debug=function(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];return c("debug",e)};var f=o;var m=function(t){for(var e="",i=0;i<arguments.length;i++)e+=t[i].replace(/\n\r?\s*/g,"")+(arguments[i+1]||"");return e},v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},y=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},_=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},b=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},h=function(t,e){return t.raw=e,t},T=Object.prototype.toString,S=function(t){return E(t)?Object.keys(t):[]};function k(e,i){S(e).forEach(function(t){return i(e[t],t)})}function C(i){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return Object.assign?Object.assign.apply(Object,[i].concat(e)):(e.forEach(function(t){t&&k(t,function(t,e){i[e]=t})}),i)}function E(t){return!!t&&"object"===("undefined"==typeof t?"undefined":v(t))}function w(t){return E(t)&&"[object Object]"===T.call(t)&&t.constructor===Object}function A(t,e){if(!t||!e)return"";if("function"==typeof g.getComputedStyle){var i=g.getComputedStyle(t);return i?i[e]:""}return""}var L=h(["Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set "," to ","."],["Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set "," to ","."]);function P(t){return"string"==typeof t&&/\S/.test(t)}function O(t){if(/\s/.test(t))throw new Error("class has illegal whitespace characters")}function x(){return p===g.document}function I(t){return E(t)&&1===t.nodeType}function D(){try{return g.parent!==g.self}catch(t){return!0}}function R(r){return function(t,e){if(!P(t))return p[r](null);P(e)&&(e=p.querySelector(e));var i=I(e)?e:p;return i[r]&&i[r](t)}}function M(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"div",i=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},e=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},r=arguments[3],n=p.createElement(t);return Object.getOwnPropertyNames(i).forEach(function(t){var e=i[t];-1!==t.indexOf("aria-")||"role"===t||"type"===t?(f.warn(m(L,t,e)),n.setAttribute(t,e)):"textContent"===t?U(n,e):n[t]=e}),Object.getOwnPropertyNames(e).forEach(function(t){n.setAttribute(t,e[t])}),r&&et(n,r),n}function U(t,e){return"undefined"==typeof t.textContent?t.innerText=e:t.textContent=e,t}function N(t,e){e.firstChild?e.insertBefore(t,e.firstChild):e.appendChild(t)}function B(t,e){return O(e),t.classList?t.classList.contains(e):(i=e,new RegExp("(^|\\s)"+i+"($|\\s)")).test(t.className);var i}function j(t,e){return t.classList?t.classList.add(e):B(t,e)||(t.className=(t.className+" "+e).trim()),t}function F(t,e){return t.classList?t.classList.remove(e):(O(e),t.className=t.className.split(/\s+/).filter(function(t){return t!==e}).join(" ")),t}function H(t,e,i){var r=B(t,e);if("function"==typeof i&&(i=i(t,e)),"boolean"!=typeof i&&(i=!r),i!==r)return i?j(t,e):F(t,e),t}function V(i,r){Object.getOwnPropertyNames(r).forEach(function(t){var e=r[t];null===e||"undefined"==typeof e||!1===e?i.removeAttribute(t):i.setAttribute(t,!0===e?"":e)})}function q(t){var e={},i=",autoplay,controls,playsinline,loop,muted,default,defaultMuted,";if(t&&t.attributes&&0<t.attributes.length)for(var r=t.attributes,n=r.length-1;0<=n;n--){var s=r[n].name,a=r[n].value;"boolean"!=typeof t[s]&&-1===i.indexOf(","+s+",")||(a=null!==a),e[s]=a}return e}function W(t,e){return t.getAttribute(e)}function z(t,e,i){t.setAttribute(e,i)}function G(t,e){t.removeAttribute(e)}function X(){p.body.focus(),p.onselectstart=function(){return!1}}function Y(){p.onselectstart=function(){return!0}}function $(t){if(t&&t.getBoundingClientRect&&t.parentNode){var e=t.getBoundingClientRect(),i={};return["bottom","height","left","right","top","width"].forEach(function(t){void 0!==e[t]&&(i[t]=e[t])}),i.height||(i.height=parseFloat(A(t,"height"))),i.width||(i.width=parseFloat(A(t,"width"))),i}}function K(t){var e=void 0;if(t.getBoundingClientRect&&t.parentNode&&(e=t.getBoundingClientRect()),!e)return{left:0,top:0};var i=p.documentElement,r=p.body,n=i.clientLeft||r.clientLeft||0,s=g.pageXOffset||r.scrollLeft,a=e.left+s-n,o=i.clientTop||r.clientTop||0,u=g.pageYOffset||r.scrollTop,l=e.top+u-o;return{left:Math.round(a),top:Math.round(l)}}function Q(t,e){var i={},r=K(t),n=t.offsetWidth,s=t.offsetHeight,a=r.top,o=r.left,u=e.pageY,l=e.pageX;return e.changedTouches&&(l=e.changedTouches[0].pageX,u=e.changedTouches[0].pageY),i.y=Math.max(0,Math.min(1,(a-u+s)/s)),i.x=Math.max(0,Math.min(1,(l-o)/n)),i}function J(t){return E(t)&&3===t.nodeType}function Z(t){for(;t.firstChild;)t.removeChild(t.firstChild);return t}function tt(t){return"function"==typeof t&&(t=t()),(Array.isArray(t)?t:[t]).map(function(t){return"function"==typeof t&&(t=t()),I(t)||J(t)?t:"string"==typeof t&&/\S/.test(t)?p.createTextNode(t):void 0}).filter(function(t){return t})}function et(e,t){return tt(t).forEach(function(t){return e.appendChild(t)}),e}function it(t,e){return et(Z(t),e)}function rt(t){return void 0===t.button&&void 0===t.buttons||(0===t.button&&void 0===t.buttons||0===t.button&&1===t.buttons)}var nt=R("querySelector"),st=R("querySelectorAll"),at=Object.freeze({isReal:x,isEl:I,isInFrame:D,createEl:M,textContent:U,prependTo:N,hasClass:B,addClass:j,removeClass:F,toggleClass:H,setAttributes:V,getAttributes:q,getAttribute:W,setAttribute:z,removeAttribute:G,blockTextSelection:X,unblockTextSelection:Y,getBoundingClientRect:$,findPosition:K,getPointerPosition:Q,isTextNode:J,emptyEl:Z,normalizeContent:tt,appendContent:et,insertContent:it,isSingleLeftClick:rt,$:nt,$$:st}),ot=1;function ut(){return ot++}var lt={},ct="vdata"+(new Date).getTime();function ht(t){var e=t[ct];return e||(e=t[ct]=ut()),lt[e]||(lt[e]={}),lt[e]}function dt(t){var e=t[ct];return!!e&&!!Object.getOwnPropertyNames(lt[e]).length}function pt(e){var t=e[ct];if(t){delete lt[t];try{delete e[ct]}catch(t){e.removeAttribute?e.removeAttribute(ct):e[ct]=null}}}function ft(t,e){var i=ht(t);0===i.handlers[e].length&&(delete i.handlers[e],t.removeEventListener?t.removeEventListener(e,i.dispatcher,!1):t.detachEvent&&t.detachEvent("on"+e,i.dispatcher)),Object.getOwnPropertyNames(i.handlers).length<=0&&(delete i.handlers,delete i.dispatcher,delete i.disabled),0===Object.getOwnPropertyNames(i).length&&pt(t)}function mt(e,i,t,r){t.forEach(function(t){e(i,t,r)})}function gt(t){function e(){return!0}function i(){return!1}if(!t||!t.isPropagationStopped){var r=t||g.event;for(var n in t={},r)"layerX"!==n&&"layerY"!==n&&"keyLocation"!==n&&"webkitMovementX"!==n&&"webkitMovementY"!==n&&("returnValue"===n&&r.preventDefault||(t[n]=r[n]));if(t.target||(t.target=t.srcElement||p),t.relatedTarget||(t.relatedTarget=t.fromElement===t.target?t.toElement:t.fromElement),t.preventDefault=function(){r.preventDefault&&r.preventDefault(),t.returnValue=!1,r.returnValue=!1,t.defaultPrevented=!0},t.defaultPrevented=!1,t.stopPropagation=function(){r.stopPropagation&&r.stopPropagation(),t.cancelBubble=!0,r.cancelBubble=!0,t.isPropagationStopped=e},t.isPropagationStopped=i,t.stopImmediatePropagation=function(){r.stopImmediatePropagation&&r.stopImmediatePropagation(),t.isImmediatePropagationStopped=e,t.stopPropagation()},t.isImmediatePropagationStopped=i,null!==t.clientX&&void 0!==t.clientX){var s=p.documentElement,a=p.body;t.pageX=t.clientX+(s&&s.scrollLeft||a&&a.scrollLeft||0)-(s&&s.clientLeft||a&&a.clientLeft||0),t.pageY=t.clientY+(s&&s.scrollTop||a&&a.scrollTop||0)-(s&&s.clientTop||a&&a.clientTop||0)}t.which=t.charCode||t.keyCode,null!==t.button&&void 0!==t.button&&(t.button=1&t.button?0:4&t.button?1:2&t.button?2:0)}return t}var yt=!1;!function(){try{var t=Object.defineProperty({},"passive",{get:function(){yt=!0}});g.addEventListener("test",null,t),g.removeEventListener("test",null,t)}catch(t){}}();var vt=["touchstart","touchmove"];function _t(a,t,e){if(Array.isArray(t))return mt(_t,a,t,e);var o=ht(a);if(o.handlers||(o.handlers={}),o.handlers[t]||(o.handlers[t]=[]),e.guid||(e.guid=ut()),o.handlers[t].push(e),o.dispatcher||(o.disabled=!1,o.dispatcher=function(t,e){if(!o.disabled){t=gt(t);var i=o.handlers[t.type];if(i)for(var r=i.slice(0),n=0,s=r.length;n<s&&!t.isImmediatePropagationStopped();n++)try{r[n].call(a,t,e)}catch(t){f.error(t)}}}),1===o.handlers[t].length)if(a.addEventListener){var i=!1;yt&&-1<vt.indexOf(t)&&(i={passive:!0}),a.addEventListener(t,o.dispatcher,i)}else a.attachEvent&&a.attachEvent("on"+t,o.dispatcher)}function bt(t,e,i){if(dt(t)){var r=ht(t);if(r.handlers){if(Array.isArray(e))return mt(bt,t,e,i);var n=function(t,e){r.handlers[e]=[],ft(t,e)};if(void 0!==e){var s=r.handlers[e];if(s)if(i){if(i.guid)for(var a=0;a<s.length;a++)s[a].guid===i.guid&&s.splice(a--,1);ft(t,e)}else n(t,e)}else for(var o in r.handlers)Object.prototype.hasOwnProperty.call(r.handlers||{},o)&&n(t,o)}}}function Tt(t,e,i){var r=dt(t)?ht(t):{},n=t.parentNode||t.ownerDocument;if("string"==typeof e?e={type:e,target:t}:e.target||(e.target=t),e=gt(e),r.dispatcher&&r.dispatcher.call(t,e,i),n&&!e.isPropagationStopped()&&!0===e.bubbles)Tt.call(null,n,e,i);else if(!n&&!e.defaultPrevented){var s=ht(e.target);e.target[e.type]&&(s.disabled=!0,"function"==typeof e.target[e.type]&&e.target[e.type](),s.disabled=!1)}return!e.defaultPrevented}function St(e,i,r){if(Array.isArray(i))return mt(St,e,i,r);var t=function t(){bt(e,i,t),r.apply(this,arguments)};t.guid=r.guid=r.guid||ut(),_t(e,i,t)}var kt=Object.freeze({fixEvent:gt,on:_t,off:bt,trigger:Tt,one:St}),Ct=!1,Et=void 0,wt=function(){if(x()&&!1!==Et.options.autoSetup){var t=Array.prototype.slice.call(p.getElementsByTagName("video")),e=Array.prototype.slice.call(p.getElementsByTagName("audio")),i=Array.prototype.slice.call(p.getElementsByTagName("video-js")),r=t.concat(e,i);if(r&&0<r.length)for(var n=0,s=r.length;n<s;n++){var a=r[n];if(!a||!a.getAttribute){At(1);break}void 0===a.player&&null!==a.getAttribute("data-setup")&&Et(a)}else Ct||At(1)}};function At(t,e){e&&(Et=e),g.setTimeout(wt,t)}x()&&"complete"===p.readyState?Ct=!0:St(g,"load",function(){Ct=!0});var Lt=function(t){var e=p.createElement("style");return e.className=t,e},Pt=function(t,e){t.styleSheet?t.styleSheet.cssText=e:t.textContent=e},Ot=function(t,e,i){e.guid||(e.guid=ut());var r=function(){return e.apply(t,arguments)};return r.guid=i?i+"_"+e.guid:e.guid,r},xt=function(e,i){var r=Date.now();return function(){var t=Date.now();i<=t-r&&(e.apply(void 0,arguments),r=t)}},It=function(r,n,s){var a=3<arguments.length&&void 0!==arguments[3]?arguments[3]:g,o=void 0;return function(){var t=this,e=arguments,i=function(){i=o=null,s||r.apply(t,e)};!o&&s&&r.apply(t,e),a.clearTimeout(o),o=a.setTimeout(i,n)}},Dt=function(){};Dt.prototype.allowedEvents_={},Dt.prototype.addEventListener=Dt.prototype.on=function(t,e){var i=this.addEventListener;this.addEventListener=function(){},_t(this,t,e),this.addEventListener=i},Dt.prototype.removeEventListener=Dt.prototype.off=function(t,e){bt(this,t,e)},Dt.prototype.one=function(t,e){var i=this.addEventListener;this.addEventListener=function(){},St(this,t,e),this.addEventListener=i},Dt.prototype.dispatchEvent=Dt.prototype.trigger=function(t){var e=t.type||t;"string"==typeof t&&(t={type:e}),t=gt(t),this.allowedEvents_[e]&&this["on"+e]&&this["on"+e](t),Tt(this,t)};var Rt=function(e){return e instanceof Dt||!!e.eventBusEl_&&["on","one","off","trigger"].every(function(t){return"function"==typeof e[t]})},Mt=function(t){return"string"==typeof t&&/\S/.test(t)||Array.isArray(t)&&!!t.length},Ut=function(t){if(!t.nodeName&&!Rt(t))throw new Error("Invalid target; must be a DOM node or evented object.")},Nt=function(t){if(!Mt(t))throw new Error("Invalid event type; must be a non-empty string or array.")},Bt=function(t){if("function"!=typeof t)throw new Error("Invalid listener; must be a function.")},jt=function(t,e){var i=e.length<3||e[0]===t||e[0]===t.eventBusEl_,r=void 0,n=void 0,s=void 0;return i?(r=t.eventBusEl_,3<=e.length&&e.shift(),n=e[0],s=e[1]):(r=e[0],n=e[1],s=e[2]),Ut(r),Nt(n),Bt(s),{isTargetingSelf:i,target:r,type:n,listener:s=Ot(t,s)}},Ft=function(t,e,i,r){Ut(t),t.nodeName?kt[e](t,i,r):t[e](i,r)},Ht={on:function(){for(var t=this,e=arguments.length,i=Array(e),r=0;r<e;r++)i[r]=arguments[r];var n=jt(this,i),s=n.isTargetingSelf,a=n.target,o=n.type,u=n.listener;if(Ft(a,"on",o,u),!s){var l=function(){return t.off(a,o,u)};l.guid=u.guid;var c=function(){return t.off("dispose",l)};c.guid=u.guid,Ft(this,"on","dispose",l),Ft(a,"on","dispose",c)}},one:function(){for(var n=this,t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];var r=jt(this,e),s=r.isTargetingSelf,a=r.target,o=r.type,u=r.listener;if(s)Ft(a,"one",o,u);else{var l=function t(){for(var e=arguments.length,i=Array(e),r=0;r<e;r++)i[r]=arguments[r];n.off(a,o,t),u.apply(null,i)};l.guid=u.guid,Ft(a,"one",o,l)}},off:function(t,e,i){if(!t||Mt(t))bt(this.eventBusEl_,t,e);else{var r=t,n=e;Ut(r),Nt(n),Bt(i),i=Ot(this,i),this.off("dispose",i),r.nodeName?(bt(r,n,i),bt(r,"dispose",i)):Rt(r)&&(r.off(n,i),r.off("dispose",i))}},trigger:function(t,e){return Tt(this.eventBusEl_,t,e)}};function Vt(t){var e=(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).eventBusKey;if(e){if(!t[e].nodeName)throw new Error('The eventBusKey "'+e+'" does not refer to an element.');t.eventBusEl_=t[e]}else t.eventBusEl_=M("span",{className:"vjs-event-bus"});return C(t,Ht),t.on("dispose",function(){t.off(),g.setTimeout(function(){t.eventBusEl_=null},0)}),t}var qt={state:{},setState:function(t){var i=this;"function"==typeof t&&(t=t());var r=void 0;return k(t,function(t,e){i.state[e]!==t&&((r=r||{})[e]={from:i.state[e],to:t}),i.state[e]=t}),r&&Rt(this)&&this.trigger({changes:r,type:"statechanged"}),r}};function Wt(t,e){return C(t,qt),t.state=C({},t.state,e),"function"==typeof t.handleStateChanged&&Rt(t)&&t.on("statechanged",t.handleStateChanged),t}function zt(t){return"string"!=typeof t?t:t.charAt(0).toUpperCase()+t.slice(1)}function Gt(){for(var i={},t=arguments.length,e=Array(t),r=0;r<t;r++)e[r]=arguments[r];return e.forEach(function(t){t&&k(t,function(t,e){w(t)?(w(i[e])||(i[e]={}),i[e]=Gt(i[e],t)):i[e]=t})}),i}var Xt=function(){function l(t,e,i){if(y(this,l),!t&&this.play?this.player_=t=this:this.player_=t,this.options_=Gt({},this.options_),e=this.options_=Gt(this.options_,e),this.id_=e.id||e.el&&e.el.id,!this.id_){var r=t&&t.id&&t.id()||"no_player";this.id_=r+"_component_"+ut()}this.name_=e.name||null,e.el?this.el_=e.el:!1!==e.createEl&&(this.el_=this.createEl()),!1!==e.evented&&Vt(this,{eventBusKey:this.el_?"el_":null}),Wt(this,this.constructor.defaultState),this.children_=[],this.childIndex_={},!(this.childNameIndex_={})!==e.initChildren&&this.initChildren(),this.ready(i),!1!==e.reportTouchActivity&&this.enableTouchActivity()}return l.prototype.dispose=function(){if(this.trigger({type:"dispose",bubbles:!1}),this.children_)for(var t=this.children_.length-1;0<=t;t--)this.children_[t].dispose&&this.children_[t].dispose();this.children_=null,this.childIndex_=null,this.childNameIndex_=null,this.el_&&(this.el_.parentNode&&this.el_.parentNode.removeChild(this.el_),pt(this.el_),this.el_=null),this.player_=null},l.prototype.player=function(){return this.player_},l.prototype.options=function(t){return f.warn("this.options() has been deprecated and will be moved to the constructor in 6.0"),t&&(this.options_=Gt(this.options_,t)),this.options_},l.prototype.el=function(){return this.el_},l.prototype.createEl=function(t,e,i){return M(t,e,i)},l.prototype.localize=function(t,n){var e=2<arguments.length&&void 0!==arguments[2]?arguments[2]:t,i=this.player_.language&&this.player_.language(),r=this.player_.languages&&this.player_.languages(),s=r&&r[i],a=i&&i.split("-")[0],o=r&&r[a],u=e;return s&&s[t]?u=s[t]:o&&o[t]&&(u=o[t]),n&&(u=u.replace(/\{(\d+)\}/g,function(t,e){var i=n[e-1],r=i;return"undefined"==typeof i&&(r=t),r})),u},l.prototype.contentEl=function(){return this.contentEl_||this.el_},l.prototype.id=function(){return this.id_},l.prototype.name=function(){return this.name_},l.prototype.children=function(){return this.children_},l.prototype.getChildById=function(t){return this.childIndex_[t]},l.prototype.getChild=function(t){if(t)return t=zt(t),this.childNameIndex_[t]},l.prototype.addChild=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:this.children_.length,r=void 0,n=void 0;if("string"==typeof t){n=zt(t);var s=e.componentClass||n;e.name=n;var a=l.getComponent(s);if(!a)throw new Error("Component "+s+" does not exist");if("function"!=typeof a)return null;r=new a(this.player_||this,e)}else r=t;if(this.children_.splice(i,0,r),"function"==typeof r.id&&(this.childIndex_[r.id()]=r),(n=n||r.name&&zt(r.name()))&&(this.childNameIndex_[n]=r),"function"==typeof r.el&&r.el()){var o=this.contentEl().children[i]||null;this.contentEl().insertBefore(r.el(),o)}return r},l.prototype.removeChild=function(t){if("string"==typeof t&&(t=this.getChild(t)),t&&this.children_){for(var e=!1,i=this.children_.length-1;0<=i;i--)if(this.children_[i]===t){e=!0,this.children_.splice(i,1);break}if(e){this.childIndex_[t.id()]=null,this.childNameIndex_[t.name()]=null;var r=t.el();r&&r.parentNode===this.contentEl()&&this.contentEl().removeChild(t.el())}}},l.prototype.initChildren=function(){var n=this,r=this.options_.children;if(r){var s=this.options_,t=void 0,i=l.getComponent("Tech");(t=Array.isArray(r)?r:Object.keys(r)).concat(Object.keys(this.options_).filter(function(e){return!t.some(function(t){return"string"==typeof t?e===t:e===t.name})})).map(function(t){var e=void 0,i=void 0;return"string"==typeof t?i=r[e=t]||n.options_[e]||{}:(e=t.name,i=t),{name:e,opts:i}}).filter(function(t){var e=l.getComponent(t.opts.componentClass||zt(t.name));return e&&!i.isTech(e)}).forEach(function(t){var e=t.name,i=t.opts;if(void 0!==s[e]&&(i=s[e]),!1!==i){!0===i&&(i={}),i.playerOptions=n.options_.playerOptions;var r=n.addChild(e,i);r&&(n[e]=r)}})}},l.prototype.buildCSSClass=function(){return""},l.prototype.ready=function(t){var e=1<arguments.length&&void 0!==arguments[1]&&arguments[1];if(t)return this.isReady_?void(e?t.call(this):this.setTimeout(t,1)):(this.readyQueue_=this.readyQueue_||[],void this.readyQueue_.push(t))},l.prototype.triggerReady=function(){this.isReady_=!0,this.setTimeout(function(){var t=this.readyQueue_;this.readyQueue_=[],t&&0<t.length&&t.forEach(function(t){t.call(this)},this),this.trigger("ready")},1)},l.prototype.$=function(t,e){return nt(t,e||this.contentEl())},l.prototype.$$=function(t,e){return st(t,e||this.contentEl())},l.prototype.hasClass=function(t){return B(this.el_,t)},l.prototype.addClass=function(t){j(this.el_,t)},l.prototype.removeClass=function(t){F(this.el_,t)},l.prototype.toggleClass=function(t,e){H(this.el_,t,e)},l.prototype.show=function(){this.removeClass("vjs-hidden")},l.prototype.hide=function(){this.addClass("vjs-hidden")},l.prototype.lockShowing=function(){this.addClass("vjs-lock-showing")},l.prototype.unlockShowing=function(){this.removeClass("vjs-lock-showing")},l.prototype.getAttribute=function(t){return W(this.el_,t)},l.prototype.setAttribute=function(t,e){z(this.el_,t,e)},l.prototype.removeAttribute=function(t){G(this.el_,t)},l.prototype.width=function(t,e){return this.dimension("width",t,e)},l.prototype.height=function(t,e){return this.dimension("height",t,e)},l.prototype.dimensions=function(t,e){this.width(t,!0),this.height(e)},l.prototype.dimension=function(t,e,i){if(void 0!==e)return null!==e&&e==e||(e=0),-1!==(""+e).indexOf("%")||-1!==(""+e).indexOf("px")?this.el_.style[t]=e:this.el_.style[t]="auto"===e?"":e+"px",void(i||this.trigger("componentresize"));if(!this.el_)return 0;var r=this.el_.style[t],n=r.indexOf("px");return-1!==n?parseInt(r.slice(0,n),10):parseInt(this.el_["offset"+zt(t)],10)},l.prototype.currentDimension=function(t){var e=0;if("width"!==t&&"height"!==t)throw new Error("currentDimension only accepts width or height value");if("function"==typeof g.getComputedStyle){var i=g.getComputedStyle(this.el_);e=i.getPropertyValue(t)||i[t]}if(0===(e=parseFloat(e))){var r="offset"+zt(t);e=this.el_[r]}return e},l.prototype.currentDimensions=function(){return{width:this.currentDimension("width"),height:this.currentDimension("height")}},l.prototype.currentWidth=function(){return this.currentDimension("width")},l.prototype.currentHeight=function(){return this.currentDimension("height")},l.prototype.focus=function(){this.el_.focus()},l.prototype.blur=function(){this.el_.blur()},l.prototype.emitTapEvents=function(){var e=0,r=null,n=void 0;this.on("touchstart",function(t){1===t.touches.length&&(r={pageX:t.touches[0].pageX,pageY:t.touches[0].pageY},e=(new Date).getTime(),n=!0)}),this.on("touchmove",function(t){if(1<t.touches.length)n=!1;else if(r){var e=t.touches[0].pageX-r.pageX,i=t.touches[0].pageY-r.pageY;10<Math.sqrt(e*e+i*i)&&(n=!1)}});var t=function(){n=!1};this.on("touchleave",t),this.on("touchcancel",t),this.on("touchend",function(t){!(r=null)===n&&((new Date).getTime()-e<200&&(t.preventDefault(),this.trigger("tap")))})},l.prototype.enableTouchActivity=function(){if(this.player()&&this.player().reportUserActivity){var e=Ot(this.player(),this.player().reportUserActivity),i=void 0;this.on("touchstart",function(){e(),this.clearInterval(i),i=this.setInterval(e,250)});var t=function(t){e(),this.clearInterval(i)};this.on("touchmove",e),this.on("touchend",t),this.on("touchcancel",t)}},l.prototype.setTimeout=function(t,e){var i=this;t=Ot(this,t);var r=g.setTimeout(t,e),n=function(){return i.clearTimeout(r)};return n.guid="vjs-timeout-"+r,this.on("dispose",n),r},l.prototype.clearTimeout=function(t){g.clearTimeout(t);var e=function(){};return e.guid="vjs-timeout-"+t,this.off("dispose",e),t},l.prototype.setInterval=function(t,e){var i=this;t=Ot(this,t);var r=g.setInterval(t,e),n=function(){return i.clearInterval(r)};return n.guid="vjs-interval-"+r,this.on("dispose",n),r},l.prototype.clearInterval=function(t){g.clearInterval(t);var e=function(){};return e.guid="vjs-interval-"+t,this.off("dispose",e),t},l.prototype.requestAnimationFrame=function(t){var e=this;if(this.supportsRaf_){t=Ot(this,t);var i=g.requestAnimationFrame(t),r=function(){return e.cancelAnimationFrame(i)};return r.guid="vjs-raf-"+i,this.on("dispose",r),i}return this.setTimeout(t,1e3/60)},l.prototype.cancelAnimationFrame=function(t){if(this.supportsRaf_){g.cancelAnimationFrame(t);var e=function(){};return e.guid="vjs-raf-"+t,this.off("dispose",e),t}return this.clearTimeout(t)},l.registerComponent=function(t,e){if("string"!=typeof t||!t)throw new Error('Illegal component name, "'+t+'"; must be a non-empty string.');var i=l.getComponent("Tech"),r=i&&i.isTech(e),n=l===e||l.prototype.isPrototypeOf(e.prototype);if(r||!n){var s=void 0;throw s=r?"techs must be registered using Tech.registerTech()":"must be a Component subclass",new Error('Illegal component, "'+t+'"; '+s+".")}t=zt(t),l.components_||(l.components_={});var a=l.getComponent("Player");if("Player"===t&&a&&a.players){var o=a.players,u=Object.keys(o);if(o&&0<u.length&&u.map(function(t){return o[t]}).every(Boolean))throw new Error("Can not register Player component after player has been created.")}return l.components_[t]=e},l.getComponent=function(t){if(t)return t=zt(t),l.components_&&l.components_[t]?l.components_[t]:void 0},l}();Xt.prototype.supportsRaf_="function"==typeof g.requestAnimationFrame&&"function"==typeof g.cancelAnimationFrame,Xt.registerComponent("Component",Xt);var Yt,$t,Kt,Qt,Jt=g.navigator&&g.navigator.userAgent||"",Zt=/AppleWebKit\/([\d.]+)/i.exec(Jt),te=Zt?parseFloat(Zt.pop()):null,ee=/iPad/i.test(Jt),ie=/iPhone/i.test(Jt)&&!ee,re=/iPod/i.test(Jt),ne=ie||ee||re,se=(Yt=Jt.match(/OS (\d+)_/i))&&Yt[1]?Yt[1]:null,ae=/Android/i.test(Jt),oe=function(){var t=Jt.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);if(!t)return null;var e=t[1]&&parseFloat(t[1]),i=t[2]&&parseFloat(t[2]);return e&&i?parseFloat(t[1]+"."+t[2]):e||null}(),ue=ae&&oe<5&&te<537,le=/Firefox/i.test(Jt),ce=/Edge/i.test(Jt),he=!ce&&/Chrome/i.test(Jt),de=($t=Jt.match(/Chrome\/(\d+)/))&&$t[1]?parseFloat($t[1]):null,pe=(Kt=/MSIE\s(\d+)\.\d/.exec(Jt),!(Qt=Kt&&parseFloat(Kt[1]))&&/Trident\/7.0/i.test(Jt)&&/rv:11.0/.test(Jt)&&(Qt=11),Qt),fe=/Safari/i.test(Jt)&&!he&&!ae&&!ce,me=fe||ne,ge=x()&&("ontouchstart"in g||g.DocumentTouch&&g.document instanceof g.DocumentTouch),ye=Object.freeze({IS_IPAD:ee,IS_IPHONE:ie,IS_IPOD:re,IS_IOS:ne,IOS_VERSION:se,IS_ANDROID:ae,ANDROID_VERSION:oe,IS_NATIVE_ANDROID:ue,IS_FIREFOX:le,IS_EDGE:ce,IS_CHROME:he,CHROME_VERSION:de,IE_VERSION:pe,IS_SAFARI:fe,IS_ANY_SAFARI:me,TOUCH_ENABLED:ge});function ve(t,e,i,r){return function(t,e,i){if("number"!=typeof e||e<0||i<e)throw new Error("Failed to execute '"+t+"' on 'TimeRanges': The index provided ("+e+") is non-numeric or out of bounds (0-"+i+").")}(t,r,i.length-1),i[r][e]}function _e(t){return void 0===t||0===t.length?{length:0,start:function(){throw new Error("This TimeRanges object is empty")},end:function(){throw new Error("This TimeRanges object is empty")}}:{length:t.length,start:ve.bind(null,"start",0,t),end:ve.bind(null,"end",1,t)}}function be(t,e){return Array.isArray(t)?_e(t):void 0===t||void 0===e?_e():_e([[t,e]])}function Te(t,e){var i=0,r=void 0,n=void 0;if(!e)return 0;t&&t.length||(t=be(0,0));for(var s=0;s<t.length;s++)r=t.start(s),e<(n=t.end(s))&&(n=e),i+=n-r;return i/e}for(var Se={},ke=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],Ce=ke[0],Ee=void 0,we=0;we<ke.length;we++)if(ke[we][1]in p){Ee=ke[we];break}if(Ee)for(var Ae=0;Ae<Ee.length;Ae++)Se[Ce[Ae]]=Ee[Ae];function Le(t){if(t instanceof Le)return t;"number"==typeof t?this.code=t:"string"==typeof t?this.message=t:E(t)&&("number"==typeof t.code&&(this.code=t.code),C(this,t)),this.message||(this.message=Le.defaultMessages[this.code]||"")}Le.prototype.code=0,Le.prototype.message="",Le.prototype.status=null,Le.errorTypes=["MEDIA_ERR_CUSTOM","MEDIA_ERR_ABORTED","MEDIA_ERR_NETWORK","MEDIA_ERR_DECODE","MEDIA_ERR_SRC_NOT_SUPPORTED","MEDIA_ERR_ENCRYPTED"],Le.defaultMessages={1:"You aborted the media playback",2:"A network error caused the media download to fail part-way.",3:"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.",4:"The media could not be loaded, either because the server or network failed or because the format is not supported.",5:"The media is encrypted and we do not have the keys to decrypt it."};for(var Pe=0;Pe<Le.errorTypes.length;Pe++)Le[Le.errorTypes[Pe]]=Pe,Le.prototype[Le.errorTypes[Pe]]=Pe;var Oe=function(t,e){var i,r=null;try{i=JSON.parse(t,e)}catch(t){r=t}return[r,i]};function xe(t){return null!=t&&"function"==typeof t.then}function Ie(t){xe(t)&&t.then(null,function(t){})}var De=function(r){return["kind","label","language","id","inBandMetadataTrackDispatchType","mode","src"].reduce(function(t,e,i){return r[e]&&(t[e]=r[e]),t},{cues:r.cues&&Array.prototype.map.call(r.cues,function(t){return{startTime:t.startTime,endTime:t.endTime,text:t.text,id:t.id}})})},Re=function(t){var e=t.$$("track"),i=Array.prototype.map.call(e,function(t){return t.track});return Array.prototype.map.call(e,function(t){var e=De(t.track);return t.src&&(e.src=t.src),e}).concat(Array.prototype.filter.call(t.textTracks(),function(t){return-1===i.indexOf(t)}).map(De))},Me=function(t,i){return t.forEach(function(t){var e=i.addRemoteTextTrack(t).track;!t.src&&t.cues&&t.cues.forEach(function(t){return e.addCue(t)})}),i.textTracks()},Ue="vjs-modal-dialog",Ne=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.opened_=i.hasBeenOpened_=i.hasBeenFilled_=!1,i.closeable(!i.options_.uncloseable),i.content(i.options_.content),i.contentEl_=M("div",{className:Ue+"-content"},{role:"document"}),i.descEl_=M("p",{className:Ue+"-description vjs-control-text",id:i.el().getAttribute("aria-describedby")}),U(i.descEl_,i.description()),i.el_.appendChild(i.descEl_),i.el_.appendChild(i.contentEl_),i}return _(n,r),n.prototype.createEl=function(){return r.prototype.createEl.call(this,"div",{className:this.buildCSSClass(),tabIndex:-1},{"aria-describedby":this.id()+"_description","aria-hidden":"true","aria-label":this.label(),role:"dialog"})},n.prototype.dispose=function(){this.contentEl_=null,this.descEl_=null,this.previouslyActiveEl_=null,r.prototype.dispose.call(this)},n.prototype.buildCSSClass=function(){return Ue+" vjs-hidden "+r.prototype.buildCSSClass.call(this)},n.prototype.handleKeyPress=function(t){27===t.which&&this.closeable()&&this.close()},n.prototype.label=function(){return this.localize(this.options_.label||"Modal Window")},n.prototype.description=function(){var t=this.options_.description||this.localize("This is a modal window.");return this.closeable()&&(t+=" "+this.localize("This modal can be closed by pressing the Escape key or activating the close button.")),t},n.prototype.open=function(){if(!this.opened_){var t=this.player();this.trigger("beforemodalopen"),this.opened_=!0,(this.options_.fillAlways||!this.hasBeenOpened_&&!this.hasBeenFilled_)&&this.fill(),this.wasPlaying_=!t.paused(),this.options_.pauseOnOpen&&this.wasPlaying_&&t.pause(),this.closeable()&&this.on(this.el_.ownerDocument,"keydown",Ot(this,this.handleKeyPress)),this.hadControls_=t.controls(),t.controls(!1),this.show(),this.conditionalFocus_(),this.el().setAttribute("aria-hidden","false"),this.trigger("modalopen"),this.hasBeenOpened_=!0}},n.prototype.opened=function(t){return"boolean"==typeof t&&this[t?"open":"close"](),this.opened_},n.prototype.close=function(){if(this.opened_){var t=this.player();this.trigger("beforemodalclose"),this.opened_=!1,this.wasPlaying_&&this.options_.pauseOnOpen&&t.play(),this.closeable()&&this.off(this.el_.ownerDocument,"keydown",Ot(this,this.handleKeyPress)),this.hadControls_&&t.controls(!0),this.hide(),this.el().setAttribute("aria-hidden","true"),this.trigger("modalclose"),this.conditionalBlur_(),this.options_.temporary&&this.dispose()}},n.prototype.closeable=function(t){if("boolean"==typeof t){var e=this.closeable_=!!t,i=this.getChild("closeButton");if(e&&!i){var r=this.contentEl_;this.contentEl_=this.el_,i=this.addChild("closeButton",{controlText:"Close Modal Dialog"}),this.contentEl_=r,this.on(i,"close",this.close)}!e&&i&&(this.off(i,"close",this.close),this.removeChild(i),i.dispose())}return this.closeable_},n.prototype.fill=function(){this.fillWith(this.content())},n.prototype.fillWith=function(t){var e=this.contentEl(),i=e.parentNode,r=e.nextSibling;this.trigger("beforemodalfill"),this.hasBeenFilled_=!0,i.removeChild(e),this.empty(),it(e,t),this.trigger("modalfill"),r?i.insertBefore(e,r):i.appendChild(e);var n=this.getChild("closeButton");n&&i.appendChild(n.el_)},n.prototype.empty=function(){this.trigger("beforemodalempty"),Z(this.contentEl()),this.trigger("modalempty")},n.prototype.content=function(t){return"undefined"!=typeof t&&(this.content_=t),this.content_},n.prototype.conditionalFocus_=function(){var t=p.activeElement,e=this.player_.el_;this.previouslyActiveEl_=null,(e.contains(t)||e===t)&&(this.previouslyActiveEl_=t,this.focus(),this.on(p,"keydown",this.handleKeyDown))},n.prototype.conditionalBlur_=function(){this.previouslyActiveEl_&&(this.previouslyActiveEl_.focus(),this.previouslyActiveEl_=null),this.off(p,"keydown",this.handleKeyDown)},n.prototype.handleKeyDown=function(t){if(9===t.which){for(var e=this.focusableEls_(),i=this.el_.querySelector(":focus"),r=void 0,n=0;n<e.length;n++)if(i===e[n]){r=n;break}p.activeElement===this.el_&&(r=0),t.shiftKey&&0===r?(e[e.length-1].focus(),t.preventDefault()):t.shiftKey||r!==e.length-1||(e[0].focus(),t.preventDefault())}},n.prototype.focusableEls_=function(){var t=this.el_.querySelectorAll("*");return Array.prototype.filter.call(t,function(t){return(t instanceof g.HTMLAnchorElement||t instanceof g.HTMLAreaElement)&&t.hasAttribute("href")||(t instanceof g.HTMLInputElement||t instanceof g.HTMLSelectElement||t instanceof g.HTMLTextAreaElement||t instanceof g.HTMLButtonElement)&&!t.hasAttribute("disabled")||t instanceof g.HTMLIFrameElement||t instanceof g.HTMLObjectElement||t instanceof g.HTMLEmbedElement||t.hasAttribute("tabindex")&&-1!==t.getAttribute("tabindex")||t.hasAttribute("contenteditable")})},n}(Xt);Ne.prototype.options_={pauseOnOpen:!0,temporary:!0},Xt.registerComponent("ModalDialog",Ne);var Be=function(r){function n(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[];y(this,n);var e=b(this,r.call(this));e.tracks_=[],Object.defineProperty(e,"length",{get:function(){return this.tracks_.length}});for(var i=0;i<t.length;i++)e.addTrack(t[i]);return e}return _(n,r),n.prototype.addTrack=function(t){var e=this.tracks_.length;""+e in this||Object.defineProperty(this,e,{get:function(){return this.tracks_[e]}}),-1===this.tracks_.indexOf(t)&&(this.tracks_.push(t),this.trigger({track:t,type:"addtrack"}))},n.prototype.removeTrack=function(t){for(var e=void 0,i=0,r=this.length;i<r;i++)if(this[i]===t){(e=this[i]).off&&e.off(),this.tracks_.splice(i,1);break}e&&this.trigger({track:e,type:"removetrack"})},n.prototype.getTrackById=function(t){for(var e=null,i=0,r=this.length;i<r;i++){var n=this[i];if(n.id===t){e=n;break}}return e},n}(Dt);for(var je in Be.prototype.allowedEvents_={change:"change",addtrack:"addtrack",removetrack:"removetrack"},Be.prototype.allowedEvents_)Be.prototype["on"+je]=null;var Fe=function(t,e){for(var i=0;i<t.length;i++)Object.keys(t[i]).length&&e.id!==t[i].id&&(t[i].enabled=!1)},He=function(r){function n(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[];y(this,n);for(var e=t.length-1;0<=e;e--)if(t[e].enabled){Fe(t,t[e]);break}var i=b(this,r.call(this,t));return i.changing_=!1,i}return _(n,r),n.prototype.addTrack=function(t){var e=this;t.enabled&&Fe(this,t),r.prototype.addTrack.call(this,t),t.addEventListener&&t.addEventListener("enabledchange",function(){e.changing_||(e.changing_=!0,Fe(e,t),e.changing_=!1,e.trigger("change"))})},n}(Be),Ve=function(t,e){for(var i=0;i<t.length;i++)Object.keys(t[i]).length&&e.id!==t[i].id&&(t[i].selected=!1)},qe=function(r){function n(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[];y(this,n);for(var e=t.length-1;0<=e;e--)if(t[e].selected){Ve(t,t[e]);break}var i=b(this,r.call(this,t));return i.changing_=!1,Object.defineProperty(i,"selectedIndex",{get:function(){for(var t=0;t<this.length;t++)if(this[t].selected)return t;return-1},set:function(){}}),i}return _(n,r),n.prototype.addTrack=function(t){var e=this;t.selected&&Ve(this,t),r.prototype.addTrack.call(this,t),t.addEventListener&&t.addEventListener("selectedchange",function(){e.changing_||(e.changing_=!0,Ve(e,t),e.changing_=!1,e.trigger("change"))})},n}(Be),We=function(e){function t(){return y(this,t),b(this,e.apply(this,arguments))}return _(t,e),t.prototype.addTrack=function(t){e.prototype.addTrack.call(this,t),t.addEventListener("modechange",Ot(this,function(){this.trigger("change")}));-1===["metadata","chapters"].indexOf(t.kind)&&t.addEventListener("modechange",Ot(this,function(){this.trigger("selectedlanguagechange")}))},t}(Be),ze=function(){function r(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[];y(this,r),this.trackElements_=[],Object.defineProperty(this,"length",{get:function(){return this.trackElements_.length}});for(var e=0,i=t.length;e<i;e++)this.addTrackElement_(t[e])}return r.prototype.addTrackElement_=function(t){var e=this.trackElements_.length;""+e in this||Object.defineProperty(this,e,{get:function(){return this.trackElements_[e]}}),-1===this.trackElements_.indexOf(t)&&this.trackElements_.push(t)},r.prototype.getTrackElementByTrack_=function(t){for(var e=void 0,i=0,r=this.trackElements_.length;i<r;i++)if(t===this.trackElements_[i].track){e=this.trackElements_[i];break}return e},r.prototype.removeTrackElement_=function(t){for(var e=0,i=this.trackElements_.length;e<i;e++)if(t===this.trackElements_[e]){this.trackElements_.splice(e,1);break}},r}(),Ge=function(){function e(t){y(this,e),e.prototype.setCues_.call(this,t),Object.defineProperty(this,"length",{get:function(){return this.length_}})}return e.prototype.setCues_=function(t){var e=this.length||0,i=0,r=t.length;this.cues_=t,this.length_=t.length;var n=function(t){""+t in this||Object.defineProperty(this,""+t,{get:function(){return this.cues_[t]}})};if(e<r)for(i=e;i<r;i++)n.call(this,i)},e.prototype.getCueById=function(t){for(var e=null,i=0,r=this.length;i<r;i++){var n=this[i];if(n.id===t){e=n;break}}return e},e}(),Xe={alternative:"alternative",captions:"captions",main:"main",sign:"sign",subtitles:"subtitles",commentary:"commentary"},Ye={alternative:"alternative",descriptions:"descriptions",main:"main","main-desc":"main-desc",translation:"translation",commentary:"commentary"},$e={subtitles:"subtitles",captions:"captions",descriptions:"descriptions",chapters:"chapters",metadata:"metadata"},Ke={disabled:"disabled",hidden:"hidden",showing:"showing"},Qe=function(s){function a(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};y(this,a);var e=b(this,s.call(this)),i={id:t.id||"vjs_track_"+ut(),kind:t.kind||"",label:t.label||"",language:t.language||""},r=function(t){Object.defineProperty(e,t,{get:function(){return i[t]},set:function(){}})};for(var n in i)r(n);return e}return _(a,s),a}(Dt),Je=function(t){var e=["protocol","hostname","port","pathname","search","hash","host"],i=p.createElement("a");i.href=t;var r=""===i.host&&"file:"!==i.protocol,n=void 0;r&&((n=p.createElement("div")).innerHTML='<a href="'+t+'"></a>',i=n.firstChild,n.setAttribute("style","display:none; position:absolute;"),p.body.appendChild(n));for(var s={},a=0;a<e.length;a++)s[e[a]]=i[e[a]];return"http:"===s.protocol&&(s.host=s.host.replace(/:80$/,"")),"https:"===s.protocol&&(s.host=s.host.replace(/:443$/,"")),s.protocol||(s.protocol=g.location.protocol),r&&p.body.removeChild(n),s},Ze=function(t){if(!t.match(/^https?:\/\//)){var e=p.createElement("div");e.innerHTML='<a href="'+t+'">x</a>',t=e.firstChild.href}return t},ti=function(t){if("string"==typeof t){var e=/^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i.exec(t);if(e)return e.pop().toLowerCase()}return""},ei=function(t){var e=g.location,i=Je(t);return(":"===i.protocol?e.protocol:i.protocol)+i.host!==e.protocol+e.host},ii=Object.freeze({parseUrl:Je,getAbsoluteURL:Ze,getFileExtension:ti,isCrossOrigin:ei}),ri=function(t){var e=ni.call(t);return"[object Function]"===e||"function"==typeof t&&"[object RegExp]"!==e||"undefined"!=typeof window&&(t===window.setTimeout||t===window.alert||t===window.confirm||t===window.prompt)},ni=Object.prototype.toString;var si=Object.freeze({default:ri,__moduleExports:ri}),ai=e(function(t,e){(e=t.exports=function(t){return t.replace(/^\s*|\s*$/g,"")}).left=function(t){return t.replace(/^\s*/,"")},e.right=function(t){return t.replace(/\s*$/,"")}}),oi=ai.left,ui=ai.right,li=Object.freeze({default:ai,__moduleExports:ai,left:oi,right:ui}),ci=si&&ri||si,hi=function(t,e,i){if(!ci(e))throw new TypeError("iterator must be a function");arguments.length<3&&(i=this);"[object Array]"===di.call(t)?function(t,e,i){for(var r=0,n=t.length;r<n;r++)pi.call(t,r)&&e.call(i,t[r],r,t)}(t,e,i):"string"==typeof t?function(t,e,i){for(var r=0,n=t.length;r<n;r++)e.call(i,t.charAt(r),r,t)}(t,e,i):function(t,e,i){for(var r in t)pi.call(t,r)&&e.call(i,t[r],r,t)}(t,e,i)},di=Object.prototype.toString,pi=Object.prototype.hasOwnProperty;var fi=Object.freeze({default:hi,__moduleExports:hi}),mi=li&&ai||li,gi=fi&&hi||fi,yi=function(t){if(!t)return{};var s={};return gi(mi(t).split("\n"),function(t){var e,i=t.indexOf(":"),r=mi(t.slice(0,i)).toLowerCase(),n=mi(t.slice(i+1));"undefined"==typeof s[r]?s[r]=n:(e=s[r],"[object Array]"===Object.prototype.toString.call(e)?s[r].push(n):s[r]=[s[r],n])}),s},vi=Object.freeze({default:yi,__moduleExports:yi}),_i=function(){for(var t={},e=0;e<arguments.length;e++){var i=arguments[e];for(var r in i)bi.call(i,r)&&(t[r]=i[r])}return t},bi=Object.prototype.hasOwnProperty;var Ti=Object.freeze({default:_i,__moduleExports:_i}),Si=vi&&yi||vi,ki=Ti&&_i||Ti,Ci=wi;function Ei(t,e,i){var r=t;return ci(e)?(i=e,"string"==typeof t&&(r={uri:t})):r=ki(e,{uri:t}),r.callback=i,r}function wi(t,e,i){return Ai(e=Ei(t,e,i))}function Ai(r){if("undefined"==typeof r.callback)throw new Error("callback argument missing");var n=!1,s=function(t,e,i){n||(n=!0,r.callback(t,e,i))};function e(t){return clearTimeout(u),t instanceof Error||(t=new Error(""+(t||"Unknown XMLHttpRequest Error"))),t.statusCode=0,s(t,m)}function t(){if(!a){var t;clearTimeout(u),t=r.useXDR&&void 0===o.status?200:1223===o.status?204:o.status;var e=m,i=null;return 0!==t?(e={body:function(){var t=void 0;if(t=o.response?o.response:o.responseText||function(t){if("document"===t.responseType)return t.responseXML;var e=t.responseXML&&"parsererror"===t.responseXML.documentElement.nodeName;return""!==t.responseType||e?null:t.responseXML}(o),f)try{t=JSON.parse(t)}catch(t){}return t}(),statusCode:t,method:c,headers:{},url:l,rawRequest:o},o.getAllResponseHeaders&&(e.headers=Si(o.getAllResponseHeaders()))):i=new Error("Internal XMLHttpRequest Error"),s(i,e,e.body)}}var i,a,o=r.xhr||null;o||(o=r.cors||r.useXDR?new wi.XDomainRequest:new wi.XMLHttpRequest);var u,l=o.url=r.uri||r.url,c=o.method=r.method||"GET",h=r.body||r.data,d=o.headers=r.headers||{},p=!!r.sync,f=!1,m={body:void 0,headers:{},statusCode:0,method:c,url:l,rawRequest:o};if("json"in r&&!1!==r.json&&(f=!0,d.accept||d.Accept||(d.Accept="application/json"),"GET"!==c&&"HEAD"!==c&&(d["content-type"]||d["Content-Type"]||(d["Content-Type"]="application/json"),h=JSON.stringify(!0===r.json?h:r.json))),o.onreadystatechange=function(){4===o.readyState&&setTimeout(t,0)},o.onload=t,o.onerror=e,o.onprogress=function(){},o.onabort=function(){a=!0},o.ontimeout=e,o.open(c,l,!p,r.username,r.password),p||(o.withCredentials=!!r.withCredentials),!p&&0<r.timeout&&(u=setTimeout(function(){if(!a){a=!0,o.abort("timeout");var t=new Error("XMLHttpRequest timeout");t.code="ETIMEDOUT",e(t)}},r.timeout)),o.setRequestHeader)for(i in d)d.hasOwnProperty(i)&&o.setRequestHeader(i,d[i]);else if(r.headers&&!function(t){for(var e in t)if(t.hasOwnProperty(e))return!1;return!0}(r.headers))throw new Error("Headers cannot be set on an XDomainRequest object");return"responseType"in r&&(o.responseType=r.responseType),"beforeSend"in r&&"function"==typeof r.beforeSend&&r.beforeSend(o),o.send(h||null),o}wi.XMLHttpRequest=g.XMLHttpRequest||function(){},wi.XDomainRequest="withCredentials"in new wi.XMLHttpRequest?wi.XMLHttpRequest:g.XDomainRequest,function(t,e){for(var i=0;i<t.length;i++)e(t[i])}(["get","put","post","patch","head","delete"],function(r){wi["delete"===r?"del":r]=function(t,e,i){return(e=Ei(t,e,i)).method=r.toUpperCase(),Ai(e)}});var Li=function(t,e){var i=new g.WebVTT.Parser(g,g.vttjs,g.WebVTT.StringDecoder()),r=[];i.oncue=function(t){e.addCue(t)},i.onparsingerror=function(t){r.push(t)},i.onflush=function(){e.trigger({type:"loadeddata",target:e})},i.parse(t),0<r.length&&(g.console&&g.console.groupCollapsed&&g.console.groupCollapsed("Text Track parsing errors for "+e.src),r.forEach(function(t){return f.error(t)}),g.console&&g.console.groupEnd&&g.console.groupEnd()),i.flush()},Pi=function(t,n){var e={uri:t},i=ei(t);i&&(e.cors=i),Ci(e,Ot(this,function(t,e,i){if(t)return f.error(t,e);if(n.loaded_=!0,"function"!=typeof g.WebVTT){if(n.tech_){var r=function(){return Li(i,n)};n.tech_.on("vttjsloaded",r),n.tech_.on("vttjserror",function(){f.error("vttjs failed to load, stopping trying to process "+n.src),n.tech_.off("vttjsloaded",r)})}}else Li(i,n)}))},Oi=function(l){function c(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};if(y(this,c),!t.tech)throw new Error("A tech was not provided.");var e=Gt(t,{kind:$e[t.kind]||"subtitles",language:t.language||t.srclang||""}),i=Ke[e.mode]||"disabled",r=e.default;"metadata"!==e.kind&&"chapters"!==e.kind||(i="hidden");var n=b(this,l.call(this,e));n.tech_=e.tech,n.cues_=[],n.activeCues_=[];var s=new Ge(n.cues_),a=new Ge(n.activeCues_),o=!1,u=Ot(n,function(){this.activeCues,o&&(this.trigger("cuechange"),o=!1)});return"disabled"!==i&&n.tech_.ready(function(){n.tech_.on("timeupdate",u)},!0),Object.defineProperties(n,{default:{get:function(){return r},set:function(){}},mode:{get:function(){return i},set:function(t){var e=this;Ke[t]&&("showing"===(i=t)&&this.tech_.ready(function(){e.tech_.on("timeupdate",u)},!0),this.trigger("modechange"))}},cues:{get:function(){return this.loaded_?s:null},set:function(){}},activeCues:{get:function(){if(!this.loaded_)return null;if(0===this.cues.length)return a;for(var t=this.tech_.currentTime(),e=[],i=0,r=this.cues.length;i<r;i++){var n=this.cues[i];n.startTime<=t&&n.endTime>=t?e.push(n):n.startTime===n.endTime&&n.startTime<=t&&n.startTime+.5>=t&&e.push(n)}if(o=!1,e.length!==this.activeCues_.length)o=!0;else for(var s=0;s<e.length;s++)-1===this.activeCues_.indexOf(e[s])&&(o=!0);return this.activeCues_=e,a.setCues_(this.activeCues_),a},set:function(){}}}),e.src?(n.src=e.src,Pi(e.src,n)):n.loaded_=!0,n}return _(c,l),c.prototype.addCue=function(t){var e=t;if(g.vttjs&&!(t instanceof g.vttjs.VTTCue)){for(var i in e=new g.vttjs.VTTCue(t.startTime,t.endTime,t.text),t)i in e||(e[i]=t[i]);e.id=t.id,e.originalCue_=t}for(var r=this.tech_.textTracks(),n=0;n<r.length;n++)r[n]!==this&&r[n].removeCue(e);this.cues_.push(e),this.cues.setCues_(this.cues_)},c.prototype.removeCue=function(t){for(var e=this.cues_.length;e--;){var i=this.cues_[e];if(i===t||i.originalCue_&&i.originalCue_===t){this.cues_.splice(e,1),this.cues.setCues_(this.cues_);break}}},c}(Qe);Oi.prototype.allowedEvents_={cuechange:"cuechange"};var xi=function(n){function s(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};y(this,s);var e=Gt(t,{kind:Ye[t.kind]||""}),i=b(this,n.call(this,e)),r=!1;return Object.defineProperty(i,"enabled",{get:function(){return r},set:function(t){"boolean"==typeof t&&t!==r&&(r=t,this.trigger("enabledchange"))}}),e.enabled&&(i.enabled=e.enabled),i.loaded_=!0,i}return _(s,n),s}(Qe),Ii=function(n){function s(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};y(this,s);var e=Gt(t,{kind:Xe[t.kind]||""}),i=b(this,n.call(this,e)),r=!1;return Object.defineProperty(i,"selected",{get:function(){return r},set:function(t){"boolean"==typeof t&&t!==r&&(r=t,this.trigger("selectedchange"))}}),e.selected&&(i.selected=e.selected),i}return _(s,n),s}(Qe),Di=0,Ri=2,Mi=function(n){function s(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};y(this,s);var e=b(this,n.call(this)),i=void 0,r=new Oi(t);return e.kind=r.kind,e.src=r.src,e.srclang=r.language,e.label=r.label,e.default=r.default,Object.defineProperties(e,{readyState:{get:function(){return i}},track:{get:function(){return r}}}),i=Di,r.addEventListener("loadeddata",function(){i=Ri,e.trigger({type:"load",target:e})}),e}return _(s,n),s}(Dt);Mi.prototype.allowedEvents_={load:"load"},Mi.NONE=Di,Mi.LOADING=1,Mi.LOADED=Ri,Mi.ERROR=3;var Ui={audio:{ListClass:He,TrackClass:xi,capitalName:"Audio"},video:{ListClass:qe,TrackClass:Ii,capitalName:"Video"},text:{ListClass:We,TrackClass:Oi,capitalName:"Text"}};Object.keys(Ui).forEach(function(t){Ui[t].getterName=t+"Tracks",Ui[t].privateName=t+"Tracks_"});var Ni={remoteText:{ListClass:We,TrackClass:Oi,capitalName:"RemoteText",getterName:"remoteTextTracks",privateName:"remoteTextTracks_"},remoteTextEl:{ListClass:ze,TrackClass:Mi,capitalName:"RemoteTextTrackEls",getterName:"remoteTextTrackEls",privateName:"remoteTextTrackEls_"}},Bi=Gt(Ui,Ni);Ni.names=Object.keys(Ni),Ui.names=Object.keys(Ui),Bi.names=[].concat(Ni.names).concat(Ui.names);var ji=Object.create||function(){function e(){}return function(t){if(1!==arguments.length)throw new Error("Object.create shim only accepts one parameter.");return e.prototype=t,new e}}();function Fi(t,e){this.name="ParsingError",this.code=t.code,this.message=e||t.message}function Hi(t){function e(t,e,i,r){return 3600*(0|t)+60*(0|e)+(0|i)+(0|r)/1e3}var i=t.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/);return i?i[3]?e(i[1],i[2],i[3].replace(":",""),i[4]):59<i[1]?e(i[1],i[2],0,i[4]):e(0,i[1],i[2],i[4]):null}function Vi(){this.values=ji(null)}function qi(t,e,i,r){var n=r?t.split(r):[t];for(var s in n)if("string"==typeof n[s]){var a=n[s].split(i);if(2===a.length)e(a[0],a[1])}}function Wi(e,t,s){var i,r,a,n=e;function o(){var t=Hi(e);if(null===t)throw new Fi(Fi.Errors.BadTimeStamp,"Malformed timestamp: "+n);return e=e.replace(/^[^\sa-zA-Z-]+/,""),t}function u(){e=e.replace(/^\s+/,"")}if(u(),t.startTime=o(),u(),"--\x3e"!==e.substr(0,3))throw new Fi(Fi.Errors.BadTimeStamp,"Malformed time stamp (time stamps must be separated by '--\x3e'): "+n);e=e.substr(3),u(),t.endTime=o(),u(),i=e,r=t,a=new Vi,qi(i,function(t,e){switch(t){case"region":for(var i=s.length-1;0<=i;i--)if(s[i].id===e){a.set(t,s[i].region);break}break;case"vertical":a.alt(t,e,["rl","lr"]);break;case"line":var r=e.split(","),n=r[0];a.integer(t,n),a.percent(t,n)&&a.set("snapToLines",!1),a.alt(t,n,["auto"]),2===r.length&&a.alt("lineAlign",r[1],["start","middle","end"]);break;case"position":r=e.split(","),a.percent(t,r[0]),2===r.length&&a.alt("positionAlign",r[1],["start","middle","end"]);break;case"size":a.percent(t,e);break;case"align":a.alt(t,e,["start","middle","end","left","right"])}},/:/,/\s/),r.region=a.get("region",null),r.vertical=a.get("vertical",""),r.line=a.get("line","auto"),r.lineAlign=a.get("lineAlign","start"),r.snapToLines=a.get("snapToLines",!0),r.size=a.get("size",100),r.align=a.get("align","middle"),r.position=a.get("position",{start:0,left:0,middle:50,end:100,right:100},r.align),r.positionAlign=a.get("positionAlign",{start:"start",left:"start",middle:"middle",end:"end",right:"end"},r.align)}((Fi.prototype=ji(Error.prototype)).constructor=Fi).Errors={BadSignature:{code:0,message:"Malformed WebVTT signature."},BadTimeStamp:{code:1,message:"Malformed time stamp."}},Vi.prototype={set:function(t,e){this.get(t)||""===e||(this.values[t]=e)},get:function(t,e,i){return i?this.has(t)?this.values[t]:e[i]:this.has(t)?this.values[t]:e},has:function(t){return t in this.values},alt:function(t,e,i){for(var r=0;r<i.length;++r)if(e===i[r]){this.set(t,e);break}},integer:function(t,e){/^-?\d+$/.test(e)&&this.set(t,parseInt(e,10))},percent:function(t,e){return!!(e.match(/^([\d]{1,3})(\.[\d]*)?%$/)&&0<=(e=parseFloat(e))&&e<=100)&&(this.set(t,e),!0)}};var zi={"&":"&","<":"<",">":">","‎":"‎","‏":"â€"," ":" "},Gi={c:"span",i:"i",b:"b",u:"u",ruby:"ruby",rt:"rt",v:"span",lang:"span"},Xi={v:"title",lang:"lang"},Yi={rt:"ruby"};function $i(s,i){function t(){if(!i)return null;var t,e=i.match(/^([^<]*)(<[^>]*>?)?/);return t=e[1]?e[1]:e[2],i=i.substr(t.length),t}function e(t){return zi[t]}function r(t){for(;f=t.match(/&(amp|lt|gt|lrm|rlm|nbsp);/);)t=t.replace(f[0],e);return t}function n(t,e){var i=Gi[t];if(!i)return null;var r=s.document.createElement(i);r.localName=i;var n=Xi[t];return n&&e&&(r[n]=e.trim()),r}for(var a,o,u,l=s.document.createElement("div"),c=l,h=[];null!==(a=t());)if("<"!==a[0])c.appendChild(s.document.createTextNode(r(a)));else{if("/"===a[1]){h.length&&h[h.length-1]===a.substr(2).replace(">","")&&(h.pop(),c=c.parentNode);continue}var d,p=Hi(a.substr(1,a.length-2));if(p){d=s.document.createProcessingInstruction("timestamp",p),c.appendChild(d);continue}var f=a.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/);if(!f)continue;if(!(d=n(f[1],f[3])))continue;if(o=c,Yi[(u=d).localName]&&Yi[u.localName]!==o.localName)continue;f[2]&&(d.className=f[2].substr(1).replace("."," ")),h.push(f[1]),c.appendChild(d),c=d}return l}var Ki=[[1470,1470],[1472,1472],[1475,1475],[1478,1478],[1488,1514],[1520,1524],[1544,1544],[1547,1547],[1549,1549],[1563,1563],[1566,1610],[1645,1647],[1649,1749],[1765,1766],[1774,1775],[1786,1805],[1807,1808],[1810,1839],[1869,1957],[1969,1969],[1984,2026],[2036,2037],[2042,2042],[2048,2069],[2074,2074],[2084,2084],[2088,2088],[2096,2110],[2112,2136],[2142,2142],[2208,2208],[2210,2220],[8207,8207],[64285,64285],[64287,64296],[64298,64310],[64312,64316],[64318,64318],[64320,64321],[64323,64324],[64326,64449],[64467,64829],[64848,64911],[64914,64967],[65008,65020],[65136,65140],[65142,65276],[67584,67589],[67592,67592],[67594,67637],[67639,67640],[67644,67644],[67647,67669],[67671,67679],[67840,67867],[67872,67897],[67903,67903],[67968,68023],[68030,68031],[68096,68096],[68112,68115],[68117,68119],[68121,68147],[68160,68167],[68176,68184],[68192,68223],[68352,68405],[68416,68437],[68440,68466],[68472,68479],[68608,68680],[126464,126467],[126469,126495],[126497,126498],[126500,126500],[126503,126503],[126505,126514],[126516,126519],[126521,126521],[126523,126523],[126530,126530],[126535,126535],[126537,126537],[126539,126539],[126541,126543],[126545,126546],[126548,126548],[126551,126551],[126553,126553],[126555,126555],[126557,126557],[126559,126559],[126561,126562],[126564,126564],[126567,126570],[126572,126578],[126580,126583],[126585,126588],[126590,126590],[126592,126601],[126603,126619],[126625,126627],[126629,126633],[126635,126651],[1114109,1114109]];function Qi(t){for(var e=0;e<Ki.length;e++){var i=Ki[e];if(t>=i[0]&&t<=i[1])return!0}return!1}function Ji(){}function Zi(t,e,i){Ji.call(this),this.cue=e,this.cueDiv=$i(t,e.text);var r={color:"rgba(255, 255, 255, 1)",backgroundColor:"rgba(0, 0, 0, 0.8)",position:"relative",left:0,right:0,top:0,bottom:0,display:"inline",writingMode:""===e.vertical?"horizontal-tb":"lr"===e.vertical?"vertical-lr":"vertical-rl",unicodeBidi:"plaintext"};this.applyStyles(r,this.cueDiv),this.div=t.document.createElement("div"),r={direction:function(t){var e=[],i="";if(!t||!t.childNodes)return"ltr";function n(t,e){for(var i=e.childNodes.length-1;0<=i;i--)t.push(e.childNodes[i])}function s(t){if(!t||!t.length)return null;var e=t.pop(),i=e.textContent||e.innerText;if(i){var r=i.match(/^.*(\n|\r)/);return r?r[t.length=0]:i}return"ruby"===e.tagName?s(t):e.childNodes?(n(t,e),s(t)):void 0}for(n(e,t);i=s(e);)for(var r=0;r<i.length;r++)if(Qi(i.charCodeAt(r)))return"rtl";return"ltr"}(this.cueDiv),writingMode:""===e.vertical?"horizontal-tb":"lr"===e.vertical?"vertical-lr":"vertical-rl",unicodeBidi:"plaintext",textAlign:"middle"===e.align?"center":e.align,font:i.font,whiteSpace:"pre-line",position:"absolute"},this.applyStyles(r),this.div.appendChild(this.cueDiv);var n=0;switch(e.positionAlign){case"start":n=e.position;break;case"middle":n=e.position-e.size/2;break;case"end":n=e.position-e.size}""===e.vertical?this.applyStyles({left:this.formatStyle(n,"%"),width:this.formatStyle(e.size,"%")}):this.applyStyles({top:this.formatStyle(n,"%"),height:this.formatStyle(e.size,"%")}),this.move=function(t){this.applyStyles({top:this.formatStyle(t.top,"px"),bottom:this.formatStyle(t.bottom,"px"),left:this.formatStyle(t.left,"px"),right:this.formatStyle(t.right,"px"),height:this.formatStyle(t.height,"px"),width:this.formatStyle(t.width,"px")})}}function tr(t){var e,i,r,n;if(t.div){i=t.div.offsetHeight,r=t.div.offsetWidth,n=t.div.offsetTop;var s=(s=t.div.childNodes)&&(s=s[0])&&s.getClientRects&&s.getClientRects();t=t.div.getBoundingClientRect(),e=s?Math.max(s[0]&&s[0].height||0,t.height/s.length):0}this.left=t.left,this.right=t.right,this.top=t.top||n,this.height=t.height||i,this.bottom=t.bottom||n+(t.height||i),this.width=t.width||r,this.lineHeight=void 0!==e?e:t.lineHeight}function er(t,e,o,u){var i=new tr(e),r=e.cue,n=function(t){if("number"==typeof t.line&&(t.snapToLines||0<=t.line&&t.line<=100))return t.line;if(!t.track||!t.track.textTrackList||!t.track.textTrackList.mediaElement)return-1;for(var e=t.track,i=e.textTrackList,r=0,n=0;n<i.length&&i[n]!==e;n++)"showing"===i[n].mode&&r++;return-1*++r}(r),s=[];if(r.snapToLines){var a;switch(r.vertical){case"":s=["+y","-y"],a="height";break;case"rl":s=["+x","-x"],a="width";break;case"lr":s=["-x","+x"],a="width"}var l=i.lineHeight,c=l*Math.round(n),h=o[a]+l,d=s[0];Math.abs(c)>h&&(c=c<0?-1:1,c*=Math.ceil(h/l)*l),n<0&&(c+=""===r.vertical?o.height:o.width,s=s.reverse()),i.move(d,c)}else{var p=i.lineHeight/o.height*100;switch(r.lineAlign){case"middle":n-=p/2;break;case"end":n-=p}switch(r.vertical){case"":e.applyStyles({top:e.formatStyle(n,"%")});break;case"rl":e.applyStyles({left:e.formatStyle(n,"%")});break;case"lr":e.applyStyles({right:e.formatStyle(n,"%")})}s=["+y","-x","+x","-y"],i=new tr(e)}var f=function(t,e){for(var i,r=new tr(t),n=1,s=0;s<e.length;s++){for(;t.overlapsOppositeAxis(o,e[s])||t.within(o)&&t.overlapsAny(u);)t.move(e[s]);if(t.within(o))return t;var a=t.intersectPercentage(o);a<n&&(i=new tr(t),n=a),t=new tr(r)}return i||r}(i,s);e.move(f.toCSSCompatValues(o))}function ir(){}Ji.prototype.applyStyles=function(t,e){for(var i in e=e||this.div,t)t.hasOwnProperty(i)&&(e.style[i]=t[i])},Ji.prototype.formatStyle=function(t,e){return 0===t?0:t+e},(Zi.prototype=ji(Ji.prototype)).constructor=Zi,tr.prototype.move=function(t,e){switch(e=void 0!==e?e:this.lineHeight,t){case"+x":this.left+=e,this.right+=e;break;case"-x":this.left-=e,this.right-=e;break;case"+y":this.top+=e,this.bottom+=e;break;case"-y":this.top-=e,this.bottom-=e}},tr.prototype.overlaps=function(t){return this.left<t.right&&this.right>t.left&&this.top<t.bottom&&this.bottom>t.top},tr.prototype.overlapsAny=function(t){for(var e=0;e<t.length;e++)if(this.overlaps(t[e]))return!0;return!1},tr.prototype.within=function(t){return this.top>=t.top&&this.bottom<=t.bottom&&this.left>=t.left&&this.right<=t.right},tr.prototype.overlapsOppositeAxis=function(t,e){switch(e){case"+x":return this.left<t.left;case"-x":return this.right>t.right;case"+y":return this.top<t.top;case"-y":return this.bottom>t.bottom}},tr.prototype.intersectPercentage=function(t){return Math.max(0,Math.min(this.right,t.right)-Math.max(this.left,t.left))*Math.max(0,Math.min(this.bottom,t.bottom)-Math.max(this.top,t.top))/(this.height*this.width)},tr.prototype.toCSSCompatValues=function(t){return{top:this.top-t.top,bottom:t.bottom-this.bottom,left:this.left-t.left,right:t.right-this.right,height:this.height,width:this.width}},tr.getSimpleBoxPosition=function(t){var e=t.div?t.div.offsetHeight:t.tagName?t.offsetHeight:0,i=t.div?t.div.offsetWidth:t.tagName?t.offsetWidth:0,r=t.div?t.div.offsetTop:t.tagName?t.offsetTop:0;return{left:(t=t.div?t.div.getBoundingClientRect():t.tagName?t.getBoundingClientRect():t).left,right:t.right,top:t.top||r,height:t.height||e,bottom:t.bottom||r+(t.height||e),width:t.width||i}},ir.StringDecoder=function(){return{decode:function(t){if(!t)return"";if("string"!=typeof t)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(t))}}},ir.convertCueToDOMTree=function(t,e){return t&&e?$i(t,e):null};ir.processCues=function(r,n,t){if(!r||!n||!t)return null;for(;t.firstChild;)t.removeChild(t.firstChild);var s=r.document.createElement("div");if(s.style.position="absolute",s.style.left="0",s.style.right="0",s.style.top="0",s.style.bottom="0",s.style.margin="1.5%",t.appendChild(s),function(t){for(var e=0;e<t.length;e++)if(t[e].hasBeenReset||!t[e].displayState)return!0;return!1}(n)){var a=[],o=tr.getSimpleBoxPosition(s),u={font:Math.round(.05*o.height*100)/100+"px sans-serif"};!function(){for(var t,e,i=0;i<n.length;i++)e=n[i],t=new Zi(r,e,u),s.appendChild(t.div),er(0,t,o,a),e.displayState=t.div,a.push(tr.getSimpleBoxPosition(t))}()}else for(var e=0;e<n.length;e++)s.appendChild(n[e].displayState)},(ir.Parser=function(t,e,i){i||(i=e,e={}),e||(e={}),this.window=t,this.vttjs=e,this.state="INITIAL",this.buffer="",this.decoder=i||new TextDecoder("utf8"),this.regionList=[]}).prototype={reportOrThrowError:function(t){if(!(t instanceof Fi))throw t;this.onparsingerror&&this.onparsingerror(t)},parse:function(t){var s=this;function e(){for(var t=s.buffer,e=0;e<t.length&&"\r"!==t[e]&&"\n"!==t[e];)++e;var i=t.substr(0,e);return"\r"===t[e]&&++e,"\n"===t[e]&&++e,s.buffer=t.substr(e),i}function i(t){t.match(/X-TIMESTAMP-MAP/)?qi(t,function(t,e){switch(t){case"X-TIMESTAMP-MAP":i=e,r=new Vi,qi(i,function(t,e){switch(t){case"MPEGT":r.integer(t+"S",e);break;case"LOCA":r.set(t+"L",Hi(e))}},/[^\d]:/,/,/),s.ontimestampmap&&s.ontimestampmap({MPEGTS:r.get("MPEGTS"),LOCAL:r.get("LOCAL")})}var i,r},/=/):qi(t,function(t,e){switch(t){case"Region":!function(t){var n=new Vi;if(qi(t,function(t,e){switch(t){case"id":n.set(t,e);break;case"width":n.percent(t,e);break;case"lines":n.integer(t,e);break;case"regionanchor":case"viewportanchor":var i=e.split(",");if(2!==i.length)break;var r=new Vi;if(r.percent("x",i[0]),r.percent("y",i[1]),!r.has("x")||!r.has("y"))break;n.set(t+"X",r.get("x")),n.set(t+"Y",r.get("y"));break;case"scroll":n.alt(t,e,["up"])}},/=/,/\s/),n.has("id")){var e=new(s.vttjs.VTTRegion||s.window.VTTRegion);e.width=n.get("width",100),e.lines=n.get("lines",3),e.regionAnchorX=n.get("regionanchorX",0),e.regionAnchorY=n.get("regionanchorY",100),e.viewportAnchorX=n.get("viewportanchorX",0),e.viewportAnchorY=n.get("viewportanchorY",100),e.scroll=n.get("scroll",""),s.onregion&&s.onregion(e),s.regionList.push({id:n.get("id"),region:e})}}(e)}},/:/)}t&&(s.buffer+=s.decoder.decode(t,{stream:!0}));try{var r;if("INITIAL"===s.state){if(!/\r\n|\n/.test(s.buffer))return this;var n=(r=e()).match(/^WEBVTT([ \t].*)?$/);if(!n||!n[0])throw new Fi(Fi.Errors.BadSignature);s.state="HEADER"}for(var a=!1;s.buffer;){if(!/\r\n|\n/.test(s.buffer))return this;switch(a?a=!1:r=e(),s.state){case"HEADER":/:/.test(r)?i(r):r||(s.state="ID");continue;case"NOTE":r||(s.state="ID");continue;case"ID":if(/^NOTE($|[ \t])/.test(r)){s.state="NOTE";break}if(!r)continue;if(s.cue=new(s.vttjs.VTTCue||s.window.VTTCue)(0,0,""),s.state="CUE",-1===r.indexOf("--\x3e")){s.cue.id=r;continue}case"CUE":try{Wi(r,s.cue,s.regionList)}catch(t){s.reportOrThrowError(t),s.cue=null,s.state="BADCUE";continue}s.state="CUETEXT";continue;case"CUETEXT":var o=-1!==r.indexOf("--\x3e");if(!r||o&&(a=!0)){s.oncue&&s.oncue(s.cue),s.cue=null,s.state="ID";continue}s.cue.text&&(s.cue.text+="\n"),s.cue.text+=r;continue;case"BADCUE":r||(s.state="ID");continue}}}catch(t){s.reportOrThrowError(t),"CUETEXT"===s.state&&s.cue&&s.oncue&&s.oncue(s.cue),s.cue=null,s.state="INITIAL"===s.state?"BADWEBVTT":"BADCUE"}return this},flush:function(){var e=this;try{if(e.buffer+=e.decoder.decode(),(e.cue||"HEADER"===e.state)&&(e.buffer+="\n\n",e.parse()),"INITIAL"===e.state)throw new Fi(Fi.Errors.BadSignature)}catch(t){e.reportOrThrowError(t)}return e.onflush&&e.onflush(),this}};var rr=ir,nr=Object.freeze({default:rr,__moduleExports:rr}),sr="auto",ar={"":1,lr:1,rl:1},or={start:1,middle:1,end:1,left:1,right:1};function ur(t){return"string"==typeof t&&(!!or[t.toLowerCase()]&&t.toLowerCase())}function lr(t,e,i){this.hasBeenReset=!1;var r="",n=!1,s=t,a=e,o=i,u=null,l="",c=!0,h="auto",d="start",p=50,f="middle",m=50,g="middle";Object.defineProperties(this,{id:{enumerable:!0,get:function(){return r},set:function(t){r=""+t}},pauseOnExit:{enumerable:!0,get:function(){return n},set:function(t){n=!!t}},startTime:{enumerable:!0,get:function(){return s},set:function(t){if("number"!=typeof t)throw new TypeError("Start time must be set to a number.");s=t,this.hasBeenReset=!0}},endTime:{enumerable:!0,get:function(){return a},set:function(t){if("number"!=typeof t)throw new TypeError("End time must be set to a number.");a=t,this.hasBeenReset=!0}},text:{enumerable:!0,get:function(){return o},set:function(t){o=""+t,this.hasBeenReset=!0}},region:{enumerable:!0,get:function(){return u},set:function(t){u=t,this.hasBeenReset=!0}},vertical:{enumerable:!0,get:function(){return l},set:function(t){var e,i="string"==typeof(e=t)&&!!ar[e.toLowerCase()]&&e.toLowerCase();if(!1===i)throw new SyntaxError("An invalid or illegal string was specified.");l=i,this.hasBeenReset=!0}},snapToLines:{enumerable:!0,get:function(){return c},set:function(t){c=!!t,this.hasBeenReset=!0}},line:{enumerable:!0,get:function(){return h},set:function(t){if("number"!=typeof t&&t!==sr)throw new SyntaxError("An invalid number or illegal string was specified.");h=t,this.hasBeenReset=!0}},lineAlign:{enumerable:!0,get:function(){return d},set:function(t){var e=ur(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");d=e,this.hasBeenReset=!0}},position:{enumerable:!0,get:function(){return p},set:function(t){if(t<0||100<t)throw new Error("Position must be between 0 and 100.");p=t,this.hasBeenReset=!0}},positionAlign:{enumerable:!0,get:function(){return f},set:function(t){var e=ur(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");f=e,this.hasBeenReset=!0}},size:{enumerable:!0,get:function(){return m},set:function(t){if(t<0||100<t)throw new Error("Size must be between 0 and 100.");m=t,this.hasBeenReset=!0}},align:{enumerable:!0,get:function(){return g},set:function(t){var e=ur(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");g=e,this.hasBeenReset=!0}}}),this.displayState=void 0}lr.prototype.getCueAsHTML=function(){return WebVTT.convertCueToDOMTree(window,this.text)};var cr=lr,hr=Object.freeze({default:cr,__moduleExports:cr}),dr={"":!0,up:!0};function pr(t){return"number"==typeof t&&0<=t&&t<=100}var fr=function(){var e=100,i=3,r=0,n=100,s=0,a=100,o="";Object.defineProperties(this,{width:{enumerable:!0,get:function(){return e},set:function(t){if(!pr(t))throw new Error("Width must be between 0 and 100.");e=t}},lines:{enumerable:!0,get:function(){return i},set:function(t){if("number"!=typeof t)throw new TypeError("Lines must be set to a number.");i=t}},regionAnchorY:{enumerable:!0,get:function(){return n},set:function(t){if(!pr(t))throw new Error("RegionAnchorX must be between 0 and 100.");n=t}},regionAnchorX:{enumerable:!0,get:function(){return r},set:function(t){if(!pr(t))throw new Error("RegionAnchorY must be between 0 and 100.");r=t}},viewportAnchorY:{enumerable:!0,get:function(){return a},set:function(t){if(!pr(t))throw new Error("ViewportAnchorY must be between 0 and 100.");a=t}},viewportAnchorX:{enumerable:!0,get:function(){return s},set:function(t){if(!pr(t))throw new Error("ViewportAnchorX must be between 0 and 100.");s=t}},scroll:{enumerable:!0,get:function(){return o},set:function(t){var e,i="string"==typeof(e=t)&&!!dr[e.toLowerCase()]&&e.toLowerCase();if(!1===i)throw new SyntaxError("An invalid or illegal string was specified.");o=i}}})},mr=Object.freeze({default:fr,__moduleExports:fr}),gr=nr&&rr||nr,yr=hr&&cr||hr,vr=mr&&fr||mr,_r=e(function(t){var e=t.exports={WebVTT:gr,VTTCue:yr,VTTRegion:vr};g.vttjs=e,g.WebVTT=e.WebVTT;var i=e.VTTCue,r=e.VTTRegion,n=g.VTTCue,s=g.VTTRegion;e.shim=function(){g.VTTCue=i,g.VTTRegion=r},e.restore=function(){g.VTTCue=n,g.VTTRegion=s},g.VTTCue||e.shim()});_r.WebVTT,_r.VTTCue,_r.VTTRegion;var br=function(e){function n(){var i=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:function(){};y(this,n),i.reportTouchActivity=!1;var r=b(this,e.call(this,null,i,t));return r.hasStarted_=!1,r.on("playing",function(){this.hasStarted_=!0}),r.on("loadstart",function(){this.hasStarted_=!1}),Bi.names.forEach(function(t){var e=Bi[t];i&&i[e.getterName]&&(r[e.privateName]=i[e.getterName])}),r.featuresProgressEvents||r.manualProgressOn(),r.featuresTimeupdateEvents||r.manualTimeUpdatesOn(),["Text","Audio","Video"].forEach(function(t){!1===i["native"+t+"Tracks"]&&(r["featuresNative"+t+"Tracks"]=!1)}),!1===i.nativeCaptions||!1===i.nativeTextTracks?r.featuresNativeTextTracks=!1:!0!==i.nativeCaptions&&!0!==i.nativeTextTracks||(r.featuresNativeTextTracks=!0),r.featuresNativeTextTracks||r.emulateTextTracks(),r.autoRemoteTextTracks_=new Bi.text.ListClass,r.initTrackListeners(),i.nativeControlsForTouch||r.emitTapEvents(),r.constructor&&(r.name_=r.constructor.name||"Unknown Tech"),r}return _(n,e),n.prototype.triggerSourceset=function(t){var e=this;this.isReady_||this.one("ready",function(){return e.setTimeout(function(){return e.triggerSourceset(t)},1)}),this.trigger({src:t,type:"sourceset"})},n.prototype.manualProgressOn=function(){this.on("durationchange",this.onDurationChange),this.manualProgress=!0,this.one("ready",this.trackProgress)},n.prototype.manualProgressOff=function(){this.manualProgress=!1,this.stopTrackingProgress(),this.off("durationchange",this.onDurationChange)},n.prototype.trackProgress=function(t){this.stopTrackingProgress(),this.progressInterval=this.setInterval(Ot(this,function(){var t=this.bufferedPercent();this.bufferedPercent_!==t&&this.trigger("progress"),1===(this.bufferedPercent_=t)&&this.stopTrackingProgress()}),500)},n.prototype.onDurationChange=function(t){this.duration_=this.duration()},n.prototype.buffered=function(){return be(0,0)},n.prototype.bufferedPercent=function(){return Te(this.buffered(),this.duration_)},n.prototype.stopTrackingProgress=function(){this.clearInterval(this.progressInterval)},n.prototype.manualTimeUpdatesOn=function(){this.manualTimeUpdates=!0,this.on("play",this.trackCurrentTime),this.on("pause",this.stopTrackingCurrentTime)},n.prototype.manualTimeUpdatesOff=function(){this.manualTimeUpdates=!1,this.stopTrackingCurrentTime(),this.off("play",this.trackCurrentTime),this.off("pause",this.stopTrackingCurrentTime)},n.prototype.trackCurrentTime=function(){this.currentTimeInterval&&this.stopTrackingCurrentTime(),this.currentTimeInterval=this.setInterval(function(){this.trigger({type:"timeupdate",target:this,manuallyTriggered:!0})},250)},n.prototype.stopTrackingCurrentTime=function(){this.clearInterval(this.currentTimeInterval),this.trigger({type:"timeupdate",target:this,manuallyTriggered:!0})},n.prototype.dispose=function(){this.clearTracks(Ui.names),this.manualProgress&&this.manualProgressOff(),this.manualTimeUpdates&&this.manualTimeUpdatesOff(),e.prototype.dispose.call(this)},n.prototype.clearTracks=function(t){var n=this;(t=[].concat(t)).forEach(function(t){for(var e=n[t+"Tracks"]()||[],i=e.length;i--;){var r=e[i];"text"===t&&n.removeRemoteTextTrack(r),e.removeTrack(r)}})},n.prototype.cleanupAutoTextTracks=function(){for(var t=this.autoRemoteTextTracks_||[],e=t.length;e--;){var i=t[e];this.removeRemoteTextTrack(i)}},n.prototype.reset=function(){},n.prototype.error=function(t){return void 0!==t&&(this.error_=new Le(t),this.trigger("error")),this.error_},n.prototype.played=function(){return this.hasStarted_?be(0,0):be()},n.prototype.setCurrentTime=function(){this.manualTimeUpdates&&this.trigger({type:"timeupdate",target:this,manuallyTriggered:!0})},n.prototype.initTrackListeners=function(){var n=this;Ui.names.forEach(function(t){var e=Ui[t],i=function(){n.trigger(t+"trackchange")},r=n[e.getterName]();r.addEventListener("removetrack",i),r.addEventListener("addtrack",i),n.on("dispose",function(){r.removeEventListener("removetrack",i),r.removeEventListener("addtrack",i)})})},n.prototype.addWebVttScript_=function(){var t=this;if(!g.WebVTT)if(p.body.contains(this.el())){if(!this.options_["vtt.js"]&&w(_r)&&0<Object.keys(_r).length)return void this.trigger("vttjsloaded");var e=p.createElement("script");e.src=this.options_["vtt.js"]||"https://vjs.zencdn.net/vttjs/0.14.1/vtt.min.js",e.onload=function(){t.trigger("vttjsloaded")},e.onerror=function(){t.trigger("vttjserror")},this.on("dispose",function(){e.onload=null,e.onerror=null}),g.WebVTT=!0,this.el().parentNode.appendChild(e)}else this.ready(this.addWebVttScript_)},n.prototype.emulateTextTracks=function(){var t=this,i=this.textTracks(),e=this.remoteTextTracks(),r=function(t){return i.addTrack(t.track)},n=function(t){return i.removeTrack(t.track)};e.on("addtrack",r),e.on("removetrack",n),this.addWebVttScript_();var s=function(){return t.trigger("texttrackchange")},a=function(){s();for(var t=0;t<i.length;t++){var e=i[t];e.removeEventListener("cuechange",s),"showing"===e.mode&&e.addEventListener("cuechange",s)}};a(),i.addEventListener("change",a),i.addEventListener("addtrack",a),i.addEventListener("removetrack",a),this.on("dispose",function(){e.off("addtrack",r),e.off("removetrack",n),i.removeEventListener("change",a),i.removeEventListener("addtrack",a),i.removeEventListener("removetrack",a);for(var t=0;t<i.length;t++){i[t].removeEventListener("cuechange",s)}})},n.prototype.addTextTrack=function(t,e,i){if(!t)throw new Error("TextTrack kind is required but was not provided");return function(t,e,i,r){var n=4<arguments.length&&void 0!==arguments[4]?arguments[4]:{},s=t.textTracks();n.kind=e,i&&(n.label=i),r&&(n.language=r),n.tech=t;var a=new Bi.text.TrackClass(n);return s.addTrack(a),a}(this,t,e,i)},n.prototype.createRemoteTextTrack=function(t){var e=Gt(t,{tech:this});return new Ni.remoteTextEl.TrackClass(e)},n.prototype.addRemoteTextTrack=function(){var t=this,e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},i=arguments[1],r=this.createRemoteTextTrack(e);return!0!==i&&!1!==i&&(f.warn('Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js'),i=!0),this.remoteTextTrackEls().addTrackElement_(r),this.remoteTextTracks().addTrack(r.track),!0!==i&&this.ready(function(){return t.autoRemoteTextTracks_.addTrack(r.track)}),r},n.prototype.removeRemoteTextTrack=function(t){var e=this.remoteTextTrackEls().getTrackElementByTrack_(t);this.remoteTextTrackEls().removeTrackElement_(e),this.remoteTextTracks().removeTrack(t),this.autoRemoteTextTracks_.removeTrack(t)},n.prototype.getVideoPlaybackQuality=function(){return{}},n.prototype.setPoster=function(){},n.prototype.playsinline=function(){},n.prototype.setPlaysinline=function(){},n.prototype.overrideNativeAudioTracks=function(){},n.prototype.overrideNativeVideoTracks=function(){},n.prototype.canPlayType=function(){return""},n.canPlayType=function(){return""},n.canPlaySource=function(t,e){return n.canPlayType(t.type)},n.isTech=function(t){return t.prototype instanceof n||t instanceof n||t===n},n.registerTech=function(t,e){if(n.techs_||(n.techs_={}),!n.isTech(e))throw new Error("Tech "+t+" must be a Tech");if(!n.canPlayType)throw new Error("Techs must have a static canPlayType method on them");if(!n.canPlaySource)throw new Error("Techs must have a static canPlaySource method on them");return t=zt(t),n.techs_[t]=e,"Tech"!==t&&n.defaultTechOrder_.push(t),e},n.getTech=function(t){if(t)return t=zt(t),n.techs_&&n.techs_[t]?n.techs_[t]:g&&g.videojs&&g.videojs[t]?(f.warn("The "+t+" tech was added to the videojs object when it should be registered using videojs.registerTech(name, tech)"),g.videojs[t]):void 0},n}(Xt);Bi.names.forEach(function(t){var e=Bi[t];br.prototype[e.getterName]=function(){return this[e.privateName]=this[e.privateName]||new e.ListClass,this[e.privateName]}}),br.prototype.featuresVolumeControl=!0,br.prototype.featuresFullscreenResize=!1,br.prototype.featuresPlaybackRate=!1,br.prototype.featuresProgressEvents=!1,br.prototype.featuresSourceset=!1,br.prototype.featuresTimeupdateEvents=!1,br.prototype.featuresNativeTextTracks=!1,br.withSourceHandlers=function(n){n.registerSourceHandler=function(t,e){var i=n.sourceHandlers;i||(i=n.sourceHandlers=[]),void 0===e&&(e=i.length),i.splice(e,0,t)},n.canPlayType=function(t){for(var e=n.sourceHandlers||[],i=void 0,r=0;r<e.length;r++)if(i=e[r].canPlayType(t))return i;return""},n.selectSourceHandler=function(t,e){for(var i=n.sourceHandlers||[],r=0;r<i.length;r++)if(i[r].canHandleSource(t,e))return i[r];return null},n.canPlaySource=function(t,e){var i=n.selectSourceHandler(t,e);return i?i.canHandleSource(t,e):""};["seekable","seeking","duration"].forEach(function(t){var e=this[t];"function"==typeof e&&(this[t]=function(){return this.sourceHandler_&&this.sourceHandler_[t]?this.sourceHandler_[t].apply(this.sourceHandler_,arguments):e.apply(this,arguments)})},n.prototype),n.prototype.setSource=function(t){var e=n.selectSourceHandler(t,this.options_);e||(n.nativeSourceHandler?e=n.nativeSourceHandler:f.error("No source handler found for the current source.")),this.disposeSourceHandler(),this.off("dispose",this.disposeSourceHandler),e!==n.nativeSourceHandler&&(this.currentSource_=t),this.sourceHandler_=e.handleSource(t,this,this.options_),this.on("dispose",this.disposeSourceHandler)},n.prototype.disposeSourceHandler=function(){this.currentSource_&&(this.clearTracks(["audio","video"]),this.currentSource_=null),this.cleanupAutoTextTracks(),this.sourceHandler_&&(this.sourceHandler_.dispose&&this.sourceHandler_.dispose(),this.sourceHandler_=null)}},Xt.registerComponent("Tech",br),br.registerTech("Tech",br),br.defaultTechOrder_=[];var Tr={},Sr={},kr={};function Cr(t,e,i){t.setTimeout(function(){return function i(){var r=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[];var n=arguments[2];var s=arguments[3];var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:[];var o=5<arguments.length&&void 0!==arguments[5]&&arguments[5];var e=t[0],u=t.slice(1);if("string"==typeof e)i(r,Tr[e],n,s,a,o);else if(e){var l=function(t,e){var i=Sr[t.id()],r=null;if(null==i)return r=e(t),Sr[t.id()]=[[e,r]],r;for(var n=0;n<i.length;n++){var s=i[n],a=s[0],o=s[1];a===e&&(r=o)}null===r&&(r=e(t),i.push([e,r]));return r}(s,e);l.setSource(C({},r),function(t,e){if(t)return i(r,u,n,s,a,o);a.push(l),i(e,r.type===e.type?u:Tr[e.type],n,s,a,o)})}else u.length?i(r,u,n,s,a,o):o?n(r,a):i(r,Tr["*"],n,s,a,!0)}(e,Tr[e.type],i,t)},1)}function Er(t,e,i){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null,n="call"+zt(i),s=t.reduce(Pr(n),r),a=s===kr,o=a?null:e[i](s);return function(t,e,i,r){for(var n=t.length-1;0<=n;n--){var s=t[n];s[e]&&s[e](r,i)}}(t,i,o,a),o}var wr={buffered:1,currentTime:1,duration:1,seekable:1,played:1,paused:1},Ar={setCurrentTime:1},Lr={play:1,pause:1};function Pr(i){return function(t,e){return t===kr?kr:e[i]?e[i](t):t}}var Or={opus:"video/ogg",ogv:"video/ogg",mp4:"video/mp4",mov:"video/mp4",m4v:"video/mp4",mkv:"video/x-matroska",mp3:"audio/mpeg",aac:"audio/aac",oga:"audio/ogg",m3u8:"application/x-mpegURL"},xr=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",e=ti(t);return Or[e.toLowerCase()]||""};function Ir(t){var e=xr(t.src);return!t.type&&e&&(t.type=e),t}var Dr=function(l){function c(t,e,i){y(this,c);var r=Gt({createEl:!1},e),n=b(this,l.call(this,t,r,i));if(e.playerOptions.sources&&0!==e.playerOptions.sources.length)t.src(e.playerOptions.sources);else for(var s=0,a=e.playerOptions.techOrder;s<a.length;s++){var o=zt(a[s]),u=br.getTech(o);if(o||(u=Xt.getComponent(o)),u&&u.isSupported()){t.loadTech_(o);break}}return n}return _(c,l),c}(Xt);Xt.registerComponent("MediaLoader",Dr);var Rr=function(n){function r(t,e){y(this,r);var i=b(this,n.call(this,t,e));return i.emitTapEvents(),i.enable(),i}return _(r,n),r.prototype.createEl=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"div",e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};e=C({innerHTML:'<span aria-hidden="true" class="vjs-icon-placeholder"></span>',className:this.buildCSSClass(),tabIndex:0},e),"button"===t&&f.error("Creating a ClickableComponent with an HTML element of "+t+" is not supported; use a Button instead."),i=C({role:"button"},i),this.tabIndex_=e.tabIndex;var r=n.prototype.createEl.call(this,t,e,i);return this.createControlTextEl(r),r},r.prototype.dispose=function(){this.controlTextEl_=null,n.prototype.dispose.call(this)},r.prototype.createControlTextEl=function(t){return this.controlTextEl_=M("span",{className:"vjs-control-text"},{"aria-live":"polite"}),t&&t.appendChild(this.controlTextEl_),this.controlText(this.controlText_,t),this.controlTextEl_},r.prototype.controlText=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:this.el();if(void 0===t)return this.controlText_||"Need Text";var i=this.localize(t);this.controlText_=t,U(this.controlTextEl_,i),this.nonIconControl||e.setAttribute("title",i)},r.prototype.buildCSSClass=function(){return"vjs-control vjs-button "+n.prototype.buildCSSClass.call(this)},r.prototype.enable=function(){this.enabled_||(this.enabled_=!0,this.removeClass("vjs-disabled"),this.el_.setAttribute("aria-disabled","false"),"undefined"!=typeof this.tabIndex_&&this.el_.setAttribute("tabIndex",this.tabIndex_),this.on(["tap","click"],this.handleClick),this.on("focus",this.handleFocus),this.on("blur",this.handleBlur))},r.prototype.disable=function(){this.enabled_=!1,this.addClass("vjs-disabled"),this.el_.setAttribute("aria-disabled","true"),"undefined"!=typeof this.tabIndex_&&this.el_.removeAttribute("tabIndex"),this.off(["tap","click"],this.handleClick),this.off("focus",this.handleFocus),this.off("blur",this.handleBlur)},r.prototype.handleClick=function(t){},r.prototype.handleFocus=function(t){_t(p,"keydown",Ot(this,this.handleKeyPress))},r.prototype.handleKeyPress=function(t){32===t.which||13===t.which?(t.preventDefault(),this.trigger("click")):n.prototype.handleKeyPress&&n.prototype.handleKeyPress.call(this,t)},r.prototype.handleBlur=function(t){bt(p,"keydown",Ot(this,this.handleKeyPress))},r}(Xt);Xt.registerComponent("ClickableComponent",Rr);var Mr=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.update(),t.on("posterchange",Ot(i,i.update)),i}return _(n,r),n.prototype.dispose=function(){this.player().off("posterchange",this.update),r.prototype.dispose.call(this)},n.prototype.createEl=function(){return M("div",{className:"vjs-poster",tabIndex:-1})},n.prototype.update=function(t){var e=this.player().poster();this.setSrc(e),e?this.show():this.hide()},n.prototype.setSrc=function(t){var e="";t&&(e='url("'+t+'")'),this.el_.style.backgroundImage=e},n.prototype.handleClick=function(t){this.player_.controls()&&(this.player_.paused()?this.player_.play():this.player_.pause())},n}(Rr);Xt.registerComponent("PosterImage",Mr);var Ur="#222",Nr={monospace:"monospace",sansSerif:"sans-serif",serif:"serif",monospaceSansSerif:'"Andale Mono", "Lucida Console", monospace',monospaceSerif:'"Courier New", monospace',proportionalSansSerif:"sans-serif",proportionalSerif:"serif",casual:'"Comic Sans MS", Impact, fantasy',script:'"Monotype Corsiva", cursive',smallcaps:'"Andale Mono", "Lucida Console", monospace, sans-serif'};function Br(t,e){return"rgba("+parseInt(t[1]+t[1],16)+","+parseInt(t[2]+t[2],16)+","+parseInt(t[3]+t[3],16)+","+e+")"}function jr(t,e,i){try{t.style[e]=i}catch(t){return}}var Fr=function(n){function s(i,t,e){y(this,s);var r=b(this,n.call(this,i,t,e));return i.on("loadstart",Ot(r,r.toggleDisplay)),i.on("texttrackchange",Ot(r,r.updateDisplay)),i.on("loadstart",Ot(r,r.preselectTrack)),i.ready(Ot(r,function(){if(i.tech_&&i.tech_.featuresNativeTextTracks)this.hide();else{i.on("fullscreenchange",Ot(this,this.updateDisplay));for(var t=this.options_.playerOptions.tracks||[],e=0;e<t.length;e++)this.player_.addRemoteTextTrack(t[e],!0);this.preselectTrack()}})),r}return _(s,n),s.prototype.preselectTrack=function(){for(var t={captions:1,subtitles:1},e=this.player_.textTracks(),i=this.player_.cache_.selectedLanguage,r=void 0,n=void 0,s=void 0,a=0;a<e.length;a++){var o=e[a];i&&i.enabled&&i.language===o.language?o.kind===i.kind?s=o:s||(s=o):i&&!i.enabled?n=r=s=null:o.default&&("descriptions"!==o.kind||r?o.kind in t&&!n&&(n=o):r=o)}s?s.mode="showing":n?n.mode="showing":r&&(r.mode="showing")},s.prototype.toggleDisplay=function(){this.player_.tech_&&this.player_.tech_.featuresNativeTextTracks?this.hide():this.show()},s.prototype.createEl=function(){return n.prototype.createEl.call(this,"div",{className:"vjs-text-track-display"},{"aria-live":"off","aria-atomic":"true"})},s.prototype.clearDisplay=function(){"function"==typeof g.WebVTT&&g.WebVTT.processCues(g,[],this.el_)},s.prototype.updateDisplay=function(){var t=this.player_.textTracks();this.clearDisplay();for(var e=null,i=null,r=t.length;r--;){var n=t[r];"showing"===n.mode&&("descriptions"===n.kind?e=n:i=n)}i?("off"!==this.getAttribute("aria-live")&&this.setAttribute("aria-live","off"),this.updateForTrack(i)):e&&("assertive"!==this.getAttribute("aria-live")&&this.setAttribute("aria-live","assertive"),this.updateForTrack(e))},s.prototype.updateForTrack=function(t){if("function"==typeof g.WebVTT&&t.activeCues){for(var e=[],i=0;i<t.activeCues.length;i++)e.push(t.activeCues[i]);if(g.WebVTT.processCues(g,e,this.el_),this.player_.textTrackSettings)for(var r=this.player_.textTrackSettings.getValues(),n=e.length;n--;){var s=e[n];if(s){var a=s.displayState;if(r.color&&(a.firstChild.style.color=r.color),r.textOpacity&&jr(a.firstChild,"color",Br(r.color||"#fff",r.textOpacity)),r.backgroundColor&&(a.firstChild.style.backgroundColor=r.backgroundColor),r.backgroundOpacity&&jr(a.firstChild,"backgroundColor",Br(r.backgroundColor||"#000",r.backgroundOpacity)),r.windowColor&&(r.windowOpacity?jr(a,"backgroundColor",Br(r.windowColor,r.windowOpacity)):a.style.backgroundColor=r.windowColor),r.edgeStyle&&("dropshadow"===r.edgeStyle?a.firstChild.style.textShadow="2px 2px 3px #222, 2px 2px 4px #222, 2px 2px 5px "+Ur:"raised"===r.edgeStyle?a.firstChild.style.textShadow="1px 1px #222, 2px 2px #222, 3px 3px "+Ur:"depressed"===r.edgeStyle?a.firstChild.style.textShadow="1px 1px #ccc, 0 1px #ccc, -1px -1px #222, 0 -1px "+Ur:"uniform"===r.edgeStyle&&(a.firstChild.style.textShadow="0 0 4px #222, 0 0 4px #222, 0 0 4px #222, 0 0 4px "+Ur)),r.fontPercent&&1!==r.fontPercent){var o=g.parseFloat(a.style.fontSize);a.style.fontSize=o*r.fontPercent+"px",a.style.height="auto",a.style.top="auto",a.style.bottom="2px"}r.fontFamily&&"default"!==r.fontFamily&&("small-caps"===r.fontFamily?a.firstChild.style.fontVariant="small-caps":a.firstChild.style.fontFamily=Nr[r.fontFamily])}}}},s}(Xt);Xt.registerComponent("TextTrackDisplay",Fr);var Hr=function(n){function t(){return y(this,t),b(this,n.apply(this,arguments))}return _(t,n),t.prototype.createEl=function(){var t=this.player_.isAudio(),e=this.localize(t?"Audio Player":"Video Player"),i=M("span",{className:"vjs-control-text",innerHTML:this.localize("{1} is loading.",[e])}),r=n.prototype.createEl.call(this,"div",{className:"vjs-loading-spinner",dir:"ltr"});return r.appendChild(i),r},t}(Xt);Xt.registerComponent("LoadingSpinner",Hr);var Vr=function(e){function t(){return y(this,t),b(this,e.apply(this,arguments))}return _(t,e),t.prototype.createEl=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};e=C({innerHTML:'<span aria-hidden="true" class="vjs-icon-placeholder"></span>',className:this.buildCSSClass()},e),i=C({type:"button"},i);var r=Xt.prototype.createEl.call(this,"button",e,i);return this.createControlTextEl(r),r},t.prototype.addChild=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=this.constructor.name;return f.warn("Adding an actionable (user controllable) child to a Button ("+i+") is not supported; use a ClickableComponent instead."),Xt.prototype.addChild.call(this,t,e)},t.prototype.enable=function(){e.prototype.enable.call(this),this.el_.removeAttribute("disabled")},t.prototype.disable=function(){e.prototype.disable.call(this),this.el_.setAttribute("disabled","disabled")},t.prototype.handleKeyPress=function(t){32!==t.which&&13!==t.which&&e.prototype.handleKeyPress.call(this,t)},t}(Rr);Xt.registerComponent("Button",Vr);var qr=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.mouseused_=!1,i.on("mousedown",i.handleMouseDown),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-big-playOld-button"},n.prototype.handleClick=function(t){var e=this.player_.play();if(!(this.mouseused_&&t.clientX&&t.clientY)){var i=this.player_.getChild("controlBar"),r=i&&i.getChild("playToggle");if(r){var n=function(){return r.focus()};xe(e)?e.then(n,function(){}):this.setTimeout(n,1)}else this.player_.focus()}},n.prototype.handleKeyPress=function(t){this.mouseused_=!1,r.prototype.handleKeyPress.call(this,t)},n.prototype.handleMouseDown=function(t){this.mouseused_=!0},n}(Vr);qr.prototype.controlText_="Play Video",Xt.registerComponent("BigPlayButton",qr);var Wr=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.controlText(e&&e.controlText||i.localize("Close")),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-close-button "+r.prototype.buildCSSClass.call(this)},n.prototype.handleClick=function(t){this.trigger({type:"close",bubbles:!1})},n}(Vr);Xt.registerComponent("CloseButton",Wr);var zr=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.on(t,"play",i.handlePlay),i.on(t,"pause",i.handlePause),i.on(t,"ended",i.handleEnded),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-playOld-control "+r.prototype.buildCSSClass.call(this)},n.prototype.handleClick=function(t){this.player_.paused()?this.player_.play():this.player_.pause()},n.prototype.handleSeeked=function(t){this.removeClass("vjs-ended"),this.player_.paused()?this.handlePause(t):this.handlePlay(t)},n.prototype.handlePlay=function(t){this.removeClass("vjs-ended"),this.removeClass("vjs-paused"),this.addClass("vjs-playing"),this.controlText("Pause")},n.prototype.handlePause=function(t){this.removeClass("vjs-playing"),this.addClass("vjs-paused"),this.controlText("Play")},n.prototype.handleEnded=function(t){this.removeClass("vjs-playing"),this.addClass("vjs-ended"),this.controlText("Replay"),this.one(this.player_,"seeked",this.handleSeeked)},n}(Vr);zr.prototype.controlText_="Play",Xt.registerComponent("PlayToggle",zr);var Gr=function(t,e){t=t<0?0:t;var i=Math.floor(t%60),r=Math.floor(t/60%60),n=Math.floor(t/3600),s=Math.floor(e/60%60),a=Math.floor(e/3600);return(isNaN(t)||t===1/0)&&(n=r=i="-"),(n=0<n||0<a?n+":":"")+(r=((n||10<=s)&&r<10?"0"+r:r)+":")+(i=i<10?"0"+i:i)},Xr=Gr;function Yr(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:t;return Xr(t,e)}var $r=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.throttledUpdateContent=xt(Ot(i,i.updateContent),25),i.on(t,"timeupdate",i.throttledUpdateContent),i}return _(n,r),n.prototype.createEl=function(t){var e=this.buildCSSClass(),i=r.prototype.createEl.call(this,"div",{className:e+" vjs-time-control vjs-control",innerHTML:'<span class="vjs-control-text">'+this.localize(this.labelText_)+" </span>"});return this.contentEl_=M("span",{className:e+"-display"},{"aria-live":"off"}),this.updateTextNode_(),i.appendChild(this.contentEl_),i},n.prototype.dispose=function(){this.contentEl_=null,this.textNode_=null,r.prototype.dispose.call(this)},n.prototype.updateTextNode_=function(){if(this.contentEl_){for(;this.contentEl_.firstChild;)this.contentEl_.removeChild(this.contentEl_.firstChild);this.textNode_=p.createTextNode(this.formattedTime_||this.formatTime_(0)),this.contentEl_.appendChild(this.textNode_)}},n.prototype.formatTime_=function(t){return Yr(t)},n.prototype.updateFormattedTime_=function(t){var e=this.formatTime_(t);e!==this.formattedTime_&&(this.formattedTime_=e,this.requestAnimationFrame(this.updateTextNode_))},n.prototype.updateContent=function(t){},n}(Xt);$r.prototype.labelText_="Time",$r.prototype.controlText_="Time",Xt.registerComponent("TimeDisplay",$r);var Kr=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.on(t,"ended",i.handleEnded),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-current-time"},n.prototype.updateContent=function(t){var e=this.player_.scrubbing()?this.player_.getCache().currentTime:this.player_.currentTime();this.updateFormattedTime_(e)},n.prototype.handleEnded=function(t){this.player_.duration()&&this.updateFormattedTime_(this.player_.duration())},n}($r);Kr.prototype.labelText_="Current Time",Kr.prototype.controlText_="Current Time",Xt.registerComponent("CurrentTimeDisplay",Kr);var Qr=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.on(t,"durationchange",i.updateContent),i.on(t,"loadedmetadata",i.throttledUpdateContent),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-duration"},n.prototype.updateContent=function(t){var e=this.player_.duration();e&&this.duration_!==e&&(this.duration_=e,this.updateFormattedTime_(e))},n}($r);Qr.prototype.labelText_="Duration",Qr.prototype.controlText_="Duration",Xt.registerComponent("DurationDisplay",Qr);var Jr=function(t){function e(){return y(this,e),b(this,t.apply(this,arguments))}return _(e,t),e.prototype.createEl=function(){return t.prototype.createEl.call(this,"div",{className:"vjs-time-control vjs-time-divider",innerHTML:"<div><span>/</span></div>"})},e}(Xt);Xt.registerComponent("TimeDivider",Jr);var Zr=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.on(t,"durationchange",i.throttledUpdateContent),i.on(t,"ended",i.handleEnded),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-remaining-time"},n.prototype.formatTime_=function(t){return"-"+r.prototype.formatTime_.call(this,t)},n.prototype.updateContent=function(t){this.player_.duration()&&(this.player_.remainingTimeDisplay?this.updateFormattedTime_(this.player_.remainingTimeDisplay()):this.updateFormattedTime_(this.player_.remainingTime()))},n.prototype.handleEnded=function(t){this.player_.duration()&&this.updateFormattedTime_(0)},n}($r);Zr.prototype.labelText_="Remaining Time",Zr.prototype.controlText_="Remaining Time",Xt.registerComponent("RemainingTimeDisplay",Zr);var tn=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.updateShowing(),i.on(i.player(),"durationchange",i.updateShowing),i}return _(n,r),n.prototype.createEl=function(){var t=r.prototype.createEl.call(this,"div",{className:"vjs-live-control vjs-control"});return this.contentEl_=M("div",{className:"vjs-live-display",innerHTML:'<span class="vjs-control-text">'+this.localize("Stream Type")+" </span>"+this.localize("LIVE")},{"aria-live":"off"}),t.appendChild(this.contentEl_),t},n.prototype.dispose=function(){this.contentEl_=null,r.prototype.dispose.call(this)},n.prototype.updateShowing=function(t){this.player().duration()===1/0?this.show():this.hide()},n}(Xt);Xt.registerComponent("LiveDisplay",tn);var en=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.bar=i.getChild(i.options_.barName),i.vertical(!!i.options_.vertical),i.enable(),i}return _(n,r),n.prototype.enabled=function(){return this.enabled_},n.prototype.enable=function(){this.enabled()||(this.on("mousedown",this.handleMouseDown),this.on("touchstart",this.handleMouseDown),this.on("focus",this.handleFocus),this.on("blur",this.handleBlur),this.on("click",this.handleClick),this.on(this.player_,"controlsvisible",this.update),this.playerEvent&&this.on(this.player_,this.playerEvent,this.update),this.removeClass("disabled"),this.setAttribute("tabindex",0),this.enabled_=!0)},n.prototype.disable=function(){if(this.enabled()){var t=this.bar.el_.ownerDocument;this.off("mousedown",this.handleMouseDown),this.off("touchstart",this.handleMouseDown),this.off("focus",this.handleFocus),this.off("blur",this.handleBlur),this.off("click",this.handleClick),this.off(this.player_,"controlsvisible",this.update),this.off(t,"mousemove",this.handleMouseMove),this.off(t,"mouseup",this.handleMouseUp),this.off(t,"touchmove",this.handleMouseMove),this.off(t,"touchend",this.handleMouseUp),this.removeAttribute("tabindex"),this.addClass("disabled"),this.playerEvent&&this.off(this.player_,this.playerEvent,this.update),this.enabled_=!1}},n.prototype.createEl=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};return e.className=e.className+" vjs-slider",e=C({tabIndex:0},e),i=C({role:"slider","aria-valuenow":0,"aria-valuemin":0,"aria-valuemax":100,tabIndex:0},i),r.prototype.createEl.call(this,t,e,i)},n.prototype.handleMouseDown=function(t){var e=this.bar.el_.ownerDocument;t.preventDefault(),X(),this.addClass("vjs-sliding"),this.trigger("slideractive"),this.on(e,"mousemove",this.handleMouseMove),this.on(e,"mouseup",this.handleMouseUp),this.on(e,"touchmove",this.handleMouseMove),this.on(e,"touchend",this.handleMouseUp),this.handleMouseMove(t)},n.prototype.handleMouseMove=function(t){},n.prototype.handleMouseUp=function(){var t=this.bar.el_.ownerDocument;Y(),this.removeClass("vjs-sliding"),this.trigger("sliderinactive"),this.off(t,"mousemove",this.handleMouseMove),this.off(t,"mouseup",this.handleMouseUp),this.off(t,"touchmove",this.handleMouseMove),this.off(t,"touchend",this.handleMouseUp),this.update()},n.prototype.update=function(){if(this.el_){var t=this.getPercent(),e=this.bar;if(e){("number"!=typeof t||t!=t||t<0||t===1/0)&&(t=0);var i=(100*t).toFixed(2)+"%",r=e.el().style;return this.vertical()?r.height=i:r.width=i,t}}},n.prototype.calculateDistance=function(t){var e=Q(this.el_,t);return this.vertical()?e.y:e.x},n.prototype.handleFocus=function(){this.on(this.bar.el_.ownerDocument,"keydown",this.handleKeyPress)},n.prototype.handleKeyPress=function(t){37===t.which||40===t.which?(t.preventDefault(),this.stepBack()):38!==t.which&&39!==t.which||(t.preventDefault(),this.stepForward())},n.prototype.handleBlur=function(){this.off(this.bar.el_.ownerDocument,"keydown",this.handleKeyPress)},n.prototype.handleClick=function(t){t.stopImmediatePropagation(),t.preventDefault()},n.prototype.vertical=function(t){if(void 0===t)return this.vertical_||!1;this.vertical_=!!t,this.vertical_?this.addClass("vjs-slider-vertical"):this.addClass("vjs-slider-horizontal")},n}(Xt);Xt.registerComponent("Slider",en);var rn=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.partEls_=[],i.on(t,"progress",i.update),i}return _(n,r),n.prototype.createEl=function(){return r.prototype.createEl.call(this,"div",{className:"vjs-load-progress",innerHTML:'<span class="vjs-control-text"><span>'+this.localize("Loaded")+"</span>: 0%</span>"})},n.prototype.dispose=function(){this.partEls_=null,r.prototype.dispose.call(this)},n.prototype.update=function(t){var e=this.player_.buffered(),i=this.player_.duration(),r=this.player_.bufferedEnd(),n=this.partEls_,s=function(t,e){var i=t/e||0;return 100*(1<=i?1:i)+"%"};this.el_.style.width=s(r,i);for(var a=0;a<e.length;a++){var o=e.start(a),u=e.end(a),l=n[a];l||(l=this.el_.appendChild(M()),n[a]=l),l.style.left=s(o,r),l.style.width=s(u-o,r)}for(var c=n.length;c>e.length;c--)this.el_.removeChild(n[c-1]);n.length=e.length},n}(Xt);Xt.registerComponent("LoadProgressBar",rn);var nn=function(t){function e(){return y(this,e),b(this,t.apply(this,arguments))}return _(e,t),e.prototype.createEl=function(){return t.prototype.createEl.call(this,"div",{className:"vjs-time-tooltip"})},e.prototype.update=function(t,e,i){var r=$(this.el_),n=$(this.player_.el()),s=t.width*e;if(n&&r){var a=t.left-n.left+s,o=t.width-s+(n.right-t.right),u=r.width/2;a<u?u+=u-a:o<u&&(u=o),u<0?u=0:u>r.width&&(u=r.width),this.el_.style.right="-"+u+"px",U(this.el_,i)}},e}(Xt);Xt.registerComponent("TimeTooltip",nn);var sn=function(t){function e(){return y(this,e),b(this,t.apply(this,arguments))}return _(e,t),e.prototype.createEl=function(){return t.prototype.createEl.call(this,"div",{className:"vjs-playOld-progress vjs-slider-bar",innerHTML:'<span class="vjs-control-text"><span>'+this.localize("Progress")+"</span>: 0%</span>"})},e.prototype.update=function(i,r){var n=this;this.rafId_&&this.cancelAnimationFrame(this.rafId_),this.rafId_=this.requestAnimationFrame(function(){var t=Yr(n.player_.scrubbing()?n.player_.getCache().currentTime:n.player_.currentTime(),n.player_.duration()),e=n.getChild("timeTooltip");e&&e.update(i,r,t)})},e}(Xt);sn.prototype.options_={children:[]},ne||ae||sn.prototype.options_.children.push("timeTooltip"),Xt.registerComponent("PlayProgressBar",sn);var an=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.update=xt(Ot(i,i.update),25),i}return _(n,r),n.prototype.createEl=function(){return r.prototype.createEl.call(this,"div",{className:"vjs-mouse-display"})},n.prototype.update=function(i,r){var n=this;this.rafId_&&this.cancelAnimationFrame(this.rafId_),this.rafId_=this.requestAnimationFrame(function(){var t=n.player_.duration(),e=Yr(r*t,t);n.el_.style.left=i.width*r+"px",n.getChild("timeTooltip").update(i,r,e)})},n}(Xt);an.prototype.options_={children:["timeTooltip"]},Xt.registerComponent("MouseTimeDisplay",an);var on=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.setEventHandlers_(),i}return _(n,r),n.prototype.setEventHandlers_=function(){var t=this;this.update=xt(Ot(this,this.update),30),this.on(this.player_,"timeupdate",this.update),this.on(this.player_,"ended",this.handleEnded),this.updateInterval=null,this.on(this.player_,["playing"],function(){t.clearInterval(t.updateInterval),t.updateInterval=t.setInterval(function(){t.requestAnimationFrame(function(){t.update()})},30)}),this.on(this.player_,["ended","pause","waiting"],function(){t.clearInterval(t.updateInterval)}),this.on(this.player_,["timeupdate","ended"],this.update)},n.prototype.createEl=function(){return r.prototype.createEl.call(this,"div",{className:"vjs-progress-holder"},{"aria-label":this.localize("Progress Bar")})},n.prototype.update_=function(t,e){var i=this.player_.duration();this.el_.setAttribute("aria-valuenow",(100*e).toFixed(2)),this.el_.setAttribute("aria-valuetext",this.localize("progress bar timing: currentTime={1} duration={2}",[Yr(t,i),Yr(i,i)],"{1} of {2}")),this.bar.update($(this.el_),e)},n.prototype.update=function(t){var e=r.prototype.update.call(this);return this.update_(this.getCurrentTime_(),e),e},n.prototype.getCurrentTime_=function(){return this.player_.scrubbing()?this.player_.getCache().currentTime:this.player_.currentTime()},n.prototype.handleEnded=function(t){this.update_(this.player_.duration(),1)},n.prototype.getPercent=function(){var t=this.getCurrentTime_()/this.player_.duration();return 1<=t?1:t||0},n.prototype.handleMouseDown=function(t){rt(t)&&(t.stopPropagation(),this.player_.scrubbing(!0),this.videoWasPlaying=!this.player_.paused(),this.player_.pause(),r.prototype.handleMouseDown.call(this,t))},n.prototype.handleMouseMove=function(t){if(rt(t)){var e=this.calculateDistance(t)*this.player_.duration();e===this.player_.duration()&&(e-=.1),this.player_.currentTime(e)}},n.prototype.enable=function(){r.prototype.enable.call(this);var t=this.getChild("mouseTimeDisplay");t&&t.show()},n.prototype.disable=function(){r.prototype.disable.call(this);var t=this.getChild("mouseTimeDisplay");t&&t.hide()},n.prototype.handleMouseUp=function(t){r.prototype.handleMouseUp.call(this,t),t&&t.stopPropagation(),this.player_.scrubbing(!1),this.player_.trigger({type:"timeupdate",target:this,manuallyTriggered:!0}),this.videoWasPlaying&&Ie(this.player_.play())},n.prototype.stepForward=function(){this.player_.currentTime(this.player_.currentTime()+5)},n.prototype.stepBack=function(){this.player_.currentTime(this.player_.currentTime()-5)},n.prototype.handleAction=function(t){this.player_.paused()?this.player_.play():this.player_.pause()},n.prototype.handleKeyPress=function(t){32===t.which||13===t.which?(t.preventDefault(),this.handleAction(t)):r.prototype.handleKeyPress&&r.prototype.handleKeyPress.call(this,t)},n}(en);on.prototype.options_={children:["loadProgressBar","playProgressBar"],barName:"playProgressBar"},ne||ae||on.prototype.options_.children.splice(1,0,"mouseTimeDisplay"),on.prototype.playerEvent="timeupdate",Xt.registerComponent("SeekBar",on);var un=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.handleMouseMove=xt(Ot(i,i.handleMouseMove),25),i.throttledHandleMouseSeek=xt(Ot(i,i.handleMouseSeek),25),i.enable(),i}return _(n,r),n.prototype.createEl=function(){return r.prototype.createEl.call(this,"div",{className:"vjs-progress-control vjs-control"})},n.prototype.handleMouseMove=function(t){var e=this.getChild("seekBar");if(e){var i=e.getChild("mouseTimeDisplay"),r=e.el(),n=$(r),s=Q(r,t).x;1<s?s=1:s<0&&(s=0),i&&i.update(n,s)}},n.prototype.handleMouseSeek=function(t){var e=this.getChild("seekBar");e&&e.handleMouseMove(t)},n.prototype.enabled=function(){return this.enabled_},n.prototype.disable=function(){this.children().forEach(function(t){return t.disable&&t.disable()}),this.enabled()&&(this.off(["mousedown","touchstart"],this.handleMouseDown),this.off(this.el_,"mousemove",this.handleMouseMove),this.handleMouseUp(),this.addClass("disabled"),this.enabled_=!1)},n.prototype.enable=function(){this.children().forEach(function(t){return t.enable&&t.enable()}),this.enabled()||(this.on(["mousedown","touchstart"],this.handleMouseDown),this.on(this.el_,"mousemove",this.handleMouseMove),this.removeClass("disabled"),this.enabled_=!0)},n.prototype.handleMouseDown=function(t){var e=this.el_.ownerDocument,i=this.getChild("seekBar");i&&i.handleMouseDown(t),this.on(e,"mousemove",this.throttledHandleMouseSeek),this.on(e,"touchmove",this.throttledHandleMouseSeek),this.on(e,"mouseup",this.handleMouseUp),this.on(e,"touchend",this.handleMouseUp)},n.prototype.handleMouseUp=function(t){var e=this.el_.ownerDocument,i=this.getChild("seekBar");i&&i.handleMouseUp(t),this.off(e,"mousemove",this.throttledHandleMouseSeek),this.off(e,"touchmove",this.throttledHandleMouseSeek),this.off(e,"mouseup",this.handleMouseUp),this.off(e,"touchend",this.handleMouseUp)},n}(Xt);un.prototype.options_={children:["seekBar"]},Xt.registerComponent("ProgressControl",un);var ln=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.on(t,"fullscreenchange",i.handleFullscreenChange),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-fullscreen-control "+r.prototype.buildCSSClass.call(this)},n.prototype.handleFullscreenChange=function(t){this.player_.isFullscreen()?this.controlText("Non-Fullscreen"):this.controlText("Fullscreen")},n.prototype.handleClick=function(t){this.player_.isFullscreen()?this.player_.exitFullscreen():this.player_.requestFullscreen()},n}(Vr);ln.prototype.controlText_="Fullscreen",Xt.registerComponent("FullscreenToggle",ln);var cn=function(t,e){e.tech_&&!e.tech_.featuresVolumeControl&&t.addClass("vjs-hidden"),t.on(e,"loadstart",function(){e.tech_.featuresVolumeControl?t.removeClass("vjs-hidden"):t.addClass("vjs-hidden")})},hn=function(t){function e(){return y(this,e),b(this,t.apply(this,arguments))}return _(e,t),e.prototype.createEl=function(){return t.prototype.createEl.call(this,"div",{className:"vjs-volume-level",innerHTML:'<span class="vjs-control-text"></span>'})},e}(Xt);Xt.registerComponent("VolumeLevel",hn);var dn=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.on("slideractive",i.updateLastVolume_),i.on(t,"volumechange",i.updateARIAAttributes),t.ready(function(){return i.updateARIAAttributes()}),i}return _(n,r),n.prototype.createEl=function(){return r.prototype.createEl.call(this,"div",{className:"vjs-volume-bar vjs-slider-bar"},{"aria-label":this.localize("Volume Level"),"aria-live":"polite"})},n.prototype.handleMouseDown=function(t){rt(t)&&r.prototype.handleMouseDown.call(this,t)},n.prototype.handleMouseMove=function(t){rt(t)&&(this.checkMuted(),this.player_.volume(this.calculateDistance(t)))},n.prototype.checkMuted=function(){this.player_.muted()&&this.player_.muted(!1)},n.prototype.getPercent=function(){return this.player_.muted()?0:this.player_.volume()},n.prototype.stepForward=function(){this.checkMuted(),this.player_.volume(this.player_.volume()+.1)},n.prototype.stepBack=function(){this.checkMuted(),this.player_.volume(this.player_.volume()-.1)},n.prototype.updateARIAAttributes=function(t){var e=this.player_.muted()?0:this.volumeAsPercentage_();this.el_.setAttribute("aria-valuenow",e),this.el_.setAttribute("aria-valuetext",e+"%")},n.prototype.volumeAsPercentage_=function(){return Math.round(100*this.player_.volume())},n.prototype.updateLastVolume_=function(){var t=this,e=this.player_.volume();this.one("sliderinactive",function(){0===t.player_.volume()&&t.player_.lastVolume_(e)})},n}(en);dn.prototype.options_={children:["volumeLevel"],barName:"volumeLevel"},dn.prototype.playerEvent="volumechange",Xt.registerComponent("VolumeBar",dn);var pn=function(r){function n(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};y(this,n),e.vertical=e.vertical||!1,("undefined"==typeof e.volumeBar||w(e.volumeBar))&&(e.volumeBar=e.volumeBar||{},e.volumeBar.vertical=e.vertical);var i=b(this,r.call(this,t,e));return cn(i,t),i.throttledHandleMouseMove=xt(Ot(i,i.handleMouseMove),25),i.on("mousedown",i.handleMouseDown),i.on("touchstart",i.handleMouseDown),i.on(i.volumeBar,["focus","slideractive"],function(){i.volumeBar.addClass("vjs-slider-active"),i.addClass("vjs-slider-active"),i.trigger("slideractive")}),i.on(i.volumeBar,["blur","sliderinactive"],function(){i.volumeBar.removeClass("vjs-slider-active"),i.removeClass("vjs-slider-active"),i.trigger("sliderinactive")}),i}return _(n,r),n.prototype.createEl=function(){var t="vjs-volume-horizontal";return this.options_.vertical&&(t="vjs-volume-vertical"),r.prototype.createEl.call(this,"div",{className:"vjs-volume-control vjs-control "+t})},n.prototype.handleMouseDown=function(t){var e=this.el_.ownerDocument;this.on(e,"mousemove",this.throttledHandleMouseMove),this.on(e,"touchmove",this.throttledHandleMouseMove),this.on(e,"mouseup",this.handleMouseUp),this.on(e,"touchend",this.handleMouseUp)},n.prototype.handleMouseUp=function(t){var e=this.el_.ownerDocument;this.off(e,"mousemove",this.throttledHandleMouseMove),this.off(e,"touchmove",this.throttledHandleMouseMove),this.off(e,"mouseup",this.handleMouseUp),this.off(e,"touchend",this.handleMouseUp)},n.prototype.handleMouseMove=function(t){this.volumeBar.handleMouseMove(t)},n}(Xt);pn.prototype.options_={children:["volumeBar"]},Xt.registerComponent("VolumeControl",pn);var fn=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return cn(i,t),i.on(t,["loadstart","volumechange"],i.update),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-mute-control "+r.prototype.buildCSSClass.call(this)},n.prototype.handleClick=function(t){var e=this.player_.volume(),i=this.player_.lastVolume_();if(0===e){var r=i<.1?.1:i;this.player_.volume(r),this.player_.muted(!1)}else this.player_.muted(!this.player_.muted())},n.prototype.update=function(t){this.updateIcon_(),this.updateControlText_()},n.prototype.updateIcon_=function(){var t=this.player_.volume(),e=3;0===t||this.player_.muted()?e=0:t<.33?e=1:t<.67&&(e=2);for(var i=0;i<4;i++)F(this.el_,"vjs-vol-"+i);j(this.el_,"vjs-vol-"+e)},n.prototype.updateControlText_=function(){var t=this.player_.muted()||0===this.player_.volume()?"Unmute":"Mute";this.controlText()!==t&&this.controlText(t)},n}(Vr);fn.prototype.controlText_="Mute",Xt.registerComponent("MuteToggle",fn);var mn=function(r){function n(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};y(this,n),"undefined"!=typeof e.inline?e.inline=e.inline:e.inline=!0,("undefined"==typeof e.volumeControl||w(e.volumeControl))&&(e.volumeControl=e.volumeControl||{},e.volumeControl.vertical=!e.inline);var i=b(this,r.call(this,t,e));return cn(i,t),i.on(i.volumeControl,["slideractive"],i.sliderActive_),i.on(i.volumeControl,["sliderinactive"],i.sliderInactive_),i}return _(n,r),n.prototype.sliderActive_=function(){this.addClass("vjs-slider-active")},n.prototype.sliderInactive_=function(){this.removeClass("vjs-slider-active")},n.prototype.createEl=function(){var t="vjs-volume-panel-horizontal";return this.options_.inline||(t="vjs-volume-panel-vertical"),r.prototype.createEl.call(this,"div",{className:"vjs-volume-panel vjs-control "+t})},n}(Xt);mn.prototype.options_={children:["muteToggle","volumeControl"]},Xt.registerComponent("VolumePanel",mn);var gn=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return e&&(i.menuButton_=e.menuButton),i.focusedChild_=-1,i.on("keydown",i.handleKeyPress),i}return _(n,r),n.prototype.addItem=function(e){this.addChild(e),e.on("click",Ot(this,function(t){this.menuButton_&&(this.menuButton_.unpressButton(),"CaptionSettingsMenuItem"!==e.name()&&this.menuButton_.focus())}))},n.prototype.createEl=function(){var t=this.options_.contentElType||"ul";this.contentEl_=M(t,{className:"vjs-menu-content"}),this.contentEl_.setAttribute("role","menu");var e=r.prototype.createEl.call(this,"div",{append:this.contentEl_,className:"vjs-menu"});return e.appendChild(this.contentEl_),_t(e,"click",function(t){t.preventDefault(),t.stopImmediatePropagation()}),e},n.prototype.dispose=function(){this.contentEl_=null,r.prototype.dispose.call(this)},n.prototype.handleKeyPress=function(t){37===t.which||40===t.which?(t.preventDefault(),this.stepForward()):38!==t.which&&39!==t.which||(t.preventDefault(),this.stepBack())},n.prototype.stepForward=function(){var t=0;void 0!==this.focusedChild_&&(t=this.focusedChild_+1),this.focus(t)},n.prototype.stepBack=function(){var t=0;void 0!==this.focusedChild_&&(t=this.focusedChild_-1),this.focus(t)},n.prototype.focus=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:0,e=this.children().slice();e.length&&e[0].className&&/vjs-menu-title/.test(e[0].className)&&e.shift(),0<e.length&&(t<0?t=0:t>=e.length&&(t=e.length-1),e[this.focusedChild_=t].el_.focus())},n}(Xt);Xt.registerComponent("Menu",gn);var yn=function(n){function s(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};y(this,s);var i=b(this,n.call(this,t,e));i.menuButton_=new Vr(t,e),i.menuButton_.controlText(i.controlText_),i.menuButton_.el_.setAttribute("aria-haspopup","true");var r=Vr.prototype.buildCSSClass();return i.menuButton_.el_.className=i.buildCSSClass()+" "+r,i.menuButton_.removeClass("vjs-control"),i.addChild(i.menuButton_),i.update(),i.enabled_=!0,i.on(i.menuButton_,"tap",i.handleClick),i.on(i.menuButton_,"click",i.handleClick),i.on(i.menuButton_,"focus",i.handleFocus),i.on(i.menuButton_,"blur",i.handleBlur),i.on("keydown",i.handleSubmenuKeyPress),i}return _(s,n),s.prototype.update=function(){var t=this.createMenu();this.menu&&(this.menu.dispose(),this.removeChild(this.menu)),this.menu=t,this.addChild(t),this.buttonPressed_=!1,this.menuButton_.el_.setAttribute("aria-expanded","false"),this.items&&this.items.length<=this.hideThreshold_?this.hide():this.show()},s.prototype.createMenu=function(){var t=new gn(this.player_,{menuButton:this});if(this.hideThreshold_=0,this.options_.title){var e=M("li",{className:"vjs-menu-title",innerHTML:zt(this.options_.title),tabIndex:-1});this.hideThreshold_+=1,t.children_.unshift(e),N(e,t.contentEl())}if(this.items=this.createItems(),this.items)for(var i=0;i<this.items.length;i++)t.addItem(this.items[i]);return t},s.prototype.createItems=function(){},s.prototype.createEl=function(){return n.prototype.createEl.call(this,"div",{className:this.buildWrapperCSSClass()},{})},s.prototype.buildWrapperCSSClass=function(){var t="vjs-menu-button";return!0===this.options_.inline?t+="-inline":t+="-popup","vjs-menu-button "+t+" "+Vr.prototype.buildCSSClass()+" "+n.prototype.buildCSSClass.call(this)},s.prototype.buildCSSClass=function(){var t="vjs-menu-button";return!0===this.options_.inline?t+="-inline":t+="-popup","vjs-menu-button "+t+" "+n.prototype.buildCSSClass.call(this)},s.prototype.controlText=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:this.menuButton_.el();return this.menuButton_.controlText(t,e)},s.prototype.handleClick=function(t){this.one(this.menu.contentEl(),"mouseleave",Ot(this,function(t){this.unpressButton(),this.el_.blur()})),this.buttonPressed_?this.unpressButton():this.pressButton()},s.prototype.focus=function(){this.menuButton_.focus()},s.prototype.blur=function(){this.menuButton_.blur()},s.prototype.handleFocus=function(){_t(p,"keydown",Ot(this,this.handleKeyPress))},s.prototype.handleBlur=function(){bt(p,"keydown",Ot(this,this.handleKeyPress))},s.prototype.handleKeyPress=function(t){27===t.which||9===t.which?(this.buttonPressed_&&this.unpressButton(),9!==t.which&&(t.preventDefault(),this.menuButton_.el_.focus())):38!==t.which&&40!==t.which||this.buttonPressed_||(this.pressButton(),t.preventDefault())},s.prototype.handleSubmenuKeyPress=function(t){27!==t.which&&9!==t.which||(this.buttonPressed_&&this.unpressButton(),9!==t.which&&(t.preventDefault(),this.menuButton_.el_.focus()))},s.prototype.pressButton=function(){if(this.enabled_){if(this.buttonPressed_=!0,this.menu.lockShowing(),this.menuButton_.el_.setAttribute("aria-expanded","true"),ne&&D())return;this.menu.focus()}},s.prototype.unpressButton=function(){this.enabled_&&(this.buttonPressed_=!1,this.menu.unlockShowing(),this.menuButton_.el_.setAttribute("aria-expanded","false"))},s.prototype.disable=function(){this.unpressButton(),this.enabled_=!1,this.addClass("vjs-disabled"),this.menuButton_.disable()},s.prototype.enable=function(){this.enabled_=!0,this.removeClass("vjs-disabled"),this.menuButton_.enable()},s}(Xt);Xt.registerComponent("MenuButton",yn);var vn=function(s){function a(t,e){y(this,a);var i=e.tracks,r=b(this,s.call(this,t,e));if(r.items.length<=1&&r.hide(),!i)return b(r);var n=Ot(r,r.update);return i.addEventListener("removetrack",n),i.addEventListener("addtrack",n),r.player_.on("ready",n),r.player_.on("dispose",function(){i.removeEventListener("removetrack",n),i.removeEventListener("addtrack",n)}),r}return _(a,s),a}(yn);Xt.registerComponent("TrackButton",vn);var _n=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.selectable=e.selectable,i.isSelected_=e.selected||!1,i.selected(i.isSelected_),i.selectable?i.el_.setAttribute("role","menuitemcheckbox"):i.el_.setAttribute("role","menuitem"),i}return _(n,r),n.prototype.createEl=function(t,e,i){return this.nonIconControl=!0,r.prototype.createEl.call(this,"li",C({className:"vjs-menu-item",innerHTML:'<span class="vjs-menu-item-text">'+this.localize(this.options_.label)+"</span>",tabIndex:-1},e),i)},n.prototype.handleClick=function(t){this.selected(!0)},n.prototype.selected=function(t){this.selectable&&(t?(this.addClass("vjs-selected"),this.el_.setAttribute("aria-checked","true"),this.controlText(", selected"),this.isSelected_=!0):(this.removeClass("vjs-selected"),this.el_.setAttribute("aria-checked","false"),this.controlText(""),this.isSelected_=!1))},n}(Rr);Xt.registerComponent("MenuItem",_n);var bn=function(u){function l(t,e){y(this,l);var i=e.track,r=t.textTracks();e.label=i.label||i.language||"Unknown",e.selected="showing"===i.mode;var n=b(this,u.call(this,t,e));n.track=i;var s=function(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];n.handleTracksChange.apply(n,e)},a=function(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];n.handleSelectedLanguageChange.apply(n,e)};if(t.on(["loadstart","texttrackchange"],s),r.addEventListener("change",s),r.addEventListener("selectedlanguagechange",a),n.on("dispose",function(){t.off(["loadstart","texttrackchange"],s),r.removeEventListener("change",s),r.removeEventListener("selectedlanguagechange",a)}),void 0===r.onchange){var o=void 0;n.on(["tap","click"],function(){if("object"!==v(g.Event))try{o=new g.Event("change")}catch(t){}o||(o=p.createEvent("Event")).initEvent("change",!0,!0),r.dispatchEvent(o)})}return n.handleTracksChange(),n}return _(l,u),l.prototype.handleClick=function(t){var e=this.track.kind,i=this.track.kinds,r=this.player_.textTracks();if(i||(i=[e]),u.prototype.handleClick.call(this,t),r)for(var n=0;n<r.length;n++){var s=r[n];s===this.track&&-1<i.indexOf(s.kind)?"showing"!==s.mode&&(s.mode="showing"):"disabled"!==s.mode&&(s.mode="disabled")}},l.prototype.handleTracksChange=function(t){var e="showing"===this.track.mode;e!==this.isSelected_&&this.selected(e)},l.prototype.handleSelectedLanguageChange=function(t){if("showing"===this.track.mode){var e=this.player_.cache_.selectedLanguage;if(e&&e.enabled&&e.language===this.track.language&&e.kind!==this.track.kind)return;this.player_.cache_.selectedLanguage={enabled:!0,language:this.track.language,kind:this.track.kind}}},l.prototype.dispose=function(){this.track=null,u.prototype.dispose.call(this)},l}(_n);Xt.registerComponent("TextTrackMenuItem",bn);var Tn=function(i){function r(t,e){return y(this,r),e.track={player:t,kind:e.kind,kinds:e.kinds,default:!1,mode:"disabled"},e.kinds||(e.kinds=[e.kind]),e.label?e.track.label=e.label:e.track.label=e.kinds.join(" and ")+" off",e.selectable=!0,b(this,i.call(this,t,e))}return _(r,i),r.prototype.handleTracksChange=function(t){for(var e=this.player().textTracks(),i=!0,r=0,n=e.length;r<n;r++){var s=e[r];if(-1<this.options_.kinds.indexOf(s.kind)&&"showing"===s.mode){i=!1;break}}i!==this.isSelected_&&this.selected(i)},r.prototype.handleSelectedLanguageChange=function(t){for(var e=this.player().textTracks(),i=!0,r=0,n=e.length;r<n;r++){var s=e[r];if(-1<["captions","descriptions","subtitles"].indexOf(s.kind)&&"showing"===s.mode){i=!1;break}}i&&(this.player_.cache_.selectedLanguage={enabled:!1})},r}(bn);Xt.registerComponent("OffTextTrackMenuItem",Tn);var Sn=function(i){function r(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return y(this,r),e.tracks=t.textTracks(),b(this,i.call(this,t,e))}return _(r,i),r.prototype.createItems=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[],e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:bn,i=void 0;this.label_&&(i=this.label_+" off"),t.push(new Tn(this.player_,{kinds:this.kinds_,kind:this.kind_,label:i})),this.hideThreshold_+=1;var r=this.player_.textTracks();Array.isArray(this.kinds_)||(this.kinds_=[this.kind_]);for(var n=0;n<r.length;n++){var s=r[n];if(-1<this.kinds_.indexOf(s.kind)){var a=new e(this.player_,{track:s,selectable:!0});a.addClass("vjs-"+s.kind+"-menu-item"),t.push(a)}}return t},r}(vn);Xt.registerComponent("TextTrackButton",Sn);var kn=function(a){function o(t,e){y(this,o);var i=e.track,r=e.cue,n=t.currentTime();e.selectable=!0,e.label=r.text,e.selected=r.startTime<=n&&n<r.endTime;var s=b(this,a.call(this,t,e));return s.track=i,s.cue=r,i.addEventListener("cuechange",Ot(s,s.update)),s}return _(o,a),o.prototype.handleClick=function(t){a.prototype.handleClick.call(this),this.player_.currentTime(this.cue.startTime),this.update(this.cue.startTime)},o.prototype.update=function(t){var e=this.cue,i=this.player_.currentTime();this.selected(e.startTime<=i&&i<e.endTime)},o}(_n);Xt.registerComponent("ChaptersTrackMenuItem",kn);var Cn=function(r){function n(t,e,i){return y(this,n),b(this,r.call(this,t,e,i))}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-chapters-button "+r.prototype.buildCSSClass.call(this)},n.prototype.buildWrapperCSSClass=function(){return"vjs-chapters-button "+r.prototype.buildWrapperCSSClass.call(this)},n.prototype.update=function(t){this.track_&&(!t||"addtrack"!==t.type&&"removetrack"!==t.type)||this.setTrack(this.findChaptersTrack()),r.prototype.update.call(this)},n.prototype.setTrack=function(t){if(this.track_!==t){if(this.updateHandler_||(this.updateHandler_=this.update.bind(this)),this.track_){var e=this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_);e&&e.removeEventListener("load",this.updateHandler_),this.track_=null}if(this.track_=t,this.track_){this.track_.mode="hidden";var i=this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_);i&&i.addEventListener("load",this.updateHandler_)}}},n.prototype.findChaptersTrack=function(){for(var t=this.player_.textTracks()||[],e=t.length-1;0<=e;e--){var i=t[e];if(i.kind===this.kind_)return i}},n.prototype.getMenuCaption=function(){return this.track_&&this.track_.label?this.track_.label:this.localize(zt(this.kind_))},n.prototype.createMenu=function(){return this.options_.title=this.getMenuCaption(),r.prototype.createMenu.call(this)},n.prototype.createItems=function(){var t=[];if(!this.track_)return t;var e=this.track_.cues;if(!e)return t;for(var i=0,r=e.length;i<r;i++){var n=e[i],s=new kn(this.player_,{track:this.track_,cue:n});t.push(s)}return t},n}(Sn);Cn.prototype.kind_="chapters",Cn.prototype.controlText_="Chapters",Xt.registerComponent("ChaptersButton",Cn);var En=function(a){function o(t,e,i){y(this,o);var r=b(this,a.call(this,t,e,i)),n=t.textTracks(),s=Ot(r,r.handleTracksChange);return n.addEventListener("change",s),r.on("dispose",function(){n.removeEventListener("change",s)}),r}return _(o,a),o.prototype.handleTracksChange=function(t){for(var e=this.player().textTracks(),i=!1,r=0,n=e.length;r<n;r++){var s=e[r];if(s.kind!==this.kind_&&"showing"===s.mode){i=!0;break}}i?this.disable():this.enable()},o.prototype.buildCSSClass=function(){return"vjs-descriptions-button "+a.prototype.buildCSSClass.call(this)},o.prototype.buildWrapperCSSClass=function(){return"vjs-descriptions-button "+a.prototype.buildWrapperCSSClass.call(this)},o}(Sn);En.prototype.kind_="descriptions",En.prototype.controlText_="Descriptions",Xt.registerComponent("DescriptionsButton",En);var wn=function(r){function n(t,e,i){return y(this,n),b(this,r.call(this,t,e,i))}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-subtitles-button "+r.prototype.buildCSSClass.call(this)},n.prototype.buildWrapperCSSClass=function(){return"vjs-subtitles-button "+r.prototype.buildWrapperCSSClass.call(this)},n}(Sn);wn.prototype.kind_="subtitles",wn.prototype.controlText_="Subtitles",Xt.registerComponent("SubtitlesButton",wn);var An=function(r){function n(t,e){y(this,n),e.track={player:t,kind:e.kind,label:e.kind+" settings",selectable:!1,default:!1,mode:"disabled"},e.selectable=!1,e.name="CaptionSettingsMenuItem";var i=b(this,r.call(this,t,e));return i.addClass("vjs-texttrack-settings"),i.controlText(", opens "+e.kind+" settings dialog"),i}return _(n,r),n.prototype.handleClick=function(t){this.player().getChild("textTrackSettings").open()},n}(bn);Xt.registerComponent("CaptionSettingsMenuItem",An);var Ln=function(r){function n(t,e,i){return y(this,n),b(this,r.call(this,t,e,i))}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-captions-button "+r.prototype.buildCSSClass.call(this)},n.prototype.buildWrapperCSSClass=function(){return"vjs-captions-button "+r.prototype.buildWrapperCSSClass.call(this)},n.prototype.createItems=function(){var t=[];return this.player().tech_&&this.player().tech_.featuresNativeTextTracks||!this.player().getChild("textTrackSettings")||(t.push(new An(this.player_,{kind:this.kind_})),this.hideThreshold_+=1),r.prototype.createItems.call(this,t)},n}(Sn);Ln.prototype.kind_="captions",Ln.prototype.controlText_="Captions",Xt.registerComponent("CaptionsButton",Ln);var Pn=function(n){function t(){return y(this,t),b(this,n.apply(this,arguments))}return _(t,n),t.prototype.createEl=function(t,e,i){var r='<span class="vjs-menu-item-text">'+this.localize(this.options_.label);return"captions"===this.options_.track.kind&&(r+='\n <span aria-hidden="true" class="vjs-icon-placeholder"></span>\n <span class="vjs-control-text"> '+this.localize("Captions")+"</span>\n "),r+="</span>",n.prototype.createEl.call(this,t,C({innerHTML:r},e),i)},t}(bn);Xt.registerComponent("SubsCapsMenuItem",Pn);var On=function(r){function n(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};y(this,n);var i=b(this,r.call(this,t,e));return i.label_="subtitles",-1<["en","en-us","en-ca","fr-ca"].indexOf(i.player_.language_)&&(i.label_="captions"),i.menuButton_.controlText(zt(i.label_)),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-subs-caps-button "+r.prototype.buildCSSClass.call(this)},n.prototype.buildWrapperCSSClass=function(){return"vjs-subs-caps-button "+r.prototype.buildWrapperCSSClass.call(this)},n.prototype.createItems=function(){var t=[];return this.player().tech_&&this.player().tech_.featuresNativeTextTracks||!this.player().getChild("textTrackSettings")||(t.push(new An(this.player_,{kind:this.label_})),this.hideThreshold_+=1),t=r.prototype.createItems.call(this,t,Pn)},n}(Sn);On.prototype.kinds_=["captions","subtitles"],On.prototype.controlText_="Subtitles",Xt.registerComponent("SubsCapsButton",On);var xn=function(a){function o(t,e){y(this,o);var i=e.track,r=t.audioTracks();e.label=i.label||i.language||"Unknown",e.selected=i.enabled;var n=b(this,a.call(this,t,e));n.track=i;var s=function(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];n.handleTracksChange.apply(n,e)};return r.addEventListener("change",s),n.on("dispose",function(){r.removeEventListener("change",s)}),n}return _(o,a),o.prototype.handleClick=function(t){var e=this.player_.audioTracks();a.prototype.handleClick.call(this,t);for(var i=0;i<e.length;i++){var r=e[i];r.enabled=r===this.track}},o.prototype.handleTracksChange=function(t){this.selected(this.track.enabled)},o}(_n);Xt.registerComponent("AudioTrackMenuItem",xn);var In=function(i){function r(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return y(this,r),e.tracks=t.audioTracks(),b(this,i.call(this,t,e))}return _(r,i),r.prototype.buildCSSClass=function(){return"vjs-audio-button "+i.prototype.buildCSSClass.call(this)},r.prototype.buildWrapperCSSClass=function(){return"vjs-audio-button "+i.prototype.buildWrapperCSSClass.call(this)},r.prototype.createItems=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:[];this.hideThreshold_=1;for(var e=this.player_.audioTracks(),i=0;i<e.length;i++){var r=e[i];t.push(new xn(this.player_,{track:r,selectable:!0}))}return t},r}(vn);In.prototype.controlText_="Audio Track",Xt.registerComponent("AudioTrackButton",In);var Dn=function(s){function a(t,e){y(this,a);var i=e.rate,r=parseFloat(i,10);e.label=i,e.selected=1===r,e.selectable=!0;var n=b(this,s.call(this,t,e));return n.label=i,n.rate=r,n.on(t,"ratechange",n.update),n}return _(a,s),a.prototype.handleClick=function(t){s.prototype.handleClick.call(this),this.player().playbackRate(this.rate)},a.prototype.update=function(t){this.selected(this.player().playbackRate()===this.rate)},a}(_n);Dn.prototype.contentElType="button",Xt.registerComponent("PlaybackRateMenuItem",Dn);var Rn=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.updateVisibility(),i.updateLabel(),i.on(t,"loadstart",i.updateVisibility),i.on(t,"ratechange",i.updateLabel),i}return _(n,r),n.prototype.createEl=function(){var t=r.prototype.createEl.call(this);return this.labelEl_=M("div",{className:"vjs-playback-rate-value",innerHTML:"1x"}),t.appendChild(this.labelEl_),t},n.prototype.dispose=function(){this.labelEl_=null,r.prototype.dispose.call(this)},n.prototype.buildCSSClass=function(){return"vjs-playback-rate "+r.prototype.buildCSSClass.call(this)},n.prototype.buildWrapperCSSClass=function(){return"vjs-playback-rate "+r.prototype.buildWrapperCSSClass.call(this)},n.prototype.createMenu=function(){var t=new gn(this.player()),e=this.playbackRates();if(e)for(var i=e.length-1;0<=i;i--)t.addChild(new Dn(this.player(),{rate:e[i]+"x"}));return t},n.prototype.updateARIAAttributes=function(){this.el().setAttribute("aria-valuenow",this.player().playbackRate())},n.prototype.handleClick=function(t){for(var e=this.player().playbackRate(),i=this.playbackRates(),r=i[0],n=0;n<i.length;n++)if(i[n]>e){r=i[n];break}this.player().playbackRate(r)},n.prototype.playbackRates=function(){return this.options_.playbackRates||this.options_.playerOptions&&this.options_.playerOptions.playbackRates},n.prototype.playbackRateSupported=function(){return this.player().tech_&&this.player().tech_.featuresPlaybackRate&&this.playbackRates()&&0<this.playbackRates().length},n.prototype.updateVisibility=function(t){this.playbackRateSupported()?this.removeClass("vjs-hidden"):this.addClass("vjs-hidden")},n.prototype.updateLabel=function(t){this.playbackRateSupported()&&(this.labelEl_.innerHTML=this.player().playbackRate()+"x")},n}(yn);Rn.prototype.controlText_="Playback Rate",Xt.registerComponent("PlaybackRateMenuButton",Rn);var Mn=function(t){function e(){return y(this,e),b(this,t.apply(this,arguments))}return _(e,t),e.prototype.buildCSSClass=function(){return"vjs-spacer "+t.prototype.buildCSSClass.call(this)},e.prototype.createEl=function(){return t.prototype.createEl.call(this,"div",{className:this.buildCSSClass()})},e}(Xt);Xt.registerComponent("Spacer",Mn);var Un=function(e){function t(){return y(this,t),b(this,e.apply(this,arguments))}return _(t,e),t.prototype.buildCSSClass=function(){return"vjs-custom-control-spacer "+e.prototype.buildCSSClass.call(this)},t.prototype.createEl=function(){var t=e.prototype.createEl.call(this,{className:this.buildCSSClass()});return t.innerHTML=" ",t},t}(Mn);Xt.registerComponent("CustomControlSpacer",Un);var Nn=function(t){function e(){return y(this,e),b(this,t.apply(this,arguments))}return _(e,t),e.prototype.createEl=function(){return t.prototype.createEl.call(this,"div",{className:"vjs-control-bar",dir:"ltr"})},e}(Xt);Nn.prototype.options_={children:["playToggle","volumePanel","currentTimeDisplay","timeDivider","durationDisplay","progressControl","liveDisplay","remainingTimeDisplay","customControlSpacer","playbackRateMenuButton","chaptersButton","descriptionsButton","subsCapsButton","audioTrackButton","fullscreenToggle"]},Xt.registerComponent("ControlBar",Nn);var Bn=function(r){function n(t,e){y(this,n);var i=b(this,r.call(this,t,e));return i.on(t,"error",i.open),i}return _(n,r),n.prototype.buildCSSClass=function(){return"vjs-error-display "+r.prototype.buildCSSClass.call(this)},n.prototype.content=function(){var t=this.player().error();return t?this.localize(t.message):""},n}(Ne);Bn.prototype.options_=Gt(Ne.prototype.options_,{pauseOnOpen:!1,fillAlways:!0,temporary:!1,uncloseable:!0}),Xt.registerComponent("ErrorDisplay",Bn);var jn="vjs-text-track-settings",Fn=["#000","Black"],Hn=["#00F","Blue"],Vn=["#0FF","Cyan"],qn=["#0F0","Green"],Wn=["#F0F","Magenta"],zn=["#F00","Red"],Gn=["#FFF","White"],Xn=["#FF0","Yellow"],Yn=["1","Opaque"],$n=["0.5","Semi-Transparent"],Kn=["0","Transparent"],Qn={backgroundColor:{selector:".vjs-bg-color > select",id:"captions-background-color-%s",label:"Color",options:[Fn,Gn,zn,qn,Hn,Xn,Wn,Vn]},backgroundOpacity:{selector:".vjs-bg-opacity > select",id:"captions-background-opacity-%s",label:"Transparency",options:[Yn,$n,Kn]},color:{selector:".vjs-fg-color > select",id:"captions-foreground-color-%s",label:"Color",options:[Gn,Fn,zn,qn,Hn,Xn,Wn,Vn]},edgeStyle:{selector:".vjs-edge-style > select",id:"%s",label:"Text Edge Style",options:[["none","None"],["raised","Raised"],["depressed","Depressed"],["uniform","Uniform"],["dropshadow","Dropshadow"]]},fontFamily:{selector:".vjs-font-family > select",id:"captions-font-family-%s",label:"Font Family",options:[["proportionalSansSerif","Proportional Sans-Serif"],["monospaceSansSerif","Monospace Sans-Serif"],["proportionalSerif","Proportional Serif"],["monospaceSerif","Monospace Serif"],["casual","Casual"],["script","Script"],["small-caps","Small Caps"]]},fontPercent:{selector:".vjs-font-percent > select",id:"captions-font-size-%s",label:"Font Size",options:[["0.50","50%"],["0.75","75%"],["1.00","100%"],["1.25","125%"],["1.50","150%"],["1.75","175%"],["2.00","200%"],["3.00","300%"],["4.00","400%"]],default:2,parser:function(t){return"1.00"===t?null:Number(t)}},textOpacity:{selector:".vjs-text-opacity > select",id:"captions-foreground-opacity-%s",label:"Transparency",options:[Yn,$n]},windowColor:{selector:".vjs-window-color > select",id:"captions-window-color-%s",label:"Color"},windowOpacity:{selector:".vjs-window-opacity > select",id:"captions-window-opacity-%s",label:"Transparency",options:[Kn,$n,Yn]}};function Jn(t,e){if(e&&(t=e(t)),t&&"none"!==t)return t}Qn.windowColor.options=Qn.backgroundColor.options;var Zn=function(r){function n(t,e){y(this,n),e.temporary=!1;var i=b(this,r.call(this,t,e));return i.updateDisplay=Ot(i,i.updateDisplay),i.fill(),i.hasBeenOpened_=i.hasBeenFilled_=!0,i.endDialog=M("p",{className:"vjs-control-text",textContent:i.localize("End of dialog window.")}),i.el().appendChild(i.endDialog),i.setDefaults(),void 0===e.persistTextTrackSettings&&(i.options_.persistTextTrackSettings=i.options_.playerOptions.persistTextTrackSettings),i.on(i.$(".vjs-done-button"),"click",function(){i.saveSettings(),i.close()}),i.on(i.$(".vjs-default-button"),"click",function(){i.setDefaults(),i.updateDisplay()}),k(Qn,function(t){i.on(i.$(t.selector),"change",i.updateDisplay)}),i.options_.persistTextTrackSettings&&i.restoreSettings(),i}return _(n,r),n.prototype.dispose=function(){this.endDialog=null,r.prototype.dispose.call(this)},n.prototype.createElSelect_=function(t){var i=this,e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:"",r=2<arguments.length&&void 0!==arguments[2]?arguments[2]:"label",n=Qn[t],s=n.id.replace("%s",this.id_),a=[e,s].join(" ").trim();return["<"+r+' id="'+s+'" class="'+("label"===r?"vjs-label":"")+'">',this.localize(n.label),"</"+r+">",'<select aria-labelledby="'+a+'">'].concat(n.options.map(function(t){var e=s+"-"+t[1].replace(/\W+/g,"");return['<option id="'+e+'" value="'+t[0]+'" ','aria-labelledby="'+a+" "+e+'">',i.localize(t[1]),"</option>"].join("")})).concat("</select>").join("")},n.prototype.createElFgColor_=function(){var t="captions-text-legend-"+this.id_;return['<fieldset class="vjs-fg-color vjs-track-setting">','<legend id="'+t+'">',this.localize("Text"),"</legend>",this.createElSelect_("color",t),'<span class="vjs-text-opacity vjs-opacity">',this.createElSelect_("textOpacity",t),"</span>","</fieldset>"].join("")},n.prototype.createElBgColor_=function(){var t="captions-background-"+this.id_;return['<fieldset class="vjs-bg-color vjs-track-setting">','<legend id="'+t+'">',this.localize("Background"),"</legend>",this.createElSelect_("backgroundColor",t),'<span class="vjs-bg-opacity vjs-opacity">',this.createElSelect_("backgroundOpacity",t),"</span>","</fieldset>"].join("")},n.prototype.createElWinColor_=function(){var t="captions-window-"+this.id_;return['<fieldset class="vjs-window-color vjs-track-setting">','<legend id="'+t+'">',this.localize("Window"),"</legend>",this.createElSelect_("windowColor",t),'<span class="vjs-window-opacity vjs-opacity">',this.createElSelect_("windowOpacity",t),"</span>","</fieldset>"].join("")},n.prototype.createElColors_=function(){return M("div",{className:"vjs-track-settings-colors",innerHTML:[this.createElFgColor_(),this.createElBgColor_(),this.createElWinColor_()].join("")})},n.prototype.createElFont_=function(){return M("div",{className:"vjs-track-settings-font",innerHTML:['<fieldset class="vjs-font-percent vjs-track-setting">',this.createElSelect_("fontPercent","","legend"),"</fieldset>",'<fieldset class="vjs-edge-style vjs-track-setting">',this.createElSelect_("edgeStyle","","legend"),"</fieldset>",'<fieldset class="vjs-font-family vjs-track-setting">',this.createElSelect_("fontFamily","","legend"),"</fieldset>"].join("")})},n.prototype.createElControls_=function(){var t=this.localize("restore all settings to the default values");return M("div",{className:"vjs-track-settings-controls",innerHTML:['<button class="vjs-default-button" title="'+t+'">',this.localize("Reset"),'<span class="vjs-control-text"> '+t+"</span>","</button>",'<button class="vjs-done-button">'+this.localize("Done")+"</button>"].join("")})},n.prototype.content=function(){return[this.createElColors_(),this.createElFont_(),this.createElControls_()]},n.prototype.label=function(){return this.localize("Caption Settings Dialog")},n.prototype.description=function(){return this.localize("Beginning of dialog window. Escape will cancel and close the window.")},n.prototype.buildCSSClass=function(){return r.prototype.buildCSSClass.call(this)+" vjs-text-track-settings"},n.prototype.getValues=function(){var a=this;return function(i,r){var t=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0;return S(i).reduce(function(t,e){return r(t,i[e],e)},t)}(Qn,function(t,e,i){var r,n,s=(r=a.$(e.selector),n=e.parser,Jn(r.options[r.options.selectedIndex].value,n));return void 0!==s&&(t[i]=s),t},{})},n.prototype.setValues=function(i){var r=this;k(Qn,function(t,e){!function(t,e,i){if(e)for(var r=0;r<t.options.length;r++)if(Jn(t.options[r].value,i)===e){t.selectedIndex=r;break}}(r.$(t.selector),i[e],t.parser)})},n.prototype.setDefaults=function(){var i=this;k(Qn,function(t){var e=t.hasOwnProperty("default")?t.default:0;i.$(t.selector).selectedIndex=e})},n.prototype.restoreSettings=function(){var t=void 0;try{t=JSON.parse(g.localStorage.getItem(jn))}catch(t){f.warn(t)}t&&this.setValues(t)},n.prototype.saveSettings=function(){if(this.options_.persistTextTrackSettings){var t=this.getValues();try{Object.keys(t).length?g.localStorage.setItem(jn,JSON.stringify(t)):g.localStorage.removeItem(jn)}catch(t){f.warn(t)}}},n.prototype.updateDisplay=function(){var t=this.player_.getChild("textTrackDisplay");t&&t.updateDisplay()},n.prototype.conditionalBlur_=function(){this.previouslyActiveEl_=null,this.off(p,"keydown",this.handleKeyDown);var t=this.player_.controlBar,e=t&&t.subsCapsButton,i=t&&t.captionsButton;e?e.focus():i&&i.focus()},n}(Ne);Xt.registerComponent("TextTrackSettings",Zn);var ts=function(s){function a(t,e){y(this,a);var i=e.ResizeObserver||g.ResizeObserver;null===e.ResizeObserver&&(i=!1);var r=Gt({createEl:!i},e),n=b(this,s.call(this,t,r));return n.ResizeObserver=e.ResizeObserver||g.ResizeObserver,n.loadListener_=null,n.resizeObserver_=null,n.debouncedHandler_=It(function(){n.resizeHandler()},100,!1,t),i?(n.resizeObserver_=new n.ResizeObserver(n.debouncedHandler_),n.resizeObserver_.observe(t.el())):(n.loadListener_=function(){n.el_.contentWindow&&_t(n.el_.contentWindow,"resize",n.debouncedHandler_),n.off("load",n.loadListener_)},n.on("load",n.loadListener_)),n}return _(a,s),a.prototype.createEl=function(){return s.prototype.createEl.call(this,"iframe",{className:"vjs-resize-manager"})},a.prototype.resizeHandler=function(){this.player_.trigger("playerresize")},a.prototype.dispose=function(){this.resizeObserver_&&(this.resizeObserver_.unobserve(this.player_.el()),this.resizeObserver_.disconnect()),this.el_&&this.el_.contentWindow&&bt(this.el_.contentWindow,"resize",this.debouncedHandler_),this.loadListener_&&this.off("load",this.loadListener_),this.ResizeObserver=null,this.resizeObserver=null,this.debouncedHandler_=null,this.loadListener_=null},a}(Xt);Xt.registerComponent("ResizeManager",ts);var es=function(t){var e=t.el();if(e.hasAttribute("src"))return t.triggerSourceset(e.src),!0;var i=t.$$("source"),r=[],n="";if(!i.length)return!1;for(var s=0;s<i.length;s++){var a=i[s].src;a&&-1===r.indexOf(a)&&r.push(a)}return!!r.length&&(1===r.length&&(n=r[0]),t.triggerSourceset(n),!0)},is=Object.defineProperty({},"innerHTML",{get:function(){return this.cloneNode(!0).innerHTML},set:function(t){var e=p.createElement(this.nodeName.toLowerCase());e.innerHTML=t;for(var i=p.createDocumentFragment();e.childNodes.length;)i.appendChild(e.childNodes[0]);return this.innerText="",g.Element.prototype.appendChild.call(this,i),this.innerHTML}}),rs=function(t,e){for(var i={},r=0;r<t.length&&!((i=Object.getOwnPropertyDescriptor(t[r],e))&&i.set&&i.get);r++);return i.enumerable=!0,i.configurable=!0,i},ns=function(s){var a=s.el();if(!a.resetSourceWatch_){var e={},t=rs([s.el(),g.HTMLMediaElement.prototype,g.Element.prototype,is],"innerHTML"),i=function(n){return function(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];var r=n.apply(a,e);return es(s),r}};["append","appendChild","insertAdjacentHTML"].forEach(function(t){a[t]&&(e[t]=a[t],a[t]=i(e[t]))}),Object.defineProperty(a,"innerHTML",Gt(t,{set:i(t.set)})),a.resetSourceWatch_=function(){a.resetSourceWatch_=null,Object.keys(e).forEach(function(t){a[t]=e[t]}),Object.defineProperty(a,"innerHTML",t)},s.one("sourceset",a.resetSourceWatch_)}},ss=Object.defineProperty({},"src",{get:function(){return this.hasAttribute("src")?Ze(g.Element.prototype.getAttribute.call(this,"src")):""},set:function(t){return g.Element.prototype.setAttribute.call(this,"src",t),t}}),as=function(r){if(r.featuresSourceset){var n=r.el();if(!n.resetSourceset_){var i=rs([r.el(),g.HTMLMediaElement.prototype,ss],"src"),s=n.setAttribute,e=n.load;Object.defineProperty(n,"src",Gt(i,{set:function(t){var e=i.set.call(n,t);return r.triggerSourceset(n.src),e}})),n.setAttribute=function(t,e){var i=s.call(n,t,e);return/src/i.test(t)&&r.triggerSourceset(n.src),i},n.load=function(){var t=e.call(n);return es(r)||(r.triggerSourceset(""),ns(r)),t},n.currentSrc?r.triggerSourceset(n.currentSrc):es(r)||ns(r),n.resetSourceset_=function(){n.resetSourceset_=null,n.load=e,n.setAttribute=s,Object.defineProperty(n,"src",i),n.resetSourceWatch_&&n.resetSourceWatch_()}}}},os=h(["Text Tracks are being loaded from another origin but the crossorigin attribute isn't used.\n This may prevent text tracks from loading."],["Text Tracks are being loaded from another origin but the crossorigin attribute isn't used.\n This may prevent text tracks from loading."]),us=function(c){function h(t,e){y(this,h);var i=b(this,c.call(this,t,e)),r=t.source,n=!1;if(r&&(i.el_.currentSrc!==r.src||t.tag&&3===t.tag.initNetworkState_)?i.setSource(r):i.handleLateInit_(i.el_),t.enableSourceset&&i.setupSourcesetHandling_(),i.el_.hasChildNodes()){for(var s=i.el_.childNodes,a=s.length,o=[];a--;){var u=s[a];"track"===u.nodeName.toLowerCase()&&(i.featuresNativeTextTracks?(i.remoteTextTrackEls().addTrackElement_(u),i.remoteTextTracks().addTrack(u.track),i.textTracks().addTrack(u.track),n||i.el_.hasAttribute("crossorigin")||!ei(u.src)||(n=!0)):o.push(u))}for(var l=0;l<o.length;l++)i.el_.removeChild(o[l])}return i.proxyNativeTracks_(),i.featuresNativeTextTracks&&n&&f.warn(m(os)),i.restoreMetadataTracksInIOSNativePlayer_(),(ge||ie||ue)&&!0===t.nativeControlsForTouch&&i.setControls(!0),i.proxyWebkitFullscreen_(),i.triggerReady(),i}return _(h,c),h.prototype.dispose=function(){this.el_.resetSourceset_&&this.el_.resetSourceset_(),h.disposeMediaElement(this.el_),this.options_=null,c.prototype.dispose.call(this)},h.prototype.setupSourcesetHandling_=function(){as(this)},h.prototype.restoreMetadataTracksInIOSNativePlayer_=function(){var r=this.textTracks(),n=void 0,t=function(){n=[];for(var t=0;t<r.length;t++){var e=r[t];"metadata"===e.kind&&n.push({track:e,storedMode:e.mode})}};t(),r.addEventListener("change",t),this.on("dispose",function(){return r.removeEventListener("change",t)});var e=function t(){for(var e=0;e<n.length;e++){var i=n[e];"disabled"===i.track.mode&&i.track.mode!==i.storedMode&&(i.track.mode=i.storedMode)}r.removeEventListener("change",t)};this.on("webkitbeginfullscreen",function(){r.removeEventListener("change",t),r.removeEventListener("change",e),r.addEventListener("change",e)}),this.on("webkitendfullscreen",function(){r.removeEventListener("change",t),r.addEventListener("change",t),r.removeEventListener("change",e)})},h.prototype.overrideNative_=function(t,e){var i=this;if(e===this["featuresNative"+t+"Tracks"]){var r=t.toLowerCase();this[r+"TracksListeners_"]&&Object.keys(this[r+"TracksListeners_"]).forEach(function(t){i.el()[r+"Tracks"].removeEventListener(t,i[r+"TracksListeners_"][t])}),this["featuresNative"+t+"Tracks"]=!e,this[r+"TracksListeners_"]=null,this.proxyNativeTracksForType_(r)}},h.prototype.overrideNativeAudioTracks=function(t){this.overrideNative_("Audio",t)},h.prototype.overrideNativeVideoTracks=function(t){this.overrideNative_("Video",t)},h.prototype.proxyNativeTracksForType_=function(t){var r=this,e=Ui[t],n=this.el()[e.getterName],s=this[e.getterName]();if(this["featuresNative"+e.capitalName+"Tracks"]&&n&&n.addEventListener){var a={change:function(t){s.trigger({type:"change",target:s,currentTarget:s,srcElement:s})},addtrack:function(t){s.addTrack(t.track)},removetrack:function(t){s.removeTrack(t.track)}},i=function(){for(var t=[],e=0;e<s.length;e++){for(var i=!1,r=0;r<n.length;r++)if(n[r]===s[e]){i=!0;break}i||t.push(s[e])}for(;t.length;)s.removeTrack(t.shift())};this[e.getterName+"Listeners_"]=a,Object.keys(a).forEach(function(e){var i=a[e];n.addEventListener(e,i),r.on("dispose",function(t){return n.removeEventListener(e,i)})}),this.on("loadstart",i),this.on("dispose",function(t){return r.off("loadstart",i)})}},h.prototype.proxyNativeTracks_=function(){var e=this;Ui.names.forEach(function(t){e.proxyNativeTracksForType_(t)})},h.prototype.createEl=function(){var t=this.options_.tag;if(!t||!this.options_.playerElIngest&&!this.movingMediaElementInDOM){if(t){var e=t.cloneNode(!0);t.parentNode&&t.parentNode.insertBefore(e,t),h.disposeMediaElement(t),t=e}else{t=p.createElement("video");var i=Gt({},this.options_.tag&&q(this.options_.tag));ge&&!0===this.options_.nativeControlsForTouch||delete i.controls,V(t,C(i,{id:this.options_.techId,class:"vjs-tech"}))}t.playerId=this.options_.playerId}"undefined"!=typeof this.options_.preload&&z(t,"preload",this.options_.preload);for(var r=["loop","muted","playsinline","autoplay"],n=0;n<r.length;n++){var s=r[n],a=this.options_[s];"undefined"!=typeof a&&(a?z(t,s,s):G(t,s),t[s]=a)}return t},h.prototype.handleLateInit_=function(t){if(0!==t.networkState&&3!==t.networkState){if(0===t.readyState){var e=!1,i=function(){e=!0};this.on("loadstart",i);var r=function(){e||this.trigger("loadstart")};return this.on("loadedmetadata",r),void this.ready(function(){this.off("loadstart",i),this.off("loadedmetadata",r),e||this.trigger("loadstart")})}var n=["loadstart"];n.push("loadedmetadata"),2<=t.readyState&&n.push("loadeddata"),3<=t.readyState&&n.push("canplay"),4<=t.readyState&&n.push("canplaythrough"),this.ready(function(){n.forEach(function(t){this.trigger(t)},this)})}},h.prototype.setCurrentTime=function(t){try{this.el_.currentTime=t}catch(t){f(t,"Video is not ready. (Video.js)")}},h.prototype.duration=function(){var e=this;if(this.el_.duration===1/0&&ae&&he&&0===this.el_.currentTime){return this.on("timeupdate",function t(){0<e.el_.currentTime&&(e.el_.duration===1/0&&e.trigger("durationchange"),e.off("timeupdate",t))}),NaN}return this.el_.duration||NaN},h.prototype.width=function(){return this.el_.offsetWidth},h.prototype.height=function(){return this.el_.offsetHeight},h.prototype.proxyWebkitFullscreen_=function(){var t=this;if("webkitDisplayingFullscreen"in this.el_){var e=function(){this.trigger("fullscreenchange",{isFullscreen:!1})},i=function(){"webkitPresentationMode"in this.el_&&"picture-in-picture"!==this.el_.webkitPresentationMode&&(this.one("webkitendfullscreen",e),this.trigger("fullscreenchange",{isFullscreen:!0}))};this.on("webkitbeginfullscreen",i),this.on("dispose",function(){t.off("webkitbeginfullscreen",i),t.off("webkitendfullscreen",e)})}},h.prototype.supportsFullScreen=function(){if("function"==typeof this.el_.webkitEnterFullScreen){var t=g.navigator&&g.navigator.userAgent||"";if(/Android/.test(t)||!/Chrome|Mac OS X 10.5/.test(t))return!0}return!1},h.prototype.enterFullScreen=function(){var t=this.el_;t.paused&&t.networkState<=t.HAVE_METADATA?(this.el_.play(),this.setTimeout(function(){t.pause(),t.webkitEnterFullScreen()},0)):t.webkitEnterFullScreen()},h.prototype.exitFullScreen=function(){this.el_.webkitExitFullScreen()},h.prototype.src=function(t){if(void 0===t)return this.el_.src;this.setSrc(t)},h.prototype.reset=function(){h.resetMediaElement(this.el_)},h.prototype.currentSrc=function(){return this.currentSource_?this.currentSource_.src:this.el_.currentSrc},h.prototype.setControls=function(t){this.el_.controls=!!t},h.prototype.addTextTrack=function(t,e,i){return this.featuresNativeTextTracks?this.el_.addTextTrack(t,e,i):c.prototype.addTextTrack.call(this,t,e,i)},h.prototype.createRemoteTextTrack=function(t){if(!this.featuresNativeTextTracks)return c.prototype.createRemoteTextTrack.call(this,t);var e=p.createElement("track");return t.kind&&(e.kind=t.kind),t.label&&(e.label=t.label),(t.language||t.srclang)&&(e.srclang=t.language||t.srclang),t.default&&(e.default=t.default),t.id&&(e.id=t.id),t.src&&(e.src=t.src),e},h.prototype.addRemoteTextTrack=function(t,e){var i=c.prototype.addRemoteTextTrack.call(this,t,e);return this.featuresNativeTextTracks&&this.el().appendChild(i),i},h.prototype.removeRemoteTextTrack=function(t){if(c.prototype.removeRemoteTextTrack.call(this,t),this.featuresNativeTextTracks)for(var e=this.$$("track"),i=e.length;i--;)t!==e[i]&&t!==e[i].track||this.el().removeChild(e[i])},h.prototype.getVideoPlaybackQuality=function(){if("function"==typeof this.el().getVideoPlaybackQuality)return this.el().getVideoPlaybackQuality();var t={};return"undefined"!=typeof this.el().webkitDroppedFrameCount&&"undefined"!=typeof this.el().webkitDecodedFrameCount&&(t.droppedVideoFrames=this.el().webkitDroppedFrameCount,t.totalVideoFrames=this.el().webkitDecodedFrameCount),g.performance&&"function"==typeof g.performance.now?t.creationTime=g.performance.now():g.performance&&g.performance.timing&&"number"==typeof g.performance.timing.navigationStart&&(t.creationTime=g.Date.now()-g.performance.timing.navigationStart),t},h}(br);if(x()){us.TEST_VID=p.createElement("video");var ls=p.createElement("track");ls.kind="captions",ls.srclang="en",ls.label="English",us.TEST_VID.appendChild(ls)}us.isSupported=function(){try{us.TEST_VID.volume=.5}catch(t){return!1}return!(!us.TEST_VID||!us.TEST_VID.canPlayType)},us.canPlayType=function(t){return us.TEST_VID.canPlayType(t)},us.canPlaySource=function(t,e){return us.canPlayType(t.type)},us.canControlVolume=function(){try{var t=us.TEST_VID.volume;return us.TEST_VID.volume=t/2+.1,t!==us.TEST_VID.volume}catch(t){return!1}},us.canControlPlaybackRate=function(){if(ae&&he&&de<58)return!1;try{var t=us.TEST_VID.playbackRate;return us.TEST_VID.playbackRate=t/2+.1,t!==us.TEST_VID.playbackRate}catch(t){return!1}},us.canOverrideAttributes=function(){try{var t=function(){};Object.defineProperty(p.createElement("video"),"src",{get:t,set:t}),Object.defineProperty(p.createElement("audio"),"src",{get:t,set:t}),Object.defineProperty(p.createElement("video"),"innerHTML",{get:t,set:t}),Object.defineProperty(p.createElement("audio"),"innerHTML",{get:t,set:t})}catch(t){return!1}return!0},us.supportsNativeTextTracks=function(){return me},us.supportsNativeVideoTracks=function(){return!(!us.TEST_VID||!us.TEST_VID.videoTracks)},us.supportsNativeAudioTracks=function(){return!(!us.TEST_VID||!us.TEST_VID.audioTracks)},us.Events=["loadstart","suspend","abort","error","emptied","stalled","loadedmetadata","loadeddata","canplay","canplaythrough","playing","waiting","seeking","seeked","ended","durationchange","timeupdate","progress","play","pause","ratechange","resize","volumechange"],us.prototype.featuresVolumeControl=us.canControlVolume(),us.prototype.featuresPlaybackRate=us.canControlPlaybackRate(),us.prototype.featuresSourceset=us.canOverrideAttributes(),us.prototype.movingMediaElementInDOM=!ne,us.prototype.featuresFullscreenResize=!0,us.prototype.featuresProgressEvents=!0,us.prototype.featuresTimeupdateEvents=!0,us.prototype.featuresNativeTextTracks=us.supportsNativeTextTracks(),us.prototype.featuresNativeVideoTracks=us.supportsNativeVideoTracks(),us.prototype.featuresNativeAudioTracks=us.supportsNativeAudioTracks();var cs=us.TEST_VID&&us.TEST_VID.constructor.prototype.canPlayType,hs=/^application\/(?:x-|vnd\.apple\.)mpegurl/i;us.patchCanPlayType=function(){4<=oe&&!le&&!he&&(us.TEST_VID.constructor.prototype.canPlayType=function(t){return t&&hs.test(t)?"maybe":cs.call(this,t)})},us.unpatchCanPlayType=function(){var t=us.TEST_VID.constructor.prototype.canPlayType;return us.TEST_VID.constructor.prototype.canPlayType=cs,t},us.patchCanPlayType(),us.disposeMediaElement=function(t){if(t){for(t.parentNode&&t.parentNode.removeChild(t);t.hasChildNodes();)t.removeChild(t.firstChild);t.removeAttribute("src"),"function"==typeof t.load&&function(){try{t.load()}catch(t){}}()}},us.resetMediaElement=function(t){if(t){for(var e=t.querySelectorAll("source"),i=e.length;i--;)t.removeChild(e[i]);t.removeAttribute("src"),"function"==typeof t.load&&function(){try{t.load()}catch(t){}}()}},["muted","defaultMuted","autoplay","controls","loop","playsinline"].forEach(function(t){us.prototype[t]=function(){return this.el_[t]||this.el_.hasAttribute(t)}}),["muted","defaultMuted","autoplay","loop","playsinline"].forEach(function(e){us.prototype["set"+zt(e)]=function(t){(this.el_[e]=t)?this.el_.setAttribute(e,e):this.el_.removeAttribute(e)}}),["paused","currentTime","buffered","volume","poster","preload","error","seeking","seekable","ended","playbackRate","defaultPlaybackRate","played","networkState","readyState","videoWidth","videoHeight"].forEach(function(t){us.prototype[t]=function(){return this.el_[t]}}),["volume","src","poster","preload","playbackRate","defaultPlaybackRate"].forEach(function(e){us.prototype["set"+zt(e)]=function(t){this.el_[e]=t}}),["pause","load","play"].forEach(function(t){us.prototype[t]=function(){return this.el_[t]()}}),br.withSourceHandlers(us),us.nativeSourceHandler={},us.nativeSourceHandler.canPlayType=function(t){try{return us.TEST_VID.canPlayType(t)}catch(t){return""}},us.nativeSourceHandler.canHandleSource=function(t,e){if(t.type)return us.nativeSourceHandler.canPlayType(t.type);if(t.src){var i=ti(t.src);return us.nativeSourceHandler.canPlayType("video/"+i)}return""},us.nativeSourceHandler.handleSource=function(t,e,i){e.setSrc(t.src)},us.nativeSourceHandler.dispose=function(){},us.registerSourceHandler(us.nativeSourceHandler),br.registerTech("Html5",us);var ds=h(["\n Using the tech directly can be dangerous. I hope you know what you're doing.\n See https://github.com/videojs/video.js/issues/2617 for more info.\n "],["\n Using the tech directly can be dangerous. I hope you know what you're doing.\n See https://github.com/videojs/video.js/issues/2617 for more info.\n "]),ps=["progress","abort","suspend","emptied","stalled","loadedmetadata","loadeddata","timeupdate","resize","volumechange","texttrackchange"],fs={canplay:"CanPlay",canplaythrough:"CanPlayThrough",playing:"Playing",seeked:"Seeked"},ms=function(c){function h(t,e,i){if(y(this,h),t.id=t.id||e.id||"vjs_video_"+ut(),(e=C(h.getTagSettings(t),e)).initChildren=!1,e.createEl=!1,e.evented=!1,e.reportTouchActivity=!1,!e.language)if("function"==typeof t.closest){var r=t.closest("[lang]");r&&r.getAttribute&&(e.language=r.getAttribute("lang"))}else for(var n=t;n&&1===n.nodeType;){if(q(n).hasOwnProperty("lang")){e.language=n.getAttribute("lang");break}n=n.parentNode}var s=b(this,c.call(this,null,e,i));if(s.isPosterFromTech_=!1,s.queuedCallbacks_=[],s.isReady_=!1,s.hasStarted_=!1,s.userActive_=!1,!s.options_||!s.options_.techOrder||!s.options_.techOrder.length)throw new Error("No techOrder specified. Did you overwrite videojs.options instead of just changing the properties you want to override?");if(s.tag=t,s.tagAttributes=t&&q(t),s.language(s.options_.language),e.languages){var a={};Object.getOwnPropertyNames(e.languages).forEach(function(t){a[t.toLowerCase()]=e.languages[t]}),s.languages_=a}else s.languages_=h.prototype.options_.languages;s.cache_={},s.poster_=e.poster||"",s.controls_=!!e.controls,s.cache_.lastVolume=1,t.controls=!1,t.removeAttribute("controls"),s.scrubbing_=!1,s.el_=s.createEl(),s.cache_.lastPlaybackRate=s.defaultPlaybackRate(),Vt(s,{eventBusKey:"el_"});var o=Gt(s.options_);if(e.plugins){var u=e.plugins;Object.keys(u).forEach(function(t){if("function"!=typeof this[t])throw new Error('plugin "'+t+'" does not exist');this[t](u[t])},s)}s.options_.playerOptions=o,s.middleware_=[],s.initChildren(),s.isAudio("audio"===t.nodeName.toLowerCase()),s.controls()?s.addClass("vjs-controls-enabled"):s.addClass("vjs-controls-disabled"),s.el_.setAttribute("role","region"),s.isAudio()?s.el_.setAttribute("aria-label",s.localize("Audio Player")):s.el_.setAttribute("aria-label",s.localize("Video Player")),s.isAudio()&&s.addClass("vjs-audio"),s.flexNotSupported_()&&s.addClass("vjs-no-flex"),ne||s.addClass("vjs-workinghover"),h.players[s.id_]=s;var l=d.split(".")[0];return s.addClass("vjs-v"+l),s.userActive(!0),s.reportUserActivity(),s.one("play",s.listenForUserActivity_),s.on("fullscreenchange",s.handleFullscreenChange_),s.on("stageclick",s.handleStageClick_),s.changingSrc_=!1,s.playWaitingForReady_=!1,s.playOnLoadstart_=null,s}return _(h,c),h.prototype.dispose=function(){this.trigger("dispose"),this.off("dispose"),this.styleEl_&&this.styleEl_.parentNode&&(this.styleEl_.parentNode.removeChild(this.styleEl_),this.styleEl_=null),h.players[this.id_]=null,this.tag&&this.tag.player&&(this.tag.player=null),this.el_&&this.el_.player&&(this.el_.player=null),this.tech_&&(this.tech_.dispose(),this.isPosterFromTech_=!1,this.poster_=""),this.playerElIngest_&&(this.playerElIngest_=null),this.tag&&(this.tag=null),Sr[this.id()]=null,c.prototype.dispose.call(this)},h.prototype.createEl=function(){var e=this.tag,i=void 0,t=this.playerElIngest_=e.parentNode&&e.parentNode.hasAttribute&&e.parentNode.hasAttribute("data-vjs-player"),r="video-js"===this.tag.tagName.toLowerCase();t?i=this.el_=e.parentNode:r||(i=this.el_=c.prototype.createEl.call(this,"div"));var n=q(e);if(r){for(i=this.el_=e,e=this.tag=p.createElement("video");i.children.length;)e.appendChild(i.firstChild);B(i,"video-js")||j(i,"video-js"),i.appendChild(e),t=this.playerElIngest_=i,Object.keys(i).forEach(function(t){e[t]=i[t]})}if(e.setAttribute("tabindex","-1"),e.removeAttribute("width"),e.removeAttribute("height"),Object.getOwnPropertyNames(n).forEach(function(t){i.setAttribute(t,n[t]),r&&e.setAttribute(t,n[t])}),e.playerId=e.id,e.id+="_html5_api",e.className="vjs-tech",e.player=i.player=this,this.addClass("vjs-paused"),!0!==g.VIDEOJS_NO_DYNAMIC_STYLE){this.styleEl_=Lt("vjs-styles-dimensions");var s=nt(".vjs-styles-defaults"),a=nt("head");a.insertBefore(this.styleEl_,s?s.nextSibling:a.firstChild)}this.width(this.options_.width),this.height(this.options_.height),this.fluid(this.options_.fluid),this.aspectRatio(this.options_.aspectRatio);for(var o=e.getElementsByTagName("a"),u=0;u<o.length;u++){var l=o.item(u);j(l,"vjs-hidden"),l.setAttribute("hidden","hidden")}return e.initNetworkState_=e.networkState,e.parentNode&&!t&&e.parentNode.insertBefore(i,e),N(e,i),this.children_.unshift(e),this.el_.setAttribute("lang",this.language_),this.el_=i},h.prototype.width=function(t){return this.dimension("width",t)},h.prototype.height=function(t){return this.dimension("height",t)},h.prototype.dimension=function(t,e){var i=t+"_";if(void 0===e)return this[i]||0;if(""===e)return this[i]=void 0,void this.updateStyleEl_();var r=parseFloat(e);isNaN(r)?f.error('Improper value "'+e+'" supplied for for '+t):(this[i]=r,this.updateStyleEl_())},h.prototype.fluid=function(t){if(void 0===t)return!!this.fluid_;this.fluid_=!!t,t?this.addClass("vjs-fluid"):this.removeClass("vjs-fluid"),this.updateStyleEl_()},h.prototype.aspectRatio=function(t){if(void 0===t)return this.aspectRatio_;if(!/^\d+\:\d+$/.test(t))throw new Error("Improper value supplied for aspect ratio. The format should be width:height, for example 16:9.");this.aspectRatio_=t,this.fluid(!0),this.updateStyleEl_()},h.prototype.updateStyleEl_=function(){if(!0!==g.VIDEOJS_NO_DYNAMIC_STYLE){var t=void 0,e=void 0,i=void 0,r=(void 0!==this.aspectRatio_&&"auto"!==this.aspectRatio_?this.aspectRatio_:0<this.videoWidth()?this.videoWidth()+":"+this.videoHeight():"16:9").split(":"),n=r[1]/r[0];t=void 0!==this.width_?this.width_:void 0!==this.height_?this.height_/n:this.videoWidth()||300,e=void 0!==this.height_?this.height_:t*n,i=/^[^a-zA-Z]/.test(this.id())?"dimensions-"+this.id():this.id()+"-dimensions",this.addClass(i),Pt(this.styleEl_,"\n ."+i+" {\n width: "+t+"px;\n height: "+e+"px;\n }\n\n ."+i+".vjs-fluid {\n padding-top: "+100*n+"%;\n }\n ")}else{var s="number"==typeof this.width_?this.width_:this.options_.width,a="number"==typeof this.height_?this.height_:this.options_.height,o=this.tech_&&this.tech_.el();o&&(0<=s&&(o.width=s),0<=a&&(o.height=a))}},h.prototype.loadTech_=function(t,e){var i=this;this.tech_&&this.unloadTech_();var r=zt(t),n=t.charAt(0).toLowerCase()+t.slice(1);"Html5"!==r&&this.tag&&(br.getTech("Html5").disposeMediaElement(this.tag),this.tag.player=null,this.tag=null),this.techName_=r,this.isReady_=!1;var s={source:e,nativeControlsForTouch:this.options_.nativeControlsForTouch,playerId:this.id(),techId:this.id()+"_"+r+"_api",autoplay:this.options_.autoplay,playsinline:this.options_.playsinline,preload:this.options_.preload,loop:this.options_.loop,muted:this.options_.muted,poster:this.poster(),language:this.language(),playerElIngest:this.playerElIngest_||!1,"vtt.js":this.options_["vtt.js"],canOverridePoster:!!this.options_.techCanOverridePoster,enableSourceset:this.options_.enableSourceset};Bi.names.forEach(function(t){var e=Bi[t];s[e.getterName]=i[e.privateName]}),C(s,this.options_[r]),C(s,this.options_[n]),C(s,this.options_[t.toLowerCase()]),this.tag&&(s.tag=this.tag),e&&e.src===this.cache_.src&&0<this.cache_.currentTime&&(s.startTime=this.cache_.currentTime);var a=br.getTech(t);if(!a)throw new Error("No Tech named '"+r+"' exists! '"+r+"' should be registered using videojs.registerTech()'");this.tech_=new a(s),this.tech_.ready(Ot(this,this.handleTechReady_),!0),Me(this.textTracksJson_||[],this.tech_),ps.forEach(function(t){i.on(i.tech_,t,i["handleTech"+zt(t)+"_"])}),Object.keys(fs).forEach(function(e){i.on(i.tech_,e,function(t){0===i.tech_.playbackRate()&&i.tech_.seeking()?i.queuedCallbacks_.push({callback:i["handleTech"+fs[e]+"_"].bind(i),event:t}):i["handleTech"+fs[e]+"_"](t)})}),this.on(this.tech_,"loadstart",this.handleTechLoadStart_),this.on(this.tech_,"sourceset",this.handleTechSourceset_),this.on(this.tech_,"waiting",this.handleTechWaiting_),this.on(this.tech_,"ended",this.handleTechEnded_),this.on(this.tech_,"seeking",this.handleTechSeeking_),this.on(this.tech_,"play",this.handleTechPlay_),this.on(this.tech_,"firstplay",this.handleTechFirstPlay_),this.on(this.tech_,"pause",this.handleTechPause_),this.on(this.tech_,"durationchange",this.handleTechDurationChange_),this.on(this.tech_,"fullscreenchange",this.handleTechFullscreenChange_),this.on(this.tech_,"error",this.handleTechError_),this.on(this.tech_,"loadedmetadata",this.updateStyleEl_),this.on(this.tech_,"posterchange",this.handleTechPosterChange_),this.on(this.tech_,"textdata",this.handleTechTextData_),this.on(this.tech_,"ratechange",this.handleTechRateChange_),this.usingNativeControls(this.techGet_("controls")),this.controls()&&!this.usingNativeControls()&&this.addTechControlsListeners_(),this.tech_.el().parentNode===this.el()||"Html5"===r&&this.tag||N(this.tech_.el(),this.el()),this.tag&&(this.tag.player=null,this.tag=null)},h.prototype.unloadTech_=function(){var i=this;Bi.names.forEach(function(t){var e=Bi[t];i[e.privateName]=i[e.getterName]()}),this.textTracksJson_=Re(this.tech_),this.isReady_=!1,this.tech_.dispose(),this.tech_=!1,this.isPosterFromTech_&&(this.poster_="",this.trigger("posterchange")),this.isPosterFromTech_=!1},h.prototype.tech=function(t){return void 0===t&&f.warn(m(ds)),this.tech_},h.prototype.addTechControlsListeners_=function(){this.removeTechControlsListeners_(),this.on(this.tech_,"mousedown",this.handleTechClick_),this.on(this.tech_,"touchstart",this.handleTechTouchStart_),this.on(this.tech_,"touchmove",this.handleTechTouchMove_),this.on(this.tech_,"touchend",this.handleTechTouchEnd_),this.on(this.tech_,"tap",this.handleTechTap_)},h.prototype.removeTechControlsListeners_=function(){this.off(this.tech_,"tap",this.handleTechTap_),this.off(this.tech_,"touchstart",this.handleTechTouchStart_),this.off(this.tech_,"touchmove",this.handleTechTouchMove_),this.off(this.tech_,"touchend",this.handleTechTouchEnd_),this.off(this.tech_,"mousedown",this.handleTechClick_)},h.prototype.handleTechReady_=function(){if(this.triggerReady(),this.cache_.volume&&this.techCall_("setVolume",this.cache_.volume),this.handleTechPosterChange_(),this.handleTechDurationChange_(),(this.src()||this.currentSrc())&&this.tag&&this.options_.autoplay&&this.paused())try{delete this.tag.poster}catch(t){f("deleting tag.poster throws in some browsers",t)}},h.prototype.handleTechLoadStart_=function(){this.removeClass("vjs-ended"),this.removeClass("vjs-seeking"),this.error(null),this.paused()?(this.hasStarted(!1),this.trigger("loadstart")):(this.trigger("loadstart"),this.trigger("firstplay"))},h.prototype.updateSourceCaches_=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",e=t,i="";"string"!=typeof e&&(e=t.src,i=t.type),this.cache_.source=this.cache_.source||{},this.cache_.sources=this.cache_.sources||[],e&&!i&&(i=function(t,e){if(!e)return"";if(t.cache_.source.src===e&&t.cache_.source.type)return t.cache_.source.type;var i=t.cache_.sources.filter(function(t){return t.src===e});if(i.length)return i[0].type;for(var r=t.$$("source"),n=0;n<r.length;n++){var s=r[n];if(s.type&&s.src&&s.src===e)return s.type}return xr(e)}(this,e)),this.cache_.source={src:e,type:i};for(var r=this.cache_.sources.filter(function(t){return t.src&&t.src===e}),n=[],s=this.$$("source"),a=[],o=0;o<s.length;o++){var u=q(s[o]);n.push(u),u.src&&u.src===e&&a.push(u.src)}a.length&&!r.length?this.cache_.sources=n:r.length||(this.cache_.sources=[this.cache_.source]),this.cache_.src=e},h.prototype.handleTechSourceset_=function(t){var i=this;if(!this.changingSrc_&&(this.updateSourceCaches_(t.src),!t.src)){this.tech_.one(["sourceset","loadstart"],function t(e){"sourceset"!==e.type&&i.updateSourceCaches_(i.techGet_("currentSrc")),i.tech_.off(["sourceset","loadstart"],t)})}this.trigger({src:t.src,type:"sourceset"})},h.prototype.hasStarted=function(t){if(void 0===t)return this.hasStarted_;t!==this.hasStarted_&&(this.hasStarted_=t,this.hasStarted_?(this.addClass("vjs-has-started"),this.trigger("firstplay")):this.removeClass("vjs-has-started"))},h.prototype.handleTechPlay_=function(){this.removeClass("vjs-ended"),this.removeClass("vjs-paused"),this.addClass("vjs-playing"),this.hasStarted(!0),this.trigger("play")},h.prototype.handleTechRateChange_=function(){0<this.tech_.playbackRate()&&0===this.cache_.lastPlaybackRate&&(this.queuedCallbacks_.forEach(function(t){return t.callback(t.event)}),this.queuedCallbacks_=[]),this.cache_.lastPlaybackRate=this.tech_.playbackRate(),this.trigger("ratechange")},h.prototype.handleTechWaiting_=function(){var t=this;this.addClass("vjs-waiting"),this.trigger("waiting"),this.one("timeupdate",function(){return t.removeClass("vjs-waiting")})},h.prototype.handleTechCanPlay_=function(){this.removeClass("vjs-waiting"),this.trigger("canplay")},h.prototype.handleTechCanPlayThrough_=function(){this.removeClass("vjs-waiting"),this.trigger("canplaythrough")},h.prototype.handleTechPlaying_=function(){this.removeClass("vjs-waiting"),this.trigger("playing")},h.prototype.handleTechSeeking_=function(){this.addClass("vjs-seeking"),this.trigger("seeking")},h.prototype.handleTechSeeked_=function(){this.removeClass("vjs-seeking"),this.trigger("seeked")},h.prototype.handleTechFirstPlay_=function(){this.options_.starttime&&(f.warn("Passing the `starttime` option to the player will be deprecated in 6.0"),this.currentTime(this.options_.starttime)),this.addClass("vjs-has-started"),this.trigger("firstplay")},h.prototype.handleTechPause_=function(){this.removeClass("vjs-playing"),this.addClass("vjs-paused"),this.trigger("pause")},h.prototype.handleTechEnded_=function(){this.addClass("vjs-ended"),this.options_.loop?(this.currentTime(0),this.play()):this.paused()||this.pause(),this.trigger("ended")},h.prototype.handleTechDurationChange_=function(){this.duration(this.techGet_("duration"))},h.prototype.handleTechClick_=function(t){rt(t)&&this.controls_&&(this.paused()?this.play():this.pause())},h.prototype.handleTechTap_=function(){this.userActive(!this.userActive())},h.prototype.handleTechTouchStart_=function(){this.userWasActive=this.userActive()},h.prototype.handleTechTouchMove_=function(){this.userWasActive&&this.reportUserActivity()},h.prototype.handleTechTouchEnd_=function(t){t.preventDefault()},h.prototype.handleFullscreenChange_=function(){this.isFullscreen()?this.addClass("vjs-fullscreen"):this.removeClass("vjs-fullscreen")},h.prototype.handleStageClick_=function(){this.reportUserActivity()},h.prototype.handleTechFullscreenChange_=function(t,e){e&&this.isFullscreen(e.isFullscreen),this.trigger("fullscreenchange")},h.prototype.handleTechError_=function(){var t=this.tech_.error();this.error(t)},h.prototype.handleTechTextData_=function(){var t=null;1<arguments.length&&(t=arguments[1]),this.trigger("textdata",t)},h.prototype.getCache=function(){return this.cache_},h.prototype.techCall_=function(n,s){this.ready(function(){if(n in Ar)return t=this.middleware_,e=this.tech_,r=s,e[i=n](t.reduce(Pr(i),r));if(n in Lr)return Er(this.middleware_,this.tech_,n,s);var t,e,i,r;try{this.tech_&&this.tech_[n](s)}catch(t){throw f(t),t}},!0)},h.prototype.techGet_=function(e){if(this.tech_&&this.tech_.isReady_){if(e in wr)return t=this.middleware_,i=this.tech_,r=e,t.reduceRight(Pr(r),i[r]());if(e in Lr)return Er(this.middleware_,this.tech_,e);var t,i,r;try{return this.tech_[e]()}catch(t){if(void 0===this.tech_[e])throw f("Video.js: "+e+" method not defined for "+this.techName_+" playback technology.",t),t;if("TypeError"===t.name)throw f("Video.js: "+e+" unavailable on "+this.techName_+" playback technology element.",t),this.tech_.isReady_=!1,t;throw f(t),t}}},h.prototype.play=function(){var t=this;if(this.playOnLoadstart_&&this.off("loadstart",this.playOnLoadstart_),this.isReady_){if(!this.changingSrc_&&(this.src()||this.currentSrc()))return this.techGet_("play");this.playOnLoadstart_=function(){t.playOnLoadstart_=null,Ie(t.play())},this.one("loadstart",this.playOnLoadstart_)}else{if(this.playWaitingForReady_)return;this.playWaitingForReady_=!0,this.ready(function(){t.playWaitingForReady_=!1,Ie(t.play())})}},h.prototype.pause=function(){this.techCall_("pause")},h.prototype.paused=function(){return!1!==this.techGet_("paused")},h.prototype.played=function(){return this.techGet_("played")||be(0,0)},h.prototype.scrubbing=function(t){if("undefined"==typeof t)return this.scrubbing_;this.scrubbing_=!!t,t?this.addClass("vjs-scrubbing"):this.removeClass("vjs-scrubbing")},h.prototype.currentTime=function(t){return"undefined"!=typeof t?(t<0&&(t=0),void this.techCall_("setCurrentTime",t)):(this.cache_.currentTime=this.techGet_("currentTime")||0,this.cache_.currentTime)},h.prototype.duration=function(t){if(void 0===t)return void 0!==this.cache_.duration?this.cache_.duration:NaN;(t=parseFloat(t))<0&&(t=1/0),t!==this.cache_.duration&&((this.cache_.duration=t)===1/0?this.addClass("vjs-live"):this.removeClass("vjs-live"),this.trigger("durationchange"))},h.prototype.remainingTime=function(){return this.duration()-this.currentTime()},h.prototype.remainingTimeDisplay=function(){return Math.floor(this.duration())-Math.floor(this.currentTime())},h.prototype.buffered=function(){var t=this.techGet_("buffered");return t&&t.length||(t=be(0,0)),t},h.prototype.bufferedPercent=function(){return Te(this.buffered(),this.duration())},h.prototype.bufferedEnd=function(){var t=this.buffered(),e=this.duration(),i=t.end(t.length-1);return e<i&&(i=e),i},h.prototype.volume=function(t){var e=void 0;return void 0!==t?(e=Math.max(0,Math.min(1,parseFloat(t))),this.cache_.volume=e,this.techCall_("setVolume",e),void(0<e&&this.lastVolume_(e))):(e=parseFloat(this.techGet_("volume")),isNaN(e)?1:e)},h.prototype.muted=function(t){if(void 0===t)return this.techGet_("muted")||!1;this.techCall_("setMuted",t)},h.prototype.defaultMuted=function(t){return void 0!==t?this.techCall_("setDefaultMuted",t):this.techGet_("defaultMuted")||!1},h.prototype.lastVolume_=function(t){if(void 0===t||0===t)return this.cache_.lastVolume;this.cache_.lastVolume=t},h.prototype.supportsFullScreen=function(){return this.techGet_("supportsFullScreen")||!1},h.prototype.isFullscreen=function(t){if(void 0===t)return!!this.isFullscreen_;this.isFullscreen_=!!t},h.prototype.requestFullscreen=function(){var i=Se;this.isFullscreen(!0),i.requestFullscreen?(_t(p,i.fullscreenchange,Ot(this,function t(e){this.isFullscreen(p[i.fullscreenElement]),!1===this.isFullscreen()&&bt(p,i.fullscreenchange,t),this.trigger("fullscreenchange")})),this.el_[i.requestFullscreen]()):this.tech_.supportsFullScreen()?this.techCall_("enterFullScreen"):(this.enterFullWindow(),this.trigger("fullscreenchange"))},h.prototype.exitFullscreen=function(){var t=Se;this.isFullscreen(!1),t.requestFullscreen?p[t.exitFullscreen]():this.tech_.supportsFullScreen()?this.techCall_("exitFullScreen"):(this.exitFullWindow(),this.trigger("fullscreenchange"))},h.prototype.enterFullWindow=function(){this.isFullWindow=!0,this.docOrigOverflow=p.documentElement.style.overflow,_t(p,"keydown",Ot(this,this.fullWindowOnEscKey)),p.documentElement.style.overflow="hidden",j(p.body,"vjs-full-window"),this.trigger("enterFullWindow")},h.prototype.fullWindowOnEscKey=function(t){27===t.keyCode&&(!0===this.isFullscreen()?this.exitFullscreen():this.exitFullWindow())},h.prototype.exitFullWindow=function(){this.isFullWindow=!1,bt(p,"keydown",this.fullWindowOnEscKey),p.documentElement.style.overflow=this.docOrigOverflow,F(p.body,"vjs-full-window"),this.trigger("exitFullWindow")},h.prototype.canPlayType=function(t){for(var e=void 0,i=0,r=this.options_.techOrder;i<r.length;i++){var n=r[i],s=br.getTech(n);if(s||(s=Xt.getComponent(n)),s){if(s.isSupported()&&(e=s.canPlayType(t)))return e}else f.error('The "'+n+'" tech is undefined. Skipped browser support check for that tech.')}return""},h.prototype.selectSource=function(t){var i,r=this,e=this.options_.techOrder.map(function(t){return[t,br.getTech(t)]}).filter(function(t){var e=t[0],i=t[1];return i?i.isSupported():(f.error('The "'+e+'" tech is undefined. Skipped browser support check for that tech.'),!1)}),n=function(t,i,r){var n=void 0;return t.some(function(e){return i.some(function(t){if(n=r(e,t))return!0})}),n},s=function(t,e){var i=t[0];if(t[1].canPlaySource(e,r.options_[i.toLowerCase()]))return{source:e,tech:i}};return(this.options_.sourceOrder?n(t,e,(i=s,function(t,e){return i(e,t)})):n(e,t,s))||!1},h.prototype.src=function(t){var n=this;if("undefined"==typeof t)return this.cache_.src||"";var s=function e(t){if(Array.isArray(t)){var i=[];t.forEach(function(t){t=e(t),Array.isArray(t)?i=i.concat(t):E(t)&&i.push(t)}),t=i}else t="string"==typeof t&&t.trim()?[Ir({src:t})]:E(t)&&"string"==typeof t.src&&t.src&&t.src.trim()?[Ir(t)]:[];return t}(t);s.length?(this.changingSrc_=!0,this.cache_.sources=s,this.updateSourceCaches_(s[0]),Cr(this,s[0],function(t,e){var i,r;if(n.middleware_=e,n.cache_.sources=s,n.updateSourceCaches_(t),n.src_(t))return 1<s.length?n.src(s.slice(1)):(n.changingSrc_=!1,n.setTimeout(function(){this.error({code:4,message:this.localize(this.options_.notSupportedMessage)})},0),void n.triggerReady());i=e,r=n.tech_,i.forEach(function(t){return t.setTech&&t.setTech(r)})})):this.setTimeout(function(){this.error({code:4,message:this.localize(this.options_.notSupportedMessage)})},0)},h.prototype.src_=function(t){var e,i,r=this,n=this.selectSource([t]);return!n||(e=n.tech,i=this.techName_,zt(e)!==zt(i)?(this.changingSrc_=!0,this.loadTech_(n.tech,n.source),this.tech_.ready(function(){r.changingSrc_=!1})):this.ready(function(){this.tech_.constructor.prototype.hasOwnProperty("setSource")?this.techCall_("setSource",t):this.techCall_("src",t.src),this.changingSrc_=!1},!0),!1)},h.prototype.load=function(){this.techCall_("load")},h.prototype.reset=function(){this.loadTech_(this.options_.techOrder[0],null),this.techCall_("reset")},h.prototype.currentSources=function(){var t=this.currentSource(),e=[];return 0!==Object.keys(t).length&&e.push(t),this.cache_.sources||e},h.prototype.currentSource=function(){return this.cache_.source||{}},h.prototype.currentSrc=function(){return this.currentSource()&&this.currentSource().src||""},h.prototype.currentType=function(){return this.currentSource()&&this.currentSource().type||""},h.prototype.preload=function(t){return void 0!==t?(this.techCall_("setPreload",t),void(this.options_.preload=t)):this.techGet_("preload")},h.prototype.autoplay=function(t){return void 0!==t?(this.techCall_("setAutoplay",t),void(this.options_.autoplay=t)):this.techGet_("autoplay",t)},h.prototype.playsinline=function(t){return void 0!==t?(this.techCall_("setPlaysinline",t),this.options_.playsinline=t,this):this.techGet_("playsinline")},h.prototype.loop=function(t){return void 0!==t?(this.techCall_("setLoop",t),void(this.options_.loop=t)):this.techGet_("loop")},h.prototype.poster=function(t){if(void 0===t)return this.poster_;t||(t=""),t!==this.poster_&&(this.poster_=t,this.techCall_("setPoster",t),this.isPosterFromTech_=!1,this.trigger("posterchange"))},h.prototype.handleTechPosterChange_=function(){if((!this.poster_||this.options_.techCanOverridePoster)&&this.tech_&&this.tech_.poster){var t=this.tech_.poster()||"";t!==this.poster_&&(this.poster_=t,this.isPosterFromTech_=!0,this.trigger("posterchange"))}},h.prototype.controls=function(t){if(void 0===t)return!!this.controls_;t=!!t,this.controls_!==t&&(this.controls_=t,this.usingNativeControls()&&this.techCall_("setControls",t),this.controls_?(this.removeClass("vjs-controls-disabled"),this.addClass("vjs-controls-enabled"),this.trigger("controlsenabled"),this.usingNativeControls()||this.addTechControlsListeners_()):(this.removeClass("vjs-controls-enabled"),this.addClass("vjs-controls-disabled"),this.trigger("controlsdisabled"),this.usingNativeControls()||this.removeTechControlsListeners_()))},h.prototype.usingNativeControls=function(t){if(void 0===t)return!!this.usingNativeControls_;t=!!t,this.usingNativeControls_!==t&&(this.usingNativeControls_=t,this.usingNativeControls_?(this.addClass("vjs-using-native-controls"),this.trigger("usingnativecontrols")):(this.removeClass("vjs-using-native-controls"),this.trigger("usingcustomcontrols")))},h.prototype.error=function(t){return void 0===t?this.error_||null:null===t?(this.error_=t,this.removeClass("vjs-error"),void(this.errorDisplay&&this.errorDisplay.close())):(this.error_=new Le(t),this.addClass("vjs-error"),f.error("(CODE:"+this.error_.code+" "+Le.errorTypes[this.error_.code]+")",this.error_.message,this.error_),void this.trigger("error"))},h.prototype.reportUserActivity=function(t){this.userActivity_=!0},h.prototype.userActive=function(t){if(void 0===t)return this.userActive_;if((t=!!t)!==this.userActive_){if(this.userActive_=t,this.userActive_)return this.userActivity_=!0,this.removeClass("vjs-user-inactive"),this.addClass("vjs-user-active"),void this.trigger("useractive");this.tech_&&this.tech_.one("mousemove",function(t){t.stopPropagation(),t.preventDefault()}),this.userActivity_=!1,this.removeClass("vjs-user-active"),this.addClass("vjs-user-inactive"),this.trigger("userinactive")}},h.prototype.listenForUserActivity_=function(){var e=void 0,i=void 0,r=void 0,n=Ot(this,this.reportUserActivity);this.on("mousedown",function(){n(),this.clearInterval(e),e=this.setInterval(n,250)}),this.on("mousemove",function(t){t.screenX===i&&t.screenY===r||(i=t.screenX,r=t.screenY,n())}),this.on("mouseup",function(t){n(),this.clearInterval(e)}),this.on("keydown",n),this.on("keyup",n);var s=void 0;this.setInterval(function(){if(this.userActivity_){this.userActivity_=!1,this.userActive(!0),this.clearTimeout(s);var t=this.options_.inactivityTimeout;t<=0||(s=this.setTimeout(function(){this.userActivity_||this.userActive(!1)},t))}},250)},h.prototype.playbackRate=function(t){if(void 0===t)return this.tech_&&this.tech_.featuresPlaybackRate?this.cache_.lastPlaybackRate||this.techGet_("playbackRate"):1;this.techCall_("setPlaybackRate",t)},h.prototype.defaultPlaybackRate=function(t){return void 0!==t?this.techCall_("setDefaultPlaybackRate",t):this.tech_&&this.tech_.featuresPlaybackRate?this.techGet_("defaultPlaybackRate"):1},h.prototype.isAudio=function(t){if(void 0===t)return!!this.isAudio_;this.isAudio_=!!t},h.prototype.addTextTrack=function(t,e,i){if(this.tech_)return this.tech_.addTextTrack(t,e,i)},h.prototype.addRemoteTextTrack=function(t,e){if(this.tech_)return this.tech_.addRemoteTextTrack(t,e)},h.prototype.removeRemoteTextTrack=function(){var t=(0<arguments.length&&void 0!==arguments[0]?arguments[0]:{}).track,e=void 0===t?arguments[0]:t;if(this.tech_)return this.tech_.removeRemoteTextTrack(e)},h.prototype.getVideoPlaybackQuality=function(){return this.techGet_("getVideoPlaybackQuality")},h.prototype.videoWidth=function(){return this.tech_&&this.tech_.videoWidth&&this.tech_.videoWidth()||0},h.prototype.videoHeight=function(){return this.tech_&&this.tech_.videoHeight&&this.tech_.videoHeight()||0},h.prototype.language=function(t){if(void 0===t)return this.language_;this.language_=String(t).toLowerCase()},h.prototype.languages=function(){return Gt(h.prototype.options_.languages,this.languages_)},h.prototype.toJSON=function(){var t=Gt(this.options_),e=t.tracks;t.tracks=[];for(var i=0;i<e.length;i++){var r=e[i];(r=Gt(r)).player=void 0,t.tracks[i]=r}return t},h.prototype.createModal=function(t,e){var i=this;(e=e||{}).content=t||"";var r=new Ne(this,e);return this.addChild(r),r.on("dispose",function(){i.removeChild(r)}),r.open(),r},h.getTagSettings=function(t){var e={sources:[],tracks:[]},i=q(t),r=i["data-setup"];if(B(t,"vjs-fluid")&&(i.fluid=!0),null!==r){var n=Oe(r||"{}"),s=n[0],a=n[1];s&&f.error(s),C(i,a)}if(C(e,i),t.hasChildNodes())for(var o=t.childNodes,u=0,l=o.length;u<l;u++){var c=o[u],h=c.nodeName.toLowerCase();"source"===h?e.sources.push(q(c)):"track"===h&&e.tracks.push(q(c))}return e},h.prototype.flexNotSupported_=function(){var t=p.createElement("i");return!("flexBasis"in t.style||"webkitFlexBasis"in t.style||"mozFlexBasis"in t.style||"msFlexBasis"in t.style||"msFlexOrder"in t.style)},h}(Xt);Bi.names.forEach(function(t){var e=Bi[t];ms.prototype[e.getterName]=function(){return this.tech_?this.tech_[e.getterName]():(this[e.privateName]=this[e.privateName]||new e.ListClass,this[e.privateName])}}),ms.players={};var gs=g.navigator;ms.prototype.options_={techOrder:br.defaultTechOrder_,html5:{},flash:{},inactivityTimeout:2e3,playbackRates:[],children:["mediaLoader","posterImage","textTrackDisplay","loadingSpinner","bigPlayButton","controlBar","errorDisplay","textTrackSettings","resizeManager"],language:gs&&(gs.languages&&gs.languages[0]||gs.userLanguage||gs.language)||"en",languages:{},notSupportedMessage:"No compatible source was found for this media."},["ended","seeking","seekable","networkState","readyState"].forEach(function(t){ms.prototype[t]=function(){return this.techGet_(t)}}),ps.forEach(function(t){ms.prototype["handleTech"+zt(t)+"_"]=function(){return this.trigger(t)}}),Xt.registerComponent("Player",ms);var ys="plugin",vs="activePlugins_",_s={},bs=function(t){return _s.hasOwnProperty(t)},Ts=function(t){return bs(t)?_s[t]:void 0},Ss=function(t,e){t[vs]=t[vs]||{},t[vs][e]=!0},ks=function(t,e,i){var r=(i?"before":"")+"pluginsetup";t.trigger(r,e),t.trigger(r+":"+e.name,e)},Cs=function(n,s){return s.prototype.name=n,function(){ks(this,{name:n,plugin:s,instance:null},!0);for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];var r=new(Function.prototype.bind.apply(s,[null].concat([this].concat(e))));return this[n]=function(){return r},ks(this,r.getEventHash()),r}},Es=function(){function s(t){if(y(this,s),this.constructor===s)throw new Error("Plugin must be sub-classed; not directly instantiated.");this.player=t,Vt(this),delete this.trigger,Wt(this,this.constructor.defaultState),Ss(t,this.name),this.dispose=Ot(this,this.dispose),t.on("dispose",this.dispose)}return s.prototype.version=function(){return this.constructor.VERSION},s.prototype.getEventHash=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};return t.name=this.name,t.plugin=this.constructor,t.instance=this,t},s.prototype.trigger=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return Tt(this.eventBusEl_,t,this.getEventHash(e))},s.prototype.handleStateChanged=function(t){},s.prototype.dispose=function(){var t=this.name,e=this.player;this.trigger("dispose"),this.off(),e.off("dispose",this.dispose),e[vs][t]=!1,this.player=this.state=null,e[t]=Cs(t,_s[t])},s.isBasic=function(t){var e="string"==typeof t?Ts(t):t;return"function"==typeof e&&!s.prototype.isPrototypeOf(e.prototype)},s.registerPlugin=function(t,e){if("string"!=typeof t)throw new Error('Illegal plugin name, "'+t+'", must be a string, was '+("undefined"==typeof t?"undefined":v(t))+".");if(bs(t))f.warn('A plugin named "'+t+'" already exists. You may want to avoid re-registering plugins!');else if(ms.prototype.hasOwnProperty(t))throw new Error('Illegal plugin name, "'+t+'", cannot share a name with an existing player method!');if("function"!=typeof e)throw new Error('Illegal plugin for "'+t+'", must be a function, was '+("undefined"==typeof e?"undefined":v(e))+".");var i,r,n;return _s[t]=e,t!==ys&&(s.isBasic(e)?ms.prototype[t]=(i=t,r=e,n=function(){ks(this,{name:i,plugin:r,instance:null},!0);var t=r.apply(this,arguments);return Ss(this,i),ks(this,{name:i,plugin:r,instance:t}),t},Object.keys(r).forEach(function(t){n[t]=r[t]}),n):ms.prototype[t]=Cs(t,e)),e},s.deregisterPlugin=function(t){if(t===ys)throw new Error("Cannot de-register base plugin.");bs(t)&&(delete _s[t],delete ms.prototype[t])},s.getPlugins=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:Object.keys(_s),i=void 0;return t.forEach(function(t){var e=Ts(t);e&&((i=i||{})[t]=e)}),i},s.getPluginVersion=function(t){var e=Ts(t);return e&&e.VERSION||""},s}();Es.getPlugin=Ts,Es.BASE_PLUGIN_NAME=ys,Es.registerPlugin(ys,Es),ms.prototype.usingPlugin=function(t){return!!this[vs]&&!0===this[vs][t]},ms.prototype.hasPlugin=function(t){return!!bs(t)};var ws=function(t){return 0===t.indexOf("#")?t.slice(1):t};function As(t,i,e){var r=As.getPlayer(t);if(r)return i&&f.warn('Player "'+t+'" is already initialised. Options will not be applied.'),e&&r.ready(e),r;var n="string"==typeof t?nt("#"+ws(t)):t;if(!I(n))throw new TypeError("The element or ID supplied is not valid. (videojs)");p.body.contains(n)||f.warn("The element supplied is not included in the DOM"),i=i||{},As.hooks("beforesetup").forEach(function(t){var e=t(n,Gt(i));E(e)&&!Array.isArray(e)?i=Gt(i,e):f.error("please return an object in beforesetup hooks")});var s=Xt.getComponent("Player");return r=new s(n,i,e),As.hooks("setup").forEach(function(t){return t(r)}),r}if(As.hooks_={},As.hooks=function(t,e){return As.hooks_[t]=As.hooks_[t]||[],e&&(As.hooks_[t]=As.hooks_[t].concat(e)),As.hooks_[t]},As.hook=function(t,e){As.hooks(t,e)},As.hookOnce=function(i,t){As.hooks(i,[].concat(t).map(function(e){return function t(){return As.removeHook(i,t),e.apply(void 0,arguments)}}))},As.removeHook=function(t,e){var i=As.hooks(t).indexOf(e);return!(i<=-1)&&(As.hooks_[t]=As.hooks_[t].slice(),As.hooks_[t].splice(i,1),!0)},!0!==g.VIDEOJS_NO_DYNAMIC_STYLE&&x()){var Ls=nt(".vjs-styles-defaults");if(!Ls){Ls=Lt("vjs-styles-defaults");var Ps=nt("head");Ps&&Ps.insertBefore(Ls,Ps.firstChild),Pt(Ls,"\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid {\n padding-top: 56.25%\n }\n ")}}At(1,As),As.VERSION=d,As.options=ms.prototype.options_,As.getPlayers=function(){return ms.players},As.getPlayer=function(t){var e=ms.players,i=void 0;if("string"==typeof t){var r=ws(t),n=e[r];if(n)return n;i=nt("#"+r)}else i=t;if(I(i)){var s=i,a=s.player,o=s.playerId;if(a||e[o])return a||e[o]}},As.getAllPlayers=function(){return Object.keys(ms.players).map(function(t){return ms.players[t]}).filter(Boolean)},As.players=ms.players,As.getComponent=Xt.getComponent,As.registerComponent=function(t,e){br.isTech(e)&&f.warn("The "+t+" tech was registered as a component. It should instead be registered using videojs.registerTech(name, tech)"),Xt.registerComponent.call(Xt,t,e)},As.getTech=br.getTech,As.registerTech=br.registerTech,As.use=function(t,e){Tr[t]=Tr[t]||[],Tr[t].push(e)},Object.defineProperty(As,"middleware",{value:{},writeable:!1,enumerable:!0}),Object.defineProperty(As.middleware,"TERMINATOR",{value:kr,writeable:!1,enumerable:!0}),As.browser=ye,As.TOUCH_ENABLED=ge,As.extend=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=function(){t.apply(this,arguments)},r={};for(var n in"object"===("undefined"==typeof e?"undefined":v(e))?(e.constructor!==Object.prototype.constructor&&(i=e.constructor),r=e):"function"==typeof e&&(i=e),function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+("undefined"==typeof e?"undefined":v(e)));t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(t.super_=e)}(i,t),r)r.hasOwnProperty(n)&&(i.prototype[n]=r[n]);return i},As.mergeOptions=Gt,As.bind=Ot,As.registerPlugin=Es.registerPlugin,As.plugin=function(t,e){return f.warn("videojs.plugin() is deprecated; use videojs.registerPlugin() instead"),Es.registerPlugin(t,e)},As.getPlugins=Es.getPlugins,As.getPlugin=Es.getPlugin,As.getPluginVersion=Es.getPluginVersion,As.addLanguage=function(t,e){var i;return t=(""+t).toLowerCase(),As.options.languages=Gt(As.options.languages,((i={})[t]=e,i)),As.options.languages[t]},As.log=f,As.createTimeRange=As.createTimeRanges=be,As.formatTime=Yr,As.setFormatTime=function(t){Xr=t},As.resetFormatTime=function(){Xr=Gr},As.parseUrl=Je,As.isCrossOrigin=ei,As.EventTarget=Dt,As.on=_t,As.one=St,As.off=bt,As.trigger=Tt,As.xhr=Ci,As.TextTrack=Oi,As.AudioTrack=xi,As.VideoTrack=Ii,["isEl","isTextNode","createEl","hasClass","addClass","removeClass","toggleClass","setAttributes","getAttributes","emptyEl","appendContent","insertContent"].forEach(function(t){As[t]=function(){return f.warn("videojs."+t+"() is deprecated; use videojs.dom."+t+"() instead"),at[t].apply(null,arguments)}}),As.computedStyle=A,As.dom=at,As.url=ii;var Os=e(function(t,e){var i,c,r,n,h;i=/^((?:[a-zA-Z0-9+\-.]+:)?)(\/\/[^\/\;?#]*)?(.*?)??(;.*?)?(\?.*?)?(#.*?)?$/,c=/^([^\/;?#]*)(.*)$/,r=/(?:\/|^)\.(?=\/)/g,n=/(?:\/|^)\.\.\/(?!\.\.\/).*?(?=\/)/g,h={buildAbsoluteURL:function(t,e,i){if(i=i||{},t=t.trim(),!(e=e.trim())){if(!i.alwaysNormalize)return t;var r=h.parseURL(t);if(!r)throw new Error("Error trying to parse base URL.");return r.path=h.normalizePath(r.path),h.buildURLFromParts(r)}var n=h.parseURL(e);if(!n)throw new Error("Error trying to parse relative URL.");if(n.scheme)return i.alwaysNormalize?(n.path=h.normalizePath(n.path),h.buildURLFromParts(n)):e;var s=h.parseURL(t);if(!s)throw new Error("Error trying to parse base URL.");if(!s.netLoc&&s.path&&"/"!==s.path[0]){var a=c.exec(s.path);s.netLoc=a[1],s.path=a[2]}s.netLoc&&!s.path&&(s.path="/");var o={scheme:s.scheme,netLoc:n.netLoc,path:null,params:n.params,query:n.query,fragment:n.fragment};if(!n.netLoc&&(o.netLoc=s.netLoc,"/"!==n.path[0]))if(n.path){var u=s.path,l=u.substring(0,u.lastIndexOf("/")+1)+n.path;o.path=h.normalizePath(l)}else o.path=s.path,n.params||(o.params=s.params,n.query||(o.query=s.query));return null===o.path&&(o.path=i.alwaysNormalize?h.normalizePath(n.path):n.path),h.buildURLFromParts(o)},parseURL:function(t){var e=i.exec(t);return e?{scheme:e[1]||"",netLoc:e[2]||"",path:e[3]||"",params:e[4]||"",query:e[5]||"",fragment:e[6]||""}:null},normalizePath:function(t){for(t=t.split("").reverse().join("").replace(r,"");t.length!==(t=t.replace(n,"")).length;);return t.split("").reverse().join("")},buildURLFromParts:function(t){return t.scheme+t.netLoc+t.path+t.params+t.query+t.fragment}},t.exports=h}),xs=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},Is=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var r in i)Object.prototype.hasOwnProperty.call(i,r)&&(t[r]=i[r])}return t},Ds=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+("undefined"==typeof e?"undefined":v(e)));t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},Rs=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!==("undefined"==typeof e?"undefined":v(e))&&"function"!=typeof e?t:e},Ms=function(){function t(){xs(this,t),this.listeners={}}return t.prototype.on=function(t,e){this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(e)},t.prototype.off=function(t,e){if(!this.listeners[t])return!1;var i=this.listeners[t].indexOf(e);return this.listeners[t].splice(i,1),-1<i},t.prototype.trigger=function(t){var e=this.listeners[t],i=void 0,r=void 0,n=void 0;if(e)if(2===arguments.length)for(r=e.length,i=0;i<r;++i)e[i].call(this,arguments[1]);else for(n=Array.prototype.slice.call(arguments,1),r=e.length,i=0;i<r;++i)e[i].apply(this,n)},t.prototype.dispose=function(){this.listeners={}},t.prototype.pipe=function(e){this.on("data",function(t){e.push(t)})},t}(),Us=function(e){function i(){xs(this,i);var t=Rs(this,e.call(this));return t.buffer="",t}return Ds(i,e),i.prototype.push=function(t){var e=void 0;for(this.buffer+=t,e=this.buffer.indexOf("\n");-1<e;e=this.buffer.indexOf("\n"))this.trigger("data",this.buffer.substring(0,e)),this.buffer=this.buffer.substring(e+1)},i}(Ms),Ns=function(t){for(var e=t.split(new RegExp('(?:^|,)((?:[^=]*)=(?:"[^"]*"|[^,]*))')),i={},r=e.length,n=void 0;r--;)""!==e[r]&&((n=/([^=]*)=(.*)/.exec(e[r]).slice(1))[0]=n[0].replace(/^\s+|\s+$/g,""),n[1]=n[1].replace(/^\s+|\s+$/g,""),n[1]=n[1].replace(/^['"](.*)['"]$/g,"$1"),i[n[0]]=n[1]);return i},Bs=function(e){function i(){xs(this,i);var t=Rs(this,e.call(this));return t.customParsers=[],t}return Ds(i,e),i.prototype.push=function(t){var e=void 0,i=void 0;if(0!==(t=t.replace(/^[\u0000\s]+|[\u0000\s]+$/g,"")).length)if("#"===t[0]){for(var r=0;r<this.customParsers.length;r++)if(this.customParsers[r].call(this,t))return;if(0===t.indexOf("#EXT"))if(t=t.replace("\r",""),e=/^#EXTM3U/.exec(t))this.trigger("data",{type:"tag",tagType:"m3u"});else{if(e=/^#EXTINF:?([0-9\.]*)?,?(.*)?$/.exec(t))return i={type:"tag",tagType:"inf"},e[1]&&(i.duration=parseFloat(e[1])),e[2]&&(i.title=e[2]),void this.trigger("data",i);if(e=/^#EXT-X-TARGETDURATION:?([0-9.]*)?/.exec(t))return i={type:"tag",tagType:"targetduration"},e[1]&&(i.duration=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#ZEN-TOTAL-DURATION:?([0-9.]*)?/.exec(t))return i={type:"tag",tagType:"totalduration"},e[1]&&(i.duration=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-VERSION:?([0-9.]*)?/.exec(t))return i={type:"tag",tagType:"version"},e[1]&&(i.version=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-MEDIA-SEQUENCE:?(\-?[0-9.]*)?/.exec(t))return i={type:"tag",tagType:"media-sequence"},e[1]&&(i.number=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-DISCONTINUITY-SEQUENCE:?(\-?[0-9.]*)?/.exec(t))return i={type:"tag",tagType:"discontinuity-sequence"},e[1]&&(i.number=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-PLAYLIST-TYPE:?(.*)?$/.exec(t))return i={type:"tag",tagType:"playlist-type"},e[1]&&(i.playlistType=e[1]),void this.trigger("data",i);if(e=/^#EXT-X-BYTERANGE:?([0-9.]*)?@?([0-9.]*)?/.exec(t))return i={type:"tag",tagType:"byterange"},e[1]&&(i.length=parseInt(e[1],10)),e[2]&&(i.offset=parseInt(e[2],10)),void this.trigger("data",i);if(e=/^#EXT-X-ALLOW-CACHE:?(YES|NO)?/.exec(t))return i={type:"tag",tagType:"allow-cache"},e[1]&&(i.allowed=!/NO/.test(e[1])),void this.trigger("data",i);if(e=/^#EXT-X-MAP:?(.*)$/.exec(t)){if(i={type:"tag",tagType:"map"},e[1]){var n=Ns(e[1]);if(n.URI&&(i.uri=n.URI),n.BYTERANGE){var s=n.BYTERANGE.split("@"),a=s[0],o=s[1];i.byterange={},a&&(i.byterange.length=parseInt(a,10)),o&&(i.byterange.offset=parseInt(o,10))}}this.trigger("data",i)}else if(e=/^#EXT-X-STREAM-INF:?(.*)$/.exec(t)){if(i={type:"tag",tagType:"stream-inf"},e[1]){if(i.attributes=Ns(e[1]),i.attributes.RESOLUTION){var u=i.attributes.RESOLUTION.split("x"),l={};u[0]&&(l.width=parseInt(u[0],10)),u[1]&&(l.height=parseInt(u[1],10)),i.attributes.RESOLUTION=l}i.attributes.BANDWIDTH&&(i.attributes.BANDWIDTH=parseInt(i.attributes.BANDWIDTH,10)),i.attributes["PROGRAM-ID"]&&(i.attributes["PROGRAM-ID"]=parseInt(i.attributes["PROGRAM-ID"],10))}this.trigger("data",i)}else{if(e=/^#EXT-X-MEDIA:?(.*)$/.exec(t))return i={type:"tag",tagType:"media"},e[1]&&(i.attributes=Ns(e[1])),void this.trigger("data",i);if(e=/^#EXT-X-ENDLIST/.exec(t))this.trigger("data",{type:"tag",tagType:"endlist"});else if(e=/^#EXT-X-DISCONTINUITY/.exec(t))this.trigger("data",{type:"tag",tagType:"discontinuity"});else{if(e=/^#EXT-X-PROGRAM-DATE-TIME:?(.*)$/.exec(t))return i={type:"tag",tagType:"program-date-time"},e[1]&&(i.dateTimeString=e[1],i.dateTimeObject=new Date(e[1])),void this.trigger("data",i);if(e=/^#EXT-X-KEY:?(.*)$/.exec(t))return i={type:"tag",tagType:"key"},e[1]&&(i.attributes=Ns(e[1]),i.attributes.IV&&("0x"===i.attributes.IV.substring(0,2).toLowerCase()&&(i.attributes.IV=i.attributes.IV.substring(2)),i.attributes.IV=i.attributes.IV.match(/.{8}/g),i.attributes.IV[0]=parseInt(i.attributes.IV[0],16),i.attributes.IV[1]=parseInt(i.attributes.IV[1],16),i.attributes.IV[2]=parseInt(i.attributes.IV[2],16),i.attributes.IV[3]=parseInt(i.attributes.IV[3],16),i.attributes.IV=new Uint32Array(i.attributes.IV))),void this.trigger("data",i);if(e=/^#EXT-X-START:?(.*)$/.exec(t))return i={type:"tag",tagType:"start"},e[1]&&(i.attributes=Ns(e[1]),i.attributes["TIME-OFFSET"]=parseFloat(i.attributes["TIME-OFFSET"]),i.attributes.PRECISE=/YES/.test(i.attributes.PRECISE)),void this.trigger("data",i);if(e=/^#EXT-X-CUE-OUT-CONT:?(.*)?$/.exec(t))return i={type:"tag",tagType:"cue-out-cont"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);if(e=/^#EXT-X-CUE-OUT:?(.*)?$/.exec(t))return i={type:"tag",tagType:"cue-out"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);if(e=/^#EXT-X-CUE-IN:?(.*)?$/.exec(t))return i={type:"tag",tagType:"cue-in"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);this.trigger("data",{type:"tag",data:t.slice(4)})}}}else this.trigger("data",{type:"comment",text:t.slice(1)})}else this.trigger("data",{type:"uri",uri:t})},i.prototype.addParser=function(t){var e=this,i=t.expression,r=t.customType,n=t.dataParser,s=t.segment;"function"!=typeof n&&(n=function(t){return t}),this.customParsers.push(function(t){if(i.exec(t))return e.trigger("data",{type:"custom",data:n(t),customType:r,segment:s}),!0})},i}(Ms),js=function(e){function i(){xs(this,i);var t=Rs(this,e.call(this));t.lineStream=new Us,t.parseStream=new Bs,t.lineStream.pipe(t.parseStream);var n=t,s=[],a={},o=void 0,u=void 0,l={AUDIO:{},VIDEO:{},"CLOSED-CAPTIONS":{},SUBTITLES:{}},c=0;return t.manifest={allowCache:!0,discontinuityStarts:[],segments:[]},t.parseStream.on("data",function(e){var i=void 0,r=void 0;({tag:function(){({"allow-cache":function(){this.manifest.allowCache=e.allowed,"allowed"in e||(this.trigger("info",{message:"defaulting allowCache to YES"}),this.manifest.allowCache=!0)},byterange:function(){var t={};"length"in e&&((a.byterange=t).length=e.length,"offset"in e||(this.trigger("info",{message:"defaulting offset to zero"}),e.offset=0)),"offset"in e&&((a.byterange=t).offset=e.offset)},endlist:function(){this.manifest.endList=!0},inf:function(){"mediaSequence"in this.manifest||(this.manifest.mediaSequence=0,this.trigger("info",{message:"defaulting media sequence to zero"})),"discontinuitySequence"in this.manifest||(this.manifest.discontinuitySequence=0,this.trigger("info",{message:"defaulting discontinuity sequence to zero"})),0<e.duration&&(a.duration=e.duration),0===e.duration&&(a.duration=.01,this.trigger("info",{message:"updating zero segment duration to a small value"})),this.manifest.segments=s},key:function(){e.attributes?"NONE"!==e.attributes.METHOD?e.attributes.URI?(e.attributes.METHOD||this.trigger("warn",{message:"defaulting key method to AES-128"}),u={method:e.attributes.METHOD||"AES-128",uri:e.attributes.URI},"undefined"!=typeof e.attributes.IV&&(u.iv=e.attributes.IV)):this.trigger("warn",{message:"ignoring key declaration without URI"}):u=null:this.trigger("warn",{message:"ignoring key declaration without attribute list"})},"media-sequence":function(){isFinite(e.number)?this.manifest.mediaSequence=e.number:this.trigger("warn",{message:"ignoring invalid media sequence: "+e.number})},"discontinuity-sequence":function(){isFinite(e.number)?(this.manifest.discontinuitySequence=e.number,c=e.number):this.trigger("warn",{message:"ignoring invalid discontinuity sequence: "+e.number})},"playlist-type":function(){/VOD|EVENT/.test(e.playlistType)?this.manifest.playlistType=e.playlistType:this.trigger("warn",{message:"ignoring unknown playlist type: "+e.playlist})},map:function(){o={},e.uri&&(o.uri=e.uri),e.byterange&&(o.byterange=e.byterange)},"stream-inf":function(){this.manifest.playlists=s,this.manifest.mediaGroups=this.manifest.mediaGroups||l,e.attributes?(a.attributes||(a.attributes={}),Is(a.attributes,e.attributes)):this.trigger("warn",{message:"ignoring empty stream-inf attributes"})},media:function(){if(this.manifest.mediaGroups=this.manifest.mediaGroups||l,e.attributes&&e.attributes.TYPE&&e.attributes["GROUP-ID"]&&e.attributes.NAME){var t=this.manifest.mediaGroups[e.attributes.TYPE];t[e.attributes["GROUP-ID"]]=t[e.attributes["GROUP-ID"]]||{},i=t[e.attributes["GROUP-ID"]],(r={default:/yes/i.test(e.attributes.DEFAULT)}).default?r.autoselect=!0:r.autoselect=/yes/i.test(e.attributes.AUTOSELECT),e.attributes.LANGUAGE&&(r.language=e.attributes.LANGUAGE),e.attributes.URI&&(r.uri=e.attributes.URI),e.attributes["INSTREAM-ID"]&&(r.instreamId=e.attributes["INSTREAM-ID"]),e.attributes.CHARACTERISTICS&&(r.characteristics=e.attributes.CHARACTERISTICS),e.attributes.FORCED&&(r.forced=/yes/i.test(e.attributes.FORCED)),i[e.attributes.NAME]=r}else this.trigger("warn",{message:"ignoring incomplete or missing media group"})},discontinuity:function(){c+=1,a.discontinuity=!0,this.manifest.discontinuityStarts.push(s.length)},"program-date-time":function(){"undefined"==typeof this.manifest.dateTimeString&&(this.manifest.dateTimeString=e.dateTimeString,this.manifest.dateTimeObject=e.dateTimeObject),a.dateTimeString=e.dateTimeString,a.dateTimeObject=e.dateTimeObject},targetduration:function(){!isFinite(e.duration)||e.duration<0?this.trigger("warn",{message:"ignoring invalid target duration: "+e.duration}):this.manifest.targetDuration=e.duration},totalduration:function(){!isFinite(e.duration)||e.duration<0?this.trigger("warn",{message:"ignoring invalid total duration: "+e.duration}):this.manifest.totalDuration=e.duration},start:function(){e.attributes&&!isNaN(e.attributes["TIME-OFFSET"])?this.manifest.start={timeOffset:e.attributes["TIME-OFFSET"],precise:e.attributes.PRECISE}:this.trigger("warn",{message:"ignoring start declaration without appropriate attribute list"})},"cue-out":function(){a.cueOut=e.data},"cue-out-cont":function(){a.cueOutCont=e.data},"cue-in":function(){a.cueIn=e.data}}[e.tagType]||function(){}).call(n)},uri:function(){a.uri=e.uri,s.push(a),!this.manifest.targetDuration||"duration"in a||(this.trigger("warn",{message:"defaulting segment duration to the target duration"}),a.duration=this.manifest.targetDuration),u&&(a.key=u),a.timeline=c,o&&(a.map=o),a={}},comment:function(){},custom:function(){e.segment?(a.custom=a.custom||{},a.custom[e.customType]=e.data):(this.manifest.custom=this.manifest.custom||{},this.manifest.custom[e.customType]=e.data)}})[e.type].call(n)}),t}return Ds(i,e),i.prototype.push=function(t){this.lineStream.push(t)},i.prototype.end=function(){this.lineStream.push("\n")},i.prototype.addParser=function(t){this.parseStream.addParser(t)},i}(Ms),Fs=function(t){var e,i=t.attributes,r=t.segments,n={attributes:(e={NAME:i.id,AUDIO:"audio",SUBTITLES:"subs",RESOLUTION:{width:i.width,height:i.height},CODECS:i.codecs,BANDWIDTH:i.bandwidth},e["PROGRAM-ID"]=1,e),uri:"",endList:"static"===(i.type||"static"),timeline:i.periodIndex,resolvedUri:"",targetDuration:i.duration,segments:r,mediaSequence:r.length?r[0].number:1};return i.contentProtection&&(n.contentProtection=i.contentProtection),n},Hs=function(t){return!!t&&"object"===("undefined"==typeof t?"undefined":v(t))},Vs=function r(){for(var t=arguments.length,e=Array(t),i=0;i<t;i++)e[i]=arguments[i];return e.reduce(function(e,i){return Object.keys(i).forEach(function(t){Array.isArray(e[t])&&Array.isArray(i[t])?e[t]=e[t].concat(i[t]):Hs(e[t])&&Hs(i[t])?e[t]=r(e[t],i[t]):e[t]=i[t]}),e},{})},qs=function(t,e){return/^[a-z]+:/i.test(e)?e:(/\/\//i.test(t)||(t=Os.buildAbsoluteURL(g.location.href,t)),Os.buildAbsoluteURL(t,e))},Ws=function(t){var e=t.baseUrl,i=void 0===e?"":e,r=t.source,n=void 0===r?"":r,s=t.range,a=void 0===s?"":s,o={uri:n,resolvedUri:qs(i||"",n)};if(a){var u=a.split("-"),l=parseInt(u[0],10),c=parseInt(u[1],10);o.byterange={length:c-l,offset:l}}return o},zs=function(t,e){for(var i,r,n,s,a,o,u,l,c,h,d,p,f=t.type,m=void 0===f?"static":f,g=t.minimumUpdatePeriod,y=void 0===g?0:g,v=t.media,_=void 0===v?"":v,b=t.sourceDuration,T=t.timescale,S=void 0===T?1:T,k=t.startNumber,C=void 0===k?1:k,E=t.periodIndex,w=[],A=-1,L=0;L<e.length;L++){var P=e[L],O=P.d,x=P.r||0,I=P.t||0;A<0&&(A=I),I&&A<I&&(A=I);var D=void 0;if(x<0){var R=L+1;R===e.length?"dynamic"===m&&0<y&&0<_.indexOf("$Number$")?(r=A,n=O,void 0,s=(i=t).NOW,a=i.clientOffset,o=i.availabilityStartTime,u=i.timescale,l=void 0===u?1:u,c=i.start,h=void 0===c?0:c,d=i.minimumUpdatePeriod,p=(s+a)/1e3+(void 0===d?0:d)-(o+h),D=Math.ceil((p*l-r)/n)):D=(b*S-A)/O:D=(e[R].t-A)/O}else D=x+1;for(var M=C+w.length+D,U=C+w.length;U<M;)w.push({number:U,duration:O/S,time:A,timeline:E}),A+=O,U++}return w},Gs=function(t){return t.reduce(function(t,e){return t.concat(e)},[])},Xs=function(t){if(!t.length)return[];for(var e=[],i=0;i<t.length;i++)e.push(t[i]);return e},Ys={static:function(t){var e=t.duration,i=t.timescale,r=void 0===i?1:i,n=t.sourceDuration;return{start:0,end:Math.ceil(n/(e/r))}},dynamic:function(t){var e=t.NOW,i=t.clientOffset,r=t.availabilityStartTime,n=t.timescale,s=void 0===n?1:n,a=t.duration,o=t.start,u=void 0===o?0:o,l=t.minimumUpdatePeriod,c=void 0===l?0:l,h=t.timeShiftBufferDepth,d=void 0===h?1/0:h,p=(e+i)/1e3,f=r+u,m=p+c-f,g=Math.ceil(m*s/a),y=Math.floor((p-f-d)*s/a),v=Math.floor((p-f)*s/a);return{start:Math.max(0,y),end:Math.min(g,v)}}},$s=function(t){var o,e=t.type,i=void 0===e?"static":e,r=t.duration,n=t.timescale,s=void 0===n?1:n,a=t.sourceDuration,u=Ys[i](t),l=function(t,e){for(var i=[],r=t;r<e;r++)i.push(r);return i}(u.start,u.end).map((o=t,function(t,e){var i=o.duration,r=o.timescale,n=void 0===r?1:r,s=o.periodIndex,a=o.startNumber;return{number:(void 0===a?1:a)+t,duration:i/n,timeline:s,time:e*i}}));if("static"===i){var c=l.length-1;l[c].duration=a-r/s*c}return l},Ks=/\$([A-z]*)(?:(%0)([0-9]+)d)?\$/g,Qs=function(t,e){return t.replace(Ks,(s=e,function(t,e,i,r){if("$$"===t)return"$";if("undefined"==typeof s[e])return t;var n=""+s[e];return"RepresentationID"===e?n:(r=i?parseInt(r,10):1)<=n.length?n:""+new Array(r-n.length+1).join("0")+n}));var s},Js=function(i,t){var e,r,n={RepresentationID:i.id,Bandwidth:i.bandwidth||0},s=i.initialization,a=void 0===s?{sourceURL:"",range:""}:s,o=Ws({baseUrl:i.baseUrl,source:Qs(a.sourceURL,n),range:a.range});return(r=t,(e=i).duration||r?e.duration?$s(e):zs(e,r):[{number:e.startNumber||1,duration:e.sourceDuration,time:0,timeline:e.periodIndex}]).map(function(t){n.Number=t.number,n.Time=t.time;var e=Qs(i.media||"",n);return{uri:e,timeline:t.timeline,duration:t.duration,resolvedUri:qs(i.baseUrl||"",e),map:o,number:t.number}})},Zs="INVALID_NUMBER_OF_PERIOD",ta="DASH_EMPTY_MANIFEST",ea="DASH_INVALID_XML",ia="NO_BASE_URL",ra="SEGMENT_TIME_UNSPECIFIED",na="UNSUPPORTED_UTC_TIMING_SCHEME",sa=function(u,t){var e=u.duration,i=u.segmentUrls,r=void 0===i?[]:i;if(!e&&!t||e&&t)throw new Error(ra);var n=r.map(function(t){return i=t,r=(e=u).baseUrl,n=e.initialization,a=Ws({baseUrl:r,source:(s=void 0===n?{}:n).sourceURL,range:s.range}),(o=Ws({baseUrl:r,source:i.media,range:i.mediaRange})).map=a,o;var e,i,r,n,s,a,o}),s=void 0;return e&&(s=$s(u)),t&&(s=zs(u,t)),s.map(function(t,e){if(n[e]){var i=n[e];return i.timeline=t.timeline,i.duration=t.duration,i.number=t.number,i}}).filter(function(t){return t})},aa=function(t){var e=t.baseUrl,i=t.initialization,r=void 0===i?{}:i,n=t.sourceDuration,s=t.timescale,a=void 0===s?1:s,o=t.indexRange,u=void 0===o?"":o,l=t.duration;if(!e)throw new Error(ia);var c=Ws({baseUrl:e,source:r.sourceURL,range:r.range}),h=Ws({baseUrl:e,source:e,range:u});if(h.map=c,l){var d=$s(t);d.length&&(h.duration=d[0].duration,h.timeline=d[0].timeline)}else n&&(h.duration=n/a,h.timeline=0);return h.number=0,[h]},oa=function(t){var e=t.attributes,i=t.segmentInfo,r=void 0,n=void 0;if(i.template?(n=Js,r=Vs(e,i.template)):i.base?(n=aa,r=Vs(e,i.base)):i.list&&(n=sa,r=Vs(e,i.list)),!n)return{attributes:e};var s=n(r,i.timeline);if(r.duration){var a=r,o=a.duration,u=a.timescale,l=void 0===u?1:u;r.duration=o/l}else s.length?r.duration=s.reduce(function(t,e){return Math.max(t,Math.ceil(e.duration))},0):r.duration=0;return{attributes:r,segments:s}},ua=function(t,e){return Xs(t.childNodes).filter(function(t){return t.tagName===e})},la=function(t){return t.textContent.trim()},ca=function(t){var e=/P(?:(\d*)Y)?(?:(\d*)M)?(?:(\d*)D)?(?:T(?:(\d*)H)?(?:(\d*)M)?(?:([\d.]*)S)?)?/.exec(t);if(!e)return 0;var i=e.slice(1),r=i[0],n=i[1],s=i[2],a=i[3],o=i[4],u=i[5];return 31536e3*parseFloat(r||0)+2592e3*parseFloat(n||0)+86400*parseFloat(s||0)+3600*parseFloat(a||0)+60*parseFloat(o||0)+parseFloat(u||0)},ha={mediaPresentationDuration:function(t){return ca(t)},availabilityStartTime:function(t){return/^\d+-\d+-\d+T\d+:\d+:\d+(\.\d+)?$/.test(e=t)&&(e+="Z"),Date.parse(e)/1e3;var e},minimumUpdatePeriod:function(t){return ca(t)},timeShiftBufferDepth:function(t){return ca(t)},start:function(t){return ca(t)},width:function(t){return parseInt(t,10)},height:function(t){return parseInt(t,10)},bandwidth:function(t){return parseInt(t,10)},startNumber:function(t){return parseInt(t,10)},timescale:function(t){return parseInt(t,10)},duration:function(t){var e=parseInt(t,10);return isNaN(e)?ca(t):e},d:function(t){return parseInt(t,10)},t:function(t){return parseInt(t,10)},r:function(t){return parseInt(t,10)},DEFAULT:function(t){return t}},da=function(t){return t&&t.attributes?Xs(t.attributes).reduce(function(t,e){var i=ha[e.name]||ha.DEFAULT;return t[e.name]=i(e.value),t},{}):{}};var pa,fa,ma={"urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b":"org.w3.clearkey","urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed":"com.widevine.alpha","urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95":"com.microsoft.playready","urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb":"com.adobe.primetime"},ga=function(t,i){return i.length?Gs(t.map(function(e){return i.map(function(t){return qs(e,la(t))})})):t},ya=function(t){var e=ua(t,"SegmentTemplate")[0],i=ua(t,"SegmentList")[0],r=i&&ua(i,"SegmentURL").map(function(t){return Vs({tag:"SegmentURL"},da(t))}),n=ua(t,"SegmentBase")[0],s=i||e,a=s&&ua(s,"SegmentTimeline")[0],o=i||n||e,u=o&&ua(o,"Initialization")[0],l=e&&da(e);l&&u?l.initialization=u&&da(u):l&&l.initialization&&(l.initialization={sourceURL:l.initialization});var c={template:l,timeline:a&&ua(a,"S").map(function(t){return da(t)}),list:i&&Vs(da(i),{segmentUrls:r,initialization:da(u)}),base:n&&Vs(da(n),{initialization:da(u)})};return Object.keys(c).forEach(function(t){c[t]||delete c[t]}),c},va=function(t){return t.reduce(function(t,e){var i=da(e),r=ma[i.schemeIdUri];if(r){t[r]={attributes:i};var n=ua(e,"cenc:pssh")[0];if(n){var s=la(n),a=s&&function(t){for(var e=g.atob(t),i=new Uint8Array(e.length),r=0;r<e.length;r++)i[r]=e.charCodeAt(r);return i}(s);t[r].pssh=a}}return t},{})},_a=function(p,f,m){return function(t){var e=da(t),i=ga(f,ua(t,"BaseURL")),r=ua(t,"Role")[0],n={role:da(r)},s=Vs(p,e,n),a=va(ua(t,"ContentProtection"));Object.keys(a).length&&(s=Vs(s,{contentProtection:a}));var o,u,l,c=ya(t),h=ua(t,"Representation"),d=Vs(m,c);return Gs(h.map((o=s,u=i,l=d,function(t){var e=ua(t,"BaseURL"),i=ga(u,e),r=Vs(o,da(t)),n=ya(t);return i.map(function(t){return{segmentInfo:Vs(l,n),attributes:Vs(r,{baseUrl:t})}})})))}},ba=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=e.manifestUri,r=void 0===i?"":i,n=e.NOW,s=void 0===n?Date.now():n,a=e.clientOffset,o=void 0===a?0:a,u=ua(t,"Period");if(1!==u.length)throw new Error(Zs);var l,c,h=da(t),d=ga([r],ua(t,"BaseURL"));return h.sourceDuration=h.mediaPresentationDuration||0,h.NOW=s,h.clientOffset=o,Gs(u.map((l=h,c=d,function(t,e){var i=ga(c,ua(t,"BaseURL")),r=da(t),n=Vs(l,r,{periodIndex:e}),s=ua(t,"AdaptationSet"),a=ya(t);return Gs(s.map(_a(n,i,a)))})))},Ta=function(t){if(""===t)throw new Error(ta);var e=(new g.DOMParser).parseFromString(t,"application/xml"),i=e&&"MPD"===e.documentElement.tagName?e.documentElement:null;if(!i||i&&0<i.getElementsByTagName("parsererror").length)throw new Error(ea);return i},Sa=function(t,e){return function(t){var e;if(!t.length)return{};var i=t[0].attributes,r=i.sourceDuration,n=i.minimumUpdatePeriod,s=void 0===n?0:n,a=t.filter(function(t){var e=t.attributes;return"video/mp4"===e.mimeType||"video"===e.contentType}).map(Fs),o=t.filter(function(t){var e=t.attributes;return"audio/mp4"===e.mimeType||"audio"===e.contentType}),u=t.filter(function(t){var e=t.attributes;return"text/vtt"===e.mimeType||"text"===e.contentType}),l={allowCache:!0,discontinuityStarts:[],segments:[],endList:!0,mediaGroups:(e={AUDIO:{},VIDEO:{}},e["CLOSED-CAPTIONS"]={},e.SUBTITLES={},e),uri:"",duration:r,playlists:a,minimumUpdatePeriod:1e3*s};return o.length&&(l.mediaGroups.AUDIO.audio=o.reduce(function(t,e){var i,r,n,s,a,o=e.attributes.role&&e.attributes.role.value||"main",u=e.attributes.lang||"",l="main";return u&&(l=e.attributes.lang+" ("+o+")"),t[l]&&t[l].playlists[0].attributes.BANDWIDTH>e.attributes.bandwidth||(t[l]={language:u,autoselect:!0,default:"main"===o,playlists:[(i=e,n=i.attributes,s=i.segments,a={attributes:(r={NAME:n.id,BANDWIDTH:n.bandwidth,CODECS:n.codecs},r["PROGRAM-ID"]=1,r),uri:"",endList:"static"===(n.type||"static"),timeline:n.periodIndex,resolvedUri:"",targetDuration:n.duration,segments:s,mediaSequence:s.length?s[0].number:1},n.contentProtection&&(a.contentProtection=n.contentProtection),a)],uri:""}),t},{})),u.length&&(l.mediaGroups.SUBTITLES.subs=u.reduce(function(t,e){var i,r,n,s,a=e.attributes.lang||"text";return t[a]||(t[a]={language:a,default:!1,autoselect:!1,playlists:[(i=e,n=i.attributes,s=i.segments,"undefined"==typeof s&&(s=[{uri:n.baseUrl,timeline:n.periodIndex,resolvedUri:n.baseUrl||"",duration:n.sourceDuration,number:0}],n.duration=n.sourceDuration),{attributes:(r={NAME:n.id,BANDWIDTH:n.bandwidth},r["PROGRAM-ID"]=1,r),uri:"",endList:"static"===(n.type||"static"),timeline:n.periodIndex,resolvedUri:n.baseUrl||"",targetDuration:n.duration,segments:s,mediaSequence:s.length?s[0].number:1})],uri:""}),t},{})),l}(ba(Ta(t),e).map(oa))},ka=function(t){return function(t){var e=ua(t,"UTCTiming")[0];if(!e)return null;var i=da(e);switch(i.schemeIdUri){case"urn:mpeg:dash:utc:http-head:2014":case"urn:mpeg:dash:utc:http-head:2012":i.method="HEAD";break;case"urn:mpeg:dash:utc:http-xsdate:2014":case"urn:mpeg:dash:utc:http-iso:2014":case"urn:mpeg:dash:utc:http-xsdate:2012":case"urn:mpeg:dash:utc:http-iso:2012":i.method="GET";break;case"urn:mpeg:dash:utc:direct:2014":case"urn:mpeg:dash:utc:direct:2012":i.method="DIRECT",i.value=Date.parse(i.value);break;case"urn:mpeg:dash:utc:http-ntp:2014":case"urn:mpeg:dash:utc:ntp:2014":case"urn:mpeg:dash:utc:sntp:2014":default:throw new Error(na)}return i}(Ta(t))},Ca={toUnsigned:function(t){return t>>>0}},Ea=Ca.toUnsigned,wa=Object.freeze({default:Ca,__moduleExports:Ca,toUnsigned:Ea}),Aa=(wa&&Ca||wa).toUnsigned;pa=function(t,e){var i,r,n,s,a,o=[];if(!e.length)return null;for(i=0;i<t.byteLength;)r=Aa(t[i]<<24|t[i+1]<<16|t[i+2]<<8|t[i+3]),n=fa(t.subarray(i+4,i+8)),s=1<r?i+r:t.byteLength,n===e[0]&&(1===e.length?o.push(t.subarray(i+8,s)):(a=pa(t.subarray(i+8,s),e.slice(1))).length&&(o=o.concat(a))),i=s;return o};fa=function(t){var e="";return e+=String.fromCharCode(t[0]),e+=String.fromCharCode(t[1]),e+=String.fromCharCode(t[2]),e+=String.fromCharCode(t[3])};var La=function(t){return pa(t,["moov","trak"]).reduce(function(t,e){var i,r,n,s,a;return(i=pa(e,["tkhd"])[0])?(r=i[0],s=Aa(i[n=0===r?12:20]<<24|i[n+1]<<16|i[n+2]<<8|i[n+3]),(a=pa(e,["mdia","mdhd"])[0])?(n=0===(r=a[0])?12:20,t[s]=Aa(a[n]<<24|a[n+1]<<16|a[n+2]<<8|a[n+3]),t):null):null},{})},Pa=function(n,t){var e,i,r;return e=pa(t,["moof","traf"]),i=[].concat.apply([],e.map(function(r){return pa(r,["tfhd"]).map(function(t){var e,i;return e=Aa(t[4]<<24|t[5]<<16|t[6]<<8|t[7]),i=n[e]||9e4,(pa(r,["tfdt"]).map(function(t){var e,i;return e=t[0],i=Aa(t[4]<<24|t[5]<<16|t[6]<<8|t[7]),1===e&&(i*=Math.pow(2,32),i+=Aa(t[8]<<24|t[9]<<16|t[10]<<8|t[11])),i})[0]||1/0)/i})})),r=Math.min.apply(null,i),isFinite(r)?r:0},Oa={H264_STREAM_TYPE:27,ADTS_STREAM_TYPE:15,METADATA_STREAM_TYPE:21},xa=Oa.H264_STREAM_TYPE,Ia=Oa.ADTS_STREAM_TYPE,Da=Oa.METADATA_STREAM_TYPE,Ra=Object.freeze({default:Oa,__moduleExports:Oa,H264_STREAM_TYPE:xa,ADTS_STREAM_TYPE:Ia,METADATA_STREAM_TYPE:Da}),Ma=function(){this.init=function(){var s={};this.on=function(t,e){s[t]||(s[t]=[]),s[t]=s[t].concat(e)},this.off=function(t,e){var i;return!!s[t]&&(i=s[t].indexOf(e),s[t]=s[t].slice(),s[t].splice(i,1),-1<i)},this.trigger=function(t){var e,i,r,n;if(e=s[t])if(2===arguments.length)for(r=e.length,i=0;i<r;++i)e[i].call(this,arguments[1]);else{for(n=[],i=arguments.length,i=1;i<arguments.length;++i)n.push(arguments[i]);for(r=e.length,i=0;i<r;++i)e[i].apply(this,n)}},this.dispose=function(){s={}}}};Ma.prototype.pipe=function(e){return this.on("data",function(t){e.push(t)}),this.on("done",function(t){e.flush(t)}),e},Ma.prototype.push=function(t){this.trigger("data",t)},Ma.prototype.flush=function(t){this.trigger("done",t)};var Ua=Ma,Na=Object.freeze({default:Ua,__moduleExports:Ua}),Ba=function(t,e){var i=1;for(e<t&&(i=-1);4294967296<Math.abs(e-t);)t+=8589934592*i;return t},ja=function t(e){var i,r;t.prototype.init.call(this),this.type_=e,this.push=function(t){t.type===this.type_&&(void 0===r&&(r=t.dts),t.dts=Ba(t.dts,r),t.pts=Ba(t.pts,r),i=t.dts,this.trigger("data",t))},this.flush=function(){r=i,this.trigger("done")},this.discontinuity=function(){i=r=void 0}};ja.prototype=new(Na&&Ua||Na);var Fa={TimestampRolloverStream:ja,handleRollover:Ba},Ha=Fa.TimestampRolloverStream,Va=Fa.handleRollover,qa=Object.freeze({default:Fa,__moduleExports:Fa,TimestampRolloverStream:Ha,handleRollover:Va}),Wa=Ra&&Oa||Ra,za=function(t){var e=31&t[1];return e<<=8,e|=t[2]},Ga=function(t){return!!(64&t[1])},Xa=function(t){var e=0;return 1<(48&t[3])>>>4&&(e+=t[4]+1),e},Ya=function(t){switch(t){case 5:return"slice_layer_without_partitioning_rbsp_idr";case 6:return"sei_rbsp";case 7:return"seq_parameter_set_rbsp";case 8:return"pic_parameter_set_rbsp";case 9:return"access_unit_delimiter_rbsp";default:return null}},$a={parseType:function(t,e){var i=za(t);return 0===i?"pat":i===e?"pmt":e?"pes":null},parsePat:function(t){var e=Ga(t),i=4+Xa(t);return e&&(i+=t[i]+1),(31&t[i+10])<<8|t[i+11]},parsePmt:function(t){var e={},i=Ga(t),r=4+Xa(t);if(i&&(r+=t[r]+1),1&t[r+5]){var n;n=3+((15&t[r+1])<<8|t[r+2])-4;for(var s=12+((15&t[r+10])<<8|t[r+11]);s<n;){var a=r+s;e[(31&t[a+1])<<8|t[a+2]]=t[a],s+=5+((15&t[a+3])<<8|t[a+4])}return e}},parsePayloadUnitStartIndicator:Ga,parsePesType:function(t,e){switch(e[za(t)]){case Wa.H264_STREAM_TYPE:return"video";case Wa.ADTS_STREAM_TYPE:return"audio";case Wa.METADATA_STREAM_TYPE:return"timed-metadata";default:return null}},parsePesTime:function(t){if(!Ga(t))return null;var e=4+Xa(t);if(e>=t.byteLength)return null;var i,r=null;return 192&(i=t[e+7])&&((r={}).pts=(14&t[e+9])<<27|(255&t[e+10])<<20|(254&t[e+11])<<12|(255&t[e+12])<<5|(254&t[e+13])>>>3,r.pts*=4,r.pts+=(6&t[e+13])>>>1,r.dts=r.pts,64&i&&(r.dts=(14&t[e+14])<<27|(255&t[e+15])<<20|(254&t[e+16])<<12|(255&t[e+17])<<5|(254&t[e+18])>>>3,r.dts*=4,r.dts+=(6&t[e+18])>>>1)),r},videoPacketContainsKeyFrame:function(t){for(var e=4+Xa(t),i=t.subarray(e),r=0,n=0,s=!1;n<i.byteLength-3;n++)if(1===i[n+2]){r=n+5;break}for(;r<i.byteLength;)switch(i[r]){case 0:if(0!==i[r-1]){r+=2;break}if(0!==i[r-2]){r++;break}for(n+3!==r-2&&"slice_layer_without_partitioning_rbsp_idr"===Ya(31&i[n+3])&&(s=!0);1!==i[++r]&&r<i.length;);n=r-2,r+=3;break;case 1:if(0!==i[r-1]||0!==i[r-2]){r+=3;break}"slice_layer_without_partitioning_rbsp_idr"===Ya(31&i[n+3])&&(s=!0),n=r-2,r+=3;break;default:r+=3}return i=i.subarray(n),r-=n,n=0,i&&3<i.byteLength&&"slice_layer_without_partitioning_rbsp_idr"===Ya(31&i[n+3])&&(s=!0),s}},Ka=$a.parseType,Qa=$a.parsePat,Ja=$a.parsePmt,Za=$a.parsePayloadUnitStartIndicator,to=$a.parsePesType,eo=$a.parsePesTime,io=$a.videoPacketContainsKeyFrame,ro=Object.freeze({default:$a,__moduleExports:$a,parseType:Ka,parsePat:Qa,parsePmt:Ja,parsePayloadUnitStartIndicator:Za,parsePesType:to,parsePesTime:eo,videoPacketContainsKeyFrame:io}),no=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350],so=function(t){return t[0]<<21|t[1]<<14|t[2]<<7|t[3]},ao={parseId3TagSize:function(t,e){var i=t[e+6]<<21|t[e+7]<<14|t[e+8]<<7|t[e+9];return(16&t[e+5])>>4?i+20:i+10},parseAdtsSize:function(t,e){var i=(224&t[e+5])>>5,r=t[e+4]<<3;return 6144&t[e+3]|r|i},parseType:function(t,e){return t[e]==="I".charCodeAt(0)&&t[e+1]==="D".charCodeAt(0)&&t[e+2]==="3".charCodeAt(0)?"timed-metadata":!0&t[e]&&240==(240&t[e+1])?"audio":null},parseSampleRate:function(t){for(var e=0;e+5<t.length;){if(255===t[e]&&240==(246&t[e+1]))return no[(60&t[e+2])>>>2];e++}return null},parseAacTimestamp:function(t){var e,i,r;e=10,64&t[5]&&(e+=4,e+=so(t.subarray(10,14)));do{if((i=so(t.subarray(e+4,e+8)))<1)return null;if("PRIV"===String.fromCharCode(t[e],t[e+1],t[e+2],t[e+3])){r=t.subarray(e+10,e+i+10);for(var n=0;n<r.byteLength;n++)if(0===r[n]){if("com.apple.streaming.transportStreamTimestamp"===unescape(function(t,e,i){var r,n="";for(r=e;r<i;r++)n+="%"+("00"+t[r].toString(16)).slice(-2);return n}(r,0,n))){var s=r.subarray(n+1),a=(1&s[3])<<30|s[4]<<22|s[5]<<14|s[6]<<6|s[7]>>>2;return a*=4,a+=3&s[7]}break}}e+=10,e+=i}while(e<t.byteLength);return null}},oo=ao.parseId3TagSize,uo=ao.parseAdtsSize,lo=ao.parseType,co=ao.parseSampleRate,ho=ao.parseAacTimestamp,po=Object.freeze({default:ao,__moduleExports:ao,parseId3TagSize:oo,parseAdtsSize:uo,parseType:lo,parseSampleRate:co,parseAacTimestamp:ho}),fo=ro&&$a||ro,mo=po&&ao||po,go=(qa&&Fa||qa).handleRollover,yo={};yo.ts=fo,yo.aac=mo;var vo=188,_o=function(t,e,i){for(var r,n,s,a,o=0,u=vo,l=!1;u<t.byteLength;)if(71!==t[o]||71!==t[u])o++,u++;else{switch(r=t.subarray(o,u),yo.ts.parseType(r,e.pid)){case"pes":n=yo.ts.parsePesType(r,e.table),s=yo.ts.parsePayloadUnitStartIndicator(r),"audio"===n&&s&&(a=yo.ts.parsePesTime(r))&&(a.type="audio",i.audio.push(a),l=!0)}if(l)break;o+=vo,u+=vo}for(o=(u=t.byteLength)-vo,l=!1;0<=o;)if(71!==t[o]||71!==t[u])o--,u--;else{switch(r=t.subarray(o,u),yo.ts.parseType(r,e.pid)){case"pes":n=yo.ts.parsePesType(r,e.table),s=yo.ts.parsePayloadUnitStartIndicator(r),"audio"===n&&s&&(a=yo.ts.parsePesTime(r))&&(a.type="audio",i.audio.push(a),l=!0)}if(l)break;o-=vo,u-=vo}},bo=function(t,e,i){for(var r,n,s,a,o,u,l,c=0,h=vo,d=!1,p={data:[],size:0};h<t.byteLength;)if(71!==t[c]||71!==t[h])c++,h++;else{switch(r=t.subarray(c,h),yo.ts.parseType(r,e.pid)){case"pes":if(n=yo.ts.parsePesType(r,e.table),s=yo.ts.parsePayloadUnitStartIndicator(r),"video"===n&&(s&&!d&&(a=yo.ts.parsePesTime(r))&&(a.type="video",i.video.push(a),d=!0),!i.firstKeyFrame)){if(s&&0!==p.size){for(o=new Uint8Array(p.size),u=0;p.data.length;)l=p.data.shift(),o.set(l,u),u+=l.byteLength;yo.ts.videoPacketContainsKeyFrame(o)&&(i.firstKeyFrame=yo.ts.parsePesTime(o),i.firstKeyFrame.type="video"),p.size=0}p.data.push(r),p.size+=r.byteLength}}if(d&&i.firstKeyFrame)break;c+=vo,h+=vo}for(c=(h=t.byteLength)-vo,d=!1;0<=c;)if(71!==t[c]||71!==t[h])c--,h--;else{switch(r=t.subarray(c,h),yo.ts.parseType(r,e.pid)){case"pes":n=yo.ts.parsePesType(r,e.table),s=yo.ts.parsePayloadUnitStartIndicator(r),"video"===n&&s&&(a=yo.ts.parsePesTime(r))&&(a.type="video",i.video.push(a),d=!0)}if(d)break;c-=vo,h-=vo}},To=function(t){var e={pid:null,table:null},i={};for(var r in function(t,e){for(var i,r=0,n=vo;n<t.byteLength;)if(71!==t[r]||71!==t[n])r++,n++;else{switch(i=t.subarray(r,n),yo.ts.parseType(i,e.pid)){case"pat":e.pid||(e.pid=yo.ts.parsePat(i));break;case"pmt":e.table||(e.table=yo.ts.parsePmt(i))}if(e.pid&&e.table)return;r+=vo,n+=vo}}(t,e),e.table){if(e.table.hasOwnProperty(r))switch(e.table[r]){case Wa.H264_STREAM_TYPE:i.video=[],bo(t,e,i),0===i.video.length&&delete i.video;break;case Wa.ADTS_STREAM_TYPE:i.audio=[],_o(t,e,i),0===i.audio.length&&delete i.audio}}return i},So=function(t,e){var i,r;return(r=(i=t)[0]==="I".charCodeAt(0)&&i[1]==="D".charCodeAt(0)&&i[2]==="3".charCodeAt(0)?function(t){for(var e,i=!1,r=0,n=null,s=null,a=0,o=0;3<=t.length-o;){switch(yo.aac.parseType(t,o)){case"timed-metadata":if(t.length-o<10){i=!0;break}if((a=yo.aac.parseId3TagSize(t,o))>t.length){i=!0;break}null===s&&(e=t.subarray(o,o+a),s=yo.aac.parseAacTimestamp(e)),o+=a;break;case"audio":if(t.length-o<7){i=!0;break}if((a=yo.aac.parseAdtsSize(t,o))>t.length){i=!0;break}null===n&&(e=t.subarray(o,o+a),n=yo.aac.parseSampleRate(e)),r++,o+=a;break;default:o++}if(i)return null}if(null===n||null===s)return null;var u=9e4/n;return{audio:[{type:"audio",dts:s,pts:s},{type:"audio",dts:s+1024*r*u,pts:s+1024*r*u}]}}(t):To(t))&&(r.audio||r.video)?(function(t,e){if(t.audio&&t.audio.length){var i=e;"undefined"==typeof i&&(i=t.audio[0].dts),t.audio.forEach(function(t){t.dts=go(t.dts,i),t.pts=go(t.pts,i),t.dtsTime=t.dts/9e4,t.ptsTime=t.pts/9e4})}if(t.video&&t.video.length){var r=e;if("undefined"==typeof r&&(r=t.video[0].dts),t.video.forEach(function(t){t.dts=go(t.dts,r),t.pts=go(t.pts,r),t.dtsTime=t.dts/9e4,t.ptsTime=t.pts/9e4}),t.firstKeyFrame){var n=t.firstKeyFrame;n.dts=go(n.dts,r),n.pts=go(n.pts,r),n.dtsTime=n.dts/9e4,n.ptsTime=n.dts/9e4}}}(r,e),r):null};var ko=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},Co=function(){function r(t,e){for(var i=0;i<e.length;i++){var r=e[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return function(t,e,i){return e&&r(t.prototype,e),i&&r(t,i),t}}(),Eo=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!==("undefined"==typeof e?"undefined":v(e))&&"function"!=typeof e?t:e},wo=function(){var t=[[[],[],[],[],[]],[[],[],[],[],[]]],e=t[0],i=t[1],r=e[4],n=i[4],s=void 0,a=void 0,o=void 0,u=[],l=[],c=void 0,h=void 0,d=void 0,p=void 0,f=void 0;for(s=0;s<256;s++)l[(u[s]=s<<1^283*(s>>7))^s]=s;for(a=o=0;!r[a];a^=c||1,o=l[o]||1)for(d=(d=o^o<<1^o<<2^o<<3^o<<4)>>8^255&d^99,f=16843009*u[h=u[c=u[n[r[a]=d]=a]]]^65537*h^257*c^16843008*a,p=257*u[d]^16843008*d,s=0;s<4;s++)e[s][a]=p=p<<24^p>>>8,i[s][d]=f=f<<24^f>>>8;for(s=0;s<5;s++)e[s]=e[s].slice(0),i[s]=i[s].slice(0);return t},Ao=null,Lo=function(){function c(t){ko(this,c),Ao||(Ao=wo()),this._tables=[[Ao[0][0].slice(),Ao[0][1].slice(),Ao[0][2].slice(),Ao[0][3].slice(),Ao[0][4].slice()],[Ao[1][0].slice(),Ao[1][1].slice(),Ao[1][2].slice(),Ao[1][3].slice(),Ao[1][4].slice()]];var e=void 0,i=void 0,r=void 0,n=void 0,s=void 0,a=this._tables[0][4],o=this._tables[1],u=t.length,l=1;if(4!==u&&6!==u&&8!==u)throw new Error("Invalid aes key size");for(n=t.slice(0),s=[],this._key=[n,s],e=u;e<4*u+28;e++)r=n[e-1],(e%u==0||8===u&&e%u==4)&&(r=a[r>>>24]<<24^a[r>>16&255]<<16^a[r>>8&255]<<8^a[255&r],e%u==0&&(r=r<<8^r>>>24^l<<24,l=l<<1^283*(l>>7))),n[e]=n[e-u]^r;for(i=0;e;i++,e--)r=n[3&i?e:e-4],s[i]=e<=4||i<4?r:o[0][a[r>>>24]]^o[1][a[r>>16&255]]^o[2][a[r>>8&255]]^o[3][a[255&r]]}return c.prototype.decrypt=function(t,e,i,r,n,s){var a=this._key[1],o=t^a[0],u=r^a[1],l=i^a[2],c=e^a[3],h=void 0,d=void 0,p=void 0,f=a.length/4-2,m=void 0,g=4,y=this._tables[1],v=y[0],_=y[1],b=y[2],T=y[3],S=y[4];for(m=0;m<f;m++)h=v[o>>>24]^_[u>>16&255]^b[l>>8&255]^T[255&c]^a[g],d=v[u>>>24]^_[l>>16&255]^b[c>>8&255]^T[255&o]^a[g+1],p=v[l>>>24]^_[c>>16&255]^b[o>>8&255]^T[255&u]^a[g+2],c=v[c>>>24]^_[o>>16&255]^b[u>>8&255]^T[255&l]^a[g+3],g+=4,o=h,u=d,l=p;for(m=0;m<4;m++)n[(3&-m)+s]=S[o>>>24]<<24^S[u>>16&255]<<16^S[l>>8&255]<<8^S[255&c]^a[g++],h=o,o=u,u=l,l=c,c=h},c}(),Po=function(){function t(){ko(this,t),this.listeners={}}return t.prototype.on=function(t,e){this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(e)},t.prototype.off=function(t,e){if(!this.listeners[t])return!1;var i=this.listeners[t].indexOf(e);return this.listeners[t].splice(i,1),-1<i},t.prototype.trigger=function(t){var e=this.listeners[t];if(e)if(2===arguments.length)for(var i=e.length,r=0;r<i;++r)e[r].call(this,arguments[1]);else for(var n=Array.prototype.slice.call(arguments,1),s=e.length,a=0;a<s;++a)e[a].apply(this,n)},t.prototype.dispose=function(){this.listeners={}},t.prototype.pipe=function(e){this.on("data",function(t){e.push(t)})},t}(),Oo=function(e){function i(){ko(this,i);var t=Eo(this,e.call(this,Po));return t.jobs=[],t.delay=1,t.timeout_=null,t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+("undefined"==typeof e?"undefined":v(e)));t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(i,e),i.prototype.processJob_=function(){this.jobs.shift()(),this.jobs.length?this.timeout_=setTimeout(this.processJob_.bind(this),this.delay):this.timeout_=null},i.prototype.push=function(t){this.jobs.push(t),this.timeout_||(this.timeout_=setTimeout(this.processJob_.bind(this),this.delay))},i}(Po),xo=function(t){return t<<24|(65280&t)<<8|(16711680&t)>>8|t>>>24},Io=function(t,e,i){var r=new Int32Array(t.buffer,t.byteOffset,t.byteLength>>2),n=new Lo(Array.prototype.slice.call(e)),s=new Uint8Array(t.byteLength),a=new Int32Array(s.buffer),o=void 0,u=void 0,l=void 0,c=void 0,h=void 0,d=void 0,p=void 0,f=void 0,m=void 0;for(o=i[0],u=i[1],l=i[2],c=i[3],m=0;m<r.length;m+=4)h=xo(r[m]),d=xo(r[m+1]),p=xo(r[m+2]),f=xo(r[m+3]),n.decrypt(h,d,p,f,a,m),a[m]=xo(a[m]^o),a[m+1]=xo(a[m+1]^u),a[m+2]=xo(a[m+2]^l),a[m+3]=xo(a[m+3]^c),o=h,u=d,l=p,c=f;return s},Do=function(){function u(t,e,i,r){ko(this,u);var n=u.STEP,s=new Int32Array(t.buffer),a=new Uint8Array(t.byteLength),o=0;for(this.asyncStream_=new Oo,this.asyncStream_.push(this.decryptChunk_(s.subarray(o,o+n),e,i,a)),o=n;o<s.length;o+=n)i=new Uint32Array([xo(s[o-4]),xo(s[o-3]),xo(s[o-2]),xo(s[o-1])]),this.asyncStream_.push(this.decryptChunk_(s.subarray(o,o+n),e,i,a));this.asyncStream_.push(function(){var t;r(null,(t=a).subarray(0,t.byteLength-t[t.byteLength-1]))})}return u.prototype.decryptChunk_=function(e,i,r,n){return function(){var t=Io(e,i,r);n.set(t,e.byteOffset)}},Co(u,null,[{key:"STEP",get:function(){return 32e3}}]),u}(),Ro=function(t,e){return/^[a-z]+:/i.test(e)?e:(/\/\//i.test(t)||(t=Os.buildAbsoluteURL(g.location.href,t)),Os.buildAbsoluteURL(t,e))},Mo=As.mergeOptions,Uo=As.log,No=function(n,s){["AUDIO","SUBTITLES"].forEach(function(t){for(var e in n.mediaGroups[t])for(var i in n.mediaGroups[t][e]){var r=n.mediaGroups[t][e][i];s(r,t,e,i)}})},Bo=function(t,e){var i=Mo(t,{}),r=i.playlists[e.uri];if(!r)return null;if(r.segments&&e.segments&&r.segments.length===e.segments.length&&r.mediaSequence===e.mediaSequence)return null;var n=Mo(r,e);r.segments&&(n.segments=function(t,e,i){var r=e.slice();i=i||0;for(var n=Math.min(t.length,e.length+i),s=i;s<n;s++)r[s-i]=Mo(t[s],r[s-i]);return r}(r.segments,e.segments,e.mediaSequence-r.mediaSequence)),n.segments.forEach(function(t){var e,i;e=t,i=n.resolvedUri,e.resolvedUri||(e.resolvedUri=Ro(i,e.uri)),e.key&&!e.key.resolvedUri&&(e.key.resolvedUri=Ro(i,e.key.uri)),e.map&&!e.map.resolvedUri&&(e.map.resolvedUri=Ro(i,e.map.uri))});for(var s=0;s<i.playlists.length;s++)i.playlists[s].uri===e.uri&&(i.playlists[s]=n);return i.playlists[e.uri]=n,i},jo=function(t){for(var e=t.playlists.length;e--;){var i=t.playlists[e];(t.playlists[i.uri]=i).resolvedUri=Ro(t.uri,i.uri),i.id=e,i.attributes||(i.attributes={},Uo.warn("Invalid playlist STREAM-INF detected. Missing BANDWIDTH attribute."))}},Fo=function(e){No(e,function(t){t.uri&&(t.resolvedUri=Ro(e.uri,t.uri))})},Ho=function(t,e){var i=t.segments[t.segments.length-1];return e&&i&&i.duration?1e3*i.duration:500*(t.targetDuration||10)},Vo=function(n){function s(t,e,i){y(this,s);var r=b(this,n.call(this));if(r.srcUrl=t,r.hls_=e,r.withCredentials=i,!r.srcUrl)throw new Error("A non-empty playlist URL is required");return r.state="HAVE_NOTHING",r.on("mediaupdatetimeout",function(){"HAVE_METADATA"===r.state&&(r.state="HAVE_CURRENT_METADATA",r.request=r.hls_.xhr({uri:Ro(r.master.uri,r.media().uri),withCredentials:r.withCredentials},function(t,e){if(r.request)return t?r.playlistRequestError(r.request,r.media().uri,"HAVE_METADATA"):void r.haveMetadata(r.request,r.media().uri)}))}),r}return _(s,n),s.prototype.playlistRequestError=function(t,e,i){this.request=null,i&&(this.state=i),this.error={playlist:this.master.playlists[e],status:t.status,message:"HLS playlist request error at URL: "+e,responseText:t.responseText,code:500<=t.status?4:2},this.trigger("error")},s.prototype.haveMetadata=function(t,e){var i=this;this.request=null,this.state="HAVE_METADATA";var r=new js;r.push(t.responseText),r.end(),r.manifest.uri=e,r.manifest.attributes=r.manifest.attributes||{};var n=Bo(this.master,r.manifest);this.targetDuration=r.manifest.targetDuration,n?(this.master=n,this.media_=this.master.playlists[r.manifest.uri]):this.trigger("playlistunchanged"),this.media().endList||(g.clearTimeout(this.mediaUpdateTimeout),this.mediaUpdateTimeout=g.setTimeout(function(){i.trigger("mediaupdatetimeout")},Ho(this.media(),!!n))),this.trigger("loadedplaylist")},s.prototype.dispose=function(){this.stopRequest(),g.clearTimeout(this.mediaUpdateTimeout)},s.prototype.stopRequest=function(){if(this.request){var t=this.request;this.request=null,t.onreadystatechange=null,t.abort()}},s.prototype.media=function(i){var r=this;if(!i)return this.media_;if("HAVE_NOTHING"===this.state)throw new Error("Cannot switch media playlist from "+this.state);var n=this.state;if("string"==typeof i){if(!this.master.playlists[i])throw new Error("Unknown playlist URI: "+i);i=this.master.playlists[i]}var t=!this.media_||i.uri!==this.media_.uri;if(this.master.playlists[i.uri].endList)return this.request&&(this.request.onreadystatechange=null,this.request.abort(),this.request=null),this.state="HAVE_METADATA",this.media_=i,void(t&&(this.trigger("mediachanging"),this.trigger("mediachange")));if(t){if(this.state="SWITCHING_MEDIA",this.request){if(Ro(this.master.uri,i.uri)===this.request.url)return;this.request.onreadystatechange=null,this.request.abort(),this.request=null}this.media_&&this.trigger("mediachanging"),this.request=this.hls_.xhr({uri:Ro(this.master.uri,i.uri),withCredentials:this.withCredentials},function(t,e){if(r.request){if(t)return r.playlistRequestError(r.request,i.uri,n);r.haveMetadata(e,i.uri),"HAVE_MASTER"===n?r.trigger("loadedmetadata"):r.trigger("mediachange")}})}},s.prototype.pause=function(){this.stopRequest(),g.clearTimeout(this.mediaUpdateTimeout),"HAVE_NOTHING"===this.state&&(this.started=!1),"SWITCHING_MEDIA"===this.state?this.media_?this.state="HAVE_METADATA":this.state="HAVE_MASTER":"HAVE_CURRENT_METADATA"===this.state&&(this.state="HAVE_METADATA")},s.prototype.load=function(t){var e=this;g.clearTimeout(this.mediaUpdateTimeout);var i=this.media();if(t){var r=i?i.targetDuration/2*1e3:5e3;this.mediaUpdateTimeout=g.setTimeout(function(){return e.load()},r)}else this.started?i&&!i.endList?this.trigger("mediaupdatetimeout"):this.trigger("loadedplaylist"):this.start()},s.prototype.start=function(){var r=this;this.started=!0,this.request=this.hls_.xhr({uri:this.srcUrl,withCredentials:this.withCredentials},function(t,e){if(r.request){if(r.request=null,t)return r.error={status:e.status,message:"HLS playlist request error at URL: "+r.srcUrl,responseText:e.responseText,code:2},"HAVE_NOTHING"===r.state&&(r.started=!1),r.trigger("error");var i=new js;return i.push(e.responseText),i.end(),r.state="HAVE_MASTER",i.manifest.uri=r.srcUrl,i.manifest.playlists?(r.master=i.manifest,jo(r.master),Fo(r.master),r.trigger("loadedplaylist"),void(r.request||r.media(i.manifest.playlists[0]))):(r.master={mediaGroups:{AUDIO:{},VIDEO:{},"CLOSED-CAPTIONS":{},SUBTITLES:{}},uri:g.location.href,playlists:[{uri:r.srcUrl,id:0}]},r.master.playlists[r.srcUrl]=r.master.playlists[0],r.master.playlists[0].resolvedUri=r.srcUrl,r.master.playlists[0].attributes=r.master.playlists[0].attributes||{},r.haveMetadata(e,r.srcUrl),r.trigger("loadedmetadata"))}})},s}(As.EventTarget),qo=As.createTimeRange,Wo=function(t,e,i){var r,n;return"undefined"==typeof e&&(e=t.mediaSequence+t.segments.length),e<t.mediaSequence?0:(r=function(t,e){var i=0,r=e-t.mediaSequence,n=t.segments[r];if(n){if("undefined"!=typeof n.start)return{result:n.start,precise:!0};if("undefined"!=typeof n.end)return{result:n.end-n.duration,precise:!0}}for(;r--;){if("undefined"!=typeof(n=t.segments[r]).end)return{result:i+n.end,precise:!0};if(i+=n.duration,"undefined"!=typeof n.start)return{result:i+n.start,precise:!0}}return{result:i,precise:!1}}(t,e)).precise?r.result:(n=function(t,e){for(var i=0,r=void 0,n=e-t.mediaSequence;n<t.segments.length;n++){if("undefined"!=typeof(r=t.segments[n]).start)return{result:r.start-i,precise:!0};if(i+=r.duration,"undefined"!=typeof r.end)return{result:r.end-i,precise:!0}}return{result:-1,precise:!1}}(t,e)).precise?n.result:r.result+i},zo=function(t,e,i){if(!t)return 0;if("number"!=typeof i&&(i=0),"undefined"==typeof e){if(t.totalDuration)return t.totalDuration;if(!t.endList)return g.Infinity}return Wo(t,e,i)},Go=function(t,e,i){var r=0;if(i<e){var n=[i,e];e=n[0],i=n[1]}if(e<0){for(var s=e;s<Math.min(0,i);s++)r+=t.targetDuration;e=0}for(var a=e;a<i;a++)r+=t.segments[a].duration;return r},Xo=function(t){if(!t.segments.length)return 0;for(var e=t.segments.length-1,i=t.segments[e].duration||t.targetDuration,r=i+2*t.targetDuration;e--&&!(r<=(i+=t.segments[e].duration)););return Math.max(0,e)},Yo=function(t,e,i){if(!t||!t.segments)return null;if(t.endList)return zo(t);if(null===e)return null;e=e||0;var r=i?Xo(t):t.segments.length;return Wo(t,t.mediaSequence+r,e)},$o=function(t){return t-Math.floor(t)==0},Ko=function(t,e){if($o(e))return e+.1*t;for(var i=e.toString().split(".")[1].length,r=1;r<=i;r++){var n=Math.pow(10,r),s=e*n;if($o(s)||r===i)return(s+t)/n}},Qo=Ko.bind(null,1),Jo=Ko.bind(null,-1),Zo=function(t){return t.excludeUntil&&t.excludeUntil>Date.now()},tu=function(t){return t.excludeUntil&&t.excludeUntil===1/0},eu=function(t){var e=Zo(t);return!t.disabled&&!e},iu=function(t,e){return e.attributes&&e.attributes[t]},ru=function(t,e){if(1===t.playlists.length)return!0;var i=e.attributes.BANDWIDTH||Number.MAX_VALUE;return 0===t.playlists.filter(function(t){return!!eu(t)&&(t.attributes.BANDWIDTH||0)<i}).length},nu={duration:zo,seekable:function(t,e){var i=e||0,r=Yo(t,e,!0);return null===r?qo():qo(i,r)},safeLiveIndex:Xo,getMediaInfoForTime:function(t,e,i,r){var n=void 0,s=void 0,a=t.segments.length,o=e-r;if(o<0){if(0<i)for(n=i-1;0<=n;n--)if(s=t.segments[n],0<(o+=Jo(s.duration)))return{mediaIndex:n,startTime:r-Go(t,i,n)};return{mediaIndex:0,startTime:e}}if(i<0){for(n=i;n<0;n++)if((o-=t.targetDuration)<0)return{mediaIndex:0,startTime:e};i=0}for(n=i;n<a;n++)if(s=t.segments[n],(o-=Qo(s.duration))<0)return{mediaIndex:n,startTime:r+Go(t,i,n)};return{mediaIndex:a-1,startTime:e}},isEnabled:eu,isDisabled:function(t){return t.disabled},isBlacklisted:Zo,isIncompatible:tu,playlistEnd:Yo,isAes:function(t){for(var e=0;e<t.segments.length;e++)if(t.segments[e].key)return!0;return!1},isFmp4:function(t){for(var e=0;e<t.segments.length;e++)if(t.segments[e].map)return!0;return!1},hasAttribute:iu,estimateSegmentRequestTime:function(t,e,i){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:0;return iu("BANDWIDTH",i)?(t*i.attributes.BANDWIDTH-8*r)/e:NaN},isLowestEnabledRendition:ru},su=As.xhr,au=As.mergeOptions,ou=function(){return function t(e,r){e=au({timeout:45e3},e);var i=t.beforeRequest||As.Hls.xhr.beforeRequest;if(i&&"function"==typeof i){var n=i(e);n&&(e=n)}var s=su(e,function(t,e){var i=s.response;!t&&i&&(s.responseTime=Date.now(),s.roundTripTime=s.responseTime-s.requestTime,s.bytesReceived=i.byteLength||i.length,s.bandwidth||(s.bandwidth=Math.floor(s.bytesReceived/s.roundTripTime*8*1e3))),e.headers&&(s.responseHeaders=e.headers),t&&"ETIMEDOUT"===t.code&&(s.timedout=!0),t||s.aborted||200===e.statusCode||206===e.statusCode||0===e.statusCode||(t=new Error("XHR Failed with a response of: "+(s&&(i||s.responseText)))),r(t,s)}),a=s.abort;return s.abort=function(){return s.aborted=!0,a.apply(s,arguments)},s.uri=e.uri,s.requestTime=Date.now(),s}},uu=function(t,e){var i=t.toString(16);return"00".substring(0,2-i.length)+i+(e%2?" ":"")},lu=function(t){return 32<=t&&t<126?String.fromCharCode(t):"."},cu=function(i){var r={};return Object.keys(i).forEach(function(t){var e=i[t];ArrayBuffer.isView(e)?r[t]={bytes:e.buffer,byteOffset:e.byteOffset,byteLength:e.byteLength}:r[t]=e}),r},hu=function(t){var e=t.byterange||{length:1/0,offset:0};return[e.length,e.offset,t.resolvedUri].join(",")},du=function(t){for(var e=Array.prototype.slice.call(t),i="",r=0;r<e.length/16;r++)i+=e.slice(16*r,16*r+16).map(uu).join("")+" "+e.slice(16*r,16*r+16).map(lu).join("")+"\n";return i},pu=Object.freeze({createTransferableMessage:cu,initSegmentId:hu,hexDump:du,tagDump:function(t){var e=t.bytes;return du(e)},textRanges:function(t){var e,i,r="",n=void 0;for(n=0;n<t.length;n++)r+=(i=n,(e=t).start(i)+"-"+e.end(i)+" ");return r}}),fu=1/30,mu=function(t,e){var i=[],r=void 0;if(t&&t.length)for(r=0;r<t.length;r++)e(t.start(r),t.end(r))&&i.push([t.start(r),t.end(r)]);return As.createTimeRanges(i)},gu=function(t,i){return mu(t,function(t,e){return t-fu<=i&&i<=e+fu})},yu=function(t,e){return mu(t,function(t){return e<=t-fu})},vu=function(t){var e=[];if(!t||!t.length)return"";for(var i=0;i<t.length;i++)e.push(t.start(i)+" => "+t.end(i));return e.join(", ")},_u=function(t){for(var e=[],i=0;i<t.length;i++)e.push({start:t.start(i),end:t.end(i)});return e},bu=function(t,e,i){var r=void 0,n=void 0;if(i&&i.cues)for(r=i.cues.length;r--;)(n=i.cues[r]).startTime<=e&&n.endTime>=t&&i.removeCue(n)},Tu=function(t){return isNaN(t)||Math.abs(t)===1/0?Number.MAX_VALUE:t},Su=function(t,e,i){var n=g.WebKitDataCue||g.VTTCue;if(e&&e.forEach(function(t){var e=t.stream;this.inbandTextTracks_[e].addCue(new n(t.startTime+this.timestampOffset,t.endTime+this.timestampOffset,t.text))},t),i){var s=Tu(t.mediaSource_.duration);if(i.forEach(function(t){var r=t.cueTime+this.timestampOffset;t.frames.forEach(function(t){var e,i=new n(r,r,t.value||t.url||t.data||"");i.frame=t,i.value=t,e=i,Object.defineProperties(e.frame,{id:{get:function(){return As.log.warn("cue.frame.id is deprecated. Use cue.value.key instead."),e.value.key}},value:{get:function(){return As.log.warn("cue.frame.value is deprecated. Use cue.value.data instead."),e.value.data}},privateData:{get:function(){return As.log.warn("cue.frame.privateData is deprecated. Use cue.value.data instead."),e.value.data}}}),this.metadataTrack_.addCue(i)},this)},t),t.metadataTrack_&&t.metadataTrack_.cues&&t.metadataTrack_.cues.length){for(var r=t.metadataTrack_.cues,a=[],o=0;o<r.length;o++)r[o]&&a.push(r[o]);var u=a.reduce(function(t,e){var i=t[e.startTime]||[];return i.push(e),t[e.startTime]=i,t},{}),l=Object.keys(u).sort(function(t,e){return Number(t)-Number(e)});l.forEach(function(t,e){var i=u[t],r=Number(l[e+1])||s;i.forEach(function(t){t.endTime=r})})}}},ku="undefined"!=typeof window?window:{},Cu="undefined"==typeof Symbol?"__target":Symbol(),Eu="application/javascript",wu=ku.BlobBuilder||ku.WebKitBlobBuilder||ku.MozBlobBuilder||ku.MSBlobBuilder,Au=ku.URL||ku.webkitURL||Au&&Au.msURL,Lu=ku.Worker;function Pu(n,s){return function(t){var e=this;if(!s)return new Lu(n);if(Lu&&!t){var i=Du(s.toString().replace(/^function.+?{/,"").slice(0,-1));return this[Cu]=new Lu(i),function(t,e){if(!t||!e)return;var i=t.terminate;t.objURL=e,t.terminate=function(){t.objURL&&Au.revokeObjectURL(t.objURL),i.call(t)}}(this[Cu],i),this[Cu]}var r={postMessage:function(t){e.onmessage&&setTimeout(function(){e.onmessage({data:t,target:r})})}};s.call(r),this.postMessage=function(t){setTimeout(function(){r.onmessage({data:t,target:e})})},this.isThisThread=!0}}if(Lu){var Ou,xu=Du("self.onmessage = function () {}"),Iu=new Uint8Array(1);try{(Ou=new Lu(xu)).postMessage(Iu,[Iu.buffer])}catch(t){Lu=null}finally{Au.revokeObjectURL(xu),Ou&&Ou.terminate()}}function Du(e){try{return Au.createObjectURL(new Blob([e],{type:Eu}))}catch(t){var i=new wu;return i.append(e),Au.createObjectURL(i.getBlob(type))}}var Ru=new Pu("./transmuxer-worker.worker.js",function(ie,t){var re=this;!function(){var o,e,i,n,s,r,t,a,u,l,c,h,d,p,f,m,g,y,v,_,b,T,S,k,C,E,w,A,L,P,O,x,I,D,R,M,U,N,B,j,F="undefined"!=typeof ie?ie:"undefined"!=typeof global?global:"undefined"!=typeof re?re:{},H="undefined"!=typeof ie?ie:"undefined"!=typeof F?F:"undefined"!=typeof re?re:{},V=Math.pow(2,32)-1;!function(){var t;if(T={avc1:[],avcC:[],btrt:[],dinf:[],dref:[],esds:[],ftyp:[],hdlr:[],mdat:[],mdhd:[],mdia:[],mfhd:[],minf:[],moof:[],moov:[],mp4a:[],mvex:[],mvhd:[],sdtp:[],smhd:[],stbl:[],stco:[],stsc:[],stsd:[],stsz:[],stts:[],styp:[],tfdt:[],tfhd:[],traf:[],trak:[],trun:[],trex:[],tkhd:[],vmhd:[]},"undefined"!=typeof Uint8Array){for(t in T)T.hasOwnProperty(t)&&(T[t]=[t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2),t.charCodeAt(3)]);S=new Uint8Array(["i".charCodeAt(0),"s".charCodeAt(0),"o".charCodeAt(0),"m".charCodeAt(0)]),C=new Uint8Array(["a".charCodeAt(0),"v".charCodeAt(0),"c".charCodeAt(0),"1".charCodeAt(0)]),k=new Uint8Array([0,0,0,1]),E=new Uint8Array([0,0,0,0,0,0,0,0,118,105,100,101,0,0,0,0,0,0,0,0,0,0,0,0,86,105,100,101,111,72,97,110,100,108,101,114,0]),w=new Uint8Array([0,0,0,0,0,0,0,0,115,111,117,110,0,0,0,0,0,0,0,0,0,0,0,0,83,111,117,110,100,72,97,110,100,108,101,114,0]),A={video:E,audio:w},O=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,12,117,114,108,32,0,0,0,1]),P=new Uint8Array([0,0,0,0,0,0,0,0]),x=new Uint8Array([0,0,0,0,0,0,0,0]),I=x,D=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0]),R=x,L=new Uint8Array([0,0,0,1,0,0,0,0,0,0,0,0])}}(),o=function(t){var e,i,r=[],n=0;for(e=1;e<arguments.length;e++)r.push(arguments[e]);for(e=r.length;e--;)n+=r[e].byteLength;for(i=new Uint8Array(n+8),new DataView(i.buffer,i.byteOffset,i.byteLength).setUint32(0,i.byteLength),i.set(t,4),e=0,n=8;e<r.length;e++)i.set(r[e],n),n+=r[e].byteLength;return i},e=function(){return o(T.dinf,o(T.dref,O))},i=function(t){return o(T.esds,new Uint8Array([0,0,0,0,3,25,0,0,0,4,17,64,21,0,6,0,0,0,218,192,0,0,218,192,5,2,t.audioobjecttype<<3|t.samplingfrequencyindex>>>1,t.samplingfrequencyindex<<7|t.channelcount<<3,6,1,2]))},f=function(t){return o(T.hdlr,A[t])},p=function(t){var e=new Uint8Array([0,0,0,0,0,0,0,2,0,0,0,3,0,1,95,144,t.duration>>>24&255,t.duration>>>16&255,t.duration>>>8&255,255&t.duration,85,196,0,0]);return t.samplerate&&(e[12]=t.samplerate>>>24&255,e[13]=t.samplerate>>>16&255,e[14]=t.samplerate>>>8&255,e[15]=255&t.samplerate),o(T.mdhd,e)},d=function(t){return o(T.mdia,p(t),f(t.type),r(t))},s=function(t){return o(T.mfhd,new Uint8Array([0,0,0,0,(4278190080&t)>>24,(16711680&t)>>16,(65280&t)>>8,255&t]))},r=function(t){return o(T.minf,"video"===t.type?o(T.vmhd,L):o(T.smhd,P),e(),g(t))},t=function(t,e){for(var i=[],r=e.length;r--;)i[r]=v(e[r]);return o.apply(null,[T.moof,s(t)].concat(i))},a=function(t){for(var e=t.length,i=[];e--;)i[e]=c(t[e]);return o.apply(null,[T.moov,l(4294967295)].concat(i).concat(u(t)))},u=function(t){for(var e=t.length,i=[];e--;)i[e]=_(t[e]);return o.apply(null,[T.mvex].concat(i))},l=function(t){var e=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,2,0,1,95,144,(4278190080&t)>>24,(16711680&t)>>16,(65280&t)>>8,255&t,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]);return o(T.mvhd,e)},m=function(t){var e,i,r=t.samples||[],n=new Uint8Array(4+r.length);for(i=0;i<r.length;i++)e=r[i].flags,n[i+4]=e.dependsOn<<4|e.isDependedOn<<2|e.hasRedundancy;return o(T.sdtp,n)},g=function(t){return o(T.stbl,y(t),o(T.stts,R),o(T.stsc,I),o(T.stsz,D),o(T.stco,x))},y=function(t){return o(T.stsd,new Uint8Array([0,0,0,0,0,0,0,1]),"video"===t.type?M(t):U(t))},M=function(t){var e,i=t.sps||[],r=t.pps||[],n=[],s=[];for(e=0;e<i.length;e++)n.push((65280&i[e].byteLength)>>>8),n.push(255&i[e].byteLength),n=n.concat(Array.prototype.slice.call(i[e]));for(e=0;e<r.length;e++)s.push((65280&r[e].byteLength)>>>8),s.push(255&r[e].byteLength),s=s.concat(Array.prototype.slice.call(r[e]));return o(T.avc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,(65280&t.width)>>8,255&t.width,(65280&t.height)>>8,255&t.height,0,72,0,0,0,72,0,0,0,0,0,0,0,1,19,118,105,100,101,111,106,115,45,99,111,110,116,114,105,98,45,104,108,115,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),o(T.avcC,new Uint8Array([1,t.profileIdc,t.profileCompatibility,t.levelIdc,255].concat([i.length]).concat(n).concat([r.length]).concat(s))),o(T.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])))},U=function(t){return o(T.mp4a,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,(65280&t.channelcount)>>8,255&t.channelcount,(65280&t.samplesize)>>8,255&t.samplesize,0,0,0,0,(65280&t.samplerate)>>8,255&t.samplerate,0,0]),i(t))},h=function(t){var e=new Uint8Array([0,0,0,7,0,0,0,0,0,0,0,0,(4278190080&t.id)>>24,(16711680&t.id)>>16,(65280&t.id)>>8,255&t.id,0,0,0,0,(4278190080&t.duration)>>24,(16711680&t.duration)>>16,(65280&t.duration)>>8,255&t.duration,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,(65280&t.width)>>8,255&t.width,0,0,(65280&t.height)>>8,255&t.height,0,0]);return o(T.tkhd,e)},v=function(t){var e,i,r,n,s,a;return e=o(T.tfhd,new Uint8Array([0,0,0,58,(4278190080&t.id)>>24,(16711680&t.id)>>16,(65280&t.id)>>8,255&t.id,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0])),s=Math.floor(t.baseMediaDecodeTime/(V+1)),a=Math.floor(t.baseMediaDecodeTime%(V+1)),i=o(T.tfdt,new Uint8Array([1,0,0,0,s>>>24&255,s>>>16&255,s>>>8&255,255&s,a>>>24&255,a>>>16&255,a>>>8&255,255&a])),92,"audio"===t.type?(r=b(t,92),o(T.traf,e,i,r)):(n=m(t),r=b(t,n.length+92),o(T.traf,e,i,r,n))},c=function(t){return t.duration=t.duration||4294967295,o(T.trak,h(t),d(t))},_=function(t){var e=new Uint8Array([0,0,0,0,(4278190080&t.id)>>24,(16711680&t.id)>>16,(65280&t.id)>>8,255&t.id,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]);return"video"!==t.type&&(e[e.length-1]=0),o(T.trex,e)},j=function(t,e){var i=0,r=0,n=0,s=0;return t.length&&(void 0!==t[0].duration&&(i=1),void 0!==t[0].size&&(r=2),void 0!==t[0].flags&&(n=4),void 0!==t[0].compositionTimeOffset&&(s=8)),[0,0,i|r|n|s,1,(4278190080&t.length)>>>24,(16711680&t.length)>>>16,(65280&t.length)>>>8,255&t.length,(4278190080&e)>>>24,(16711680&e)>>>16,(65280&e)>>>8,255&e]},B=function(t,e){var i,r,n,s;for(e+=20+16*(r=t.samples||[]).length,i=j(r,e),s=0;s<r.length;s++)n=r[s],i=i.concat([(4278190080&n.duration)>>>24,(16711680&n.duration)>>>16,(65280&n.duration)>>>8,255&n.duration,(4278190080&n.size)>>>24,(16711680&n.size)>>>16,(65280&n.size)>>>8,255&n.size,n.flags.isLeading<<2|n.flags.dependsOn,n.flags.isDependedOn<<6|n.flags.hasRedundancy<<4|n.flags.paddingValue<<1|n.flags.isNonSyncSample,61440&n.flags.degradationPriority,15&n.flags.degradationPriority,(4278190080&n.compositionTimeOffset)>>>24,(16711680&n.compositionTimeOffset)>>>16,(65280&n.compositionTimeOffset)>>>8,255&n.compositionTimeOffset]);return o(T.trun,new Uint8Array(i))},N=function(t,e){var i,r,n,s;for(e+=20+8*(r=t.samples||[]).length,i=j(r,e),s=0;s<r.length;s++)n=r[s],i=i.concat([(4278190080&n.duration)>>>24,(16711680&n.duration)>>>16,(65280&n.duration)>>>8,255&n.duration,(4278190080&n.size)>>>24,(16711680&n.size)>>>16,(65280&n.size)>>>8,255&n.size]);return o(T.trun,new Uint8Array(i))},b=function(t,e){return"audio"===t.type?N(t,e):B(t,e)};var q={ftyp:n=function(){return o(T.ftyp,S,k,S,C)},mdat:function(t){return o(T.mdat,t)},moof:t,moov:a,initSegment:function(t){var e,i=n(),r=a(t);return(e=new Uint8Array(i.byteLength+r.byteLength)).set(i),e.set(r,i.byteLength),e}},W=function(){this.init=function(){var s={};this.on=function(t,e){s[t]||(s[t]=[]),s[t]=s[t].concat(e)},this.off=function(t,e){var i;return!!s[t]&&(i=s[t].indexOf(e),s[t]=s[t].slice(),s[t].splice(i,1),-1<i)},this.trigger=function(t){var e,i,r,n;if(e=s[t])if(2===arguments.length)for(r=e.length,i=0;i<r;++i)e[i].call(this,arguments[1]);else{for(n=[],i=arguments.length,i=1;i<arguments.length;++i)n.push(arguments[i]);for(r=e.length,i=0;i<r;++i)e[i].apply(this,n)}},this.dispose=function(){s={}}}};W.prototype.pipe=function(e){return this.on("data",function(t){e.push(t)}),this.on("done",function(t){e.flush(t)}),e},W.prototype.push=function(t){this.trigger("data",t)},W.prototype.flush=function(t){this.trigger("done",t)};var z=W,G=function t(){t.prototype.init.call(this),this.captionPackets_=[],this.ccStreams_=[new Q(0,0),new Q(0,1),new Q(1,0),new Q(1,1)],this.reset(),this.ccStreams_.forEach(function(t){t.on("data",this.trigger.bind(this,"data")),t.on("done",this.trigger.bind(this,"done"))},this)};(G.prototype=new z).push=function(t){var e,i,r;if("sei_rbsp"===t.nalUnitType&&(4===(e=function(t){for(var e=0,i={payloadType:-1,payloadSize:0},r=0,n=0;e<t.byteLength&&128!==t[e];){for(;255===t[e];)r+=255,e++;for(r+=t[e++];255===t[e];)n+=255,e++;if(n+=t[e++],!i.payload&&4===r){i.payloadType=r,i.payloadSize=n,i.payload=t.subarray(e,e+n);break}e+=n,n=r=0}return i}(t.escapedRBSP)).payloadType&&(i=181!==(r=e).payload[0]?null:49!=(r.payload[1]<<8|r.payload[2])?null:"GA94"!==String.fromCharCode(r.payload[3],r.payload[4],r.payload[5],r.payload[6])?null:3!==r.payload[7]?null:r.payload.subarray(8,r.payload.length-1))))if(t.dts<this.latestDts_)this.ignoreNextEqualDts_=!0;else{if(t.dts===this.latestDts_&&this.ignoreNextEqualDts_)return this.numSameDts_--,void(this.numSameDts_||(this.ignoreNextEqualDts_=!1));this.captionPackets_=this.captionPackets_.concat(function(t,e){var i,r,n,s,a=[];if(!(64&e[0]))return a;for(r=31&e[0],i=0;i<r;i++)s={type:3&e[2+(n=3*i)],pts:t},4&e[n+2]&&(s.ccData=e[n+3]<<8|e[n+4],a.push(s));return a}(t.pts,i)),this.latestDts_!==t.dts&&(this.numSameDts_=0),this.numSameDts_++,this.latestDts_=t.dts}},G.prototype.flush=function(){this.captionPackets_.length?(this.captionPackets_.forEach(function(t,e){t.presortIndex=e}),this.captionPackets_.sort(function(t,e){return t.pts===e.pts?t.presortIndex-e.presortIndex:t.pts-e.pts}),this.captionPackets_.forEach(function(t){t.type<2&&this.dispatchCea608Packet(t)},this),this.captionPackets_.length=0,this.ccStreams_.forEach(function(t){t.flush()},this)):this.ccStreams_.forEach(function(t){t.flush()},this)},G.prototype.reset=function(){this.latestDts_=null,this.ignoreNextEqualDts_=!1,this.numSameDts_=0,this.activeCea608Channel_=[null,null],this.ccStreams_.forEach(function(t){t.reset()})},G.prototype.dispatchCea608Packet=function(t){this.setsChannel1Active(t)?this.activeCea608Channel_[t.type]=0:this.setsChannel2Active(t)&&(this.activeCea608Channel_[t.type]=1),null!==this.activeCea608Channel_[t.type]&&this.ccStreams_[(t.type<<1)+this.activeCea608Channel_[t.type]].push(t)},G.prototype.setsChannel1Active=function(t){return 4096==(30720&t.ccData)},G.prototype.setsChannel2Active=function(t){return 6144==(30720&t.ccData)};var X={42:225,92:233,94:237,95:243,96:250,123:231,124:247,125:209,126:241,127:9608,304:174,305:176,306:189,307:191,308:8482,309:162,310:163,311:9834,312:224,313:160,314:232,315:226,316:234,317:238,318:244,319:251,544:193,545:201,546:211,547:218,548:220,549:252,550:8216,551:161,552:42,553:39,554:8212,555:169,556:8480,557:8226,558:8220,559:8221,560:192,561:194,562:199,563:200,564:202,565:203,566:235,567:206,568:207,569:239,570:212,571:217,572:249,573:219,574:171,575:187,800:195,801:227,802:205,803:204,804:236,805:210,806:242,807:213,808:245,809:123,810:125,811:92,812:94,813:95,814:124,815:126,816:196,817:228,818:214,819:246,820:223,821:165,822:164,823:9474,824:197,825:229,826:216,827:248,828:9484,829:9488,830:9492,831:9496},Y=function(t){return null===t?"":(t=X[t]||t,String.fromCharCode(t))},$=[4352,4384,4608,4640,5376,5408,5632,5664,5888,5920,4096,4864,4896,5120,5152],K=function(){for(var t=[],e=15;e--;)t.push("");return t},Q=function t(e,i){t.prototype.init.call(this),this.field_=e||0,this.dataChannel_=i||0,this.name_="CC"+(1+(this.field_<<1|this.dataChannel_)),this.setConstants(),this.reset(),this.push=function(t){var e,i,r,n,s;if((e=32639&t.ccData)!==this.lastControlCode_){if(4096==(61440&e)?this.lastControlCode_=e:e!==this.PADDING_&&(this.lastControlCode_=null),r=e>>>8,n=255&e,e!==this.PADDING_)if(e===this.RESUME_CAPTION_LOADING_)this.mode_="popOn";else if(e===this.END_OF_CAPTION_)this.clearFormatting(t.pts),this.flushDisplayed(t.pts),i=this.displayed_,this.displayed_=this.nonDisplayed_,this.nonDisplayed_=i,this.startPts_=t.pts;else if(e===this.ROLL_UP_2_ROWS_)this.topRow_=13,this.mode_="rollUp";else if(e===this.ROLL_UP_3_ROWS_)this.topRow_=12,this.mode_="rollUp";else if(e===this.ROLL_UP_4_ROWS_)this.topRow_=11,this.mode_="rollUp";else if(e===this.CARRIAGE_RETURN_)this.clearFormatting(t.pts),this.flushDisplayed(t.pts),this.shiftRowsUp_(),this.startPts_=t.pts;else if(e===this.BACKSPACE_)"popOn"===this.mode_?this.nonDisplayed_[14]=this.nonDisplayed_[14].slice(0,-1):this.displayed_[14]=this.displayed_[14].slice(0,-1);else if(e===this.ERASE_DISPLAYED_MEMORY_)this.flushDisplayed(t.pts),this.displayed_=K();else if(e===this.ERASE_NON_DISPLAYED_MEMORY_)this.nonDisplayed_=K();else if(e===this.RESUME_DIRECT_CAPTIONING_)this.mode_="paintOn";else if(this.isSpecialCharacter(r,n))s=Y((r=(3&r)<<8)|n),this[this.mode_](t.pts,s),this.column_++;else if(this.isExtCharacter(r,n))"popOn"===this.mode_?this.nonDisplayed_[this.row_]=this.nonDisplayed_[this.row_].slice(0,-1):this.displayed_[14]=this.displayed_[14].slice(0,-1),s=Y((r=(3&r)<<8)|n),this[this.mode_](t.pts,s),this.column_++;else if(this.isMidRowCode(r,n))this.clearFormatting(t.pts),this[this.mode_](t.pts," "),this.column_++,14==(14&n)&&this.addFormatting(t.pts,["i"]),1==(1&n)&&this.addFormatting(t.pts,["u"]);else if(this.isOffsetControlCode(r,n))this.column_+=3&n;else if(this.isPAC(r,n)){var a=$.indexOf(7968&e);a!==this.row_&&(this.clearFormatting(t.pts),this.row_=a),1&n&&-1===this.formatting_.indexOf("u")&&this.addFormatting(t.pts,["u"]),16==(16&e)&&(this.column_=4*((14&e)>>1)),this.isColorPAC(n)&&14==(14&n)&&this.addFormatting(t.pts,["i"])}else this.isNormalChar(r)&&(0===n&&(n=null),s=Y(r),s+=Y(n),this[this.mode_](t.pts,s),this.column_+=s.length)}else this.lastControlCode_=null}};Q.prototype=new z,Q.prototype.flushDisplayed=function(t){var e=this.displayed_.map(function(t){return t.trim()}).join("\n").replace(/^\n+|\n+$/g,"");e.length&&this.trigger("data",{startPts:this.startPts_,endPts:t,text:e,stream:this.name_})},Q.prototype.reset=function(){this.mode_="popOn",this.topRow_=0,this.startPts_=0,this.displayed_=K(),this.nonDisplayed_=K(),this.lastControlCode_=null,this.column_=0,this.row_=14,this.formatting_=[]},Q.prototype.setConstants=function(){0===this.dataChannel_?(this.BASE_=16,this.EXT_=17,this.CONTROL_=(20|this.field_)<<8,this.OFFSET_=23):1===this.dataChannel_&&(this.BASE_=24,this.EXT_=25,this.CONTROL_=(28|this.field_)<<8,this.OFFSET_=31),this.PADDING_=0,this.RESUME_CAPTION_LOADING_=32|this.CONTROL_,this.END_OF_CAPTION_=47|this.CONTROL_,this.ROLL_UP_2_ROWS_=37|this.CONTROL_,this.ROLL_UP_3_ROWS_=38|this.CONTROL_,this.ROLL_UP_4_ROWS_=39|this.CONTROL_,this.CARRIAGE_RETURN_=45|this.CONTROL_,this.RESUME_DIRECT_CAPTIONING_=41|this.CONTROL_,this.BACKSPACE_=33|this.CONTROL_,this.ERASE_DISPLAYED_MEMORY_=44|this.CONTROL_,this.ERASE_NON_DISPLAYED_MEMORY_=46|this.CONTROL_},Q.prototype.isSpecialCharacter=function(t,e){return t===this.EXT_&&48<=e&&e<=63},Q.prototype.isExtCharacter=function(t,e){return(t===this.EXT_+1||t===this.EXT_+2)&&32<=e&&e<=63},Q.prototype.isMidRowCode=function(t,e){return t===this.EXT_&&32<=e&&e<=47},Q.prototype.isOffsetControlCode=function(t,e){return t===this.OFFSET_&&33<=e&&e<=35},Q.prototype.isPAC=function(t,e){return t>=this.BASE_&&t<this.BASE_+8&&64<=e&&e<=127},Q.prototype.isColorPAC=function(t){return 64<=t&&t<=79||96<=t&&t<=127},Q.prototype.isNormalChar=function(t){return 32<=t&&t<=127},Q.prototype.addFormatting=function(t,e){this.formatting_=this.formatting_.concat(e);var i=e.reduce(function(t,e){return t+"<"+e+">"},"");this[this.mode_](t,i)},Q.prototype.clearFormatting=function(t){if(this.formatting_.length){var e=this.formatting_.reverse().reduce(function(t,e){return t+"</"+e+">"},"");this.formatting_=[],this[this.mode_](t,e)}},Q.prototype.popOn=function(t,e){var i=this.nonDisplayed_[this.row_];i+=e,this.nonDisplayed_[this.row_]=i},Q.prototype.rollUp=function(t,e){var i=this.displayed_[14];i+=e,this.displayed_[14]=i},Q.prototype.shiftRowsUp_=function(){var t;for(t=0;t<this.topRow_;t++)this.displayed_[t]="";for(t=this.topRow_;t<14;t++)this.displayed_[t]=this.displayed_[t+1];this.displayed_[14]=""},Q.prototype.paintOn=function(){};var J={CaptionStream:G,Cea608Stream:Q},Z={H264_STREAM_TYPE:27,ADTS_STREAM_TYPE:15,METADATA_STREAM_TYPE:21},tt=function(t,e){var i=1;for(e<t&&(i=-1);4294967296<Math.abs(e-t);)t+=8589934592*i;return t},et=function t(e){var i,r;t.prototype.init.call(this),this.type_=e,this.push=function(t){t.type===this.type_&&(void 0===r&&(r=t.dts),t.dts=tt(t.dts,r),t.pts=tt(t.pts,r),i=t.dts,this.trigger("data",t))},this.flush=function(){r=i,this.trigger("done")},this.discontinuity=function(){i=r=void 0}};et.prototype=new z;var it,rt=et,nt=function(t,e,i){var r,n="";for(r=e;r<i;r++)n+="%"+("00"+t[r].toString(16)).slice(-2);return n},st=function(t,e,i){return decodeURIComponent(nt(t,e,i))},at=function(t){return t[0]<<21|t[1]<<14|t[2]<<7|t[3]},ot={TXXX:function(t){var e;if(3===t.data[0]){for(e=1;e<t.data.length;e++)if(0===t.data[e]){t.description=st(t.data,1,e),t.value=st(t.data,e+1,t.data.length).replace(/\0*$/,"");break}t.data=t.value}},WXXX:function(t){var e;if(3===t.data[0])for(e=1;e<t.data.length;e++)if(0===t.data[e]){t.description=st(t.data,1,e),t.url=st(t.data,e+1,t.data.length);break}},PRIV:function(t){var e,i;for(e=0;e<t.data.length;e++)if(0===t.data[e]){t.owner=(i=t.data,unescape(nt(i,0,e)));break}t.privateData=t.data.subarray(e+1),t.data=t.privateData}};(it=function(t){var e,u={debug:!(!t||!t.debug),descriptor:t&&t.descriptor},l=0,c=[],h=0;if(it.prototype.init.call(this),this.dispatchType=Z.METADATA_STREAM_TYPE.toString(16),u.descriptor)for(e=0;e<u.descriptor.length;e++)this.dispatchType+=("00"+u.descriptor[e].toString(16)).slice(-2);this.push=function(t){var e,i,r,n,s;if("timed-metadata"===t.type)if(t.dataAlignmentIndicator&&(h=0,c.length=0),0===c.length&&(t.data.length<10||t.data[0]!=="I".charCodeAt(0)||t.data[1]!=="D".charCodeAt(0)||t.data[2]!=="3".charCodeAt(0)))u.debug;else if(c.push(t),h+=t.data.byteLength,1===c.length&&(l=at(t.data.subarray(6,10)),l+=10),!(h<l)){for(e={data:new Uint8Array(l),frames:[],pts:c[0].pts,dts:c[0].dts},s=0;s<l;)e.data.set(c[0].data.subarray(0,l-s),s),s+=c[0].data.byteLength,h-=c[0].data.byteLength,c.shift();i=10,64&e.data[5]&&(i+=4,i+=at(e.data.subarray(10,14)),l-=at(e.data.subarray(16,20)));do{if((r=at(e.data.subarray(i+4,i+8)))<1)return;if((n={id:String.fromCharCode(e.data[i],e.data[i+1],e.data[i+2],e.data[i+3]),data:e.data.subarray(i+10,i+r+10)}).key=n.id,ot[n.id]&&(ot[n.id](n),"com.apple.streaming.transportStreamTimestamp"===n.owner)){var a=n.data,o=(1&a[3])<<30|a[4]<<22|a[5]<<14|a[6]<<6|a[7]>>>2;o*=4,o+=3&a[7],n.timeStamp=o,void 0===e.pts&&void 0===e.dts&&(e.pts=n.timeStamp,e.dts=n.timeStamp),this.trigger("timestamp",n)}e.frames.push(n),i+=10,i+=r}while(i<l);this.trigger("data",e)}}}).prototype=new z;var ut,lt,ct,ht=it,dt=rt;(ut=function(){var n=new Uint8Array(188),s=0;ut.prototype.init.call(this),this.push=function(t){var e,i=0,r=188;for(s?((e=new Uint8Array(t.byteLength+s)).set(n.subarray(0,s)),e.set(t,s),s=0):e=t;r<e.byteLength;)71!==e[i]||71!==e[r]?(i++,r++):(this.trigger("data",e.subarray(i,r)),i+=188,r+=188);i<e.byteLength&&(n.set(e.subarray(i),0),s=e.byteLength-i)},this.flush=function(){188===s&&71===n[0]&&(this.trigger("data",n),s=0),this.trigger("done")}}).prototype=new z,(lt=function(){var r,n,s,a;lt.prototype.init.call(this),(a=this).packetsWaitingForPmt=[],this.programMapTable=void 0,r=function(t,e){var i=0;e.payloadUnitStartIndicator&&(i+=t[i]+1),"pat"===e.type?n(t.subarray(i),e):s(t.subarray(i),e)},n=function(t,e){e.section_number=t[7],e.last_section_number=t[8],a.pmtPid=(31&t[10])<<8|t[11],e.pmtPid=a.pmtPid},s=function(t,e){var i,r;if(1&t[5]){for(a.programMapTable={video:null,audio:null,"timed-metadata":{}},i=3+((15&t[1])<<8|t[2])-4,r=12+((15&t[10])<<8|t[11]);r<i;){var n=t[r],s=(31&t[r+1])<<8|t[r+2];n===Z.H264_STREAM_TYPE&&null===a.programMapTable.video?a.programMapTable.video=s:n===Z.ADTS_STREAM_TYPE&&null===a.programMapTable.audio?a.programMapTable.audio=s:n===Z.METADATA_STREAM_TYPE&&(a.programMapTable["timed-metadata"][s]=n),r+=5+((15&t[r+3])<<8|t[r+4])}e.programMapTable=a.programMapTable}},this.push=function(t){var e={},i=4;if(e.payloadUnitStartIndicator=!!(64&t[1]),e.pid=31&t[1],e.pid<<=8,e.pid|=t[2],1<(48&t[3])>>>4&&(i+=t[i]+1),0===e.pid)e.type="pat",r(t.subarray(i),e),this.trigger("data",e);else if(e.pid===this.pmtPid)for(e.type="pmt",r(t.subarray(i),e),this.trigger("data",e);this.packetsWaitingForPmt.length;)this.processPes_.apply(this,this.packetsWaitingForPmt.shift());else void 0===this.programMapTable?this.packetsWaitingForPmt.push([t,i,e]):this.processPes_(t,i,e)},this.processPes_=function(t,e,i){i.pid===this.programMapTable.video?i.streamType=Z.H264_STREAM_TYPE:i.pid===this.programMapTable.audio?i.streamType=Z.ADTS_STREAM_TYPE:i.streamType=this.programMapTable["timed-metadata"][i.pid],i.type="pes",i.data=t.subarray(e),this.trigger("data",i)}}).prototype=new z,lt.STREAM_TYPES={h264:27,adts:15},(ct=function(){var d=this,r={data:[],size:0},n={data:[],size:0},s={data:[],size:0},a=function(t,e,i){var r,n,s=new Uint8Array(t.size),a={type:e},o=0,u=0;if(t.data.length&&!(t.size<9)){for(a.trackId=t.data[0].pid,o=0;o<t.data.length;o++)n=t.data[o],s.set(n.data,u),u+=n.data.byteLength;var l,c,h;l=s,(c=a).packetLength=6+(l[4]<<8|l[5]),c.dataAlignmentIndicator=0!=(4&l[6]),192&(h=l[7])&&(c.pts=(14&l[9])<<27|(255&l[10])<<20|(254&l[11])<<12|(255&l[12])<<5|(254&l[13])>>>3,c.pts*=4,c.pts+=(6&l[13])>>>1,c.dts=c.pts,64&h&&(c.dts=(14&l[14])<<27|(255&l[15])<<20|(254&l[16])<<12|(255&l[17])<<5|(254&l[18])>>>3,c.dts*=4,c.dts+=(6&l[18])>>>1)),c.data=l.subarray(9+l[8]),r="video"===e||a.packetLength<=t.size,(i||r)&&(t.size=0,t.data.length=0),r&&d.trigger("data",a)}};ct.prototype.init.call(this),this.push=function(i){({pat:function(){},pes:function(){var t,e;switch(i.streamType){case Z.H264_STREAM_TYPE:case Z.H264_STREAM_TYPE:t=r,e="video";break;case Z.ADTS_STREAM_TYPE:t=n,e="audio";break;case Z.METADATA_STREAM_TYPE:t=s,e="timed-metadata";break;default:return}i.payloadUnitStartIndicator&&a(t,e,!0),t.data.push(i),t.size+=i.data.byteLength},pmt:function(){var t={type:"metadata",tracks:[]},e=i.programMapTable;null!==e.video&&t.tracks.push({timelineStartInfo:{baseMediaDecodeTime:0},id:+e.video,codec:"avc",type:"video"}),null!==e.audio&&t.tracks.push({timelineStartInfo:{baseMediaDecodeTime:0},id:+e.audio,codec:"adts",type:"audio"}),d.trigger("data",t)}})[i.type]()},this.flush=function(){a(r,"video"),a(n,"audio"),a(s,"timed-metadata"),this.trigger("done")}}).prototype=new z;var pt={PAT_PID:0,MP2T_PACKET_LENGTH:188,TransportPacketStream:ut,TransportParseStream:lt,ElementaryStream:ct,TimestampRolloverStream:dt,CaptionStream:J.CaptionStream,Cea608Stream:J.Cea608Stream,MetadataStream:ht};for(var ft in Z)Z.hasOwnProperty(ft)&&(pt[ft]=Z[ft]);var mt,gt=pt,yt=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350];(mt=function(){var l;mt.prototype.init.call(this),this.push=function(t){var e,i,r,n,s,a,o=0,u=0;if("audio"===t.type)for(l?(n=l,(l=new Uint8Array(n.byteLength+t.data.byteLength)).set(n),l.set(t.data,n.byteLength)):l=t.data;o+5<l.length;)if(255===l[o]&&240==(246&l[o+1])){if(i=2*(1&~l[o+1]),e=(3&l[o+3])<<11|l[o+4]<<3|(224&l[o+5])>>5,a=9e4*(s=1024*(1+(3&l[o+6])))/yt[(60&l[o+2])>>>2],r=o+e,l.byteLength<r)return;if(this.trigger("data",{pts:t.pts+u*a,dts:t.dts+u*a,sampleCount:s,audioobjecttype:1+(l[o+2]>>>6&3),channelcount:(1&l[o+2])<<2|(192&l[o+3])>>>6,samplerate:yt[(60&l[o+2])>>>2],samplingfrequencyindex:(60&l[o+2])>>>2,samplesize:16,data:l.subarray(o+7+i,r)}),l.byteLength===r)return void(l=void 0);u++,l=l.subarray(r)}else o++},this.flush=function(){this.trigger("done")}}).prototype=new z;var vt,_t,bt,Tt=mt,St=function(r){var n=r.byteLength,s=0,a=0;this.length=function(){return 8*n},this.bitsAvailable=function(){return 8*n+a},this.loadWord=function(){var t=r.byteLength-n,e=new Uint8Array(4),i=Math.min(4,n);if(0===i)throw new Error("no bytes available");e.set(r.subarray(t,t+i)),s=new DataView(e.buffer).getUint32(0),a=8*i,n-=i},this.skipBits=function(t){var e;t<a||(t-=a,t-=8*(e=Math.floor(t/8)),n-=e,this.loadWord()),s<<=t,a-=t},this.readBits=function(t){var e=Math.min(a,t),i=s>>>32-e;return 0<(a-=e)?s<<=e:0<n&&this.loadWord(),0<(e=t-e)?i<<e|this.readBits(e):i},this.skipLeadingZeros=function(){var t;for(t=0;t<a;++t)if(0!=(s&2147483648>>>t))return s<<=t,a-=t,t;return this.loadWord(),t+this.skipLeadingZeros()},this.skipUnsignedExpGolomb=function(){this.skipBits(1+this.skipLeadingZeros())},this.skipExpGolomb=function(){this.skipBits(1+this.skipLeadingZeros())},this.readUnsignedExpGolomb=function(){var t=this.skipLeadingZeros();return this.readBits(t+1)-1},this.readExpGolomb=function(){var t=this.readUnsignedExpGolomb();return 1&t?1+t>>>1:-1*(t>>>1)},this.readBoolean=function(){return 1===this.readBits(1)},this.readUnsignedByte=function(){return this.readBits(8)},this.loadWord()};(_t=function(){var i,r,n=0;_t.prototype.init.call(this),this.push=function(t){var e;for(r?((e=new Uint8Array(r.byteLength+t.data.byteLength)).set(r),e.set(t.data,r.byteLength),r=e):r=t.data;n<r.byteLength-3;n++)if(1===r[n+2]){i=n+5;break}for(;i<r.byteLength;)switch(r[i]){case 0:if(0!==r[i-1]){i+=2;break}if(0!==r[i-2]){i++;break}for(n+3!==i-2&&this.trigger("data",r.subarray(n+3,i-2));1!==r[++i]&&i<r.length;);n=i-2,i+=3;break;case 1:if(0!==r[i-1]||0!==r[i-2]){i+=3;break}this.trigger("data",r.subarray(n+3,i-2)),n=i-2,i+=3;break;default:i+=3}r=r.subarray(n),i-=n,n=0},this.flush=function(){r&&3<r.byteLength&&this.trigger("data",r.subarray(n+3)),r=null,n=0,this.trigger("done")}}).prototype=new z,bt={100:!0,110:!0,122:!0,244:!0,44:!0,83:!0,86:!0,118:!0,128:!0,138:!0,139:!0,134:!0},(vt=function(){var i,r,n,s,a,o,_,e=new _t;vt.prototype.init.call(this),(i=this).push=function(t){"video"===t.type&&(r=t.trackId,n=t.pts,s=t.dts,e.push(t))},e.on("data",function(t){var e={trackId:r,pts:n,dts:s,data:t};switch(31&t[0]){case 5:e.nalUnitType="slice_layer_without_partitioning_rbsp_idr";break;case 6:e.nalUnitType="sei_rbsp",e.escapedRBSP=a(t.subarray(1));break;case 7:e.nalUnitType="seq_parameter_set_rbsp",e.escapedRBSP=a(t.subarray(1)),e.config=o(e.escapedRBSP);break;case 8:e.nalUnitType="pic_parameter_set_rbsp";break;case 9:e.nalUnitType="access_unit_delimiter_rbsp"}i.trigger("data",e)}),e.on("done",function(){i.trigger("done")}),this.flush=function(){e.flush()},_=function(t,e){var i,r=8,n=8;for(i=0;i<t;i++)0!==n&&(n=(r+e.readExpGolomb()+256)%256),r=0===n?r:n},a=function(t){for(var e,i,r=t.byteLength,n=[],s=1;s<r-2;)0===t[s]&&0===t[s+1]&&3===t[s+2]?(n.push(s+2),s+=2):s++;if(0===n.length)return t;e=r-n.length,i=new Uint8Array(e);var a=0;for(s=0;s<e;a++,s++)a===n[0]&&(a++,n.shift()),i[s]=t[a];return i},o=function(t){var e,i,r,n,s,a,o,u,l,c,h,d,p,f=0,m=0,g=0,y=0,v=1;if(i=(e=new St(t)).readUnsignedByte(),n=e.readUnsignedByte(),r=e.readUnsignedByte(),e.skipUnsignedExpGolomb(),bt[i]&&(3===(s=e.readUnsignedExpGolomb())&&e.skipBits(1),e.skipUnsignedExpGolomb(),e.skipUnsignedExpGolomb(),e.skipBits(1),e.readBoolean()))for(h=3!==s?8:12,p=0;p<h;p++)e.readBoolean()&&_(p<6?16:64,e);if(e.skipUnsignedExpGolomb(),0===(a=e.readUnsignedExpGolomb()))e.readUnsignedExpGolomb();else if(1===a)for(e.skipBits(1),e.skipExpGolomb(),e.skipExpGolomb(),o=e.readUnsignedExpGolomb(),p=0;p<o;p++)e.skipExpGolomb();if(e.skipUnsignedExpGolomb(),e.skipBits(1),u=e.readUnsignedExpGolomb(),l=e.readUnsignedExpGolomb(),0===(c=e.readBits(1))&&e.skipBits(1),e.skipBits(1),e.readBoolean()&&(f=e.readUnsignedExpGolomb(),m=e.readUnsignedExpGolomb(),g=e.readUnsignedExpGolomb(),y=e.readUnsignedExpGolomb()),e.readBoolean()&&e.readBoolean()){switch(e.readUnsignedByte()){case 1:d=[1,1];break;case 2:d=[12,11];break;case 3:d=[10,11];break;case 4:d=[16,11];break;case 5:d=[40,33];break;case 6:d=[24,11];break;case 7:d=[20,11];break;case 8:d=[32,11];break;case 9:d=[80,33];break;case 10:d=[18,11];break;case 11:d=[15,11];break;case 12:d=[64,33];break;case 13:d=[160,99];break;case 14:d=[4,3];break;case 15:d=[3,2];break;case 16:d=[2,1];break;case 255:d=[e.readUnsignedByte()<<8|e.readUnsignedByte(),e.readUnsignedByte()<<8|e.readUnsignedByte()]}d&&(v=d[0]/d[1])}return{profileIdc:i,levelIdc:r,profileCompatibility:n,width:Math.ceil((16*(u+1)-2*f-2*m)*v),height:(2-c)*(l+1)*16-2*g-2*y}}}).prototype=new z;var kt,Ct={H264Stream:vt,NalByteStream:_t};(kt=function(){var o=new Uint8Array,u=0;kt.prototype.init.call(this),this.setTimestamp=function(t){u=t},this.parseId3TagSize=function(t,e){var i=t[e+6]<<21|t[e+7]<<14|t[e+8]<<7|t[e+9];return(16&t[e+5])>>4?i+20:i+10},this.parseAdtsSize=function(t,e){var i=(224&t[e+5])>>5,r=t[e+4]<<3;return 6144&t[e+3]|r|i},this.push=function(t){var e,i,r,n,s=0,a=0;for(o.length?(n=o.length,(o=new Uint8Array(t.byteLength+n)).set(o.subarray(0,n)),o.set(t,n)):o=t;3<=o.length-a;)if(o[a]!=="I".charCodeAt(0)||o[a+1]!=="D".charCodeAt(0)||o[a+2]!=="3".charCodeAt(0))if(!0&o[a]&&240==(240&o[a+1])){if(o.length-a<7)break;if((s=this.parseAdtsSize(o,a))>o.length)break;r={type:"audio",data:o.subarray(a,a+s),pts:u,dts:u},this.trigger("data",r),a+=s}else a++;else{if(o.length-a<10)break;if((s=this.parseId3TagSize(o,a))>o.length)break;i={type:"timed-metadata",data:o.subarray(a,a+s)},this.trigger("data",i),a+=s}e=o.length-a,o=0<e?o.subarray(a):new Uint8Array}}).prototype=new z;var Et,wt,At,Lt,Pt,Ot,xt,It,Dt,Rt,Mt,Ut,Nt,Bt,jt,Ft=kt,Ht=[33,16,5,32,164,27],Vt=[33,65,108,84,1,2,4,8,168,2,4,8,17,191,252],qt=function(t){for(var e=[];t--;)e.push(0);return e},Wt={96000:[Ht,[227,64],qt(154),[56]],88200:[Ht,[231],qt(170),[56]],64000:[Ht,[248,192],qt(240),[56]],48000:[Ht,[255,192],qt(268),[55,148,128],qt(54),[112]],44100:[Ht,[255,192],qt(268),[55,163,128],qt(84),[112]],32000:[Ht,[255,192],qt(268),[55,234],qt(226),[112]],24000:[Ht,[255,192],qt(268),[55,255,128],qt(268),[111,112],qt(126),[224]],16000:[Ht,[255,192],qt(268),[55,255,128],qt(268),[111,255],qt(269),[223,108],qt(195),[1,192]],12000:[Vt,qt(268),[3,127,248],qt(268),[6,255,240],qt(268),[13,255,224],qt(268),[27,253,128],qt(259),[56]],11025:[Vt,qt(268),[3,127,248],qt(268),[6,255,240],qt(268),[13,255,224],qt(268),[27,255,192],qt(268),[55,175,128],qt(108),[112]],8000:[Vt,qt(268),[3,121,16],qt(47),[7]]},zt=(Et=Wt,Object.keys(Et).reduce(function(t,e){return t[e]=new Uint8Array(Et[e].reduce(function(t,e){return t.concat(e)},[])),t},{})),Gt=(wt=function(t){return 9e4*t},At=function(t,e){return t*e},Lt=function(t){return t/9e4},Pt=function(t,e){return t/e},function(t,e){return wt(Pt(t,e))}),Xt=function(t,e){return At(Lt(t),e)},Yt=Ct.H264Stream,$t=["audioobjecttype","channelcount","samplerate","samplingfrequencyindex","samplesize"],Kt=["width","height","profileIdc","levelIdc","profileCompatibility"];Rt=function(t){return t[0]==="I".charCodeAt(0)&&t[1]==="D".charCodeAt(0)&&t[2]==="3".charCodeAt(0)},Bt=function(t,e){var i;if(t.length!==e.length)return!1;for(i=0;i<t.length;i++)if(t[i]!==e[i])return!1;return!0},jt=function(t){var e,i=0;for(e=0;e<t.length;e++)i+=t[e].data.byteLength;return i},(xt=function(n,s){var a=[],o=0,e=0,l=0,c=1/0;s=s||{},xt.prototype.init.call(this),this.push=function(e){Mt(n,e),n&&$t.forEach(function(t){n[t]=e[t]}),a.push(e)},this.setEarliestDts=function(t){e=t-n.timelineStartInfo.baseMediaDecodeTime},this.setVideoBaseMediaDecodeTime=function(t){c=t},this.setAudioAppendStart=function(t){l=t},this.flush=function(){var t,e,i,r;0!==a.length&&(t=this.trimAdtsFramesByEarliestDts_(a),n.baseMediaDecodeTime=Nt(n,s.keepOriginalTimestamps),this.prefixWithSilence_(n,t),n.samples=this.generateSampleTable_(t),i=q.mdat(this.concatenateFrameData_(t)),a=[],e=q.moof(o,[n]),r=new Uint8Array(e.byteLength+i.byteLength),o++,r.set(e),r.set(i,e.byteLength),Ut(n),this.trigger("data",{track:n,boxes:r})),this.trigger("done","AudioSegmentStream")},this.prefixWithSilence_=function(t,e){var i,r,n,s,a=0,o=0,u=0;if(e.length&&(i=Gt(t.baseMediaDecodeTime,t.samplerate),r=Math.ceil(9e4/(t.samplerate/1024)),l&&c&&(a=i-Math.max(l,c),u=(o=Math.floor(a/r))*r),!(o<1||45e3<u))){for((n=zt[t.samplerate])||(n=e[0].data),s=0;s<o;s++)e.splice(s,0,{data:n});t.baseMediaDecodeTime-=Math.floor(Xt(u,t.samplerate))}},this.trimAdtsFramesByEarliestDts_=function(t){return n.minSegmentDts>=e?t:(n.minSegmentDts=1/0,t.filter(function(t){return t.dts>=e&&(n.minSegmentDts=Math.min(n.minSegmentDts,t.dts),n.minSegmentPts=n.minSegmentDts,!0)}))},this.generateSampleTable_=function(t){var e,i,r=[];for(e=0;e<t.length;e++)i=t[e],r.push({size:i.data.byteLength,duration:1024});return r},this.concatenateFrameData_=function(t){var e,i,r=0,n=new Uint8Array(jt(t));for(e=0;e<t.length;e++)i=t[e],n.set(i.data,r),r+=i.data.byteLength;return n}}).prototype=new z,(Ot=function(o,u){var e,i,l=0,c=[],h=[];u=u||{},Ot.prototype.init.call(this),delete o.minPTS,this.gopCache_=[],this.push=function(t){Mt(o,t),"seq_parameter_set_rbsp"!==t.nalUnitType||e||(e=t.config,o.sps=[t.data],Kt.forEach(function(t){o[t]=e[t]},this)),"pic_parameter_set_rbsp"!==t.nalUnitType||i||(i=t.data,o.pps=[t.data]),c.push(t)},this.flush=function(){for(var t,e,i,r,n,s;c.length&&"access_unit_delimiter_rbsp"!==c[0].nalUnitType;)c.shift();if(0===c.length)return this.resetStream_(),void this.trigger("done","VideoSegmentStream");if(t=this.groupNalsIntoFrames_(c),(i=this.groupFramesIntoGops_(t))[0][0].keyFrame||((e=this.getGopForFusion_(c[0],o))?(i.unshift(e),i.byteLength+=e.byteLength,i.nalCount+=e.nalCount,i.pts=e.pts,i.dts=e.dts,i.duration+=e.duration):i=this.extendFirstKeyFrame_(i)),h.length){var a;if(!(a=u.alignGopsAtEnd?this.alignGopsAtEnd_(i):this.alignGopsAtStart_(i)))return this.gopCache_.unshift({gop:i.pop(),pps:o.pps,sps:o.sps}),this.gopCache_.length=Math.min(6,this.gopCache_.length),c=[],this.resetStream_(),void this.trigger("done","VideoSegmentStream");Ut(o),i=a}Mt(o,i),o.samples=this.generateSampleTable_(i),n=q.mdat(this.concatenateNalData_(i)),o.baseMediaDecodeTime=Nt(o,u.keepOriginalTimestamps),this.trigger("processedGopsInfo",i.map(function(t){return{pts:t.pts,dts:t.dts,byteLength:t.byteLength}})),this.gopCache_.unshift({gop:i.pop(),pps:o.pps,sps:o.sps}),this.gopCache_.length=Math.min(6,this.gopCache_.length),c=[],this.trigger("baseMediaDecodeTime",o.baseMediaDecodeTime),this.trigger("timelineStartInfo",o.timelineStartInfo),r=q.moof(l,[o]),s=new Uint8Array(r.byteLength+n.byteLength),l++,s.set(r),s.set(n,r.byteLength),this.trigger("data",{track:o,boxes:s}),this.resetStream_(),this.trigger("done","VideoSegmentStream")},this.resetStream_=function(){Ut(o),i=e=void 0},this.getGopForFusion_=function(t){var e,i,r,n,s,a=1/0;for(s=0;s<this.gopCache_.length;s++)r=(n=this.gopCache_[s]).gop,o.pps&&Bt(o.pps[0],n.pps[0])&&o.sps&&Bt(o.sps[0],n.sps[0])&&(r.dts<o.timelineStartInfo.dts||-1e4<=(e=t.dts-r.dts-r.duration)&&e<=45e3&&(!i||e<a)&&(i=n,a=e));return i?i.gop:null},this.extendFirstKeyFrame_=function(t){var e;return!t[0][0].keyFrame&&1<t.length&&(e=t.shift(),t.byteLength-=e.byteLength,t.nalCount-=e.nalCount,t[0][0].dts=e.dts,t[0][0].pts=e.pts,t[0][0].duration+=e.duration),t},this.groupNalsIntoFrames_=function(t){var e,i,r=[],n=[];for(e=r.byteLength=0;e<t.length;e++)"access_unit_delimiter_rbsp"===(i=t[e]).nalUnitType?(r.length&&(r.duration=i.dts-r.dts,n.push(r)),(r=[i]).byteLength=i.data.byteLength,r.pts=i.pts,r.dts=i.dts):("slice_layer_without_partitioning_rbsp_idr"===i.nalUnitType&&(r.keyFrame=!0),r.duration=i.dts-r.dts,r.byteLength+=i.data.byteLength,r.push(i));return n.length&&(!r.duration||r.duration<=0)&&(r.duration=n[n.length-1].duration),n.push(r),n},this.groupFramesIntoGops_=function(t){var e,i,r=[],n=[];for(r.byteLength=0,r.nalCount=0,r.duration=0,r.pts=t[0].pts,r.dts=t[0].dts,n.byteLength=0,n.nalCount=0,n.duration=0,n.pts=t[0].pts,n.dts=t[0].dts,e=0;e<t.length;e++)(i=t[e]).keyFrame?(r.length&&(n.push(r),n.byteLength+=r.byteLength,n.nalCount+=r.nalCount,n.duration+=r.duration),(r=[i]).nalCount=i.length,r.byteLength=i.byteLength,r.pts=i.pts,r.dts=i.dts,r.duration=i.duration):(r.duration+=i.duration,r.nalCount+=i.length,r.byteLength+=i.byteLength,r.push(i));return n.length&&r.duration<=0&&(r.duration=n[n.length-1].duration),n.byteLength+=r.byteLength,n.nalCount+=r.nalCount,n.duration+=r.duration,n.push(r),n},this.generateSampleTable_=function(t,e){var i,r,n,s,a,o=e||0,u=[];for(i=0;i<t.length;i++)for(s=t[i],r=0;r<s.length;r++)a=s[r],(n={size:0,flags:{isLeading:0,dependsOn:1,isDependedOn:0,hasRedundancy:0,degradationPriority:0}}).dataOffset=o,n.compositionTimeOffset=a.pts-a.dts,n.duration=a.duration,n.size=4*a.length,n.size+=a.byteLength,a.keyFrame&&(n.flags.dependsOn=2),o+=n.size,u.push(n);return u},this.concatenateNalData_=function(t){var e,i,r,n,s,a,o=0,u=t.byteLength,l=t.nalCount,c=new Uint8Array(u+4*l),h=new DataView(c.buffer);for(e=0;e<t.length;e++)for(n=t[e],i=0;i<n.length;i++)for(s=n[i],r=0;r<s.length;r++)a=s[r],h.setUint32(o,a.data.byteLength),o+=4,c.set(a.data,o),o+=a.data.byteLength;return c},this.alignGopsAtStart_=function(t){var e,i,r,n,s,a,o,u;for(s=t.byteLength,a=t.nalCount,o=t.duration,e=i=0;e<h.length&&i<t.length&&(r=h[e],n=t[i],r.pts!==n.pts);)n.pts>r.pts?e++:(i++,s-=n.byteLength,a-=n.nalCount,o-=n.duration);return 0===i?t:i===t.length?null:((u=t.slice(i)).byteLength=s,u.duration=o,u.nalCount=a,u.pts=u[0].pts,u.dts=u[0].dts,u)},this.alignGopsAtEnd_=function(t){var e,i,r,n,s,a,o;for(e=h.length-1,i=t.length-1,s=null,a=!1;0<=e&&0<=i;){if(r=h[e],n=t[i],r.pts===n.pts){a=!0;break}r.pts>n.pts?e--:(e===h.length-1&&(s=i),i--)}if(!a&&null===s)return null;if(0===(o=a?i:s))return t;var u=t.slice(o),l=u.reduce(function(t,e){return t.byteLength+=e.byteLength,t.duration+=e.duration,t.nalCount+=e.nalCount,t},{byteLength:0,duration:0,nalCount:0});return u.byteLength=l.byteLength,u.duration=l.duration,u.nalCount=l.nalCount,u.pts=u[0].pts,u.dts=u[0].dts,u},this.alignGopsWith=function(t){h=t}}).prototype=new z,Mt=function(t,e){"number"==typeof e.pts&&(void 0===t.timelineStartInfo.pts&&(t.timelineStartInfo.pts=e.pts),void 0===t.minSegmentPts?t.minSegmentPts=e.pts:t.minSegmentPts=Math.min(t.minSegmentPts,e.pts),void 0===t.maxSegmentPts?t.maxSegmentPts=e.pts:t.maxSegmentPts=Math.max(t.maxSegmentPts,e.pts)),"number"==typeof e.dts&&(void 0===t.timelineStartInfo.dts&&(t.timelineStartInfo.dts=e.dts),void 0===t.minSegmentDts?t.minSegmentDts=e.dts:t.minSegmentDts=Math.min(t.minSegmentDts,e.dts),void 0===t.maxSegmentDts?t.maxSegmentDts=e.dts:t.maxSegmentDts=Math.max(t.maxSegmentDts,e.dts))},Ut=function(t){delete t.minSegmentDts,delete t.maxSegmentDts,delete t.minSegmentPts,delete t.maxSegmentPts},Nt=function(t,e){var i,r=t.minSegmentDts;return e||(r-=t.timelineStartInfo.dts),i=t.timelineStartInfo.baseMediaDecodeTime,i+=r,i=Math.max(0,i),"audio"===t.type&&(i*=t.samplerate/9e4,i=Math.floor(i)),i},(Dt=function(t,e){this.numberOfTracks=0,this.metadataStream=e,"undefined"!=typeof t.remux?this.remuxTracks=!!t.remux:this.remuxTracks=!0,this.pendingTracks=[],this.videoTrack=null,this.pendingBoxes=[],this.pendingCaptions=[],this.pendingMetadata=[],this.pendingBytes=0,this.emittedTracks=0,Dt.prototype.init.call(this),this.push=function(t){return t.text?this.pendingCaptions.push(t):t.frames?this.pendingMetadata.push(t):(this.pendingTracks.push(t.track),this.pendingBoxes.push(t.boxes),this.pendingBytes+=t.boxes.byteLength,"video"===t.track.type&&(this.videoTrack=t.track),void("audio"===t.track.type&&(this.audioTrack=t.track)))}}).prototype=new z,Dt.prototype.flush=function(t){var e,i,r,n,s=0,a={captions:[],captionStreams:{},metadata:[],info:{}},o=0;if(this.pendingTracks.length<this.numberOfTracks){if("VideoSegmentStream"!==t&&"AudioSegmentStream"!==t)return;if(this.remuxTracks)return;if(0===this.pendingTracks.length)return this.emittedTracks++,void(this.emittedTracks>=this.numberOfTracks&&(this.trigger("done"),this.emittedTracks=0))}for(this.videoTrack?(o=this.videoTrack.timelineStartInfo.pts,Kt.forEach(function(t){a.info[t]=this.videoTrack[t]},this)):this.audioTrack&&(o=this.audioTrack.timelineStartInfo.pts,$t.forEach(function(t){a.info[t]=this.audioTrack[t]},this)),1===this.pendingTracks.length?a.type=this.pendingTracks[0].type:a.type="combined",this.emittedTracks+=this.pendingTracks.length,r=q.initSegment(this.pendingTracks),a.initSegment=new Uint8Array(r.byteLength),a.initSegment.set(r),a.data=new Uint8Array(this.pendingBytes),n=0;n<this.pendingBoxes.length;n++)a.data.set(this.pendingBoxes[n],s),s+=this.pendingBoxes[n].byteLength;for(n=0;n<this.pendingCaptions.length;n++)(e=this.pendingCaptions[n]).startTime=e.startPts-o,e.startTime/=9e4,e.endTime=e.endPts-o,e.endTime/=9e4,a.captionStreams[e.stream]=!0,a.captions.push(e);for(n=0;n<this.pendingMetadata.length;n++)(i=this.pendingMetadata[n]).cueTime=i.pts-o,i.cueTime/=9e4,a.metadata.push(i);a.metadata.dispatchType=this.metadataStream.dispatchType,this.pendingTracks.length=0,this.videoTrack=null,this.pendingBoxes.length=0,this.pendingCaptions.length=0,this.pendingBytes=0,this.pendingMetadata.length=0,this.trigger("data",a),this.emittedTracks>=this.numberOfTracks&&(this.trigger("done"),this.emittedTracks=0)},(It=function(r){var n,s,a=this,i=!0;It.prototype.init.call(this),r=r||{},this.baseMediaDecodeTime=r.baseMediaDecodeTime||0,this.transmuxPipeline_={},this.setupAacPipeline=function(){var e={};(this.transmuxPipeline_=e).type="aac",e.metadataStream=new gt.MetadataStream,e.aacStream=new Ft,e.audioTimestampRolloverStream=new gt.TimestampRolloverStream("audio"),e.timedMetadataTimestampRolloverStream=new gt.TimestampRolloverStream("timed-metadata"),e.adtsStream=new Tt,e.coalesceStream=new Dt(r,e.metadataStream),e.headOfPipeline=e.aacStream,e.aacStream.pipe(e.audioTimestampRolloverStream).pipe(e.adtsStream),e.aacStream.pipe(e.timedMetadataTimestampRolloverStream).pipe(e.metadataStream).pipe(e.coalesceStream),e.metadataStream.on("timestamp",function(t){e.aacStream.setTimestamp(t.timeStamp)}),e.aacStream.on("data",function(t){"timed-metadata"!==t.type||e.audioSegmentStream||(s=s||{timelineStartInfo:{baseMediaDecodeTime:a.baseMediaDecodeTime},codec:"adts",type:"audio"},e.coalesceStream.numberOfTracks++,e.audioSegmentStream=new xt(s,r),e.adtsStream.pipe(e.audioSegmentStream).pipe(e.coalesceStream))}),e.coalesceStream.on("data",this.trigger.bind(this,"data")),e.coalesceStream.on("done",this.trigger.bind(this,"done"))},this.setupTsPipeline=function(){var i={};(this.transmuxPipeline_=i).type="ts",i.metadataStream=new gt.MetadataStream,i.packetStream=new gt.TransportPacketStream,i.parseStream=new gt.TransportParseStream,i.elementaryStream=new gt.ElementaryStream,i.videoTimestampRolloverStream=new gt.TimestampRolloverStream("video"),i.audioTimestampRolloverStream=new gt.TimestampRolloverStream("audio"),i.timedMetadataTimestampRolloverStream=new gt.TimestampRolloverStream("timed-metadata"),i.adtsStream=new Tt,i.h264Stream=new Yt,i.captionStream=new gt.CaptionStream,i.coalesceStream=new Dt(r,i.metadataStream),i.headOfPipeline=i.packetStream,i.packetStream.pipe(i.parseStream).pipe(i.elementaryStream),i.elementaryStream.pipe(i.videoTimestampRolloverStream).pipe(i.h264Stream),i.elementaryStream.pipe(i.audioTimestampRolloverStream).pipe(i.adtsStream),i.elementaryStream.pipe(i.timedMetadataTimestampRolloverStream).pipe(i.metadataStream).pipe(i.coalesceStream),i.h264Stream.pipe(i.captionStream).pipe(i.coalesceStream),i.elementaryStream.on("data",function(t){var e;if("metadata"===t.type){for(e=t.tracks.length;e--;)n||"video"!==t.tracks[e].type?s||"audio"!==t.tracks[e].type||((s=t.tracks[e]).timelineStartInfo.baseMediaDecodeTime=a.baseMediaDecodeTime):(n=t.tracks[e]).timelineStartInfo.baseMediaDecodeTime=a.baseMediaDecodeTime;n&&!i.videoSegmentStream&&(i.coalesceStream.numberOfTracks++,i.videoSegmentStream=new Ot(n,r),i.videoSegmentStream.on("timelineStartInfo",function(t){s&&(s.timelineStartInfo=t,i.audioSegmentStream.setEarliestDts(t.dts))}),i.videoSegmentStream.on("processedGopsInfo",a.trigger.bind(a,"gopInfo")),i.videoSegmentStream.on("baseMediaDecodeTime",function(t){s&&i.audioSegmentStream.setVideoBaseMediaDecodeTime(t)}),i.h264Stream.pipe(i.videoSegmentStream).pipe(i.coalesceStream)),s&&!i.audioSegmentStream&&(i.coalesceStream.numberOfTracks++,i.audioSegmentStream=new xt(s,r),i.adtsStream.pipe(i.audioSegmentStream).pipe(i.coalesceStream))}}),i.coalesceStream.on("data",this.trigger.bind(this,"data")),i.coalesceStream.on("done",this.trigger.bind(this,"done"))},this.setBaseMediaDecodeTime=function(t){var e=this.transmuxPipeline_;this.baseMediaDecodeTime=t,s&&(s.timelineStartInfo.dts=void 0,s.timelineStartInfo.pts=void 0,Ut(s),s.timelineStartInfo.baseMediaDecodeTime=t,e.audioTimestampRolloverStream&&e.audioTimestampRolloverStream.discontinuity()),n&&(e.videoSegmentStream&&(e.videoSegmentStream.gopCache_=[],e.videoTimestampRolloverStream.discontinuity()),n.timelineStartInfo.dts=void 0,n.timelineStartInfo.pts=void 0,Ut(n),e.captionStream.reset(),n.timelineStartInfo.baseMediaDecodeTime=t),e.timedMetadataTimestampRolloverStream&&e.timedMetadataTimestampRolloverStream.discontinuity()},this.setAudioAppendStart=function(t){s&&this.transmuxPipeline_.audioSegmentStream.setAudioAppendStart(t)},this.alignGopsWith=function(t){n&&this.transmuxPipeline_.videoSegmentStream&&this.transmuxPipeline_.videoSegmentStream.alignGopsWith(t)},this.push=function(t){if(i){var e=Rt(t);e&&"aac"!==this.transmuxPipeline_.type?this.setupAacPipeline():e||"ts"===this.transmuxPipeline_.type||this.setupTsPipeline(),i=!1}this.transmuxPipeline_.headOfPipeline.push(t)},this.flush=function(){i=!0,this.transmuxPipeline_.headOfPipeline.flush()},this.resetCaptions=function(){this.transmuxPipeline_.captionStream&&this.transmuxPipeline_.captionStream.reset()}}).prototype=new z;var Qt={Transmuxer:It,VideoSegmentStream:Ot,AudioSegmentStream:xt,AUDIO_PROPERTIES:$t,VIDEO_PROPERTIES:Kt},Jt={generator:q,Transmuxer:Qt.Transmuxer,AudioSegmentStream:Qt.AudioSegmentStream,VideoSegmentStream:Qt.VideoSegmentStream},Zt=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},te=function(){function r(t,e){for(var i=0;i<e.length;i++){var r=e[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return function(t,e,i){return e&&r(t.prototype,e),i&&r(t,i),t}}(),ee=function(){function e(t){Zt(this,e),this.options=t||{},this.init()}return te(e,[{key:"init",value:function(){var t;this.transmuxer&&this.transmuxer.dispose(),this.transmuxer=new Jt.Transmuxer(this.options),(t=this.transmuxer).on("data",function(t){var e=t.initSegment;t.initSegment={data:e.buffer,byteOffset:e.byteOffset,byteLength:e.byteLength};var i=t.data;t.data=i.buffer,H.postMessage({action:"data",segment:t,byteOffset:i.byteOffset,byteLength:i.byteLength},[t.data])}),t.captionStream&&t.captionStream.on("data",function(t){H.postMessage({action:"caption",data:t})}),t.on("done",function(t){H.postMessage({action:"done"})}),t.on("gopInfo",function(t){H.postMessage({action:"gopInfo",gopInfo:t})})}},{key:"push",value:function(t){var e=new Uint8Array(t.data,t.byteOffset,t.byteLength);this.transmuxer.push(e)}},{key:"reset",value:function(){this.init()}},{key:"setTimestampOffset",value:function(t){var e=t.timestampOffset||0;this.transmuxer.setBaseMediaDecodeTime(Math.round(9e4*e))}},{key:"setAudioAppendStart",value:function(t){this.transmuxer.setAudioAppendStart(Math.ceil(9e4*t.appendStart))}},{key:"flush",value:function(t){this.transmuxer.flush()}},{key:"resetCaptions",value:function(){this.transmuxer.resetCaptions()}},{key:"alignGopsWith",value:function(t){this.transmuxer.alignGopsWith(t.gopsToAlignWith.slice())}}]),e}();new function(t){t.onmessage=function(t){"init"===t.data.action&&t.data.options?this.messageHandlers=new ee(t.data.options):(this.messageHandlers||(this.messageHandlers=new ee),t.data&&t.data.action&&"init"!==t.data.action&&this.messageHandlers[t.data.action]&&this.messageHandlers[t.data.action](t.data))}}(re)}()}),Mu=function(t){return/mp4a\.\d+.\d+/i.test(t)},Uu=function(t){return/avc1\.[\da-f]+/i.test(t)},Nu=function(t){return t.map(function(t){return t.replace(/avc1\.(\d+)\.(\d+)/i,function(t,e,i){return"avc1."+("00"+Number(e).toString(16)).slice(-2)+"00"+("00"+Number(i).toString(16)).slice(-2)})})},Bu=function(n){function s(t,e){y(this,s);var i=b(this,n.call(this,As.EventTarget));i.timestampOffset_=0,i.pendingBuffers_=[],i.bufferUpdating_=!1,i.mediaSource_=t,i.codecs_=e,i.audioCodec_=null,i.videoCodec_=null,i.audioDisabled_=!1,i.appendAudioInitSegment_=!0,i.gopBuffer_=[],i.timeMapping_=0,i.safeAppend_=11<=As.browser.IE_VERSION;var r={remux:!1,alignGopsAtEnd:i.safeAppend_};return i.codecs_.forEach(function(t){Mu(t)?i.audioCodec_=t:Uu(t)&&(i.videoCodec_=t)}),i.transmuxer_=new Ru,i.transmuxer_.postMessage({action:"init",options:r}),i.transmuxer_.onmessage=function(t){return"data"===t.data.action?i.data_(t):"done"===t.data.action?i.done_(t):"gopInfo"===t.data.action?i.appendGopInfo_(t):void 0},Object.defineProperty(i,"timestampOffset",{get:function(){return this.timestampOffset_},set:function(t){"number"==typeof t&&0<=t&&(this.timestampOffset_=t,this.appendAudioInitSegment_=!0,this.gopBuffer_.length=0,this.timeMapping_=0,this.transmuxer_.postMessage({action:"setTimestampOffset",timestampOffset:t}))}}),Object.defineProperty(i,"appendWindowStart",{get:function(){return(this.videoBuffer_||this.audioBuffer_).appendWindowStart},set:function(t){this.videoBuffer_&&(this.videoBuffer_.appendWindowStart=t),this.audioBuffer_&&(this.audioBuffer_.appendWindowStart=t)}}),Object.defineProperty(i,"updating",{get:function(){return!!(this.bufferUpdating_||!this.audioDisabled_&&this.audioBuffer_&&this.audioBuffer_.updating||this.videoBuffer_&&this.videoBuffer_.updating)}}),Object.defineProperty(i,"buffered",{get:function(){var t=null,e=null,i=0,r=[],n=[];if(!this.videoBuffer_&&!this.audioBuffer_)return As.createTimeRange();if(!this.videoBuffer_)return this.audioBuffer_.buffered;if(!this.audioBuffer_)return this.videoBuffer_.buffered;if(this.audioDisabled_)return this.videoBuffer_.buffered;if(0===this.videoBuffer_.buffered.length&&0===this.audioBuffer_.buffered.length)return As.createTimeRange();for(var s=this.videoBuffer_.buffered,a=this.audioBuffer_.buffered,o=s.length;o--;)r.push({time:s.start(o),type:"start"}),r.push({time:s.end(o),type:"end"});for(o=a.length;o--;)r.push({time:a.start(o),type:"start"}),r.push({time:a.end(o),type:"end"});for(r.sort(function(t,e){return t.time-e.time}),o=0;o<r.length;o++)"start"===r[o].type?2===++i&&(t=r[o].time):"end"===r[o].type&&1===--i&&(e=r[o].time),null!==t&&null!==e&&(n.push([t,e]),e=t=null);return As.createTimeRanges(n)}}),i}return _(s,n),s.prototype.data_=function(t){var e=t.data.segment;e.data=new Uint8Array(e.data,t.data.byteOffset,t.data.byteLength),e.initSegment=new Uint8Array(e.initSegment.data,e.initSegment.byteOffset,e.initSegment.byteLength),function(t,e,i){var r=e.player_;if(i.captions&&i.captions.length)for(var n in t.inbandTextTracks_||(t.inbandTextTracks_={}),i.captionStreams)if(!t.inbandTextTracks_[n]){r.tech_.trigger({type:"usage",name:"hls-608"});var s=r.textTracks().getTrackById(n);t.inbandTextTracks_[n]=s||r.addRemoteTextTrack({kind:"captions",id:n,label:n},!1).track}i.metadata&&i.metadata.length&&!t.metadataTrack_&&(t.metadataTrack_=r.addRemoteTextTrack({kind:"metadata",label:"Timed Metadata"},!1).track,t.metadataTrack_.inBandMetadataTrackDispatchType=i.metadata.dispatchType)}(this,this.mediaSource_,e),this.pendingBuffers_.push(e)},s.prototype.done_=function(t){"closed"!==this.mediaSource_.readyState?this.processPendingSegments_():this.pendingBuffers_.length=0},s.prototype.createRealSourceBuffers_=function(){var r=this,n=["audio","video"];n.forEach(function(e){if(r[e+"Codec_"]&&!r[e+"Buffer_"]){var i=null;if(r.mediaSource_[e+"Buffer_"])(i=r.mediaSource_[e+"Buffer_"]).updating=!1;else{var t=e+'/mp4;codecs="'+r[e+"Codec_"]+'"';i=function(t,e){var i=t.addSourceBuffer(e),r=Object.create(null);r.updating=!1,r.realBuffer_=i;var n=function(e){"function"==typeof i[e]?r[e]=function(){return i[e].apply(i,arguments)}:"undefined"==typeof r[e]&&Object.defineProperty(r,e,{get:function(){return i[e]},set:function(t){return i[e]=t}})};for(var s in i)n(s);return r}(r.mediaSource_.nativeMediaSource_,t),r.mediaSource_[e+"Buffer_"]=i}r[e+"Buffer_"]=i,["update","updatestart","updateend"].forEach(function(t){i.addEventListener(t,function(){if("audio"!==e||!r.audioDisabled_)return"updateend"===t&&(r[e+"Buffer_"].updating=!1),n.every(function(t){return!("audio"!==t||!r.audioDisabled_)||(e===t||!r[t+"Buffer_"]||!r[t+"Buffer_"].updating)})?r.trigger(t):void 0})})}})},s.prototype.appendBuffer=function(t){if(this.bufferUpdating_=!0,this.audioBuffer_&&this.audioBuffer_.buffered.length){var e=this.audioBuffer_.buffered;this.transmuxer_.postMessage({action:"setAudioAppendStart",appendStart:e.end(e.length-1)})}this.videoBuffer_&&this.transmuxer_.postMessage({action:"alignGopsWith",gopsToAlignWith:function(t,e,i){if(!e||!t.length)return[];var r=Math.ceil(9e4*(e.currentTime()-i+3)),n=void 0;for(n=0;n<t.length&&!(t[n].pts>r);n++);return t.slice(n)}(this.gopBuffer_,this.mediaSource_.player_,this.timeMapping_)}),this.transmuxer_.postMessage({action:"push",data:t.buffer,byteOffset:t.byteOffset,byteLength:t.byteLength},[t.buffer]),this.transmuxer_.postMessage({action:"flush"})},s.prototype.appendGopInfo_=function(t){this.gopBuffer_=function(t,e,i){if(!e.length)return t;if(i)return e.slice();for(var r=e[0].pts,n=0;n<t.length&&!(t[n].pts>=r);n++);return t.slice(0,n).concat(e)}(this.gopBuffer_,t.data.gopInfo,this.safeAppend_)},s.prototype.remove=function(t,e){if(this.videoBuffer_&&(this.videoBuffer_.updating=!0,this.videoBuffer_.remove(t,e),this.gopBuffer_=function(t,e,i,r){for(var n=Math.ceil(9e4*(e-r)),s=Math.ceil(9e4*(i-r)),a=t.slice(),o=t.length;o--&&!(t[o].pts<=s););if(-1===o)return a;for(var u=o+1;u--&&!(t[u].pts<=n););return u=Math.max(u,0),a.splice(u,o-u+1),a}(this.gopBuffer_,t,e,this.timeMapping_)),!this.audioDisabled_&&this.audioBuffer_&&(this.audioBuffer_.updating=!0,this.audioBuffer_.remove(t,e)),bu(t,e,this.metadataTrack_),this.inbandTextTracks_)for(var i in this.inbandTextTracks_)bu(t,e,this.inbandTextTracks_[i])},s.prototype.processPendingSegments_=function(){var t={video:{segments:[],bytes:0},audio:{segments:[],bytes:0},captions:[],metadata:[]};t=this.pendingBuffers_.reduce(function(t,e){var i=e.type,r=e.data,n=e.initSegment;return t[i].segments.push(r),t[i].bytes+=r.byteLength,t[i].initSegment=n,e.captions&&(t.captions=t.captions.concat(e.captions)),e.info&&(t[i].info=e.info),e.metadata&&(t.metadata=t.metadata.concat(e.metadata)),t},t),this.videoBuffer_||this.audioBuffer_||(0===t.video.bytes&&(this.videoCodec_=null),0===t.audio.bytes&&(this.audioCodec_=null),this.createRealSourceBuffers_()),t.audio.info&&this.mediaSource_.trigger({type:"audioinfo",info:t.audio.info}),t.video.info&&this.mediaSource_.trigger({type:"videoinfo",info:t.video.info}),this.appendAudioInitSegment_&&(!this.audioDisabled_&&this.audioBuffer_&&(t.audio.segments.unshift(t.audio.initSegment),t.audio.bytes+=t.audio.initSegment.byteLength),this.appendAudioInitSegment_=!1);var e=!1;this.videoBuffer_&&t.video.bytes?(t.video.segments.unshift(t.video.initSegment),t.video.bytes+=t.video.initSegment.byteLength,this.concatAndAppendSegments_(t.video,this.videoBuffer_),Su(this,t.captions,t.metadata)):!this.videoBuffer_||!this.audioDisabled_&&this.audioBuffer_||(e=!0),!this.audioDisabled_&&this.audioBuffer_&&this.concatAndAppendSegments_(t.audio,this.audioBuffer_),this.pendingBuffers_.length=0,e&&this.trigger("updateend"),this.bufferUpdating_=!1},s.prototype.concatAndAppendSegments_=function(t,e){var i=0,r=void 0;if(t.bytes){r=new Uint8Array(t.bytes),t.segments.forEach(function(t){r.set(t,i),i+=t.byteLength});try{e.updating=!0,e.appendBuffer(r)}catch(t){this.mediaSource_.player_&&this.mediaSource_.player_.error({code:-3,type:"APPEND_BUFFER_ERR",message:t.message,originalError:t})}}},s.prototype.abort=function(){this.videoBuffer_&&this.videoBuffer_.abort(),!this.audioDisabled_&&this.audioBuffer_&&this.audioBuffer_.abort(),this.transmuxer_&&this.transmuxer_.postMessage({action:"reset"}),this.pendingBuffers_.length=0,this.bufferUpdating_=!1},s}(As.EventTarget),ju=function(e){function i(){y(this,i);var s=b(this,e.call(this)),t=void 0;for(t in s.nativeMediaSource_=new g.MediaSource,s.nativeMediaSource_)t in i.prototype||"function"!=typeof s.nativeMediaSource_[t]||(s[t]=s.nativeMediaSource_[t].bind(s.nativeMediaSource_));return s.duration_=NaN,Object.defineProperty(s,"duration",{get:function(){return this.duration_===1/0?this.duration_:this.nativeMediaSource_.duration},set:function(t){(this.duration_=t)===1/0||(this.nativeMediaSource_.duration=t)}}),Object.defineProperty(s,"seekable",{get:function(){return this.duration_===1/0?As.createTimeRanges([[0,this.nativeMediaSource_.duration]]):this.nativeMediaSource_.seekable}}),Object.defineProperty(s,"readyState",{get:function(){return this.nativeMediaSource_.readyState}}),Object.defineProperty(s,"activeSourceBuffers",{get:function(){return this.activeSourceBuffers_}}),s.sourceBuffers=[],s.activeSourceBuffers_=[],s.updateActiveSourceBuffers_=function(){if(s.activeSourceBuffers_.length=0,1===s.sourceBuffers.length){var t=s.sourceBuffers[0];return t.appendAudioInitSegment_=!0,t.audioDisabled_=!t.audioCodec_,void s.activeSourceBuffers_.push(t)}for(var i=!1,r=!0,e=0;e<s.player_.audioTracks().length;e++){var n=s.player_.audioTracks()[e];if(n.enabled&&"main"!==n.kind){r=!(i=!0);break}}s.sourceBuffers.forEach(function(t,e){if(t.appendAudioInitSegment_=!0,t.videoCodec_&&t.audioCodec_)t.audioDisabled_=i;else if(t.videoCodec_&&!t.audioCodec_)t.audioDisabled_=!0,r=!1;else if(!t.videoCodec_&&t.audioCodec_&&(t.audioDisabled_=e?r:!r,t.audioDisabled_))return;s.activeSourceBuffers_.push(t)})},s.onPlayerMediachange_=function(){s.sourceBuffers.forEach(function(t){t.appendAudioInitSegment_=!0})},s.onHlsReset_=function(){s.sourceBuffers.forEach(function(t){t.transmuxer_&&t.transmuxer_.postMessage({action:"resetCaptions"})})},s.onHlsSegmentTimeMapping_=function(e){s.sourceBuffers.forEach(function(t){return t.timeMapping_=e.mapping})},["sourceopen","sourceclose","sourceended"].forEach(function(t){this.nativeMediaSource_.addEventListener(t,this.trigger.bind(this))},s),s.on("sourceopen",function(t){var e=p.querySelector('[src="'+s.url_+'"]');e&&(s.player_=As(e.parentNode),s.player_.tech_.on("hls-reset",s.onHlsReset_),s.player_.tech_.on("hls-segment-time-mapping",s.onHlsSegmentTimeMapping_),s.player_.audioTracks&&s.player_.audioTracks()&&(s.player_.audioTracks().on("change",s.updateActiveSourceBuffers_),s.player_.audioTracks().on("addtrack",s.updateActiveSourceBuffers_),s.player_.audioTracks().on("removetrack",s.updateActiveSourceBuffers_)),s.player_.on("mediachange",s.onPlayerMediachange_))}),s.on("sourceended",function(t){for(var e=Tu(s.duration),i=0;i<s.sourceBuffers.length;i++){var r=s.sourceBuffers[i],n=r.metadataTrack_&&r.metadataTrack_.cues;n&&n.length&&(n[n.length-1].endTime=e)}}),s.on("sourceclose",function(t){this.sourceBuffers.forEach(function(t){t.transmuxer_&&t.transmuxer_.terminate()}),this.sourceBuffers.length=0,this.player_&&(this.player_.audioTracks&&this.player_.audioTracks()&&(this.player_.audioTracks().off("change",this.updateActiveSourceBuffers_),this.player_.audioTracks().off("addtrack",this.updateActiveSourceBuffers_),this.player_.audioTracks().off("removetrack",this.updateActiveSourceBuffers_)),this.player_.el_&&(this.player_.off("mediachange",this.onPlayerMediachange_),this.player_.tech_.off("hls-reset",this.onHlsReset_),this.player_.tech_.off("hls-segment-time-mapping",this.onHlsSegmentTimeMapping_)))}),s}return _(i,e),i.prototype.addSeekableRange_=function(t,e){var i=void 0;if(this.duration!==1/0)throw(i=new Error("MediaSource.addSeekableRange() can only be invoked when the duration is Infinity")).name="InvalidStateError",i.code=11,i;(e>this.nativeMediaSource_.duration||isNaN(this.nativeMediaSource_.duration))&&(this.nativeMediaSource_.duration=e)},i.prototype.addSourceBuffer=function(t){var n,e,i=void 0,r=(n={type:"",parameters:{}},e=t.trim().split(";"),n.type=e.shift().trim(),e.forEach(function(t){var e=t.trim().split("=");if(1<e.length){var i=e[0].replace(/"/g,"").trim(),r=e[1].replace(/"/g,"").trim();n.parameters[i]=r}}),n);if(/^(video|audio)\/mp2t$/i.test(r.type)){var s=[];r.parameters&&r.parameters.codecs&&(s=r.parameters.codecs.split(","),s=(s=Nu(s)).filter(function(t){return Mu(t)||Uu(t)})),0===s.length&&(s=["avc1.4d400d","mp4a.40.2"]),i=new Bu(this,s),0!==this.sourceBuffers.length&&(this.sourceBuffers[0].createRealSourceBuffers_(),i.createRealSourceBuffers_(),this.sourceBuffers[0].audioDisabled_=!0)}else i=this.nativeMediaSource_.addSourceBuffer(t);return this.sourceBuffers.push(i),i},i}(As.EventTarget),Fu=0;As.mediaSources={};var Hu=function(t,e){var i=As.mediaSources[t];if(!i)throw new Error("Media Source not found (Video.js)");i.trigger({type:"sourceopen",swfId:e})},Vu=function(){return!!g.MediaSource&&!!g.MediaSource.isTypeSupported&&g.MediaSource.isTypeSupported('video/mp4;codecs="avc1.4d400d,mp4a.40.2"')},qu=function(){if(this.MediaSource={open:Hu,supportsNativeMediaSources:Vu},Vu())return new ju;throw new Error("Cannot use create a virtual MediaSource for this video")};qu.open=Hu,qu.supportsNativeMediaSources=Vu;var Wu={createObjectURL:function(t){var e=void 0;return t instanceof ju?(e=g.URL.createObjectURL(t.nativeMediaSource_),t.url_=e):t instanceof ju?(e="blob:vjs-media-source/"+Fu,Fu++,As.mediaSources[e]=t,e):(e=g.URL.createObjectURL(t),t.url_=e)}};As.MediaSource=qu,As.URL=Wu;var zu=As.mergeOptions,Gu=function(t,e){for(var a=zu(t,{duration:e.duration,minimumUpdatePeriod:e.minimumUpdatePeriod}),i=0;i<e.playlists.length;i++){var r=Bo(a,e.playlists[i]);r&&(a=r)}return No(e,function(t,e,i,r){if(t.playlists&&t.playlists.length){var n=t.playlists[0].uri,s=Bo(a,t.playlists[0]);s&&((a=s).mediaGroups[e][i][r].playlists[0]=a.playlists[n])}}),a},Xu=function(s){function a(t,e,i,r){y(this,a);var n=b(this,s.call(this));if(n.hls_=e,n.withCredentials=i,!t)throw new Error("A non-empty playlist URL or playlist is required");return n.on("minimumUpdatePeriod",function(){n.refreshXml_()}),n.on("mediaupdatetimeout",function(){n.refreshMedia_()}),"string"==typeof t?(n.srcUrl=t,n.state="HAVE_NOTHING",b(n)):(n.masterPlaylistLoader_=r,n.state="HAVE_METADATA",n.started=!0,n.media(t),g.setTimeout(function(){n.trigger("loadedmetadata")},0),n)}return _(a,s),a.prototype.dispose=function(){this.stopRequest(),g.clearTimeout(this.mediaUpdateTimeout)},a.prototype.stopRequest=function(){if(this.request){var t=this.request;this.request=null,t.onreadystatechange=null,t.abort()}},a.prototype.media=function(t){if(!t)return this.media_;if("HAVE_NOTHING"===this.state)throw new Error("Cannot switch media playlist from "+this.state);var e=this.state;if("string"==typeof t){if(!this.master.playlists[t])throw new Error("Unknown playlist URI: "+t);t=this.master.playlists[t]}var i=!this.media_||t.uri!==this.media_.uri;this.state="HAVE_METADATA",i&&(this.media_&&this.trigger("mediachanging"),this.media_=t,this.refreshMedia_(),"HAVE_MASTER"!==e&&this.trigger("mediachange"))},a.prototype.pause=function(){this.stopRequest(),"HAVE_NOTHING"===this.state&&(this.started=!1)},a.prototype.load=function(){this.started?this.trigger("loadedplaylist"):this.start()},a.prototype.parseMasterXml=function(){var s=Sa(this.masterXml_,{manifestUri:this.srcUrl,clientOffset:this.clientOffset_});s.uri=this.srcUrl;for(var t=0;t<s.playlists.length;t++){var e="placeholder-uri-"+t;s.playlists[t].uri=e,s.playlists[e]=s.playlists[t]}return No(s,function(t,e,i,r){if(t.playlists&&t.playlists.length){var n="placeholder-uri-"+e+"-"+i+"-"+r;t.playlists[0].uri=n,s.playlists[n]=t.playlists[0]}}),jo(s),Fo(s),s},a.prototype.start=function(){var i=this;this.started=!0,this.request=this.hls_.xhr({uri:this.srcUrl,withCredentials:this.withCredentials},function(t,e){if(i.request){if(i.request=null,t)return i.error={status:e.status,message:"DASH playlist request error at URL: "+i.srcUrl,responseText:e.responseText,code:2},"HAVE_NOTHING"===i.state&&(i.started=!1),i.trigger("error");i.masterXml_=e.responseText,e.responseHeaders&&e.responseHeaders.date?i.masterLoaded_=Date.parse(e.responseHeaders.date):i.masterLoaded_=Date.now(),i.syncClientServerClock_(i.onClientServerClockSync_.bind(i))}})},a.prototype.syncClientServerClock_=function(r){var n=this,s=ka(this.masterXml_);return null===s?(this.clientOffset_=this.masterLoaded_-Date.now(),r()):"DIRECT"===s.method?(this.clientOffset_=s.value-Date.now(),r()):void(this.request=this.hls_.xhr({uri:Ro(this.srcUrl,s.value),method:s.method,withCredentials:this.withCredentials},function(t,e){if(n.request){if(t)return n.clientOffset_=n.masterLoaded_-Date.now(),r();var i=void 0;i="HEAD"===s.method?e.responseHeaders&&e.responseHeaders.date?Date.parse(e.responseHeaders.date):n.masterLoaded_:Date.parse(e.responseText),n.clientOffset_=i-Date.now(),r()}}))},a.prototype.onClientServerClockSync_=function(){var t=this;this.master=this.parseMasterXml(),this.state="HAVE_MASTER",this.trigger("loadedplaylist"),this.media_||this.media(this.master.playlists[0]),g.setTimeout(function(){t.trigger("loadedmetadata")},0),this.master.minimumUpdatePeriod&&g.setTimeout(function(){t.trigger("minimumUpdatePeriod")},this.master.minimumUpdatePeriod)},a.prototype.refreshXml_=function(){var r=this;this.request=this.hls_.xhr({uri:this.srcUrl,withCredentials:this.withCredentials},function(t,e){if(r.request){if(r.request=null,t)return r.error={status:e.status,message:"DASH playlist request error at URL: "+r.srcUrl,responseText:e.responseText,code:2},"HAVE_NOTHING"===r.state&&(r.started=!1),r.trigger("error");r.masterXml_=e.responseText;var i=r.parseMasterXml();r.master=Gu(r.master,i),g.setTimeout(function(){r.trigger("minimumUpdatePeriod")},r.master.minimumUpdatePeriod)}})},a.prototype.refreshMedia_=function(){var t=this,e=void 0,i=void 0;this.masterPlaylistLoader_?(e=this.masterPlaylistLoader_.master,i=this.masterPlaylistLoader_.parseMasterXml()):(e=this.master,i=this.parseMasterXml());var r=Gu(e,i);r?(this.masterPlaylistLoader_?this.masterPlaylistLoader_.master=r:this.master=r,this.media_=r.playlists[this.media_.uri]):this.trigger("playlistunchanged"),this.media().endList||(this.mediaUpdateTimeout=g.setTimeout(function(){t.trigger("mediaupdatetimeout")},Ho(this.media(),!!r))),this.trigger("loadedplaylist")},a}(As.EventTarget),Yu=function(t){return As.log.debug?As.log.debug.bind(As,"VHS:",t+" >"):function(){}};function $u(){}var Ku=function(){function n(t,e,i,r){y(this,n),this.callbacks_=[],this.pendingCallback_=null,this.timestampOffset_=0,this.mediaSource=t,this.processedAppend_=!1,this.type_=i,this.mimeType_=e,this.logger_=Yu("SourceUpdater["+i+"]["+e+"]"),"closed"===t.readyState?t.addEventListener("sourceopen",this.createSourceBuffer_.bind(this,e,r)):this.createSourceBuffer_(e,r)}return n.prototype.createSourceBuffer_=function(t,e){var i=this;this.sourceBuffer_=this.mediaSource.addSourceBuffer(t),this.logger_("created SourceBuffer"),e&&(e.trigger("sourcebufferadded"),this.mediaSource.sourceBuffers.length<2)?e.on("sourcebufferadded",function(){i.start_()}):this.start_()},n.prototype.start_=function(){var e=this;this.started_=!0,this.onUpdateendCallback_=function(){var t=e.pendingCallback_;e.pendingCallback_=null,e.logger_("buffered ["+vu(e.buffered())+"]"),t&&t(),e.runCallback_()},this.sourceBuffer_.addEventListener("updateend",this.onUpdateendCallback_),this.runCallback_()},n.prototype.abort=function(t){var e=this;this.processedAppend_&&this.queueCallback_(function(){e.sourceBuffer_.abort()},t)},n.prototype.appendBuffer=function(t,e){var i=this;this.processedAppend_=!0,this.queueCallback_(function(){i.sourceBuffer_.appendBuffer(t)},e)},n.prototype.buffered=function(){return this.sourceBuffer_?this.sourceBuffer_.buffered:As.createTimeRanges()},n.prototype.remove=function(t,e){var i=this;this.processedAppend_&&this.queueCallback_(function(){i.logger_("remove ["+t+" => "+e+"]"),i.sourceBuffer_.remove(t,e)},$u)},n.prototype.updating=function(){return!this.sourceBuffer_||this.sourceBuffer_.updating||this.pendingCallback_},n.prototype.timestampOffset=function(t){var e=this;return"undefined"!=typeof t&&(this.queueCallback_(function(){e.sourceBuffer_.timestampOffset=t}),this.timestampOffset_=t),this.timestampOffset_},n.prototype.queueCallback_=function(t,e){this.callbacks_.push([t.bind(this),e]),this.runCallback_()},n.prototype.runCallback_=function(){var t=void 0;!this.updating()&&this.callbacks_.length&&this.started_&&(t=this.callbacks_.shift(),this.pendingCallback_=t[1],t[0]())},n.prototype.dispose=function(){this.sourceBuffer_.removeEventListener("updateend",this.onUpdateendCallback_),this.sourceBuffer_&&"open"===this.mediaSource.readyState&&this.sourceBuffer_.abort()},n}(),Qu={GOAL_BUFFER_LENGTH:30,MAX_GOAL_BUFFER_LENGTH:60,GOAL_BUFFER_LENGTH_RATE:1,BANDWIDTH_VARIANCE:1.2,BUFFER_LOW_WATER_LINE:0,MAX_BUFFER_LOW_WATER_LINE:30,BUFFER_LOW_WATER_LINE_RATE:1},Ju=2,Zu=-101,tl=-102,el=function(t){var e,i,r={};return t.byterange&&(r.Range=(e=t.byterange,i=e.offset+e.length-1,"bytes="+e.offset+"-"+i)),r},il=function(t){t.forEach(function(t){t.abort()})},rl=function(t,e){return e.timedout?{status:e.status,message:"HLS request timed-out at URL: "+e.uri,code:Zu,xhr:e}:e.aborted?{status:e.status,message:"HLS request aborted at URL: "+e.uri,code:tl,xhr:e}:t?{status:e.status,message:"HLS request errored at URL: "+e.uri,code:Ju,xhr:e}:null},nl=function(a,o,u){var l=[],c=0;return function(t,e){if(t&&(il(a),l.push(t)),(c+=1)===a.length){if(e.endOfAllRequests=Date.now(),0<l.length){var i=l.reduce(function(t,e){return e.code>t.code?e:t});return u(i,e)}return e.encryptedBytes?(n=e,s=u,(r=o).addEventListener("message",function t(e){if(e.data.source===n.requestId){r.removeEventListener("message",t);var i=e.data.decrypted;return n.bytes=new Uint8Array(i.bytes,i.byteOffset,i.byteLength),s(null,n)}}),void r.postMessage(cu({source:n.requestId,encrypted:n.encryptedBytes,key:n.key.bytes,iv:n.key.iv}),[n.encryptedBytes.buffer,n.key.bytes.buffer])):u(null,e)}var r,n,s}},sl=function(n,s){return function(t){var e,i,r;return n.stats=As.mergeOptions(n.stats,(i=(e=t).target,(r={bandwidth:1/0,bytesReceived:0,roundTripTime:Date.now()-i.requestTime||0}).bytesReceived=e.loaded,r.bandwidth=Math.floor(r.bytesReceived/r.roundTripTime*8*1e3),r)),!n.stats.firstBytesReceivedAt&&n.stats.bytesReceived&&(n.stats.firstBytesReceivedAt=Date.now()),s(t,n)}},al=function(t,e,i,r,n,s){var a,o,u,l,c=[],h=nl(c,i,s);if(r.key){var d=t(As.mergeOptions(e,{uri:r.key.resolvedUri,responseType:"arraybuffer"}),(a=r,o=h,function(t,e){var i=e.response,r=rl(t,e);if(r)return o(r,a);if(16!==i.byteLength)return o({status:e.status,message:"Invalid HLS key at URL: "+e.uri,code:Ju,xhr:e},a);var n=new DataView(i);return a.key.bytes=new Uint32Array([n.getUint32(0),n.getUint32(4),n.getUint32(8),n.getUint32(12)]),o(null,a)}));c.push(d)}if(r.map&&!r.map.bytes){var p=t(As.mergeOptions(e,{uri:r.map.resolvedUri,responseType:"arraybuffer",headers:el(r.map)}),(u=r,l=h,function(t,e){var i=e.response,r=rl(t,e);return r?l(r,u):0===i.byteLength?l({status:e.status,message:"Empty HLS segment content at URL: "+e.uri,code:Ju,xhr:e},u):(u.map.bytes=new Uint8Array(e.response),l(null,u))}));c.push(p)}var f,m,g=t(As.mergeOptions(e,{uri:r.resolvedUri,responseType:"arraybuffer",headers:el(r)}),(f=r,m=h,function(t,e){var i,r=e.response,n=rl(t,e);return n?m(n,f):0===r.byteLength?m({status:e.status,message:"Empty HLS segment content at URL: "+e.uri,code:Ju,xhr:e},f):(f.stats={bandwidth:(i=e).bandwidth,bytesReceived:i.bytesReceived||0,roundTripTime:i.roundTripTime||0},f.key?f.encryptedBytes=new Uint8Array(e.response):f.bytes=new Uint8Array(e.response),m(null,f))}));return g.addEventListener("progress",sl(r,n)),c.push(g),function(){return il(c)}},ol={videoCodec:"avc1",videoObjectTypeIndicator:".4d400d",audioProfile:"2"},ul=function(){var t,e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",i={codecCount:0};return i.codecCount=e.split(",").length,i.codecCount=i.codecCount||2,(t=/(^|\s|,)+(avc[13])([^ ,]*)/i.exec(e))&&(i.videoCodec=t[2],i.videoObjectTypeIndicator=t[3]),i.audioProfile=/(^|\s|,)+mp4a.[0-9A-Fa-f]+\.([0-9A-Fa-f]+)/i.exec(e),i.audioProfile=i.audioProfile&&i.audioProfile[2],i},ll=function(t,e,i){return t+"/"+e+'; codecs="'+i.filter(function(t){return!!t}).join(", ")+'"'},cl=function(t,e){var i,r,n=(i=e).segments&&i.segments.length&&i.segments[0].map?"mp4":"mp2t",s=(r=e.attributes||{}).CODECS?ul(r.CODECS):ol,a=e.attributes||{},o=!0,u=!1;if(!e)return[];if(t.mediaGroups.AUDIO&&a.AUDIO){var l=t.mediaGroups.AUDIO[a.AUDIO];if(l)for(var c in o=!(u=!0),l)if(!l[c].uri&&!l[c].playlists){o=!0;break}}u&&!s.audioProfile&&(o||(s.audioProfile=function(t,e){if(!t.mediaGroups.AUDIO||!e)return null;var i=t.mediaGroups.AUDIO[e];if(!i)return null;for(var r in i){var n=i[r];if(n.default&&n.playlists)return ul(n.playlists[0].attributes.CODECS).audioProfile}return null}(t,a.AUDIO)),s.audioProfile||(As.log.warn("Multiple audio tracks present but no audio codec string is specified. Attempting to use the default audio codec (mp4a.40.2)"),s.audioProfile=ol.audioProfile));var h={};s.videoCodec&&(h.video=""+s.videoCodec+s.videoObjectTypeIndicator),s.audioProfile&&(h.audio="mp4a.40."+s.audioProfile);var d=ll("audio",n,[h.audio]),p=ll("video",n,[h.video]),f=ll("video",n,[h.video,h.audio]);return u?!o&&h.video?[p,d]:o||h.video?[f,d]:[d,d]:h.video?[f]:[d]},hl=function(t,e){var i;return t&&(i=g.getComputedStyle(t))?i[e]:""},dl=function(t,r){var n=t.slice();t.sort(function(t,e){var i=r(t,e);return 0===i?n.indexOf(t)-n.indexOf(e):i})},pl=function(t,e){var i=void 0,r=void 0;return t.attributes.BANDWIDTH&&(i=t.attributes.BANDWIDTH),i=i||g.Number.MAX_VALUE,e.attributes.BANDWIDTH&&(r=e.attributes.BANDWIDTH),i-(r=r||g.Number.MAX_VALUE)},fl=function(t,e,i){if(!t||!e)return!1;var r=i===t.segments.length;return t.endList&&"open"===e.readyState&&r},ml=function(t){return"number"==typeof t&&isFinite(t)},gl=function(i){function r(t){y(this,r);var e=b(this,i.call(this));if(!t)throw new TypeError("Initialization settings are required");if("function"!=typeof t.currentTime)throw new TypeError("No currentTime getter specified");if(!t.mediaSource)throw new TypeError("No MediaSource specified");return e.bandwidth=t.bandwidth,e.throughput={rate:0,count:0},e.roundTrip=NaN,e.resetStats_(),e.mediaIndex=null,e.hasPlayed_=t.hasPlayed,e.currentTime_=t.currentTime,e.seekable_=t.seekable,e.seeking_=t.seeking,e.duration_=t.duration,e.mediaSource_=t.mediaSource,e.hls_=t.hls,e.loaderType_=t.loaderType,e.startingMedia_=void 0,e.segmentMetadataTrack_=t.segmentMetadataTrack,e.goalBufferLength_=t.goalBufferLength,e.sourceType_=t.sourceType,e.state_="INIT",e.checkBufferTimeout_=null,e.error_=void 0,e.currentTimeline_=-1,e.pendingSegment_=null,e.mimeType_=null,e.sourceUpdater_=null,e.xhrOptions_=null,e.activeInitSegmentId_=null,e.initSegments_={},e.decrypter_=t.decrypter,e.syncController_=t.syncController,e.syncPoint_={segmentIndex:0,time:0},e.syncController_.on("syncinfoupdate",function(){return e.trigger("syncinfoupdate")}),e.mediaSource_.addEventListener("sourceopen",function(){return e.ended_=!1}),e.fetchAtBuffer_=!1,e.logger_=Yu("SegmentLoader["+e.loaderType_+"]"),Object.defineProperty(e,"state",{get:function(){return this.state_},set:function(t){t!==this.state_&&(this.logger_(this.state_+" -> "+t),this.state_=t)}}),e}return _(r,i),r.prototype.resetStats_=function(){this.mediaBytesTransferred=0,this.mediaRequests=0,this.mediaRequestsAborted=0,this.mediaRequestsTimedout=0,this.mediaRequestsErrored=0,this.mediaTransferDuration=0,this.mediaSecondsLoaded=0},r.prototype.dispose=function(){this.state="DISPOSED",this.pause(),this.abort_(),this.sourceUpdater_&&this.sourceUpdater_.dispose(),this.resetStats_()},r.prototype.abort=function(){"WAITING"===this.state?(this.abort_(),this.state="READY",this.paused()||this.monitorBuffer_()):this.pendingSegment_&&(this.pendingSegment_=null)},r.prototype.abort_=function(){this.pendingSegment_&&this.pendingSegment_.abortRequests(),this.pendingSegment_=null},r.prototype.error=function(t){return"undefined"!=typeof t&&(this.error_=t),this.pendingSegment_=null,this.error_},r.prototype.endOfStream=function(){this.ended_=!0,this.pause(),this.trigger("ended")},r.prototype.buffered_=function(){return this.sourceUpdater_?this.sourceUpdater_.buffered():As.createTimeRanges()},r.prototype.initSegment=function(t){var e=1<arguments.length&&void 0!==arguments[1]&&arguments[1];if(!t)return null;var i=hu(t),r=this.initSegments_[i];return e&&!r&&t.bytes&&(this.initSegments_[i]=r={resolvedUri:t.resolvedUri,byterange:t.byterange,bytes:t.bytes}),r||t},r.prototype.couldBeginLoading_=function(){return this.playlist_&&(this.sourceUpdater_||this.mimeType_&&"INIT"===this.state)&&!this.paused()},r.prototype.load=function(){if(this.monitorBuffer_(),this.playlist_){if(this.syncController_.setDateTimeMapping(this.playlist_),"INIT"===this.state&&this.couldBeginLoading_())return this.init_();!this.couldBeginLoading_()||"READY"!==this.state&&"INIT"!==this.state||(this.state="READY")}},r.prototype.init_=function(){return this.state="READY",this.sourceUpdater_=new Ku(this.mediaSource_,this.mimeType_,this.loaderType_,this.sourceBufferEmitter_),this.resetEverything(),this.monitorBuffer_()},r.prototype.playlist=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(t){var i=this.playlist_,r=this.pendingSegment_;this.playlist_=t,this.xhrOptions_=e,this.hasPlayed_()||(t.syncInfo={mediaSequence:t.mediaSequence,time:0});var n=i?i.id:null;if(this.logger_("playlist update ["+n+" => "+t.id+"]"),this.trigger("syncinfoupdate"),"INIT"===this.state&&this.couldBeginLoading_())return this.init_();if(i&&i.uri===t.uri){var s=t.mediaSequence-i.mediaSequence;this.logger_("live window shift ["+s+"]"),null!==this.mediaIndex&&(this.mediaIndex-=s),r&&(r.mediaIndex-=s,0<=r.mediaIndex&&(r.segment=t.segments[r.mediaIndex])),this.syncController_.saveExpiredSegmentInfo(i,t)}else null!==this.mediaIndex&&this.resyncLoader()}},r.prototype.pause=function(){this.checkBufferTimeout_&&(g.clearTimeout(this.checkBufferTimeout_),this.checkBufferTimeout_=null)},r.prototype.paused=function(){return null===this.checkBufferTimeout_},r.prototype.mimeType=function(t,e){this.mimeType_||(this.mimeType_=t,this.sourceBufferEmitter_=e,"INIT"===this.state&&this.couldBeginLoading_()&&this.init_())},r.prototype.resetEverything=function(){this.ended_=!1,this.resetLoader(),this.remove(0,this.duration_()),this.trigger("reseteverything")},r.prototype.resetLoader=function(){this.fetchAtBuffer_=!1,this.resyncLoader()},r.prototype.resyncLoader=function(){this.mediaIndex=null,this.syncPoint_=null,this.abort()},r.prototype.remove=function(t,e){this.sourceUpdater_&&this.sourceUpdater_.remove(t,e),bu(t,e,this.segmentMetadataTrack_)},r.prototype.monitorBuffer_=function(){this.checkBufferTimeout_&&g.clearTimeout(this.checkBufferTimeout_),this.checkBufferTimeout_=g.setTimeout(this.monitorBufferTick_.bind(this),1)},r.prototype.monitorBufferTick_=function(){"READY"===this.state&&this.fillBuffer_(),this.checkBufferTimeout_&&g.clearTimeout(this.checkBufferTimeout_),this.checkBufferTimeout_=g.setTimeout(this.monitorBufferTick_.bind(this),500)},r.prototype.fillBuffer_=function(){if(!this.sourceUpdater_.updating()){this.syncPoint_||(this.syncPoint_=this.syncController_.getSyncPoint(this.playlist_,this.duration_(),this.currentTimeline_,this.currentTime_()));var t=this.checkBuffer_(this.buffered_(),this.playlist_,this.mediaIndex,this.hasPlayed_(),this.currentTime_(),this.syncPoint_);if(t)fl(this.playlist_,this.mediaSource_,t.mediaIndex)?this.endOfStream():(t.mediaIndex!==this.playlist_.segments.length-1||"ended"!==this.mediaSource_.readyState||this.seeking_())&&((t.timeline!==this.currentTimeline_||null!==t.startOfSegment&&t.startOfSegment<this.sourceUpdater_.timestampOffset())&&(this.syncController_.reset(),t.timestampOffset=t.startOfSegment),this.loadSegment_(t))}},r.prototype.checkBuffer_=function(t,e,i,r,n,s){var a=0,o=void 0;t.length&&(a=t.end(t.length-1));var u=Math.max(0,a-n);if(!e.segments.length)return null;if(u>=this.goalBufferLength_())return null;if(!r&&1<=u)return null;if(null===s)return i=this.getSyncSegmentCandidate_(e),this.generateSegmentInfo_(e,i,null,!0);if(null!==i){var l=e.segments[i];return o=l&&l.end?l.end:a,this.generateSegmentInfo_(e,i+1,o,!1)}if(this.fetchAtBuffer_){var c=nu.getMediaInfoForTime(e,a,s.segmentIndex,s.time);i=c.mediaIndex,o=c.startTime}else{var h=nu.getMediaInfoForTime(e,n,s.segmentIndex,s.time);i=h.mediaIndex,o=h.startTime}return this.generateSegmentInfo_(e,i,o,!1)},r.prototype.getSyncSegmentCandidate_=function(t){var e=this;if(-1===this.currentTimeline_)return 0;var i=t.segments.map(function(t,e){return{timeline:t.timeline,segmentIndex:e}}).filter(function(t){return t.timeline===e.currentTimeline_});return i.length?i[Math.min(i.length-1,1)].segmentIndex:Math.max(t.segments.length-1,0)},r.prototype.generateSegmentInfo_=function(t,e,i,r){if(e<0||e>=t.segments.length)return null;var n=t.segments[e];return{requestId:"segment-loader-"+Math.random(),uri:n.resolvedUri,mediaIndex:e,isSyncRequest:r,startOfSegment:i,playlist:t,bytes:null,encryptedBytes:null,timestampOffset:null,timeline:n.timeline,duration:n.duration,segment:n}},r.prototype.abortRequestEarly_=function(t){if(this.hls_.tech_.paused()||!this.xhrOptions_.timeout||!this.playlist_.attributes.BANDWIDTH)return!1;if(Date.now()-(t.firstBytesReceivedAt||Date.now())<1e3)return!1;var e=this.currentTime_(),i=t.bandwidth,r=this.pendingSegment_.duration,n=nu.estimateSegmentRequestTime(r,i,this.playlist_,t.bytesReceived),s=function(t,e){var i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:1;return((t.length?t.end(t.length-1):0)-e)/i}(this.buffered_(),e,this.hls_.tech_.playbackRate())-1;if(n<=s)return!1;var a=function(t){var e=t.master,i=t.currentTime,r=t.bandwidth,n=t.duration,s=t.segmentDuration,a=t.timeUntilRebuffer,o=t.currentTimeline,u=t.syncController,l=e.playlists.filter(function(t){return!nu.isIncompatible(t)}),c=l.filter(nu.isEnabled);c.length||(c=l.filter(function(t){return!nu.isDisabled(t)}));var h=c.filter(nu.hasAttribute.bind(null,"BANDWIDTH")).map(function(t){var e=u.getSyncPoint(t,n,o,i)?1:2;return{playlist:t,rebufferingImpact:nu.estimateSegmentRequestTime(s,r,t)*e-a}}),d=h.filter(function(t){return t.rebufferingImpact<=0});return dl(d,function(t,e){return pl(e.playlist,t.playlist)}),d.length?d[0]:(dl(h,function(t,e){return t.rebufferingImpact-e.rebufferingImpact}),h[0]||null)}({master:this.hls_.playlists.master,currentTime:e,bandwidth:i,duration:this.duration_(),segmentDuration:r,timeUntilRebuffer:s,currentTimeline:this.currentTimeline_,syncController:this.syncController_});if(a){var o=n-s-a.rebufferingImpact,u=.5;return s<=fu&&(u=1),!a.playlist||a.playlist.uri===this.playlist_.uri||o<u?!1:(this.bandwidth=a.playlist.attributes.BANDWIDTH*Qu.BANDWIDTH_VARIANCE+1,this.abort(),this.trigger("earlyabort"),!0)}},r.prototype.handleProgress_=function(t,e){this.pendingSegment_&&e.requestId===this.pendingSegment_.requestId&&!this.abortRequestEarly_(e.stats)&&this.trigger("progress")},r.prototype.loadSegment_=function(t){this.state="WAITING",this.pendingSegment_=t,this.trimBackBuffer_(t),t.abortRequests=al(this.hls_.xhr,this.xhrOptions_,this.decrypter_,this.createSimplifiedSegmentObj_(t),this.handleProgress_.bind(this),this.segmentRequestFinished_.bind(this))},r.prototype.trimBackBuffer_=function(t){var e,i,r,n,s=(e=this.seekable_(),i=this.currentTime_(),r=this.playlist_.targetDuration||10,n=void 0,n=e.length&&0<e.start(0)&&e.start(0)<i?e.start(0):i-30,Math.min(n,i-r));0<s&&this.remove(0,s)},r.prototype.createSimplifiedSegmentObj_=function(t){var e=t.segment,i={resolvedUri:e.resolvedUri,byterange:e.byterange,requestId:t.requestId};if(e.key){var r=e.key.iv||new Uint32Array([0,0,0,t.mediaIndex+t.playlist.mediaSequence]);i.key={resolvedUri:e.key.resolvedUri,iv:r}}return e.map&&(i.map=this.initSegment(e.map)),i},r.prototype.segmentRequestFinished_=function(t,e){if(this.mediaRequests+=1,e.stats&&(this.mediaBytesTransferred+=e.stats.bytesReceived,this.mediaTransferDuration+=e.stats.roundTripTime),this.pendingSegment_){if(e.requestId===this.pendingSegment_.requestId){if(t)return this.pendingSegment_=null,this.state="READY",t.code===tl?void(this.mediaRequestsAborted+=1):(this.pause(),t.code===Zu?(this.mediaRequestsTimedout+=1,this.bandwidth=1,this.roundTrip=NaN,void this.trigger("bandwidthupdate")):(this.mediaRequestsErrored+=1,this.error(t),void this.trigger("error")));this.bandwidth=e.stats.bandwidth,this.roundTrip=e.stats.roundTripTime,e.map&&(e.map=this.initSegment(e.map,!0)),this.processSegmentResponse_(e)}}else this.mediaRequestsAborted+=1},r.prototype.processSegmentResponse_=function(t){var e=this.pendingSegment_;e.bytes=t.bytes,t.map&&(e.segment.map.bytes=t.map.bytes),e.endOfAllRequests=t.endOfAllRequests,this.handleSegment_()},r.prototype.handleSegment_=function(){var t=this;if(this.pendingSegment_){var e=this.pendingSegment_,i=e.segment,r=this.syncController_.probeSegmentInfo(e);"undefined"==typeof this.startingMedia_&&r&&(r.containsAudio||r.containsVideo)&&(this.startingMedia_={containsAudio:r.containsAudio,containsVideo:r.containsVideo});var n,s,a,o=(n=this.loaderType_,s=this.startingMedia_,a=r,"main"===n&&s&&a?a.containsAudio||a.containsVideo?s.containsVideo&&!a.containsVideo?"Only audio found in segment when we expected video. We can't switch to audio only from a stream that had video. To get rid of this message, please add codec information to the manifest.":!s.containsVideo&&a.containsVideo?"Video found in segment when we expected only audio. We can't switch to a stream with video from an audio only stream. To get rid of this message, please add codec information to the manifest.":null:"Neither audio nor video found in segment.":null);if(o)return this.error({message:o,blacklistDuration:1/0}),void this.trigger("error");if(e.isSyncRequest)return this.trigger("syncinfoupdate"),this.pendingSegment_=null,void(this.state="READY");null!==e.timestampOffset&&e.timestampOffset!==this.sourceUpdater_.timestampOffset()&&(this.sourceUpdater_.timestampOffset(e.timestampOffset),this.trigger("timestampoffset"));var u,l,c,h,d,p,f,m,g,y,v,_=this.syncController_.mappingForTimeline(e.timeline);if(null!==_&&this.trigger({type:"segmenttimemapping",mapping:_}),this.state="APPENDING",i.map){var b=hu(i.map);if(!this.activeInitSegmentId_||this.activeInitSegmentId_!==b){var T=this.initSegment(i.map);this.sourceUpdater_.appendBuffer(T.bytes,function(){t.activeInitSegmentId_=b})}}e.byteLength=e.bytes.byteLength,"number"==typeof i.start&&"number"==typeof i.end?this.mediaSecondsLoaded+=i.end-i.start:this.mediaSecondsLoaded+=i.duration,this.logger_((l=(u=e).segment,c=l.start,h=l.end,d=u.playlist,p=d.mediaSequence,f=d.id,m=d.segments,g=void 0===m?[]:m,y=u.mediaIndex,v=u.timeline,["appending ["+y+"] of ["+p+", "+(p+g.length)+"] from playlist ["+f+"]","["+c+" => "+h+"] in timeline ["+v+"]"].join(" "))),this.sourceUpdater_.appendBuffer(e.bytes,this.handleUpdateEnd_.bind(this))}else this.state="READY"},r.prototype.handleUpdateEnd_=function(){if(!this.pendingSegment_)return this.state="READY",void(this.paused()||this.monitorBuffer_());var t=this.pendingSegment_,e=t.segment,i=null!==this.mediaIndex;(this.pendingSegment_=null,this.recordThroughput_(t),this.addSegmentMetadataCue_(t),this.state="READY",this.mediaIndex=t.mediaIndex,this.fetchAtBuffer_=!0,this.currentTimeline_=t.timeline,this.trigger("syncinfoupdate"),e.end&&this.currentTime_()-e.end>3*t.playlist.targetDuration)?this.resetEverything():(i&&this.trigger("bandwidthupdate"),this.trigger("progress"),fl(t.playlist,this.mediaSource_,t.mediaIndex+1)&&this.endOfStream(),this.paused()||this.monitorBuffer_())},r.prototype.recordThroughput_=function(t){var e=this.throughput.rate,i=Date.now()-t.endOfAllRequests+1,r=Math.floor(t.byteLength/i*8*1e3);this.throughput.rate+=(r-e)/++this.throughput.count},r.prototype.addSegmentMetadataCue_=function(t){if(this.segmentMetadataTrack_){var e=t.segment,i=e.start,r=e.end;if(ml(i)&&ml(r)){bu(i,r,this.segmentMetadataTrack_);var n=g.WebKitDataCue||g.VTTCue,s={bandwidth:t.playlist.attributes.BANDWIDTH,resolution:t.playlist.attributes.RESOLUTION,codecs:t.playlist.attributes.CODECS,byteLength:t.byteLength,uri:t.uri,timeline:t.timeline,playlist:t.playlist.uri,start:i,end:r},a=new n(i,r,JSON.stringify(s));a.value=s,this.segmentMetadataTrack_.addCue(a)}}},r}(As.EventTarget),yl=new Uint8Array("\n\n".split("").map(function(t){return t.charCodeAt(0)})),vl=function(t){return String.fromCharCode.apply(null,t)},_l=function(r){function n(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};y(this,n);var i=b(this,r.call(this,t,e));return i.mediaSource_=null,i.subtitlesTrack_=null,i}return _(n,r),n.prototype.buffered_=function(){if(!this.subtitlesTrack_||!this.subtitlesTrack_.cues.length)return As.createTimeRanges();var t=this.subtitlesTrack_.cues,e=t[0].startTime,i=t[t.length-1].startTime;return As.createTimeRanges([[e,i]])},n.prototype.initSegment=function(t){var e=1<arguments.length&&void 0!==arguments[1]&&arguments[1];if(!t)return null;var i=hu(t),r=this.initSegments_[i];if(e&&!r&&t.bytes){var n=yl.byteLength+t.bytes.byteLength,s=new Uint8Array(n);s.set(t.bytes),s.set(yl,t.bytes.byteLength),this.initSegments_[i]=r={resolvedUri:t.resolvedUri,byterange:t.byterange,bytes:s}}return r||t},n.prototype.couldBeginLoading_=function(){return this.playlist_&&this.subtitlesTrack_&&!this.paused()},n.prototype.init_=function(){return this.state="READY",this.resetEverything(),this.monitorBuffer_()},n.prototype.track=function(t){return"undefined"==typeof t||(this.subtitlesTrack_=t,"INIT"===this.state&&this.couldBeginLoading_()&&this.init_()),this.subtitlesTrack_},n.prototype.remove=function(t,e){bu(t,e,this.subtitlesTrack_)},n.prototype.fillBuffer_=function(){var t=this;this.syncPoint_||(this.syncPoint_=this.syncController_.getSyncPoint(this.playlist_,this.duration_(),this.currentTimeline_,this.currentTime_()));var e=this.checkBuffer_(this.buffered_(),this.playlist_,this.mediaIndex,this.hasPlayed_(),this.currentTime_(),this.syncPoint_);if(e=this.skipEmptySegments_(e)){if(null===this.syncController_.timestampOffsetForTimeline(e.timeline)){return this.syncController_.one("timestampoffset",function(){t.state="READY",t.paused()||t.monitorBuffer_()}),void(this.state="WAITING_ON_TIMELINE")}this.loadSegment_(e)}},n.prototype.skipEmptySegments_=function(t){for(;t&&t.segment.empty;)t=this.generateSegmentInfo_(t.playlist,t.mediaIndex+1,t.startOfSegment+t.duration,t.isSyncRequest);return t},n.prototype.handleSegment_=function(){var e=this;if(this.pendingSegment_&&this.subtitlesTrack_){this.state="APPENDING";var t=this.pendingSegment_,i=t.segment;if("function"!=typeof g.WebVTT&&this.subtitlesTrack_&&this.subtitlesTrack_.tech_){var r=function(){e.handleSegment_()};return this.state="WAITING_ON_VTTJS",this.subtitlesTrack_.tech_.one("vttjsloaded",r),void this.subtitlesTrack_.tech_.one("vttjserror",function(){e.subtitlesTrack_.tech_.off("vttjsloaded",r),e.error({message:"Error loading vtt.js"}),e.state="READY",e.pause(),e.trigger("error")})}i.requested=!0;try{this.parseVTTCues_(t)}catch(t){return this.error({message:t.message}),this.state="READY",this.pause(),this.trigger("error")}if(this.updateTimeMapping_(t,this.syncController_.timelines[t.timeline],this.playlist_),t.isSyncRequest)return this.trigger("syncinfoupdate"),this.pendingSegment_=null,void(this.state="READY");t.byteLength=t.bytes.byteLength,this.mediaSecondsLoaded+=i.duration,t.cues.length&&this.remove(t.cues[0].endTime,t.cues[t.cues.length-1].endTime),t.cues.forEach(function(t){e.subtitlesTrack_.addCue(t)}),this.handleUpdateEnd_()}else this.state="READY"},n.prototype.parseVTTCues_=function(e){var t=void 0,i=!1;"function"==typeof g.TextDecoder?t=new g.TextDecoder("utf8"):(t=g.WebVTT.StringDecoder(),i=!0);var r=new g.WebVTT.Parser(g,g.vttjs,t);if(e.cues=[],e.timestampmap={MPEGTS:0,LOCAL:0},r.oncue=e.cues.push.bind(e.cues),r.ontimestampmap=function(t){return e.timestampmap=t},r.onparsingerror=function(t){As.log.warn("Error encountered when parsing cues: "+t.message)},e.segment.map){var n=e.segment.map.bytes;i&&(n=vl(n)),r.parse(n)}var s=e.bytes;i&&(s=vl(s)),r.parse(s),r.flush()},n.prototype.updateTimeMapping_=function(t,e,i){var r=t.segment;if(e)if(t.cues.length){var n=t.timestampmap,s=n.MPEGTS/9e4-n.LOCAL+e.mapping;if(t.cues.forEach(function(t){t.startTime+=s,t.endTime+=s}),!i.syncInfo){var a=t.cues[0].startTime,o=t.cues[t.cues.length-1].startTime;i.syncInfo={mediaSequence:i.mediaSequence+t.mediaIndex,time:Math.min(a,o-r.duration)}}}else r.empty=!0},n}(gl),bl=function(t,e){for(var i=t.cues,r=0;r<i.length;r++){var n=i[r];if(e>=n.adStartTime&&e<=n.adEndTime)return n}return null},Tl=So,Sl=[{name:"VOD",run:function(t,e,i,r,n){if(i!==1/0){return{time:0,segmentIndex:0}}return null}},{name:"ProgramDateTime",run:function(t,e,i,r,n){if(!t.datetimeToDisplayTime)return null;var s=e.segments||[],a=null,o=null;n=n||0;for(var u=0;u<s.length;u++){var l=s[u];if(l.dateTimeObject){var c=l.dateTimeObject.getTime()/1e3+t.datetimeToDisplayTime,h=Math.abs(n-c);if(null!==o&&o<h)break;o=h,a={time:c,segmentIndex:u}}}return a}},{name:"Segment",run:function(t,e,i,r,n){var s=e.segments||[],a=null,o=null;n=n||0;for(var u=0;u<s.length;u++){var l=s[u];if(l.timeline===r&&"undefined"!=typeof l.start){var c=Math.abs(n-l.start);if(null!==o&&o<c)break;(!a||null===o||c<=o)&&(o=c,a={time:l.start,segmentIndex:u})}}return a}},{name:"Discontinuity",run:function(t,e,i,r,n){var s=null;if(n=n||0,e.discontinuityStarts&&e.discontinuityStarts.length)for(var a=null,o=0;o<e.discontinuityStarts.length;o++){var u=e.discontinuityStarts[o],l=e.discontinuitySequence+o+1,c=t.discontinuities[l];if(c){var h=Math.abs(n-c.time);if(null!==a&&a<h)break;(!s||null===a||h<=a)&&(a=h,s={time:c.time,segmentIndex:u})}}return s}},{name:"Playlist",run:function(t,e,i,r,n){return e.syncInfo?{time:e.syncInfo.time,segmentIndex:e.syncInfo.mediaSequence-e.mediaSequence}:null}}],kl=function(e){function i(){y(this,i);var t=b(this,e.call(this));return t.inspectCache_=void 0,t.timelines=[],t.discontinuities=[],t.datetimeToDisplayTime=null,t.logger_=Yu("SyncController"),t}return _(i,e),i.prototype.getSyncPoint=function(t,e,i,r){var n=this.runStrategies_(t,e,i,r);return n.length?this.selectSyncPoint_(n,{key:"time",value:r}):null},i.prototype.getExpiredTime=function(t,e){if(!t||!t.segments)return null;var i=this.runStrategies_(t,e,t.discontinuitySequence,0);if(!i.length)return null;var r=this.selectSyncPoint_(i,{key:"segmentIndex",value:0});return 0<r.segmentIndex&&(r.time*=-1),Math.abs(r.time+Go(t,r.segmentIndex,0))},i.prototype.runStrategies_=function(t,e,i,r){for(var n=[],s=0;s<Sl.length;s++){var a=Sl[s],o=a.run(this,t,e,i,r);o&&(o.strategy=a.name,n.push({strategy:a.name,syncPoint:o}))}return n},i.prototype.selectSyncPoint_=function(t,e){for(var i=t[0].syncPoint,r=Math.abs(t[0].syncPoint[e.key]-e.value),n=t[0].strategy,s=1;s<t.length;s++){var a=Math.abs(t[s].syncPoint[e.key]-e.value);a<r&&(r=a,i=t[s].syncPoint,n=t[s].strategy)}return this.logger_("syncPoint for ["+e.key+": "+e.value+"] chosen with strategy ["+n+"]: [time:"+i.time+", segmentIndex:"+i.segmentIndex+"]"),i},i.prototype.saveExpiredSegmentInfo=function(t,e){for(var i=e.mediaSequence-t.mediaSequence-1;0<=i;i--){var r=t.segments[i];if(r&&"undefined"!=typeof r.start){e.syncInfo={mediaSequence:t.mediaSequence+i,time:r.start},this.logger_("playlist refresh sync: [time:"+e.syncInfo.time+", mediaSequence: "+e.syncInfo.mediaSequence+"]"),this.trigger("syncinfoupdate");break}}},i.prototype.setDateTimeMapping=function(t){if(!this.datetimeToDisplayTime&&t.segments&&t.segments.length&&t.segments[0].dateTimeObject){var e=t.segments[0].dateTimeObject.getTime()/1e3;this.datetimeToDisplayTime=-e}},i.prototype.reset=function(){this.inspectCache_=void 0},i.prototype.probeSegmentInfo=function(t){var e=t.segment,i=t.playlist,r=void 0;return(r=e.map?this.probeMp4Segment_(t):this.probeTsSegment_(t))&&this.calculateSegmentTimeMapping_(t,r)&&(this.saveDiscontinuitySyncInfo_(t),i.syncInfo||(i.syncInfo={mediaSequence:i.mediaSequence+t.mediaIndex,time:e.start})),r},i.prototype.probeMp4Segment_=function(t){var e=t.segment,i=La(e.map.bytes),r=Pa(i,t.bytes);return null!==t.timestampOffset&&(t.timestampOffset-=r),{start:r,end:r+e.duration}},i.prototype.probeTsSegment_=function(t){var e=Tl(t.bytes,this.inspectCache_),i=void 0,r=void 0;return e?(e.video&&2===e.video.length?(this.inspectCache_=e.video[1].dts,i=e.video[0].dtsTime,r=e.video[1].dtsTime):e.audio&&2===e.audio.length&&(this.inspectCache_=e.audio[1].dts,i=e.audio[0].dtsTime,r=e.audio[1].dtsTime),{start:i,end:r,containsVideo:e.video&&2===e.video.length,containsAudio:e.audio&&2===e.audio.length}):null},i.prototype.timestampOffsetForTimeline=function(t){return"undefined"==typeof this.timelines[t]?null:this.timelines[t].time},i.prototype.mappingForTimeline=function(t){return"undefined"==typeof this.timelines[t]?null:this.timelines[t].mapping},i.prototype.calculateSegmentTimeMapping_=function(t,e){var i=t.segment,r=this.timelines[t.timeline];if(null!==t.timestampOffset)r={time:t.startOfSegment,mapping:t.startOfSegment-e.start},this.timelines[t.timeline]=r,this.trigger("timestampoffset"),this.logger_("time mapping for timeline "+t.timeline+": [time: "+r.time+"] [mapping: "+r.mapping+"]"),i.start=t.startOfSegment,i.end=e.end+r.mapping;else{if(!r)return!1;i.start=e.start+r.mapping,i.end=e.end+r.mapping}return!0},i.prototype.saveDiscontinuitySyncInfo_=function(t){var e=t.playlist,i=t.segment;if(i.discontinuity)this.discontinuities[i.timeline]={time:i.start,accuracy:0};else if(e.discontinuityStarts&&e.discontinuityStarts.length)for(var r=0;r<e.discontinuityStarts.length;r++){var n=e.discontinuityStarts[r],s=e.discontinuitySequence+r+1,a=n-t.mediaIndex,o=Math.abs(a);if(!this.discontinuities[s]||this.discontinuities[s].accuracy>o){var u=void 0;u=a<0?i.start-Go(e,t.mediaIndex,n):i.end+Go(e,t.mediaIndex+1,n),this.discontinuities[s]={time:u,accuracy:o}}}},i}(As.EventTarget),Cl=new Pu("./decrypter-worker.worker.js",function(t,e){var i,s,h,r,n,d,p,g,a,l,y,o,u=this;i="undefined"!=typeof t?t:"undefined"!=typeof global?global:"undefined"!=typeof u?u:{},s="undefined"!=typeof t?t:"undefined"!=typeof i?i:"undefined"!=typeof u?u:{},h=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},r=function(){function r(t,e){for(var i=0;i<e.length;i++){var r=e[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return function(t,e,i){return e&&r(t.prototype,e),i&&r(t,i),t}}(),n=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!==("undefined"==typeof e?"undefined":v(e))&&"function"!=typeof e?t:e},d=function(){var t=[[[],[],[],[],[]],[[],[],[],[],[]]],e=t[0],i=t[1],r=e[4],n=i[4],s=void 0,a=void 0,o=void 0,u=[],l=[],c=void 0,h=void 0,d=void 0,p=void 0,f=void 0;for(s=0;s<256;s++)l[(u[s]=s<<1^283*(s>>7))^s]=s;for(a=o=0;!r[a];a^=c||1,o=l[o]||1)for(d=(d=o^o<<1^o<<2^o<<3^o<<4)>>8^255&d^99,f=16843009*u[h=u[c=u[n[r[a]=d]=a]]]^65537*h^257*c^16843008*a,p=257*u[d]^16843008*d,s=0;s<4;s++)e[s][a]=p=p<<24^p>>>8,i[s][d]=f=f<<24^f>>>8;for(s=0;s<5;s++)e[s]=e[s].slice(0),i[s]=i[s].slice(0);return t},p=null,g=function(){function c(t){h(this,c),p||(p=d()),this._tables=[[p[0][0].slice(),p[0][1].slice(),p[0][2].slice(),p[0][3].slice(),p[0][4].slice()],[p[1][0].slice(),p[1][1].slice(),p[1][2].slice(),p[1][3].slice(),p[1][4].slice()]];var e=void 0,i=void 0,r=void 0,n=void 0,s=void 0,a=this._tables[0][4],o=this._tables[1],u=t.length,l=1;if(4!==u&&6!==u&&8!==u)throw new Error("Invalid aes key size");for(n=t.slice(0),s=[],this._key=[n,s],e=u;e<4*u+28;e++)r=n[e-1],(e%u==0||8===u&&e%u==4)&&(r=a[r>>>24]<<24^a[r>>16&255]<<16^a[r>>8&255]<<8^a[255&r],e%u==0&&(r=r<<8^r>>>24^l<<24,l=l<<1^283*(l>>7))),n[e]=n[e-u]^r;for(i=0;e;i++,e--)r=n[3&i?e:e-4],s[i]=e<=4||i<4?r:o[0][a[r>>>24]]^o[1][a[r>>16&255]]^o[2][a[r>>8&255]]^o[3][a[255&r]]}return c.prototype.decrypt=function(t,e,i,r,n,s){var a=this._key[1],o=t^a[0],u=r^a[1],l=i^a[2],c=e^a[3],h=void 0,d=void 0,p=void 0,f=a.length/4-2,m=void 0,g=4,y=this._tables[1],v=y[0],_=y[1],b=y[2],T=y[3],S=y[4];for(m=0;m<f;m++)h=v[o>>>24]^_[u>>16&255]^b[l>>8&255]^T[255&c]^a[g],d=v[u>>>24]^_[l>>16&255]^b[c>>8&255]^T[255&o]^a[g+1],p=v[l>>>24]^_[c>>16&255]^b[o>>8&255]^T[255&u]^a[g+2],c=v[c>>>24]^_[o>>16&255]^b[u>>8&255]^T[255&l]^a[g+3],g+=4,o=h,u=d,l=p;for(m=0;m<4;m++)n[(3&-m)+s]=S[o>>>24]<<24^S[u>>16&255]<<16^S[l>>8&255]<<8^S[255&c]^a[g++],h=o,o=u,u=l,l=c,c=h},c}(),a=function(){function t(){h(this,t),this.listeners={}}return t.prototype.on=function(t,e){this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(e)},t.prototype.off=function(t,e){if(!this.listeners[t])return!1;var i=this.listeners[t].indexOf(e);return this.listeners[t].splice(i,1),-1<i},t.prototype.trigger=function(t){var e=this.listeners[t];if(e)if(2===arguments.length)for(var i=e.length,r=0;r<i;++r)e[r].call(this,arguments[1]);else for(var n=Array.prototype.slice.call(arguments,1),s=e.length,a=0;a<s;++a)e[a].apply(this,n)},t.prototype.dispose=function(){this.listeners={}},t.prototype.pipe=function(e){this.on("data",function(t){e.push(t)})},t}(),l=function(e){function i(){h(this,i);var t=n(this,e.call(this,a));return t.jobs=[],t.delay=1,t.timeout_=null,t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+("undefined"==typeof e?"undefined":v(e)));t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(i,e),i.prototype.processJob_=function(){this.jobs.shift()(),this.jobs.length?this.timeout_=setTimeout(this.processJob_.bind(this),this.delay):this.timeout_=null},i.prototype.push=function(t){this.jobs.push(t),this.timeout_||(this.timeout_=setTimeout(this.processJob_.bind(this),this.delay))},i}(a),y=function(t){return t<<24|(65280&t)<<8|(16711680&t)>>8|t>>>24},o=function(){function u(t,e,i,r){h(this,u);var n=u.STEP,s=new Int32Array(t.buffer),a=new Uint8Array(t.byteLength),o=0;for(this.asyncStream_=new l,this.asyncStream_.push(this.decryptChunk_(s.subarray(o,o+n),e,i,a)),o=n;o<s.length;o+=n)i=new Uint32Array([y(s[o-4]),y(s[o-3]),y(s[o-2]),y(s[o-1])]),this.asyncStream_.push(this.decryptChunk_(s.subarray(o,o+n),e,i,a));this.asyncStream_.push(function(){var t;r(null,(t=a).subarray(0,t.byteLength-t[t.byteLength-1]))})}return u.prototype.decryptChunk_=function(e,i,r,n){return function(){var t=function(t,e,i){var r=new Int32Array(t.buffer,t.byteOffset,t.byteLength>>2),n=new g(Array.prototype.slice.call(e)),s=new Uint8Array(t.byteLength),a=new Int32Array(s.buffer),o=void 0,u=void 0,l=void 0,c=void 0,h=void 0,d=void 0,p=void 0,f=void 0,m=void 0;for(o=i[0],u=i[1],l=i[2],c=i[3],m=0;m<r.length;m+=4)h=y(r[m]),d=y(r[m+1]),p=y(r[m+2]),f=y(r[m+3]),n.decrypt(h,d,p,f,a,m),a[m]=y(a[m]^o),a[m+1]=y(a[m+1]^u),a[m+2]=y(a[m+2]^l),a[m+3]=y(a[m+3]^c),o=h,u=d,l=p,c=f;return s}(e,i,r);n.set(t,e.byteOffset)}},r(u,null,[{key:"STEP",get:function(){return 32e3}}]),u}(),new function(t){t.onmessage=function(t){var n=t.data,e=new Uint8Array(n.encrypted.bytes,n.encrypted.byteOffset,n.encrypted.byteLength),i=new Uint32Array(n.key.bytes,n.key.byteOffset,n.key.byteLength/4),r=new Uint32Array(n.iv.bytes,n.iv.byteOffset,n.iv.byteLength/4);new o(e,i,r,function(t,e){var i,r;s.postMessage((i={source:n.source,decrypted:e},r={},Object.keys(i).forEach(function(t){var e=i[t];ArrayBuffer.isView(e)?r[t]={bytes:e.buffer,byteOffset:e.byteOffset,byteLength:e.byteLength}:r[t]=e}),r),[e.buffer])})}}(u)}),El=function(t,e){t.abort(),t.pause(),e&&e.activePlaylistLoader&&(e.activePlaylistLoader.pause(),e.activePlaylistLoader=null)},wl=function(t,e){(e.activePlaylistLoader=t).load()},Al={AUDIO:function(u,l){return function(){var t=l.segmentLoaders[u],e=l.mediaTypes[u],i=l.blacklistCurrentPlaylist;El(t,e);var r=e.activeTrack(),n=e.activeGroup(),s=(n.filter(function(t){return t.default})[0]||n[0]).id,a=e.tracks[s];if(r!==a){for(var o in As.log.warn("Problem encountered loading the alternate audio track.Switching back to default."),e.tracks)e.tracks[o].enabled=e.tracks[o]===a;e.onTrackChanged()}else i({message:"Problem encountered loading the default audio track."})}},SUBTITLES:function(r,n){return function(){var t=n.segmentLoaders[r],e=n.mediaTypes[r];As.log.warn("Problem encountered loading the subtitle track.Disabling subtitle track."),El(t,e);var i=e.activeTrack();i&&(i.mode="disabled"),e.onTrackChanged()}}},Ll={AUDIO:function(t,e,i){if(e){var r=i.tech,n=i.requestOptions,s=i.segmentLoaders[t];e.on("loadedmetadata",function(){var t=e.media();s.playlist(t,n),(!r.paused()||t.endList&&"none"!==r.preload())&&s.load()}),e.on("loadedplaylist",function(){s.playlist(e.media(),n),r.paused()||s.load()}),e.on("error",Al[t](t,i))}},SUBTITLES:function(t,e,i){var r=i.tech,n=i.requestOptions,s=i.segmentLoaders[t],a=i.mediaTypes[t];e.on("loadedmetadata",function(){var t=e.media();s.playlist(t,n),s.track(a.activeTrack()),(!r.paused()||t.endList&&"none"!==r.preload())&&s.load()}),e.on("loadedplaylist",function(){s.playlist(e.media(),n),r.paused()||s.load()}),e.on("error",Al[t](t,i))}},Pl=function(e,i){return function(t){return t.attributes[e]===i}},Ol=function(e){return function(t){return t.resolvedUri===e}},xl={AUDIO:function(t,e){var i,r,n=e.hls,s=e.sourceType,a=e.segmentLoaders[t],o=e.requestOptions.withCredentials,u=e.master,l=u.mediaGroups,c=u.playlists,h=e.mediaTypes[t],d=h.groups,p=h.tracks,f=e.masterPlaylistLoader;for(var m in l[t]&&0!==Object.keys(l[t]).length||(l[t]={main:{default:{default:!0}}}),l[t]){d[m]||(d[m]=[]);var g=c.filter(Pl(t,m));for(var y in l[t][m]){var v=l[t][m][y];g.filter(Ol(v.resolvedUri)).length&&delete v.resolvedUri;var _=void 0;if(_=v.resolvedUri?new Vo(v.resolvedUri,n,o):v.playlists&&"dash"===s?new Xu(v.playlists[0],n,o,f):null,v=As.mergeOptions({id:y,playlistLoader:_},v),Ll[t](t,v.playlistLoader,e),d[m].push(v),"undefined"==typeof p[y]){var b=new As.AudioTrack({id:y,kind:(i=v,r=void 0,r=i.default?"main":"alternative",i.characteristics&&0<=i.characteristics.indexOf("public.accessibility.describes-video")&&(r="main-desc"),r),enabled:!1,language:v.language,default:v.default,label:y});p[y]=b}}}a.on("error",Al[t](t,e))},SUBTITLES:function(t,e){var i=e.tech,r=e.hls,n=e.sourceType,s=e.segmentLoaders[t],a=e.requestOptions.withCredentials,o=e.master.mediaGroups,u=e.mediaTypes[t],l=u.groups,c=u.tracks,h=e.masterPlaylistLoader;for(var d in o[t])for(var p in l[d]||(l[d]=[]),o[t][d])if(!o[t][d][p].forced){var f=o[t][d][p],m=void 0;if("hls"===n?m=new Vo(f.resolvedUri,r,a):"dash"===n&&(m=new Xu(f.playlists[0],r,a,h)),f=As.mergeOptions({id:p,playlistLoader:m},f),Ll[t](t,f.playlistLoader,e),l[d].push(f),"undefined"==typeof c[p]){var g=i.addRemoteTextTrack({id:p,kind:"subtitles",enabled:!1,language:f.language,label:p},!1).track;c[p]=g}}s.on("error",Al[t](t,e))},"CLOSED-CAPTIONS":function(t,e){var i=e.tech,r=e.master.mediaGroups,n=e.mediaTypes[t],s=n.groups,a=n.tracks;for(var o in r[t])for(var u in s[o]||(s[o]=[]),r[t][o]){var l=r[t][o][u];if(l.instreamId.match(/CC\d/)&&(s[o].push(As.mergeOptions({id:u},l)),"undefined"==typeof a[u])){var c=i.addRemoteTextTrack({id:l.instreamId,kind:"captions",enabled:!1,language:l.language,label:u},!1).track;a[u]=c}}}},Il={AUDIO:function(i,r){return function(){var t=r.mediaTypes[i].tracks;for(var e in t)if(t[e].enabled)return t[e];return null}},SUBTITLES:function(i,r){return function(){var t=r.mediaTypes[i].tracks;for(var e in t)if("showing"===t[e].mode)return t[e];return null}}},Dl=function(e){["AUDIO","SUBTITLES","CLOSED-CAPTIONS"].forEach(function(t){xl[t](t,e)});var i=e.mediaTypes,t=e.masterPlaylistLoader,r=e.tech,n=e.hls;["AUDIO","SUBTITLES"].forEach(function(t){var s,a,o,u,l,c;i[t].activeGroup=(s=t,a=e,function(e){var t=a.masterPlaylistLoader,i=a.mediaTypes[s].groups,r=t.media();if(!r)return null;var n=null;return r.attributes[s]&&(n=i[r.attributes[s]]),n=n||i.main,"undefined"==typeof e?n:null===e?null:n.filter(function(t){return t.id===e.id})[0]||null}),i[t].activeTrack=Il[t](t,e),i[t].onGroupChanged=(o=t,u=e,function(){var t=u.segmentLoaders,e=t[o],i=t.main,r=u.mediaTypes[o],n=r.activeTrack(),s=r.activeGroup(n),a=r.activePlaylistLoader;El(e,r),s&&(s.playlistLoader?(e.resyncLoader(),wl(s.playlistLoader,r)):a&&i.resetEverything())}),i[t].onTrackChanged=(l=t,c=e,function(){var t=c.segmentLoaders,e=t[l],i=t.main,r=c.mediaTypes[l],n=r.activeTrack(),s=r.activeGroup(n),a=r.activePlaylistLoader;El(e,r),s&&(s.playlistLoader?(a!==s.playlistLoader&&(e.track&&e.track(n),e.resetEverything()),wl(s.playlistLoader,r)):i.resetEverything())})});var s=i.AUDIO.activeGroup(),a=(s.filter(function(t){return t.default})[0]||s[0]).id;i.AUDIO.tracks[a].enabled=!0,i.AUDIO.onTrackChanged(),t.on("mediachange",function(){["AUDIO","SUBTITLES"].forEach(function(t){return i[t].onGroupChanged()})});var o=function(){i.AUDIO.onTrackChanged(),r.trigger({type:"usage",name:"hls-audio-change"})};for(var u in r.audioTracks().addEventListener("change",o),r.remoteTextTracks().addEventListener("change",i.SUBTITLES.onTrackChanged),n.on("dispose",function(){r.audioTracks().removeEventListener("change",o),r.remoteTextTracks().removeEventListener("change",i.SUBTITLES.onTrackChanged)}),r.clearTracks("audio"),i.AUDIO.tracks)r.audioTracks().addTrack(i.AUDIO.tracks[u])},Rl=function(){var e={};return["AUDIO","SUBTITLES","CLOSED-CAPTIONS"].forEach(function(t){e[t]={groups:{},tracks:{},activePlaylistLoader:null,activeGroup:$u,activeTrack:$u,onGroupChanged:$u,onTrackChanged:$u}}),e},Ml=void 0,Ul=["mediaRequests","mediaRequestsAborted","mediaRequestsTimedout","mediaRequestsErrored","mediaTransferDuration","mediaBytesTransferred"],Nl=function(t){return this.audioSegmentLoader_[t]+this.mainSegmentLoader_[t]},Bl=function(d){function p(t){y(this,p);var e=b(this,d.call(this)),i=t.url,r=t.withCredentials,n=t.tech,s=t.bandwidth,a=t.externHls,o=t.useCueTags,u=t.blacklistDuration,l=t.enableLowInitialPlaylist,c=t.sourceType;if(!i)throw new Error("A non-empty playlist URL is required");Ml=a,e.withCredentials=r,e.tech_=n,e.hls_=n.hls,e.sourceType_=c,e.useCueTags_=o,e.blacklistDuration=u,e.enableLowInitialPlaylist=l,e.useCueTags_&&(e.cueTagsTrack_=e.tech_.addTextTrack("metadata","ad-cues"),e.cueTagsTrack_.inBandMetadataTrackDispatchType=""),e.requestOptions_={withCredentials:e.withCredentials,timeout:null},e.mediaTypes_=Rl(),e.mediaSource=new As.MediaSource,e.mediaSource.addEventListener("sourceopen",e.handleSourceOpen_.bind(e)),e.seekable_=As.createTimeRanges(),e.hasPlayed_=function(){return!1},e.syncController_=new kl(t),e.segmentMetadataTrack_=n.addRemoteTextTrack({kind:"metadata",label:"segment-metadata"},!1).track,e.decrypter_=new Cl;var h={hls:e.hls_,mediaSource:e.mediaSource,currentTime:e.tech_.currentTime.bind(e.tech_),seekable:function(){return e.seekable()},seeking:function(){return e.tech_.seeking()},duration:function(){return e.mediaSource.duration},hasPlayed:function(){return e.hasPlayed_()},goalBufferLength:function(){return e.goalBufferLength()},bandwidth:s,syncController:e.syncController_,decrypter:e.decrypter_,sourceType:e.sourceType_};return e.masterPlaylistLoader_="dash"===e.sourceType_?new Xu(i,e.hls_,e.withCredentials):new Vo(i,e.hls_,e.withCredentials),e.setupMasterPlaylistLoaderListeners_(),e.mainSegmentLoader_=new gl(As.mergeOptions(h,{segmentMetadataTrack:e.segmentMetadataTrack_,loaderType:"main"}),t),e.audioSegmentLoader_=new gl(As.mergeOptions(h,{loaderType:"audio"}),t),e.subtitleSegmentLoader_=new _l(As.mergeOptions(h,{loaderType:"vtt"}),t),e.setupSegmentLoaderListeners_(),Ul.forEach(function(t){e[t+"_"]=Nl.bind(e,t)}),e.logger_=Yu("MPC"),e.masterPlaylistLoader_.load(),e}return _(p,d),p.prototype.setupMasterPlaylistLoaderListeners_=function(){var r=this;this.masterPlaylistLoader_.on("loadedmetadata",function(){var t=r.masterPlaylistLoader_.media(),e=1.5*r.masterPlaylistLoader_.targetDuration*1e3;ru(r.masterPlaylistLoader_.master,r.masterPlaylistLoader_.media())?r.requestOptions_.timeout=0:r.requestOptions_.timeout=e,t.endList&&"none"!==r.tech_.preload()&&(r.mainSegmentLoader_.playlist(t,r.requestOptions_),r.mainSegmentLoader_.load()),Dl({sourceType:r.sourceType_,segmentLoaders:{AUDIO:r.audioSegmentLoader_,SUBTITLES:r.subtitleSegmentLoader_,main:r.mainSegmentLoader_},tech:r.tech_,requestOptions:r.requestOptions_,masterPlaylistLoader:r.masterPlaylistLoader_,hls:r.hls_,master:r.master(),mediaTypes:r.mediaTypes_,blacklistCurrentPlaylist:r.blacklistCurrentPlaylist.bind(r)}),r.triggerPresenceUsage_(r.master(),t);try{r.setupSourceBuffers_()}catch(t){return As.log.warn("Failed to create SourceBuffers",t),r.mediaSource.endOfStream("decode")}r.setupFirstPlay(),r.trigger("selectedinitialmedia")}),this.masterPlaylistLoader_.on("loadedplaylist",function(){var t=r.masterPlaylistLoader_.media();if(!t){r.excludeUnsupportedVariants_();var e=void 0;return r.enableLowInitialPlaylist&&(e=r.selectInitialPlaylist()),e||(e=r.selectPlaylist()),r.initialMedia_=e,void r.masterPlaylistLoader_.media(r.initialMedia_)}if(r.useCueTags_&&r.updateAdCues_(t),r.mainSegmentLoader_.playlist(t,r.requestOptions_),r.updateDuration(),r.tech_.paused()||r.mainSegmentLoader_.load(),!t.endList){var i=function(){var t=r.seekable();0!==t.length&&r.mediaSource.addSeekableRange_(t.start(0),t.end(0))};if(r.duration()!==1/0){r.tech_.one("durationchange",function t(){r.duration()===1/0?i():r.tech_.one("durationchange",t)})}else i()}}),this.masterPlaylistLoader_.on("error",function(){r.blacklistCurrentPlaylist(r.masterPlaylistLoader_.error)}),this.masterPlaylistLoader_.on("mediachanging",function(){r.mainSegmentLoader_.abort(),r.mainSegmentLoader_.pause()}),this.masterPlaylistLoader_.on("mediachange",function(){var t=r.masterPlaylistLoader_.media(),e=1.5*r.masterPlaylistLoader_.targetDuration*1e3;ru(r.masterPlaylistLoader_.master,r.masterPlaylistLoader_.media())?r.requestOptions_.timeout=0:r.requestOptions_.timeout=e,r.mainSegmentLoader_.playlist(t,r.requestOptions_),r.mainSegmentLoader_.load(),r.tech_.trigger({type:"mediachange",bubbles:!0})}),this.masterPlaylistLoader_.on("playlistunchanged",function(){var t=r.masterPlaylistLoader_.media();r.stuckAtPlaylistEnd_(t)&&(r.blacklistCurrentPlaylist({message:"Playlist no longer updating."}),r.tech_.trigger("playliststuck"))}),this.masterPlaylistLoader_.on("renditiondisabled",function(){r.tech_.trigger({type:"usage",name:"hls-rendition-disabled"})}),this.masterPlaylistLoader_.on("renditionenabled",function(){r.tech_.trigger({type:"usage",name:"hls-rendition-enabled"})})},p.prototype.triggerPresenceUsage_=function(t,e){var i=t.mediaGroups||{},r=!0,n=Object.keys(i.AUDIO);for(var s in i.AUDIO)for(var a in i.AUDIO[s]){i.AUDIO[s][a].uri||(r=!1)}r&&this.tech_.trigger({type:"usage",name:"hls-demuxed"}),Object.keys(i.SUBTITLES).length&&this.tech_.trigger({type:"usage",name:"hls-webvtt"}),Ml.Playlist.isAes(e)&&this.tech_.trigger({type:"usage",name:"hls-aes"}),Ml.Playlist.isFmp4(e)&&this.tech_.trigger({type:"usage",name:"hls-fmp4"}),n.length&&1<Object.keys(i.AUDIO[n[0]]).length&&this.tech_.trigger({type:"usage",name:"hls-alternate-audio"}),this.useCueTags_&&this.tech_.trigger({type:"usage",name:"hls-playlist-cue-tags"})},p.prototype.setupSegmentLoaderListeners_=function(){var s=this;this.mainSegmentLoader_.on("bandwidthupdate",function(){var t=s.selectPlaylist(),e=s.masterPlaylistLoader_.media(),i=s.tech_.buffered(),r=i.length?i.end(i.length-1)-s.tech_.currentTime():0,n=s.bufferLowWaterLine();(!e.endList||s.duration()<Qu.MAX_BUFFER_LOW_WATER_LINE||t.attributes.BANDWIDTH<e.attributes.BANDWIDTH||n<=r)&&s.masterPlaylistLoader_.media(t),s.tech_.trigger("bandwidthupdate")}),this.mainSegmentLoader_.on("progress",function(){s.trigger("progress")}),this.mainSegmentLoader_.on("error",function(){s.blacklistCurrentPlaylist(s.mainSegmentLoader_.error())}),this.mainSegmentLoader_.on("syncinfoupdate",function(){s.onSyncInfoUpdate_()}),this.mainSegmentLoader_.on("timestampoffset",function(){s.tech_.trigger({type:"usage",name:"hls-timestamp-offset"})}),this.audioSegmentLoader_.on("syncinfoupdate",function(){s.onSyncInfoUpdate_()}),this.mainSegmentLoader_.on("ended",function(){s.onEndOfStream()}),this.mainSegmentLoader_.on("earlyabort",function(){s.blacklistCurrentPlaylist({message:"Aborted early because there isn't enough bandwidth to complete the request without rebuffering."},120)}),this.mainSegmentLoader_.on("reseteverything",function(){s.tech_.trigger("hls-reset")}),this.mainSegmentLoader_.on("segmenttimemapping",function(t){s.tech_.trigger({type:"hls-segment-time-mapping",mapping:t.mapping})}),this.audioSegmentLoader_.on("ended",function(){s.onEndOfStream()})},p.prototype.mediaSecondsLoaded_=function(){return Math.max(this.audioSegmentLoader_.mediaSecondsLoaded+this.mainSegmentLoader_.mediaSecondsLoaded)},p.prototype.load=function(){this.mainSegmentLoader_.load(),this.mediaTypes_.AUDIO.activePlaylistLoader&&this.audioSegmentLoader_.load(),this.mediaTypes_.SUBTITLES.activePlaylistLoader&&this.subtitleSegmentLoader_.load()},p.prototype.fastQualityChange_=function(){var t=this.selectPlaylist();t!==this.masterPlaylistLoader_.media()&&(this.masterPlaylistLoader_.media(t),this.mainSegmentLoader_.resetLoader())},p.prototype.play=function(){if(!this.setupFirstPlay()){this.tech_.ended()&&this.tech_.setCurrentTime(0),this.hasPlayed_()&&this.load();var t=this.tech_.seekable();return this.tech_.duration()===1/0&&this.tech_.currentTime()<t.start(0)?this.tech_.setCurrentTime(t.end(t.length-1)):void 0}},p.prototype.setupFirstPlay=function(){var t=this,e=this.masterPlaylistLoader_.media();if(!e||this.tech_.paused()||this.hasPlayed_())return!1;if(!e.endList){var i=this.seekable();if(!i.length)return!1;if(As.browser.IE_VERSION&&0===this.tech_.readyState())return this.tech_.one("loadedmetadata",function(){t.trigger("firstplay"),t.tech_.setCurrentTime(i.end(0)),t.hasPlayed_=function(){return!0}}),!1;this.trigger("firstplay"),this.tech_.setCurrentTime(i.end(0))}return this.hasPlayed_=function(){return!0},this.load(),!0},p.prototype.handleSourceOpen_=function(){try{this.setupSourceBuffers_()}catch(t){return As.log.warn("Failed to create Source Buffers",t),this.mediaSource.endOfStream("decode")}if(this.tech_.autoplay()){var t=this.tech_.play();"undefined"!=typeof t&&"function"==typeof t.then&&t.then(null,function(t){})}this.trigger("sourceopen")},p.prototype.onEndOfStream=function(){var t=this.mainSegmentLoader_.ended_;this.mediaTypes_.AUDIO.activePlaylistLoader&&(t=!this.mainSegmentLoader_.startingMedia_||this.mainSegmentLoader_.startingMedia_.containsVideo?t&&this.audioSegmentLoader_.ended_:this.audioSegmentLoader_.ended_),t&&this.mediaSource.endOfStream()},p.prototype.stuckAtPlaylistEnd_=function(t){if(!this.seekable().length)return!1;var e=this.syncController_.getExpiredTime(t,this.mediaSource.duration);if(null===e)return!1;var i=Ml.Playlist.playlistEnd(t,e),r=this.tech_.currentTime(),n=this.tech_.buffered();if(!n.length)return i-r<=.1;var s=n.end(n.length-1);return s-r<=.1&&i-s<=.1},p.prototype.blacklistCurrentPlaylist=function(){var t,e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},i=arguments[1],r=void 0;if(r=e.playlist||this.masterPlaylistLoader_.media(),i=i||e.blacklistDuration||this.blacklistDuration,!r){this.error=e;try{return this.mediaSource.endOfStream("network")}catch(t){return this.trigger("error")}}var n=1===this.masterPlaylistLoader_.master.playlists.filter(eu).length;return n?(As.log.warn("Problem encountered with the current HLS playlist. Trying again since it is the final playlist."),this.tech_.trigger("retryplaylist"),this.masterPlaylistLoader_.load(n)):(r.excludeUntil=Date.now()+1e3*i,this.tech_.trigger("blacklistplaylist"),this.tech_.trigger({type:"usage",name:"hls-rendition-blacklisted"}),t=this.selectPlaylist(),As.log.warn("Problem encountered with the current HLS playlist."+(e.message?" "+e.message:"")+" Switching to another playlist."),this.masterPlaylistLoader_.media(t))},p.prototype.pauseLoading=function(){this.mainSegmentLoader_.pause(),this.mediaTypes_.AUDIO.activePlaylistLoader&&this.audioSegmentLoader_.pause(),this.mediaTypes_.SUBTITLES.activePlaylistLoader&&this.subtitleSegmentLoader_.pause()},p.prototype.setCurrentTime=function(t){var e=gu(this.tech_.buffered(),t);return this.masterPlaylistLoader_&&this.masterPlaylistLoader_.media()&&this.masterPlaylistLoader_.media().segments?e&&e.length?t:(this.mainSegmentLoader_.resetEverything(),this.mainSegmentLoader_.abort(),this.mediaTypes_.AUDIO.activePlaylistLoader&&(this.audioSegmentLoader_.resetEverything(),this.audioSegmentLoader_.abort()),this.mediaTypes_.SUBTITLES.activePlaylistLoader&&(this.subtitleSegmentLoader_.resetEverything(),this.subtitleSegmentLoader_.abort()),void this.load()):0},p.prototype.duration=function(){return this.masterPlaylistLoader_?this.mediaSource?this.mediaSource.duration:Ml.Playlist.duration(this.masterPlaylistLoader_.media()):0},p.prototype.seekable=function(){return this.seekable_},p.prototype.onSyncInfoUpdate_=function(){var t=void 0,e=void 0;if(this.masterPlaylistLoader_){var i=this.masterPlaylistLoader_.media();if(i){var r=this.syncController_.getExpiredTime(i,this.mediaSource.duration);if(null!==r&&0!==(t=Ml.Playlist.seekable(i,r)).length){if(this.mediaTypes_.AUDIO.activePlaylistLoader){if(i=this.mediaTypes_.AUDIO.activePlaylistLoader.media(),null===(r=this.syncController_.getExpiredTime(i,this.mediaSource.duration)))return;if(0===(e=Ml.Playlist.seekable(i,r)).length)return}e?e.start(0)>t.end(0)||t.start(0)>e.end(0)?this.seekable_=t:this.seekable_=As.createTimeRanges([[e.start(0)>t.start(0)?e.start(0):t.start(0),e.end(0)<t.end(0)?e.end(0):t.end(0)]]):this.seekable_=t,this.logger_("seekable updated ["+vu(this.seekable_)+"]"),this.tech_.trigger("seekablechanged")}}}},p.prototype.updateDuration=function(){var e=this,t=this.mediaSource.duration,i=Ml.Playlist.duration(this.masterPlaylistLoader_.media()),r=this.tech_.buffered(),n=function t(){e.mediaSource.duration=i,e.tech_.trigger("durationchange"),e.mediaSource.removeEventListener("sourceopen",t)};0<r.length&&(i=Math.max(i,r.end(r.length-1))),t!==i&&("open"!==this.mediaSource.readyState?this.mediaSource.addEventListener("sourceopen",n):n())},p.prototype.dispose=function(){var r=this;this.decrypter_.terminate(),this.masterPlaylistLoader_.dispose(),this.mainSegmentLoader_.dispose(),["AUDIO","SUBTITLES"].forEach(function(t){var e=r.mediaTypes_[t].groups;for(var i in e)e[i].forEach(function(t){t.playlistLoader&&t.playlistLoader.dispose()})}),this.audioSegmentLoader_.dispose(),this.subtitleSegmentLoader_.dispose()},p.prototype.master=function(){return this.masterPlaylistLoader_.master},p.prototype.media=function(){return this.masterPlaylistLoader_.media()||this.initialMedia_},p.prototype.setupSourceBuffers_=function(){var t,e=this.masterPlaylistLoader_.media();if(e&&"open"===this.mediaSource.readyState){if((t=cl(this.masterPlaylistLoader_.master,e)).length<1)return this.error="No compatible SourceBuffer configuration for the variant stream:"+e.resolvedUri,this.mediaSource.endOfStream("decode");this.configureLoaderMimeTypes_(t),this.excludeIncompatibleVariants_(e)}},p.prototype.configureLoaderMimeTypes_=function(t){var e=1<t.length&&-1===t[0].indexOf(",")&&t[0]!==t[1]?new As.EventTarget:null;this.mainSegmentLoader_.mimeType(t[0],e),t[1]&&this.audioSegmentLoader_.mimeType(t[1],e)},p.prototype.excludeUnsupportedVariants_=function(){this.master().playlists.forEach(function(t){t.attributes.CODECS&&g.MediaSource&&g.MediaSource.isTypeSupported&&!g.MediaSource.isTypeSupported('video/mp4; codecs="'+t.attributes.CODECS.replace(/avc1\.(\d+)\.(\d+)/i,function(t){return Nu([t])[0]})+'"')&&(t.excludeUntil=1/0)})},p.prototype.excludeIncompatibleVariants_=function(t){var i=2,r=null,e=void 0;t.attributes.CODECS&&(e=ul(t.attributes.CODECS),r=e.videoCodec,i=e.codecCount),this.master().playlists.forEach(function(t){var e={codecCount:2,videoCodec:null};t.attributes.CODECS&&(e=ul(t.attributes.CODECS)),e.codecCount!==i&&(t.excludeUntil=1/0),e.videoCodec!==r&&(t.excludeUntil=1/0)})},p.prototype.updateAdCues_=function(t){var e=0,i=this.seekable();i.length&&(e=i.start(0)),function(t,e){var i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0;if(t.segments)for(var r=i,n=void 0,s=0;s<t.segments.length;s++){var a=t.segments[s];if(n||(n=bl(e,r+a.duration/2)),n){if("cueIn"in a){n.endTime=r,n.adEndTime=r,r+=a.duration,n=null;continue}if(r<n.endTime){r+=a.duration;continue}n.endTime+=a.duration}else if("cueOut"in a&&((n=new g.VTTCue(r,r+a.duration,a.cueOut)).adStartTime=r,n.adEndTime=r+parseFloat(a.cueOut),e.addCue(n)),"cueOutCont"in a){var o,u,l=a.cueOutCont.split("/").map(parseFloat);o=l[0],u=l[1],(n=new g.VTTCue(r,r+a.duration,"")).adStartTime=r-o,n.adEndTime=n.adStartTime+u,e.addCue(n)}r+=a.duration}}(t,this.cueTagsTrack_,e)},p.prototype.goalBufferLength=function(){var t=this.tech_.currentTime(),e=Qu.GOAL_BUFFER_LENGTH,i=Qu.GOAL_BUFFER_LENGTH_RATE,r=Math.max(e,Qu.MAX_GOAL_BUFFER_LENGTH);return Math.min(e+t*i,r)},p.prototype.bufferLowWaterLine=function(){var t=this.tech_.currentTime(),e=Qu.BUFFER_LOW_WATER_LINE,i=Qu.BUFFER_LOW_WATER_LINE_RATE,r=Math.max(e,Qu.MAX_BUFFER_LOW_WATER_LINE);return Math.min(e+t*i,r)},p}(As.EventTarget),jl=function t(e,i,r){y(this,t);var n,s,a,o=e.masterPlaylistController_.fastQualityChange_.bind(e.masterPlaylistController_);if(i.attributes.RESOLUTION){var u=i.attributes.RESOLUTION;this.width=u.width,this.height=u.height}this.bandwidth=i.attributes.BANDWIDTH,this.id=r,this.enabled=(n=e.playlists,s=i.uri,a=o,function(t){var e=n.master.playlists[s],i=tu(e),r=eu(e);return"undefined"==typeof t?r:(t?delete e.disabled:e.disabled=!0,t===r||i||(a(),t?n.trigger("renditionenabled"):n.trigger("renditiondisabled")),t)})},Fl=["seeking","seeked","pause","playing","error"],Hl=function(){function a(t){var e=this;y(this,a),this.tech_=t.tech,this.seekable=t.seekable,this.consecutiveUpdates=0,this.lastRecordedTime=null,this.timer_=null,this.checkCurrentTimeTimeout_=null,this.logger_=Yu("PlaybackWatcher"),this.logger_("initialize");var i=function(){return e.monitorCurrentTime_()},r=function(){return e.techWaiting_()},n=function(){return e.cancelTimer_()},s=function(){return e.fixesBadSeeks_()};this.tech_.on("seekablechanged",s),this.tech_.on("waiting",r),this.tech_.on(Fl,n),this.tech_.on("canplay",i),this.dispose=function(){e.logger_("dispose"),e.tech_.off("seekablechanged",s),e.tech_.off("waiting",r),e.tech_.off(Fl,n),e.tech_.off("canplay",i),e.checkCurrentTimeTimeout_&&g.clearTimeout(e.checkCurrentTimeTimeout_),e.cancelTimer_()}}return a.prototype.monitorCurrentTime_=function(){this.checkCurrentTime_(),this.checkCurrentTimeTimeout_&&g.clearTimeout(this.checkCurrentTimeTimeout_),this.checkCurrentTimeTimeout_=g.setTimeout(this.monitorCurrentTime_.bind(this),250)},a.prototype.checkCurrentTime_=function(){if(this.tech_.seeking()&&this.fixesBadSeeks_())return this.consecutiveUpdates=0,void(this.lastRecordedTime=this.tech_.currentTime());if(!this.tech_.paused()&&!this.tech_.seeking()){var t=this.tech_.currentTime(),e=this.tech_.buffered();if(this.lastRecordedTime===t&&(!e.length||t+.1>=e.end(e.length-1)))return this.techWaiting_();5<=this.consecutiveUpdates&&t===this.lastRecordedTime?(this.consecutiveUpdates++,this.waiting_()):t===this.lastRecordedTime?this.consecutiveUpdates++:(this.consecutiveUpdates=0,this.lastRecordedTime=t)}},a.prototype.cancelTimer_=function(){this.consecutiveUpdates=0,this.timer_&&(this.logger_("cancelTimer_"),clearTimeout(this.timer_)),this.timer_=null},a.prototype.fixesBadSeeks_=function(){var t=this.tech_.seeking(),e=this.seekable(),i=this.tech_.currentTime(),r=void 0;t&&this.afterSeekableWindow_(e,i)&&(r=e.end(e.length-1));t&&this.beforeSeekableWindow_(e,i)&&(r=e.start(0)+.1);return"undefined"!=typeof r&&(this.logger_("Trying to seek outside of seekable at time "+i+" with seekable range "+vu(e)+". Seeking to "+r+"."),this.tech_.setCurrentTime(r),!0)},a.prototype.waiting_=function(){if(!this.techWaiting_()){var t=this.tech_.currentTime(),e=this.tech_.buffered(),i=gu(e,t);return i.length&&t+3<=i.end(0)?(this.cancelTimer_(),this.tech_.setCurrentTime(t),this.logger_("Stopped at "+t+" while inside a buffered region ["+i.start(0)+" -> "+i.end(0)+"]. Attempting to resume playback by seeking to the current time."),void this.tech_.trigger({type:"usage",name:"hls-unknown-waiting"})):void 0}},a.prototype.techWaiting_=function(){var t=this.seekable(),e=this.tech_.currentTime();if(this.tech_.seeking()&&this.fixesBadSeeks_())return!0;if(this.tech_.seeking()||null!==this.timer_)return!0;if(this.beforeSeekableWindow_(t,e)){var i=t.end(t.length-1);return this.logger_("Fell out of live window at time "+e+". Seeking to live point (seekable end) "+i),this.cancelTimer_(),this.tech_.setCurrentTime(i),this.tech_.trigger({type:"usage",name:"hls-live-resync"}),!0}var r=this.tech_.buffered(),n=yu(r,e);if(this.videoUnderflow_(n,r,e))return this.cancelTimer_(),this.tech_.setCurrentTime(e),this.tech_.trigger({type:"usage",name:"hls-video-underflow"}),!0;if(0<n.length){var s=n.start(0)-e;return this.logger_("Stopped at "+e+", setting timer for "+s+", seeking to "+n.start(0)),this.timer_=setTimeout(this.skipTheGap_.bind(this),1e3*s,e),!0}return!1},a.prototype.afterSeekableWindow_=function(t,e){return!!t.length&&e>t.end(t.length-1)+.1},a.prototype.beforeSeekableWindow_=function(t,e){return!!(t.length&&0<t.start(0)&&e<t.start(0)-.1)},a.prototype.videoUnderflow_=function(t,e,i){if(0===t.length){var r=this.gapFromVideoUnderflow_(e,i);if(r)return this.logger_("Encountered a gap in video from "+r.start+" to "+r.end+". Seeking to current time "+i),!0}return!1},a.prototype.skipTheGap_=function(t){var e=this.tech_.buffered(),i=this.tech_.currentTime(),r=yu(e,i);this.cancelTimer_(),0!==r.length&&i===t&&(this.logger_("skipTheGap_:","currentTime:",i,"scheduled currentTime:",t,"nextRange start:",r.start(0)),this.tech_.setCurrentTime(r.start(0)+fu),this.tech_.trigger({type:"usage",name:"hls-gap-skip"}))},a.prototype.gapFromVideoUnderflow_=function(t,e){for(var i=function(t){if(t.length<2)return As.createTimeRanges();for(var e=[],i=1;i<t.length;i++){var r=t.end(i-1),n=t.start(i);e.push([r,n])}return As.createTimeRanges(e)}(t),r=0;r<i.length;r++){var n=i.start(r),s=i.end(r);if(e-n<4&&2<e-n)return{start:n,end:s}}return null},a}(),Vl={errorInterval:30,getSource:function(t){return t(this.tech({IWillNotUseThisInPlugins:!0}).currentSource_)}},ql=function(t){!function e(i,t){var r=0,n=0,s=As.mergeOptions(Vl,t);i.ready(function(){i.trigger({type:"usage",name:"hls-error-reload-initialized"})});var a=function(){n&&i.currentTime(n)},o=function(t){null!=t&&(n=i.duration()!==1/0&&i.currentTime()||0,i.one("loadedmetadata",a),i.src(t),i.trigger({type:"usage",name:"hls-error-reload"}),i.play())},u=function(){if(Date.now()-r<1e3*s.errorInterval)i.trigger({type:"usage",name:"hls-error-reload-canceled"});else{if(s.getSource&&"function"==typeof s.getSource)return r=Date.now(),s.getSource.call(i,o);As.log.error("ERROR: reloadSourceOnError - The option getSource must be a function!")}},l=function t(){i.off("loadedmetadata",a),i.off("error",u),i.off("dispose",t)};i.on("error",u),i.on("dispose",l),i.reloadSourceOnError=function(t){l(),e(i,t)}}(this,t)},Wl={PlaylistLoader:Vo,Playlist:nu,Decrypter:Do,AsyncStream:Oo,decrypt:Io,utils:pu,STANDARD_PLAYLIST_SELECTOR:function(){return function(t,e,i,r){var n=t.playlists.map(function(t){var e,i;return e=t.attributes.RESOLUTION&&t.attributes.RESOLUTION.width,i=t.attributes.RESOLUTION&&t.attributes.RESOLUTION.height,{bandwidth:t.attributes.BANDWIDTH||g.Number.MAX_VALUE,width:e,height:i,playlist:t}});dl(n,function(t,e){return t.bandwidth-e.bandwidth});var s=(n=n.filter(function(t){return!nu.isIncompatible(t.playlist)})).filter(function(t){return nu.isEnabled(t.playlist)});s.length||(s=n.filter(function(t){return!nu.isDisabled(t.playlist)}));var a=s.filter(function(t){return t.bandwidth*Qu.BANDWIDTH_VARIANCE<e}),o=a[a.length-1],u=a.filter(function(t){return t.bandwidth===o.bandwidth})[0],l=a.filter(function(t){return t.width&&t.height});dl(l,function(t,e){return t.width-e.width});var c=l.filter(function(t){return t.width===i&&t.height===r});o=c[c.length-1];var h=c.filter(function(t){return t.bandwidth===o.bandwidth})[0],d=void 0,p=void 0,f=void 0;h||(p=(d=l.filter(function(t){return t.width>i||t.height>r})).filter(function(t){return t.width===d[0].width&&t.height===d[0].height}),o=p[p.length-1],f=p.filter(function(t){return t.bandwidth===o.bandwidth})[0]);var m=f||h||u||s[0]||n[0];return m?m.playlist:null}(this.playlists.master,this.systemBandwidth,parseInt(hl(this.tech_.el(),"width"),10),parseInt(hl(this.tech_.el(),"height"),10))},INITIAL_PLAYLIST_SELECTOR:function(){var t=this.playlists.master.playlists.filter(nu.isEnabled);return dl(t,function(t,e){return pl(t,e)}),t.filter(function(t){return ul(t.attributes.CODECS).videoCodec})[0]||null},comparePlaylistBandwidth:pl,comparePlaylistResolution:function(t,e){var i=void 0,r=void 0;return t.attributes.RESOLUTION&&t.attributes.RESOLUTION.width&&(i=t.attributes.RESOLUTION.width),i=i||g.Number.MAX_VALUE,e.attributes.RESOLUTION&&e.attributes.RESOLUTION.width&&(r=e.attributes.RESOLUTION.width),i===(r=r||g.Number.MAX_VALUE)&&t.attributes.BANDWIDTH&&e.attributes.BANDWIDTH?t.attributes.BANDWIDTH-e.attributes.BANDWIDTH:i-r},xhr:ou()};["GOAL_BUFFER_LENGTH","MAX_GOAL_BUFFER_LENGTH","GOAL_BUFFER_LENGTH_RATE","BUFFER_LOW_WATER_LINE","MAX_BUFFER_LOW_WATER_LINE","BUFFER_LOW_WATER_LINE_RATE","BANDWIDTH_VARIANCE"].forEach(function(e){Object.defineProperty(Wl,e,{get:function(){return As.log.warn("using Hls."+e+" is UNSAFE be sure you know what you are doing"),Qu[e]},set:function(t){As.log.warn("using Hls."+e+" is UNSAFE be sure you know what you are doing"),"number"!=typeof t||t<0?As.log.warn("value of Hls."+e+" must be greater than or equal to 0"):Qu[e]=t}})});var zl=function(t){if(/^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i.test(t))return"hls";return/^application\/dash\+xml/i.test(t)?"dash":null},Gl=function(t,e){for(var i=e.media(),r=-1,n=0;n<t.length;n++)if(t[n].id===i.uri){r=n;break}t.selectedIndex_=r,t.trigger({selectedIndex:r,type:"change"})};Wl.canPlaySource=function(){return As.log.warn("HLS is no longer a tech. Please remove it from your player's techOrder.")};var Xl=function(t){if("dash"===t.options_.sourceType){var e=As.players[t.tech_.options_.playerId];if(e.eme){var i=function(t,e,i){if(!t)return t;var r={};for(var n in t)r[n]={audioContentType:'audio/mp4; codecs="'+i.attributes.CODECS+'"',videoContentType:'video/mp4; codecs="'+e.attributes.CODECS+'"'},e.contentProtection&&e.contentProtection[n]&&e.contentProtection[n].pssh&&(r[n].pssh=e.contentProtection[n].pssh),"string"==typeof t[n]&&(r[n].url=t[n]);return As.mergeOptions(t,r)}(t.source_.keySystems,t.playlists.media(),t.masterPlaylistController_.mediaTypes_.AUDIO.activePlaylistLoader.media());i&&(e.currentSource().keySystems=i)}}};Wl.supportsNativeHls=function(){var e=p.createElement("video");if(!As.getTech("Html5").isSupported())return!1;return["application/vnd.apple.mpegurl","audio/mpegurl","audio/x-mpegurl","application/x-mpegurl","video/x-mpegurl","video/mpegurl","application/mpegurl"].some(function(t){return/maybe|probably/i.test(e.canPlayType(t))})}(),Wl.supportsNativeDash=!!As.getTech("Html5").isSupported()&&/maybe|probably/i.test(p.createElement("video").canPlayType("application/dash+xml")),Wl.supportsTypeNatively=function(t){return"hls"===t?Wl.supportsNativeHls:"dash"===t&&Wl.supportsNativeDash},Wl.isSupported=function(){return As.log.warn("HLS is no longer a tech. Please remove it from your player's techOrder.")};var Yl=function(s){function a(t,e,i){y(this,a);var r=b(this,s.call(this,e,i.hls));if(e.options_&&e.options_.playerId){var n=As(e.options_.playerId);n.hasOwnProperty("hls")||Object.defineProperty(n,"hls",{get:function(){return As.log.warn("player.hls is deprecated. Use player.tech_.hls instead."),e.trigger({type:"usage",name:"hls-player-access"}),r}}),n.vhs=r,n.dash=r}if(r.tech_=e,r.source_=t,r.stats={},r.ignoreNextSeekingEvent_=!1,r.setOptions_(),r.options_.overrideNative&&(e.featuresNativeVideoTracks||e.featuresNativeAudioTracks))throw new Error("Overriding native HLS requires emulated tracks. See https://git.io/vMpjB");return r.on(p,["fullscreenchange","webkitfullscreenchange","mozfullscreenchange","MSFullscreenChange"],function(t){var e=p.fullscreenElement||p.webkitFullscreenElement||p.mozFullScreenElement||p.msFullscreenElement;e&&e.contains(r.tech_.el())&&r.masterPlaylistController_.fastQualityChange_()}),r.on(r.tech_,"seeking",function(){this.ignoreNextSeekingEvent_?this.ignoreNextSeekingEvent_=!1:this.setCurrentTime(this.tech_.currentTime())}),r.on(r.tech_,"error",function(){this.masterPlaylistController_&&this.masterPlaylistController_.pauseLoading()}),r.on(r.tech_,"play",r.play),r}return _(a,s),a.prototype.setOptions_=function(){var e=this;this.options_.withCredentials=this.options_.withCredentials||!1,"number"!=typeof this.options_.blacklistDuration&&(this.options_.blacklistDuration=300),"number"!=typeof this.options_.bandwidth&&(this.options_.bandwidth=4194304),this.options_.enableLowInitialPlaylist=this.options_.enableLowInitialPlaylist&&4194304===this.options_.bandwidth,["withCredentials","bandwidth"].forEach(function(t){"undefined"!=typeof e.source_[t]&&(e.options_[t]=e.source_[t])}),this.bandwidth=this.options_.bandwidth},a.prototype.src=function(t,e){var r=this;t&&(this.setOptions_(),this.options_.url=this.source_.src,this.options_.tech=this.tech_,this.options_.externHls=Wl,this.options_.sourceType=zl(e),this.masterPlaylistController_=new Bl(this.options_),this.playbackWatcher_=new Hl(As.mergeOptions(this.options_,{seekable:function(){return r.seekable()}})),this.masterPlaylistController_.on("error",function(){As.players[r.tech_.options_.playerId].error(r.masterPlaylistController_.error)}),this.masterPlaylistController_.selectPlaylist=this.selectPlaylist?this.selectPlaylist.bind(this):Wl.STANDARD_PLAYLIST_SELECTOR.bind(this),this.masterPlaylistController_.selectInitialPlaylist=Wl.INITIAL_PLAYLIST_SELECTOR.bind(this),this.playlists=this.masterPlaylistController_.masterPlaylistLoader_,this.mediaSource=this.masterPlaylistController_.mediaSource,Object.defineProperties(this,{selectPlaylist:{get:function(){return this.masterPlaylistController_.selectPlaylist},set:function(t){this.masterPlaylistController_.selectPlaylist=t.bind(this)}},throughput:{get:function(){return this.masterPlaylistController_.mainSegmentLoader_.throughput.rate},set:function(t){this.masterPlaylistController_.mainSegmentLoader_.throughput.rate=t,this.masterPlaylistController_.mainSegmentLoader_.throughput.count=1}},bandwidth:{get:function(){return this.masterPlaylistController_.mainSegmentLoader_.bandwidth},set:function(t){this.masterPlaylistController_.mainSegmentLoader_.bandwidth=t,this.masterPlaylistController_.mainSegmentLoader_.throughput={rate:0,count:0}}},systemBandwidth:{get:function(){var t=1/(this.bandwidth||1),e=void 0;return e=0<this.throughput?1/this.throughput:0,Math.floor(1/(t+e))},set:function(){As.log.error('The "systemBandwidth" property is read-only')}}}),Object.defineProperties(this.stats,{bandwidth:{get:function(){return r.bandwidth||0},enumerable:!0},mediaRequests:{get:function(){return r.masterPlaylistController_.mediaRequests_()||0},enumerable:!0},mediaRequestsAborted:{get:function(){return r.masterPlaylistController_.mediaRequestsAborted_()||0},enumerable:!0},mediaRequestsTimedout:{get:function(){return r.masterPlaylistController_.mediaRequestsTimedout_()||0},enumerable:!0},mediaRequestsErrored:{get:function(){return r.masterPlaylistController_.mediaRequestsErrored_()||0},enumerable:!0},mediaTransferDuration:{get:function(){return r.masterPlaylistController_.mediaTransferDuration_()||0},enumerable:!0},mediaBytesTransferred:{get:function(){return r.masterPlaylistController_.mediaBytesTransferred_()||0},enumerable:!0},mediaSecondsLoaded:{get:function(){return r.masterPlaylistController_.mediaSecondsLoaded_()||0},enumerable:!0},buffered:{get:function(){return _u(r.tech_.buffered())},enumerable:!0},currentTime:{get:function(){return r.tech_.currentTime()},enumerable:!0},currentSource:{get:function(){return r.tech_.currentSource_},enumerable:!0},currentTech:{get:function(){return r.tech_.name_},enumerable:!0},duration:{get:function(){return r.tech_.duration()},enumerable:!0},master:{get:function(){return r.playlists.master},enumerable:!0},playerDimensions:{get:function(){return r.tech_.currentDimensions()},enumerable:!0},seekable:{get:function(){return _u(r.tech_.seekable())},enumerable:!0},timestamp:{get:function(){return Date.now()},enumerable:!0},videoPlaybackQuality:{get:function(){return r.tech_.getVideoPlaybackQuality()},enumerable:!0}}),this.tech_.one("canplay",this.masterPlaylistController_.setupFirstPlay.bind(this.masterPlaylistController_)),this.masterPlaylistController_.on("selectedinitialmedia",function(){var i,t;t=(i=r).playlists,i.representations=function(){return t.master.playlists.filter(function(t){return!tu(t)}).map(function(t,e){return new jl(i,t,t.uri)})},Xl(r)}),this.on(this.masterPlaylistController_,"progress",function(){this.tech_.trigger("progress")}),this.on(this.masterPlaylistController_,"firstplay",function(){this.ignoreNextSeekingEvent_=!0}),this.tech_.ready(function(){return r.setupQualityLevels_()}),this.tech_.el()&&this.tech_.src(As.URL.createObjectURL(this.masterPlaylistController_.mediaSource)))},a.prototype.setupQualityLevels_=function(){var i=this,t=As.players[this.tech_.options_.playerId];t&&t.qualityLevels&&(this.qualityLevels_=t.qualityLevels(),this.masterPlaylistController_.on("selectedinitialmedia",function(){var e,t;e=i.qualityLevels_,(t=i).representations().forEach(function(t){e.addQualityLevel(t)}),Gl(e,t.playlists)}),this.playlists.on("mediachange",function(){Gl(i.qualityLevels_,i.playlists)}))},a.prototype.play=function(){this.masterPlaylistController_.play()},a.prototype.setCurrentTime=function(t){this.masterPlaylistController_.setCurrentTime(t)},a.prototype.duration=function(){return this.masterPlaylistController_.duration()},a.prototype.seekable=function(){return this.masterPlaylistController_.seekable()},a.prototype.dispose=function(){this.playbackWatcher_&&this.playbackWatcher_.dispose(),this.masterPlaylistController_&&this.masterPlaylistController_.dispose(),this.qualityLevels_&&this.qualityLevels_.dispose(),s.prototype.dispose.call(this)},a}(As.getComponent("Component")),$l={name:"videojs-http-streaming",VERSION:"1.0.0",canHandleSource:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=As.mergeOptions(As.options,e);return $l.canPlayType(t.type,i)},handleSource:function(t,e){var i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},r=As.mergeOptions(As.options,i);return e.hls=new Yl(t,e,r),e.hls.xhr=ou(),e.hls.src(t.src,t.type),e.hls},canPlayType:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},i=As.mergeOptions(As.options,e).hls.overrideNative,r=zl(t);return r&&(!Wl.supportsTypeNatively(r)||i)?"maybe":""}};return"undefined"!=typeof As.MediaSource&&"undefined"!=typeof As.URL||(As.MediaSource=qu,As.URL=Wu),qu.supportsNativeMediaSources()&&As.getTech("Html5").registerSourceHandler($l,0),As.HlsHandler=Yl,As.HlsSourceHandler=$l,As.Hls=Wl,As.use||As.registerComponent("Hls",Wl),As.options.hls=As.options.hls||{},As.registerPlugin?As.registerPlugin("reloadSourceOnError",ql):As.plugin("reloadSourceOnError",ql),As}); diff --git a/form/src/assets/play/bg.jpg b/form/src/assets/play/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..701c49c4c716d9e48412993f87f47d0fdcfbbe44 Binary files /dev/null and b/form/src/assets/play/bg.jpg differ diff --git a/form/src/assets/play/btn_left.png b/form/src/assets/play/btn_left.png new file mode 100644 index 0000000000000000000000000000000000000000..e3428fd5bcda4bad311e87c5aa5669fdb7e96a60 Binary files /dev/null and b/form/src/assets/play/btn_left.png differ diff --git a/form/src/assets/play/btn_right.png b/form/src/assets/play/btn_right.png new file mode 100644 index 0000000000000000000000000000000000000000..db0f274024b4ad41d5219acf3936ec2b2f79459c Binary files /dev/null and b/form/src/assets/play/btn_right.png differ diff --git a/form/src/assets/play/default/audio.mp3 b/form/src/assets/play/default/audio.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..66313dcf084aa98da69908cb6ee9da2d0d4a451e Binary files /dev/null and b/form/src/assets/play/default/audio.mp3 differ diff --git a/form/src/assets/play/default/pic.jpg b/form/src/assets/play/default/pic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1da3c1135cc324bf3ec67cc0c7b4c19caeef08f1 Binary files /dev/null and b/form/src/assets/play/default/pic.jpg differ diff --git a/form/src/assets/play/music/click.mp3 b/form/src/assets/play/music/click.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..f551dc50e89af2d63b79892af8bf1d61ae92f7a5 Binary files /dev/null and b/form/src/assets/play/music/click.mp3 differ diff --git a/form/src/assets/play/text_bg.png b/form/src/assets/play/text_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..6084daeadcb2cec320328e7e1f362d104b7ffbaa Binary files /dev/null and b/form/src/assets/play/text_bg.png differ diff --git a/form/src/environments/environment.prod.ts b/form/src/environments/environment.prod.ts new file mode 100644 index 0000000000000000000000000000000000000000..3612073bc31cd4c1f5d6cbb00318521e9a61bd8a --- /dev/null +++ b/form/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/form/src/environments/environment.ts b/form/src/environments/environment.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b4f817adb754769ca126a939d48ac4b0850489d --- /dev/null +++ b/form/src/environments/environment.ts @@ -0,0 +1,16 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/form/src/favicon.ico b/form/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8081c7ceaf2be08bf59010158c586170d9d2d517 Binary files /dev/null and b/form/src/favicon.ico differ diff --git a/form/src/index.html b/form/src/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e55641675b96cbe7dae938f19f7d6ba8773e4c42 --- /dev/null +++ b/form/src/index.html @@ -0,0 +1,16 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>NgOne</title> + <base href="/"> +<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">--> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="icon" type="image/x-icon" href="favicon.ico"> + <script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script> + +</head> +<body> +<app-root></app-root> +</body> +</html> diff --git a/form/src/main.ts b/form/src/main.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7b673cf44b388e9989fe908b78d7d73cd2e1409 --- /dev/null +++ b/form/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/form/src/online.html b/form/src/online.html new file mode 100644 index 0000000000000000000000000000000000000000..91956f843fb74ef758b62c9df4a4ffa63b53137c --- /dev/null +++ b/form/src/online.html @@ -0,0 +1,16 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>NgOne</title> + <base href="/"> +<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">--> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="icon" type="image/x-icon" href="favicon.ico"> + <script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script> + +</head> +<body> + Hello World!! +</body> +</html> diff --git a/form/src/polyfills.ts b/form/src/polyfills.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa665d6b8740860e1d67de37a26ab362ef8ba974 --- /dev/null +++ b/form/src/polyfills.ts @@ -0,0 +1,63 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/form/src/styles.css b/form/src/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..90d4ee0072ce3fc41812f8af910219f9eea3c3de --- /dev/null +++ b/form/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/form/src/test.ts b/form/src/test.ts new file mode 100644 index 0000000000000000000000000000000000000000..16317897b1c50a3a71bc775a8d6429f2b4c6cf98 --- /dev/null +++ b/form/src/test.ts @@ -0,0 +1,20 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/form/tsconfig.app.json b/form/tsconfig.app.json new file mode 100644 index 0000000000000000000000000000000000000000..8fe350f7afcad454efbb2db2a17b977cf9c564c6 --- /dev/null +++ b/form/tsconfig.app.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [ + "node" + ] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/test.ts", + "src/**/*.spec.ts" + ] +} diff --git a/form/tsconfig.json b/form/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..b4f6b3c22ef6509c186cb31d4e79428a309c1b22 --- /dev/null +++ b/form/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "module": "esnext", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "importHelpers": true, + "target": "es2015", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + }, + "angularCompilerOptions": { + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true + } +} diff --git a/form/tsconfig.spec.json b/form/tsconfig.spec.json new file mode 100644 index 0000000000000000000000000000000000000000..6400fde7d544029c82e13d368a6b69d6664fe857 --- /dev/null +++ b/form/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/form/tslint.json b/form/tslint.json new file mode 100644 index 0000000000000000000000000000000000000000..4fcb4b1d413f773db7ea534e2c9d6d29436a819a --- /dev/null +++ b/form/tslint.json @@ -0,0 +1,100 @@ +{ + "extends": "tslint:recommended", + "rules": { + "array-type": false, + "arrow-parens": false, + "deprecation": { + "severity": "warning" + }, + "component-class-suffix": true, + "contextual-lifecycle": true, + "directive-class-suffix": true, + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ], + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "interface-name": false, + "max-classes-per-file": false, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-consecutive-blank-lines": false, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-empty": false, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-switch-case-fall-through": true, + "no-use-before-declare": true, + "no-var-requires": false, + + "no-shadowed-variable": false, + + "object-literal-key-quotes": [ + true, + "as-needed" + ], + "object-literal-sort-keys": false, + "ordered-imports": false, + "quotemark": [ + true, + "single" + ], + "trailing-comma": false, + "no-conflicting-lifecycle": true, + "no-host-metadata-property": true, + "no-input-rename": true, + "no-inputs-metadata-property": true, + "no-output-native": true, + "no-output-on-prefix": true, + "no-output-rename": true, + "no-outputs-metadata-property": true, + "template-banana-in-box": true, + "template-no-negated-async": true, + "use-lifecycle-interface": true, + "use-pipe-transform-interface": true, + "no-trailing-whitespace": false, + "variable-name": false, + + "no-unused-expression": false, + "align": false + }, + "rulesDirectory": [ + "codelyzer" + ] +}